Merge "msm-camera: Avoid adding top up to calulated ab/ib for single stream."
diff --git a/Documentation/devicetree/bindings/arm/msm/clock-krait-8974.txt b/Documentation/devicetree/bindings/arm/msm/clock-krait-8974.txt
index ee9a286..d9ccb09 100644
--- a/Documentation/devicetree/bindings/arm/msm/clock-krait-8974.txt
+++ b/Documentation/devicetree/bindings/arm/msm/clock-krait-8974.txt
@@ -41,6 +41,8 @@
 - qcom,hfpll-user-vco-mask:
 			The mask to be used when programming the VCO selection
 			bits in the user control register.
+- qcom,pvs-config-ver:
+			The version of the data in qcom,speedX-pvsY-bin-vZ.
 
 Example:
 	qcom,clock-krait@f9016000 {
diff --git a/Documentation/devicetree/bindings/arm/msm/cpr-regulator.txt b/Documentation/devicetree/bindings/arm/msm/cpr-regulator.txt
index f724e60..bba4cf7 100644
--- a/Documentation/devicetree/bindings/arm/msm/cpr-regulator.txt
+++ b/Documentation/devicetree/bindings/arm/msm/cpr-regulator.txt
@@ -11,7 +11,7 @@
 	bits to indicate what bin (and voltage range) a chip is in.
 
 Required properties:
-- compatible:			Must be "qti,cpr-regulator"
+- compatible:			Must be "qcom,cpr-regulator"
 - reg:				Register addresses for RBCPR, RBCPR clock
 				select, PVS and CPR eFuse address
 - reg-names:			Register names. Must be "rbcpr", "rbcpr_clk",
@@ -22,41 +22,38 @@
 				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
-- qti,pvs-init-voltage:  	A list of integers whose length is equal to 2
-				to the power of qti,pvs-fuse[num-of-bits]. The
-				location or 0-based index of an element in the
-				list corresponds to the bin number. The value of
-				each integer corresponds to the initial voltage
-				of the PVS bin in turbo mode in microvolts.
-- qti,pvs-corner-ceiling-slow:	Ceiling voltages of all corners for APC_PVS_SLOW
-- qti,pvs-corner-ceiling-nom:	Ceiling voltages of all corners for APC_PVS_NOM
-- qti,pvs-corner-ceiling-fast:	Ceiling voltages of all corners for APC_PVS_FAST
-				The ceiling voltages for each of above three
+- qcom,pvs-voltage-table: 	Array of triples in which each triple indicates the initial voltage
+				of the PVS bin in SVS, NOM and Turbo corner in microvolts.
+				The location or 0-based index of an triple in the
+				list corresponds to the bin number.
+- qcom,cpr-voltage-ceiling:	Ceiling voltages of SVS, NOM and TURBO corners respectively
+- qcom,cpr-voltage-floor:	Floor voltages of SVS, NOM and TURBO corners respectively
+				The ceiling voltages for each of above two
 				properties may look like this:
 				  0 (SVS voltage):		1050000 uV
 				  1 (NORMAL voltage):		1150000 uV
 				  2 (TURBO voltage):		1275000 uV
 - vdd-apc-supply:		Regulator to supply VDD APC power
-- qti,vdd-apc-step-up-limit:	Limit of vdd-apc-supply steps for scaling up.
-- qti,vdd-apc-step-down-limit:	Limit of vdd-apc-supply steps for scaling down.
-- qti,cpr-ref-clk:		The reference clock in kHz.
-- qti,cpr-timer-delay:		The delay in microseconds for the timer interval.
-- qti,cpr-timer-cons-up:	Consecutive number of timer interval (qti,cpr-timer-delay)
+- qcom,vdd-apc-step-up-limit:	Limit of vdd-apc-supply steps for scaling up.
+- qcom,vdd-apc-step-down-limit:	Limit of vdd-apc-supply steps for scaling down.
+- qcom,cpr-ref-clk:		The reference clock in kHz.
+- qcom,cpr-timer-delay:		The delay in microseconds for the timer interval.
+- qcom,cpr-timer-cons-up:	Consecutive number of timer interval (qcom,cpr-timer-delay)
 				occurred before issuing UP interrupt.
-- qti,cpr-timer-cons-down:	Consecutive number of timer interval (qti,cpr-timer-delay)
+- qcom,cpr-timer-cons-down:	Consecutive number of timer interval (qcom,cpr-timer-delay)
 				occurred before issuing DOWN interrupt.
-- qti,cpr-irq-line:		Internal interrupt route signal of RBCPR, one of 0, 1 or 2.
-- qti,cpr-step-quotient:	Number of CPR quotient (Ring Oscillator(RO) count) per vdd-apc-supply step
+- qcom,cpr-irq-line:		Internal interrupt route signal of RBCPR, one of 0, 1 or 2.
+- qcom,cpr-step-quotient:	Number of CPR quotient (Ring Oscillator(RO) count) per vdd-apc-supply step
 				to issue error_steps.
-- qti,cpr-up-threshold:	The threshold for CPR to issue interrupt when
+- qcom,cpr-up-threshold:	The threshold for CPR to issue interrupt when
 				error_steps is greater than it when stepping up.
-- qti,cpr-down-threshold:	The threshold for CPR to issue interrupt when
+- qcom,cpr-down-threshold:	The threshold for CPR to issue interrupt when
 				error_steps is greater than it when stepping down.
-- qti,cpr-idle-clocks:		Idle clock cycles RO can be in.
-- qti,cpr-gcnt-time:		The time for gate count in microseconds.
-- qti,cpr-apc-volt-step:	The voltage in microvolt per CPR step, such as 5000uV.
+- qcom,cpr-idle-clocks:		Idle clock cycles RO can be in.
+- qcom,cpr-gcnt-time:		The time for gate count in microseconds.
+- qcom,cpr-apc-volt-step:	The voltage in microvolt per CPR step, such as 5000uV.
 
-- qti,pvs-fuse-redun-sel:	Array of 5 elements to indicate where to read the bits, what value to
+- qcom,pvs-fuse-redun-sel:	Array of 5 elements to indicate where to read the bits, what value to
 				compare with in order to decide if the redundant PVS fuse bits would be
 				used instead of the original bits and method to read fuse row, reading
 				register through SCM or directly. The 5 elements with index [0..4] are:
@@ -70,19 +67,19 @@
 				Otherwise, the original PVS bits should be selected. If the 5th
 				element is 0, read the fuse row from register directly. Otherwise,
 				read it through SCM.
-- qti,pvs-fuse:			Array of 4 elements to indicate the bits for PVS fuse and read method.
+- qcom,pvs-fuse:			Array of 4 elements to indicate the bits for PVS fuse and read method.
 				The array should have index and value like this:
 				  [0] => the PVS fuse row number
 				  [1] => LSB bit position of the bits
 				  [2] => number of bits
 				  [3] => fuse reading method, 0 for direct reading or 1 for SCM reading
-- qti,pvs-fuse-redun:		Array of 4 elements to indicate the bits for redundant PVS fuse.
+- qcom,pvs-fuse-redun:		Array of 4 elements to indicate the bits for redundant PVS fuse.
 				The array should have index and value like this:
 				  [0] => the redundant PVS fuse row number
 				  [1] => LSB bit position of the bits
 				  [2] => number of bits
 				  [3] => fuse reading method, 0 for direct reading or 1 for SCM reading
-- qti,cpr-fuse-redun-sel:	Array of 5 elements to indicate where to read the bits, what value to
+- qcom,cpr-fuse-redun-sel:	Array of 5 elements to indicate where to read the bits, what value to
 				compare with in order to decide if the redundant CPR fuse bits would be
 				used instead of the original bits and method to read fuse row, using SCM
 				to read or read register directly. The 5 elements with index [0..4] are:
@@ -96,32 +93,32 @@
 				Otherwise, the original CPR bits should be selected. If the 5th element
 				is 0, read the fuse row from register directly. Otherwise, read it through
 				SCM.
-- qti,cpr-fuse-row:		Array of row number of CPR fuse and method to read that row. It should have
+- qcom,cpr-fuse-row:		Array of row number of CPR fuse and method to read that row. It should have
 				index and value like this:
 				 [0] => the fuse row number
 				 [1] => fuse reading method, 0 for direct reading or 1 for SCM reading
-- qti,cpr-fuse-bp-cpr-disable:	Bit position of the bit to indicate if CPR should be disable
-- qti,cpr-fuse-bp-scheme:	Bit position of the bit to indicate if it's a global/local scheme
-- qti,cpr-fuse-target-quot:	Array of bit positions in fuse for Target Quotient of all corners.
+- qcom,cpr-fuse-bp-cpr-disable:	Bit position of the bit to indicate if CPR should be disable
+- qcom,cpr-fuse-bp-scheme:	Bit position of the bit to indicate if it's a global/local scheme
+- qcom,cpr-fuse-target-quot:	Array of bit positions in fuse for Target Quotient of all corners.
 				It should have index and value like this:
 				  [0] => bit position of the LSB bit for SVS target quotient
 				  [1] => bit position of the LSB bit for NOMINAL target quotient
 				  [2] => bit position of the LSB bit for TURBO target quotient
-- qti,cpr-fuse-ro-sel:		Array of bit positions in fuse for RO select of all corners.
+- qcom,cpr-fuse-ro-sel:		Array of bit positions in fuse for RO select of all corners.
 				It should have index and value like this:
 				  [0] => bit position of the LSB bit for SVS RO select bits
 				  [1] => bit position of the LSB bit for NOMINAL RO select bits
 				  [2] => bit position of the LSB bit for TURBO RO select bits
-- qti,cpr-fuse-redun-row:	Array of row number of redundant CPR fuse and method to read that
+- qcom,cpr-fuse-redun-row:	Array of row number of redundant CPR fuse and method to read that
 				row. It should have index and value like this:
 				 [0] => the redundant fuse row number
 				 [1] => the value to indicate reading the fuse row directly or using SCM
-- qti,cpr-fuse-redun-target-quot:	Array of bit positions in fuse for redundant Target Quotient of all corners.
+- qcom,cpr-fuse-redun-target-quot:	Array of bit positions in fuse for redundant Target Quotient of all corners.
 				It should have index and value like this:
 				  [0] => bit position of the LSB bit for redundant SVS target quotient
 				  [1] => bit position of the LSB bit for redundant NOMINAL target quotient
 				  [2] => bit position of the LSB bit for redundant TURBO target quotient
-- qti,cpr-fuse-redun-ro-sel:	Array of bit positions in eFuse for redundant RO select.
+- qcom,cpr-fuse-redun-ro-sel:	Array of bit positions in eFuse for redundant RO select.
 				It should have index and value like this:
 				  [0] => bit position of the LSB bit for redundant SVS RO select bits
 				  [1] => bit position of the LSB bit for redundant NOMINAL RO select bits
@@ -131,23 +128,31 @@
 Optional properties:
 - vdd-mx-supply:		Regulator to supply memory power as dependency
 				of VDD APC.
-- qti,vdd-mx-vmax:		The maximum voltage in uV for vdd-mx-supply. This
+- qcom,vdd-mx-vmax:		The maximum voltage in uV for vdd-mx-supply. This
 				is required when vdd-mx-supply is present.
-- qti,vdd-mx-vmin-method:	The method to determine the minimum voltage for
+- qcom,vdd-mx-vmin-method:	The method to determine the minimum voltage for
 				vdd-mx-supply, which can be one of following
 				choices compared with VDD APC:
 				  0 => equal to the voltage(vmin) of VDD APC
 				  1 => equal to PVS corner ceiling voltage
 				  2 => equal to slow speed corner ceiling
-				  3 => equal to qti,vdd-mx-vmax
+				  3 => equal to qcom,vdd-mx-vmax
+				  4 => equal to VDD_APC corner mapped vdd-mx voltage
 				This is required when vdd-mx-supply is present.
-- qti,cpr-fuse-redun-bp-cpr-disable:	Redundant bit position of the bit to indicate if CPR should be disable
-- qti,cpr-fuse-redun-bp-scheme:	Redundant bit position of the bit to indicate if it's a global/local scheme
+- qcom,vdd-mx-corner-map:	Array of 3 elements which defines the mapping from VDD_APC
+				fuse voltage corners to vdd-mx-supply voltages.
+				The 3 elements with index[0..2] are:
+				[0] => voltage to set for vdd-mx when VDD_APC is running at SVS corner
+				[1] => voltage to set for vdd-mx when VDD_APC is running at NOM corner
+				[2] => voltage to set for vdd-mx when VDD_APC is running at TURBO corner
+				This is required when the qcom,vdd-mx-vmin-method property has a value of 4.
+- qcom,cpr-fuse-redun-bp-cpr-disable:	Redundant bit position of the bit to indicate if CPR should be disable
+- qcom,cpr-fuse-redun-bp-scheme:	Redundant bit position of the bit to indicate if it's a global/local scheme
 					This property is required if cpr-fuse-redun-bp-cpr-disable
 					is present, and vise versa.
-- qti,cpr-enable:		Present: CPR enabled by default.
+- qcom,cpr-enable:		Present: CPR enabled by default.
 				Not Present: CPR disable by default.
-- qti,cpr-fuse-cond-min-volt-sel:	Array of 5 elements to indicate where to read the bits,  what value to
+- qcom,cpr-fuse-cond-min-volt-sel:	Array of 5 elements to indicate where to read the bits,  what value to
 				compare with in order to decide if the conditional minimum apc voltage needs
 				to be applied and the fuse reading method.
 				The 5 elements with index[0..4] are:
@@ -159,11 +164,11 @@
 				When the value of the fuse bits specified by first 3 elements is not equal to
 				the value in 4th element, then set the apc voltage for all parts running
 				at each voltage corner to be not lower than the voltage defined
-				using "qti,cpr-cond-min-voltage".
-- qti,cpr-cond-min-voltage:	Minimum voltage in microvolts for SVS, NOM and TURBO mode if the fuse bits
-				defined in qti,cpr-fuse-cond-min-volt-sel have not been programmed with the
+				using "qcom,cpr-cond-min-voltage".
+- qcom,cpr-cond-min-voltage:	Minimum voltage in microvolts for SVS, NOM and TURBO mode if the fuse bits
+				defined in qcom,cpr-fuse-cond-min-volt-sel have not been programmed with the
 				expected data. This is required if cpr-fuse-cond-min-volt-sel is present.
-- qti,cpr-fuse-uplift-sel: 	Array of 5 elements to indicate where to read the bits, what value to
+- qcom,cpr-fuse-uplift-sel: 	Array of 5 elements to indicate where to read the bits, what value to
 				compare with in order to enable or disable the pvs voltage uplift workaround,
 				and the fuse reading method.
 				The 5 elements with index[0..4] are:
@@ -175,7 +180,7 @@
 				[4]: => fuse reading method, 0 for direct reading or 1 for SCM reading.
 				When the value of the fuse bits specified by first 3 elements equals to the
 				value in 4th element, the pvs voltage uplift workaround will be enabled.
-- qti,speed-bin-fuse-sel:	Array of 4 elements to indicate where to read the speed bin of the processor,
+- qcom,speed-bin-fuse-sel:	Array of 4 elements to indicate where to read the speed bin of the processor,
 				and the fuse reading method.
 				The 4 elements with index[0..3] are:
 				[0]: => the fuse row number of the selector;
@@ -183,82 +188,179 @@
 				[2]: => number of the bits;
 				[3]: => fuse reading method, 0 for direct reading or 1 for SCM reading.
 				This is required if cpr-fuse-uplift-disable-sel is present.
-- qti,cpr-uplift-voltage:	Uplift in microvolts used for increasing pvs init voltage. If this property is present,
+- qcom,cpr-uplift-voltage:	Uplift in microvolts used for increasing pvs init voltage. If this property is present,
 				This is required if cpr-fuse-uplift-disable-sel is present.
-- qti,cpr-uplift-max-volt:	Maximum voltage in microvolts used for pvs voltage uplift workaround to limit
+- qcom,cpr-uplift-max-volt:	Maximum voltage in microvolts used for pvs voltage uplift workaround to limit
 				the maximum pvs voltage.
 				This is required if cpr-fuse-uplift-disable-sel is present.
-- qti,cpr-uplift-quotient:	Three numbers used for pvs voltage uplift workaround to be added to the target
+- qcom,cpr-uplift-quotient:	Three numbers used for pvs voltage uplift workaround to be added to the target
 				quotient for each corner.
 				The 3 quotient increment with index[0..2] are:
 				[0]: => for SVS corner target quotient;
 				[1]: => for NORM corner target quotient;
 				[2]: => for TURBO corner target quotient;
 				This is required if cpr-fuse-uplift-disable-sel is present.
-- qti,cpr-uplift-speed-bin:	The speed bin value corresponding to one type of processor which needs to apply the
+- qcom,cpr-uplift-speed-bin:	The speed bin value corresponding to one type of processor which needs to apply the
 				pvs voltage uplift workaround.
 				This is required if cpr-fuse-uplift-disable-sel is present.
+- qcom,cpr-quotient-adjustment:	Array of three elements of CPR quotient adjustments for each corner.
+				The 3 quotient adjustments with index[0..2] are:
+				[0] => amount to add to the SVS quotient
+				[1] => amount to add to the NORM quotient
+				[2] => amount to add to the TURBO quotient
+				If this property is specified, then the quotient adjustment values are added to the target
+				quotient values read from fuses before writing them into the CPR GCNT target control registers.
+				This property can be used to add static margin to the voltage rail managed by the CPR controller.
+- vdd-apc-optional-prim-supply:	Present: Regulator of highest priority to supply VDD APC power
+				Not Present: No such regulator.
+- vdd-apc-optional-sec-supply:	Present: Regulator of second highest priority to supply VDD APC power.
+				Not Present: No such regulator.
+- qcom,cpr-speed-bin-max-corners: Array of quintuples in which each quintuple maps a CPU speed bin and PVS version to
+				the maximum virtual voltage corner corresponding to the SVS, NORMAL and TURBO corners.
+				The 5 elements in one quintuple are:
+				[0]: => the speed bin of the CPU.
+				[1]: => the PVS version of the CPU.
+				[2]: => the max virtual voltage corner value corresponding to SVS corner for this speed bin.
+				[3]: => the max virtual voltage corner value corresponding to NORMAL corner for this speed bin.
+				[4]: => the max virtual voltage corner value corresponding to TURBO corner for this speed bin.
+				No CPR target quotient scaling is applied on chips which have a speed bin + PVS version
+				pair that does not appear in one of the quintuples in this property. If the property is
+				specified, then quotient scaling is enabled for the TURBO corner. If this property is
+				not specified, then no quotient scaling can take place.
+- qcom,cpr-corner-map:		Array of elements of fuse corner value for each virtual corner.
+				The location or 1-based index of an element in the list corresponds to
+				the virtual corner value. For example, the first element in the list is the fuse corner
+				value that virtual corner 1 maps to.
+				This property is required if qcom,cpr-speed-bin-max-corners is present.
+- qcom,cpr-corner-frequency-map: Array of tuples in which a tuple describes a corner to application processor frequency
+				mapping.
+				The 2 elements in one tuple are:
+				[0]: => a virtual voltage corner.
+				[1]: => the application processor frequency in Hz corresponding to the virtual corner.
+				This property is required if qcom,cpr-speed-bin-max-corners is present.
+- qcom,pvs-version-fuse-sel:	Array of 4 elements to indicate where to read the pvs version of the processor,
+				and the fuse reading method.
+				The 4 elements with index[0..3] are:
+				[0]: => the fuse row number of the selector;
+				[1]: => LSB bit position of the bits;
+				[2]: => the number of bits;
+				[3]: => fuse reading method, 0 for direct reading or 1 for SCM reading.
+				This property is required if qcom,cpr-speed-bin-max-corners is present.
+- qcom,cpr-quot-adjust-scaling-factor-max: The maximum allowed CPR target quotient scaling factor to use when
+				calculating the quotient adjustment for a given virtual voltage corner. It
+				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 {
 		status = "okay";
-		compatible = "qti,cpr-regulator";
+		compatible = "qcom,cpr-regulator";
 		reg = <0xf9018000 0x1000>, <0xfc4b8000 0x1000>;
 		reg-names = "rbcpr", "efuse_addr";
 		interrupts = <0 15 0>;
 		regulator-name = "apc_corner";
 		regulator-min-microvolt = <1>;
-		regulator-max-microvolt = <3>;
+		regulator-max-microvolt = <12>;
 
-		qti,pvs-fuse = <22 6 5 1>;
-		qti,pvs-fuse-redun-sel = <22 24 3 2 1>;
-		qti,pvs-fuse-redun = <22 27 5 1>;
+		qcom,pvs-fuse = <22 6 5 1>;
+		qcom,pvs-fuse-redun-sel = <22 24 3 2 1>;
+		qcom,pvs-fuse-redun = <22 27 5 1>;
 
-		qti,pvs-init-voltage = <1330000 1330000 1330000 1320000
-						1310000 1300000 1290000 1280000
-						1270000 1260000 1250000 1240000
-						1230000 1220000 1210000 1200000
-						1190000 1180000 1170000 1160000
-						1150000 1140000 1140000 1140000
-						1140000 1140000 1140000 1140000
-						1140000 1140000 1140000 1140000>;
-		qti,pvs-corner-ceiling-slow = <1050000 1160000 1275000>;
-		qti,pvs-corner-ceiling-nom  =  <975000 1075000 1200000>;
-		qti,pvs-corner-ceiling-fast =  <900000 1000000 1140000>;
+		qcom,pvs-voltage-table =
+			<1050000 1150000 1350000>,
+			<1050000 1150000 1340000>,
+			<1050000 1150000 1330000>,
+			<1050000 1150000 1320000>,
+			<1050000 1150000 1310000>,
+			<1050000 1150000 1300000>,
+			<1050000 1150000 1290000>,
+			<1050000 1150000 1280000>,
+			<1050000 1150000 1270000>,
+			<1050000 1140000 1260000>,
+			<1050000 1130000 1250000>,
+			<1050000 1120000 1240000>,
+			<1050000 1110000 1230000>,
+			<1050000 1100000 1220000>,
+			<1050000 1090000 1210000>,
+			<1050000 1080000 1200000>,
+			<1050000 1070000 1190000>,
+			<1050000 1060000 1180000>,
+			<1050000 1050000 1170000>,
+			<1050000 1050000 1160000>,
+			<1050000 1050000 1150000>,
+			<1050000 1050000 1140000>,
+			<1050000 1050000 1140000>,
+			<1050000 1050000 1140000>,
+			<1050000 1050000 1140000>,
+			<1050000 1050000 1140000>,
+			<1050000 1050000 1140000>,
+			<1050000 1050000 1140000>,
+			<1050000 1050000 1140000>,
+			<1050000 1050000 1140000>,
+			<1050000 1050000 1140000>,
+			<1050000 1050000 1140000>;
+		qcom,cpr-voltage-ceiling = <1050000 1150000 1280000>;
+		qcom,cpr-voltage-floor = <1050000 1050000 1100000>;
 		vdd-apc-supply = <&pm8226_s2>;
+		vdd-apc-optional-prim-supply = <&ncp6335d>;
+		vdd-apc-optional-sec-supply = <&fan53555>;
 		vdd-mx-supply = <&pm8226_l3_ao>;
-		qti,vdd-mx-vmax = <1350000>;
-		qti,vdd-mx-vmin-method = <1>;
-		qti,vdd-apc-step-up-limit = <1>;
-		qti,vdd-apc-step-down-limit = <1>;
-		qti,cpr-ref-clk = <19200>;
-		qti,cpr-timer-delay = <5000>;
-		qti,cpr-timer-cons-up = <1>;
-		qti,cpr-timer-cons-down = <2>;
-		qti,cpr-irq-line = <0>;
-		qti,cpr-step-quotient = <15>;
-		qti,cpr-up-threshold = <1>;
-		qti,cpr-down-threshold = <2>;
-		qti,cpr-idle-clocks = <5>;
-		qti,cpr-gcnt-time = <1>;
-		qti,cpr-apc-volt-step = <5000>;
+		qcom,vdd-mx-vmax = <1350000>;
+		qcom,vdd-mx-vmin-method = <1>;
+		qcom,vdd-apc-step-up-limit = <1>;
+		qcom,vdd-apc-step-down-limit = <1>;
+		qcom,cpr-ref-clk = <19200>;
+		qcom,cpr-timer-delay = <5000>;
+		qcom,cpr-timer-cons-up = <1>;
+		qcom,cpr-timer-cons-down = <2>;
+		qcom,cpr-irq-line = <0>;
+		qcom,cpr-step-quotient = <15>;
+		qcom,cpr-up-threshold = <1>;
+		qcom,cpr-down-threshold = <2>;
+		qcom,cpr-idle-clocks = <5>;
+		qcom,cpr-gcnt-time = <1>;
+		qcom,cpr-apc-volt-step = <5000>;
 
-		qti,cpr-fuse-row = <138 1>;
-		qti,cpr-fuse-bp-cpr-disable = <36>;
-		qti,cpr-fuse-bp-scheme = <37>;
-		qti,cpr-fuse-target-quot = <24 12 0>;
-		qti,cpr-fuse-ro-sel = <54 38 41>;
-		qti,cpr-fuse-redun-sel = <138 57 1 1 1>;
-		qti,cpr-fuse-redun-row = <139 1>;
-		qti,cpr-fuse-redun-target-quot = <24 12 0>;
-		qti,cpr-fuse-redun-ro-sel = <46 36 39>;
-		qti,cpr-fuse-cond-min-volt-sel = <54 42 6 7 1>;
-		qti,cpr-cond-min-voltage = <1140000>;
-		qti,cpr-fuse-uplift-sel = <22 53 1 0 0>;
-		qti,cpr-uplift-voltage = <50000>;
-		qti,cpr-uplift-quotient = <0 0 120>;
-		qti,cpr-uplift-max-volt = <1350000>;
-		qti,cpr-uplift-speed-bin = <1>;
-		qti,speed-bin-fuse-sel = <22 0 3 0>;
+		qcom,cpr-fuse-row = <138 1>;
+		qcom,cpr-fuse-bp-cpr-disable = <36>;
+		qcom,cpr-fuse-bp-scheme = <37>;
+		qcom,cpr-fuse-target-quot = <24 12 0>;
+		qcom,cpr-fuse-ro-sel = <54 38 41>;
+		qcom,cpr-fuse-redun-sel = <138 57 1 1 1>;
+		qcom,cpr-fuse-redun-row = <139 1>;
+		qcom,cpr-fuse-redun-target-quot = <24 12 0>;
+		qcom,cpr-fuse-redun-ro-sel = <46 36 39>;
+		qcom,cpr-fuse-cond-min-volt-sel = <54 42 6 7 1>;
+		qcom,cpr-cond-min-voltage = <1140000>;
+		qcom,cpr-fuse-uplift-sel = <22 53 1 0 0>;
+		qcom,cpr-uplift-voltage = <50000>;
+		qcom,cpr-uplift-quotient = <0 0 120>;
+		qcom,cpr-uplift-max-volt = <1350000>;
+		qcom,cpr-uplift-speed-bin = <1>;
+		qcom,speed-bin-fuse-sel = <22 0 3 0>;
+		qcom,cpr-corner-map = <1 1 2 2 3 3 3 3 3 3 3 3>;
+		qcom,cpr-corner-frequency-map =
+				<1 300000000>,
+				<2 384000000>,
+				<3 600000000>,
+				<4 787200000>,
+				<5 998400000>,
+				<6 1094400000>,
+				<7 1190400000>,
+				<8 1305600000>,
+				<9 1344000000>,
+				<10 1401600000>,
+				<11 1497600000>,
+				<12 1593600000>;
+		qcom,pvs-version-fuse-sel = <22 4 2 0>;
+		qcom,cpr-speed-bin-max-corners =
+				<0 1 2 4 7>,
+				<1 1 2 4 12>,
+				<2 1 2 4 10>,
+				<5 1 2 4 14>;
+		qcom,cpr-quot-adjust-scaling-factor-max = <650>;
 	};
 
diff --git a/Documentation/devicetree/bindings/arm/msm/cpubw.txt b/Documentation/devicetree/bindings/arm/msm/cpubw.txt
new file mode 100644
index 0000000..1dc3835
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/msm/cpubw.txt
@@ -0,0 +1,30 @@
+MSM CPU bandwidth device
+
+cpubw is a device that represents the CPU subsystem master ports in a MSM SoC
+and the related info that is needed to make CPU to DDR bandwidth votes.
+
+Required properties:
+- compatible:		Must be "qcom,cpubw"
+- qcom,cpu-mem-ports:	A list of tuples where each tuple consists of a bus
+			master (CPU subsystem) port number and a bus slave
+			(memory) port number.
+- qcom,bw-tbl:		A list of meaningful instantaneous bandwidth values
+			(in MB/s) that can be requested from the CPU
+			subsystem to DDR. The list of values depend on the
+			supported DDR frequencies and the bus widths.
+
+Example:
+
+	qcom,cpubw {
+		compatible = "qcom,cpubw";
+		qcom,cpu-mem-ports = <1 512>, <2 512>;
+		qcom,bw-tbl =
+			<  572 /*  75 MHz */ >,
+			< 1144 /* 150 MHz */ >,
+			< 1525 /* 200 MHz */ >,
+			< 2342 /* 307 MHz */ >,
+			< 3509 /* 460 MHz */ >,
+			< 4684 /* 614 MHz */ >,
+			< 6103 /* 800 MHz */ >,
+			< 7102 /* 931 MHz */ >;
+	};
diff --git a/Documentation/devicetree/bindings/arm/msm/ext-buck-control.txt b/Documentation/devicetree/bindings/arm/msm/ext-buck-control.txt
new file mode 100644
index 0000000..37c0995
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/msm/ext-buck-control.txt
@@ -0,0 +1,26 @@
+* MSM EXT BUCK REGULATOR CONTROL
+
+External buck regulator is used to power up the APC rail.
+This buck can be turn-on & turn-off by toggling a gpio
+line which is connected to buck enable pin. This driver
+control the external regulator behaviour with the help
+of RPM by sending the sleep and active sets when APPS
+decide to enter into low power state with RPM assisted.
+
+The required properties for EXT BUCK CONTROL are:
+
+- compatible: "qcom,ext-buck-control"
+
+The optional properties are:
+- qcom,gpio-num: Indicates the GPIO number which will turn-on and turn-off
+		 the external buck.
+- qcom,settling-time-us: Indicates the settling time for the external buck to
+			 get turn-on or turn-off. Settling time is calculated
+			 in terms of QTIMER(19.2MHz) and the value is in us.
+
+Example:
+	qcom,ext-buck-control {
+		compatible = "qcom,ext-buck-control";
+		qcom,gpio-num = <50>;
+		qcom,settling-time-us = <2580>;
+};
diff --git a/Documentation/devicetree/bindings/arm/msm/kraitbw-l2pm.txt b/Documentation/devicetree/bindings/arm/msm/kraitbw-l2pm.txt
new file mode 100644
index 0000000..17d55d4
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/msm/kraitbw-l2pm.txt
@@ -0,0 +1,18 @@
+MSM Krait L2 performance monitor counters for bandwidth measurement device
+
+krait-l2pm is a device that represents the Krait L2 PM counters that can be
+used to measure the bandwidth of read/write traffic from the Krait CPU
+subsystem.
+
+Required properties:
+- compatible:		Must be "qcom,kraitbw_l2pm"
+- interrupts:		Lists the L2 PM counter overflow IRQ.
+- qcom,bytes-per-beat:	The number of bytes transferred in one data beat from
+			the Krait CPU subsystem.
+
+Example:
+	qcom,kraitbw-l2pm {
+		compatible = "qcom,kraitbw-l2pm";
+		interrupts = <0 1 1>;
+		qcom,bytes-per-beat = <8>;
+	};
diff --git a/Documentation/devicetree/bindings/arm/msm/lpm-levels.txt b/Documentation/devicetree/bindings/arm/msm/lpm-levels.txt
index 0696730..7f52be8 100644
--- a/Documentation/devicetree/bindings/arm/msm/lpm-levels.txt
+++ b/Documentation/devicetree/bindings/arm/msm/lpm-levels.txt
@@ -58,6 +58,9 @@
 - qcom,min-cpu-mode: The min cpu sleep mode at which the given system level is
 		 valid. All cpus should have entered this low power mode before
 		 this system level can be chosen.
+- qcom,send-rpm-sleep-set: The system mode notifies RPM of Apps sleep and should
+		send the current sleep set votes and configure MPM before
+		entering this low power mode.
 
 Example:
 qcom,lpm-levels {
diff --git a/Documentation/devicetree/bindings/arm/msm/msm-cpufreq.txt b/Documentation/devicetree/bindings/arm/msm/msm-cpufreq.txt
index 02514d4..fed49c9 100644
--- a/Documentation/devicetree/bindings/arm/msm/msm-cpufreq.txt
+++ b/Documentation/devicetree/bindings/arm/msm/msm-cpufreq.txt
@@ -9,23 +9,15 @@
 - compatible:		Must be "qcom,msm-cpufreq"
 - qcom,cpufreq-table:	A list of tuples where each tuple consists of a
 			usable CPU frequency (KHz), an optional cache
-			frequency (KHz) and an optional memory bandwidth
+			frequency (KHz) and a mandatory memory bandwidth
 			value (MBPS) listed in that order.  The cache
 			frequencies shall not be listed if the device cannot
-			run the cache asynchronous to one or more CPUs. The
-			memory bandwidth values shall not be listed if the
-			optional cpu-mem-ports property is not supplied.
-
-Optional properties:
-- qcom,cpu-mem-ports:	A list of tuples where each tuple consists of a bus
-			master (CPU) port number and a bus slave (memory)
-			port number.
+			run the cache asynchronous to one or more CPUs.
 
 Example:
 	qcom,msm-cpufreq@0 {
 		regs = <0 4>
 		compatible = "qcom,msm-cpufreq";
-		qcom,cpu-mem-ports = <1 512>, <2 513>;
 		qcom,cpufreq-table =
 			<  300000  300000  600 >,
 			<  422400  422400 1200 >,
diff --git a/Documentation/devicetree/bindings/arm/msm/msm_bus.txt b/Documentation/devicetree/bindings/arm/msm/msm_bus.txt
index 6283a82..e6e54bf 100644
--- a/Documentation/devicetree/bindings/arm/msm/msm_bus.txt
+++ b/Documentation/devicetree/bindings/arm/msm/msm_bus.txt
@@ -20,10 +20,12 @@
 these features:
 
 qcom,ntieredslaves:	Number of tiered slaves on the bus.
-qcom,qos-freq:		QoS frequency (In Hz)
+qcom,qos-freq:		QoS frequency (In KHz)
 qcom,hw-sel:		A string which decides whether QoS data
 			should be sent to RPM, set using BIMC or NoCs.
 			It can be set to "RPM", "NoC" or "BIMC".
+qcom,qos-baseoffset:	Base address offset of QoS registers from the bus device
+			base address.
 qcom,rpm-en:		A boolean flag indicating whether RPM transactions are
 			supported for nodes of the bus.
 qcom,ahb:		A boolean flag indicating whether the bus is ahb type.
@@ -98,8 +100,8 @@
 			(Can be Fixed/Limiter/Bypass/Regulator)
 qcom,bimc,bw:		Bandwidth limit for a BIMC master using dual modes.
 			This bandwidth is used to calculate Grant count and
-			other parameters used in Limiter and Regular mode
-			for static BKE configuration. It is defined in KBps.
+			other parameters used in Limiter and Regular mode.
+			for static BKE configuration. It is defined in KBytes/s.
 qcom,bimc,gp:		Grant Period for configuring a master in limiter
 			mode. This is an integer value in nano-seconds.
 qcom,bimc,thmp:		Medium threshold percentage for BIMC masters.
@@ -109,11 +111,12 @@
 			1 and 100.
 qcom,thresh:		Beyond this threshold frequency, the mode usage is
 			switched from mode specified by property qcom,mode
-			to the one specified by qcom,mode-thresh. In case the
-			requested IB value falls below this threshold, the mode
-			is switched back to qcom,mode. Frequency is specified in
-			KBps.
-
+			to the one specified by qcom,mode-thresh. These thresholds
+			can be setup in increasing order of thresholds, so the
+			requested IB is evaluated at each threshold level before
+			making the decision to switch QoS modes and applying the
+			corresponding qcom,bimc,bw limitig bw as needed.
+			This is specified in KBytes/s.
 
 
 
diff --git a/Documentation/devicetree/bindings/arm/msm/pm-8x60.txt b/Documentation/devicetree/bindings/arm/msm/pm-8x60.txt
index 795af3b..2fbe4ca 100644
--- a/Documentation/devicetree/bindings/arm/msm/pm-8x60.txt
+++ b/Documentation/devicetree/bindings/arm/msm/pm-8x60.txt
@@ -12,6 +12,7 @@
 The required properties for PM-8x60 are:
 
 - compatible: "qcom,pm-8x60"
+- qcom,lpm-levels: phandle for associated lpm_levels device.
 
 The optional properties are:
 
@@ -39,4 +40,5 @@
 		reg = <0xfe800664 0x40>;
 		qcom,pc-mode = "tz_l2_int";
 		qcom,use-sync-timer;
+		qcom,lpm-levels = <&lpm_levels>;
 	};
diff --git a/Documentation/devicetree/bindings/arm/msm/rpm-regulator-smd.txt b/Documentation/devicetree/bindings/arm/msm/rpm-regulator-smd.txt
index 3d70a9b..2b25fcb 100644
--- a/Documentation/devicetree/bindings/arm/msm/rpm-regulator-smd.txt
+++ b/Documentation/devicetree/bindings/arm/msm/rpm-regulator-smd.txt
@@ -32,6 +32,10 @@
 - qcom,enable-time:    Time in us to delay after enabling the regulator
 - qcom,hpm-min-load:   Load current in uA which corresponds to the minimum load
 			which requires the regulator to be in high power mode.
+- qcom,apps-only:      Flag which indicates that the regulator only has
+			consumers on the application processor. If this flag
+			is specified, then voltage and current updates are
+			only sent to the RPM if the regulator is enabled.
 
 [Second Level Nodes]
 
@@ -84,6 +88,7 @@
 				current updates are only sent if the given
 				regulator has also been enabled by a Linux
 				consumer.
+
 The following properties specify initial values for parameters to be sent to the
 RPM in regulator requests.
 - qcom,init-enable:            0 = regulator disabled
diff --git a/Documentation/devicetree/bindings/crypto/msm/qcedev.txt b/Documentation/devicetree/bindings/crypto/msm/qcedev.txt
index 3ca9080..fc94be4 100644
--- a/Documentation/devicetree/bindings/crypto/msm/qcedev.txt
+++ b/Documentation/devicetree/bindings/crypto/msm/qcedev.txt
@@ -12,6 +12,7 @@
   - qcom,msm_bus,active-only: Boolean flag for context of request (actve/dual)
   - qcom,msm_bus,num_paths: The paths for source and destination ports
   - qcom,msm_bus,vectors: Vectors for bus topology.
+  - qcom,ce-device: Device number.
 
 Optional properties:
   - qcom,ce-hw-shared : optional, indicates if the hardware is shared between EE.
@@ -27,6 +28,7 @@
 		interrupts = <0 235 0>;
 		qcom,bam-pipe-pair = <0>;
 		qcom,ce-hw-instance = <1>;
+		qcom,ce-device = <0>;
 		qcom,ce-hw-shared;
                 qcom,msm-bus,name = "qcedev-noc";
 		qcom,msm-bus,num-cases = <2>;
diff --git a/Documentation/devicetree/bindings/crypto/msm/qcrypto.txt b/Documentation/devicetree/bindings/crypto/msm/qcrypto.txt
index 01cc798..6561b6a 100644
--- a/Documentation/devicetree/bindings/crypto/msm/qcrypto.txt
+++ b/Documentation/devicetree/bindings/crypto/msm/qcrypto.txt
@@ -12,10 +12,18 @@
   - qcom,msm_bus,active-only: Boolean flag for context of request (actve/dual)
   - qcom,msm_bus,num_paths: The paths for source and destination ports
   - qcom,msm_bus,vectors: Vectors for bus topology.
+  - qcom,ce-device: Device number.
 
 Optional properties:
   - qcom,ce-hw-shared : optional, indicates if the hardware is shared between EE.
   - qcom,ce-hw-key : optional, indicates if the hardware supports use of HW KEY.
+  - qcom,use-sw-aes-cbc-ecb-ctr-algo : optional, indicates if use SW aes-cbc/ecb/ctr algorithm.
+  - qcom,use-sw-aes-xts-algo : optional, indicates if use SW aes-xts algorithm.
+  - qcom,use-sw-aead-algo : optional, indicates if use SW aead algorithm.
+  - qcom,use-sw-ahash-algo : optional, indicates if use SW hash algorithm.
+  - qcom,use-sw-hmac-algo : optional, indicates if use SW hmac algorithm.
+  - qcom,use-sw-aes-ccm-algo : optional, indicates if use SW aes-ccm algorithm.
+  - qcom,clk-mgmt-sus-res : optional, indicate if the ce clocks need to be disabled/enabled in suspend/resume function.
 
 Example:
 
@@ -27,6 +35,7 @@
 		interrupts = <0 235 0>;
 		qcom,bam-pipe-pair = <1>;
 		qcom,ce-hw-instance = <1>;
+		qcom,ce-device = <0>;
 		qcom,ce-hw-shared;
                 qcom,msm-bus,name = "qcrypto-noc";
 		qcom,msm-bus,num-cases = <2>;
diff --git a/Documentation/devicetree/bindings/fb/mdss-dsi-ctrl.txt b/Documentation/devicetree/bindings/fb/mdss-dsi-ctrl.txt
index cda437a..b88c3ce 100644
--- a/Documentation/devicetree/bindings/fb/mdss-dsi-ctrl.txt
+++ b/Documentation/devicetree/bindings/fb/mdss-dsi-ctrl.txt
@@ -6,7 +6,12 @@
 Required properties:
 - compatible:				Must be "qcom,mdss-dsi-ctrl"
 - cell-index:				Specifies the controller used among the two controllers.
-- reg:					offset and length of the register set for the device.
+- reg: 					Base address and length of the different register
+					regions(s) required for DSI device functionality.
+- reg-names: 				A list of strings that map in order to the list of regs.
+					"dsi_ctrl" - MDSS DSI controller register region
+					"dsi_phy" - MDSS DSI PHY register region
+					"mmss_misc_phys" - Register region for MMSS DSI clamps
 - vdd-supply:				Phandle for vdd regulator device node.
 - vddio-supply:				Phandle for vdd-io regulator device node.
 - vdda-supply:				Phandle for vreg regulator device node.
@@ -52,7 +57,10 @@
 		compatible = "qcom,mdss-dsi-ctrl";
 		label = "MDSS DSI CTRL->0";
 		cell-index = <0>;
-		reg = <0xfd922800 0x600>;
+		reg = 	<0xfd922800 0x1f8>,
+			<0xfd922b00 0x2b0>,
+			<0xfd828000 0x108>;
+		reg-names = "dsi_ctrl", "dsi_phy", "mmss_misc_phys";
 		vdd-supply = <&pm8226_l15>;
 		vddio-supply = <&pm8226_l8>;
 		vdda-supply = <&pm8226_l4>;
diff --git a/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt b/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
index 0e236f2..f6b4923 100644
--- a/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
+++ b/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
@@ -126,6 +126,9 @@
 						implemented during suspend/resume.
 					"dfps_immediate_clk_mode" = FPS change request is
 						implemented immediately using DSI clocks.
+					"dfps_immediate_porch_mode" = FPS change request is
+						implemented immediately by changing panel porch
+						values.
 - qcom,mdss-dsi-bl-pmic-control-type:	A string that specifies the implementation of backlight
 					control for this panel.
 					"bl_ctrl_pwm" = Backlight controlled by PWM gpio.
@@ -142,6 +145,8 @@
 					0 = default value.
 - qcom,mdss-dsi-bl-max-level:		Specifies the max backlight level supported by the panel.
 					255 = default value.
+- qcom,mdss-brightness-max-level:	Specifies the max brightness level supported.
+					255 = default value.
 - qcom,mdss-dsi-interleave-mode:	Specifies interleave mode.
 					0 = default value.
 - qcom,mdss-dsi-panel-type:		Specifies the panel operating mode.
@@ -154,15 +159,9 @@
 					1 = TE through TE gpio pin. (default)
 - qcom,mdss-dsi-te-dcs-command:		Inserts the dcs command.
 					1 = default value.
-- qcom,mdss-dsi-te-v-sync-rd-ptr-irq-line:	Configures the scan line number that the dsi
-					pixel transfer will start on. Rasing this number
-					will result in delaying the start of the pixel
-					transfer.
+- qcom,mdss-dsi-wr-mem-start:		DCS command for write_memory_start.
 					0x2c = default value.
-- qcom,mdss-dsi-te-v-sync-continue-lines:	Represents the difference in number of lines
-					between estimated read pointer and write pointer
-					to allow the updating of all the lines except
-					the first line of the frame.
+- qcom,mdss-dsi-wr-mem-continue:	DCS command for write_memory_continue.
 					0x3c = default value.
 - qcom,mdss-dsi-h-sync-pulse:		Specifies the pulse mode option for the panel.
 					0 = Don't send hsa/he following vs/ve packet(default)
@@ -255,6 +254,40 @@
 					mode. This master delay (t_init_delay as per DSI spec) should be sum
 					of DSI internal delay to reach fuctional after power up and minimum
 					delay required by panel to reach functional.
+- 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.
@@ -305,8 +338,8 @@
 		qcom,mdss-dsi-te-check-enable;
 		qcom,mdss-dsi-te-using-te-pin;
 		qcom,mdss-dsi-te-dcs-command = <1>;
-		qcom,mdss-dsi-te-v-sync-continue-lines = <0x3c>;
-		qcom,mdss-dsi-te-v-sync-rd-ptr-irq-line = <0x2c>;
+		qcom,mdss-dsi-wr-mem-continue = <0x3c>;
+		qcom,mdss-dsi-wr-mem-start = <0x2c>;
 		qcom,mdss-dsi-te-pin-select = <1>;
 		qcom,mdss-dsi-h-sync-pulse = <1>;
 		qcom,mdss-dsi-hfp-power-mode;
@@ -349,5 +382,15 @@
 		qcom,mdss-dsi-reset-sequence = <1 2>, <0 10>, <1 10>;
 		qcom,mdss-dsi-lp11-init;
 		qcom,mdss-dsi-init-delay-us = <100>;
+		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-edp.txt b/Documentation/devicetree/bindings/fb/mdss-edp.txt
index 2070c64..fd8d14f 100644
--- a/Documentation/devicetree/bindings/fb/mdss-edp.txt
+++ b/Documentation/devicetree/bindings/fb/mdss-edp.txt
@@ -26,6 +26,8 @@
 
 Optional properties:
 - qcom,cont-splash-enabled:             Boolean used to enable continuous splash mode.
+- qcom,mdss-brightness-max-level:	Specifies the max brightness level supported.
+					255 = default value.
 
 Example:
 	mdss_edp: qcom,mdss_edp@fd923400 {
diff --git a/Documentation/devicetree/bindings/fb/mdss-mdp.txt b/Documentation/devicetree/bindings/fb/mdss-mdp.txt
index 9530c62..bd11551 100644
--- a/Documentation/devicetree/bindings/fb/mdss-mdp.txt
+++ b/Documentation/devicetree/bindings/fb/mdss-mdp.txt
@@ -23,6 +23,18 @@
 				previous property, the amount of fetch ids
 				defined should match the number of offsets
 				defined in property: qcom,mdss-pipe-vig-off
+- qcom,mdss-pipe-vig-xin-id:	Array of VBIF clients ids (xins) corresponding
+				to the respective VIG pipes. Number of xin ids
+				defined should match the number of offsets
+				defined in property: qcom,mdss-pipe-vig-off
+- qcom,mdss-pipe-vig-clk-ctrl-off: Array of offsets describing clk control
+				offsets for dynamic clock gating. 1st value
+				in the array represents offset of the control
+				register. 2nd value represents bit offset within
+				control register and 3rd value represents bit
+				offset within status register. Number of tuples
+				defined should match the number of offsets
+				defined in property: qcom,mdss-pipe-vig-off
 - qcom,mdss-pipe-rgb-off:	Array of offsets for MDP source surface pipes of
 				type RGB, the offsets are calculated from
 				register "mdp_phys" defined in reg property.
@@ -34,6 +46,18 @@
 				previous property, the amount of fetch ids
 				defined should match the number of offsets
 				defined in property: qcom,mdss-pipe-rgb-off
+- qcom,mdss-pipe-rgb-xin-id:	Array of VBIF clients ids (xins) corresponding
+				to the respective RGB pipes. Number of xin ids
+				defined should match the number of offsets
+				defined in property: qcom,mdss-pipe-rgb-off
+- qcom,mdss-pipe-rgb-clk-ctrl-off: Array of offsets describing clk control
+				offsets for dynamic clock gating. 1st value
+				in the array represents offset of the control
+				register. 2nd value represents bit offset within
+				control register and 3rd value represents bit
+				offset within status register. Number of tuples
+				defined should match the number of offsets
+				defined in property: qcom,mdss-pipe-rgb-off
 - qcom,mdss-pipe-dma-off:	Array of offsets for MDP source surface pipes of
 				type DMA, the offsets are calculated from
 				register "mdp_phys" defined in reg property.
@@ -45,6 +69,18 @@
 				previous property, the amount of fetch ids
 				defined should match the number of offsets
 				defined in property: qcom,mdss-pipe-dma-off
+- qcom,mdss-pipe-dma-xin-id:	Array of VBIF clients ids (xins) corresponding
+				to the respective DMA pipes. Number of xin ids
+				defined should match the number of offsets
+				defined in property: qcom,mdss-pipe-dma-off
+- qcom,mdss-pipe-dma-clk-ctrl-off: Array of offsets describing clk control
+				offsets for dynamic clock gating. 1st value
+				in the array represents offset of the control
+				register. 2nd value represents bit offset within
+				control register and 3rd value represents bit
+				offset within status register. Number of tuples
+				defined should match the number of offsets
+				defined in property: qcom,mdss-pipe-dma-off
 - qcom,mdss-smp-data:		Array of shared memory pool data. There should
 				be only two values in this property. The first
 				value corresponds to the number of smp blocks
@@ -105,6 +141,79 @@
 				- "edp"
 				- "hdmi"
 
+Bus Scaling Data:
+- qcom,msm-bus,name:		String property describing MDSS client.
+- qcom,msm-bus,num-cases:	This is the the number of Bus Scaling use cases
+				defined in the vectors property. This must be
+				set to <3> for MDSS driver where use-case 0 is
+				used to take off MDSS BW votes from the system.
+				And use-case 1 & 2 are used in ping-pong fashion
+				to generate run-time BW requests.
+- qcom,msm-bus,active-only:	A boolean flag indicating if it is active only.
+- qcom,msm-bus,num-paths:	This represents the number of paths in each
+				Bus Scaling Usecase. This value depends on
+				how many number of AXI master ports are
+				dedicated to MDSS for particular chipset.
+- qcom,msm-bus,vectors-KBps:	* A series of 4 cell properties, with a format
+				of (src, dst, ab, ib) which is defined at
+				Documentation/devicetree/bindings/arm/msm/msm_bus.txt
+				* Current values of src & dst are defined at
+				arch/arm/mach-msm/msm_bus_board.h
+				src values allowed for MDSS are:
+					22 = MSM_BUS_MASTER_MDP_PORT0
+					23 = MSM_BUS_MASTER_MDP_PORT1
+				dst values allowed for MDSS are:
+					512 = MSM_BUS_SLAVE_EBI_CH0
+				ab: Represents aggregated bandwidth.
+				ib: Represents instantaneous bandwidth.
+				* Total number of 4 cell properties will be
+				(number of use-cases * number of paths).
+				* These values will be overridden by the driver
+				based on the run-time requirements. So initial
+				ab and ib values defined here are random and
+				bare no logic except for the use-case 0 where ab
+				and ib values needs to be 0.
+
+- qcom,mdss-prefill-outstanding-buffer-bytes: The size of mdp outstanding buffer
+				in bytes. The buffer is filled during prefill
+				time and the buffer size shall be included in
+				prefill bandwidth calculation.
+- qcom,mdss-prefill-y-buffer-bytes: The size of mdp y plane buffer in bytes. The
+				buffer is filled during prefill time when format
+				is YUV and the buffer size shall be included in
+				prefill bandwidth calculation.
+- qcom,mdss-prefill-scaler-buffer-lines-bilinear: The value indicates how many lines
+				of scaler line buffer need to be filled during
+				prefill time. If bilinear scalar is enabled, then this
+				number of lines is used to determine how many bytes
+				of scaler buffer to be included in prefill bandwidth
+				calculation.
+- qcom,mdss-prefill-scaler-buffer-lines-caf: The value indicates how many lines of
+				of scaler line buffer need to be filled during
+				prefill time. If CAF mode filter is enabled, then
+				this number of lines is used to determine how many
+				bytes of scaler buffer to be included in prefill
+				bandwidth calculation.
+- qcom,mdss-prefill-post-scaler-buffer: The size of post scaler buffer in bytes.
+				The buffer is used to smooth the output of the
+				scaler. If the buffer is present in h/w, it is
+				filled during prefill time and the number of bytes
+				shall be included in prefill bandwidth calculation.
+- qcom,mdss-prefill-pingpong-buffer-pixels: The size of pingpong buffer in pixels.
+				The buffer is used to keep pixels flowing to the
+				panel interface. If the vertical start position of a
+				layer is in the beginning of the active area, pingpong
+				buffer must be filled during prefill time to generate
+				starting lines. The number of bytes to be filled is
+				determined by the line width, starting position,
+				byte per pixel and scaling ratio, this number shall be
+				included in prefill bandwidth calculation.
+- qcom,mdss-prefill-fbc-lines:  The value indicates how many lines are required to fill
+				fbc buffer during prefill time if FBC (Frame Buffer
+				Compressor) is enabled. The number of bytes to be filled
+				is determined by the line width, bytes per pixel and
+				scaling ratio, this number shall be included in prefill bandwidth
+				calculation.
 Optional properties:
 - vdd-cx-supply :	Phandle for vdd CX regulator device node.
 - batfet-supply :	Phandle for battery FET regulator device node.
@@ -137,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
@@ -158,6 +269,43 @@
 				applied in scenarios where panel interface can
 				be more tolerant to memory latency such as
 				command mode panels.
+- qcom,mdss-rotator-ot-limit:	This integer value indicates maximum number of pending
+				writes that can be allowed from rotator client. Default
+				value is 16 which is the maximum. This value can be
+				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
+				overcome system inefficiencies and avoid any
+				glitches. These fudge factors are expressed in
+				terms of numerator and denominator. First value
+				is numerator followed by denominator. They all
+				are optional but highly recommended.
+				Ex:
+				x = value to be fudged
+				a = numerator, default value is 1
+				b = denominator, default value is 1
+				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
+				linear format. The value tells the GPU highest memory
+				 bank bit used.
+
 Optional subnodes:
 Child nodes representing the frame buffer virtual devices.
 
@@ -186,6 +334,12 @@
 			 This property is required whenever the continuous splash
 			 screen feature is enabled for the corresponding
 			 framebuffer device.
+- qcom,mdss-fb-splash-logo-enabled:    The boolean entry enables the framebuffer
+					driver to display the splash logo image.
+					It is independent of continuous splash
+					screen feature and has no relation with
+					qcom,cont-splash-enabled entry present in
+					panel configuration.
 
 Example:
 	mdss_mdp: qcom,mdss_mdp@fd900000 {
@@ -201,6 +355,23 @@
 		qcom,max-bandwidth-low-kbps = <2300000>;
 		qcom,max-bandwidth-high-kbps = <3000000>;
 
+		/* Bus Scale Settings */
+		qcom,msm-bus,name = "mdss_mdp";
+		qcom,msm-bus,num-cases = <3>;
+		qcom,msm-bus,num-paths = <2>;
+		qcom,msm-bus,vectors-KBps =
+			<22 512 0 0>, <23 512 0 0>,
+			<22 512 0 6400000>, <23 512 0 6400000>,
+			<22 512 0 6400000>, <23 512 0 6400000>;
+
+		/* Fudge factors */
+		qcom,mdss-ab-factor = <2 1>;		/* 2 times    */
+		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>;
@@ -218,13 +389,33 @@
 						<2 2 3>,
 						<2 4 5>,
 						<2 6 7>;
+
+		qcom,mdss-pipe-vig-xin-id = <0 4 8>;
+		qcom,mdss-pipe-rgb-xin-id = <1 5 9>;
+		qcom,mdss-pipe-dma-xin-id = <2 10>;
+
 		qcom,mdss-smp-data = <22 4096>;
 		qcom,mdss-rot-block-size = <64>;
+		qcom,mdss-rotator-ot-limit = <2>;
 		qcom,mdss-smp-mb-per-pipe = <2>;
 		qcom,mdss-pref-prim-intf = "dsi";
 		qcom,mdss-has-bwc;
 		qcom,mdss-has-decimation;
 		qcom,mdss-has-wfd-blk;
+		qcom,mdss-no-lut-read;
+
+		qcom,mdss-pipe-vig-clk-ctrl-offsets = <0x3AC 0 0>,
+						      <0x3B4 0 0>,
+						      <0x3BC 0 0>,
+						      <0x3C4 0 0>;
+
+		qcom,mdss-pipe-rgb-clk-ctrl-offsets = <0x3AC 4 8>,
+						      <0x3B4 4 8>,
+						      <0x3BC 4 8>,
+						      <0x3C4 4 8>;
+
+		qcom,mdss-pipe-dma-clk-ctrl-offsets = <0x3AC 8 12>,
+						      <0x3B4 8 12>;
 
 		qcom,mdss-ctl-off = <0x00000600 0x00000700 0x00000800
 				     0x00000900 0x0000A00>;
@@ -238,11 +429,21 @@
 		qcom,mdss-intf-off = <0x00021100 0x00021300
 					   0x00021500 0x00021700>;
 
+		/* buffer parameters to calculate prefill bandwidth */
+		qcom,mdss-prefill-outstanding-buffer-bytes = <1024>;
+		qcom,mdss-prefill-y-buffer-bytes = <4096>;
+		qcom,mdss-prefill-scaler-buffer-lines-bilinear = <2>;
+		qcom,mdss-prefill-scaler-buffer-lines-caf = <4>;
+		qcom,mdss-prefill-post-scaler-buffer-pixels = <2048>;
+		qcom,mdss-prefill-pingpong-buffer-pixels = <5120>;
+		qcom,mdss-prefill-fbc-lines = <2>;
+
 		mdss_fb0: qcom,mdss_fb_primary {
 			cell-index = <0>;
 			compatible = "qcom,mdss-fb";
 			qcom,mdss-mixer-swap;
 			qcom,mdss-fb-split = <480 240>
+			qcom,mdss-fb-splash-logo-enabled:
 		};
 	};
 
diff --git a/Documentation/devicetree/bindings/fb/msm-hdmi-tx.txt b/Documentation/devicetree/bindings/fb/msm-hdmi-tx.txt
index 8579ec0..b4bfb92 100644
--- a/Documentation/devicetree/bindings/fb/msm-hdmi-tx.txt
+++ b/Documentation/devicetree/bindings/fb/msm-hdmi-tx.txt
@@ -28,6 +28,7 @@
 - qcom,hdmi-tx-mux-sel: gpio required to toggle HDMI output between
   docking station, type A, and liquid device, type D, ports. Required
   property for liquid devices.
+- qcom,hdmi-tx-ddc-mux-sel: gpio for ddc mux select.
 - qcom,hdmi-tx-mux-en: gpio required to enable mux for HDMI output
   on liquid devices. Required property for liquid devices.
 
@@ -57,6 +58,7 @@
 		qcom,hdmi-tx-max-voltage-level = <0 0 1800000 1800000>;
 		qcom,hdmi-tx-peak-current = <0 0 1800000 0>;
 
+		qcom,hdmi-tx-ddc-mux-sel = <&pma8084_gpios 6 0>;
 		qcom,hdmi-tx-cec = <&msmgpio 31 0>;
 		qcom,hdmi-tx-ddc-clk = <&msmgpio 32 0>;
 		qcom,hdmi-tx-ddc-data = <&msmgpio 33 0>;
diff --git a/Documentation/devicetree/bindings/gpu/adreno.txt b/Documentation/devicetree/bindings/gpu/adreno.txt
index 656f3a4..ec5cfa5 100644
--- a/Documentation/devicetree/bindings/gpu/adreno.txt
+++ b/Documentation/devicetree/bindings/gpu/adreno.txt
@@ -71,6 +71,13 @@
 			   This is used to override faulty hardware readings.
 - qcom,strtstp-sleepwake:  Boolean. Enables use of GPU SLUMBER instead of SLEEP for power savings
 
+- qcom,pm-qos-latency:		Every time GPU wakes up from sleep, driver votes for
+				acceptable maximum latency to the pm-qos driver. This
+				voting demands that *CPU* can not go into a power save
+				state *if* the latency to bring CPU back into normal
+				state is more than this value.
+				Value is in microseconds.
+
 The following properties are optional as collecting data via coresight might
 not be supported for every chipset. The documentation for coresight
 properties can be found in:
diff --git a/Documentation/devicetree/bindings/hwmon/qpnp-adc-current.txt b/Documentation/devicetree/bindings/hwmon/qpnp-adc-current.txt
index 31bf540..3e6d060 100644
--- a/Documentation/devicetree/bindings/hwmon/qpnp-adc-current.txt
+++ b/Documentation/devicetree/bindings/hwmon/qpnp-adc-current.txt
@@ -9,7 +9,12 @@
 
 Required properties:
 - compatible : should be "qcom,qpnp-iadc" for Current ADC driver.
-- reg : offset and length of the PMIC Aribter register map.
+- reg : offset and length of the PMIC Arbiter register map.
+- reg-names : resource names used for the physical base address of the PMIC IADC
+	      peripheral, the SMBB_BAT_IF_TRIM_CNST_RDS register.
+	      Should be "iadc-base" for the PMIC IADC peripheral base register.
+	      Should be "batt-id-trim-cnst-rds" for reading the
+	      SMBB_BAT_IF_TRIM_CNST_RDS register.
 - address-cells : Must be one.
 - size-cells : Must be zero.
 - interrupts : The USR bank peripheral IADC interrupt.
@@ -21,6 +26,18 @@
 - qcom,rsense : Use this property when external rsense should be used
 		for current calculation and specify the units in nano-ohms.
 - qcom,iadc-poll-eoc: Use polling instead of interrupts for End of Conversion completion.
+- 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 the TypeA to read the IADC and SMBB trim register and
+				  apply the default RSENSE if conditions are met.
+			      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.
 
 Channel node
 NOTE: Atleast one Channel node is required.
diff --git a/Documentation/devicetree/bindings/hwmon/qpnp-adc-voltage.txt b/Documentation/devicetree/bindings/hwmon/qpnp-adc-voltage.txt
index ae7d039..83403ba 100644
--- a/Documentation/devicetree/bindings/hwmon/qpnp-adc-voltage.txt
+++ b/Documentation/devicetree/bindings/hwmon/qpnp-adc-voltage.txt
@@ -22,6 +22,9 @@
 
 Optional properties:
 - qcom,vadc-poll-eoc: Use polling instead of interrupts for End of Conversion completion.
+- 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.
 
 Client required property:
 - qcom,<consumer name>-vadc : The phandle to the corresponding vadc device.
@@ -49,6 +52,7 @@
 				 2 : {1, 4}
 				 3 : {1, 6}
 				 4 : {1, 20}
+				 5 : {1, 8}
 - qcom,calibration-type : Reference voltage to use for channel calibration.
 			  Channel calibration is dependendent on the channel.
 			  Certain channels like XO_THERM, BATT_THERM use ratiometric
@@ -65,6 +69,8 @@
 			3 : Returns current across 0.1 ohm resistor.
 			4 : Returns XO thermistor voltage in degree's Centigrade.
 			5 : Returns result in degC for 150k pull-up.
+			9 : Conversion to temperature based on -15~55 allowable
+			    battery charging tempeature setting for btm parameters.
 - qcom,hw-settle-time : Settling period for the channel before ADC read.
 			Select from the following unsigned int.
 			0 : 0us
diff --git a/Documentation/devicetree/bindings/i2c/i2c-qup.txt b/Documentation/devicetree/bindings/i2c/i2c-qup.txt
index fd7b635..fd96908 100644
--- a/Documentation/devicetree/bindings/i2c/i2c-qup.txt
+++ b/Documentation/devicetree/bindings/i2c/i2c-qup.txt
@@ -36,6 +36,10 @@
 		      callbacks.
  - qcom,master-id    : Master endpoint number used for voting on clocks using
 		      bus-scaling driver.
+ - qcom,clk-ctl-xfer : When present, the clocks's state (prepare_enable/
+		      unprepare_disable) is controlled by i2c-transaction's
+		      begining and ending. When missing, the clock's state
+		      is controlled by runtime-pm events.
 
 Example:
 	i2c_3: i2c@f9966000 {
@@ -47,6 +51,7 @@
 		interrupt-names = "qup_err_intr";
 		qcom,i2c-bus-freq = <100000>;
 		qcom,i2c-src-freq = <24000000>;
+		qcom,clk-ctl-xfer;
 		qcom,scl-gpio = <&msmgpio 7 0>;
 		qcom,sda-gpio = <&msmgpio 6 0>;
 	};
diff --git a/Documentation/devicetree/bindings/input/misc/hbtp_input.txt b/Documentation/devicetree/bindings/input/misc/hbtp_input.txt
new file mode 100644
index 0000000..54643c7
--- /dev/null
+++ b/Documentation/devicetree/bindings/input/misc/hbtp_input.txt
@@ -0,0 +1,14 @@
+Platform device for Host Based Touch Processing (hbtp)
+
+Required properties:
+
+ - compatible		: should be "qcom,hbtp"
+ - vcc_ana-supply	: Analog power supply needed to power device
+
+Example:
+	&soc {
+		hbtp {
+			compatible = "qcom,hbtp";
+			vcc_ana-supply = <&pm8941_l18>;
+		};
+	};
diff --git a/Documentation/devicetree/bindings/input/misc/mma8x5x.txt b/Documentation/devicetree/bindings/input/misc/mma8x5x.txt
index 854939c..7e5d3a4 100644
--- a/Documentation/devicetree/bindings/input/misc/mma8x5x.txt
+++ b/Documentation/devicetree/bindings/input/misc/mma8x5x.txt
@@ -22,6 +22,7 @@
  - interrupt-parent	: parent of interrupt.
  - interrupts		: sensor signal interrupt to indicate new data ready or
 				 a motion is detected.
+ - fsl,use-interrupt	: to enable interrupt mode.
  - fsl,irq-gpio	: First irq gpio which is to provide interrupts to host, same
 				 as "interrupts" node. It will also contain active low or active
 				 high information.
@@ -36,4 +37,5 @@
 		vio-supply = <&pm8110_l14>;
 		fsl,sensors-position = <5>;
 		fsl,irq-gpio = <&msmgpio 0x81 0x02>;
+		fsl,use-interrupt;
 	};
\ No newline at end of file
diff --git a/Documentation/devicetree/bindings/input/touchscreen/gt9xx/gt9xx.txt b/Documentation/devicetree/bindings/input/touchscreen/gt9xx/gt9xx.txt
index f2ca95b..ba61a2f 100644
--- a/Documentation/devicetree/bindings/input/touchscreen/gt9xx/gt9xx.txt
+++ b/Documentation/devicetree/bindings/input/touchscreen/gt9xx/gt9xx.txt
@@ -29,7 +29,7 @@
 				It is a four tuple consisting of min x,
 				min y, max x and max y values.
  - goodix,i2c-pull-up	: To specify pull up is required.
- - goodix,no-force-update	: To specify force update is allowed.
+ - goodix,force-update	: To specify force update is allowed.
  - goodix,enable-power-off	: Power off touchscreen during suspend.
  - goodix,button-map	: Button map of key codes. The number of key codes
 				depend on panel.
@@ -52,6 +52,12 @@
  - goodix,cfg-data5	: Touch screen controller config data group 5. Ask vendor
 				to provide that.
  - goodix,fw-name	: Touch screen controller firmware file name.
+ - goodix,slide-wakeup	: To specify slide-wakeup property is enabled or not.
+ - goodix,dbl-clk-wakeup	: To specify dbl-clk-wakeup property is enabled or not.
+ - goodix,change-x2y	: To specify change-x2y property is enabled or not.
+ - goodix,driver-send-cfg	: To specify driver-send-cfg property is enabled or not.
+ - goodix,have-touch-key	: To specify have-touch-key property is enabled or not.
+ - goodix,with-pen	: To specify with-pen property is enabled or not.
 Example:
 i2c@f9927000 {
 		goodix@5d {
@@ -87,5 +93,7 @@
 				FF FF FF FF FF FF FF 22 22 22
 				22 22 22 FF 07 01];
 			goodix,fw_name = "gtp_fw.bin";
+			goodix,have-touch-key;
+			goodix,driver-send-cfg;
 		};
 };
diff --git a/Documentation/devicetree/bindings/leds/leds-qpnp.txt b/Documentation/devicetree/bindings/leds/leds-qpnp.txt
index 749c594..1aca300 100644
--- a/Documentation/devicetree/bindings/leds/leds-qpnp.txt
+++ b/Documentation/devicetree/bindings/leds/leds-qpnp.txt
@@ -52,13 +52,15 @@
 RGB Led is a tri-colored led, Red, Blue & Green.
 
 Required properties for RGB led:
-- qcom,mode: mode the led should operate in, options "pwm" and "lpg"
-- qcom,pwm-channel: pwm channel the led will operate on
+- qcom,mode: mode the led should operate in, options "pwm" and "lpg". "manual" mode is not supported for RGB led.
 
 Required properties for PWM mode only:
+- qcom,pwm-channel: pwm channel the led will operate on
 - qcom,pwm-us: time the pwm device will modulate at (us)
 
 Required properties for LPG mode only:
+- qcom,pwm-channel: pwm channel the led will operate on
+- qcom,pwm-us: time the pwm device will modulate at (us)
 - qcom,duty-pcts: array of values for duty cycle to go through
 - qcom,start-idx: starting point duty-pcts array
 
@@ -93,6 +95,7 @@
 
 Required properties for LPG mode only:
 - qcom,pwm-channel: pwm channel the led will operate on
+- qcom,pwm-us: time the pwm device will modulate at (us)
 - qcom,duty-pcts: array of values for duty cycle to go through
 - qcom,start-idx: starting point duty-pcts array
 
@@ -106,9 +109,7 @@
 and the required rows are enabled by specifying values in the properties.
 
 Required properties for keypad backlight:
-- qcom,mode: mode the led should operate in, options "pwm" and "lpg"
-- qcom,pwm-channel: pwm channel the led will operate on
-- qcom,pwm-us: time the pwm device will modulate at (us)
+- qcom,mode: mode the led should operate in, options "pwm" and "lpg". "manual" mode is not supported for keypad backlight.
 - qcom,row-id: specify the id of the row. Supported values are 0 to 3.
 
 Optional properties for keypad backlight:
@@ -118,9 +119,12 @@
 - qcom,always-on: specify if the module has to be always on
 
 Required properties for PWM mode only:
+- qcom,pwm-channel: pwm channel the led will operate on
 - qcom,pwm-us: time the pwm device will modulate at (us)
 
 Required properties for LPG mode only:
+- qcom,pwm-channel: pwm channel the led will operate on
+- qcom,pwm-us: time the pwm device will modulate at (us)
 - qcom,duty-pcts: array of values for duty cycle to go through
 - qcom,start-idx: starting point duty-pcts array
 
@@ -201,6 +205,7 @@
 			linux,name = "led:rgb_green";
 			qcom,mode = "lpg";
 			qcom,pwm-channel = <5>;
+			qcom,pwm-us = <1000>;
 			qcom,duty-ms = <20>;
 			qcom,start-idx = <1>;
 			qcom,idx-len = <10>;
diff --git a/Documentation/devicetree/bindings/media/video/msm-cci.txt b/Documentation/devicetree/bindings/media/video/msm-cci.txt
index 317c078..f256d78 100644
--- a/Documentation/devicetree/bindings/media/video/msm-cci.txt
+++ b/Documentation/devicetree/bindings/media/video/msm-cci.txt
@@ -48,6 +48,7 @@
 
 Required properties:
 - compatible : should be manufacturer name followed by sensor name
+    - "qcom,camera"
     - "qcom,s5k3l1yx"
     - "sne,imx134"
     - "qcom,imx135"
@@ -153,6 +154,8 @@
 - qcom,vdd-cx-supply : should contain regulator from which cx voltage is
     supplied
 - qcom,vdd-cx-name : should contain names of cx regulator
+- qcom,eeprom-src : if eeprom memory is supported by this sensor, this
+   property should contain phandle of respective eeprom nodes
 
 * Qualcomm MSM ACTUATOR
 
@@ -208,6 +211,7 @@
                qcom,csiphy-sd-index = <2>;
                qcom,csid-sd-index = <0>;
                qcom,actuator-src = <&actuator0>;
+               qcom,eeprom-src = <&eeprom0 &eeprom1>;
                qcom,led-flash-src = <&led_flash0>;
                qcom,mount-angle = <90>;
                qcom,sensor-name = "s5k3l1yx";
diff --git a/Documentation/devicetree/bindings/media/video/msm-eeprom.txt b/Documentation/devicetree/bindings/media/video/msm-eeprom.txt
index c7821f5..6aa0a16 100644
--- a/Documentation/devicetree/bindings/media/video/msm-eeprom.txt
+++ b/Documentation/devicetree/bindings/media/video/msm-eeprom.txt
@@ -57,6 +57,14 @@
 - qcom,pageen%d : number %d page enable reg size, start address, address type,
     data, data type, delay in ms. size 0 stand for not used.
 - cam_vdig-supply : should contain regulator to be used for the digital vdd.
+- qcom,saddr%d : property should specify the slave address for block (%d).
+
+Optional properties -EEPROM Camera Multimodule
+- qcom,mm-data-support - Camera Multimodule data capability flag.
+- qcom,mm-data-compressed - Camera Multimodule data compresion flag.
+- qcom,mm-data-offset - Camera Multimodule data start offset.
+- qcom,mm-data-size - Camera Multimodule data size.
+
 
 Example:
 
@@ -75,6 +83,12 @@
         qcom,pageen1 = <1 0x0202 2 0x01 1 10>;
         qcom,poll1 = <0 0x0 2 0 1 1>;
         qcom,mem1 = <32 0x3000 2 0 1 0>;
+        qcom,saddr1 = <0x62>;
+
+	qcom,mm-data-support;
+	qcom,mm-data-compressed;
+	qcom,mm-data-offset = 0;
+	qcom,mm-data-size = 0;
 
         cam_vdig-supply = <&pm8226_l5>;
         cam_vio-supply = <&pm8226_lvs1>;
diff --git a/Documentation/devicetree/bindings/memory.txt b/Documentation/devicetree/bindings/memory.txt
index e98ee05..32f6a24 100644
--- a/Documentation/devicetree/bindings/memory.txt
+++ b/Documentation/devicetree/bindings/memory.txt
@@ -36,6 +36,7 @@
 	reg = <(baseaddr) (size)>;
 	(linux,contiguous-region);
 	(linux,default-contiguous-region);
+	(linux,memory-limit);
         label = (unique_name);
 };
 
@@ -48,6 +49,11 @@
 linux,default-contiguous-region: property indicating that the region
 		is the default region for all contiguous memory
 		allocations, Linux specific (optional)
+linux,memory-limit: property specifying an upper bound on the physical address
+		of the region if the region is placed dynamically. If no limit
+		is specificed, the region may be placed anywhere in the physical
+		address space. 0 may be used to specify lowmem (i.e. the region
+		will be placed in the direct mapped lowmem region)
 label:		an internal name used for automatically associating the
 		cma region with a given device. The label is optional;
 		if the label is not given the client is responsible for
diff --git a/Documentation/devicetree/bindings/mmc/sdhci-msm.txt b/Documentation/devicetree/bindings/mmc/sdhci-msm.txt
index d502f78..8c41926 100644
--- a/Documentation/devicetree/bindings/mmc/sdhci-msm.txt
+++ b/Documentation/devicetree/bindings/mmc/sdhci-msm.txt
@@ -55,6 +55,9 @@
 				   no default value that the driver assumes if this property
 				   is not specified. So if this property is not specified,
 				   then SDHC driver will not vote for PM QOS.
+        - qcom,dat1-mpm-int:    specifies MPM interrupt number (e.g. sdhc_2 node below)
+				corresponding to DAT1 line of SDHC (used only if slot has dedicated
+				DAT1 MSM pin (not GPIO))
 
 In the following, <supply> can be vdd (flash core voltage) or vdd-io (I/O voltage).
 	- qcom,<supply>-always-on - specifies whether supply should be kept "on" always.
@@ -165,4 +168,5 @@
 				<81 512 106496 212992>, /* 208 MB/s */
 				<81 512 2147483647 4294967295>; /* Max. bandwidth */
 		qcom,bus-bw-vectors-bps = <0 13631488 27262976 54525952 109051904 218103808 4294967295>;
+		qcom,dat1-mpm-int = <44>;
 	};
diff --git a/Documentation/devicetree/bindings/mtd/msm_qpic_nand.txt b/Documentation/devicetree/bindings/mtd/msm_qpic_nand.txt
index 8cef7f0..447c8c1 100644
--- a/Documentation/devicetree/bindings/mtd/msm_qpic_nand.txt
+++ b/Documentation/devicetree/bindings/mtd/msm_qpic_nand.txt
@@ -13,11 +13,12 @@
 Each partition is represented as a sub-node of the qcom,mtd-partitions device.
 Each node's name represents the name of the corresponding partition.
 
-Required properties:
-- reg : The partition offset and size
-- label : The label / name for this partition.
+This is now completely optional as the partition information is avaialble from
+bootloader.
 
 Optional properties:
+- reg : The partition offset and size
+- label : The label / name for this partition.
 - read-only: This parameter, if present, indicates that this partition
   should only be mounted read-only.
 
diff --git a/Documentation/devicetree/bindings/nfc/nfc-nci.txt b/Documentation/devicetree/bindings/nfc/nfc-nci.txt
index dca7d5c..7af847c 100644
--- a/Documentation/devicetree/bindings/nfc/nfc-nci.txt
+++ b/Documentation/devicetree/bindings/nfc/nfc-nci.txt
@@ -8,15 +8,16 @@
 - reg: NCI i2c slave address.
 - qcom,dis-gpio: specific gpio for hardware reset.
 - qcom,irq-gpio: specific gpio for read interrupt.
-- qcom,clk-src: nfc clock source ("BBCLK2", "RFCLK3", "GPCLK","GPCLK2" ...)
-- qcom,clk-en-gpio: msm gpio clock,used ony if clock source is msm gpio
-- vlogic-supply: LDO for power supply
+- qcom,clk-src: nfc clock source ("BBCLK2", "RFCLK3", "GPCLK", "GPCLK2", ...)
+- qcom,clk-src-gpio: msm gpio clock,used ony if clock source is msm gpio
+- qcom,clk-req-gpio: clk-req input gpio for MSM based clocks.
+                     not used for pmic implementation
 - interrupt-parent: Should be phandle for the interrupt controller
                     that services interrupts for this device.
-- interrupts: should contain the NFC interrupt. NFC has one read interrupt.
-- qcom,clk-gpio: pmic gpio on which bbclk2 signal is coming.
+- interrupts: Nfc read interrupt,gpio-clk-req interrupt
+- qcom,clk-gpio: pmic or msm gpio on which bbclk2 signal is coming.
 
-LDO example:
+Example:
 
 	i2c@f9925000 { /* BLSP-1 QUP-3 */
 		nfc-nci@e {
@@ -24,12 +25,11 @@
 			reg = <0x0e>;
 			qcom,irq-gpio = <&msmgpio 77 0x00>;
 			qcom,dis-gpio = <&msmgpio 93 0x00>;
-			qcom,clk-en-gpio = <&msmgpio 78 0x00>;
-			qcom,clk-src = "GPCLK";
+			qcom,clk-src-gpio = <&msmgpio 78 0x00>;
+			qcom,clk-src = "GPCLK2";
 			interrupt-parent = <&msmgpio>;
 			interrupts = <77 0>;
 			qcom,clk-gpio = <&msmgpio 75 0x00>;
-			vlogic-supply = <&pm8110_l14>;
 		};
 	};
 
diff --git a/Documentation/devicetree/bindings/platform/msm/qpnp-power-on.txt b/Documentation/devicetree/bindings/platform/msm/qpnp-power-on.txt
index 83237f9..7b70369 100644
--- a/Documentation/devicetree/bindings/platform/msm/qpnp-power-on.txt
+++ b/Documentation/devicetree/bindings/platform/msm/qpnp-power-on.txt
@@ -36,6 +36,10 @@
 				to include it more than once.
 - qcom,s3-debounce		The debounce delay for stage3 reset trigger in
 				secs. The values range from 0 to 128.
+- qcom,s3-src			The source for stage 3 reset. It can be one of
+				"kpdpwr", "resin", "kpdpwr-or-resin" or
+				"kpdpwr-and-resin". The default value is
+				"kpdpwr-and-resin".
 
 All the below properties are in the sub-node section (properties of the child
 node).
@@ -92,6 +96,7 @@
 		qcom,pon-dbc-delay = <15625>;
 		qcom,system-reset;
 		qcom,s3-debounce = <32>;
+		qcom,s3-src = "resin";
 
 		qcom,pon_1 {
 			qcom,pon-type = <0>;
diff --git a/Documentation/devicetree/bindings/power/qpnp-charger.txt b/Documentation/devicetree/bindings/power/qpnp-charger.txt
index 7d8fe0a..87ecc64 100644
--- a/Documentation/devicetree/bindings/power/qpnp-charger.txt
+++ b/Documentation/devicetree/bindings/power/qpnp-charger.txt
@@ -103,6 +103,13 @@
 - qcom,use-external-rsense		A boolean that controls whether BMS will use
 					an external sensor resistor instead of the default
 					RDS of the batfet.
+- qcom,vbatdet-maxerr-mv		This property in mV is a hystersis value for the charge
+					resume voltage property qcom,vbatdet-delta-mv. If this
+					property is not defined it defaults to 50 mV.
+- qcom,parallel-ovp-mode		When this option is enabled, it allows charging through both
+					DC and USB OVP FETs. Please note that this should only
+					be enabled in board designs with PM8941 which have DC_IN
+					and USB_IN connected via a short.
 
 Sub node required structure:
 - A qcom,chg node must be a child of an SPMI node that has specified
diff --git a/Documentation/devicetree/bindings/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/qseecom/qseecom.txt b/Documentation/devicetree/bindings/qseecom/qseecom.txt
index ac82387..c0426a7 100644
--- a/Documentation/devicetree/bindings/qseecom/qseecom.txt
+++ b/Documentation/devicetree/bindings/qseecom/qseecom.txt
@@ -4,6 +4,7 @@
 - compatible : Should be "qcom,qseecom"
 - reg : should contain memory region address reserved for loading secure apps.
 - qcom,disk-encrypt-pipe-pair : indicates what CE HW pipe pair is used for disk encryption
+- qcom,file-encrypt-pipe-pair : indicates what CE HW pipe pair is used for file encryption
 - qcom,hlos-ce-hw-instance : indicates what CE HW is used by HLOS crypto driver
 - qcom,qsee-ce-hw-instance : indicates what CE HW is used by secure domain (TZ) crypto driver
 - qcom, msm_bus,name: Should be "qseecom-noc"
@@ -11,14 +12,22 @@
 - qcom, msm_bus,num_paths: The paths for source and destination ports
 - qcom, msm_bus,vectors: Vectors for bus topology.
 
+Optional properties:
+  - qcom,support-bus-scaling : indicates if driver support scaling the bus for crypto operation.
+  - qcom,support-fde : indicates if driver support key managing for full disk encryption feature.
+  - qcom,support-pfe : indicates if driver support key managing for per file encryption feature.
+
 Example:
 	qcom,qseecom@fe806000 {
 		compatible = "qcom,qseecom";
 		reg = <0x7f00000 0x500000>;
 		reg-names = "secapp-region";
                 qcom,disk-encrypt-pipe-pair = <2>;
+                qcom,file-encrypt-pipe-pair = <0>;
 		qcom,hlos-ce-hw-instance = <1>;
 		qcom,qsee-ce-hw-instance = <0>;
+		qcom,support-fde;
+		qcom,support-pfe;
 		qcom,msm_bus,name = "qseecom-noc";
 		qcom,msm_bus,num_cases = <4>;
 		qcom,msm_bus,active_only = <0>;
diff --git a/Documentation/devicetree/bindings/regulator/fan53555.txt b/Documentation/devicetree/bindings/regulator/fan53555.txt
new file mode 100644
index 0000000..57b54d6
--- /dev/null
+++ b/Documentation/devicetree/bindings/regulator/fan53555.txt
@@ -0,0 +1,50 @@
+Fairchild Semiconductor FAN53555 regulator
+
+The FAN53555 is a step-down switching voltage regulator that delivers a
+digitally programmable output from an input voltage supply of 2.5 V to 5.5 V.
+The output voltage is programmed through an I2C interface capable of operating
+up to 3.4 MHz.
+
+The fan53555 interface is via I2C bus.
+
+Required Properties:
+- compatible:			Must be "fairchild,fan53555-regulator".
+- reg:				The device 8-bit I2C address.
+- fairchild,backup-vsel:	Register ID of backup register.
+				Supported values are 0 or 1.
+				The voltage selection ID used while the system
+				is active will be the other option not used
+				during running.
+- regulator-min-microvolt:	Minimum voltage in microvolts supported by this
+				regulator.
+- regulator-max-microvolt:	Maximum voltage in microvolts supported by this
+				regulator.
+- regulator-ramp-delay:		The slew rate of the regulator, in uV/us.
+				Supported values are 64000, 32000, 16000,
+				8000, 4000, 2000, 1000 and 500.
+
+Optional Properties:
+- fairchild,vsel-gpio:		Present: GPIO connects to the VSEL pin and set
+				the output.
+				Not Present: No GPIO is connected to vsel pin.
+- fairchild,restore-reg:	Present: Restore vsel register from backup
+				register.
+				Not Present: No restore.
+- fairchild,disable-suspend:	Present: Disable regulator suspend method.
+				Not Present: Do not disable regulator suspend
+				method.
+
+Example:
+	i2c_0 {
+		fan53555-regulator@60 {
+			compatible = "fairchild,fan53555-regulator";
+			reg = <0x60>;
+			fairchild,backup-vsel = <1>;
+			regulator-min-microvolt = <1050000>;
+			regulator-max-microvolt = <1350000>;
+			regulator-ramp-delay = <8000>;
+			fairchild,vsel-gpio = <&msmgpio 2 1>;
+			fairchild,restore-reg;
+			fairchild,disable-suspend;
+		};
+	};
diff --git a/Documentation/devicetree/bindings/regulator/krait-regulator.txt b/Documentation/devicetree/bindings/regulator/krait-regulator.txt
index 7c661fe..004c4df 100644
--- a/Documentation/devicetree/bindings/regulator/krait-regulator.txt
+++ b/Documentation/devicetree/bindings/regulator/krait-regulator.txt
@@ -22,7 +22,12 @@
 				the phase scaling factor eFuse address.
 - qcom,pfm-threshold		The power coeff threshold in abstract power units below which
 				pmic will be made to operate in PFM mode.
-
+- qcom,phase-scaling-factor-bits-pos	indicates bit position of scaling factor data within the efuse
+					register.
+- qcom,valid-scaling-factor-versions	This is an array holding four boolean values and indicates whether
+					the version read from efuses is valid.
+					The version is a two bit field and the value read from hardware is
+					used as an index in this array to check for validity.
 Optional properties:
 - qcom,use-phase-switching	indicates whether the driver should add/shed phases on the PMIC
 				ganged regulator as cpus are hotplugged.
@@ -70,6 +75,9 @@
 		qcom,use-phase-switching;
 		qcom,use-phase-scaling-factor;
 		qcom,pfm-threshold = <376975>;
+		qcom,phase-scaling-factor-bits-pos = <18>;
+		qcom,valid-scaling-factor-versions = <0 1 1 0>;
+
 		#address-cells = <1>;
 		#size-cells = <1>;
 		ranges;
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/regulator/onsemi-ncp6335d.txt b/Documentation/devicetree/bindings/regulator/onsemi-ncp6335d.txt
new file mode 100644
index 0000000..648cb11
--- /dev/null
+++ b/Documentation/devicetree/bindings/regulator/onsemi-ncp6335d.txt
@@ -0,0 +1,71 @@
+ON Semiconductor NCP6335d regulator
+
+NCP6335d is able to deliver up to 5.0 A, with programmable output voltage from
+0.6 V to 1.87 V in 10mV steps, with synchronous rectification and automatic PWM/
+PFM transitions, enable pins and power good/fail signaling.
+
+The NCP6335d interface is via I2C bus.
+
+Required Properties:
+- compatible:			Must be "onnn,ncp6335d-regulator".
+- reg:				The device 8-bit I2C address.
+- regulator-min-microvolt:	Minimum voltage in microvolts supported by this
+				regulator.
+- regulator-max-microvolt:	Maximum voltage in microvolts supported by this
+				regulator.
+- onnn,min-setpoint:		Minimum setpoint voltage in microvolts supported
+				by this regulator.
+- onnn,step-size:		The step size of the regulator, in uV.
+- onnn,min-slew-ns:		Minimum time in ns needed to change voltage by
+				one step size. This value corresponds to DVS
+				mode bit of 00b in command register.
+- onnn,max-slew-ns:		Maximum time in ns needed to change voltage by
+				one step size. This value corresponds to DVS
+				mode bit of 11b in command register.
+- onnn,vsel:			Working vsel register. Supported value are 0
+				or 1.
+- onnn,slew-ns:			Time in ns needed to change voltage by one step
+				size. Supported value are 333, 666, 1333, 2666.
+
+Optional Properties:
+- onnn,discharge-enable:	Present: discharge enabled.
+				Not Present: discharge disabled.
+- onnn,restore-reg:		Present: Restore vsel register from backup register.
+				Not Present: No restore.
+- onnn,vsel-gpio:		Present: GPIO connects to the VSEL pin and set the
+				VSEL pin according to device tree flag.
+				Not Present: No GPIO is connected to vsel pin.
+- onnn,sleep-enable:		Present: Forced in sleep mode when EN and VSEL
+				pins are low.
+				Not Present: Low quiescent current mode when EN and VSEL
+				pins are low.
+- onnn,tlmm-config:		Array of 2 elements to indicate the mask value and the value
+				to write in the masked bits.
+				This property is used to allow the VSEL GPIO to toggle on certain
+				Qualcomm processors. If it is not specified, then no register write is required.
+				The 2 elements with index[0..1] are:
+				[0] => the mask value;
+				[1] => the value to write into the masked bits.
+- onnn,mode:			A string which specifies the initial mode to use for the regulator.
+				Supported values are "pwm" and "auto". PWM mode is more
+				robust, but draws more current than auto mode. If this propery
+				is not specified, then the regulator will be in the hardware default mode.
+
+Example:
+	i2c_0 {
+		ncp6335d-regulator@1c {
+			compatible = "onnn,ncp6335d-regulator";
+			reg = <0x1c>;
+			onnn,vsel = <0>;
+			onnn,slew-rate-ns = <2666>;
+			onnn,discharge-enable;
+			onnn,step-size = <10000>;
+			onnn,min-slew-ns = <333>;
+			onnn,max-slew-ns = <2666>;
+
+			regulator-min-microvolt = <1050000>;
+			regulator-max-microvolt = <1350000>;
+			onnn,min-setpoint = <600000>;
+			onnn,vsel-gpio = <&msmgpio 2 1>;
+		};
+	};
diff --git a/Documentation/devicetree/bindings/slimbus/slim-msm-ctrl.txt b/Documentation/devicetree/bindings/slimbus/slim-msm-ctrl.txt
index 64f2ddd..d25b456 100644
--- a/Documentation/devicetree/bindings/slimbus/slim-msm-ctrl.txt
+++ b/Documentation/devicetree/bindings/slimbus/slim-msm-ctrl.txt
@@ -54,7 +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 provides the identifier of slimbus component on
+		 external mdm. This property enables the slimbus driver to
+		 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/sound/qcom-audio-dev.txt b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
index 6277054..401a2ec 100644
--- a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
+++ b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
@@ -140,6 +140,7 @@
                             FM Rx and TX port ID values from 12292 to 12293
                             incall record Rx and TX port ID values from 32771 to 32772
                             inCall Music Delivery port ID is 32773
+                            incall Music 2 Delivery port ID is 32770
 
 * msm-auxpcm
 
@@ -376,6 +377,11 @@
 			compatible = "qcom,msm-dai-q6-dev";
 			qcom,msm-dai-q6-dev-id = <32773>;
 		};
+
+		qcom,msm-dai-q6-incall-music-2-rx {
+			compatible = "qcom,msm-dai-q6-dev";
+			qcom,msm-dai-q6-dev-id = <32770>;
+		};
 	};
 
 	qcom,msm-pri-auxpcm {
@@ -461,7 +467,11 @@
 			    codec.
 - qcom,mbhc-bias-internal: Flag to indicate if internal micbias should be used
 			   for headset detection.
-
+- qcom,mbhc-audio-jack-type : String to indicate the jack type on the hardware.
+		Possible Values:
+		4-pole-jack : Jack on the hardware is 4-pole.
+		5-pole-jack : Jack on the hardware is 5-pole.
+		6-pole-jack : Jack on the hardware is 6-pole.
 * APQ8074 ASoC Machine driver
 
 Required properties:
@@ -518,6 +528,7 @@
 	qcom,sec-auxpcm-gpio-sync = <&msmgpio 80 0>;
 	qcom,sec-auxpcm-gpio-din  = <&msmgpio 81 0>;
 	qcom,sec-auxpcm-gpio-dout = <&msmgpio 82 0>;
+	qcom,mbhc-audio-jack-type = "4-pole-jack";
 };
 
 * msm-dai-mi2s
diff --git a/Documentation/devicetree/bindings/sound/voice-svc.txt b/Documentation/devicetree/bindings/sound/voice-svc.txt
new file mode 100644
index 0000000..deca7f5
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/voice-svc.txt
@@ -0,0 +1,11 @@
+* Voice Service binding
+
+Required properties:
+- compatible : "qcom,msm-voice-svc"
+
+Example:
+
+	qcom,msm-voice-svc {
+		compatible = "qcom,msm-voice-svc";
+	};
+
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/thermal/qpnp-adc-tm.txt b/Documentation/devicetree/bindings/thermal/qpnp-adc-tm.txt
index e1681ca..415a3ef 100644
--- a/Documentation/devicetree/bindings/thermal/qpnp-adc-tm.txt
+++ b/Documentation/devicetree/bindings/thermal/qpnp-adc-tm.txt
@@ -26,6 +26,12 @@
 		to set temperature thresholds and receive notification when the temperature
 		crosses a set threshold, read temperature and enable/set trip types supported
 		by the thermal framework.
+- qcom,meas-interval-timer-idx: If present select from the following timer index to choose
+		a preset configurable measurement interval timer value. The driver defaults
+		to timer 1 with a measurement interval of 1 second if the property is not present.
+		0 : Select Timer 1 for a measurement polling interval of 1 second.
+		1 : Select Timer 2 for a measurement polling interval of 500ms.
+		2 : Select Timer 3 for a measurement polling interval of 4 seconds.
 
 Client required property:
 - qcom,<consumer name>-adc_tm : The phandle to the corresponding adc_tm device.
@@ -53,6 +59,7 @@
 				 2 : pre-div ratio of {1, 4}
 				 3 : pre-div ratio of {1, 6}
 				 4 : pre-div ratio of {1, 20}
+				 5 : pre-div ratio of {1, 8}
 - qcom,calibration-type : Reference voltage to use for channel calibration.
 			  Channel calibration is dependendent on the channel.
 			  Certain channels like XO_THERM, BATT_THERM use ratiometric
diff --git a/Documentation/devicetree/bindings/usb/ice40-hcd.txt b/Documentation/devicetree/bindings/usb/ice40-hcd.txt
new file mode 100644
index 0000000..43d24dc
--- /dev/null
+++ b/Documentation/devicetree/bindings/usb/ice40-hcd.txt
@@ -0,0 +1,45 @@
+ICE40 FPGA based SPI-USB bridge
+
+Documentation/devicetree/bindings/spi/spi-bus.txt provides the details
+of the required and optional properties of a SPI slave device node.
+
+The purpose of this document is to provide the additional properties
+that are required to use the ICE40 FPGA based SPI slave device as a
+USB host controller.
+
+Required properties:
+- compatible : should be "lattice,ice40-spi-usb"
+- <supply-name>-supply: handle to the regulator device tree node
+  Required "supply-name" is "core-vcc" and "spi-vcc"
+- reset-gpio: gpio used to assert the bridge chip reset
+- slave-select-gpio: gpio used to select the slave during configuration
+  loading
+- config-done-gpio: gpio used to indicate the configuration status
+- vcc-en-gpio: gpio used to enable the chip power supply
+
+Optional properties:
+- interrupts: IRQ lines used by this controller
+- clk-en-gpio: gpio used to enable the 19.2 MHZ clock to the bridge
+  chip. If it is not present, assume that the clock is available on
+  the bridge chip board.
+- <supply-name>-supply: handle to the regulator device tree node
+  Optional "supply-name" is "gpio" used to power up the gpio bank
+  used by this device
+
+	spi@f9923000 {
+		lattice,spi-usb@3 {
+			compatible = "lattice,ice40-spi-usb";
+			reg = <3>;
+			spi-max-frequency = <50000000>;
+			spi-cpol = <1>;
+			spi-cpha = <1>;
+			interrupt-parent = <&msmgpio>;
+			interrupts = <121 0x8>;
+			core-vcc-supply = <&pm8226_l2>;
+			spi-vcc-supply = <&pm8226_l5>;
+			lattice,reset-gpio = <&msmgpio 114 0>;
+			lattice,slave-select-gpio = <&msmgpio 118 0>;
+			lattice,config-done-gpio = <&msmgpio 115 0>;
+			lattice,vcc-en-gpio = <&msmgpio 117 0>;
+		};
+	};
diff --git a/Documentation/devicetree/bindings/usb/msm-ehci-hsic.txt b/Documentation/devicetree/bindings/usb/msm-ehci-hsic.txt
index 24f21b4..6562607 100644
--- a/Documentation/devicetree/bindings/usb/msm-ehci-hsic.txt
+++ b/Documentation/devicetree/bindings/usb/msm-ehci-hsic.txt
@@ -131,15 +131,24 @@
 
 Required properties :
 - compatible : should be "qcom,hsic-smsc-hub"
-- smsc,model-id : should be either <3503> or <4604> depending on hub model
-- smsc,<gpio-name>-gpio : handle to the GPIO node, see "gpios property"
-  in Documentation/devicetree/bindings/gpio/gpio.txt.
-  Required "gpio-name" is "reset" and optionally - "refclk", "int".
-- <supply-name>-supply: handle to the regulator device tree node
-  Required "supply-name" is "hub_init" and optionally - "hub_vbus".
+- smsc,model-id : should be <3502>/<3503>/<4604> depending on hub model. It
+  will be 0 for standalone HSIC controller configuration.
+- smsc,reset-gpio: this output gpio is used to assert/de-assert the hub reset
 - Sub node for "MSM HSIC EHCI controller".
   Sub node has the required properties mentioned above.
 
+Optional properties :
+- smsc,int-gpio: this input gpio indicate HUB suspend status and signal remote
+  wakeup interrupt
+- smsc,refclk-gpio: this gpio is used to supply the reference clock
+- smsc,xo-clk-gio: this output gpio is used to control the external XO clock
+  which is supplied to the hub as a reference clock
+- hub-vbus-supply: this regulator is used to supply the power to
+  downstream ports
+- hub-int-supply: this regulator is used to bias the interrupt gpio
+- ext-hub-vddio-supply: this regulator is used to supply the power to one of
+  the hub's VDD.
+
 Example SMSC HSIC HUB :
 	hsic_hub {
 		compatible = "qcom,hsic-smsc-hub";
@@ -148,8 +157,8 @@
 		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 = <&pm8941_mvs1>;
+		hub-int-supply = <&pm8941_l10>;
+		hub-vbus-supply = <&pm8941_mvs1>;
 
 		hsic@f9a00000 {
 			compatible = "qcom,hsic-host";
diff --git a/Documentation/devicetree/bindings/usb/msm-hsusb.txt b/Documentation/devicetree/bindings/usb/msm-hsusb.txt
index 623a23c..979819f 100644
--- a/Documentation/devicetree/bindings/usb/msm-hsusb.txt
+++ b/Documentation/devicetree/bindings/usb/msm-hsusb.txt
@@ -93,6 +93,8 @@
 	enable this feature without proper bus voting.
 -qcom,disable-retention-with-vdd-min: If present dont allow phy retention but allow
 	vdd min.
+- 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.
 
 Example HSUSB OTG controller device node :
 	usb@f9690000 {
@@ -120,6 +122,7 @@
 		qcom,disable-retention-with-vdd-min;
 		qcom,hsusb-otg-dpsehv-int = <49>;
 		qcom,hsusb-otg-dmsehv-int = <58>;
+		qcom,usbin-vadc = <&pm8226_vadc>;
 		qcom,msm_bus,name = "usb2";
 		qcom,msm_bus,num_cases = <2>;
 		qcom,msm_bus,active_only = <0>;
@@ -156,6 +159,7 @@
   and no peripheral connected over dock during low power mode, fourth value represents
   minimum value to vote when USB is operational, fifth item represents maximum value
   to vote for USB is operational.
+- qcom,usb2-enable-uicc: If present, usb2 port will be used for uicc card connection.
 
 Example MSM HSUSB EHCI controller device node :
 	ehci: qcom,ehci-host@f9a55000 {
@@ -169,6 +173,7 @@
 		qcom,usb2-enable-hsphy2;
 		qcom,usb2-power-budget = <500>;
 		qcom,vdd-voltage-level = <1 2 3 5 7>;
+		qcom,usb2-enable-uicc;
 	};
 
 ANDROID USB:
@@ -191,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 a7a646d..d2f03ea 100644
--- a/Documentation/devicetree/bindings/usb/msm-ssusb.txt
+++ b/Documentation/devicetree/bindings/usb/msm-ssusb.txt
@@ -58,6 +58,10 @@
 		for TX fifo allocation in QDSS composition
 - qcom,dwc-ssphy-deemphasis-value: This property if present represents ss phy
   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".
@@ -85,6 +89,7 @@
 		qcom,dwc-usb3-msm-tx-fifo-size = <29696>;
 		qcom,dwc-usb3-msm-qdss-tx-fifo-size = <16384>;
 		qcom,dwc-ssphy-deemphasis-value = <26>;
+		qcom,usbin-vadc = <&pm8941_vadc>;
 
 		qcom,msm_bus,name = "usb3";
 		qcom,msm_bus,num_cases = <2>;
diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
index 35e7324..440dac1 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.txt
+++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
@@ -8,6 +8,7 @@
 apm	Applied Micro Circuits Corporation (APM)
 arm	ARM Ltd.
 atmel	Atmel Corporation
+avago	Avago Technologies
 bosch	Bosch Sensortec GmbH
 capella	Capella Microsystems, Inc.
 cavium	Cavium, Inc.
@@ -17,6 +18,7 @@
 denx	Denx Software Engineering
 epson	Seiko Epson Corp.
 est	ESTeem Wireless Modems
+fairchild	Fairchild Semiconductor International, Inc.
 focaltech Focaltech systems
 fsl	Freescale Semiconductor
 GEFanuc	GE Fanuc Intelligent Platforms Embedded Systems, Inc.
@@ -27,6 +29,7 @@
 idt	Integrated Device Technologies, Inc.
 intercontrol	Inter Control Group
 invn	InvenSense Inc.
+lattice	Lattice Semiconductor.
 linux	Linux-specific binding
 kionix	Kionix Inc.
 marvell	Marvell Technology Group Ltd.
diff --git a/Documentation/usb/ice40-hcd.txt b/Documentation/usb/ice40-hcd.txt
new file mode 100644
index 0000000..54f845e
--- /dev/null
+++ b/Documentation/usb/ice40-hcd.txt
@@ -0,0 +1,247 @@
+Introduction
+============
+
+USB UICC connectivity is required for MSM8x12. This SoC has only 1 USB
+controller which is used for peripheral mode and charging. Hence an external
+USB host controller over SPI is used to connect a USB UICC card. ICE40 FPGA
+based SPI to IC-USB (Inter-Chip USB) bridge chip is used.
+
+The ICE40 Host controller driver (ice40-hcd) is registered as a SPI protocol
+driver and interacts with the SPI subsystem on one side and interacts with the
+USB core on the other side.
+
+Hardware description
+====================
+
+The ICE40 devices are SRAM-based FPGAs. The SRAM memory cells are volatile,
+meaning that once power is removed from the device, its configuration is lost
+and must be reloaded on the next power-up. An on-chip non-volatile configuration
+memory or an external SPI flash are not used to store the configuration data due
+to increased power consumption.  Instead, the software loads the configuration
+data through SPI interface after powering up the bridge chip. Once the
+configuration data is programmed successfully, the bridge chip will be ready for
+the USB host controller operations.
+
+The ICE40 device has an interrupt signal apart from the standard SPI signals
+CSn, SCLK, MOSI and MISO. It has support for 25 to 50 MHz frequencies. The
+maximum operating frequency during configuration loading is 25 MHz.
+
+The bridge chip requires two power supplies, SPI_VCC (1.8v - 3.3v) and VCC_CORE
+(1.2v). The SPI_VCC manages the SPI slave portion and VCC_CORE manages the USB
+serial engine (SIE) portion.  It requires a 19.2 MHz reference clock and a
+32 MHz clock is required for remote wakeup detection during suspend.
+
+The configuration loading sequence:
+
+- Assert the RSTn pin. This keeps bridge chip in reset state after downloading
+the configuration data.
+- The bridge chip samples the SPI interface chip select pin during power-up and
+enters SPI slave mode if it is low. Drive the chip select pin low before
+powering up the bridge chip.
+- Power-up the bridge chip by enabling SPI_VCC and VCC_CORE
+- De-assert the chip select pin after 50 usec.
+- Transfer the configuration data over SPI. Note that the bridge chip requires
+49 dummy clock cycles after sending the data.
+- The bridge chip indicates the status of the configuration loading via config
+done pin. It may take 50 usec to assert this pin.
+
+The 19.2 MHz clock should be supplied before de-asserting the RSTn pin. A PLL
+is used to generate a 48MHz clock signal that then creates a 12MHz clock signal
+by a divider. When the PLLOK bit is set in USB Transfer Result register, it
+indicates that the PLL output is locked to the input reference clock. When it
+is 0, it indicates that the PLL is out of lock. It is recommended to assert the
+RSTn pin to re-synchronize the PLL to the reference clock when the PLL loses
+lock. The chip will be ready for the USB host controller operations after it is
+brought out of reset and PLL is synchronized to the reference clock.
+
+The software is responsible for initiating all the USB host transfers by writing
+the associated registers. The SIE in the bridge chip performs the USB host
+operations via the IC-USB bus based on the registers set by the software. The
+USB transfer results as well as the bus status like the peripheral connection,
+disconnection, resume, etc. are notified to software through the interrupt and
+the internal registers.
+
+The bridge chip provides the DP & DM pull-down resistor control to the software.
+The pull-down resistors are enabled automatically after the power up to force
+the SE0 condition on the bus. The software is required to disable these
+resistors before driving the reset on the bus. Control, Bulk and Interrupt
+transfers are supported. The data toggling states are not maintained in the
+hardware and should be serviced by the software. The bridge chip returns
+one of the following values for a USB transaction (SETUP/IN/OUT) via Transfer
+result register.
+
+xSUCCESS: Successful transfer.
+xBUSY: The SIE is busy with a USB transfer.
+xPKTERR: Packet Error (stuff, EOP).
+xPIDERR: PID check bits are incorrect.
+xNAK: Device returned NAK. This is not an error condition for IN/OUT. But it
+is an error condition for SETUP.
+xSTALL: Device returned STALL.
+xWRONGPID: Wrong PID is received. For example a IN transaction is attempted on
+OUT endpoint.
+xCRCERR: CRC error.
+xTOGERR: Toggle bit error. The SIE returns ACK when the toggle mismatch happens
+for IN transaction  and returns this error code. Software should discard the
+data as it was received already in the previous transaction.
+xBADLEN: Too big packet size received.
+xTIMEOUT: Device failed to respond in time.
+
+Software description
+====================
+
+This driver is compiled as a module and is loaded by the userspace after
+getting the UICC card insertion event from the modem processor. The module is
+unloaded upon the UICC card removal.
+
+This driver registers as a SPI protocol driver. The SPI controller driver
+manages the chip select pin. This pin needs to be driven low before powering
+up the bridge chip. Hence this pin settings are overridden temporarily during
+the bridge chip power-up sequence. The original settings are restored before
+sending the configuration data to the bridge chip which acts as a SPI slave.
+Both pinctl and gpiomux framework allow this type of use case.
+
+The configuration data file is stored on the eMMC card. Firmware class API
+request_firmware() is used to read the configuration data file. The
+configuration data is then sent to the bridge chip via SPI interface. The
+bridge chip asserts the config done pin once the configuration is completed.
+
+The driver registers as a Full Speed (USB 1.1) HCD. The following methods
+are implemented that are part of hc_drive struct:
+
+reset: It is called one time by the core during HCD registration. The
+default address 0 is programmed and the line state is sampled to check if any
+device is connected. If any device is connected, the port flags are updated
+accordingly. As the module is loaded after the UICC card is inserted, the
+device would be present at this time.
+
+start: This method is called one time by the core during HCD registration.
+The bridge chip is programmed to transmit the SOFs.
+
+stop: The method is called one time by the core during HCD deregistration.
+The bridge chip is programmed to stop transmitting the SOFs.
+
+hub_control: This method is called by the core to manage the Root HUB. The
+hardware does not maintain port state.  The software maintain the port
+state and provide the information to the core when required.  The following
+HUB class requests are supported.
+
+- GetHubDescriptor: The HUB descriptor is sent to the core. Only 1 port
+is present. Over current protection and port power control are not supported.
+- SetPortFeature: The device reset and suspend are supported. The The DP & DM
+pull-down resistors are disabled before driving the reset as per the IC-USB
+spec. The reset signaling is stopped when the core queries the port status.
+- GetPortStatus: The device connection status is sent to the core.  If a reset
+is in progress, it is stopped before returning the port status.
+- ClearPortFeature: The device resume (clear suspend) is supported.
+
+urb_enqueue: This method is called by the core to initiate a USB Control/Bulk
+transfer.  If the endpoint private context is not present, it will be created to
+hold the endpoint number, host endpoint structure, transaction error count, halt
+state and unlink state. The URB is attached to the endpoint URB list. If the
+endpoint is not active, it is attached to the asynchronous schedule list and the
+work is scheduled to traverse this list. The traversal algorithm is explained
+later in this document.
+
+urb_dequeue: This method is called by the core when an URB is unlinked.  If the
+endpoint is not active, the URB is unlinked immediately.  Otherwise the endpoint
+is marked for unlink and URB is unlinked from the asynchronous schedule work.
+
+bus_suspend: This method is called by the core during root hub suspend. The SOFs
+are already stopped during the port suspend which happens before root hub
+suspend. Assert the RSTn pin to put the bridge chip in reset state and stop XO
+(19.2 MHz) clock.
+
+bus_resume: This method is called by the core during root hub resume. Turn on
+the XO clock and de-assert the RSTn signal to bring the chip out of reset.
+
+endpoint_disable: This method is called by the core during the device
+disconnect. All the URB are unlinked by this time, so free the endpoint private
+structure.
+
+Asynchronous scheduling:
+
+All the active endpoints are queued to the asynchronous schedule list. A worker
+thread iterates over this circular list and process the URBs. Processing an URB
+involves initiating multiple SETUP/IN/OUT transactions and checking the result.
+After receiving the DATA/ACK, the toggle bit is inverted.
+
+A URB is finished when any of the following events occur:
+
+- The entire data is received for an OUT endpoint or a short packet is received
+for an IN endpoint.
+- The endpoint is stalled by the device. -EPIPE is returned.
+- Transaction error is occurred consecutively 3 times. -EPROTO is returned.
+- A NAK received for a SETUP transaction.
+- The URB is unlinked.
+
+The next transaction is issued on the next endpoint (if available) irrespective
+of the result of the current transaction.  But the IN/OUT transaction of data
+or status phase is attempted immediately after the SETUP transaction for a
+control endpoint. If a NAK is received for this transaction, the control
+transfer is resumed next time when the control endpoint is encountered in the
+asynchronous schedule list. This is to give the control transfers priority
+over the bulk transfers.
+
+The endpoint is marked as halted when a URB is finished due to transaction
+errors or stall condition. The halted endpoint is removed from the asynchronous
+schedule list.  It will be added again next time when a URB is enqueued on this
+endpoint.
+
+This driver provides debugfs interface and exports a file called "command" under
+<debugfs root>/ice40 directory.  The following strings can be echoed to this
+file.
+
+"poll": If the device is connected after the module is loaded, it will not be
+detected automatically. The bus is sampled when this string is echoed. If a
+device is connected, port flags are updated and core is notified about the
+device connect event.
+
+"rwtest": Function Address register is written and read back to validate the
+contents. This should NOT be used while the usb device is connected. This is
+strictly for debugging purpose.
+
+"dump": Dumps all the register values to the kernel log buffer.
+
+Design Goals:
+=============
+
+- Handle errors gracefully. Implement retry mechanism for transaction errors,
+memory failures. Mark HCD as dead for serious errors like SPI transaction
+errors to avoid further interactions with the attached USB device.
+- Keep the asynchronous schedule algorithm simple and efficient. Take advantage
+of the static configuration of the USB device. UICC cards has only CCID and Mass
+storage interfaces. These interface protocol allows only 1 active transfer on
+either in or out endpoint.
+- Add trace points to capture USB transactions.
+
+Driver parameters
+=================
+
+The driver is compiled as a module and it accepts the configuration data file
+name as a module param called "firmware". The default configuration file name
+is "ice40.bin".
+
+Config options
+==============
+
+Set CONFIG_USB_SL811_HCD to m to compile this driver as a module.  The driver
+should not be compiled statically, because the configuration data is not
+available during kernel boot.
+
+To do
+=====
+
+- The bridge chip has 2 IN FIFO and 2 OUT FIFO.  Implement double buffering.
+- The bridge chip has an interrupt to indicate the transaction (IN/OUT)
+completion. The current implementation uses polling for simplicity and to avoid
+interrupt latencies.  Evaluate interrupt approach.
+- The bridge chip can be completely power collapsed during suspend to avoid
+leakage currents. As the bridge chip does not have any non-volatile memory,
+the configuration data needs to be loaded during resume. This method has higher
+power savings with higher resume latencies. Evaluate this approach.
+- Implement Interrupt transfers if required.
+- The request_firmware() API copies the configuration data file to the kernel
+virtual memory. This memory can't be used for DMA. The current implementation
+copies this data into contiguous physical memory which is allocated via
+kmalloc. If this memory allocation fails, try to allocate multiple pages
+and submit the SPI message with multiple transfers.
diff --git a/Documentation/usb/uicc.txt b/Documentation/usb/uicc.txt
new file mode 100644
index 0000000..7bf4d86
--- /dev/null
+++ b/Documentation/usb/uicc.txt
@@ -0,0 +1,161 @@
+Introduction
+============
+
+This feature requires supporting Mass Storage and Integrated Circuit Card
+interfaces exposed by the UICC (Universal Integrated Circuit Card) device.
+The MSM acts as a USB host and UICC acts as a peripheral. The UICC device
+that is used here is also referred to as Mega-SIM. This feature will be
+supported on MSM8x26.
+
+Hardware description
+====================
+
+The USB3503 HSIC (High Speed Inter Chip) hub's down stream port is modified
+to support Inter-Chip USB for connecting the UICC device. The USB3503 is
+connected to MSM via HSIC interface. The UICC device operates in Full Speed
+mode.
+
+The UICC device will support CCID (Integrated Circuit Card interface Device)
+specification. This interface supports 1 Bulk In, 1 Bulk Out and 1 Interrupt
+endpoint. The Interrupt endpoint is used by the device to send asynchronous
+notifications like card insertion/removal and hardware error events.
+The Bulk endpoints are used for the data communication.
+
+The UICC device will support the Mass Storage Bulk Only 1.0 specification.
+It supports SCSI Transparent subclass '06', corresponding to support of the
+SCSI Primary Command set. It implements SCSI Peripheral Device Type '00'
+(TYPE_DISK) corresponding to a direct access SCSI block device.
+
+Software description
+====================
+
+The MSM HSIC controller driver(drivers/usb/host/ehci-msm-hsic.c)  takes care
+of HSIC PHY and link management. The USB3503 HSIC hub is managed by the SMSC
+hub driver(drivers/misc/smsc_hubc.c). Both these drivers are well tested on
+APQ8074 dragon board and are re-used to support this feature.
+
+The mass storage interface is managed by the standard Linux USB storage driver.
+This driver interfaces with SCSI and block layers to export the disk to
+user space.
+
+A new USB driver is implemented to manage the CCID interface. This driver is
+referred to as USB CCID driver in this document. This driver is implemented
+as a pass-through module and provides the character device interface to
+user space. The CCID specification is implemented in the user space.
+
+The CCID command and responses are exchanged over the Bulk endpoints. The
+user space application uses write() and read() calls to send commands and
+receive responses.
+
+The CCID class specific requests are sent over the control endpoint. As
+control requests have a specific format, ioctls are implemented.
+
+The UICC device sends asynchronous notifications over the interrupt endpoint.
+The card insertion/removal and hardware error events are sent to user space
+via an ioctl().
+
+Design Goals:
+============
+
+1. Re-use the existing services available in user space. This is achieved
+by implementing the kernel USB CCID driver as a pass-through module.
+
+2. Support runtime card insertion/removal.
+
+3. Support runtime power management.
+
+4. Support Multiple card configuration. More than 1 IC can be connected to
+the USB UICC device.
+
+Power Management
+================
+
+The USB core uses the runtime PM framework to auto suspend the USB devices that
+are not in use. The Auto-suspend is forbidden for all devices except hub class
+devices. The USB CCID driver enables auto-suspend for the UICC device.
+
+An USB device can be suspended only when all of its interfaces are suspended.
+The USB storage interface device acts as a parent device to the underlying
+SCSI host, target and block devices. Runtime PM must be enabled for the
+SCSI device to allow USB storage interface suspend. The SCSI device runtime
+suspend and auto-suspend timeout will be configured from user space via sysfs
+files.
+
+The HSIC platform device and USB3503 HUB device will be runtime suspended
+only after the USB UICC device is suspended.
+
+SMP/multi-core
+==============
+
+The USB CCID driver does not allow multiple clients to open the device file
+concurrently. -EBUSY will be returned if open() is attempted when the
+file is already opened.
+
+The write() and read() methods are implemented synchronously. If another
+write() is called when a previous write() is in progress, -EBUSY is
+returned. The same is applicable to read().
+
+Mutexes will be used to prevent concurrent open(), read() and write() access.
+
+Interface
+=========
+
+A character device file (/dev/ccid_bridge) will be exposed by the USB CCID
+driver. open(), read(), write(), ioctl() and close() methods are implemented.
+This device node is accessible only to the root by default.  User space init
+or udev scripts should change the permissions of this device file if it needs
+to be accessed by non-root applications.
+
+open(): The open() is blocked until the UICC device is detected and the CCID
+interface probe is completed. Returns the appropriate error code in case of
+failure.
+
+read(): An URB is submitted on the Bulk In endpoint. The read() is blocked
+until the URB is completed and the data is copied to the user space buffer
+upon success. An appropriate error code is returned in case of failure.
+-ENODEV must be treated as a serious error and no further I/O will be
+attempted.
+
+write(): An URB is submitted on the Bulk Out endpoint. The write() is blocked
+until the URB is completed. An appropriate error code is returned in case of
+failure. -ENODEV must be treated as a serious error and no further I/O will be
+attempted.
+
+ioctl(): The ioctl() method is required for facilitating Control transfers and
+Interrupt transfers.
+
+USB_CCID_GET_CLASS_DESC: This read-only ioctl returns the smart card class
+descriptor as described in the 5.1 section of USB smart card class spec.
+
+USB_CCID_ABORT: This write-only ioctl sends A ABORT class specific request on
+control endpoint. The class request details are mentioned in section 5.3.1.
+
+USB_CCID_GET_CLOCK_FREQUENCIES: This read and write ioctl returns the clock
+frequencies supported by the CCID device. A GET_CLOCK_FREQUENCIES class request
+is sent on the control endpoint. The class request details are mentioned in
+section 5.3.2.
+
+USB_CCID_GET_DATA_RATES: This read and write ioctl returns the data rates
+supported by the CCID device. A GET_DATA_RATES class request is sent on the
+control endpoint. The class request details are mentioned in section 5.3.3.
+
+USB_CCID_GET_EVENT: This read-only ioctl returns the asynchronous event sent
+by the UICC device. The ioctl() is blocked until such event is received from
+the UICC device. This ioctl() returns -ENOENT error code when the device
+does not have an interrupt endpoint and does not support remote wakeup
+capability.
+
+close(): Cancels any ongoing I/O before it returns.
+
+Config options
+==============
+
+Turn on USB_EHCI_MSM_HSIC, USB_HSIC_SMSC_HUB and USB_CCID_BRIDGE configs to
+enable this feature.
+
+References
+==========
+
+Specification for Integrated Circuit(s) Cards Interface Devices
+
+Smart Cards; UICC-Terminal interface; Physical and logical characteristics
diff --git a/Documentation/vm/ksm.txt b/Documentation/vm/ksm.txt
index b392e49..8e54981 100644
--- a/Documentation/vm/ksm.txt
+++ b/Documentation/vm/ksm.txt
@@ -72,6 +72,13 @@
 pages_unshared   - how many pages unique but repeatedly checked for merging
 pages_volatile   - how many pages changing too fast to be placed in a tree
 full_scans       - how many times all mergeable areas have been scanned
+deferred_timer   - whether to use deferred timers or not
+                 e.g. "echo 1 > /sys/kernel/mm/ksm/deferred_timer"
+                 Default: 0 (means, we are not using deferred timers. Users
+		 might want to set deferred_timer option if they donot want
+		 ksm thread to wakeup CPU to carryout ksm activities thus
+		 gaining on battery while compromising slightly on memory
+		 that could have been saved.)
 
 A high ratio of pages_sharing to pages_shared indicates good sharing, but
 a high ratio of pages_unshared to pages_sharing indicates wasted effort.
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-dragonboard.dtsi b/arch/arm/boot/dts/apq8074-dragonboard.dtsi
index c7e24d9..8c76a6d 100644
--- a/arch/arm/boot/dts/apq8074-dragonboard.dtsi
+++ b/arch/arm/boot/dts/apq8074-dragonboard.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
@@ -74,7 +74,7 @@
 		/* Dragonboard has an always-on VBUS supply for HSIC hub,
 		 * providing a dummy regulator for the hub driver
 		 */
-		hub_vbus-supply = <&vph_pwr_vreg>;
+		hub-vbus-supply = <&vph_pwr_vreg>;
 
 		hsic_host: hsic@f9a00000 {
 			compatible = "qcom,hsic-host";
diff --git a/arch/arm/boot/dts/apq8074-v1.dtsi b/arch/arm/boot/dts/apq8074-v1.dtsi
index 59e7f7f..be7dee8 100644
--- a/arch/arm/boot/dts/apq8074-v1.dtsi
+++ b/arch/arm/boot/dts/apq8074-v1.dtsi
@@ -27,15 +27,17 @@
 		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>;
 		qcom,msm-bus,num-paths = <1>;
+		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 3575c92..064a28c 100644
--- a/arch/arm/boot/dts/apq8074-v2.0-1.dtsi
+++ b/arch/arm/boot/dts/apq8074-v2.0-1.dtsi
@@ -31,11 +31,13 @@
 		qcom,msm-bus,num-cases = <4>;
 		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 18f00c5..010d574 100644
--- a/arch/arm/boot/dts/apq8074-v2.2.dtsi
+++ b/arch/arm/boot/dts/apq8074-v2.2.dtsi
@@ -31,11 +31,13 @@
 		qcom,msm-bus,num-cases = <4>;
 		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/apq8084-camera-sensor-cdp.dtsi b/arch/arm/boot/dts/apq8084-camera-sensor-cdp.dtsi
new file mode 100644
index 0000000..173ea63
--- /dev/null
+++ b/arch/arm/boot/dts/apq8084-camera-sensor-cdp.dtsi
@@ -0,0 +1,164 @@
+/*
+ * 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.
+ */
+
+&cci {
+
+	actuator0: qcom,actuator@36 {
+		cell-index = <1>;
+		reg = <0x36>;
+		compatible = "qcom,actuator";
+		qcom,cci-master = <0>;
+	};
+
+	qcom,camera@20 {
+		compatible = "qcom,imx135";
+		reg = <0x20>;
+		qcom,slave-id = <0x20 0x0016 0x0135>;
+		qcom,csiphy-sd-index = <0>;
+		qcom,csid-sd-index = <0>;
+		qcom,mount-angle = <90>;
+		qcom,sensor-name = "imx135";
+		qcom,actuator-src = <&actuator0>;
+		cam_vdig-supply = <&pma8084_l27>;
+		cam_vio-supply = <&pma8084_lvs4>;
+		cam_vana-supply = <&pma8084_l17>;
+		cam_vaf-supply = <&pma8084_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 = <1050000 0 2800000 2700000>;
+		qcom,cam-vreg-max-voltage = <1050000 0 2800000 2700000>;
+		qcom,cam-vreg-op-mode = <105000 0 80000 100000>;
+		qcom,gpio-no-mux = <0>;
+		gpios = <&msmgpio 15 0>,
+			<&msmgpio 36 0>,
+			<&msmgpio 35 0>;
+		qcom,gpio-reset = <1>;
+		qcom,gpio-standby = <2>;
+		qcom,gpio-req-tbl-num = <0 1 2>;
+		qcom,gpio-req-tbl-flags = <1 0 0>;
+		qcom,gpio-req-tbl-label = "CAMIF_MCLK",
+					  "CAM_RESET1",
+					  "CAM_STANDBY";
+		qcom,gpio-set-tbl-num = <1 1>;
+		qcom,gpio-set-tbl-flags = <0 2>;
+		qcom,gpio-set-tbl-delay = <1000 30000>;
+		qcom,csi-lane-assign = <0x4320>;
+		qcom,csi-lane-mask = <0x1F>;
+		qcom,sensor-position = <0>;
+		qcom,sensor-mode = <0>;
+	        qcom,sensor-type = <0>;
+		qcom,cci-master = <0>;
+		status = "ok";
+	};
+
+	qcom,camera@6d {
+		compatible = "qcom,imx132";
+		reg = <0x6d>;
+		qcom,slave-id = <0x6c 0x0 0x0132>;
+		qcom,csiphy-sd-index = <2>;
+		qcom,csid-sd-index = <2>;
+		qcom,mount-angle = <270>;
+		qcom,sensor-name = "imx132";
+        cam_vana-supply = <&pma8084_l17>;
+		cam_vdig-supply = <&pma8084_l15>;
+		cam_vio-supply = <&pma8084_lvs4>;
+		qcom,cam-vreg-name =  "cam_vana", "cam_vdig", "cam_vio";
+		qcom,cam-vreg-type = <0 0 1>;
+		qcom,cam-vreg-min-voltage = <2800000 1200000 0>;
+		qcom,cam-vreg-max-voltage = <2800000 1200000 0>;
+		qcom,cam-vreg-op-mode = <80000 105000 0>;
+		qcom,gpio-no-mux = <0>;
+		gpios = <&msmgpio 17 0>,
+			    <&msmgpio 25 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_MCLK2",
+					  "CAM_XSHUTDOWN";
+		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@0 {
+		cell-index = <0>;
+		compatible = "qcom,camera";
+		reg = <0x00>;
+		qcom,csiphy-sd-index = <0>;
+		qcom,csid-sd-index = <0>;
+		qcom,actuator-src = <&actuator0>;
+		qcom,mount-angle = <90>;
+		cam_vdig-supply = <&pma8084_l27>;
+		cam_vio-supply = <&pma8084_lvs4>;
+		cam_vana-supply = <&pma8084_l17>;
+		cam_vaf-supply = <&pma8084_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 = <1050000 0 2800000 2700000>;
+		qcom,cam-vreg-max-voltage = <1050000 0 2800000 2700000>;
+		qcom,cam-vreg-op-mode = <105000 0 80000 100000>;
+		qcom,gpio-no-mux = <0>;
+		gpios = <&msmgpio 15 0>,
+			<&msmgpio 36 0>,
+			<&msmgpio 35 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,sensor-position = <0>;
+		qcom,sensor-mode = <1>;
+		qcom,cci-master = <0>;
+		status = "ok";
+	};
+
+	qcom,camera@1 {
+		cell-index = <1>;
+		compatible = "qcom,camera";
+		reg = <0x01>;
+		qcom,slave-id = <0x6c 0x0 0x0132>;
+		qcom,csiphy-sd-index = <2>;
+		qcom,csid-sd-index = <2>;
+		qcom,mount-angle = <270>;
+		cam_vana-supply = <&pma8084_l17>;
+		cam_vdig-supply = <&pma8084_l15>;
+		cam_vio-supply = <&pma8084_lvs4>;
+		qcom,cam-vreg-name =  "cam_vana", "cam_vdig", "cam_vio";
+		qcom,cam-vreg-type = <0 0 1>;
+		qcom,cam-vreg-min-voltage = <2850000 1225000 0>;
+		qcom,cam-vreg-max-voltage = <2850000 1225000 0>;
+		qcom,cam-vreg-op-mode = <80000 105000 0>;
+		qcom,gpio-no-mux = <0>;
+		gpios = <&msmgpio 17 0>,
+			    <&msmgpio 25 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_MCLK2",
+					  "CAM_XSHUTDOWN";
+		qcom,sensor-position = <1>;
+		qcom,sensor-mode = <1>;
+		qcom,cci-master = <0>;
+		status = "ok";
+	};
+};
diff --git a/arch/arm/boot/dts/apq8084-camera-sensor-mtp.dtsi b/arch/arm/boot/dts/apq8084-camera-sensor-mtp.dtsi
new file mode 100644
index 0000000..bfbbf54
--- /dev/null
+++ b/arch/arm/boot/dts/apq8084-camera-sensor-mtp.dtsi
@@ -0,0 +1,163 @@
+/*
+ * 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.
+ */
+
+&cci {
+
+	actuator0: qcom,actuator@36 {
+		cell-index = <1>;
+		reg = <0x36>;
+		compatible = "qcom,actuator";
+		qcom,cci-master = <0>;
+	};
+
+	qcom,camera@20 {
+		compatible = "qcom,imx135";
+		reg = <0x20>;
+		qcom,slave-id = <0x20 0x0016 0x0135>;
+		qcom,csiphy-sd-index = <0>;
+		qcom,csid-sd-index = <0>;
+		qcom,mount-angle = <90>;
+		qcom,sensor-name = "imx135";
+		qcom,actuator-src = <&actuator0>;
+		cam_vdig-supply = <&pma8084_l27>;
+		cam_vio-supply = <&pma8084_lvs4>;
+		cam_vana-supply = <&pma8084_l17>;
+		cam_vaf-supply = <&pma8084_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 = <1050000 0 2800000 2700000>;
+		qcom,cam-vreg-max-voltage = <1050000 0 2800000 2700000>;
+		qcom,cam-vreg-op-mode = <105000 0 80000 100000>;
+		qcom,gpio-no-mux = <0>;
+		gpios = <&msmgpio 15 0>,
+			<&msmgpio 36 0>,
+			<&msmgpio 35 0>;
+		qcom,gpio-reset = <1>;
+		qcom,gpio-standby = <2>;
+		qcom,gpio-req-tbl-num = <0 1 2>;
+		qcom,gpio-req-tbl-flags = <1 0 0>;
+		qcom,gpio-req-tbl-label = "CAMIF_MCLK",
+					  "CAM_RESET1",
+					  "CAM_STANDBY";
+		qcom,gpio-set-tbl-num = <1 1>;
+		qcom,gpio-set-tbl-flags = <0 2>;
+		qcom,gpio-set-tbl-delay = <1000 30000>;
+		qcom,csi-lane-assign = <0x4320>;
+		qcom,csi-lane-mask = <0x1F>;
+		qcom,sensor-position = <0>;
+		qcom,sensor-mode = <0>;
+	        qcom,sensor-type = <0>;
+		qcom,cci-master = <0>;
+		status = "ok";
+	};
+
+	qcom,camera@6d {
+		compatible = "qcom,imx132";
+		reg = <0x6d>;
+		qcom,slave-id = <0x6c 0x0 0x0132>;
+		qcom,csiphy-sd-index = <2>;
+		qcom,csid-sd-index = <2>;
+		qcom,mount-angle = <90>;
+		qcom,sensor-name = "imx132";
+        cam_vana-supply = <&pma8084_l17>;
+		cam_vdig-supply = <&pma8084_l15>;
+		cam_vio-supply = <&pma8084_lvs4>;
+		qcom,cam-vreg-name =  "cam_vana", "cam_vdig", "cam_vio";
+		qcom,cam-vreg-type = <0 0 1>;
+		qcom,cam-vreg-min-voltage = <2800000 1200000 0>;
+		qcom,cam-vreg-max-voltage = <2800000 1200000 0>;
+		qcom,cam-vreg-op-mode = <80000 105000 0>;
+		qcom,gpio-no-mux = <0>;
+		gpios = <&msmgpio 17 0>,
+			    <&msmgpio 25 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_MCLK2",
+					  "CAM_XSHUTDOWN";
+		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@0 {
+		cell-index = <0>;
+		compatible = "qcom,camera";
+		reg = <0x00>;
+		qcom,csiphy-sd-index = <0>;
+		qcom,csid-sd-index = <0>;
+		qcom,mount-angle = <90>;
+		qcom,actuator-src = <&actuator0>;
+		cam_vdig-supply = <&pma8084_l27>;
+		cam_vio-supply = <&pma8084_lvs4>;
+		cam_vana-supply = <&pma8084_l17>;
+		cam_vaf-supply = <&pma8084_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 = <1050000 0 2800000 2700000>;
+		qcom,cam-vreg-max-voltage = <1050000 0 2800000 2700000>;
+		qcom,cam-vreg-op-mode = <105000 0 80000 100000>;
+		qcom,gpio-no-mux = <0>;
+		gpios = <&msmgpio 15 0>,
+			<&msmgpio 36 0>,
+			<&msmgpio 35 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,sensor-position = <0>;
+		qcom,sensor-mode = <1>;
+		qcom,cci-master = <0>;
+		status = "ok";
+	};
+
+	qcom,camera@1 {
+		cell-index = <1>;
+		compatible = "qcom,camera";
+		reg = <0x01>;
+		qcom,csiphy-sd-index = <2>;
+		qcom,csid-sd-index = <2>;
+		qcom,mount-angle = <270>;
+		cam_vana-supply = <&pma8084_l17>;
+		cam_vdig-supply = <&pma8084_l15>;
+		cam_vio-supply = <&pma8084_lvs4>;
+		qcom,cam-vreg-name =  "cam_vana", "cam_vdig", "cam_vio";
+		qcom,cam-vreg-type = <0 0 1>;
+		qcom,cam-vreg-min-voltage = <2850000 1225000 0>;
+		qcom,cam-vreg-max-voltage = <2850000 1225000 0>;
+		qcom,cam-vreg-op-mode = <80000 105000 0>;
+		qcom,gpio-no-mux = <0>;
+		gpios = <&msmgpio 17 0>,
+			    <&msmgpio 25 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_MCLK2",
+					  "CAM_XSHUTDOWN";
+		qcom,sensor-position = <1>;
+		qcom,sensor-mode = <1>;
+		qcom,cci-master = <0>;
+		status = "ok";
+	};
+};
diff --git a/arch/arm/boot/dts/apq8084-mdss.dtsi b/arch/arm/boot/dts/apq8084-mdss.dtsi
index 15d5018..665eedc 100644
--- a/arch/arm/boot/dts/apq8084-mdss.dtsi
+++ b/arch/arm/boot/dts/apq8084-mdss.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
@@ -24,6 +24,20 @@
 		qcom,max-bandwidth-low-kbps = <6000000>;
 		qcom,max-bandwidth-high-kbps = <6000000>;
 
+		/* Bus Scale Settings */
+		qcom,msm-bus,name = "mdss_mdp";
+		qcom,msm-bus,num-cases = <3>;
+		qcom,msm-bus,num-paths = <2>;
+		qcom,msm-bus,vectors-KBps =
+			<22 512 0 0>, <23 512 0 0>,
+			<22 512 0 6400000>, <23 512 0 6400000>,
+			<22 512 0 6400000>, <23 512 0 6400000>;
+
+		/* Fudge factors */
+		qcom,mdss-ab-factor = <2 1>;		/* 2 times    */
+		qcom,mdss-ib-factor = <6 5>;		/* 1.2 times  */
+		qcom,mdss-clk-factor = <105 100>;	/* 1.05 times */
+
 		qcom,max-clk-rate = <320000000>;
 
 		qcom,mdss-pipe-vig-off = <0x00001200 0x00001600
@@ -36,6 +50,21 @@
 		qcom,mdss-pipe-rgb-fetch-id = <16 17 18 22>;
 		qcom,mdss-pipe-dma-fetch-id = <10 13>;
 
+		qcom,mdss-pipe-vig-xin-id = <0 4 8 12>;
+		qcom,mdss-pipe-rgb-xin-id = <1 5 9 13>;
+		qcom,mdss-pipe-dma-xin-id = <2 10>;
+
+		qcom,mdss-pipe-vig-clk-ctrl-offsets = <0x3AC 0 0>,
+						      <0x3B4 0 0>,
+						      <0x3BC 0 0>,
+						      <0x3C4 0 0>;
+		qcom,mdss-pipe-rgb-clk-ctrl-offsets = <0x3AC 4 8>,
+						      <0x3B4 4 8>,
+						      <0x3BC 4 8>,
+						      <0x3C4 4 8>;
+		qcom,mdss-pipe-dma-clk-ctrl-offsets = <0x3AC 8 12>,
+						      <0x3B4 8 12>;
+
 		qcom,mdss-smp-data = <44 8192>;
 
 		qcom,mdss-ctl-off = <0x00000600 0x00000700 0x00000800
@@ -56,6 +85,15 @@
 		qcom,mdss-has-bwc;
 		qcom,mdss-has-decimation;
 
+		/* buffer parameters to calculate prefill bandwidth */
+		qcom,mdss-prefill-outstanding-buffer-bytes = <1024>;
+		qcom,mdss-prefill-y-buffer-bytes = <4096>;
+		qcom,mdss-prefill-scaler-buffer-lines-bilinear = <2>;
+		qcom,mdss-prefill-scaler-buffer-lines-caf = <4>;
+		qcom,mdss-prefill-post-scaler-buffer-pixels = <2048>;
+		qcom,mdss-prefill-pingpong-buffer-pixels = <5120>;
+		qcom,mdss-prefill-fbc-lines = <2>;
+
 		mdss_fb0: qcom,mdss_fb_primary {
 			cell-index = <0>;
 			compatible = "qcom,mdss-fb";
diff --git a/arch/arm/boot/dts/dsi-panel-generic-720p-cmd.dtsi b/arch/arm/boot/dts/dsi-panel-generic-720p-cmd.dtsi
index 17e6e94..214c7f8 100644
--- a/arch/arm/boot/dts/dsi-panel-generic-720p-cmd.dtsi
+++ b/arch/arm/boot/dts/dsi-panel-generic-720p-cmd.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
@@ -59,8 +59,8 @@
 		qcom,mdss-dsi-lane-2-state;
 		qcom,mdss-dsi-lane-3-state;
 		qcom,mdss-dsi-te-pin-select = <1>;
-		qcom,mdss-dsi-te-v-sync-rd-ptr-irq-line = <0x2c>;
-		qcom,mdss-dsi-te-v-sync-continues-lines = <0x3c>;
+		qcom,mdss-dsi-wr-mem-start = <0x2c>;
+		qcom,mdss-dsi-wr-mem-continue = <0x3c>;
 		qcom,mdss-dsi-te-dcs-command = <1>;
 		qcom,mdss-dsi-te-check-enable;
 		qcom,mdss-dsi-te-using-te-pin;
@@ -75,5 +75,6 @@
 		qcom,mdss-dsi-mdp-trigger = "none";
 		qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_pwm";
 		qcom,mdss-dsi-reset-sequence = <1 20>, <0 200>, <1 20>;
+		qcom,partial-update-enabled;
 	};
 };
diff --git a/arch/arm/boot/dts/dsi-panel-hx8394a-720p-video.dtsi b/arch/arm/boot/dts/dsi-panel-hx8394a-720p-video.dtsi
index 5302d8ae..760ecd7 100644
--- a/arch/arm/boot/dts/dsi-panel-hx8394a-720p-video.dtsi
+++ b/arch/arm/boot/dts/dsi-panel-hx8394a-720p-video.dtsi
@@ -77,6 +77,8 @@
 		qcom,mdss-dsi-mdp-trigger = "none";
 		qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
 		qcom,mdss-dsi-reset-sequence = <1 20>, <0 1>, <1 20>;
+		qcom,mdss-pan-physical-width-dimension = <59>;
+		qcom,mdss-pan-physical-height-dimension = <104>;
 
 	};
 };
diff --git a/arch/arm/boot/dts/dsi-panel-jdi-1080p-video.dtsi b/arch/arm/boot/dts/dsi-panel-jdi-1080p-video.dtsi
index be42509..17b39fc 100644
--- a/arch/arm/boot/dts/dsi-panel-jdi-1080p-video.dtsi
+++ b/arch/arm/boot/dts/dsi-panel-jdi-1080p-video.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
@@ -30,8 +30,8 @@
 		qcom,mdss-dsi-h-back-porch = <64>;
 		qcom,mdss-dsi-h-pulse-width = <16>;
 		qcom,mdss-dsi-h-sync-skew = <0>;
-		qcom,mdss-dsi-v-back-porch = <4>;
-		qcom,mdss-dsi-v-front-porch = <3>;
+		qcom,mdss-dsi-v-back-porch = <16>;
+		qcom,mdss-dsi-v-front-porch = <4>;
 		qcom,mdss-dsi-v-pulse-width = <1>;
 		qcom,mdss-dsi-h-left-border = <0>;
 		qcom,mdss-dsi-h-right-border = <0>;
@@ -57,7 +57,7 @@
 		qcom,mdss-dsi-lane-1-state;
 		qcom,mdss-dsi-lane-2-state;
 		qcom,mdss-dsi-lane-3-state;
-		qcom,mdss-dsi-panel-timings = [e1 37 25 00 67 6b 2a 3a 59 03 04 00];
+		qcom,mdss-dsi-panel-timings = [e7 36 24 00 66 6a 2a 3a 2d 03 04 00];
 		qcom,mdss-dsi-t-clk-post = <0x04>;
 		qcom,mdss-dsi-t-clk-pre = <0x1b>;
 		qcom,mdss-dsi-bl-min-level = <1>;
@@ -66,5 +66,7 @@
 		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>;
+		qcom,mdss-pan-physical-width-dimension = <61>;
+		qcom,mdss-pan-physical-height-dimension = <110>;
 	};
 };
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-jdi-dualmipi0-cmd.dtsi b/arch/arm/boot/dts/dsi-panel-jdi-dualmipi0-cmd.dtsi
new file mode 100644
index 0000000..d8bf36f
--- /dev/null
+++ b/arch/arm/boot/dts/dsi-panel-jdi-dualmipi0-cmd.dtsi
@@ -0,0 +1,91 @@
+/* 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.
+ */
+
+&mdss_mdp {
+	dsi_dual_jdi_cmd_0: qcom,mdss_dsi_jdi_qhd_dualmipi0_cmd{
+		qcom,mdss-dsi-panel-name = "Dual 0 cmd mode dsi panel";
+		qcom,mdss-dsi-panel-controller = <&mdss_dsi0>;
+		qcom,mdss-dsi-panel-type = "dsi_cmd_mode";
+		qcom,mdss-dsi-panel-destination = "display_1";
+		qcom,mdss-dsi-panel-framerate = <60>;
+		qcom,mdss-dsi-virtual-channel-id = <0>;
+		qcom,mdss-dsi-stream = <0>;
+		qcom,mdss-dsi-panel-width = <1280>;
+		qcom,mdss-dsi-panel-height = <1440>;
+		qcom,mdss-dsi-h-front-porch = <120>;
+		qcom,mdss-dsi-h-back-porch = <44>;
+		qcom,mdss-dsi-h-pulse-width = <16>;
+		qcom,mdss-dsi-h-sync-skew = <0>;
+		qcom,mdss-dsi-v-back-porch = <4>;
+		qcom,mdss-dsi-v-front-porch = <8>;
+		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-color-order = "rgb_swap_rgb";
+		qcom,mdss-dsi-underflow-color = <0xff>;
+		qcom,mdss-dsi-border-color = <0>;
+		qcom,mdss-dsi-h-sync-pulse = <0>;
+		qcom,mdss-dsi-traffic-mode = "non_burst_sync_event";
+		qcom,mdss-dsi-lane-map = "lane_map_0123";
+		qcom,mdss-dsi-bllp-eof-power-mode;
+		qcom,mdss-dsi-bllp-power-mode;
+		qcom,mdss-dsi-panel-broadcast-mode;
+		qcom,mdss-dsi-lane-0-state;
+		qcom,mdss-dsi-lane-1-state;
+		qcom,mdss-dsi-lane-2-state;
+		qcom,mdss-dsi-lane-3-state;
+		qcom,mdss-dsi-panel-timings = [cd 32 22 00 60 64 26 34 29 03
+									04 00];
+		qcom,mdss-dsi-reset-sequence = <1 200>, <0 200>, <1 20>;
+		qcom,mdss-dsi-t-clk-post = <0x03>;
+		qcom,mdss-dsi-t-clk-pre = <0x27>;
+		qcom,mdss-dsi-bl-max-level = <4095>;
+		qcom,mdss-dsi-dma-trigger = "trigger_sw";
+		qcom,mdss-dsi-mdp-trigger = "none";
+		qcom,mdss-dsi-te-pin-select = <1>;
+		qcom,mdss-dsi-te-v-sync-rd-ptr-irq-line = <0x2c>;
+		qcom,mdss-dsi-te-v-sync-continues-lines = <0x3c>;
+		qcom,mdss-dsi-te-dcs-command = <1>;
+		qcom,mdss-dsi-te-check-enable;
+		qcom,mdss-dsi-te-using-te-pin;
+		qcom,mdss-dsi-on-command = [29 01 00 00 00 00 02 b0 03
+			05 01 00 00 0a 00 01 00
+			/* Soft reset, wait 10ms */
+			15 01 00 00 0a 00 02 3a 77
+			/* Set Pixel format (24 bpp) */
+			39 01 00 00 0a 00 05 2a 00 00 04 ff
+			/* Set Column address */
+			39 01 00 00 0a 00 05 2b 00 00 05 9f
+			/* Set page address */
+			15 01 00 00 0a 00 02 35 00
+			/* Set tear on */
+			39 01 00 00 0a 00 03 44 00 00
+			/* Set tear scan line */
+			15 01 00 00 0a 00 02 51 ff
+			/* write display brightness */
+			15 01 00 00 0a 00 02 53 24
+			 /* write control brightness */
+			15 01 00 00 0a 00 02 55 00
+			/* CABC brightness */
+			05 01 00 00 78 00 01 11
+			/* exit sleep mode, wait 120ms */
+			05 01 00 00 10 00 01 29];
+			/* Set display on, wait 16ms */
+		qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
+		qcom,mdss-dsi-off-command = [05 01 00 00 32 00 02 28 00
+					05 01 00 00 78 00 02 10 00];
+		qcom,mdss-dsi-off-command-state = "dsi_hs_mode";
+	};
+};
diff --git a/arch/arm/boot/dts/dsi-panel-jdi-dualmipi0-video.dtsi b/arch/arm/boot/dts/dsi-panel-jdi-dualmipi0-video.dtsi
new file mode 100644
index 0000000..5cf88f9
--- /dev/null
+++ b/arch/arm/boot/dts/dsi-panel-jdi-dualmipi0-video.dtsi
@@ -0,0 +1,92 @@
+/* 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.
+ */
+
+&mdss_mdp {
+	dsi_dual_jdi_video_0: qcom,dsi_jdi_qhd_video_0 {
+		qcom,mdss-dsi-panel-name = "Dual 0 video mode dsi panel";
+		qcom,mdss-dsi-panel-controller = <&mdss_dsi0>;
+		qcom,mdss-dsi-panel-type = "dsi_video_mode";
+		qcom,mdss-dsi-panel-destination = "display_1";
+		qcom,mdss-dsi-panel-framerate = <60>;
+		qcom,mdss-dsi-virtual-channel-id = <0>;
+		qcom,mdss-dsi-stream = <0>;
+		qcom,mdss-dsi-panel-width = <1280>;
+		qcom,mdss-dsi-panel-height = <1440>;
+		qcom,mdss-dsi-h-front-porch = <120>;
+		qcom,mdss-dsi-h-back-porch = <44>;
+		qcom,mdss-dsi-h-pulse-width = <16>;
+		qcom,mdss-dsi-h-sync-skew = <0>;
+		qcom,mdss-dsi-v-back-porch = <4>;
+		qcom,mdss-dsi-v-front-porch = <8>;
+		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-h-sync-pulse = <0>;
+		qcom,mdss-dsi-traffic-mode = "non_burst_sync_event";
+		qcom,mdss-dsi-bllp-eof-power-mode;
+		qcom,mdss-dsi-bllp-power-mode;
+		qcom,mdss-dsi-panel-broadcast-mode;
+		qcom,mdss-dsi-lane-0-state;
+		qcom,mdss-dsi-lane-1-state;
+		qcom,mdss-dsi-lane-2-state;
+		qcom,mdss-dsi-lane-3-state;
+		qcom,mdss-dsi-panel-timings = [cd 32 22 00 60 64 26 34 29 03
+									04 00];
+		qcom,mdss-dsi-t-clk-post = <0x03>;
+		qcom,mdss-dsi-t-clk-pre = <0x27>;
+		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_pwm";
+		qcom,mdss-dsi-on-command = [05 01 00 00 0a 00 01 00
+						/* Soft reset, wait 10ms */
+					15 01 00 00 0a 00 02 3a 77
+						/* Set Pixel format (24 bpp) */
+					39 01 00 00 0a 00 05 2a 00 00 04 ff
+						/* Set Column address */
+					39 01 00 00 0a 00 05 2b 00 00 05 9f
+						/* Set page address */
+					15 01 00 00 0a 00 02 35 00
+						/* Set tear on */
+					39 01 00 00 0a 00 03 44 00 00
+						/* Set tear scan line */
+					15 01 00 00 0a 00 02 51 ff
+						/* write display brightness */
+					15 01 00 00 0a 00 02 53 24
+						/* write control brightness */
+					15 01 00 00 0a 00 02 55 00
+						/* CABC brightness */
+					05 01 00 00 78 00 01 11
+					/* exit sleep mode, wait 120ms */
+					23 01 00 00 0a 00 02 b0 00
+						/* MCAP */
+					29 01 00 00 0a 00 02 b3 14
+						/* Interface setting */
+					29 01 00 00 0a 00 14 ce 7d 40 48 56 67
+					78 88 98 a7 b5 c3 d1 de e9 f2 fa ff 04
+					00    /* Backlight control 4 */
+					23 01 00 00 0a 00 02 b0 03
+						/* MCAP */
+					05 01 00 00 10 00 01 29];
+					/* Set display on, wait 16ms */
+		qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
+		qcom,mdss-dsi-off-command = [05 01 00 00 32 00 02 28 00
+					05 01 00 00 78 00 02 10 00];
+		qcom,mdss-dsi-off-command-state = "dsi_hs_mode";
+		qcom,mdss-dsi-reset-sequence = <1 20>, <0 200>, <1 20>;
+	};
+};
diff --git a/arch/arm/boot/dts/dsi-panel-jdi-dualmipi1-cmd.dtsi b/arch/arm/boot/dts/dsi-panel-jdi-dualmipi1-cmd.dtsi
new file mode 100644
index 0000000..e1473ca
--- /dev/null
+++ b/arch/arm/boot/dts/dsi-panel-jdi-dualmipi1-cmd.dtsi
@@ -0,0 +1,91 @@
+/* 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.
+ */
+
+&mdss_mdp {
+	dsi_dual_jdi_cmd_1: qcom,mdss_dsi_jdi_qhd_dualmipi1_cmd{
+		qcom,mdss-dsi-panel-name = "Dual 1 cmd mode dsi panel";
+		qcom,mdss-dsi-panel-controller = <&mdss_dsi1>;
+		qcom,mdss-dsi-panel-type = "dsi_cmd_mode";
+		qcom,mdss-dsi-panel-destination = "display_2";
+		qcom,mdss-dsi-panel-framerate = <60>;
+		qcom,mdss-dsi-virtual-channel-id = <0>;
+		qcom,mdss-dsi-stream = <0>;
+		qcom,mdss-dsi-panel-width = <1280>;
+		qcom,mdss-dsi-panel-height = <1440>;
+		qcom,mdss-dsi-h-front-porch = <120>;
+		qcom,mdss-dsi-h-back-porch = <44>;
+		qcom,mdss-dsi-h-pulse-width = <16>;
+		qcom,mdss-dsi-h-sync-skew = <0>;
+		qcom,mdss-dsi-v-back-porch = <4>;
+		qcom,mdss-dsi-v-front-porch = <8>;
+		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-color-order = "rgb_swap_rgb";
+		qcom,mdss-dsi-underflow-color = <0xff>;
+		qcom,mdss-dsi-border-color = <0>;
+		qcom,mdss-dsi-h-sync-pulse = <0>;
+		qcom,mdss-dsi-traffic-mode = "non_burst_sync_event";
+		qcom,mdss-dsi-lane-map = "lane_map_0123";
+		qcom,mdss-dsi-bllp-eof-power-mode;
+		qcom,mdss-dsi-bllp-power-mode;
+		qcom,mdss-dsi-panel-broadcast-mode;
+		qcom,mdss-dsi-lane-0-state;
+		qcom,mdss-dsi-lane-1-state;
+		qcom,mdss-dsi-lane-2-state;
+		qcom,mdss-dsi-lane-3-state;
+		qcom,mdss-dsi-panel-timings = [cd 32 22 00 60 64 26 34 29 03
+									04 00];
+		qcom,mdss-dsi-reset-sequence = <1 200>, <0 200>, <1 20>;
+		qcom,mdss-dsi-t-clk-post = <0x03>;
+		qcom,mdss-dsi-t-clk-pre = <0x27>;
+		qcom,mdss-dsi-bl-max-level = <4095>;
+		qcom,mdss-dsi-dma-trigger = "trigger_sw";
+		qcom,mdss-dsi-mdp-trigger = "none";
+		qcom,mdss-dsi-te-pin-select = <1>;
+		qcom,mdss-dsi-te-v-sync-rd-ptr-irq-line = <0x2c>;
+		qcom,mdss-dsi-te-v-sync-continues-lines = <0x3c>;
+		qcom,mdss-dsi-te-dcs-command = <1>;
+		qcom,mdss-dsi-te-check-enable;
+		qcom,mdss-dsi-te-using-te-pin;
+		qcom,mdss-dsi-on-command = [29 01 00 00 00 00 02 b0 03
+			05 01 00 00 0a 00 01 00
+			/* Soft reset, wait 10ms */
+			15 01 00 00 0a 00 02 3a 77
+			/* Set Pixel format (24 bpp) */
+			39 01 00 00 0a 00 05 2a 00 00 04 ff
+			/* Set Column address */
+			39 01 00 00 0a 00 05 2b 00 00 05 9f
+			/* Set page address */
+			15 01 00 00 0a 00 02 35 00
+			/* Set tear on */
+			39 01 00 00 0a 00 03 44 00 00
+			/* Set tear scan line */
+			15 01 00 00 0a 00 02 51 ff
+			/* write display brightness */
+			15 01 00 00 0a 00 02 53 24
+			 /* write control brightness */
+			15 01 00 00 0a 00 02 55 00
+			/* CABC brightness */
+			05 01 00 00 78 00 01 11
+			/* exit sleep mode, wait 120ms */
+			05 01 00 00 10 00 01 29];
+			/* Set display on, wait 16ms */
+		qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
+		qcom,mdss-dsi-off-command = [05 01 00 00 32 00 02 28 00
+					05 01 00 00 78 00 02 10 00];
+		qcom,mdss-dsi-off-command-state = "dsi_hs_mode";
+	};
+};
diff --git a/arch/arm/boot/dts/dsi-panel-jdi-dualmipi1-video.dtsi b/arch/arm/boot/dts/dsi-panel-jdi-dualmipi1-video.dtsi
new file mode 100644
index 0000000..a405bff
--- /dev/null
+++ b/arch/arm/boot/dts/dsi-panel-jdi-dualmipi1-video.dtsi
@@ -0,0 +1,92 @@
+/* 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.
+ */
+
+&mdss_mdp {
+	dsi_dual_jdi_video_1: qcom,dsi_jdi_qhd_video_1 {
+	qcom,mdss-dsi-panel-name = "Dual 1 video mode dsi panel";
+		qcom,mdss-dsi-panel-controller = <&mdss_dsi1>;
+		qcom,mdss-dsi-panel-type = "dsi_video_mode";
+		qcom,mdss-dsi-panel-destination = "display_2";
+		qcom,mdss-dsi-panel-framerate = <60>;
+		qcom,mdss-dsi-virtual-channel-id = <0>;
+		qcom,mdss-dsi-stream = <0>;
+		qcom,mdss-dsi-panel-width = <1280>;
+		qcom,mdss-dsi-panel-height = <1440>;
+		qcom,mdss-dsi-h-front-porch = <120>;
+		qcom,mdss-dsi-h-back-porch = <44>;
+		qcom,mdss-dsi-h-pulse-width = <16>;
+		qcom,mdss-dsi-h-sync-skew = <0>;
+		qcom,mdss-dsi-v-back-porch = <4>;
+		qcom,mdss-dsi-v-front-porch = <8>;
+		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-h-sync-pulse = <0>;
+		qcom,mdss-dsi-traffic-mode = "non_burst_sync_event";
+		qcom,mdss-dsi-bllp-eof-power-mode;
+		qcom,mdss-dsi-bllp-power-mode;
+		qcom,mdss-dsi-lane-0-state;
+		qcom,mdss-dsi-lane-1-state;
+		qcom,mdss-dsi-lane-2-state;
+		qcom,mdss-dsi-lane-3-state;
+		qcom,mdss-dsi-panel-broadcast-mode;
+		qcom,mdss-dsi-panel-timings = [cd 32 22 00 60 64 26 34 29 03
+									04 00];
+		qcom,mdss-dsi-t-clk-post = <0x03>;
+		qcom,mdss-dsi-t-clk-pre = <0x27>;
+		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-on-command = [05 01 00 00 0a 00 01 00
+						/* Soft reset, wait 10ms */
+					15 01 00 00 0a 00 02 3a 77
+						/* Set Pixel format (24 bpp) */
+					39 01 00 00 0a 00 05 2a 00 00 04 ff
+						/* Set Column address */
+					39 01 00 00 0a 00 05 2b 00 00 05 9f
+						/* Set page address */
+					15 01 00 00 0a 00 02 35 00
+						/* Set tear on */
+					39 01 00 00 0a 00 03 44 00 00
+						/* Set tear scan line */
+					15 01 00 00 0a 00 02 51 ff
+						/* write display brightness */
+					15 01 00 00 0a 00 02 53 24
+						/* write control brightness */
+					15 01 00 00 0a 00 02 55 00
+						/* CABC brightness */
+					05 01 00 00 78 00 01 11
+					/* exit sleep mode, wait 120ms */
+					23 01 00 00 0a 00 02 b0 00
+						/* MCAP */
+					29 01 00 00 0a 00 02 b3 14
+						/* Interface setting */
+					29 01 00 00 0a 00 14 ce 7d 40 48 56 67
+					78 88 98 a7 b5 c3 d1 de e9 f2 fa ff 04
+					00    /* Backlight control 4 */
+					23 01 00 00 0a 00 02 b0 03
+						/* MCAP */
+					05 01 00 00 10 00 01 29];
+					/* Set display on, wait 16ms */
+		qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
+		qcom,mdss-dsi-off-command = [05 01 00 00 32 00 02 28 00
+					05 01 00 00 78 00 02 10 00];
+		qcom,mdss-dsi-off-command-state = "dsi_hs_mode";
+		qcom,mdss-dsi-reset-sequence = <1 20>, <0 200>, <1 20>;
+	};
+};
diff --git a/arch/arm/boot/dts/dsi-panel-nt35590-720p-cmd.dtsi b/arch/arm/boot/dts/dsi-panel-nt35590-720p-cmd.dtsi
index d3547d8..cbc38f2 100644
--- a/arch/arm/boot/dts/dsi-panel-nt35590-720p-cmd.dtsi
+++ b/arch/arm/boot/dts/dsi-panel-nt35590-720p-cmd.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
@@ -517,7 +517,7 @@
 		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-wr-mem-start = <0x2c>;
 		qcom,mdss-dsi-te-dcs-command = <1>;
 		qcom,mdss-dsi-te-check-enable;
 		qcom,mdss-dsi-te-using-te-pin;
diff --git a/arch/arm/boot/dts/dsi-panel-nt35590-720p-video.dtsi b/arch/arm/boot/dts/dsi-panel-nt35590-720p-video.dtsi
index 8d28996..9a18a31 100644
--- a/arch/arm/boot/dts/dsi-panel-nt35590-720p-video.dtsi
+++ b/arch/arm/boot/dts/dsi-panel-nt35590-720p-video.dtsi
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+/* 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
@@ -30,7 +30,7 @@
 		qcom,mdss-dsi-h-back-porch = <164>;
 		qcom,mdss-dsi-h-pulse-width = <8>;
 		qcom,mdss-dsi-h-sync-skew = <0>;
-		qcom,mdss-dsi-v-back-porch = <1>;
+		qcom,mdss-dsi-v-back-porch = <11>;
 		qcom,mdss-dsi-v-front-porch = <6>;
 		qcom,mdss-dsi-v-pulse-width = <1>;
 		qcom,mdss-dsi-h-left-border = <0>;
@@ -504,7 +504,9 @@
 					29 01 00 00 00 00 02 6A 60
 					29 01 00 00 00 00 02 FF 00
 					29 01 00 00 78 00 02 29 00
-					29 01 00 00 78 00 02 53 2C];
+					29 01 00 00 78 00 02 53 2C
+					29 01 00 00 00 00 02 FF 00
+					29 01 00 00 00 00 06 3B 03 06 03 02 02];
 		qcom,mdss-dsi-off-command = [05 01 00 00 32 00 02 28 00
 					05 01 00 00 78 00 02 10 00];
 		qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
diff --git a/arch/arm/boot/dts/dsi-panel-ssd2080m-720p-video.dtsi b/arch/arm/boot/dts/dsi-panel-ssd2080m-720p-video.dtsi
index 60bba5d..39b10b3 100644
--- a/arch/arm/boot/dts/dsi-panel-ssd2080m-720p-video.dtsi
+++ b/arch/arm/boot/dts/dsi-panel-ssd2080m-720p-video.dtsi
@@ -31,7 +31,7 @@
 		qcom,mdss-dsi-h-pulse-width = <14>;
 		qcom,mdss-dsi-h-sync-skew = <0>;
 		qcom,mdss-dsi-v-back-porch = <14>;
-		qcom,mdss-dsi-v-front-porch = <30>;
+		qcom,mdss-dsi-v-front-porch = <25>;
 		qcom,mdss-dsi-v-pulse-width = <2>;
 		qcom,mdss-dsi-h-left-border = <0>;
 		qcom,mdss-dsi-h-right-border = <0>;
@@ -43,11 +43,12 @@
 		qcom,mdss-dsi-border-color = <0>;
 		qcom,mdss-dsi-pixel-packing = "tight";
 		qcom,mdss-dsi-on-command = [15 01 00 00 00 00 02 FF 01
+			29 01 00 00 00 00 02 53 00
 			29 01 00 00 00 00 05 C6 63 00 81 31
 			29 01 00 00 00 00 05 CB E7 80 73 33
 			29 01 00 00 00 00 02 EC D2
 			29 01 00 00 00 00 03 B3 04 9F
-			29 01 00 00 00 00 04 B2 16 1E 10
+			29 01 00 00 00 00 04 B2 16 26 10
 			29 01 00 00 00 00 02 B4 00
 			29 01 00 00 00 00 02 C1 04
 			29 01 00 00 00 00 04 C2 BE 00 58
@@ -63,19 +64,19 @@
 			29 01 00 00 00 00 04 E6 FF FF 0F
 			29 01 00 00 00 00 02 C7 3F
 			29 01 00 00 00 00 07 B5 47 00 00 08 00 01
-			29 01 00 00 00 00 08 C4 DF 72 12 12 66 E3 99
-			29 01 00 00 00 00 07 D0 0A 00 0D 15 1F 2E
-			29 01 00 00 00 00 06 D1 28 27 14 02 01
-			29 01 00 00 00 00 07 D2 0A 00 0D 15 1F 2E
-			29 01 00 00 00 00 06 D3 28 27 14 02 01
-			29 01 00 00 00 00 07 D4 0A 00 0D 15 1F 2E
-			29 01 00 00 00 00 06 D5 28 27 14 02 01
-			29 01 00 00 00 00 07 D6 0A 00 0D 15 1F 2E
-			29 01 00 00 00 00 06 D7 28 27 14 02 01
-			29 01 00 00 00 00 07 D8 0A 00 0D 15 1F 2E
-			29 01 00 00 00 00 06 D9 28 27 14 02 01
-			29 01 00 00 00 00 07 DA 0A 00 0D 15 1F 2E
-			29 01 00 00 00 00 06 DB 28 27 14 02 01
+			29 01 00 00 00 00 08 C4 DF C2 0C 0C 63 E3 99
+			29 01 00 00 00 00 07 D0 0A 00 06 09 10 20
+			29 01 00 00 00 00 06 D1 1D 32 1B 00 00
+			29 01 00 00 00 00 07 D2 0A 00 06 09 10 20
+			29 01 00 00 00 00 06 D3 1D 32 1B 00 00
+			29 01 00 00 00 00 07 D4 0A 00 06 09 10 20
+			29 01 00 00 00 00 06 D5 1D 32 1B 00 00
+			29 01 00 00 00 00 07 D6 0A 00 06 09 10 20
+			29 01 00 00 00 00 06 D7 1D 32 1B 00 00
+			29 01 00 00 00 00 07 D8 0A 00 06 09 10 20
+			29 01 00 00 00 00 06 D9 1D 32 1B 00 00
+			29 01 00 00 00 00 07 DA 0A 00 06 09 10 20
+			29 01 00 00 00 00 06 DB 1D 32 1B 00 00
 			29 01 00 00 00 00 03 CC 10 00
 			29 01 00 00 00 00 04 CE 4E 55 A5
 			29 01 00 00 00 00 04 E0 01 02 02
@@ -84,18 +85,20 @@
 			29 01 00 00 00 00 03 E1 90 00
 			29 01 00 00 00 00 07 DE 95 CF E2 CE 11 15
 			29 01 00 00 00 00 02 CF 46
-			29 01 00 00 00 00 03 C5 77 47
+			29 01 00 00 00 00 02 C5 66
 			29 01 00 00 00 00 03 ED 00 20
-			05 01 00 00 B4 00 02 11 00
-			05 01 00 00 82 00 02 29 00
-			15 01 00 00 00 00 02 53 2c];
-		qcom,mdss-dsi-off-command = [15 01 00 00 32 00 02 10 00
-			15 01 00 00 32 00 02 53 00
-			15 01 00 00 00 00 02 c2 00
+			15 01 00 00 00 00 02 53 2c
+			05 01 00 00 20 00 02 11 00
+			05 01 00 00 20 00 02 29 00];
+
+		qcom,mdss-dsi-off-command = [05 01 00 00 32 00 02 10 00
+			39 01 00 00 20 00 02 53 00
+			39 01 00 00 20 00 02 c2 00
 			39 01 00 00 00 00 02 cf 40
-			15 01 00 00 50 00 03 de 84 00
+			39 01 00 00 20 00 03 de 84 00
 			39 01 00 00 00 00 02 cb 22
-			15 01 00 00 00 00 02 c3 00];
+			39 01 00 00 00 00 02 c3 00];
+
 		qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
 		qcom,mdss-dsi-off-command-state = "dsi_hs_mode";
 		qcom,mdss-dsi-h-sync-pulse = <1>;
@@ -115,5 +118,7 @@
 		qcom,mdss-dsi-mdp-trigger = "none";
 		qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
 		qcom,mdss-dsi-reset-sequence = <1 20>, <0 2>, <1 20>;
+		qcom,mdss-dsi-lp11-init;
+		qcom,mdss-dsi-init-delay-us = <50000>;
 	};
 };
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 168dda4..e6aaa41 100644
--- a/arch/arm/boot/dts/dsi-panel-truly-wvga-cmd.dtsi
+++ b/arch/arm/boot/dts/dsi-panel-truly-wvga-cmd.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
@@ -151,8 +151,8 @@
 		qcom,mdss-dsi-lane-0-state;
 		qcom,mdss-dsi-lane-1-state;
 		qcom,mdss-dsi-te-pin-select = <1>;
-		qcom,mdss-dsi-te-v-sync-rd-ptr-irq-line = <0x2c>;
-		qcom,mdss-dsi-te-v-sync-continues-lines = <0x3c>;
+		qcom,mdss-dsi-wr-mem-start = <0x2c>;
+		qcom,mdss-dsi-wr-mem-continue = <0x3c>;
 		qcom,mdss-dsi-te-dcs-command = <1>;
 		qcom,mdss-dsi-te-check-enable;
 		qcom,mdss-dsi-te-using-te-pin;
@@ -165,5 +165,11 @@
 		qcom,mdss-dsi-mdp-trigger = "trigger_te";
 		qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
 		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/dsi-panel-truly-wvga-video.dtsi b/arch/arm/boot/dts/dsi-panel-truly-wvga-video.dtsi
index 121e54d..bdc43a9 100644
--- a/arch/arm/boot/dts/dsi-panel-truly-wvga-video.dtsi
+++ b/arch/arm/boot/dts/dsi-panel-truly-wvga-video.dtsi
@@ -163,5 +163,7 @@
 		qcom,mdss-dsi-mdp-trigger = "none";
 		qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
 		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>;
 	};
 };
diff --git a/arch/arm/boot/dts/msm-pm8110.dtsi b/arch/arm/boot/dts/msm-pm8110.dtsi
index 20e8a96..5ccecfa 100644
--- a/arch/arm/boot/dts/msm-pm8110.dtsi
+++ b/arch/arm/boot/dts/msm-pm8110.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
@@ -22,7 +22,7 @@
 		#address-cells = <1>;
 		#size-cells = <1>;
 
-		qcom,revid@100 {
+		pm8110_revid: qcom,revid@100 {
 			compatible = "qcom,qpnp-revid";
 			reg = <0x100 0x100>;
 		};
@@ -219,6 +219,7 @@
 			qcom,adc-bit-resolution = <15>;
 			qcom,adc-vdd-reference = <1800>;
 			qcom,vadc-poll-eoc;
+			qcom,pmic-revid = <&pm8110_revid>;
 
 			chan@8 {
 				label = "die_temp";
@@ -256,7 +257,9 @@
 
 		pm8110_iadc: iadc@3600 {
 			compatible = "qcom,qpnp-iadc";
-			reg = <0x3600 0x100>;
+			reg = <0x3600 0x100>,
+			      <0x12f1 0x1>;
+			reg-names = "iadc-base", "batt-id-trim-cnst-rds";
 			#address-cells = <1>;
 			#size-cells = <0>;
 			interrupts = <0x0 0x36 0x0>;
@@ -265,6 +268,8 @@
 			qcom,adc-vdd-reference = <1800>;
 			qcom,iadc-vadc = <&pm8110_vadc>;
 			qcom,iadc-poll-eoc;
+			qcom,use-default-rds-trim = <1>;
+			qcom,pmic-revid = <&pm8110_revid>;
 
 			chan@0 {
 				label = "internal_rsense";
@@ -334,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 6d506cc..6e1b985 100644
--- a/arch/arm/boot/dts/msm-pm8226.dtsi
+++ b/arch/arm/boot/dts/msm-pm8226.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
@@ -39,6 +39,7 @@
 			qcom,pon-dbc-delay = <15625>;
 			qcom,system-reset;
 			qcom,s3-debounce = <32>;
+			qcom,s3-src = "kpdpwr-and-resin";
 
 			qcom,pon_1 {
 				qcom,pon-type = <0>;
@@ -50,10 +51,6 @@
 				qcom,pon-type = <1>;
 				qcom,pull-up = <1>;
 				linux,code = <114>;
-				qcom,s1-timer = <6720>;
-				qcom,s2-timer = <2000>;
-				qcom,s2-type = <7>;
-				qcom,support-reset = <1>;
 			};
 
 			qcom,pon_3 {
@@ -213,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>;
 			};
@@ -366,6 +367,8 @@
 			interrupt-names = "eoc-int-en-set";
 			qcom,adc-bit-resolution = <15>;
 			qcom,adc-vdd-reference = <1800>;
+			qcom,vadc-poll-eoc;
+			qcom,pmic-revid = <&pm8226_revid>;
 
 			chan@8 {
 				label = "die_temp";
@@ -414,7 +417,9 @@
 
 		pm8226_iadc: iadc@3600 {
 			compatible = "qcom,qpnp-iadc";
-			reg = <0x3600 0x100>;
+			reg = <0x3600 0x100>,
+			      <0x12f1 0x1>;
+			reg-names = "iadc-base", "batt-id-trim-cnst-rds";
 			#address-cells = <1>;
 			#size-cells = <0>;
 			interrupts = <0x0 0x36 0x0>;
@@ -422,6 +427,9 @@
 			qcom,adc-bit-resolution = <16>;
 			qcom,adc-vdd-reference = <1800>;
 			qcom,iadc-vadc = <&pm8226_vadc>;
+			qcom,iadc-poll-eoc;
+			qcom,use-default-rds-trim = <2>;
+			qcom,pmic-revid = <&pm8226_revid>;
 
 			chan@0 {
 				label = "internal_rsense";
@@ -860,22 +868,6 @@
 				qcom,current = <625>;
 			};
 
-			pm8226_flash1: qcom,flash_1 {
-				qcom,max-current = <1000>;
-				qcom,default-state = "off";
-				qcom,headroom = <3>;
-				qcom,duration = <1280>;
-				qcom,clamp-curr = <200>;
-				qcom,startup-dly = <3>;
-				qcom,safety-timer;
-				linux,default-trigger =
-						"flash1_trigger";
-				label = "flash";
-				qcom,id = <2>;
-				linux,name = "led:flash_1";
-				qcom,current = <625>;
-			};
-
 			pm8226_torch: qcom,flash_torch {
 				qcom,max-current = <200>;
 				qcom,default-state = "off";
diff --git a/arch/arm/boot/dts/msm-pm8941.dtsi b/arch/arm/boot/dts/msm-pm8941.dtsi
index 520decd..d8046c5 100644
--- a/arch/arm/boot/dts/msm-pm8941.dtsi
+++ b/arch/arm/boot/dts/msm-pm8941.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
@@ -27,7 +27,7 @@
 		reg = <0x900 0x100>;
 	};
 
-	qcom,revid@100 {
+	pm8941_revid: qcom,revid@100 {
 		compatible = "qcom,qpnp-revid";
 		reg = <0x100 0x100>;
 	};
@@ -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>;
 		};
@@ -577,6 +581,7 @@
 		qcom,adc-bit-resolution = <15>;
 		qcom,adc-vdd-reference = <1800>;
 		qcom,vadc-poll-eoc;
+		qcom,pmic-revid = <&pm8941_revid>;
 
 		chan@0 {
 			label = "usb_in";
@@ -812,7 +817,9 @@
 
 	pm8941_iadc: iadc@3600 {
 		compatible = "qcom,qpnp-iadc";
-		reg = <0x3600 0x100>;
+		reg = <0x3600 0x100>,
+		      <0x12f1 0x1>;
+		reg-names = "iadc-base", "batt-id-trim-cnst-rds";
 		#address-cells = <1>;
 		#size-cells = <0>;
 		interrupts = <0x0 0x36 0x0>;
@@ -821,6 +828,8 @@
 		qcom,adc-vdd-reference = <1800>;
 		qcom,iadc-vadc = <&pm8941_vadc>;
 		qcom,iadc-poll-eoc;
+		qcom,use-default-rds-trim = <0>;
+		qcom,pmic-revid = <&pm8941_revid>;
 
 		chan@0 {
 			label = "internal_rsense";
@@ -872,6 +881,7 @@
 			qcom,hw-settle-time = <2>;
 			qcom,fast-avg-setup = <3>;
 			qcom,btm-channel-number = <0x68>;
+			qcom,meas-interval-timer-idx = <2>;
 		};
 
 		chan@8 {
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-1080p-cdp.dtsi b/arch/arm/boot/dts/msm8226-1080p-cdp.dtsi
index bb66538..4163b95 100644
--- a/arch/arm/boot/dts/msm8226-1080p-cdp.dtsi
+++ b/arch/arm/boot/dts/msm8226-1080p-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
@@ -31,6 +31,7 @@
 			synaptics,i2c-pull-up;
 			synaptics,power-down;
 			synaptics,disable-gpios;
+			synaptics,fw-image-name = "PR1469074-s3408bt_001F010D.img";
 		};
 	};
 
@@ -129,6 +130,7 @@
 		qcom,cdc-mclk-gpios = <&pm8226_gpios 1 0>;
 		qcom,cdc-vdd-spkr-gpios = <&pm8226_gpios 2 0>;
 		qcom,headset-jack-type-NC;
+		qcom,mbhc-audio-jack-type = "6-pole-jack";
 	};
 
 	sound-9302 {
diff --git a/arch/arm/boot/dts/msm8226-1080p-mtp.dtsi b/arch/arm/boot/dts/msm8226-1080p-mtp.dtsi
index 31624de..3734273 100644
--- a/arch/arm/boot/dts/msm8226-1080p-mtp.dtsi
+++ b/arch/arm/boot/dts/msm8226-1080p-mtp.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
@@ -31,6 +31,7 @@
 			synaptics,i2c-pull-up;
 			synaptics,power-down;
 			synaptics,disable-gpios;
+			synaptics,fw-image-name = "PR1469074-s3408bt_001F010D.img";
 		};
 	};
 
@@ -119,6 +120,7 @@
 
 		qcom,cdc-mclk-gpios = <&pm8226_gpios 1 0>;
 		qcom,cdc-vdd-spkr-gpios = <&pm8226_gpios 2 0>;
+		qcom,cdc-us-euro-gpios = <&msmgpio 69 0>;
 	};
 
 	sound-9302 {
@@ -136,6 +138,7 @@
 
 		qcom,cdc-mclk-gpios = <&pm8226_gpios 1 0>;
 		qcom,cdc-vdd-spkr-gpios = <&pm8226_gpios 2 0>;
+		qcom,cdc-us-euro-gpios = <&msmgpio 69 0>;
 	};
 };
 
diff --git a/arch/arm/boot/dts/msm8226-720p-cdp.dtsi b/arch/arm/boot/dts/msm8226-720p-cdp.dtsi
index 9a1eb36..66f9b18 100644
--- a/arch/arm/boot/dts/msm8226-720p-cdp.dtsi
+++ b/arch/arm/boot/dts/msm8226-720p-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
@@ -35,6 +35,20 @@
 		};
 	};
 
+	i2c@f9925000 { /* BLSP1 QUP3 */
+		nfc-nci@0e {
+			compatible = "qcom,nfc-nci";
+			reg = <0x0e>;
+			qcom,irq-gpio = <&msmgpio 21 0x00>;
+			qcom,dis-gpio = <&msmgpio 20 0x00>;
+			qcom,clk-src = "BBCLK2";
+			interrupt-parent = <&msmgpio>;
+			interrupts = <21 0>;
+			qcom,clk-gpio = <&pm8226_gpios 3 0>;
+		};
+	};
+
+
 	gpio_keys {
 		compatible = "gpio-keys";
 		input-name = "gpio-keys";
@@ -106,6 +120,7 @@
 		qcom,cdc-mclk-gpios = <&pm8226_gpios 1 0>;
 		qcom,cdc-vdd-spkr-gpios = <&pm8226_gpios 2 0>;
 		qcom,headset-jack-type-NC;
+		qcom,mbhc-audio-jack-type = "6-pole-jack";
 	};
 
 	sound-9302 {
@@ -371,6 +386,11 @@
 	};
 
 	gpio@c200 { /* GPIO 3 */
+		qcom,mode = <0>;		/* QPNP_PIN_MODE_DIG_IN */
+		qcom,pull = <5>;		/* QPNP_PIN_PULL_NO */
+		qcom,vin-sel = <2>;		/* QPNP_PIN_VIN2 */
+		qcom,src-sel = <2>;		/* QPNP_PIN_SEL_FUNC_1 */
+		qcom,master-en = <1>;
 	};
 
 	gpio@c300 { /* GPIO 4 */
diff --git a/arch/arm/boot/dts/msm8226-720p-mtp.dtsi b/arch/arm/boot/dts/msm8226-720p-mtp.dtsi
index 7f4f8fc..b4d9139 100644
--- a/arch/arm/boot/dts/msm8226-720p-mtp.dtsi
+++ b/arch/arm/boot/dts/msm8226-720p-mtp.dtsi
@@ -110,6 +110,7 @@
 
 		qcom,cdc-mclk-gpios = <&pm8226_gpios 1 0>;
 		qcom,cdc-vdd-spkr-gpios = <&pm8226_gpios 2 0>;
+		qcom,cdc-us-euro-gpios = <&msmgpio 69 0>;
 	};
 
 	sound-9302 {
@@ -127,6 +128,7 @@
 
 		qcom,cdc-mclk-gpios = <&pm8226_gpios 1 0>;
 		qcom,cdc-vdd-spkr-gpios = <&pm8226_gpios 2 0>;
+		qcom,cdc-us-euro-gpios = <&msmgpio 69 0>;
 	};
 };
 
diff --git a/arch/arm/boot/dts/msm8226-bus.dtsi b/arch/arm/boot/dts/msm8226-bus.dtsi
index 74b4a30..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>;
@@ -998,9 +1002,10 @@
 		qcom,fabclk-dual = "mem_clk";
 		qcom,fabclk-active = "mem_a_clk";
 		qcom,ntieredslaves = <0>;
-		qcom,qos-freq = <4800>;
+		qcom,qos-freq = <19200>;
 		qcom,hw-sel = "BIMC";
 		qcom,rpm-en;
+		qcom,nfab = <6>;
 
 		mas-ampss-m0 {
 			cell-id = <1>;
@@ -1008,12 +1013,18 @@
 			qcom,masterp = <0>;
 			qcom,tier = <2>;
 			qcom,hw-sel = "BIMC";
-			qcom,mode = "Fixed";
+			qcom,mode = "Limiter";
 			qcom,qport = <0>;
 			qcom,ws = <10000>;
 			qcom,mas-hw-id = <0>;
 			qcom,prio-rd = <0>;
 			qcom,prio-wr = <0>;
+			qcom,mode-thresh = "Fixed";
+			qcom,thresh = <1800000>;
+			qcom,dual-conf;
+			qcom,bimc,bw = <450000>;
+			qcom,bimc,gp = <5000>;
+			qcom,bimc,thmp = <50>;
 		};
 
 		mas-mss-proc {
@@ -1082,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-camera-sensor-cdp.dtsi b/arch/arm/boot/dts/msm8226-camera-sensor-cdp.dtsi
index fa5c739..05a3f07 100644
--- a/arch/arm/boot/dts/msm8226-camera-sensor-cdp.dtsi
+++ b/arch/arm/boot/dts/msm8226-camera-sensor-cdp.dtsi
@@ -1,5 +1,5 @@
 /*
- * 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
@@ -17,7 +17,7 @@
 		cell-index = <0>;
 		compatible = "qcom,camera-led-flash";
 		qcom,flash-type = <1>;
-		qcom,flash-source = <&pm8226_flash0 &pm8226_flash1>;
+		qcom,flash-source = <&pm8226_flash0>;
 		qcom,torch-source = <&pm8226_torch>;
 	};
 };
@@ -192,4 +192,69 @@
 		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 = <90>;
+		qcom,actuator-src = <&actuator0>;
+		qcom,led-flash-src = <&led_flash0>;
+		cam_vdig-supply = <&pm8226_l5>;
+		cam_vana-supply = <&pm8226_l19>;
+		cam_vio-supply = <&pm8226_lvs1>;
+		cam_vaf-supply = <&pm8226_l15>;
+		qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana",
+			"cam_vaf";
+		qcom,cam-vreg-type = <0 1 0 0>;
+		qcom,cam-vreg-min-voltage = <1200000 0 2850000 2800000>;
+		qcom,cam-vreg-max-voltage = <1200000 0 2850000 2800000>;
+		qcom,cam-vreg-op-mode = <200000 0 80000 100000>;
+		gpios = <&msmgpio 26 0>,
+			<&msmgpio 37 0>,
+			<&msmgpio 36 0>;
+		qcom,gpio-reset = <1>;
+		qcom,gpio-standby = <2>;
+		qcom,gpio-req-tbl-num = <0 1 2>;
+		qcom,gpio-req-tbl-flags = <1 0 0>;
+		qcom,gpio-req-tbl-label = "CAMIF_MCLK",
+			"CAM_RESET1",
+			"CAM_STANDBY";
+		qcom,sensor-position = <0>;
+		qcom,sensor-mode = <0>;
+		qcom,cci-master = <0>;
+		status = "ok";
+	};
+
+	qcom,camera@1 {
+		cell-index = <1>;
+		compatible = "qcom,camera";
+		reg = <0x1>;
+		qcom,csiphy-sd-index = <1>;
+		qcom,csid-sd-index = <1>;
+		qcom,mount-angle = <0>;
+		cam_vdig-supply = <&pm8226_l5>;
+		cam_vana-supply = <&pm8226_l19>;
+		cam_vio-supply = <&pm8226_lvs1>;
+		qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana";
+		qcom,cam-vreg-type = <0 1 0>;
+		qcom,cam-vreg-min-voltage = <1200000 0 2850000>;
+		qcom,cam-vreg-max-voltage = <1200000 0 2850000>;
+		qcom,cam-vreg-op-mode = <200000 0 80000>;
+		gpios = <&msmgpio 26 0>,
+			<&msmgpio 28 0>,
+			<&msmgpio 35 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_RESET",
+			"CAM_STANDBY";
+		qcom,sensor-position = <1>;
+		qcom,sensor-mode = <1>;
+		qcom,cci-master = <0>;
+		status = "ok";
+	};
 };
diff --git a/arch/arm/boot/dts/msm8226-camera-sensor-mtp.dtsi b/arch/arm/boot/dts/msm8226-camera-sensor-mtp.dtsi
index 5d1e1c8..a6af2c2 100644
--- a/arch/arm/boot/dts/msm8226-camera-sensor-mtp.dtsi
+++ b/arch/arm/boot/dts/msm8226-camera-sensor-mtp.dtsi
@@ -1,5 +1,5 @@
 /*
- * 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
@@ -17,7 +17,7 @@
 		cell-index = <0>;
 		compatible = "qcom,camera-led-flash";
 		qcom,flash-type = <1>;
-		qcom,flash-source = <&pm8226_flash0 &pm8226_flash1>;
+		qcom,flash-source = <&pm8226_flash0>;
 		qcom,torch-source = <&pm8226_torch>;
 	};
 };
@@ -106,4 +106,71 @@
 		qcom,cci-master = <0>;
 		status = "ok";
 	};
+	qcom,camera@0 {
+		cell-index = <0>;
+		compatible = "qcom,camera";
+		reg = <0x0>;
+		qcom,csiphy-sd-index = <0>;
+		qcom,csid-sd-index = <0>;
+		qcom,mount-angle = <270>;
+		qcom,actuator-src = <&actuator0>;
+		qcom,led-flash-src = <&led_flash0>;
+		cam_vdig-supply = <&pm8226_l5>;
+		cam_vana-supply = <&pm8226_l19>;
+		cam_vio-supply = <&pm8226_lvs1>;
+		cam_vaf-supply = <&pm8226_l15>;
+		qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana",
+			 "cam_vaf";
+		qcom,cam-vreg-type = <0 1 0 0>;
+		qcom,cam-vreg-min-voltage = <1200000 0 2850000 2800000>;
+		qcom,cam-vreg-max-voltage = <1200000 0 2850000 2800000>;
+		qcom,cam-vreg-op-mode = <200000 0 80000 100000>;
+		qcom,gpio-no-mux = <0>;
+		gpios = <&msmgpio 26 0>,
+			<&msmgpio 37 0>,
+			<&msmgpio 35 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,sensor-position = <0>;
+		qcom,sensor-mode = <0>;
+		qcom,cci-master = <0>;
+		status = "ok";
+	};
+
+	qcom,camera@1 {
+		cell-index = <1>;
+		compatible = "qcom,camera";
+		reg = <0x1>;
+		qcom,csiphy-sd-index = <1>;
+		qcom,csid-sd-index = <1>;
+		qcom,mount-angle = <270>;
+		cam_vdig-supply = <&pm8226_l5>;
+		cam_vana-supply = <&pm8226_l19>;
+		cam_vio-supply = <&pm8226_lvs1>;
+		qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana";
+		qcom,cam-vreg-type = <0 1 0>;
+		qcom,cam-vreg-min-voltage = <1200000 0 2850000>;
+		qcom,cam-vreg-max-voltage = <1200000 0 2850000>;
+		qcom,cam-vreg-op-mode = <200000 0 80000>;
+		qcom,gpio-no-mux = <0>;
+		gpios = <&msmgpio 26 0>,
+			<&msmgpio 28 0>,
+			<&msmgpio 36 0>;
+		qcom,gpio-reset = <1>;
+		qcom,gpio-standby = <2>;
+		qcom,gpio-req-tbl-num = <0 1 2>;
+		qcom,gpio-req-tbl-flags = <1 0 0>;
+		qcom,gpio-req-tbl-label = "CAMIF_MCLK",
+			"CAM_RESET",
+			"CAM_STANDBY";
+		qcom,sensor-position = <1>;
+		qcom,sensor-mode = <0>;
+		qcom,cci-master = <0>;
+		status = "ok";
+	};
 };
diff --git a/arch/arm/boot/dts/msm8226-camera-sensor-qrd.dtsi b/arch/arm/boot/dts/msm8226-camera-sensor-qrd.dtsi
index fd6d618..dab92ff 100644
--- a/arch/arm/boot/dts/msm8226-camera-sensor-qrd.dtsi
+++ b/arch/arm/boot/dts/msm8226-camera-sensor-qrd.dtsi
@@ -1,5 +1,5 @@
 /*
- * 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
@@ -17,7 +17,7 @@
 		cell-index = <0>;
 		compatible = "qcom,camera-led-flash";
 		qcom,flash-type = <1>;
-		qcom,flash-source = <&pm8226_flash0 &pm8226_flash1>;
+		qcom,flash-source = <&pm8226_flash0>;
 		qcom,torch-source = <&pm8226_torch>;
 	};
 };
@@ -442,4 +442,85 @@
 		qcom,cci-master = <0>;
 		status = "ok";
 	};
+	qcom,camera@0 {
+		cell-index = <0>;
+		compatible = "qcom,camera";
+		reg = <0x0>;
+		qcom,csiphy-sd-index = <0>;
+		qcom,csid-sd-index = <0>;
+		qcom,mount-angle = <90>;
+		qcom,actuator-src = <&actuator0>;
+		qcom,eeprom-src = <&eeprom0>;
+		qcom,led-flash-src = <&led_flash0>;
+		cam_vdig-supply = <&pm8226_l5>;
+		cam_vana-supply = <&pm8226_l19>;
+		cam_vio-supply = <&pm8226_lvs1>;
+		cam_vaf-supply = <&pm8226_l15>;
+		qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana",
+			 "cam_vaf";
+		qcom,cam-vreg-type = <0 1 0 0>;
+		qcom,cam-vreg-min-voltage = <1200000 0 2850000 2800000>;
+		qcom,cam-vreg-max-voltage = <1200000 0 2850000 2800000>;
+		qcom,cam-vreg-op-mode = <200000 0 80000 100000>;
+		qcom,gpio-no-mux = <0>;
+		gpios = <&msmgpio 26 0>,
+			<&msmgpio 37 0>,
+			<&msmgpio 36 0>,
+			<&msmgpio 22 0>,
+			<&msmgpio 34 0>;
+		qcom,gpio-reset = <1>;
+		qcom,gpio-standby = <2>;
+		qcom,gpio-vdig = <3>;
+		qcom,gpio-af-pwdm = <4>;
+		qcom,gpio-req-tbl-num = <0 1 2 3 4>;
+		qcom,gpio-req-tbl-flags = <1 0 0 0 0>;
+		qcom,gpio-req-tbl-label = "CAMIF_MCLK",
+			"CAM_RESET1",
+			"CAM_STANDBY",
+			"CAM_VDIG",
+			"CAM_AF_PWDM";
+		qcom,sensor-position = <0>;
+		qcom,sensor-mode = <0>;
+		qcom,cci-master = <0>;
+		status = "ok";
+	};
+
+	qcom,camera@1 {
+		cell-index = <1>;
+		compatible = "qcom,camera";
+		reg = <0x1>;
+		qcom,csiphy-sd-index = <1>;
+		qcom,csid-sd-index = <1>;
+		qcom,eeprom-src = <&eeprom2>;
+		qcom,mount-angle = <270>;
+		cam_vdig-supply = <&pm8226_l5>;
+		cam_vana-supply = <&pm8226_l19>;
+		cam_vio-supply = <&pm8226_lvs1>;
+		qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana";
+		qcom,cam-vreg-type = <0 1 0>;
+		qcom,cam-vreg-min-voltage = <1200000 0 2850000>;
+		qcom,cam-vreg-max-voltage = <1200000 0 2850000>;
+		qcom,cam-vreg-op-mode = <200000 0 80000>;
+		qcom,gpio-no-mux = <0>;
+		gpios = <&msmgpio 26 0>,
+			<&msmgpio 28 0>,
+			<&msmgpio 35 0>,
+			<&msmgpio 21 0>;
+		qcom,gpio-reset = <1>;
+		qcom,gpio-standby = <2>;
+		qcom,gpio-vdig = <3>;
+		qcom,gpio-req-tbl-num = <0 1 2 3>;
+		qcom,gpio-req-tbl-flags = <1 0 0 0>;
+		qcom,gpio-req-tbl-label = "CAMIF_MCLK",
+			"CAM_RESET",
+			"CAM_STANDBY",
+			"CAM_VDIG";
+		qcom,gpio-set-tbl-num = <1 1>;
+		qcom,gpio-set-tbl-flags = <0 2>;
+		qcom,gpio-set-tbl-delay = <1000 4000>;
+		qcom,sensor-position = <1>;
+		qcom,sensor-mode = <0>;
+		qcom,cci-master = <0>;
+		status = "ok";
+	};
 };
diff --git a/arch/arm/boot/dts/msm8226-gpu.dtsi b/arch/arm/boot/dts/msm8226-gpu.dtsi
index 590f733..d1c3264 100644
--- a/arch/arm/boot/dts/msm8226-gpu.dtsi
+++ b/arch/arm/boot/dts/msm8226-gpu.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
@@ -34,9 +34,9 @@
 		qcom,msm-bus,num-paths = <2>;
 		qcom,msm-bus,vectors-KBps =
 			<26 512 0 0>, <89 604 0 0>,
-			<26 512 0 1600000>, <89 604 0 3200000>,
-			<26 512 0 3200000>, <89 604 0 5120000>,
-			<26 512 0 4256000>, <89 604 0 6400000>;
+			<26 512 800000 1600000>, <89 604 0 3200000>,
+			<26 512 1600000 3200000>, <89 604 0 5120000>,
+			<26 512 2128000 4256000>, <89 604 0 6400000>;
 
 
 		/* GDSC oxili regulators */
@@ -47,6 +47,9 @@
 		/* IOMMU Data */
 		iommu = <&kgsl_iommu>;
 
+		/* CPU latency parameter */
+		qcom,pm-qos-latency = <701>;
+
 		/* Power levels */
 		qcom,gpu-pwrlevels {
 			#address-cells = <1>;
diff --git a/arch/arm/boot/dts/msm8226-mdss.dtsi b/arch/arm/boot/dts/msm8226-mdss.dtsi
index 38cfe66..cedec5f 100644
--- a/arch/arm/boot/dts/msm8226-mdss.dtsi
+++ b/arch/arm/boot/dts/msm8226-mdss.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
@@ -19,8 +19,27 @@
 		interrupts = <0 72 0>;
 		vdd-supply = <&gdsc_mdss>;
 
-		qcom,max-bandwidth-low-kbps = <1660000>;
+		qcom,max-bandwidth-low-kbps = <1100000>;
 		qcom,max-bandwidth-high-kbps = <1660000>;
+
+		/* Bus Scale Settings */
+		qcom,msm-bus,name = "mdss_mdp";
+		qcom,msm-bus,num-cases = <3>;
+		qcom,msm-bus,num-paths = <1>;
+		qcom,msm-bus,vectors-KBps =
+			<22 512 0 0>,
+			<22 512 0 6400000>,
+			<22 512 0 6400000>;
+
+		/* Fudge factors */
+		qcom,mdss-ab-factor = <1 1>;		/* 1 times    */
+		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>;
@@ -28,8 +47,19 @@
 		qcom,mdss-pipe-vig-fetch-id = <1>;
 		qcom,mdss-pipe-rgb-fetch-id = <7>;
 		qcom,mdss-pipe-dma-fetch-id = <4>;
+
+		qcom,mdss-pipe-vig-xin-id = <0>;
+		qcom,mdss-pipe-rgb-xin-id = <1>;
+		qcom,mdss-pipe-dma-xin-id = <2>;
+
+		qcom,mdss-pipe-vig-clk-ctrl-offsets = <0x3AC 0 0>;
+		qcom,mdss-pipe-rgb-clk-ctrl-offsets = <0x3AC 4 8>;
+		qcom,mdss-pipe-dma-clk-ctrl-offsets = <0x3AC 8 12>;
+
 		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>;
@@ -38,14 +68,30 @@
 		qcom,mdss-wb-off = <0x00011100 0x00013100>;
 		qcom,mdss-intf-off = <0x00000000 0x00021300>;
 		qcom,mdss-rot-block-size = <64>;
-		qcom,mdss-smp-mb-per-pipe = <4>;
+		qcom,mdss-rotator-ot-limit = <2>;
+		qcom,mdss-smp-mb-per-pipe = <3>;
 		vdd-cx-supply = <&pm8226_s1_corner>;
 
 		qcom,vbif-settings = <0x004 0x00000001>,
 				     <0x0D8 0x00000707>,
 				     <0x124 0x00000003>;
 		qcom,mdp-settings = <0x02E0 0x000000A5>,
-				    <0x02E4 0x00000055>;
+				    <0x02E4 0x00000055>,
+				    <0x03AC 0xC0000CCC>,
+				    <0x03B4 0xC0000000>,
+				    <0x03BC 0x00C00C00>,
+				    <0x04A8 0x0CCCC000>,
+				    <0x04B0 0xC0000000>,
+				    <0x04B8 0xC0000000>;
+
+		/* buffer parameters to calculate prefill bandwidth */
+		qcom,mdss-prefill-outstanding-buffer-bytes = <1024>;
+		qcom,mdss-prefill-y-buffer-bytes = <0>;
+		qcom,mdss-prefill-scaler-buffer-lines-bilinear = <2>;
+		qcom,mdss-prefill-scaler-buffer-lines-caf = <4>;
+		qcom,mdss-prefill-post-scaler-buffer-pixels = <0>;
+		qcom,mdss-prefill-pingpong-buffer-pixels = <4096>;
+		qcom,mdss-prefill-fbc-lines = <0>;
 
 		mdss_fb0: qcom,mdss_fb_primary {
 			cell-index = <0>;
@@ -65,7 +111,10 @@
 		compatible = "qcom,mdss-dsi-ctrl";
 		label = "MDSS DSI CTRL->0";
 		cell-index = <0>;
-		reg = <0xfd922800 0x600>;
+		reg = 	<0xfd922800 0x1f8>,
+			<0xfd922b00 0x2b0>,
+			<0xfd828000 0x108>;
+		reg-names = "dsi_ctrl", "dsi_phy", "mmss_misc_phys";
 		qcom,mdss-fb-map = <&mdss_fb0>;
 		qcom,mdss-mdp = <&mdss_mdp>;
 		vdd-supply = <&pm8226_l15>;
diff --git a/arch/arm/boot/dts/msm8226-qrd-skuf.dtsi b/arch/arm/boot/dts/msm8226-qrd-skuf.dtsi
index 2e32ac4..42de953 100755
--- a/arch/arm/boot/dts/msm8226-qrd-skuf.dtsi
+++ b/arch/arm/boot/dts/msm8226-qrd-skuf.dtsi
@@ -82,7 +82,7 @@
 			avdd-supply = <&tp_power>;
 			goodix,panel-coords = <0 0 720 1200>;
 			goodix,display-coords = <0 0 720 1080>;
-			goodix,button-map= <158 102 139>;
+			goodix,button-map= <139 172 158>;
 			goodix,product-id = "915";
 			goodix,cfg-data0 = [
 				41 D0 02 00 05 05 35 11 01 0F
@@ -125,6 +125,8 @@
 				FF FF FF FF FF FF FF FF FF FF
 				FF FF FF FF 3E 01];
 			goodix,fw_name = "gtp_fw.bin";
+			goodix,have-touch-key;
+			goodix,driver-send-cfg;
 		};
 	};
 };
diff --git a/arch/arm/boot/dts/msm8226-qrd.dtsi b/arch/arm/boot/dts/msm8226-qrd.dtsi
index 7ff97f6..cd56da3 100644
--- a/arch/arm/boot/dts/msm8226-qrd.dtsi
+++ b/arch/arm/boot/dts/msm8226-qrd.dtsi
@@ -17,6 +17,20 @@
 		status = "ok";
 	};
 
+        i2c@f9925000 { /* BLSP1 QUP3 */
+                nfc-nci@0e {
+                        compatible = "qcom,nfc-nci";
+                        reg = <0x0e>;
+                        qcom,irq-gpio = <&msmgpio 21 0x00>;
+                        qcom,dis-gpio = <&msmgpio 20 0x00>;
+                        qcom,clk-src = "BBCLK2";
+                        qcom,clk-en-gpio = <&msmgpio 0 0x00>;
+                        interrupt-parent = <&msmgpio>;
+                        interrupts = <21 0>;
+                        qcom,clk-gpio = <&pm8226_gpios 3 0>;
+                };
+        };
+
 	i2c@f9927000 { /* BLSP1 QUP5 */
 		synaptics@20 {
 			compatible = "synaptics,rmi4";
@@ -468,13 +482,6 @@
 	};
 };
 
-&slim_msm {
-	tapan_codec {
-		qcom,cdc-micbias1-ext-cap;
-		qcom,cdc-micbias3-ext-cap;
-	};
-};
-
 &pm8226_vadc {
 	chan@30 {
 		label = "batt_therm";
diff --git a/arch/arm/boot/dts/msm8226-regulator.dtsi b/arch/arm/boot/dts/msm8226-regulator.dtsi
index 7db913a..78e1a63 100644
--- a/arch/arm/boot/dts/msm8226-regulator.dtsi
+++ b/arch/arm/boot/dts/msm8226-regulator.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
@@ -19,7 +19,7 @@
 			regulator-name = "8226_s2";
 			reg = <0x1700 0x100>;
 			regulator-min-microvolt = <900000>;
-			regulator-max-microvolt = <1275000>;
+			regulator-max-microvolt = <1350000>;
 			qcom,mode = "auto";
 		};
 	};
@@ -30,67 +30,88 @@
 &soc {
 	apc_vreg_corner: regulator@f9018000 {
 		status = "okay";
-		compatible = "qti,cpr-regulator";
+		compatible = "qcom,cpr-regulator";
 		reg = <0xf9018000 0x1000>, <0xf9011064 4>, <0xfc4b8000 0x1000>;
 		reg-names = "rbcpr", "rbcpr_clk", "efuse_addr";
 		interrupts = <0 15 0>;
 		regulator-name = "apc_corner";
-		regulator-min-microvolt = <1>;
-		regulator-max-microvolt = <3>;
 
-		qti,pvs-fuse-redun-sel = <22 24 3 2 0>;
-		qti,pvs-fuse = <22 6 5 0>;
-		qti,pvs-fuse-redun = <22 27 5 0>;
+		qcom,pvs-fuse-redun-sel = <22 24 3 2 0>;
+		qcom,pvs-fuse = <22 6 5 0>;
+		qcom,pvs-fuse-redun = <22 27 5 0>;
 
-		qti,pvs-init-voltage = <1275000 1275000 1275000 1275000 1275000
-					1275000 1260000 1245000 1230000 1215000
-					1200000 1185000 1170000 1155000 1140000
-					1140000 1140000 1140000 1140000 1140000
-					1150000 1140000 1140000 1140000 1140000
-					1140000 1140000 1140000 1275000 1275000
-					1275000 1275000>;
-		qti,pvs-corner-ceiling-slow = <1050000 1150000 1275000>;
-		qti,pvs-corner-ceiling-nom  = <1050000 1075000 1200000>;
-		qti,pvs-corner-ceiling-fast = <1050000 1050000 1100000>;
+		qcom,pvs-voltage-table =
+			<1050000 1150000 1350000>,
+			<1050000 1150000 1340000>,
+			<1050000 1150000 1330000>,
+			<1050000 1150000 1320000>,
+			<1050000 1150000 1310000>,
+			<1050000 1150000 1300000>,
+			<1050000 1150000 1290000>,
+			<1050000 1150000 1280000>,
+			<1050000 1150000 1270000>,
+			<1050000 1140000 1260000>,
+			<1050000 1130000 1250000>,
+			<1050000 1120000 1240000>,
+			<1050000 1110000 1230000>,
+			<1050000 1100000 1220000>,
+			<1050000 1090000 1210000>,
+			<1050000 1080000 1200000>,
+			<1050000 1070000 1190000>,
+			<1050000 1060000 1180000>,
+			<1050000 1050000 1170000>,
+			<1050000 1050000 1160000>,
+			<1050000 1050000 1150000>,
+			<1050000 1050000 1140000>,
+			<1050000 1050000 1140000>,
+			<1050000 1050000 1140000>,
+			<1050000 1050000 1140000>,
+			<1050000 1050000 1140000>,
+			<1050000 1050000 1140000>,
+			<1050000 1050000 1140000>,
+			<1050000 1050000 1140000>,
+			<1050000 1050000 1140000>,
+			<1050000 1050000 1140000>,
+			<1050000 1050000 1140000>;
+		qcom,cpr-voltage-ceiling = <1050000 1150000 1280000>;
+		qcom,cpr-voltage-floor = <1050000 1050000 1100000>;
 		vdd-apc-supply = <&pm8226_s2>;
 
 		vdd-mx-supply = <&pm8226_l3_ao>;
-		qti,vdd-mx-vmax = <1350000>;
-		qti,vdd-mx-vmin-method = <1>;
+		qcom,vdd-mx-vmax = <1337500>;
+		qcom,vdd-mx-vmin-method = <1>;
 
-		qti,cpr-ref-clk = <19200>;
-		qti,cpr-timer-delay = <5000>;
-		qti,cpr-timer-cons-up = <0>;
-		qti,cpr-timer-cons-down = <2>;
-		qti,cpr-irq-line = <0>;
-		qti,cpr-step-quotient = <15>;
-		qti,cpr-up-threshold = <0>;
-		qti,cpr-down-threshold = <10>;
-		qti,cpr-idle-clocks = <0>;
-		qti,cpr-gcnt-time = <1>;
-		qti,vdd-apc-step-up-limit = <1>;
-		qti,vdd-apc-step-down-limit = <1>;
-		qti,cpr-apc-volt-step = <5000>;
+		qcom,cpr-ref-clk = <19200>;
+		qcom,cpr-timer-delay = <5000>;
+		qcom,cpr-timer-cons-up = <0>;
+		qcom,cpr-timer-cons-down = <2>;
+		qcom,cpr-irq-line = <0>;
+		qcom,cpr-step-quotient = <30>;
+		qcom,cpr-idle-clocks = <0>;
+		qcom,cpr-gcnt-time = <1>;
+		qcom,vdd-apc-step-up-limit = <1>;
+		qcom,vdd-apc-step-down-limit = <1>;
+		qcom,cpr-apc-volt-step = <10000>;
 
-		qti,cpr-fuse-redun-sel = <138 57 1 1 0>;
-		qti,cpr-fuse-row = <138 0>;
-		qti,cpr-fuse-bp-cpr-disable = <36>;
-		qti,cpr-fuse-bp-scheme = <37>;
-		qti,cpr-fuse-target-quot = <24 12 0>;
-		qti,cpr-fuse-ro-sel = <54 38 41>;
-		qti,cpr-fuse-redun-row = <139 0>;
-		qti,cpr-fuse-redun-target-quot = <24 12 0>;
-		qti,cpr-fuse-redun-ro-sel = <46 36 39>;
+		qcom,cpr-fuse-redun-sel = <138 57 1 1 0>;
+		qcom,cpr-fuse-row = <138 0>;
+		qcom,cpr-fuse-bp-cpr-disable = <36>;
+		qcom,cpr-fuse-bp-scheme = <37>;
+		qcom,cpr-fuse-target-quot = <24 12 0>;
+		qcom,cpr-fuse-ro-sel = <54 38 41>;
+		qcom,cpr-fuse-redun-row = <139 0>;
+		qcom,cpr-fuse-redun-target-quot = <24 12 0>;
+		qcom,cpr-fuse-redun-ro-sel = <46 36 39>;
 
-		qti,cpr-enable;
-		qti,cpr-fuse-cond-min-volt-sel = <54 42 6 7 1>;
-		qti,cpr-cond-min-voltage = <1140000>;
-		qti,cpr-fuse-uplift-sel = <22 53 1 0 0>;
-		qti,cpr-uplift-voltage = <50000>;
-		qti,cpr-uplift-quotient = <0 0 120>;
-		qti,cpr-uplift-max-volt = <1350000>;
-		qti,cpr-uplift-speed-bin = <1>;
-		qti,speed-bin-fuse-sel = <22 0 3 0>;
+		qcom,cpr-enable;
+		qcom,cpr-fuse-cond-min-volt-sel = <54 42 6 7 1>;
+		qcom,cpr-cond-min-voltage = <1140000>;
+		qcom,cpr-fuse-uplift-sel = <22 53 1 0 0>;
+		qcom,cpr-uplift-voltage = <50000>;
+		qcom,cpr-uplift-quotient = <0 0 120>;
+		qcom,cpr-uplift-max-volt = <1330000>;
+		qcom,cpr-uplift-speed-bin = <1>;
+		qcom,speed-bin-fuse-sel = <22 0 3 0>;
 	};
 };
 
@@ -189,7 +210,7 @@
 		pm8226_l3: regulator-l3 {
 			regulator-name = "8226_l3";
 			regulator-min-microvolt = <750000>;
-			regulator-max-microvolt = <1275000>;
+			regulator-max-microvolt = <1337500>;
 			status = "okay";
 		};
 		pm8226_l3_ao: regulator-3-ao {
@@ -197,7 +218,7 @@
 			regulator-name = "8226_l3_ao";
 			qcom,set = <1>;
 			regulator-min-microvolt = <750000>;
-			regulator-max-microvolt = <1275000>;
+			regulator-max-microvolt = <1337500>;
 			status = "okay";
 		};
 		pm8226_l3_so: regulator-l3-so {
@@ -205,7 +226,7 @@
 			regulator-name = "8226_l3_so";
 			qcom,set = <2>;
 			regulator-min-microvolt = <750000>;
-			regulator-max-microvolt = <1275000>;
+			regulator-max-microvolt = <1337500>;
 			qcom,init-voltage = <750000>;
 			status = "okay";
 		};
diff --git a/arch/arm/boot/dts/msm8226-v1-pm.dtsi b/arch/arm/boot/dts/msm8226-v1-pm.dtsi
index a1a8480..10aff70 100644
--- a/arch/arm/boot/dts/msm8226-v1-pm.dtsi
+++ b/arch/arm/boot/dts/msm8226-v1-pm.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
@@ -105,7 +105,7 @@
 		qcom,L2-spm-is-apcs-master;
 	};
 
-	qcom,lpm-levels {
+	lpm_levels: qcom,lpm-levels {
 		compatible = "qcom,lpm-levels";
 		qcom,default-l2-state = "l2_cache_active";
 		#address-cells = <1>;
@@ -145,16 +145,6 @@
 			compatible = "qcom,system-modes";
 
 			qcom,system-modes@0 {
-				qcom,l2 = "l2_cache_gdhs";
-				qcom,latency-us = <10700>;
-				qcom,ss-power = <372>;
-				qcom,energy-overhead = <738750>;
-				qcom,time-overhead = <1410>;
-				qcom,min-cpu-mode= "pc";
-				qcom,sync-cpus;
-			};
-
-			qcom,system-modes@1 {
 				qcom,l2 = "l2_cache_pc_no_rpm";
 				qcom,latency-us = <1000>;
 				qcom,ss-power = <315>;
@@ -164,7 +154,7 @@
 				qcom,sync-cpus;
 			};
 
-			qcom,system-modes@2 {
+			qcom,system-modes@1 {
 				qcom,l2 = "l2_cache_pc";
 				qcom,latency-us = <12700>;
 				qcom,ss-power = <315>;
@@ -172,6 +162,7 @@
 				qcom,time-overhead = <2400>;
 				qcom,min-cpu-mode= "pc";
 				qcom,sync-cpus;
+				qcom,send-rpm-sleep-set;
 			};
 		};
 	};
@@ -235,6 +226,9 @@
 			<0xff 191>, /* lpass_irq_out_apcs(3) */
 			<0xff 192>, /* lpass_irq_out_apcs(4) */
 			<0xff 194>, /* lpass_irq_out_apcs(6) */
+			<0xff 195>, /* SLIMbus  slimbus_core_ee1_irq */
+			<0xff 196>, /* BAM-Lite - SlimBus */
+			<0xff 198>, /* coresight-tmc-etr interrupt */
 			<0xff 200>, /* rpm_ipc(4) */
 			<0xff 201>, /* rpm_ipc(5) */
 			<0xff 202>, /* rpm_ipc(6) */
@@ -306,6 +300,7 @@
 		qcom,pc-resets-timer;
 		qcom,cpus-as-clocks;
 		qcom,synced-clocks;
+		qcom,lpm-levels = <&lpm_levels>;
 	};
 
 	qcom,cpu-sleep-status@f9088008{
diff --git a/arch/arm/boot/dts/msm8226-v1-qrd-dvt.dts b/arch/arm/boot/dts/msm8226-v1-qrd-dvt.dts
index 7e9f91b..9bfd280 100644
--- a/arch/arm/boot/dts/msm8226-v1-qrd-dvt.dts
+++ b/arch/arm/boot/dts/msm8226-v1-qrd-dvt.dts
@@ -27,3 +27,10 @@
 &dsi_hx8394a_720_vid {
 	qcom,cont-splash-enabled;
 };
+
+&slim_msm {
+	tapan_codec {
+		qcom,cdc-micbias1-ext-cap;
+		qcom,cdc-micbias3-ext-cap;
+	};
+};
\ No newline at end of file
diff --git a/arch/arm/boot/dts/msm8226-v1-qrd-evt.dts b/arch/arm/boot/dts/msm8226-v1-qrd-evt.dts
index c93d9db..44dd280 100644
--- a/arch/arm/boot/dts/msm8226-v1-qrd-evt.dts
+++ b/arch/arm/boot/dts/msm8226-v1-qrd-evt.dts
@@ -27,3 +27,10 @@
 &dsi_nt35590_720_vid {
 	qcom,cont-splash-enabled;
 };
+
+&slim_msm {
+	tapan_codec {
+		qcom,cdc-micbias1-ext-cap;
+		qcom,cdc-micbias3-ext-cap;
+	};
+};
\ No newline at end of file
diff --git a/arch/arm/boot/dts/msm8226-v1-qrd-skuf-pvt.dts b/arch/arm/boot/dts/msm8226-v1-qrd-skuf-pvt.dts
index 43e1e21..75885a3 100644
--- a/arch/arm/boot/dts/msm8226-v1-qrd-skuf-pvt.dts
+++ b/arch/arm/boot/dts/msm8226-v1-qrd-skuf-pvt.dts
@@ -20,3 +20,9 @@
 	qcom,board-id = <0x2000b 2>;
 };
 
+&slim_msm {
+	tapan_codec {
+		qcom,cdc-micbias1-ext-cap;
+		qcom,cdc-micbias3-ext-cap;
+	};
+};
\ No newline at end of file
diff --git a/arch/arm/boot/dts/msm8226-v1-qrd-skuf.dts b/arch/arm/boot/dts/msm8226-v1-qrd-skuf.dts
index b836928..d5df1d3 100644
--- a/arch/arm/boot/dts/msm8226-v1-qrd-skuf.dts
+++ b/arch/arm/boot/dts/msm8226-v1-qrd-skuf.dts
@@ -27,3 +27,10 @@
 &pm8226_iadc {
         qcom,rsense = <10000000>;
 };
+
+&slim_msm {
+	tapan_codec {
+		qcom,cdc-micbias1-ext-cap;
+		qcom,cdc-micbias3-ext-cap;
+	};
+};
\ No newline at end of file
diff --git a/arch/arm/boot/dts/msm8226-v1.dtsi b/arch/arm/boot/dts/msm8226-v1.dtsi
index 7f2048f..b9455fb 100644
--- a/arch/arm/boot/dts/msm8226-v1.dtsi
+++ b/arch/arm/boot/dts/msm8226-v1.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
@@ -65,3 +65,63 @@
 	qcom,retain-periph;
 	qcom,retain-mem;
 };
+
+&pm8226_s2 {
+	regulator-max-microvolt = <1275000>;
+};
+
+&pm8226_l3 {
+	regulator-max-microvolt = <1287500>;
+};
+
+&pm8226_l3_ao {
+	regulator-max-microvolt = <1287500>;
+};
+
+&pm8226_l3_so {
+	regulator-max-microvolt = <1287500>;
+};
+
+&apc_vreg_corner {
+	regulator-min-microvolt = <1>;
+	regulator-max-microvolt = <3>;
+	qcom,pvs-voltage-table =
+		<1050000 1150000 1275000>,
+		<1050000 1150000 1275000>,
+		<1050000 1150000 1275000>,
+		<1050000 1150000 1275000>,
+		<1050000 1150000 1275000>,
+		<1050000 1150000 1275000>,
+		<1050000 1150000 1275000>,
+		<1050000 1150000 1275000>,
+		<1050000 1150000 1275000>,
+		<1050000 1150000 1275000>,
+		<1050000 1150000 1275000>,
+		<1050000 1150000 1275000>,
+		<1050000 1150000 1275000>,
+		<1050000 1150000 1275000>,
+		<1050000 1150000 1275000>,
+		<1050000 1150000 1275000>,
+		<1050000 1150000 1275000>,
+		<1050000 1150000 1275000>,
+		<1050000 1150000 1275000>,
+		<1050000 1150000 1275000>,
+		<1050000 1150000 1275000>,
+		<1050000 1150000 1275000>,
+		<1050000 1150000 1275000>,
+		<1050000 1150000 1275000>,
+		<1050000 1150000 1275000>,
+		<1050000 1150000 1275000>,
+		<1050000 1150000 1275000>,
+		<1050000 1150000 1275000>,
+		<1050000 1150000 1275000>,
+		<1050000 1150000 1275000>,
+		<1050000 1150000 1275000>,
+		<1050000 1150000 1275000>;
+	qcom,cpr-voltage-ceiling = <1050000 1150000 1275000>;
+	qcom,cpr-voltage-floor = <1050000 1050000 1100000>;
+	qcom,cpr-step-quotient = <15>;
+	qcom,cpr-apc-volt-step = <5000>;
+	qcom,cpr-up-threshold = <0>;
+	qcom,cpr-down-threshold = <10>;
+};
diff --git a/arch/arm/boot/dts/msm8226-v2-1080p-cdp.dts b/arch/arm/boot/dts/msm8226-v2-1080p-cdp.dts
index 77cc08c..d48f8b6 100644
--- a/arch/arm/boot/dts/msm8226-v2-1080p-cdp.dts
+++ b/arch/arm/boot/dts/msm8226-v2-1080p-cdp.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
@@ -21,6 +21,6 @@
 	qcom,board-id = <1 2>;
 };
 
-&hsic_host {
+&smsc_hub {
 	status = "ok";
 };
diff --git a/arch/arm/boot/dts/msm8226-v2-720p-cdp.dts b/arch/arm/boot/dts/msm8226-v2-720p-cdp.dts
index 966ae2b..f73bac0 100644
--- a/arch/arm/boot/dts/msm8226-v2-720p-cdp.dts
+++ b/arch/arm/boot/dts/msm8226-v2-720p-cdp.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
@@ -21,6 +21,6 @@
 	qcom,board-id = <1 0>;
 };
 
-&hsic_host {
+&smsc_hub {
 	status = "ok";
 };
diff --git a/arch/arm/boot/dts/msm8226-v2-pm.dtsi b/arch/arm/boot/dts/msm8226-v2-pm.dtsi
index 2e9f6db..7af2c7f 100644
--- a/arch/arm/boot/dts/msm8226-v2-pm.dtsi
+++ b/arch/arm/boot/dts/msm8226-v2-pm.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
@@ -96,7 +96,7 @@
 		qcom,phase-port = <0x1>;
 		qcom,pfm-port = <0x2>;
 		qcom,saw2-spm-cmd-ret = [00 03 00 0f];
-		qcom,saw2-spm-cmd-gdhs = [00 20 32 6b c0 e0 d0 42 07 50
+		qcom,saw2-spm-cmd-gdhs = [00 20 32 6b c0 e0 d0 42 03 50
 				4e 02 02 d0 e0 c0 22 6b 02 32 50 0f];
 		qcom,saw2-spm-cmd-pc-no-rpm = [00 32 b0 10 e0 d0 6b c0 42 f0
 				11 03 01 b0 50 4e 02 02 c0 d0 12 e0 6b 02 32
@@ -107,7 +107,7 @@
 		qcom,L2-spm-is-apcs-master;
 	};
 
-	qcom,lpm-levels {
+	lpm_levels: qcom,lpm-levels {
 		compatible = "qcom,lpm-levels";
 		qcom,default-l2-state = "l2_cache_active";
 		#address-cells = <1>;
@@ -148,11 +148,11 @@
 
 			qcom,system-modes@0 {
 				qcom,l2 = "l2_cache_gdhs";
-				qcom,latency-us = <10700>;
+				qcom,latency-us = <700>;
 				qcom,ss-power = <372>;
 				qcom,energy-overhead = <738750>;
 				qcom,time-overhead = <1410>;
-				qcom,min-cpu-mode= "pc";
+				qcom,min-cpu-mode= "standalone_pc";
 				qcom,sync-cpus;
 			};
 
@@ -174,6 +174,7 @@
 				qcom,time-overhead = <2400>;
 				qcom,min-cpu-mode= "pc";
 				qcom,sync-cpus;
+				qcom,send-rpm-sleep-set;
 			};
 		};
 	};
@@ -237,6 +238,9 @@
 			<0xff 191>, /* lpass_irq_out_apcs(3) */
 			<0xff 192>, /* lpass_irq_out_apcs(4) */
 			<0xff 194>, /* lpass_irq_out_apcs(6) */
+			<0xff 195>, /* SLIMbus  slimbus_core_ee1_irq */
+			<0xff 196>, /* BAM-Lite - SlimBus */
+			<0xff 198>, /* coresight-tmc-etr interrupt */
 			<0xff 200>, /* rpm_ipc(4) */
 			<0xff 201>, /* rpm_ipc(5) */
 			<0xff 202>, /* rpm_ipc(6) */
@@ -308,6 +312,7 @@
 		qcom,pc-resets-timer;
 		qcom,cpus-as-clocks;
 		qcom,synced-clocks;
+		qcom,lpm-levels = <&lpm_levels>;
 	};
 
 	qcom,cpu-sleep-status@f9088008{
diff --git a/arch/arm/boot/dts/msm8226-v2-qrd-dvt.dts b/arch/arm/boot/dts/msm8226-v2-qrd-dvt.dts
index 13402af..5fd1d3b 100644
--- a/arch/arm/boot/dts/msm8226-v2-qrd-dvt.dts
+++ b/arch/arm/boot/dts/msm8226-v2-qrd-dvt.dts
@@ -35,3 +35,10 @@
 &pm8226_iadc {
 	qcom,rsense = <10000000>;
 };
+
+&slim_msm {
+	tapan_codec {
+		qcom,cdc-micbias1-ext-cap;
+		qcom,cdc-micbias3-ext-cap;
+	};
+};
\ No newline at end of file
diff --git a/arch/arm/boot/dts/msm8226-v2-qrd-evt.dts b/arch/arm/boot/dts/msm8226-v2-qrd-evt.dts
index b707d1c..fedbb9a 100644
--- a/arch/arm/boot/dts/msm8226-v2-qrd-evt.dts
+++ b/arch/arm/boot/dts/msm8226-v2-qrd-evt.dts
@@ -27,3 +27,10 @@
 &dsi_nt35590_720_vid {
 	qcom,cont-splash-enabled;
 };
+
+&slim_msm {
+	tapan_codec {
+		qcom,cdc-micbias1-ext-cap;
+		qcom,cdc-micbias3-ext-cap;
+	};
+};
\ No newline at end of file
diff --git a/arch/arm/boot/dts/msm8226-v2-qrd-pvt.dts b/arch/arm/boot/dts/msm8226-v2-qrd-pvt.dts
index 4b6a1da..e78f24c 100644
--- a/arch/arm/boot/dts/msm8226-v2-qrd-pvt.dts
+++ b/arch/arm/boot/dts/msm8226-v2-qrd-pvt.dts
@@ -27,3 +27,10 @@
 &dsi_nt35590_720_vid {
 	qcom,cont-splash-enabled;
 };
+
+&slim_msm {
+	tapan_codec {
+		qcom,cdc-micbias1-ext-cap;
+		qcom,cdc-micbias3-ext-cap;
+	};
+};
\ No newline at end of file
diff --git a/arch/arm/boot/dts/msm8226-v2-qrd-skuf-pvt.dts b/arch/arm/boot/dts/msm8226-v2-qrd-skuf-pvt.dts
index f5ac301..ad1d077 100644
--- a/arch/arm/boot/dts/msm8226-v2-qrd-skuf-pvt.dts
+++ b/arch/arm/boot/dts/msm8226-v2-qrd-skuf-pvt.dts
@@ -20,3 +20,9 @@
 	qcom,board-id = <0x2000b 0x2>;
 };
 
+&slim_msm {
+	tapan_codec {
+		qcom,cdc-micbias1-ext-cap;
+		qcom,cdc-micbias3-ext-cap;
+	};
+};
\ No newline at end of file
diff --git a/arch/arm/boot/dts/msm8226-v2-qrd-skuf.dts b/arch/arm/boot/dts/msm8226-v2-qrd-skuf.dts
index 9aa12f6..be6fb69 100644
--- a/arch/arm/boot/dts/msm8226-v2-qrd-skuf.dts
+++ b/arch/arm/boot/dts/msm8226-v2-qrd-skuf.dts
@@ -27,3 +27,10 @@
 &pm8226_iadc {
 	qcom,rsense = <10000000>;
 };
+
+&slim_msm {
+	tapan_codec {
+		qcom,cdc-micbias1-ext-cap;
+		qcom,cdc-micbias3-ext-cap;
+	};
+};
\ No newline at end of file
diff --git a/arch/arm/boot/dts/msm8226-v2.dtsi b/arch/arm/boot/dts/msm8226-v2.dtsi
index 4149169..787c9fb 100644
--- a/arch/arm/boot/dts/msm8226-v2.dtsi
+++ b/arch/arm/boot/dts/msm8226-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
@@ -31,41 +31,34 @@
 		      <223 0x20000>;
 };
 
-&pm8226_l3 {
-	regulator-min-microvolt = <750000>;
-	regulator-max-microvolt = <1337500>;
-};
-
-&pm8226_l3_ao {
-	regulator-min-microvolt = <750000>;
-	regulator-max-microvolt = <1337500>;
-};
-
-&pm8226_l3_so {
-	regulator-min-microvolt = <750000>;
-	regulator-max-microvolt = <1337500>;
-};
-
-&pm8226_s2 {
-	regulator-min-microvolt = <900000>;
-	regulator-max-microvolt = <1330000>;
-};
-
 &apc_vreg_corner {
-	qti,pvs-init-voltage = <1330000 1330000 1330000 1320000 1310000
-					1300000 1290000 1280000 1270000 1260000
-					1250000 1240000 1230000 1220000 1210000
-					1200000 1190000 1180000 1170000 1160000
-					1150000 1140000 1140000 1140000 1140000
-					1140000 1140000 1140000 1140000 1140000
-					1140000 1140000>;
-	qti,pvs-corner-ceiling-slow = <1050000 1150000 1280000>;
-	qti,pvs-corner-ceiling-nom  = <1050000 1080000 1200000>;
-	qti,pvs-corner-ceiling-fast = <1050000 1050000 1100000>;
-	qti,cpr-step-quotient = <30>;
-	qti,cpr-up-threshold = <0>;
-	qti,cpr-down-threshold = <5>;
-	qti,cpr-apc-volt-step = <10000>;
+	regulator-min-microvolt = <1>;
+	regulator-max-microvolt = <14>;
+	qcom,cpr-up-threshold = <0>;
+	qcom,cpr-down-threshold = <5>;
+	qcom,cpr-corner-map = <1 1 2 2 3 3 3 3 3 3 3 3 3 3>;
+	qcom,pvs-version-fuse-sel = <22 4 2 0>;
+	qcom,cpr-corner-frequency-map =
+			<1 300000000>,
+			<2 384000000>,
+			<3 600000000>,
+			<4 787200000>,
+			<5 998400000>,
+			<6 1094400000>,
+			<7 1190400000>,
+			<8 1305600000>,
+			<9 1344000000>,
+			<10 1401600000>,
+			<11 1497600000>,
+			<12 1593600000>,
+			<13 1689600000>,
+			<14 1785600000>;
+	qcom,cpr-speed-bin-max-corners =
+			<0 2 2 4 7>,
+			<1 2 2 4 12>,
+			<2 2 2 4 10>,
+			<5 2 2 4 14>;
+	qcom,cpr-quot-adjust-scaling-factor-max = <650>;
 };
 
 &msm_gpu {
@@ -78,41 +71,54 @@
 		reg =	<0xf9011050 0x8>,
 			<0xfc4b80b0 0x8>;
 		reg-names = "rcg-base", "efuse";
+		qcom,speed0-bin-v0 =
+			<         0 0>,
+			< 384000000 2>,
+			< 787200000 4>,
+			<1190400000 7>;
 		qcom,speed0-bin-v2 =
 			<         0 0>,
-			< 384000000 1>,
-			< 787200000 2>,
-			<1190400000 3>;
-		qcom,speed6-bin-v2 =
-			<         0 0>,
-			< 384000000 1>,
-			< 787200000 2>,
-			<1190400000 3>;
+			< 384000000 2>,
+			< 787200000 4>,
+			< 998400000 5>,
+			<1094400000 6>,
+			<1190400000 7>;
 		qcom,speed2-bin-v2 =
 			<         0 0>,
-			< 384000000 1>,
-			< 787200000 2>,
-			<1401600000 3>;
-		qcom,speed5-bin-v2 =
-			<         0 0>,
-			< 384000000 1>,
-			< 787200000 2>,
-			<1401600000 3>;
-		qcom,speed4-bin-v2 =
-			<         0 0>,
-			< 384000000 1>,
-			< 787200000 2>,
-			<1401600000 3>;
-		qcom,speed7-bin-v2 =
-			<         0 0>,
-			< 384000000 1>,
-			< 787200000 2>,
-			<1401600000 3>;
+			< 384000000 2>,
+			< 787200000 4>,
+			< 998400000 5>,
+			<1094400000 6>,
+			<1190400000 7>,
+			<1305600000 8>,
+			<1344000000 9>,
+			<1401600000 10>;
 		qcom,speed1-bin-v2 =
 			<         0 0>,
-			< 384000000 1>,
-			< 787200000 2>,
-			<1593600000 3>;
+			< 384000000 2>,
+			< 787200000 4>,
+			< 998400000 5>,
+			<1094400000 6>,
+			<1190400000 7>,
+			<1305600000 8>,
+			<1344000000 9>,
+			<1401600000 10>,
+			<1497600000 11>,
+			<1593600000 12>;
+		qcom,speed5-bin-v2 =
+			<         0 0>,
+			< 384000000 2>,
+			< 787200000 4>,
+			< 998400000 5>,
+			<1094400000 6>,
+			<1190400000 7>,
+			<1305600000 8>,
+			<1344000000 9>,
+			<1401600000 10>,
+			<1497600000 11>,
+			<1593600000 12>,
+			<1689600000 13>,
+			<1785600000 14>;
 	};
 };
 
diff --git a/arch/arm/boot/dts/msm8226.dtsi b/arch/arm/boot/dts/msm8226.dtsi
index baa81cc..8d2414c 100644
--- a/arch/arm/boot/dts/msm8226.dtsi
+++ b/arch/arm/boot/dts/msm8226.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
@@ -282,8 +282,9 @@
 		qcom,hsusb-otg-phy-type = <2>;
 		qcom,hsusb-otg-mode = <1>;
 		qcom,hsusb-otg-otg-control = <2>;
+		qcom,hsusb-otg-disable-reset;
 		qcom,dp-manual-pullup;
-		qcom,ahb-async-bridge-bypass;
+		qcom,usbin-vadc = <&pm8226_vadc>;
 
 		qcom,msm-bus,name = "usb";
 		qcom,msm-bus,num-cases = <3>;
@@ -299,37 +300,46 @@
 		reg = <0xfe8050c8 0xc8>;
 		qcom,android-usb-swfi-latency = <1>;
 		qcom,streaming-func = "rndis";
+		qcom,android-usb-uicc-nluns = <1>;
 	};
 
-	hsic_host: hsic@f9a00000 {
+	smsc_hub: hsic_hub {
 		status = "disabled";
-		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 115 0x8>;
-		interrupt-names = "core_irq", "async_irq", "wakeup";
-		hsic_vdd_dig-supply = <&pm8226_s1_corner>;
-		HSIC_GDSC-supply = <&gdsc_usb_hsic>;
-		hsic,strobe-gpio = <&msmgpio 115 0x00>;
-		hsic,data-gpio = <&msmgpio 116 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>;
+		compatible = "qcom,hsic-smsc-hub";
+		smsc,model-id = <0>;
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
 
-		qcom,msm-bus,name = "hsic";
-		qcom,msm-bus,num-cases = <2>;
-		qcom,msm-bus,num-paths = <1>;
-		qcom,msm-bus,vectors-KBps =
+		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 115 0x8>;
+			interrupt-names = "core_irq", "async_irq", "wakeup";
+			hsic_vdd_dig-supply = <&pm8226_s1_corner>;
+			HSIC_GDSC-supply = <&gdsc_usb_hsic>;
+			hsic,strobe-gpio = <&msmgpio 115 0x00>;
+			hsic,data-gpio = <&msmgpio 116 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>;
+		};
 	};
 
 	wcd9xxx_intc: wcd9xxx-irq {
@@ -486,6 +496,14 @@
 		compatible = "qcom,msm-lsm-client";
 	};
 
+	qti,msm-pcm-loopback {
+		compatible = "qti,msm-pcm-loopback";
+	};
+
+	qcom,msm-voice-svc {
+		compatible = "qcom,msm-voice-svc";
+	};
+
 	qcom,msm-dai-q6 {
 		compatible = "qcom,msm-dai-q6";
 		qcom,msm-dai-q6-sb-0-rx {
@@ -758,6 +776,7 @@
 
 		qcom,bus-width = <8>;
 
+		qcom,cpu-dma-latency-us = <701>;
 		qcom,msm-bus,name = "sdcc1";
 		qcom,msm-bus,num-cases = <8>;
 		qcom,msm-bus,num-paths = <1>;
@@ -785,6 +804,7 @@
 
 		qcom,bus-width = <8>;
 
+		qcom,cpu-dma-latency-us = <701>;
 		qcom,msm-bus,name = "sdhc1";
 		qcom,msm-bus,num-cases = <8>;
 		qcom,msm-bus,num-paths = <1>;
@@ -815,6 +835,7 @@
 
 		qcom,bus-width = <4>;
 
+		qcom,cpu-dma-latency-us = <701>;
 		qcom,msm-bus,name = "sdcc2";
 		qcom,msm-bus,num-cases = <8>;
 		qcom,msm-bus,num-paths = <1>;
@@ -842,6 +863,7 @@
 
 		qcom,bus-width = <4>;
 
+		qcom,cpu-dma-latency-us = <701>;
 		qcom,msm-bus,name = "sdhc2";
 		qcom,msm-bus,num-cases = <8>;
 		qcom,msm-bus,num-paths = <1>;
@@ -868,6 +890,7 @@
 		reg-names = "core_mem", "dml_mem", "bam_mem";
 
 		qcom,bus-width = <4>;
+		qcom,cpu-dma-latency-us = <701>;
 		gpios = <&msmgpio 44 0>, /* CLK */
 			<&msmgpio 43 0>, /* CMD */
 			<&msmgpio 42 0>, /* DATA0 */
@@ -911,6 +934,7 @@
 		reg-names = "hc_mem", "core_mem";
 
 		qcom,bus-width = <4>;
+		qcom,cpu-dma-latency-us = <701>;
 		gpios = <&msmgpio 44 0>, /* CLK */
 			<&msmgpio 43 0>, /* CMD */
 			<&msmgpio 42 0>, /* DATA0 */
@@ -977,7 +1001,7 @@
 		qcom,scl-gpio = <&msmgpio 11 0>;
 		qcom,master-id = <86>;
 	};
-	i2c@f9926000 { /* BLSP-1 QUP-4 */
+	i2c_0: i2c@f9926000 { /* BLSP-1 QUP-4 */
 		cell-index = <0>;
 		compatible = "qcom,i2c-qup";
 		reg = <0xf9926000 0x1000>;
@@ -987,6 +1011,8 @@
 		interrupts = <0 98 0>;
 		interrupt-names = "qup_err_intr";
 		qcom,i2c-bus-freq = <100000>;
+		qcom,i2c-src-freq = <19200000>;
+		qcom,master-id = <86>;
 	};
 
 	i2c@f9927000 { /* BLSP1 QUP5 */
@@ -1018,23 +1044,34 @@
 		cpu-vdd-supply = <&apc_vreg_corner>;
 	};
 
+	qcom,cpubw {
+		compatible = "qcom,cpubw";
+		qcom,cpu-mem-ports = <1 512>;
+		qcom,bw-tbl =
+			< 1525 /* 200 MHz */ >,
+			< 2441 /* 320 MHz */ >,
+			< 3051 /* 400 MHz */ >,
+			< 4066 /* 533 MHz */ >;
+	};
+
 	qcom,msm-cpufreq@0 {
 		reg = <0 4>;
 		compatible = "qcom,msm-cpufreq";
-		qcom,cpu-mem-ports = <1 512>;
 		qcom,cpufreq-table =
-			<  300000 1600 /* 200 MHz */ >,
-			<  384000 1600 /* 200 MHz */ >,
-			<  600000 1600 /* 200 MHz */ >,
-			<  787200 3200 /* 400 MHz */ >,
-			<  998400 4264 /* 533 MHz */ >,
-			< 1094400 4264 /* 533 MHz */ >,
-			< 1190400 4264 /* 533 MHz */ >,
-			< 1305600 4264 /* 533 MHz */ >,
-			< 1344000 4264 /* 533 MHz */ >,
-			< 1401600 4264 /* 533 MHz */ >,
-			< 1497600 4264 /* 533 MHz */ >,
-			< 1593600 4264 /* 533 MHz */ >;
+			<  300000 1525 >,
+			<  384000 1525 >,
+			<  600000 1525 >,
+			<  787200 1525 >,
+			<  998400 4066 >,
+			< 1094400 4066 >,
+			< 1190400 4066 >,
+			< 1305600 4066 >,
+			< 1344000 4066 >,
+			< 1401600 4066 >,
+			< 1497600 4066 >,
+			< 1593600 4066 >,
+			< 1689600 4066 >,
+			< 1785600 4066 >;
 	};
 
 	qcom,ocmem@fdd00000 {
@@ -1238,8 +1275,8 @@
                 qcom,msm-bus,num-cases = <2>;
                 qcom,msm-bus,num-paths = <1>;
                 qcom,msm-bus,vectors-KBps =
-                                <1 618 0 0>,
-                                <1 618 0 800>;
+                                <54 618 0 0>,
+                                <54 618 0 800>;
 	};
 
 	qcom,tz-log@fe805720 {
@@ -1294,15 +1331,17 @@
 		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,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>;
 	};
 
 	qcom,qcrypto@fd404000 {
@@ -1313,6 +1352,7 @@
 		interrupts = <0 207 0>;
 		qcom,bam-pipe-pair = <2>;
 		qcom,ce-hw-instance = <0>;
+		qcom,ce-device = <0>;
 		qcom,ce-hw-shared;
 		qcom,msm-bus,name = "qcrypto-noc";
 		qcom,msm-bus,num-cases = <2>;
@@ -1331,6 +1371,7 @@
 		interrupts = <0 207 0>;
 		qcom,bam-pipe-pair = <1>;
 		qcom,ce-hw-instance = <0>;
+		qcom,ce-device = <0>;
 		qcom,ce-hw-shared;
 		qcom,msm-bus,name = "qcedev-noc";
 		qcom,msm-bus,num-cases = <2>;
@@ -1346,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 {
@@ -1494,6 +1541,7 @@
 		qcom,hw-settle-time = <2>;
 		qcom,fast-avg-setup = <3>;
 		qcom,btm-channel-number = <0x48>;
+		qcom,meas-interval-timer-idx = <2>;
 	};
 
 	chan@8 {
diff --git a/arch/arm/boot/dts/msm8610-bus.dtsi b/arch/arm/boot/dts/msm8610-bus.dtsi
index 54c698c..d26d660 100644
--- a/arch/arm/boot/dts/msm8610-bus.dtsi
+++ b/arch/arm/boot/dts/msm8610-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
@@ -41,8 +41,8 @@
 			qcom,qport = <0>;
 			qcom,ws = <10000>;
 			qcom,mas-hw-id = <8>;
-			qcom,prio1 = <2>;
-			qcom,prio0 = <2>;
+			qcom,prio1 = <3>;
+			qcom,prio0 = <3>;
 		};
 
 		mas-vfe {
diff --git a/arch/arm/boot/dts/msm8610-camera-sensor-cdp-mtp.dtsi b/arch/arm/boot/dts/msm8610-camera-sensor-cdp-mtp.dtsi
index bdcab77..1d47a94 100644
--- a/arch/arm/boot/dts/msm8610-camera-sensor-cdp-mtp.dtsi
+++ b/arch/arm/boot/dts/msm8610-camera-sensor-cdp-mtp.dtsi
@@ -192,8 +192,8 @@
 		reg = <0x6d>;
 		qcom,slave-id = <0x20 0x0 0x9724>;
 		qcom,csiphy-sd-index = <1>;
-		qcom,csid-sd-index = <0>;
-		qcom,mount-angle = <90>;
+		qcom,csid-sd-index = <1>;
+		qcom,mount-angle = <270>;
 		qcom,sensor-name = "ov9724";
 		cam_vdig-supply = <&pm8110_l4>;
 		cam_vana-supply = <&pm8110_l19>;
@@ -204,7 +204,7 @@
 		qcom,cam-vreg-max-voltage = <1200000 0 2850000>;
 		qcom,cam-vreg-op-mode = <200000 0 80000>;
 		qcom,gpio-no-mux = <0>;
-		gpios = <&msmgpio 14 0>,
+		gpios = <&msmgpio 13 0>,
 				<&msmgpio 15 0>,
 				<&msmgpio 8 0>;
 		qcom,gpio-reset = <1>;
@@ -218,7 +218,7 @@
 		qcom,gpio-set-tbl-flags = <0 2>;
 		qcom,gpio-set-tbl-delay = <1000 4000>;
 		qcom,csi-lane-assign = <0xe4>;
-		qcom,csi-lane-mask = <0x1>;
+		qcom,csi-lane-mask = <0x3>;
 		qcom,sensor-position = <1>;
 		qcom,sensor-mode = <1>;
 		qcom,cci-master = <0>;
@@ -261,5 +261,72 @@
 		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 = <90>;
+		qcom,actuator-src = <&actuator0>;
+		qcom,led-flash-src = <&led_flash0>;
+		cam_vdig-supply = <&pm8110_l2>;
+		cam_vana-supply = <&pm8110_l19>;
+		cam_vio-supply = <&pm8110_l14>;
+		cam_vaf-supply = <&pm8110_l16>;
+		qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana",
+							 "cam_vaf";
+		qcom,cam-vreg-type = <0 0 0 0>;
+		qcom,cam-vreg-min-voltage = <1200000 1800000 2850000 3000000>;
+		qcom,cam-vreg-max-voltage = <1200000 1800000 2850000 3000000>;
+		qcom,cam-vreg-op-mode = <200000 8000 80000 100000>;
+		qcom,gpio-no-mux = <0>;
+		gpios = <&msmgpio 13 0>,
+			<&msmgpio 21 0>,
+			<&msmgpio 20 0>;
+		qcom,gpio-reset = <1>;
+		qcom,gpio-standby = <2>;
+		qcom,gpio-req-tbl-num = <0 1 2>;
+		qcom,gpio-req-tbl-flags = <1 0 0>;
+		qcom,gpio-req-tbl-label = "CAMIF_MCLK",
+			"CAM_RESET1",
+			"CAM_STANDBY";
+		qcom,sensor-position = <0>;
+		qcom,sensor-mode = <0>;
+		qcom,cci-master = <0>;
+		status = "ok";
+	};
+
+	qcom,camera@1 {
+		cell-index = <1>;
+		compatible = "qcom,camera";
+		reg = <0x1>;
+		qcom,csiphy-sd-index = <1>;
+		qcom,csid-sd-index = <1>;
+		qcom,mount-angle = <90>;
+		cam_vdig-supply = <&pm8110_l4>;
+		cam_vana-supply = <&pm8110_l19>;
+		cam_vio-supply = <&pm8110_l14>;
+		qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana";
+		qcom,cam-vreg-type = <0 1 0>;
+		qcom,cam-vreg-min-voltage = <1200000 0 2850000>;
+		qcom,cam-vreg-max-voltage = <1200000 0 2850000>;
+		qcom,cam-vreg-op-mode = <200000 0 80000>;
+		qcom,gpio-no-mux = <0>;
+		gpios = <&msmgpio 14 0>,
+			<&msmgpio 15 0>,
+			<&msmgpio 8 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_RESET",
+			"CAM_STANDBY";
+		qcom,sensor-position = <1>;
+		qcom,sensor-mode = <0>;
+		qcom,cci-master = <0>;
+		status = "ok";
+	};
 
 };
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-gpu.dtsi b/arch/arm/boot/dts/msm8610-gpu.dtsi
index 7e3ee0d..480ec11 100644
--- a/arch/arm/boot/dts/msm8610-gpu.dtsi
+++ b/arch/arm/boot/dts/msm8610-gpu.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
@@ -38,7 +38,7 @@
 			<26 512 0 0>,
 			<26 512 0 800000>,
 			<26 512 0 1600000>,
-			<26 512 0 2128000>;
+			<26 512 0 2664000>;
 
 		/* GDSC oxili regulators */
 		vdd-supply = <&gdsc_oxili_cx>;
@@ -46,6 +46,9 @@
 		/* IOMMU Data */
 		iommu = <&gfx_iommu>;
 
+		/* CPU latency parameter */
+		qcom,pm-qos-latency = <701>;
+
 		/* Power levels */
 		qcom,gpu-pwrlevels {
 			#address-cells = <1>;
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 3b0f2a2..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, 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 */
@@ -151,10 +151,11 @@
 			reg = <0x0e>;
 			qcom,irq-gpio = <&msmgpio 77 0x00>;
 			qcom,dis-gpio = <&msmgpio 93 0x00>;
-			qcom,clk-en-gpio = <&msmgpio 78 0x00>;
+			qcom,clk-req-gpio = <&msmgpio 75 0x00>;
+			qcom,clk-src-gpio = <&msmgpio 78 0x00>;
 			qcom,clk-src = "GPCLK";
 			interrupt-parent = <&msmgpio>;
-			interrupts = <77 0>;
+			interrupts = <77 75 0>;
 			qcom,clk-gpio = <&pm8110_gpios 1 0>;
 		};
 	};
diff --git a/arch/arm/boot/dts/msm8610-qrd-skuaa.dtsi b/arch/arm/boot/dts/msm8610-qrd-skuaa.dtsi
index 719830e..d731ce0 100644
--- a/arch/arm/boot/dts/msm8610-qrd-skuaa.dtsi
+++ b/arch/arm/boot/dts/msm8610-qrd-skuaa.dtsi
@@ -38,11 +38,12 @@
 			compatible = "qcom,nfc-nci";
 			reg = <0x0e>;
 			qcom,irq-gpio = <&msmgpio 77 0x00>;
+			qcom,clk-req-gpio = <&msmgpio 75 0x00>;
 			qcom,dis-gpio = <&msmgpio 93 0x00>;
-			qcom,clk-en-gpio = <&msmgpio 78 0x00>;
+			qcom,clk-src-gpio = <&msmgpio 78 0x00>;
 			qcom,clk-src = "GPCLK2";
 			interrupt-parent = <&msmgpio>;
-			interrupts = <77 0>;
+			interrupts = <77 75 0>;
 			qcom,clk-gpio = <&msmgpio 75 0x00>;
 		};
 	};
@@ -95,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 a22958a..336553a 100644
--- a/arch/arm/boot/dts/msm8610-qrd-skuab.dtsi
+++ b/arch/arm/boot/dts/msm8610-qrd-skuab.dtsi
@@ -65,7 +65,7 @@
 			vcc-i2c-supply = <&pm8110_l14>;
 			goodix,panel-coords = <0 0 540 980>;
 			goodix,display-coords = <0 0 540 960>;
-			goodix,button-map= <139 102 158>;
+			goodix,button-map= <139 172 158>;
 			goodix,product-id = "915";
 			goodix,enable-power-off;
 			goodix,cfg-data0 = [
@@ -88,6 +88,8 @@
 				00 FF FF FF FF FF FF FF 00 00
 				00 FF FF FF FF FF FF FF FF FF
 				F8 FF FF FF E4 01];
+			goodix,have-touch-key;
+			goodix,driver-send-cfg;
 		};
 	};
 	gen-vkeys {
@@ -101,6 +103,20 @@
 		qcom,y-offset = <0>;
 	};
 
+	i2c@f9924000 { /* BLSP-1 QUP-2 */
+		nfc-nci@e {
+			compatible = "qcom,nfc-nci";
+			reg = <0x0e>;
+			qcom,irq-gpio = <&msmgpio 77 0x00>;
+			qcom,dis-gpio = <&msmgpio 93 0x00>;
+			qcom,clk-en-gpio = <&msmgpio 78 0x00>;
+			qcom,clk-src = "GPCLK2";
+			interrupt-parent = <&msmgpio>;
+			interrupts = <77 0>;
+			qcom,clk-gpio = <&msmgpio 75 0x00>;
+		};
+	};
+
     i2c@f9925000 {
 		fsl@1c {
 			compatible = "fsl,mma8x5x";
@@ -167,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-regulator.dtsi b/arch/arm/boot/dts/msm8610-regulator.dtsi
index 543f59e..6639668 100644
--- a/arch/arm/boot/dts/msm8610-regulator.dtsi
+++ b/arch/arm/boot/dts/msm8610-regulator.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
@@ -30,7 +30,7 @@
 &soc {
 	apc_vreg_corner: regulator@f9018000 {
 		status = "okay";
-		compatible = "qti,cpr-regulator";
+		compatible = "qcom,cpr-regulator";
 		reg = <0xf9018000 0x1000>, <0xf9011064 4>, <0xfc4b8000 0x1000>;
 		reg-names = "rbcpr", "rbcpr_clk", "efuse_addr";
 		interrupts = <0 15 0>;
@@ -38,53 +38,78 @@
 		regulator-min-microvolt = <1>;
 		regulator-max-microvolt = <3>;
 
-		qti,pvs-fuse-redun-sel = <53 25 3 2 1>;
-		qti,pvs-fuse = <23 6 5 1>;
-		qti,pvs-fuse-redun = <61 47 5 1>;
+		qcom,pvs-fuse-redun-sel = <53 25 3 2 1>;
+		qcom,pvs-fuse = <23 6 5 1>;
+		qcom,pvs-fuse-redun = <61 47 5 1>;
 
-		qti,pvs-init-voltage = <1275000 1275000 1275000 1275000 1275000
-					1275000 1275000 1275000 1275000 1275000
-					1275000 1275000 1275000 1275000 1275000
-					1275000 1275000 1275000 1275000 1275000
-					1275000 1275000 1275000 1275000 1275000
-					1275000 1275000 1275000 1275000 1275000
-					1275000 1275000>;
-		qti,pvs-corner-ceiling-slow = <1150000 1150000 1275000>;
-		qti,pvs-corner-ceiling-nom  = <1075000 1075000 1275000>;
-		qti,pvs-corner-ceiling-fast = <1050000 1050000 1275000>;
+		qcom,pvs-voltage-table =
+			<1050000 1150000 1275000>,
+			<1050000 1150000 1275000>,
+			<1050000 1150000 1275000>,
+			<1050000 1150000 1275000>,
+			<1050000 1150000 1275000>,
+			<1050000 1150000 1275000>,
+			<1050000 1150000 1275000>,
+			<1050000 1150000 1275000>,
+			<1050000 1150000 1275000>,
+			<1050000 1150000 1275000>,
+			<1050000 1150000 1275000>,
+			<1050000 1150000 1275000>,
+			<1050000 1150000 1275000>,
+			<1050000 1150000 1275000>,
+			<1050000 1150000 1275000>,
+			<1050000 1150000 1275000>,
+			<1050000 1150000 1275000>,
+			<1050000 1150000 1275000>,
+			<1050000 1150000 1275000>,
+			<1050000 1150000 1275000>,
+			<1050000 1150000 1275000>,
+			<1050000 1150000 1275000>,
+			<1050000 1150000 1275000>,
+			<1050000 1150000 1275000>,
+			<1050000 1150000 1275000>,
+			<1050000 1150000 1275000>,
+			<1050000 1150000 1275000>,
+			<1050000 1150000 1275000>,
+			<1050000 1150000 1275000>,
+			<1050000 1150000 1275000>,
+			<1050000 1150000 1275000>,
+			<1050000 1150000 1275000>;
+		qcom,cpr-voltage-ceiling = <1050000 1150000 1275000>;
+		qcom,cpr-voltage-floor = <1050000 1050000 1275000>;
 		vdd-apc-supply = <&pm8110_s2>;
 
 		vdd-mx-supply = <&pm8110_l3_ao>;
-		qti,vdd-mx-vmax = <1350000>;
-		qti,vdd-mx-vmin-method = <1>;
+		qcom,vdd-mx-vmax = <1350000>;
+		qcom,vdd-mx-vmin-method = <1>;
 
-		qti,cpr-ref-clk = <19200>;
-		qti,cpr-timer-delay = <5000>;
-		qti,cpr-timer-cons-up = <0>;
-		qti,cpr-timer-cons-down = <2>;
-		qti,cpr-irq-line = <0>;
-		qti,cpr-step-quotient = <15>;
-		qti,cpr-up-threshold = <0>;
-		qti,cpr-down-threshold = <10>;
-		qti,cpr-idle-clocks = <5>;
-		qti,cpr-gcnt-time = <1>;
-		qti,vdd-apc-step-up-limit = <1>;
-		qti,vdd-apc-step-down-limit = <1>;
-		qti,cpr-apc-volt-step = <5000>;
+		qcom,cpr-ref-clk = <19200>;
+		qcom,cpr-timer-delay = <5000>;
+		qcom,cpr-timer-cons-up = <0>;
+		qcom,cpr-timer-cons-down = <2>;
+		qcom,cpr-irq-line = <0>;
+		qcom,cpr-step-quotient = <15>;
+		qcom,cpr-up-threshold = <0>;
+		qcom,cpr-down-threshold = <10>;
+		qcom,cpr-idle-clocks = <5>;
+		qcom,cpr-gcnt-time = <1>;
+		qcom,vdd-apc-step-up-limit = <1>;
+		qcom,vdd-apc-step-down-limit = <1>;
+		qcom,cpr-apc-volt-step = <5000>;
 
-		qti,cpr-fuse-redun-sel = <53 25 3 2 1>;
-		qti,cpr-fuse-row = <61 1>;
-		qti,cpr-fuse-bp-cpr-disable = <39>;
-		qti,cpr-fuse-bp-scheme = <40>;
-		qti,cpr-fuse-target-quot = <27 15 3>;
-		qti,cpr-fuse-ro-sel = <47 41 44>;
-		qti,cpr-fuse-redun-row = <52 1>;
-		qti,cpr-fuse-redun-bp-cpr-disable = <24>;
-		qti,cpr-fuse-redun-bp-scheme = <25>;
-		qti,cpr-fuse-redun-target-quot = <32 12 0>;
-		qti,cpr-fuse-redun-ro-sel = <44 26 29>;
+		qcom,cpr-fuse-redun-sel = <53 25 3 2 1>;
+		qcom,cpr-fuse-row = <61 1>;
+		qcom,cpr-fuse-bp-cpr-disable = <39>;
+		qcom,cpr-fuse-bp-scheme = <40>;
+		qcom,cpr-fuse-target-quot = <27 15 3>;
+		qcom,cpr-fuse-ro-sel = <47 41 44>;
+		qcom,cpr-fuse-redun-row = <52 1>;
+		qcom,cpr-fuse-redun-bp-cpr-disable = <24>;
+		qcom,cpr-fuse-redun-bp-scheme = <25>;
+		qcom,cpr-fuse-redun-target-quot = <32 12 0>;
+		qcom,cpr-fuse-redun-ro-sel = <44 26 29>;
 
-		qti,cpr-enable;
+		qcom,cpr-enable;
 	};
 };
 
diff --git a/arch/arm/boot/dts/msm8610-v1-pm.dtsi b/arch/arm/boot/dts/msm8610-v1-pm.dtsi
index ea37413..adc66d7 100644
--- a/arch/arm/boot/dts/msm8610-v1-pm.dtsi
+++ b/arch/arm/boot/dts/msm8610-v1-pm.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
@@ -105,7 +105,7 @@
 		qcom,L2-spm-is-apcs-master;
 	};
 
-	qcom,lpm-levels {
+	lpm_levels: qcom,lpm-levels {
 		compatible = "qcom,lpm-levels";
 		qcom,default-l2-state = "l2_cache_active";
 		#address-cells = <1>;
@@ -145,16 +145,6 @@
 			compatible = "qcom,system-modes";
 
 			qcom,system-modes@0 {
-				qcom,l2 = "l2_cache_gdhs";
-				qcom,latency-us = <10700>;
-				qcom,ss-power = <372>;
-				qcom,energy-overhead = <738750>;
-				qcom,time-overhead = <1410>;
-				qcom,min-cpu-mode= "pc";
-				qcom,sync-cpus;
-			};
-
-			qcom,system-modes@1 {
 				qcom,l2 = "l2_cache_pc_no_rpm";
 				qcom,latency-us = <1000>;
 				qcom,ss-power = <315>;
@@ -164,7 +154,7 @@
 				qcom,sync-cpus;
 			};
 
-			qcom,system-modes@2 {
+			qcom,system-modes@1 {
 				qcom,l2 = "l2_cache_pc";
 				qcom,latency-us = <12700>;
 				qcom,ss-power = <315>;
@@ -172,6 +162,7 @@
 				qcom,time-overhead = <2400>;
 				qcom,min-cpu-mode= "pc";
 				qcom,sync-cpus;
+				qcom,send-rpm-sleep-set;
 			};
 		};
 	};
@@ -236,6 +227,7 @@
 			<0xff 191>, /* lpass_irq_out_apcs(3) */
 			<0xff 192>, /* lpass_irq_out_apcs(4) */
 			<0xff 194>, /* lpass_irq_out_apcs(6) */
+			<0xff 198>, /* QDSS - u_qdss */
 			<0xff 200>, /* rpm_ipc(4) */
 			<0xff 201>, /* rpm_ipc(5) */
 			<0xff 202>, /* rpm_ipc(6) */
@@ -302,6 +294,9 @@
 		qcom,pc-mode = "tz_l2_int";
 		qcom,use-sync-timer;
 		qcom,pc-resets-timer;
+		qcom,cpus-as-clocks;
+		qcom,synced-clocks;
+		qcom,lpm-levels = <&lpm_levels>;
 	};
 
 	qcom,cpu-sleep-status@f9088008{
diff --git a/arch/arm/boot/dts/msm8610-v1.dtsi b/arch/arm/boot/dts/msm8610-v1.dtsi
index 9d8c411..8965e93 100644
--- a/arch/arm/boot/dts/msm8610-v1.dtsi
+++ b/arch/arm/boot/dts/msm8610-v1.dtsi
@@ -20,6 +20,7 @@
 /include/ "msm8610-v1-pm.dtsi"
 
 / {
-	qcom,msm-id = <147 0>, <165 0>, <161 0>, <162 0>,
-			<163 0>, <164 0>, <166 0>;
+	qcom,msm-id = <147 1000>, <165 1000>, <161 1000>, <162 1000>,
+			<163 1000>, <164 1000>, <166 1000>, <225 1000>,
+			<226 1000>;
 };
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-v2-pm.dtsi b/arch/arm/boot/dts/msm8610-v2-pm.dtsi
index 19fb185..b69b061 100644
--- a/arch/arm/boot/dts/msm8610-v2-pm.dtsi
+++ b/arch/arm/boot/dts/msm8610-v2-pm.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
@@ -96,7 +96,7 @@
 		qcom,phase-port = <0x1>;
 		qcom,pfm-port = <0x2>;
 		qcom,saw2-spm-cmd-ret = [00 03 00 0f];
-		qcom,saw2-spm-cmd-gdhs = [00 20 32 6b c0 e0 d0 42 07 50
+		qcom,saw2-spm-cmd-gdhs = [00 20 32 6b c0 e0 d0 42 03 50
 				4e 02 02 d0 e0 c0 22 6b 02 32 50 0f];
 		qcom,saw2-spm-cmd-pc = [00 32 b0 10 e0 d0 6b c0 42 f0
 				11 07 01 b0 50 4e 02 02 c0 d0 12 e0 6b 02 32
@@ -107,7 +107,7 @@
 		qcom,L2-spm-is-apcs-master;
 	};
 
-	qcom,lpm-levels {
+	lpm_levels: qcom,lpm-levels {
 		compatible = "qcom,lpm-levels";
 		qcom,default-l2-state = "l2_cache_active";
 		#address-cells = <1>;
@@ -148,11 +148,11 @@
 
 			qcom,system-modes@0 {
 				qcom,l2 = "l2_cache_gdhs";
-				qcom,latency-us = <10700>;
+				qcom,latency-us = <700>;
 				qcom,ss-power = <372>;
 				qcom,energy-overhead = <738750>;
 				qcom,time-overhead = <1410>;
-				qcom,min-cpu-mode= "pc";
+				qcom,min-cpu-mode= "standalone_pc";
 				qcom,sync-cpus;
 			};
 
@@ -174,6 +174,7 @@
 				qcom,time-overhead = <2400>;
 				qcom,min-cpu-mode= "pc";
 				qcom,sync-cpus;
+				qcom,send-rpm-sleep-set;
 			};
 		};
 	};
@@ -238,6 +239,7 @@
 			<0xff 191>, /* lpass_irq_out_apcs(3) */
 			<0xff 192>, /* lpass_irq_out_apcs(4) */
 			<0xff 194>, /* lpass_irq_out_apcs(6) */
+			<0xff 198>, /* QDSS - u_qdss */
 			<0xff 200>, /* rpm_ipc(4) */
 			<0xff 201>, /* rpm_ipc(5) */
 			<0xff 202>, /* rpm_ipc(6) */
@@ -304,6 +306,9 @@
 		qcom,pc-mode = "tz_l2_int";
 		qcom,use-sync-timer;
 		qcom,pc-resets-timer;
+		qcom,cpus-as-clocks;
+		qcom,synced-clocks;
+		qcom,lpm-levels = <&lpm_levels>;
 	};
 
 	qcom,cpu-sleep-status@f9088008{
diff --git a/arch/arm/boot/dts/msm8610-v2.dtsi b/arch/arm/boot/dts/msm8610-v2.dtsi
index a1f466a..221598d 100644
--- a/arch/arm/boot/dts/msm8610-v2.dtsi
+++ b/arch/arm/boot/dts/msm8610-v2.dtsi
@@ -21,5 +21,6 @@
 
 / {
 	qcom,msm-id = <147 0x10001>, <165 0x10001>, <161 0x10001>, <162 0x10001>,
-				  <163 0x10001>, <164 0x10001>, <166 0x10001>;
+				  <163 0x10001>, <164 0x10001>, <166 0x10001>,
+				  <225 0x10001>, <226 0x10001>;
 };
diff --git a/arch/arm/boot/dts/msm8610.dtsi b/arch/arm/boot/dts/msm8610.dtsi
index 03ef738..90dae06 100644
--- a/arch/arm/boot/dts/msm8610.dtsi
+++ b/arch/arm/boot/dts/msm8610.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
@@ -240,7 +240,6 @@
 		qcom,hsusb-otg-otg-control = <2>;
 		qcom,hsusb-otg-disable-reset;
 		qcom,dp-manual-pullup;
-		qcom,ahb-async-bridge-bypass;
 		qcom,disable-retention-with-vdd-min;
 
 		qcom,msm-bus,name = "usb2";
@@ -257,6 +256,7 @@
 		reg = <0xfe8050c8 0xc8>;
 		qcom,android-usb-swfi-latency = <1>;
 		qcom,streaming-func = "rndis";
+		qcom,android-usb-uicc-nluns = <1>;
 	};
 
 	rmtfs_sharedmem {
@@ -306,6 +306,7 @@
 		qcom,bus-width = <8>;
 		qcom,nonremovable;
 		qcom,bus-speed-mode = "HS200_1p8v", "DDR_1p8v";
+		qcom,cpu-dma-latency-us = <701>;
 
 		status = "disabled";
 	};
@@ -339,6 +340,7 @@
 		qcom,xpc;
 		qcom,bus-speed-mode = "SDR12", "SDR25", "SDR50", "DDR50", "SDR104";
 		qcom,current-limit = <800>;
+		qcom,cpu-dma-latency-us = <701>;
 
 		status = "disabled";
 	};
@@ -352,6 +354,7 @@
 		interrupt-names = "hc_irq", "pwr_irq";
 
 		qcom,bus-width = <8>;
+		qcom,cpu-dma-latency-us = <701>;
 		status = "disabled";
 	};
 
@@ -364,6 +367,7 @@
 		interrupt-names = "hc_irq", "pwr_irq";
 
 		qcom,bus-width = <4>;
+		qcom,cpu-dma-latency-us = <701>;
 		status = "disabled";
 	};
 
@@ -464,11 +468,39 @@
 		qcom,ipi-ping;
 	};
 
-	qcom,acpuclk@f9011050 {
-		compatible = "qcom,acpuclk-a7";
+	qcom,clock-a7@f9011050 {
+		compatible = "qcom,clock-a7-8226";
 		reg = <0xf9011050 0x8>;
-		reg-names = "rcg_base";
-		a7_cpu-supply = <&apc_vreg_corner>;
+		reg-names = "rcg-base";
+		clock-names = "clk-4", "clk-5";
+		qcom,speed0-bin-v0 =
+			<         0 0>,
+			< 384000000 1>,
+			< 787200000 2>,
+			<1190400000 3>;
+
+		cpu-vdd-supply = <&apc_vreg_corner>;
+	};
+
+	qcom,cpubw {
+		compatible = "qcom,cpubw";
+		qcom,cpu-mem-ports = <1 512>;
+		qcom,bw-tbl =
+			<  762 /* 100 MHz */ >,
+			< 1525 /* 200 MHz */ >,
+			< 2540 /* 333 MHz */ >;
+	};
+
+	qcom,msm-cpufreq@0 {
+		reg = <0 4>;
+		compatible = "qcom,msm-cpufreq";
+		qcom,cpufreq-table =
+			<  300000  762 >,
+			<  384000  762 >,
+			<  600000 1525 >,
+			<  787200 1525 >,
+			<  998400 2540 >,
+			< 1190400 2540 >;
 	};
 
 	spmi_bus: qcom,spmi@fc4c0000 {
@@ -535,6 +567,8 @@
 	i2c@f9924000 { /* BLSP-1 QUP-3 */
 		cell-index = <2>;
 		compatible = "qcom,i2c-qup";
+		#address-cells = <1>;
+		#size-cells = <0>;
 		reg-names = "qup_phys_addr";
 		reg = <0xf9924000 0x1000>;
 		interrupt-names = "qup_err_intr";
@@ -559,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>;
 	};
 
@@ -577,6 +612,7 @@
 		qcom,gpio-miso = <&msmgpio 87 0>;
 		qcom,gpio-clk  = <&msmgpio 89 0>;
 		qcom,gpio-cs0  = <&msmgpio 88 0>;
+		qcom,gpio-cs2  = <&msmgpio 85 0>;
 
 		qcom,infinite-mode = <0>;
 		qcom,use-bam;
@@ -584,6 +620,21 @@
 		qcom,bam-consumer-pipe-index = <18>;
 		qcom,bam-producer-pipe-index = <19>;
 		qcom,master-id = <86>;
+
+		lattice,spi-usb@2 {
+			compatible = "lattice,ice40-spi-usb";
+			reg = <2>;
+			spi-max-frequency = <50000000>;
+			spi-cpol = <1>;
+			spi-cpha = <1>;
+			core-vcc-supply = <&pm8110_l2>;
+			spi-vcc-supply = <&pm8110_l6>;
+			gpio-supply = <&pm8110_l22>;
+			lattice,reset-gpio = <&msmgpio 95 0>;
+			lattice,slave-select-gpio = <&msmgpio 85 0>;
+			lattice,config-done-gpio = <&msmgpio 94 0>;
+			lattice,vcc-en-gpio = <&msmgpio 96 0>;
+		};
 	};
 
 	qcom,pronto@fb21b000 {
@@ -736,6 +787,11 @@
 			compatible = "qcom,msm-dai-q6-dev";
 			qcom,msm-dai-q6-dev-id = <32773>;
 		};
+
+		qcom,msm-dai-q6-incall-music-2-rx {
+			compatible = "qcom,msm-dai-q6-dev";
+			qcom,msm-dai-q6-dev-id = <32770>;
+		};
 	};
 
 	qcom,msm-pcm-hostless {
@@ -875,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 {
@@ -951,6 +1008,7 @@
 		interrupts = <0 207 0>;
 		qcom,bam-pipe-pair = <2>;
 		qcom,ce-hw-instance = <1>;
+		qcom,ce-device = <0>;
 		qcom,ce-hw-shared;
 		qcom,msm-bus,name = "qcrypto-noc";
 		qcom,msm-bus,num-cases = <2>;
@@ -969,6 +1027,7 @@
 		interrupts = <0 207 0>;
 		qcom,bam-pipe-pair = <1>;
 		qcom,ce-hw-instance = <1>;
+		qcom,ce-device = <0>;
 		qcom,ce-hw-shared;
 		qcom,msm-bus,name = "qcedev-noc";
 		qcom,msm-bus,num-cases = <2>;
@@ -984,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 {
@@ -1042,7 +1107,7 @@
 		label = "vchg_sns";
 		reg = <2>;
 		qcom,decimation = <0>;
-		qcom,pre-div-channel-scaling = <2>;
+		qcom,pre-div-channel-scaling = <5>;
 		qcom,calibration-type = "absolute";
 		qcom,scale-function = <0>;
 		qcom,hw-settle-time = <0>;
@@ -1139,6 +1204,7 @@
 		qcom,hw-settle-time = <2>;
 		qcom,fast-avg-setup = <3>;
 		qcom,btm-channel-number = <0x48>;
+		qcom,meas-interval-timer-idx = <2>;
 	};
 
 	chan@8 {
diff --git a/arch/arm/boot/dts/msm8612-qrd-camera-sensor.dtsi b/arch/arm/boot/dts/msm8612-qrd-camera-sensor.dtsi
index 205e749..551e007 100644
--- a/arch/arm/boot/dts/msm8612-qrd-camera-sensor.dtsi
+++ b/arch/arm/boot/dts/msm8612-qrd-camera-sensor.dtsi
@@ -1,5 +1,5 @@
 /*
- * 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
@@ -95,4 +95,65 @@
 		qcom,cci-master = <0>;
 		status = "ok";
 	};
+	qcom,camera@1 {
+		cell-index = <0>;
+		compatible = "qcom,camera";
+		reg = <0x01>;
+		qcom,csiphy-sd-index = <0>;
+		qcom,csid-sd-index = <0>;
+		qcom,mount-angle = <90>;
+		cam_vdig-supply = <&pm8110_l2>;
+		cam_vana-supply = <&pm8110_l19>;
+		cam_vio-supply = <&pm8110_l14>;
+		qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana";
+		qcom,cam-vreg-type = <0 0 0>;
+		qcom,cam-vreg-min-voltage = <1200000 1800000 2850000>;
+		qcom,cam-vreg-max-voltage = <1200000 1800000 2850000>;
+		qcom,cam-vreg-op-mode = <200000 8000 80000>;
+		qcom,gpio-no-mux = <0>;
+		gpios = <&msmgpio 13 0>,
+			<&msmgpio 21 0>,
+			<&msmgpio 20 0>;
+		qcom,gpio-reset = <1>;
+		qcom,gpio-standby = <2>;
+		qcom,gpio-req-tbl-num = <0 1 2>;
+		qcom,gpio-req-tbl-flags = <1 0 0>;
+		qcom,gpio-req-tbl-label = "CAMIF_MCLK",
+			"CAM_RESET1",
+			"CAM_STANDBY";
+		qcom,sensor-position = <0>;
+		qcom,sensor-mode = <0>;
+		qcom,cci-master = <0>;
+		status = "ok";
+	};
+	qcom,camera@2 {
+		cell-index = <1>;
+		compatible = "qcom,camera";
+		reg = <0x02>;
+		qcom,csiphy-sd-index = <1>;
+		qcom,csid-sd-index = <1>;
+		qcom,mount-angle = <270>;
+		cam_vdig-supply = <&pm8110_l14>;
+		cam_vana-supply = <&pm8110_l19>;
+		cam_vio-supply = <&pm8110_l14>;
+		qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana";
+		qcom,cam-vreg-type = <0 1 0>;
+		qcom,cam-vreg-min-voltage = <1800000 1800000 2850000>;
+		qcom,cam-vreg-max-voltage = <1800000 1800000 2850000>;
+		qcom,cam-vreg-op-mode = <200000 0 80000>;
+		qcom,gpio-no-mux = <0>;
+		gpios = <&msmgpio 14 0>,
+				<&msmgpio 15 0>,
+				<&msmgpio 85 0>;
+		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_RESET",
+				"CAM_STANDBY";
+		qcom,sensor-position = <1>;
+		qcom,sensor-mode = <0>;
+		qcom,cci-master = <0>;
+		status = "ok";
+	};
 };
diff --git a/arch/arm/boot/dts/msm8926-camera-sensor-qrd.dtsi b/arch/arm/boot/dts/msm8926-camera-sensor-qrd.dtsi
index 9b812da..6af862f 100644
--- a/arch/arm/boot/dts/msm8926-camera-sensor-qrd.dtsi
+++ b/arch/arm/boot/dts/msm8926-camera-sensor-qrd.dtsi
@@ -1,5 +1,5 @@
 /*
- * 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
@@ -17,7 +17,7 @@
 		cell-index = <0>;
 		compatible = "qcom,camera-led-flash";
 		qcom,flash-type = <1>;
-		qcom,flash-source = <&pm8226_flash0 &pm8226_flash1>;
+		qcom,flash-source = <&pm8226_flash0>;
 		qcom,torch-source = <&pm8226_torch>;
 	};
 };
@@ -229,4 +229,78 @@
 		qcom,cci-master = <0>;
 		status = "ok";
 	};
+
+	qcom,camera@0 {
+		cell-index = <0>;
+		compatible = "qcom,camera";
+		reg = <0x00>;
+		qcom,csiphy-sd-index = <0>;
+		qcom,csid-sd-index = <0>;
+		qcom,actuator-src = <&actuator0>;
+		qcom,led-flash-src = <&led_flash0>;
+		qcom,mount-angle = <90>;
+		cam_vdig-supply = <&pm8226_l5>;
+		cam_vana-supply = <&pm8226_l19>;
+		cam_vio-supply = <&pm8226_lvs1>;
+		cam_vaf-supply = <&pm8226_l15>;
+		qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana",
+		                                         "cam_vaf";
+		qcom,cam-vreg-type = <0 1 0 0>;
+		qcom,cam-vreg-min-voltage = <1200000 0 2850000 2800000>;
+		qcom,cam-vreg-max-voltage = <1200000 0 2850000 2800000>;
+		qcom,cam-vreg-op-mode = <200000 0 80000 100000>;
+		qcom,gpio-no-mux = <0>;
+		gpios = <&msmgpio 26 0>,
+		        <&msmgpio 37 0>,
+		        <&msmgpio 36 0>,
+		        <&msmgpio 15 0>;
+		qcom,gpio-reset = <1>;
+		qcom,gpio-standby = <2>;
+		qcom,gpio-af-pwdm = <3>;
+		qcom,gpio-req-tbl-num = <0 1 2 3>;
+		qcom,gpio-req-tbl-flags = <1 0 0 0>;
+		qcom,gpio-req-tbl-label = "CAMIF_MCLK",
+		        "CAM_RESET1",
+		        "CAM_STANDBY",
+		        "CAM_AF_PWDM";
+		qcom,sensor-position = <0>;
+		qcom,sensor-mode = <0>;
+		qcom,cci-master = <0>;
+		status = "ok";
+	};
+
+	qcom,camera@1 {
+		cell-index = <1>;
+		compatible = "qcom,camera";
+		reg = <0x01>;
+		qcom,csiphy-sd-index = <1>;
+		qcom,csid-sd-index = <1>;
+		qcom,mount-angle = <270>;
+		cam_vdig-supply = <&pm8226_l5>;
+		cam_vana-supply = <&pm8226_l19>;
+		cam_vio-supply = <&pm8226_lvs1>;
+		qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana";
+		qcom,cam-vreg-type = <0 1 0>;
+		qcom,cam-vreg-min-voltage = <1200000 0 2850000>;
+		qcom,cam-vreg-max-voltage = <1200000 0 2850000>;
+		qcom,cam-vreg-op-mode = <200000 0 80000>;
+		qcom,gpio-no-mux = <0>;
+		gpios = <&msmgpio 26 0>,
+				<&msmgpio 28 0>,
+				<&msmgpio 35 0>,
+				<&msmgpio 23 0>;
+		qcom,gpio-reset = <1>;
+		qcom,gpio-standby = <2>;
+		qcom,gpio-vdig = <3>;
+		qcom,gpio-req-tbl-num = <0 1 2 3>;
+		qcom,gpio-req-tbl-flags = <1 0 0 0>;
+		qcom,gpio-req-tbl-label = "CAMIF_MCLK",
+				"CAM_RESET",
+				"CAM_STANDBY",
+				"CAM_VDIG";
+		qcom,sensor-position = <1>;
+		qcom,sensor-mode = <0>;
+		qcom,cci-master = <0>;
+		status = "ok";
+	};
 };
diff --git a/arch/arm/boot/dts/msm8926-qrd-skug.dts b/arch/arm/boot/dts/msm8926-qrd-skug.dtsi
similarity index 90%
rename from arch/arm/boot/dts/msm8926-qrd-skug.dts
rename to arch/arm/boot/dts/msm8926-qrd-skug.dtsi
index 15a2d58..dabadda 100644
--- a/arch/arm/boot/dts/msm8926-qrd-skug.dts
+++ b/arch/arm/boot/dts/msm8926-qrd-skug.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
@@ -10,17 +10,9 @@
  * GNU General Public License for more details.
  */
 
-/dts-v1/;
-/include/ "msm8926.dtsi"
 /include/ "msm8226-qrd.dtsi"
 /include/ "msm8926-camera-sensor-qrd.dtsi"
 
-/ {
-	model = "Qualcomm MSM 8926 QRD SKUG";
-	compatible = "qcom,msm8926-qrd", "qcom,msm8926", "qcom,qrd";
-	qcom,board-id = <11 5>;
-};
-
 &qrd_batterydata {
 	qcom,rpull-up-kohm = <100>;
 	qcom,vref-batt-therm = <1800000>;
@@ -106,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-1080p-cdp.dts b/arch/arm/boot/dts/msm8926-v1-1080p-cdp.dts
similarity index 88%
copy from arch/arm/boot/dts/msm8926-1080p-cdp.dts
copy to arch/arm/boot/dts/msm8926-v1-1080p-cdp.dts
index 33e484a..1829a8e 100644
--- a/arch/arm/boot/dts/msm8926-1080p-cdp.dts
+++ b/arch/arm/boot/dts/msm8926-v1-1080p-cdp.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
@@ -12,7 +12,7 @@
 
 
 /dts-v1/;
-/include/ "msm8926.dtsi"
+/include/ "msm8926-v1.dtsi"
 /include/ "msm8226-1080p-cdp.dtsi"
 /include/ "msm8226-camera-sensor-cdp.dtsi"
 
@@ -33,6 +33,6 @@
 
 };
 
-&hsic_host {
+&smsc_hub {
 	status = "ok";
 };
diff --git a/arch/arm/boot/dts/msm8926-1080p-mtp.dts b/arch/arm/boot/dts/msm8926-v1-1080p-mtp.dts
similarity index 79%
rename from arch/arm/boot/dts/msm8926-1080p-mtp.dts
rename to arch/arm/boot/dts/msm8926-v1-1080p-mtp.dts
index c1217a2..d94b40c9 100644
--- a/arch/arm/boot/dts/msm8926-1080p-mtp.dts
+++ b/arch/arm/boot/dts/msm8926-v1-1080p-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
@@ -12,7 +12,7 @@
 
 
 /dts-v1/;
-/include/ "msm8926.dtsi"
+/include/ "msm8926-v1.dtsi"
 /include/ "msm8226-1080p-mtp.dtsi"
 /include/ "msm8226-camera-sensor-mtp.dtsi"
 
@@ -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-720p-cdp.dts b/arch/arm/boot/dts/msm8926-v1-720p-cdp.dts
similarity index 88%
rename from arch/arm/boot/dts/msm8926-720p-cdp.dts
rename to arch/arm/boot/dts/msm8926-v1-720p-cdp.dts
index 80bb5e6..2217f15 100644
--- a/arch/arm/boot/dts/msm8926-720p-cdp.dts
+++ b/arch/arm/boot/dts/msm8926-v1-720p-cdp.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
@@ -12,7 +12,7 @@
 
 
 /dts-v1/;
-/include/ "msm8926.dtsi"
+/include/ "msm8926-v1.dtsi"
 /include/ "msm8226-720p-cdp.dtsi"
 /include/ "msm8226-camera-sensor-cdp.dtsi"
 
@@ -33,6 +33,6 @@
 
 };
 
-&hsic_host {
+&smsc_hub {
 	status = "ok";
 };
diff --git a/arch/arm/boot/dts/msm8926-720p-mtp.dts b/arch/arm/boot/dts/msm8926-v1-720p-mtp.dts
similarity index 79%
rename from arch/arm/boot/dts/msm8926-720p-mtp.dts
rename to arch/arm/boot/dts/msm8926-v1-720p-mtp.dts
index 32301fd..74fe06f 100644
--- a/arch/arm/boot/dts/msm8926-720p-mtp.dts
+++ b/arch/arm/boot/dts/msm8926-v1-720p-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
@@ -12,7 +12,7 @@
 
 
 /dts-v1/;
-/include/ "msm8926.dtsi"
+/include/ "msm8926-v1.dtsi"
 /include/ "msm8226-720p-mtp.dtsi"
 /include/ "msm8226-camera-sensor-mtp.dtsi"
 
@@ -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-qrd.dts b/arch/arm/boot/dts/msm8926-v1-qrd-skug-pvt.dts
similarity index 65%
copy from arch/arm/boot/dts/msm8926-qrd.dts
copy to arch/arm/boot/dts/msm8926-v1-qrd-skug-pvt.dts
index 8ee8828..fb5bc01 100644
--- a/arch/arm/boot/dts/msm8926-qrd.dts
+++ b/arch/arm/boot/dts/msm8926-v1-qrd-skug-pvt.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
@@ -11,11 +11,18 @@
  */
 
 /dts-v1/;
-/include/ "msm8926.dtsi"
-/include/ "msm8226-qrd.dtsi"
+/include/ "msm8926-v1.dtsi"
+/include/ "msm8926-qrd-skug.dtsi"
 
 / {
-	model = "Qualcomm MSM 8926 QRD";
+	model = "Qti MSM 8926 QRD SKUG PVT";
 	compatible = "qcom,msm8926-qrd", "qcom,msm8926", "qcom,qrd";
-	qcom,board-id = <11 0>;
+	qcom,board-id = <0x2000b 5>;
+};
+
+&pm8226_vadc {
+	chan@30 {
+		label = "batt_therm";
+		qcom,scale-function = <9>;
+	};
 };
diff --git a/arch/arm/boot/dts/msm8926-qrd.dts b/arch/arm/boot/dts/msm8926-v1-qrd-skug.dts
similarity index 73%
copy from arch/arm/boot/dts/msm8926-qrd.dts
copy to arch/arm/boot/dts/msm8926-v1-qrd-skug.dts
index 8ee8828..0cb6119 100644
--- a/arch/arm/boot/dts/msm8926-qrd.dts
+++ b/arch/arm/boot/dts/msm8926-v1-qrd-skug.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
@@ -11,11 +11,12 @@
  */
 
 /dts-v1/;
-/include/ "msm8926.dtsi"
-/include/ "msm8226-qrd.dtsi"
+/include/ "msm8926-v1.dtsi"
+/include/ "msm8926-qrd-skug.dtsi"
 
 / {
-	model = "Qualcomm MSM 8926 QRD";
+	model = "Qualcomm MSM 8926 QRD SKUG";
 	compatible = "qcom,msm8926-qrd", "qcom,msm8926", "qcom,qrd";
-	qcom,board-id = <11 0>;
+	qcom,board-id = <11 5>;
 };
+
diff --git a/arch/arm/boot/dts/msm8926-qrd.dts b/arch/arm/boot/dts/msm8926-v1-qrd.dts
similarity index 86%
rename from arch/arm/boot/dts/msm8926-qrd.dts
rename to arch/arm/boot/dts/msm8926-v1-qrd.dts
index 8ee8828..fa6ff64 100644
--- a/arch/arm/boot/dts/msm8926-qrd.dts
+++ b/arch/arm/boot/dts/msm8926-v1-qrd.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
@@ -11,7 +11,7 @@
  */
 
 /dts-v1/;
-/include/ "msm8926.dtsi"
+/include/ "msm8926-v1.dtsi"
 /include/ "msm8226-qrd.dtsi"
 
 / {
diff --git a/arch/arm/boot/dts/msm8926-qrd.dts b/arch/arm/boot/dts/msm8926-v1.dtsi
similarity index 68%
copy from arch/arm/boot/dts/msm8926-qrd.dts
copy to arch/arm/boot/dts/msm8926-v1.dtsi
index 8ee8828..c70cf71 100644
--- a/arch/arm/boot/dts/msm8926-qrd.dts
+++ b/arch/arm/boot/dts/msm8926-v1.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
@@ -10,12 +10,11 @@
  * GNU General Public License for more details.
  */
 
-/dts-v1/;
 /include/ "msm8926.dtsi"
-/include/ "msm8226-qrd.dtsi"
 
 / {
-	model = "Qualcomm MSM 8926 QRD";
-	compatible = "qcom,msm8926-qrd", "qcom,msm8926", "qcom,qrd";
-	qcom,board-id = <11 0>;
+	qcom,msm-id = <200 0>,
+		      <224 0>,
+		      <200 0x10001>,
+		      <224 0x10001>;
 };
diff --git a/arch/arm/boot/dts/msm8926-1080p-cdp.dts b/arch/arm/boot/dts/msm8926-v2-1080p-cdp.dts
similarity index 88%
rename from arch/arm/boot/dts/msm8926-1080p-cdp.dts
rename to arch/arm/boot/dts/msm8926-v2-1080p-cdp.dts
index 33e484a..7ab37cd 100644
--- a/arch/arm/boot/dts/msm8926-1080p-cdp.dts
+++ b/arch/arm/boot/dts/msm8926-v2-1080p-cdp.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
@@ -12,7 +12,7 @@
 
 
 /dts-v1/;
-/include/ "msm8926.dtsi"
+/include/ "msm8926-v2.dtsi"
 /include/ "msm8226-1080p-cdp.dtsi"
 /include/ "msm8226-camera-sensor-cdp.dtsi"
 
@@ -33,6 +33,6 @@
 
 };
 
-&hsic_host {
+&smsc_hub {
 	status = "ok";
 };
diff --git a/arch/arm/boot/dts/msm8926-1080p-cdp.dts b/arch/arm/boot/dts/msm8926-v2-1080p-ext-buck-cdp.dts
similarity index 84%
copy from arch/arm/boot/dts/msm8926-1080p-cdp.dts
copy to arch/arm/boot/dts/msm8926-v2-1080p-ext-buck-cdp.dts
index 33e484a..d38b53f 100644
--- a/arch/arm/boot/dts/msm8926-1080p-cdp.dts
+++ b/arch/arm/boot/dts/msm8926-v2-1080p-ext-buck-cdp.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
@@ -12,14 +12,14 @@
 
 
 /dts-v1/;
-/include/ "msm8926.dtsi"
+/include/ "msm8926-v2-ext-buck.dtsi"
 /include/ "msm8226-1080p-cdp.dtsi"
 /include/ "msm8226-camera-sensor-cdp.dtsi"
 
 / {
 	model = "Qualcomm MSM 8926 CDP";
 	compatible = "qcom,msm8926-cdp", "qcom,msm8926", "qcom,cdp";
-	qcom,board-id = <1 2>;
+	qcom,board-id = <1 3>;
 };
 
 &pm8226_chg {
@@ -33,6 +33,6 @@
 
 };
 
-&hsic_host {
+&smsc_hub {
 	status = "ok";
 };
diff --git a/arch/arm/boot/dts/msm8926-1080p-mtp.dts b/arch/arm/boot/dts/msm8926-v2-1080p-ext-buck-mtp.dts
similarity index 66%
copy from arch/arm/boot/dts/msm8926-1080p-mtp.dts
copy to arch/arm/boot/dts/msm8926-v2-1080p-ext-buck-mtp.dts
index c1217a2..0a33976 100644
--- a/arch/arm/boot/dts/msm8926-1080p-mtp.dts
+++ b/arch/arm/boot/dts/msm8926-v2-1080p-ext-buck-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
@@ -12,12 +12,21 @@
 
 
 /dts-v1/;
-/include/ "msm8926.dtsi"
+/include/ "msm8926-v2-ext-buck.dtsi"
 /include/ "msm8226-1080p-mtp.dtsi"
 /include/ "msm8226-camera-sensor-mtp.dtsi"
 
 / {
 	model = "Qualcomm MSM 8926 MTP";
 	compatible = "qcom,msm8926-mtp", "qcom,msm8926", "qcom,mtp";
-	qcom,board-id = <8 2>;
+	qcom,board-id = <8 3>;
+};
+
+&smsc_hub {
+	status = "ok";
+	smsc,model-id = <3502>;
+	smsc,reset-gpio = <&msmgpio 114 0x00>;
+	smsc,int-gpio = <&msmgpio 9 0x00>;
+	smsc,xo-clk-gpio = <&msmgpio 8 0x00>;
+	hub-int-supply = <&pm8226_l6>;
 };
diff --git a/arch/arm/boot/dts/msm8926-1080p-mtp.dts b/arch/arm/boot/dts/msm8926-v2-1080p-mtp.dts
similarity index 69%
copy from arch/arm/boot/dts/msm8926-1080p-mtp.dts
copy to arch/arm/boot/dts/msm8926-v2-1080p-mtp.dts
index c1217a2..2466f8b 100644
--- a/arch/arm/boot/dts/msm8926-1080p-mtp.dts
+++ b/arch/arm/boot/dts/msm8926-v2-1080p-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
@@ -12,7 +12,7 @@
 
 
 /dts-v1/;
-/include/ "msm8926.dtsi"
+/include/ "msm8926-v2.dtsi"
 /include/ "msm8226-1080p-mtp.dtsi"
 /include/ "msm8226-camera-sensor-mtp.dtsi"
 
@@ -21,3 +21,12 @@
 	compatible = "qcom,msm8926-mtp", "qcom,msm8926", "qcom,mtp";
 	qcom,board-id = <8 2>;
 };
+
+&smsc_hub {
+	status = "ok";
+	smsc,model-id = <3502>;
+	smsc,reset-gpio = <&msmgpio 114 0x00>;
+	smsc,int-gpio = <&msmgpio 9 0x00>;
+	smsc,xo-clk-gpio = <&msmgpio 8 0x00>;
+	hub-int-supply = <&pm8226_l6>;
+};
diff --git a/arch/arm/boot/dts/msm8926-720p-cdp.dts b/arch/arm/boot/dts/msm8926-v2-720p-cdp.dts
similarity index 88%
copy from arch/arm/boot/dts/msm8926-720p-cdp.dts
copy to arch/arm/boot/dts/msm8926-v2-720p-cdp.dts
index 80bb5e6..5c5ad89 100644
--- a/arch/arm/boot/dts/msm8926-720p-cdp.dts
+++ b/arch/arm/boot/dts/msm8926-v2-720p-cdp.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
@@ -12,7 +12,7 @@
 
 
 /dts-v1/;
-/include/ "msm8926.dtsi"
+/include/ "msm8926-v2.dtsi"
 /include/ "msm8226-720p-cdp.dtsi"
 /include/ "msm8226-camera-sensor-cdp.dtsi"
 
@@ -33,6 +33,6 @@
 
 };
 
-&hsic_host {
+&smsc_hub {
 	status = "ok";
 };
diff --git a/arch/arm/boot/dts/msm8926-720p-mtp.dts b/arch/arm/boot/dts/msm8926-v2-720p-mtp.dts
similarity index 69%
copy from arch/arm/boot/dts/msm8926-720p-mtp.dts
copy to arch/arm/boot/dts/msm8926-v2-720p-mtp.dts
index 32301fd..2c577cd 100644
--- a/arch/arm/boot/dts/msm8926-720p-mtp.dts
+++ b/arch/arm/boot/dts/msm8926-v2-720p-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
@@ -12,7 +12,7 @@
 
 
 /dts-v1/;
-/include/ "msm8926.dtsi"
+/include/ "msm8926-v2.dtsi"
 /include/ "msm8226-720p-mtp.dtsi"
 /include/ "msm8226-camera-sensor-mtp.dtsi"
 
@@ -21,3 +21,12 @@
 	compatible = "qcom,msm8926-mtp", "qcom,msm8926", "qcom,mtp";
 	qcom,board-id = <8 0>;
 };
+
+&smsc_hub {
+	status = "ok";
+	smsc,model-id = <3502>;
+	smsc,reset-gpio = <&msmgpio 114 0x00>;
+	smsc,int-gpio = <&msmgpio 9 0x00>;
+	smsc,xo-clk-gpio = <&msmgpio 8 0x00>;
+	hub-int-supply = <&pm8226_l6>;
+};
diff --git a/arch/arm/boot/dts/msm8926-v2-ext-buck.dtsi b/arch/arm/boot/dts/msm8926-v2-ext-buck.dtsi
new file mode 100644
index 0000000..8a95116
--- /dev/null
+++ b/arch/arm/boot/dts/msm8926-v2-ext-buck.dtsi
@@ -0,0 +1,87 @@
+/* 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/ "msm8926-v2.dtsi"
+
+&i2c_0 {
+	qcom,sda-gpio = <&msmgpio 14 0>;
+	qcom,scl-gpio = <&msmgpio 15 0>;
+
+	ncp6335d: ncp6335d-regulator@1c {
+		compatible = "onnn,ncp6335d-regulator";
+		reg = <0x1c>;
+		onnn,vsel = <0>;
+		onnn,slew-ns = <2666>;
+		onnn,step-size = <10000>;
+		onnn,min-slew-ns = <333>;
+		onnn,max-slew-ns = <2666>;
+		regulator-min-microvolt = <1050000>;
+		regulator-max-microvolt = <1350000>;
+		onnn,min-setpoint = <600000>;
+		onnn,vsel-gpio = <&msmgpio 2 1>;
+		onnn,discharge-enable;
+		onnn,restore-reg;
+		onnn,tlmm-config = <0x80 0x0>;
+	};
+
+	fan53555: fan53555-regulator@60 {
+		compatible = "fairchild,fan53555-regulator";
+		reg = <0x60>;
+		fairchild,backup-vsel = <1>;
+		regulator-min-microvolt = <1050000>;
+		regulator-max-microvolt = <1350000>;
+		regulator-ramp-delay = <8000>;
+		fairchild,vsel-gpio = <&msmgpio 2 1>;
+		fairchild,restore-reg;
+		fairchild,disable-suspend;
+	};
+};
+
+&apc_vreg_corner {
+	vdd-apc-optional-prim-supply = <&ncp6335d>;
+	vdd-apc-supply = <&fan53555>;
+};
+
+&soc {
+	qcom,spm@f9012000 {
+		compatible = "qcom,spm-v2";
+		qcom,saw2-spm-cmd-pc-no-rpm = [00 32 10 e0 d0 6b c0 42 f0
+				03 50 4e 02 02 c0 d0 12 e0 6b 02 32
+				50 f0 0f];
+		qcom,saw2-spm-cmd-pc = [00 32 10 e0 d0 6b c0 42 f0
+				07 50 4e 02 02 c0 d0 12 e0 6b 02 32
+				50 f0 0f];
+	};
+
+	qcom,lpm-levels {
+		qcom,system-modes {
+			compatible = "qcom,system-modes";
+			qcom,system-modes@2 {
+				qcom,l2 = "l2_cache_pc";
+				qcom,latency-us = <13200>;
+				qcom,ss-power = <315>;
+				qcom,energy-overhead = <1027150>;
+				qcom,time-overhead = <2400>;
+				qcom,min-cpu-mode= "pc";
+				qcom,sync-cpus;
+				qcom,send-rpm-sleep-set;
+			};
+		};
+	};
+
+	qcom,ext-buck-control {
+		compatible = "qcom,ext-buck-control";
+		qcom,gpio-num = <50>;
+		qcom,settling-time-us = <9600>;
+	};
+
+};
diff --git a/arch/arm/boot/dts/msm8926-qrd.dts b/arch/arm/boot/dts/msm8926-v2-qrd-skug-pvt.dts
similarity index 65%
copy from arch/arm/boot/dts/msm8926-qrd.dts
copy to arch/arm/boot/dts/msm8926-v2-qrd-skug-pvt.dts
index 8ee8828..f8cd88d 100644
--- a/arch/arm/boot/dts/msm8926-qrd.dts
+++ b/arch/arm/boot/dts/msm8926-v2-qrd-skug-pvt.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
@@ -11,11 +11,18 @@
  */
 
 /dts-v1/;
-/include/ "msm8926.dtsi"
-/include/ "msm8226-qrd.dtsi"
+/include/ "msm8926-v2.dtsi"
+/include/ "msm8926-qrd-skug.dtsi"
 
 / {
-	model = "Qualcomm MSM 8926 QRD";
+	model = "Qti MSM 8926 QRD SKUG PVT";
 	compatible = "qcom,msm8926-qrd", "qcom,msm8926", "qcom,qrd";
-	qcom,board-id = <11 0>;
+	qcom,board-id = <0x2000b 5>;
+};
+
+&pm8226_vadc {
+	chan@30 {
+		label = "batt_therm";
+		qcom,scale-function = <9>;
+	};
 };
diff --git a/arch/arm/boot/dts/msm8926-qrd.dts b/arch/arm/boot/dts/msm8926-v2-qrd-skug.dts
similarity index 73%
copy from arch/arm/boot/dts/msm8926-qrd.dts
copy to arch/arm/boot/dts/msm8926-v2-qrd-skug.dts
index 8ee8828..0d69e51 100644
--- a/arch/arm/boot/dts/msm8926-qrd.dts
+++ b/arch/arm/boot/dts/msm8926-v2-qrd-skug.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
@@ -11,11 +11,12 @@
  */
 
 /dts-v1/;
-/include/ "msm8926.dtsi"
-/include/ "msm8226-qrd.dtsi"
+/include/ "msm8926-v2.dtsi"
+/include/ "msm8926-qrd-skug.dtsi"
 
 / {
-	model = "Qualcomm MSM 8926 QRD";
+	model = "Qualcomm MSM 8926 QRD SKUG";
 	compatible = "qcom,msm8926-qrd", "qcom,msm8926", "qcom,qrd";
-	qcom,board-id = <11 0>;
+	qcom,board-id = <11 5>;
 };
+
diff --git a/arch/arm/boot/dts/msm8926-qrd.dts b/arch/arm/boot/dts/msm8926-v2-qrd.dts
similarity index 86%
copy from arch/arm/boot/dts/msm8926-qrd.dts
copy to arch/arm/boot/dts/msm8926-v2-qrd.dts
index 8ee8828..6223055 100644
--- a/arch/arm/boot/dts/msm8926-qrd.dts
+++ b/arch/arm/boot/dts/msm8926-v2-qrd.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
@@ -11,7 +11,7 @@
  */
 
 /dts-v1/;
-/include/ "msm8926.dtsi"
+/include/ "msm8926-v2.dtsi"
 /include/ "msm8226-qrd.dtsi"
 
 / {
diff --git a/arch/arm/boot/dts/msm8926-v2.dtsi b/arch/arm/boot/dts/msm8926-v2.dtsi
new file mode 100644
index 0000000..c443ba6
--- /dev/null
+++ b/arch/arm/boot/dts/msm8926-v2.dtsi
@@ -0,0 +1,110 @@
+/* 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/ "msm8926.dtsi"
+
+/ {
+	qcom,msm-id = <200 0x20000>,
+		      <224 0x20000>;
+};
+
+&msm_gpu {
+	/* Updated chip ID */
+	qcom,chipid = <0x03000512>;
+
+	/* Bus Scale Settings */
+	qcom,msm-bus,num-cases = <4>;
+	qcom,msm-bus,vectors-KBps =
+		<26 512 0 0>, <89 604 0 0>,
+		<26 512 0 1800000>, <89 604 0 3200000>,
+		<26 512 0 3600000>, <89 604 0 5120000>,
+		<26 512 0 4800000>, <89 604 0 6400000>;
+
+	/* Power levels */
+	qcom,gpu-pwrlevels {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		compatible = "qcom,gpu-pwrlevels";
+
+		qcom,gpu-pwrlevel@0 {
+			reg = <0>;
+			qcom,gpu-freq = <500000000>;
+			qcom,bus-freq = <3>;
+			qcom,io-fraction = <0>;
+		};
+
+		qcom,gpu-pwrlevel@1 {
+			reg = <1>;
+			qcom,gpu-freq = <320000000>;
+			qcom,bus-freq = <2>;
+			qcom,io-fraction = <33>;
+		};
+
+		qcom,gpu-pwrlevel@2 {
+			reg = <2>;
+			qcom,gpu-freq = <200000000>;
+			qcom,bus-freq = <1>;
+			qcom,io-fraction = <100>;
+		};
+
+		qcom,gpu-pwrlevel@3 {
+			reg = <3>;
+			qcom,gpu-freq = <19000000>;
+			qcom,bus-freq = <0>;
+			qcom,io-fraction = <0>;
+		};
+	};
+};
+
+&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>;
+};
+
+&pm8226_l3_ao {
+	regulator-max-microvolt = <1287500>;
+};
+
+&pm8226_l3_so {
+	regulator-max-microvolt = <1287500>;
+};
+
+&apc_vreg_corner {
+	/delete-property/ qcom,cpr-enable;
+	/delete-property/ qcom,cpr-fuse-cond-min-volt-sel;
+	/delete-property/ qcom,cpr-cond-min-voltage;
+	/delete-property/ qcom,cpr-fuse-uplift-sel;
+	/delete-property/ qcom,cpr-uplift-voltage;
+	/delete-property/ qcom,cpr-uplift-quotient;
+	/delete-property/ qcom,cpr-uplift-max-volt;
+	/delete-property/ qcom,cpr-uplift-speed-bin;
+	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 0b876a1..1919022 100644
--- a/arch/arm/boot/dts/msm8926.dtsi
+++ b/arch/arm/boot/dts/msm8926.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,10 +22,11 @@
 / {
 	model = "Qualcomm MSM 8926";
 	compatible = "qcom,msm8926";
-	qcom,msm-id = <200 0>,
-		      <224 0>,
-		      <200 0x10001>,
-		      <224 0x10001>;
+
+};
+
+&qsecom_mem {
+	linux,memory-limit = <0x0>;
 };
 
 &soc {
@@ -39,10 +40,58 @@
 		vdd_mss-supply = <&pm8226_s5>;
 	};
 
-	qcom,acpuclk@f9011050 {
+	qcom,clock-a7@f9011050 {
 		reg =	<0xf9011050 0x8>,
 			<0xfc4b80b0 0x8>;
-		reg-names = "rcg_base", "pte_efuse";
+		reg-names = "rcg-base", "efuse";
+		qcom,speed0-bin-v0 =
+			<         0 0>,
+			< 384000000 2>,
+			< 787200000 4>,
+			<1190400000 7>;
+		qcom,speed0-bin-v1 =
+			<         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>,
+			< 384000000 2>,
+			< 787200000 4>,
+			< 998400000 5>,
+			<1094400000 6>,
+			<1190400000 7>,
+			<1305600000 8>,
+			<1344000000 9>,
+			<1401600000 10>,
+			<1497600000 11>,
+			<1593600000 12>;
+		qcom,speed5-bin-v1 =
+			<         0 0>,
+			< 384000000 2>,
+			< 787200000 4>,
+			< 998400000 5>,
+			<1094400000 6>,
+			<1190400000 7>,
+			<1305600000 8>,
+			<1344000000 9>,
+			<1401600000 10>,
+			<1497600000 11>,
+			<1593600000 12>,
+			<1689600000 13>,
+			<1785600000 14>;
 	};
 
 	qcom,msm-thermal {
@@ -95,41 +144,35 @@
 	};
 };
 
-&pm8226_l3 {
-	regulator-min-microvolt = <750000>;
-	regulator-max-microvolt = <1350000>;
-};
-
-&pm8226_l3_ao {
-	regulator-min-microvolt = <750000>;
-	regulator-max-microvolt = <1350000>;
-};
-
-&pm8226_l3_so {
-	regulator-min-microvolt = <750000>;
-	regulator-max-microvolt = <1350000>;
-};
-
-&pm8226_s2 {
-	regulator-min-microvolt = <900000>;
-	regulator-max-microvolt = <1350000>;
-};
-
 &apc_vreg_corner {
-	qti,pvs-init-voltage = <1350000 1340000 1330000 1320000 1310000
-					1300000 1290000 1280000 1270000 1260000
-					1250000 1240000 1230000 1220000 1210000
-					1200000 1190000 1180000 1170000 1160000
-					1150000 1140000 1140000 1140000 1140000
-					1140000 1140000 1140000 1140000 1140000
-					1140000 1140000>;
-	qti,pvs-corner-ceiling-slow = <1050000 1150000 1280000>;
-	qti,pvs-corner-ceiling-nom  = <1050000 1080000 1200000>;
-	qti,pvs-corner-ceiling-fast = <1050000 1050000 1100000>;
-	qti,cpr-step-quotient = <30>;
-	qti,cpr-up-threshold = <0>;
-	qti,cpr-down-threshold = <5>;
-	qti,cpr-apc-volt-step = <10000>;
+	qcom,cpr-up-threshold = <0>;
+	qcom,cpr-down-threshold = <2>;
+	regulator-min-microvolt = <1>;
+	regulator-max-microvolt = <14>;
+	qcom,cpr-corner-map = <1 1 2 2 3 3 3 3 3 3 3 3 3 3>;
+	qcom,cpr-quotient-adjustment = <0 72 72>;
+	qcom,pvs-version-fuse-sel = <22 4 2 0>;
+	qcom,cpr-corner-frequency-map =
+			<1 300000000>,
+			<2 384000000>,
+			<3 600000000>,
+			<4 787200000>,
+			<5 998400000>,
+			<6 1094400000>,
+			<7 1190400000>,
+			<8 1305600000>,
+			<9 1344000000>,
+			<10 1401600000>,
+			<11 1497600000>,
+			<12 1593600000>,
+			<13 1689600000>,
+			<14 1785600000>;
+	qcom,cpr-speed-bin-max-corners =
+			<0 1 2 4 7>,
+			<1 1 2 4 12>,
+			<2 1 2 4 10>,
+			<5 1 2 4 14>;
+	qcom,cpr-quot-adjust-scaling-factor-max = <650>;
 };
 
 &tsens {
@@ -153,3 +196,9 @@
 	hsic,strobe-gpio = <&msmgpio 119 0x00>;
 	hsic,data-gpio = <&msmgpio 120 0x00>;
 };
+
+&usb_otg {
+	/delete-property/ qcom,hsusb-otg-disable-reset;
+	qcom,ahb-async-bridge-bypass;
+};
+
diff --git a/arch/arm/boot/dts/msm8974-bus.dtsi b/arch/arm/boot/dts/msm8974-bus.dtsi
index af51327..ba8b27e 100644
--- a/arch/arm/boot/dts/msm8974-bus.dtsi
+++ b/arch/arm/boot/dts/msm8974-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
@@ -1168,12 +1168,18 @@
 			qcom,masterp = <0>;
 			qcom,tier = <2>;
 			qcom,hw-sel = "BIMC";
-			qcom,mode = "Fixed";
+			qcom,mode = "Limiter";
 			qcom,qport = <0>;
 			qcom,ws = <10000>;
 			qcom,mas-hw-id = <0>;
 			qcom,prio-rd = <0>;
 			qcom,prio-wr = <0>;
+			qcom,mode-thresh = "Fixed";
+			qcom,thresh = <2000000 2456000>;
+			qcom,dual-conf;
+			qcom,bimc,bw = <300000 450000>;
+			qcom,bimc,gp = <5000>;
+			qcom,bimc,thmp = <50>;
 		};
 
 		mas-ampss-m1 {
@@ -1182,12 +1188,18 @@
 			qcom,masterp = <1>;
 			qcom,tier = <2>;
 			qcom,hw-sel = "BIMC";
-			qcom,mode = "Fixed";
+			qcom,mode = "Limiter";
 			qcom,qport = <1>;
 			qcom,ws = <10000>;
 			qcom,mas-hw-id = <0>;
 			qcom,prio-rd = <0>;
 			qcom,prio-wr = <0>;
+			qcom,mode-thresh = "Fixed";
+			qcom,thresh = <2000000 2456000>;
+			qcom,dual-conf;
+			qcom,bimc,bw = <300000 450000>;
+			qcom,bimc,gp = <5000>;
+			qcom,bimc,thmp = <50>;
 		};
 
 		mas-mss-proc {
diff --git a/arch/arm/boot/dts/msm8974-camera-sensor-cdp.dtsi b/arch/arm/boot/dts/msm8974-camera-sensor-cdp.dtsi
index 9948833..2e58167 100644
--- a/arch/arm/boot/dts/msm8974-camera-sensor-cdp.dtsi
+++ b/arch/arm/boot/dts/msm8974-camera-sensor-cdp.dtsi
@@ -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
@@ -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,4 +61,104 @@
 		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 = <90>;
+		qcom,actuator-src = <&actuator0>;
+		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_MCLK0",
+					  "CAM_RESET0",
+					  "CAM_STANDBY0";
+		qcom,sensor-position = <0>;
+		qcom,sensor-mode = <0>;
+		qcom,cci-master = <0>;
+		status = "ok";
+	};
+
+	qcom,camera@1 {
+		cell-index = <1>;
+		compatible = "qcom,camera";
+		reg = <0x1>;
+		qcom,csiphy-sd-index = <1>;
+		qcom,csid-sd-index = <0>;
+		qcom,mount-angle = <90>;
+		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>;
+		gpios = <&msmgpio 16 0>,
+			<&msmgpio 92 0>,
+			<&msmgpio 91 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_MCLK1",
+					  "CAM_RESET1",
+					  "CAM_STANDBY1";
+		qcom,sensor-position = <0>;
+		qcom,sensor-mode = <0>;
+		qcom,cci-master = <0>;
+		status = "ok";
+	};
+
+	qcom,camera@2 {
+		cell-index = <2>;
+		compatible = "qcom,camera";
+		reg = <0x02>;
+		qcom,csiphy-sd-index = <2>;
+		qcom,csid-sd-index = <2>;
+		qcom,mount-angle = <90>;
+		cam_vdig-supply = <&pm8941_l3>;
+		cam_vana-supply = <&pm8941_l17>;
+		cam_vio-supply = <&pm8941_lvs3>;
+		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 28 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_MCLK2",
+					  "CAM_RESET2",
+					  "CAM_STANDBY2";
+		qcom,sensor-position = <1>;
+		qcom,sensor-mode = <0>;
+		qcom,cci-master = <0>;
+		status = "ok";
+	};
 };
diff --git a/arch/arm/boot/dts/msm8974-camera-sensor-dragonboard.dtsi b/arch/arm/boot/dts/msm8974-camera-sensor-dragonboard.dtsi
index 2f8e558..7ca986d 100644
--- a/arch/arm/boot/dts/msm8974-camera-sensor-dragonboard.dtsi
+++ b/arch/arm/boot/dts/msm8974-camera-sensor-dragonboard.dtsi
@@ -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
@@ -185,4 +185,105 @@
 		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,actuator-src = <&actuator0>;
+		qcom,vdd-cx-supply = <&pm8841_s2>;
+		qcom,vdd-cx-name = "qcom,vdd-cx";
+		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>;
+		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,cci-master = <0>;
+		status = "ok";
+	};
+
+	qcom,camera@1 {
+		cell-index = <1>;
+		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";
+		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>;
+		gpios = <&msmgpio 16 0>,
+			<&msmgpio 92 0>,
+			<&msmgpio 91 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,sensor-position = <1>;
+		qcom,sensor-mode = <0>;
+		qcom,cci-master = <0>;
+		status = "ok";
+	};
+
+	qcom,camera@2 {
+		cell-index = <2>;
+		compatible = "qcom,camera";
+		reg = <0x2>;
+		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";
+		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 17 0>,
+			<&msmgpio 18 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";
+		qcom,sensor-position = <1>;
+		qcom,sensor-mode = <0>;
+		qcom,cci-master = <0>;
+		status = "ok";
+	};
 };
diff --git a/arch/arm/boot/dts/msm8974-camera-sensor-fluid.dtsi b/arch/arm/boot/dts/msm8974-camera-sensor-fluid.dtsi
index 07eb311..ecf5098 100644
--- a/arch/arm/boot/dts/msm8974-camera-sensor-fluid.dtsi
+++ b/arch/arm/boot/dts/msm8974-camera-sensor-fluid.dtsi
@@ -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
@@ -190,4 +190,105 @@
 		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 = <270>;
+		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>;
+		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>;
+		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,sensor-position = <0>;
+		qcom,sensor-mode = <0>;
+		qcom,cci-master = <0>;
+		status = "ok";
+	};
+
+	qcom,camera@1 {
+		cell-index = <1>;
+		compatible = "qcom,camera";
+		reg = <0x1>;
+		qcom,csiphy-sd-index = <1>;
+		qcom,csid-sd-index = <1>;
+		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>;
+		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>;
+		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,sensor-position = <1>;
+		qcom,sensor-mode = <0>;
+		qcom,cci-master = <1>;
+		status = "ok";
+	};
+
+	qcom,camera@2 {
+		cell-index = <2>;
+		compatible = "qcom,camera";
+		reg = <0x2>;
+		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>;
+		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>;
+		gpios = <&msmgpio 17 0>,
+			<&msmgpio 18 0>,
+			<&msmgpio 28 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,cci-master = <1>;
+		status = "ok";
+	};
 };
diff --git a/arch/arm/boot/dts/msm8974-camera-sensor-liquid.dtsi b/arch/arm/boot/dts/msm8974-camera-sensor-liquid.dtsi
index bf7f492..a22355a 100644
--- a/arch/arm/boot/dts/msm8974-camera-sensor-liquid.dtsi
+++ b/arch/arm/boot/dts/msm8974-camera-sensor-liquid.dtsi
@@ -1,6 +1,6 @@
 
 /*
- * 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
@@ -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,4 +61,104 @@
 		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 = <90>;
+		qcom,actuator-src = <&actuator0>;
+		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_MCLK0",
+					  "CAM_RESET0",
+					  "CAM_STANDBY0";
+		qcom,sensor-position = <0>;
+		qcom,sensor-mode = <0>;
+		qcom,cci-master = <0>;
+		status = "ok";
+	};
+
+	qcom,camera@1 {
+		cell-index = <1>;
+		compatible = "qcom,camera";
+		reg = <0x1>;
+		qcom,csiphy-sd-index = <1>;
+		qcom,csid-sd-index = <0>;
+		qcom,mount-angle = <90>;
+		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>;
+		gpios = <&msmgpio 16 0>,
+			<&msmgpio 92 0>,
+			<&msmgpio 91 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_MCLK1",
+					  "CAM_RESET1",
+					  "CAM_STANDBY1";
+		qcom,sensor-position = <0>;
+		qcom,sensor-mode = <0>;
+		qcom,cci-master = <0>;
+		status = "ok";
+	};
+
+	qcom,camera@2 {
+		cell-index = <2>;
+		compatible = "qcom,camera";
+		reg = <0x02>;
+		qcom,csiphy-sd-index = <2>;
+		qcom,csid-sd-index = <2>;
+		qcom,mount-angle = <90>;
+		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 17 0>,
+			<&msmgpio 18 0>,
+			<&msmgpio 28 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_MCLK2",
+					  "CAM_RESET2",
+					  "CAM_STANDBY2";
+		qcom,sensor-position = <1>;
+		qcom,sensor-mode = <0>;
+		qcom,cci-master = <0>;
+		status = "ok";
+	};
 };
diff --git a/arch/arm/boot/dts/msm8974-camera-sensor-mtp.dtsi b/arch/arm/boot/dts/msm8974-camera-sensor-mtp.dtsi
index 9d44bda..c3c0d47 100644
--- a/arch/arm/boot/dts/msm8974-camera-sensor-mtp.dtsi
+++ b/arch/arm/boot/dts/msm8974-camera-sensor-mtp.dtsi
@@ -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
@@ -16,6 +16,7 @@
 		cell-index = <0>;
 		compatible = "qcom,camera-led-flash";
 		qcom,flash-type = <1>;
+		qcom,torch-source = <&pm8941_torch>;
 		qcom,flash-source = <&pm8941_flash0 &pm8941_flash1>;
 	};
 };
@@ -36,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>;
@@ -190,4 +70,104 @@
 		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 = <90>;
+		qcom,actuator-src = <&actuator0>;
+		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_MCLK0",
+					  "CAM_RESET0",
+					  "CAM_STANDBY0";
+		qcom,sensor-position = <0>;
+		qcom,sensor-mode = <0>;
+		qcom,cci-master = <0>;
+		status = "ok";
+	};
+
+	qcom,camera@1 {
+		cell-index = <1>;
+		compatible = "qcom,camera";
+		reg = <0x1>;
+		qcom,csiphy-sd-index = <1>;
+		qcom,csid-sd-index = <0>;
+		qcom,mount-angle = <90>;
+		cam_vdig-supply = <&pm8941_l3>;
+		cam_vana-supply = <&pm8941_l17>;
+		cam_vio-supply = <&pm8941_lvs3>;
+		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>;
+		gpios = <&msmgpio 16 0>,
+			<&msmgpio 92 0>,
+			<&msmgpio 91 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_MCLK1",
+					  "CAM_RESET1",
+					  "CAM_STANDBY1";
+		qcom,sensor-position = <0>;
+		qcom,sensor-mode = <0>;
+		qcom,cci-master = <0>;
+		status = "ok";
+	};
+
+	qcom,camera@2 {
+		cell-index = <2>;
+		compatible = "qcom,camera";
+		reg = <0x02>;
+		qcom,csiphy-sd-index = <2>;
+		qcom,csid-sd-index = <2>;
+		qcom,mount-angle = <90>;
+		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>,
+			<&msmgpio 28 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_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-cdp.dtsi b/arch/arm/boot/dts/msm8974-cdp.dtsi
index 9e7b2e6..3b4c881 100644
--- a/arch/arm/boot/dts/msm8974-cdp.dtsi
+++ b/arch/arm/boot/dts/msm8974-cdp.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
@@ -220,6 +220,7 @@
 		qcom,hdmi-audio-rx;
 		qcom,us-euro-gpios = <&pm8941_gpios 20 0>;
 		qcom,cdc-micbias2-headset-only;
+		qcom,mbhc-audio-jack-type = "6-pole-jack";
 	};
 
 	usb2_otg_sw: regulator-tpd4s214 {
@@ -757,3 +758,34 @@
 &dsi_tosh_720_vid {
        qcom,cont-splash-enabled;
 };
+
+&dsi_generic_720p_cmd {
+       qcom,cont-splash-enabled;
+};
+
+&dsi_jdi_1080_vid {
+       qcom,cont-splash-enabled;
+};
+
+&dsi_dual_jdi_video_0 {
+	qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_pwm";
+	qcom,mdss-dsi-bl-pmic-pwm-frequency = <100>;
+	qcom,mdss-dsi-bl-pmic-bank-select = <7>;
+	qcom,cont-splash-enabled;
+};
+
+&dsi_dual_jdi_video_1 {
+	qcom,cont-splash-enabled;
+};
+
+&dsi_dual_jdi_cmd_0 {
+	qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_pwm";
+	qcom,mdss-dsi-bl-pmic-pwm-frequency = <100>;
+	qcom,mdss-dsi-bl-pmic-bank-select = <7>;
+	qcom,cont-splash-enabled;
+};
+
+&dsi_dual_jdi_cmd_1 {
+	qcom,cont-splash-enabled;
+};
+
diff --git a/arch/arm/boot/dts/msm8974-fluid.dtsi b/arch/arm/boot/dts/msm8974-fluid.dtsi
index d0ca01d..eb5a5b6 100644
--- a/arch/arm/boot/dts/msm8974-fluid.dtsi
+++ b/arch/arm/boot/dts/msm8974-fluid.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
@@ -133,6 +133,20 @@
 		};
 	};
 
+	i2c@f9928000 { /* BLSP1 QUP6 */
+		nfc-nci@e {
+			compatible = "qcom,nfc-nci";
+			reg = <0x0e>;
+			qcom,irq-gpio = <&msmgpio 59 0x00>;
+			qcom,dis-gpio = <&msmgpio 13 0x00>;
+			qcom,clk-src = "BBCLK2";
+			qcom,clk-en-gpio = <&msmgpio 0 0x00>;
+			interrupt-parent = <&msmgpio>;
+			interrupts = <59 0>;
+			qcom,clk-gpio = <&pm8941_gpios 32 0>;
+		};
+	};
+
 	i2c@f9967000 {
 		sii8334@72 {
 			compatible = "qcom,mhl-sii8334";
@@ -257,6 +271,7 @@
 		qcom,hdmi-audio-rx;
 		qcom,ext-ult-lo-amp-gpio = <&pm8941_gpios 6 0>;
 		qcom,cdc-micbias2-headset-only;
+		qcom,mbhc-audio-jack-type = "6-pole-jack";
 	};
 };
 
@@ -606,6 +621,11 @@
 	};
 
 	gpio@df00 { /* GPIO 32 */
+		qcom,mode = <0>;		/* QPNP_PIN_MODE_DIG_IN */
+		qcom,pull = <5>;		/* QPNP_PIN_PULL_NO */
+		qcom,vin-sel = <2>;		/* QPNP_PIN_VIN2 */
+		qcom,src-sel = <2>;		/* QPNP_PIN_SEL_FUNC_1 */
+		qcom,master-en = <1>;
 	};
 
 	gpio@e000 { /* GPIO 33 */
diff --git a/arch/arm/boot/dts/msm8974-liquid.dtsi b/arch/arm/boot/dts/msm8974-liquid.dtsi
index 922e3e0..5d1034b 100644
--- a/arch/arm/boot/dts/msm8974-liquid.dtsi
+++ b/arch/arm/boot/dts/msm8974-liquid.dtsi
@@ -26,13 +26,13 @@
 
         qcom,mdss_mdp@fd900000 {
                 qcom,mdss-pref-prim-intf = "edp";
-		qcom,panel-lpg-channel = <7>; /* LPG Channel 8 */
-		qcom,panel-pwm-period = <53>;
         };
 
 	qcom,mdss_edp@fd923400 {
 		status = "ok";
 		qcom,cont-splash-enabled;
+		qcom,panel-lpg-channel = <7>; /* LPG Channel 8 */
+		qcom,panel-pwm-period = <53>;
 	};
 
 	i2c@f9967000 {
@@ -396,12 +396,12 @@
 			compatible = "qcom,hsic-host";
 			reg = <0xf9a00000 0x400>;
 			#address-cells = <0>;
-	                interrupt-parent = <&hsic_host>;
+			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
+			        1 &intc 0 148 0
 		                2 &msmgpio 144 0x8>;
 			interrupt-names = "core_irq", "async_irq", "wakeup";
 			hsic_vdd_dig-supply = <&pm8841_s2_corner>;
@@ -445,6 +445,7 @@
                 qcom,msm-bus,name = "wlan_sdio";
                 qca,wifi-chip-pwd-supply = <&ath_chip_pwd_l>;
         };
+
 };
 
 &mdss_fb0 {
diff --git a/arch/arm/boot/dts/msm8974-mdss-panels.dtsi b/arch/arm/boot/dts/msm8974-mdss-panels.dtsi
index d405bf8..c11ef0a 100644
--- a/arch/arm/boot/dts/msm8974-mdss-panels.dtsi
+++ b/arch/arm/boot/dts/msm8974-mdss-panels.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
@@ -15,3 +15,7 @@
 /include/ "dsi-panel-sharp-qhd-video.dtsi"
 /include/ "dsi-panel-generic-720p-cmd.dtsi"
 /include/ "dsi-panel-jdi-1080p-video.dtsi"
+/include/ "dsi-panel-jdi-dualmipi0-video.dtsi"
+/include/ "dsi-panel-jdi-dualmipi1-video.dtsi"
+/include/ "dsi-panel-jdi-dualmipi0-cmd.dtsi"
+/include/ "dsi-panel-jdi-dualmipi1-cmd.dtsi"
diff --git a/arch/arm/boot/dts/msm8974-mdss.dtsi b/arch/arm/boot/dts/msm8974-mdss.dtsi
index e409c94..3fef47a 100644
--- a/arch/arm/boot/dts/msm8974-mdss.dtsi
+++ b/arch/arm/boot/dts/msm8974-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
@@ -21,6 +21,22 @@
 
 		qcom,max-bandwidth-low-kbps = <2300000>;
 		qcom,max-bandwidth-high-kbps = <3000000>;
+
+		/* Bus Scale Settings */
+		qcom,msm-bus,name = "mdss_mdp";
+		qcom,msm-bus,num-cases = <3>;
+		qcom,msm-bus,num-paths = <1>;
+		qcom,msm-bus,vectors-KBps =
+			<22 512 0 0>,
+			<22 512 0 6400000>,
+			<22 512 0 6400000>;
+
+		/* Fudge factors */
+		qcom,mdss-ab-factor = <2 1>;		/* 2 times    */
+		qcom,mdss-ib-factor = <6 5>;		/* 1.2 times  */
+		qcom,mdss-clk-factor = <5 4>;		/* 1.25 times */
+		qcom,mdss-ib-factor-overlap = <7 4>;	/* 1.75 times  */
+
 		qcom,max-clk-rate = <320000000>;
 		qcom,mdss-pipe-vig-off = <0x00001200 0x00001600
 					       0x00001A00>;
@@ -30,6 +46,20 @@
 		qcom,mdss-pipe-vig-fetch-id = <1 4 7>;
 		qcom,mdss-pipe-rgb-fetch-id = <16 17 18>;
 		qcom,mdss-pipe-dma-fetch-id = <10 13>;
+
+		qcom,mdss-pipe-vig-xin-id = <0 4 8>;
+		qcom,mdss-pipe-rgb-xin-id = <1 5 9>;
+		qcom,mdss-pipe-dma-xin-id = <2 10>;
+
+		qcom,mdss-pipe-vig-clk-ctrl-offsets = <0x3AC 0 0>,
+						      <0x3B4 0 0>,
+						      <0x3BC 0 0>;
+		qcom,mdss-pipe-rgb-clk-ctrl-offsets = <0x3AC 4 8>,
+						      <0x3B4 4 8>,
+						      <0x3BC 4 8>;
+		qcom,mdss-pipe-dma-clk-ctrl-offsets = <0x3AC 8 12>,
+						      <0x3B4 8 12>;
+
 		qcom,mdss-smp-data = <22 4096>;
 
 		qcom,mdss-ctl-off = <0x00000600 0x00000700 0x00000800
@@ -61,6 +91,15 @@
 				    <0x04B0 0xCCCCC0C0>,
 				    <0x04B8 0xCCCCC000>;
 
+		/* buffer parameters to calculate prefill bandwidth */
+		qcom,mdss-prefill-outstanding-buffer-bytes = <1024>;
+		qcom,mdss-prefill-y-buffer-bytes = <4096>;
+		qcom,mdss-prefill-scaler-buffer-lines-bilinear = <2>;
+		qcom,mdss-prefill-scaler-buffer-lines-caf = <4>;
+		qcom,mdss-prefill-post-scaler-buffer-pixels = <0>;
+		qcom,mdss-prefill-pingpong-buffer-pixels = <4096>;
+		qcom,mdss-prefill-fbc-lines = <2>;
+
 		mdss_fb0: qcom,mdss_fb_primary {
 			cell-index = <0>;
 			compatible = "qcom,mdss-fb";
@@ -84,7 +123,10 @@
 		compatible = "qcom,mdss-dsi-ctrl";
 		label = "MDSS DSI CTRL->0";
 		cell-index = <0>;
-		reg = <0xfd922800 0x600>;
+		reg = 	<0xfd922800 0x1f8>,
+			<0xfd922b00 0x2b0>,
+			<0xfdf30000 0x108>;
+		reg-names = "dsi_ctrl", "dsi_phy", "mmss_misc_phys";
 		vdd-supply = <&pm8941_l22>;
 		vddio-supply = <&pm8941_l12>;
 		vdda-supply = <&pm8941_l2>;
@@ -140,12 +182,56 @@
 		compatible = "qcom,mdss-dsi-ctrl";
 		label = "MDSS DSI CTRL->1";
 		cell-index = <1>;
-		reg = <0xfd922e00 0x600>;
+		reg = 	<0xfd922e00 0x1f8>,
+			<0xfd923100 0x2b0>,
+			<0xfdf30000 0x108>;
+		reg-names = "dsi_ctrl", "dsi_phy", "mmss_misc_phys";
 		vdd-supply = <&pm8941_l22>;
 		vddio-supply = <&pm8941_l12>;
 		vdda-supply = <&pm8941_l2>;
 		qcom,mdss-fb-map = <&mdss_fb0>;
 		qcom,mdss-mdp = <&mdss_mdp>;
+		qcom,platform-strength-ctrl = [ff 06];
+		qcom,platform-bist-ctrl = [00 00 b1 ff 00 00];
+		qcom,platform-regulator-settings = [07 09 03 00 20 00 01];
+		qcom,platform-lane-config = [00 00 00 00 00 00 00 01 97
+			00 00 00 00 05 00 00 01 97
+			00 00 00 00 0a 00 00 01 97
+			00 00 00 00 0f 00 00 01 97
+			00 c0 00 00 00 00 00 01 bb];
+		qcom,platform-supply-entry1 {
+				qcom,supply-name = "vdd";
+				qcom,supply-min-voltage = <3000000>;
+				qcom,supply-max-voltage = <3000000>;
+				qcom,supply-enable-load = <100000>;
+				qcom,supply-disable-load = <100>;
+				qcom,supply-pre-on-sleep = <0>;
+				qcom,supply-post-on-sleep = <20>;
+				qcom,supply-pre-off-sleep = <0>;
+				qcom,supply-post-off-sleep = <0>;
+		};
+		qcom,platform-supply-entry2 {
+				qcom,supply-name = "vddio";
+				qcom,supply-min-voltage = <1800000>;
+				qcom,supply-max-voltage = <1800000>;
+				qcom,supply-enable-load = <100000>;
+				qcom,supply-disable-load = <100>;
+				qcom,supply-pre-on-sleep = <0>;
+				qcom,supply-post-on-sleep = <20>;
+				qcom,supply-pre-off-sleep = <0>;
+				qcom,supply-post-off-sleep = <0>;
+		};
+		qcom,platform-supply-entry3 {
+				qcom,supply-name = "vdda";
+				qcom,supply-min-voltage = <1200000>;
+				qcom,supply-max-voltage = <1200000>;
+				qcom,supply-enable-load = <100000>;
+				qcom,supply-disable-load = <100>;
+				qcom,supply-pre-on-sleep = <0>;
+				qcom,supply-post-on-sleep = <0>;
+				qcom,supply-pre-off-sleep = <0>;
+				qcom,supply-post-off-sleep = <0>;
+		};
 	};
 
 	mdss_hdmi_tx: qcom,hdmi_tx@fd922100 {
diff --git a/arch/arm/boot/dts/msm8974-mtp.dtsi b/arch/arm/boot/dts/msm8974-mtp.dtsi
index f73bcdc..d118d51 100644
--- a/arch/arm/boot/dts/msm8974-mtp.dtsi
+++ b/arch/arm/boot/dts/msm8974-mtp.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
@@ -214,6 +214,7 @@
 	sound {
 		qcom,model = "msm8974-taiko-mtp-snd-card";
 		qcom,cdc-micbias2-headset-only;
+		qcom,mbhc-audio-jack-type = "6-pole-jack";
 	};
 };
 
@@ -707,6 +708,7 @@
 	taiko_codec {
 		qcom,cdc-micbias1-ext-cap;
 		qcom,cdc-micbias2-ext-cap;
+		qcom,cdc-micbias3-ext-cap;
 		qcom,cdc-micbias4-ext-cap;
 	};
 };
@@ -733,3 +735,11 @@
 &dsi_tosh_720_vid {
        qcom,cont-splash-enabled;
 };
+
+&dsi_generic_720p_cmd {
+       qcom,cont-splash-enabled;
+};
+
+&dsi_jdi_1080_vid {
+       qcom,cont-splash-enabled;
+};
diff --git a/arch/arm/boot/dts/msm8974-regulator.dtsi b/arch/arm/boot/dts/msm8974-regulator.dtsi
index 9b9202e..45b716a 100644
--- a/arch/arm/boot/dts/msm8974-regulator.dtsi
+++ b/arch/arm/boot/dts/msm8974-regulator.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
@@ -288,7 +288,7 @@
 	rpm-regulator-ldoa11 {
 		status = "okay";
 		pm8941_l11: regulator-l11 {
-			regulator-min-microvolt = <1300000>;
+			regulator-min-microvolt = <1225000>;
 			regulator-max-microvolt = <1350000>;
 			qcom,init-voltage = <1300000>;
 			status = "okay";
@@ -465,6 +465,8 @@
 		ranges;
 		qcom,pfm-threshold = <76>;
 		qcom,use-phase-scaling-factor;
+		qcom,phase-scaling-factor-bits-pos = <16>;
+		qcom,valid-scaling-factor-versions = <0 1 0 0>;
 
 		krait0_vreg: regulator@f9088000 {
 			compatible = "qcom,krait-regulator";
diff --git a/arch/arm/boot/dts/msm8974-v1-pm.dtsi b/arch/arm/boot/dts/msm8974-v1-pm.dtsi
index 179edac..516d068 100644
--- a/arch/arm/boot/dts/msm8974-v1-pm.dtsi
+++ b/arch/arm/boot/dts/msm8974-v1-pm.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
@@ -124,13 +124,13 @@
 		qcom,phase-port = <0x1>;
 		qcom,pfm-port = <0x2>;
 		qcom,saw2-spm-cmd-ret = [1f 00 20 03 22 00 0f];
-		qcom,saw2-spm-cmd-gdhs = [00 20 32 42 07 44 22 50 02 32 50 0f];
+		qcom,saw2-spm-cmd-gdhs = [00 20 32 42 03 44 22 50 02 32 50 0f];
 		qcom,saw2-spm-cmd-pc = [00 10 32 b0 11 42 07 01 b0 12 44
 				50 02 32 50 0f];
 		qcom,L2-spm-is-apcs-master;
 	};
 
-	qcom,lpm-levels {
+	lpm_levels: qcom,lpm-levels {
 		compatible = "qcom,lpm-levels";
 		qcom,default-l2-state = "l2_cache_retention";
 		#address-cells = <1>;
@@ -311,6 +311,7 @@
 		qcom,pc-mode = "tz_l2_int";
 		qcom,use-sync-timer;
 		qcom,cpus-as-clocks;
+		qcom,lpm-levels = <&lpm_levels>;
 	};
 
 	qcom,cpu-sleep-status@f9088008 {
diff --git a/arch/arm/boot/dts/msm8974-v1.dtsi b/arch/arm/boot/dts/msm8974-v1.dtsi
index 556e912..6146454 100644
--- a/arch/arm/boot/dts/msm8974-v1.dtsi
+++ b/arch/arm/boot/dts/msm8974-v1.dtsi
@@ -149,6 +149,10 @@
 	qcom,hsusb-otg-pnoc-errata-fix;
 };
 
+&usb3 {
+	qcom,usbin-vadc = <&pm8941_vadc>;
+};
+
 &gdsc_venus {
 	qcom,skip-logic-collapse;
 	qcom,retain-periph;
diff --git a/arch/arm/boot/dts/msm8974-v2-pm.dtsi b/arch/arm/boot/dts/msm8974-v2-pm.dtsi
index e2d40f7..cde5e5a9 100644
--- a/arch/arm/boot/dts/msm8974-v2-pm.dtsi
+++ b/arch/arm/boot/dts/msm8974-v2-pm.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
@@ -120,13 +120,13 @@
 		qcom,phase-port = <0x1>;
 		qcom,pfm-port = <0x2>;
 		qcom,saw2-spm-cmd-ret = [1f 00 03 00 0f];
-		qcom,saw2-spm-cmd-gdhs = [00 32 42 07 44 50 02 32 50 0f];
+		qcom,saw2-spm-cmd-gdhs = [00 32 42 03 44 50 02 32 50 0f];
 		qcom,saw2-spm-cmd-pc = [00 10 32 b0 11 42 07 01 b0 12 44
 				50 02 32 50 0f];
 		qcom,L2-spm-is-apcs-master;
 	};
 
-	qcom,lpm-levels {
+	lpm_levels: qcom,lpm-levels {
 		compatible = "qcom,lpm-levels";
 		qcom,default-l2-state = "l2_cache_retention";
 		#address-cells = <1>;
@@ -172,12 +172,13 @@
 
 			qcom,system-mode@0 {
 				qcom,l2 = "l2_cache_gdhs";
-				qcom,latency-us = <20000>;
+				qcom,latency-us = <500>;
 				qcom,ss-power = <163>;
-				qcom,energy-overhead = <1577736>;
-				qcom,time-overhead = <5067>;
-				qcom,min-cpu-mode= "pc";
+				qcom,energy-overhead = <577736>;
+				qcom,time-overhead = <1000>;
+				qcom,min-cpu-mode= "standalone_pc";
 				qcom,sync-cpus;
+
 			};
 
 			qcom,system-mode@1 {
@@ -188,6 +189,7 @@
 				qcom,time-overhead = <6605>;
 				qcom,min-cpu-mode = "pc";
 				qcom,sync-cpus;
+				qcom,send-rpm-sleep-set;
 			};
 		};
 	};
@@ -212,6 +214,7 @@
 			<50 172>, /* usb1_hs_async_wakeup_irq */
 			<53 104>, /* mdss_irq */
 			<62 222>, /* ee0_krait_hlos_spmi_periph_irq */
+			<0xff 33>,  /* APCC_qgicL2PerfMonIrptReq */
 			<0xff 34>,  /* APCC_qgicL2ErrorIrptReq */
 			<0xff 35>,  /* WDT_barkInt */
 			<0xff 40>,  /* qtimer_phy_irq */
@@ -321,6 +324,7 @@
 		qcom,pc-mode = "tz_l2_int";
 		qcom,use-sync-timer;
 		qcom,cpus-as-clocks;
+		qcom,lpm-levels = <&lpm_levels>;
 
 		qcom,pm-snoc-client {
 			compatible = "qcom,pm-snoc-client";
diff --git a/arch/arm/boot/dts/msm8974-v2.2.dtsi b/arch/arm/boot/dts/msm8974-v2.2.dtsi
index 3ed5720..14897ba 100644
--- a/arch/arm/boot/dts/msm8974-v2.2.dtsi
+++ b/arch/arm/boot/dts/msm8974-v2.2.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
@@ -93,3 +93,7 @@
 	qcom,retain-periph;
 	qcom,retain-mem;
 };
+
+&gdsc_venus {
+	qcom,skip-logic-collapse;
+};
diff --git a/arch/arm/boot/dts/msm8974-v2.dtsi b/arch/arm/boot/dts/msm8974-v2.dtsi
index 9176117..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
@@ -49,6 +49,10 @@
 	};
 };
 
+&usb3 {
+	qcom,usbin-vadc = <&pm8941_vadc>;
+};
+
 /* GPU overrides */
 &msm_gpu {
 	/* Updated chip ID */
@@ -122,7 +126,7 @@
 	qcom,dec-ocmem-ab-ib = <0 0>,
 		<176000 519000>,
 		<456000 519000>,
-		<864000 519000>,
+		<864000 629000>,
 		<1728000 1038000>,
 		<2766000 1661000>,
 		<3456000 2076000>,
@@ -194,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 a912da8..63a37f5 100644
--- a/arch/arm/boot/dts/msm8974.dtsi
+++ b/arch/arm/boot/dts/msm8974.dtsi
@@ -215,7 +215,7 @@
 		vdd-supply = <&gdsc_venus>;
 		qcom,hfi = "venus";
 		qcom,has-ocmem;
-		qcom,max-hw-load = <1224450>; /* 4k @ 30 + 1080p @ 30*/
+		qcom,max-hw-load = <1216800>; /* 3840 x 2160 @ 30 + 1080p @ 30*/
 	};
 
 	qcom,vidc {
@@ -335,7 +335,7 @@
 		qcom,bus-speed-mode = "HS200_1p8v", "DDR_1p8v";
 
 		qcom,msm-bus,name = "sdcc1";
-		qcom,msm-bus,num-cases = <8>;
+		qcom,msm-bus,num-cases = <9>;
 		qcom,msm-bus,num-paths = <1>;
 		qcom,msm-bus,vectors-KBps = <78 512 0 0>, /* No vote */
 				<78 512 1600 3200>,    /* 400 KB/s*/
@@ -344,8 +344,11 @@
 				<78 512 200000 400000>, /* 50 MB/s */
 				<78 512 400000 800000>, /* 100 MB/s */
 				<78 512 800000 1600000>, /* 200 MB/s */
+				<78 512 800000 1600000>, /* 400 MB/s */
 				<78 512 2048000 4096000>; /* Max. bandwidth */
-		qcom,bus-bw-vectors-bps = <0 400000 20000000 25000000 50000000 100000000 200000000 4294967295>;
+		qcom,bus-bw-vectors-bps = <0 400000 20000000 25000000 50000000
+						100000000 200000000 400000000
+						4294967295>;
 		qcom,dat1-mpm-int = <42>;
 		status = "disable";
 	};
@@ -498,7 +501,7 @@
 		qcom,cpu-dma-latency-us = <200>;
 
 		qcom,msm-bus,name = "sdhc1";
-		qcom,msm-bus,num-cases = <8>;
+		qcom,msm-bus,num-cases = <9>;
 		qcom,msm-bus,num-paths = <1>;
 		qcom,msm-bus,vectors-KBps = <78 512 0 0>, /* No vote */
 				<78 512 1600 3200>,    /* 400 KB/s*/
@@ -507,8 +510,12 @@
 				<78 512 200000 400000>, /* 50 MB/s */
 				<78 512 400000 800000>, /* 100 MB/s */
 				<78 512 800000 1600000>, /* 200 MB/s */
+				<78 512 800000 1600000>, /* 400 MB/s */
 				<78 512 2048000 4096000>; /* Max. bandwidth */
-		qcom,bus-bw-vectors-bps = <0 400000 20000000 25000000 50000000 100000000 200000000 4294967295>;
+		qcom,bus-bw-vectors-bps = <0 400000 20000000 25000000 50000000
+						100000000 200000000 400000000
+						4294967295>;
+		qcom,dat1-mpm-int = <42>;
 		status = "disable";
 	};
 
@@ -535,6 +542,7 @@
 				<81 512 800000 1600000>, /* 200 MB/s */
 				<81 512 2048000 4096000>; /* Max. bandwidth */
 		qcom,bus-bw-vectors-bps = <0 400000 20000000 25000000 50000000 100000000 200000000 4294967295>;
+		qcom,dat1-mpm-int = <44>;
 		status = "disable";
 	};
 
@@ -542,8 +550,17 @@
 		compatible = "qcom,sdhci-msm";
 		reg = <0xf9864900 0x11c>, <0xf9864000 0x800>;
 		reg-names = "hc_mem", "core_mem";
-		interrupts = <0 127 0>, <0 224 0>;
-		interrupt-names = "hc_irq", "pwr_irq";
+
+		#address-cells = <0>;
+		interrupt-parent = <&sdhc_3>;
+		interrupts = <0 1 2>;
+		#interrupt-cells = <1>;
+		interrupt-map-mask = <0xffffffff>;
+		interrupt-map = <0 &intc 0 127 0
+				1 &intc 0 224 0
+				2 &msmgpio 37 0x8>;
+		interrupt-names = "hc_irq", "pwr_irq", "sdiowakeup_irq";
+
 		gpios = <&msmgpio 40 0>, /* CLK */
 			<&msmgpio 39 0>, /* CMD */
 			<&msmgpio 38 0>, /* DATA0 */
@@ -575,8 +592,17 @@
 		compatible = "qcom,sdhci-msm";
 		reg = <0xf98e4900 0x11c>, <0xf98e4000 0x800>;
 		reg-names = "hc_mem", "core_mem";
-		interrupts = <0 129 0>, <0 227 0>;
-		interrupt-names = "hc_irq", "pwr_irq";
+
+		#address-cells = <0>;
+		interrupt-parent = <&sdhc_4>;
+		interrupts = <0 1 2>;
+		#interrupt-cells = <1>;
+		interrupt-map-mask = <0xffffffff>;
+		interrupt-map = <0 &intc 0 129 0
+				1 &intc 0 227 0
+				2 &msmgpio 95 0x8>;
+		interrupt-names = "hc_irq", "pwr_irq", "sdiowakeup_irq";
+
 		gpios = <&msmgpio 93 0>, /* CLK */
 			<&msmgpio 91 0>, /* CMD */
 			<&msmgpio 96 0>, /* DATA0 */
@@ -745,7 +771,7 @@
 			qcom,cdc-micbias-ldoh-v = <0x3>;
 			qcom,cdc-micbias-cfilt1-mv = <1800>;
 			qcom,cdc-micbias-cfilt2-mv = <2700>;
-			qcom,cdc-micbias-cfilt3-mv = <1800>;
+			qcom,cdc-micbias-cfilt3-mv = <2700>;
 			qcom,cdc-micbias1-cfilt-sel = <0x0>;
 			qcom,cdc-micbias2-cfilt-sel = <0x1>;
 			qcom,cdc-micbias3-cfilt-sel = <0x2>;
@@ -911,7 +937,8 @@
 		hfpll-dig-supply = <&pm8841_s2_corner_ao>;
 		hfpll-analog-supply = <&pm8941_l12_ao>;
 		qcom,hfpll-config-val = <0x04D0405D>;
-                qcom,hfpll-user-vco-mask = <0x00100000>;
+		qcom,hfpll-user-vco-mask = <0x00100000>;
+		qcom,pvs-config-ver = <1>;
 
 		qcom,l2-fmax =
 			<          0 0			 >,
@@ -1515,25 +1542,47 @@
 			< 2265600000  925000 691 >;
 	};
 
+	qcom,cpubw {
+		compatible = "qcom,cpubw";
+		qcom,cpu-mem-ports = <1 512>, <2 512>;
+		qcom,bw-tbl =
+			<  381 /*  50 MHz */ >,
+			<  572 /*  75 MHz */ >,
+			<  762 /* 100 MHz */ >,
+			< 1144 /* 150 MHz */ >,
+			< 1525 /* 200 MHz */ >,
+			< 2342 /* 307 MHz */ >,
+			< 3509 /* 460 MHz */ >,
+			< 4684 /* 614 MHz */ >,
+			< 6103 /* 800 MHz */ >,
+			< 7102 /* 931 MHz */ >;
+	};
+
+	qcom,kraitbw-l2pm {
+		compatible = "qcom,kraitbw-l2pm";
+		interrupts = <0 1 1>;
+		qcom,bytes-per-beat = <8>;
+	};
+
 	qcom,msm-cpufreq@0 {
 		reg = <0 4>;
 		compatible = "qcom,msm-cpufreq";
-		qcom,cpu-mem-ports = <1 512>, <2 512>;
 		qcom,cpufreq-table =
-			<  300000  300000  600 /*  75 MHz */ >,
-			<  422400  422400 1200 /* 150 MHz */ >,
-			<  652800  499200 1600 /* 200 MHz */ >,
-			<  729600  576000 2456 /* 307 MHz */ >,
-			<  883200  576000 2456 /* 307 MHz */ >,
-			<  960000  960000 3680 /* 460 MHz */ >,
-			< 1036800 1036800 3680 /* 460 MHz */ >,
-			< 1190400 1036800 3680 /* 460 MHz */ >,
-			< 1267200 1267200 4912 /* 614 MHz */ >,
-			< 1497600 1497600 4912 /* 614 MHz */ >,
-			< 1574400 1574400 6400 /* 800 MHz */ >,
-			< 1728000 1651200 6400 /* 800 MHz */ >,
-			< 1958400 1728000 7448 /* 931 MHz */ >,
-			< 2265600 1728000 7448 /* 931 MHz */ >;
+			<  300000  300000  572 >,
+			<  422400  422400 1144 >,
+			<  652800  499200 1525 >,
+			<  729600  576000 2342 >,
+			<  883200  576000 2342 >,
+			<  960000  960000 3509 >,
+			< 1036800 1036800 3509 >,
+			< 1190400 1036800 3509 >,
+			< 1267200 1267200 4684 >,
+			< 1497600 1497600 4684 >,
+			< 1574400 1574400 6103 >,
+			< 1728000 1651200 6103 >,
+			< 1958400 1728000 7102 >,
+			< 2265600 1728000 7102 >,
+			< 2457600 1728000 7102 >;
 	};
 
 	usb3: qcom,ssusb@f9200000 {
@@ -1800,6 +1849,11 @@
 			compatible = "qcom,msm-dai-q6-dev";
 			qcom,msm-dai-q6-dev-id = <32773>;
 		};
+
+		qcom,msm-dai-q6-incall-music-2-rx {
+			compatible = "qcom,msm-dai-q6-dev";
+			qcom,msm-dai-q6-dev-id = <32770>;
+		};
 	};
 
 	qcom,msm-pri-auxpcm {
@@ -1980,8 +2034,8 @@
 		qcom,msm-bus,num-cases = <2>;
 		qcom,msm-bus,num-paths = <1>;
 		qcom,msm-bus,vectors-KBps =
-				<1 618 0 0>,
-				<1 618 0 800>;
+				<88 618 0 0>,
+				<88 618 0 800>;
         };
 
 	qseecom: qcom,qseecom@7b00000 {
@@ -1989,12 +2043,15 @@
 		reg = <0x7b00000 0x500000>;
 		reg-names = "secapp-region";
 		qcom,disk-encrypt-pipe-pair = <2>;
+		qcom,file-encrypt-pipe-pair = <0>;
 		qcom,hlos-ce-hw-instance = <1>;
 		qcom,qsee-ce-hw-instance = <0>;
-		qcom,support-bus-scaling = <1>;
+		qcom,support-bus-scaling;
 		qcom,msm-bus,name = "qseecom-noc";
 		qcom,msm-bus,num-cases = <4>;
 		qcom,msm-bus,num-paths = <1>;
+		qcom,support-fde;
+		qcom,support-pfe;
 		qcom,msm-bus,vectors-KBps =
 				<55 512 0 0>,
 				<55 512 0 0>,
@@ -2091,11 +2148,12 @@
         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>;
 		qcom,ce-hw-instance = <1>;
+		qcom,ce-device = <0>;
                 qcom,msm-bus,name = "qcedev-noc";
 		qcom,msm-bus,num-cases = <2>;
 		qcom,msm-bus,num-paths = <1>;
@@ -2104,17 +2162,43 @@
 				<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>;
 		qcom,ce-hw-instance = <1>;
+		qcom,ce-device = <0>;
+		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,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>;
@@ -2326,6 +2410,22 @@
 		compatible = "qcom,bcl";
 	};
 
+	i2c@f9928000 { /* BLSP-1 QUP-6 */
+		cell-index = <3>;
+		compatible = "qcom,i2c-qup";
+		reg = <0xf9928000 0x1000>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		reg-names = "qup_phys_addr";
+		interrupts = <0 100 0>;
+		interrupt-names = "qup_err_intr";
+		qcom,i2c-bus-freq = <400000>;
+		qcom,i2c-src-freq = <19200000>;
+		qcom,scl-gpio = <&msmgpio 30 0>;
+		qcom,sda-gpio = <&msmgpio 29 0>;
+		qcom,master-id = <86>;
+	};
+
 	qcom,ssm {
 		compatible = "qcom,ssm";
 		qcom,channel-name = "SSM_RTR";
@@ -2354,6 +2454,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 b6a6fcb..b9f2574 100644
--- a/arch/arm/boot/dts/msm8974pro-ab-pm8941-cdp.dts
+++ b/arch/arm/boot/dts/msm8974pro-ab-pm8941-cdp.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
@@ -20,3 +20,13 @@
 	compatible = "qcom,msm8974-cdp", "qcom,msm8974", "qcom,cdp";
 	qcom,board-id = <1 0>;
 };
+
+&sdhc_1 {
+	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
new file mode 100644
index 0000000..feefded
--- /dev/null
+++ b/arch/arm/boot/dts/msm8974pro-ab-pm8941-fluid-hbtp.dts
@@ -0,0 +1,52 @@
+/* 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.
+ */
+
+/dts-v1/;
+
+/include/ "msm8974pro-ab-pm8941.dtsi"
+/include/ "msm8974-fluid.dtsi"
+/include/ "dsi-panel-jdi-720p-cmd.dtsi"
+
+/ {
+	model = "Qualcomm MSM 8974Pro-AA/AB FLUID";
+	compatible = "qcom,msm8974-fluid", "qcom,msm8974", "qcom,fluid";
+	qcom,board-id = <3 1>;
+};
+
+&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";
+	};
+
+	hbtp {
+		compatible = "qcom,hbtp";
+		vcc_ana-supply = <&pm8941_l18>;
+	};
+};
+
+&i2c_0 {
+	/* mhl-sii8334 is on i2c_0 and uses gpio 12 as mhl-pwr-gpio.
+	 * Display panel needs gpio 12 as TE gpio in command mode.
+	 * Disabling the bus to make sure that display gets the gpio.
+	 */
+	status = "disabled";
+};
+
+&sdhc_1 {
+	qcom,pad-pull-on = <0x0 0x3 0x3 0x1>; /* no-pull, pull-up, pull-up, pull-down */
+	qcom,pad-pull-off = <0x0 0x3 0x3 0x1>; /* no-pull, pull-up, pull-up, pull-down */
+};
diff --git a/arch/arm/boot/dts/msm8974pro-ab-pm8941-fluid.dts b/arch/arm/boot/dts/msm8974pro-ab-pm8941-fluid.dts
index be298d1..010a4ad 100644
--- a/arch/arm/boot/dts/msm8974pro-ab-pm8941-fluid.dts
+++ b/arch/arm/boot/dts/msm8974pro-ab-pm8941-fluid.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
@@ -20,3 +20,8 @@
 	compatible = "qcom,msm8974-fluid", "qcom,msm8974", "qcom,fluid";
 	qcom,board-id = <3 0>;
 };
+
+&sdhc_1 {
+	qcom,pad-pull-on = <0x0 0x3 0x3 0x1>; /* no-pull, pull-up, pull-up, pull-down */
+	qcom,pad-pull-off = <0x0 0x3 0x3 0x1>; /* no-pull, pull-up, pull-up, pull-down */
+};
diff --git a/arch/arm/boot/dts/msm8974pro-ab-pm8941-liquid.dts b/arch/arm/boot/dts/msm8974pro-ab-pm8941-liquid.dts
index 49c3df0..0192f56 100644
--- a/arch/arm/boot/dts/msm8974pro-ab-pm8941-liquid.dts
+++ b/arch/arm/boot/dts/msm8974pro-ab-pm8941-liquid.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
@@ -20,3 +20,8 @@
 	compatible = "qcom,msm8974-liquid", "qcom,msm8974", "qcom,liquid";
 	qcom,board-id = <9 0>;
 };
+
+&sdhc_1 {
+	qcom,pad-pull-on = <0x0 0x3 0x3 0x1>; /* no-pull, pull-up, pull-up, pull-down */
+	qcom,pad-pull-off = <0x0 0x3 0x3 0x1>; /* no-pull, pull-up, pull-up, pull-down */
+};
diff --git a/arch/arm/boot/dts/msm8974pro-ab-pm8941-mtp.dts b/arch/arm/boot/dts/msm8974pro-ab-pm8941-mtp.dts
index 6b62391..99c4ec7 100644
--- a/arch/arm/boot/dts/msm8974pro-ab-pm8941-mtp.dts
+++ b/arch/arm/boot/dts/msm8974pro-ab-pm8941-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,5 +22,14 @@
 };
 
 &sdhc_1 {
-	qcom,pad-drv-on = <0x7 0x4 0x4>; /* 16mA, 10mA, 10mA */
+	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 */
+	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-cdp.dts b/arch/arm/boot/dts/msm8974pro-ac-pm8941-cdp.dts
index 3e0feda..08ef393 100644
--- a/arch/arm/boot/dts/msm8974pro-ac-pm8941-cdp.dts
+++ b/arch/arm/boot/dts/msm8974pro-ac-pm8941-cdp.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
@@ -20,3 +20,8 @@
 	compatible = "qcom,msm8974-cdp", "qcom,msm8974", "qcom,cdp";
 	qcom,board-id = <1 0>;
 };
+
+&sdhc_1 {
+	qcom,pad-pull-on = <0x0 0x3 0x3 0x1>; /* no-pull, pull-up, pull-up, pull-down */
+	qcom,pad-pull-off = <0x0 0x3 0x3 0x1>; /* no-pull, pull-up, pull-up, pull-down */
+};
diff --git a/arch/arm/boot/dts/msm8974pro-ac-pm8941-liquid.dts b/arch/arm/boot/dts/msm8974pro-ac-pm8941-liquid.dts
index 7b88abe..8118e48 100644
--- a/arch/arm/boot/dts/msm8974pro-ac-pm8941-liquid.dts
+++ b/arch/arm/boot/dts/msm8974pro-ac-pm8941-liquid.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
@@ -20,3 +20,8 @@
 	compatible = "qcom,msm8974-liquid", "qcom,msm8974", "qcom,liquid";
 	qcom,board-id = <9 0>;
 };
+
+&sdhc_1 {
+	qcom,pad-pull-on = <0x0 0x3 0x3 0x1>; /* no-pull, pull-up, pull-up, pull-down */
+	qcom,pad-pull-off = <0x0 0x3 0x3 0x1>; /* no-pull, pull-up, pull-up, pull-down */
+};
diff --git a/arch/arm/boot/dts/msm8974pro-ac-pm8941-mtp.dts b/arch/arm/boot/dts/msm8974pro-ac-pm8941-mtp.dts
index f79d361..a25b8ca 100644
--- a/arch/arm/boot/dts/msm8974pro-ac-pm8941-mtp.dts
+++ b/arch/arm/boot/dts/msm8974pro-ac-pm8941-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,9 +22,11 @@
 };
 
 &sdhc_1 {
-	qcom,clk-rates = <400000 20000000 25000000 50000000 100000000 192000000 384000000>;
-	qcom,bus-speed-mode = "HS400_1p8v", "HS200_1p8v", "DDR_1p8v";
-
 	qcom,pad-pull-on = <0x0 0x3 0x3 0x1>; /* no-pull, pull-up, pull-up, pull-down */
 	qcom,pad-pull-off = <0x0 0x3 0x3 0x1>; /* no-pull, pull-up, pull-up, pull-down */
 };
+
+&ehci {
+	status = "ok";
+	qcom,usb2-enable-uicc;
+};
diff --git a/arch/arm/boot/dts/msm8974pro-ac-pm8941.dtsi b/arch/arm/boot/dts/msm8974pro-ac-pm8941.dtsi
index cdcfecb..694049a 100644
--- a/arch/arm/boot/dts/msm8974pro-ac-pm8941.dtsi
+++ b/arch/arm/boot/dts/msm8974pro-ac-pm8941.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
@@ -18,7 +18,3 @@
 		      <213 0x10000>,
 		      <216 0x10000>;
 };
-
-&sdhc_1 {
-	reg = <0xf9824900 0x1a0>, <0xf9824000 0x800>;
-};
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 dc438bb..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 {
@@ -102,6 +150,8 @@
 	vbus_dwc3-supply = <&pm8941_mvs1>;
 	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>;
@@ -239,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 {
@@ -253,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-ac-pma8084.dtsi b/arch/arm/boot/dts/msm8974pro-ac-pma8084.dtsi
index 4b7ed1d..46fae99 100644
--- a/arch/arm/boot/dts/msm8974pro-ac-pma8084.dtsi
+++ b/arch/arm/boot/dts/msm8974pro-ac-pma8084.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
@@ -18,7 +18,3 @@
 		      <213 0x10000>,
 		      <216 0x10000>;
 };
-
-&sdhc_1 {
-	reg = <0xf9824900 0x1a0>, <0xf9824000 0x800>;
-};
diff --git a/arch/arm/boot/dts/msm8974pro-pm.dtsi b/arch/arm/boot/dts/msm8974pro-pm.dtsi
index 63cb68b..0307e2a 100644
--- a/arch/arm/boot/dts/msm8974pro-pm.dtsi
+++ b/arch/arm/boot/dts/msm8974pro-pm.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
@@ -120,13 +120,13 @@
 		qcom,phase-port = <0x1>;
 		qcom,pfm-port = <0x2>;
 		qcom,saw2-spm-cmd-ret = [1f 00 03 00 0f];
-		qcom,saw2-spm-cmd-gdhs = [00 32 42 07 44 50 02 32 50 0f];
+		qcom,saw2-spm-cmd-gdhs = [00 32 42 03 44 50 02 32 50 0f];
 		qcom,saw2-spm-cmd-pc = [00 10 32 b0 11 42 07 01 b0 12 44
 				50 02 32 50 0f];
 		qcom,L2-spm-is-apcs-master;
 	};
 
-	qcom,lpm-levels {
+	lpm_levels: qcom,lpm-levels {
 		compatible = "qcom,lpm-levels";
 		qcom,allow-synced-levels;
 		qcom,default-l2-state = "l2_cache_retention";
@@ -174,11 +174,11 @@
 
 			qcom,system-mode@0 {
 				qcom,l2 = "l2_cache_gdhs";
-				qcom,latency-us = <20000>;
+				qcom,latency-us = <500>;
 				qcom,ss-power = <163>;
-				qcom,energy-overhead = <1577736>;
-				qcom,time-overhead = <5067>;
-				qcom,min-cpu-mode= "pc";
+				qcom,energy-overhead = <577736>;
+				qcom,time-overhead = <1000>;
+				qcom,min-cpu-mode= "standalone_pc";
 				qcom,sync-cpus;
 			};
 
@@ -190,6 +190,7 @@
 				qcom,time-overhead = <6605>;
 				qcom,min-cpu-mode = "pc";
 				qcom,sync-cpus;
+				qcom,send-rpm-sleep-set;
 			};
 		};
 	};
@@ -217,7 +218,7 @@
 			<0xff 18>,  /* APCx_qgicQTmrSecPhysIrptReq */
 			<0xff 19>,  /* APCx_qgicQTmrSecPhysIrptReq */
 			<0xff 25>,  /* APCx_qgicExtFaultIrptReq */
-			<0xff 33>, /*l2_perf_mon*/
+			<0xff 33>,  /* APCC_qgicL2PerfMonIrptReq */
 			<0xff 34>,  /* APCC_qgicL2ErrorIrptReq */
 			<0xff 35>,  /* WDT_barkInt */
 			<0xff 40>,  /* qtimer_phy_irq */
@@ -241,6 +242,7 @@
 			<0xff 109>,  /* ocmem_dm_nonsec_irq */
 			<0xff 126>,  /* bam_irq[0] */
 			<0xff 140>,  /* uart_dm_intr */
+			<0xff 146>,  /* uart_dm_intr: blsp2_uart_2_irq */
 			<0xff 155>,  /* sdcc_irq[0] */
 			<0xff 157>,  /* sdcc_irq[0] */
 			<0xff 159>,  /* sdcc_irq[0] */
@@ -332,6 +334,7 @@
 		reg = <0xfe805664 0x40>;
 		qcom,pc-mode = "tz_l2_int";
 		qcom,cpus-as-clocks;
+		qcom,lpm-levels = <&lpm_levels>;
 
 		qcom,pm-snoc-client {
 			compatible = "qcom,pm-snoc-client";
@@ -375,4 +378,12 @@
 		reg = <0xfc000000 0x1a0000>;
 		qcom,start-offset = <0x190010>;
 	};
+
+	qcom,rpm-master-stats@fc428150 {
+		compatible = "qcom,rpm-master-stats";
+		reg = <0xfc428150 0x3200>;
+		qcom,masters = "APSS", "MPSS", "LPSS", "PRONTO";
+		qcom,master-stats-version = <2>;
+		qcom,master-offset = <2560>;
+	};
 };
diff --git a/arch/arm/boot/dts/msm8974pro-pm8941.dtsi b/arch/arm/boot/dts/msm8974pro-pm8941.dtsi
index 2783ffd..b502078 100644
--- a/arch/arm/boot/dts/msm8974pro-pm8941.dtsi
+++ b/arch/arm/boot/dts/msm8974pro-pm8941.dtsi
@@ -34,26 +34,28 @@
 
 &krait_pdn {
 	qcom,use-phase-switching;
+        qcom,valid-scaling-factor-versions = <0 1 1 0>;
+
 };
 
 &krait0_vreg {
 		regulator-max-microvolt = <1120000>;
-		qcom,ldo-delta-voltage = <25000>;
+		qcom,ldo-delta-voltage = <12500>;
 };
 
 &krait1_vreg {
 		regulator-max-microvolt = <1120000>;
-		qcom,ldo-delta-voltage = <25000>;
+		qcom,ldo-delta-voltage = <12500>;
 };
 
 &krait2_vreg {
 		regulator-max-microvolt = <1120000>;
-		qcom,ldo-delta-voltage = <25000>;
+		qcom,ldo-delta-voltage = <12500>;
 };
 
 &krait3_vreg {
 		regulator-max-microvolt = <1120000>;
-		qcom,ldo-delta-voltage = <25000>;
+		qcom,ldo-delta-voltage = <12500>;
 };
 
 &tspp {
@@ -64,6 +66,16 @@
 	qcom,init-smps-mode = <0>;	/* Allow AUTO mode for VDD_CX. */
 };
 
+&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 {
 	status = "ok";
 
diff --git a/arch/arm/boot/dts/msm8974pro-pma8084-mtp.dtsi b/arch/arm/boot/dts/msm8974pro-pma8084-mtp.dtsi
old mode 100755
new mode 100644
index a22d806..12ed7d4
--- a/arch/arm/boot/dts/msm8974pro-pma8084-mtp.dtsi
+++ b/arch/arm/boot/dts/msm8974pro-pma8084-mtp.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
@@ -42,6 +42,37 @@
 		cam_vana-supply = <&pma8084_l17>;
 		cam_vio-supply = <&pma8084_lvs4>;
 	};
+
+
+	qcom,camera@0 {
+		qcom,vdd-cx-supply = <&pma8084_s2>;
+		cam_vdig-supply = <&pma8084_l3>;
+		cam_vana-supply = <&pma8084_l17>;
+		cam_vio-supply = <&pma8084_lvs4>;
+		cam_vaf-supply = <&pma8084_l23>;
+	};
+
+	qcom,camera@1 {
+		qcom,vdd-cx-supply = <&pma8084_s2>;
+		cam_vdig-supply = <&pma8084_l3>;
+		cam_vana-supply = <&pma8084_l17>;
+		cam_vio-supply = <&pma8084_lvs4>;
+		cam_vaf-supply = <&pma8084_l23>;
+	};
+
+	qcom,camera@2 {
+		qcom,vdd-cx-supply = <&pma8084_s2>;
+		cam_vdig-supply = <&pma8084_l3>;
+		cam_vana-supply = <&pma8084_l17>;
+		cam_vio-supply = <&pma8084_lvs4>;
+	};
+
+	qcom,camera@3 {
+		qcom,vdd-cx-supply = <&pma8084_s2>;
+		cam_vdig-supply = <&pma8084_l3>;
+		cam_vana-supply = <&pma8084_l17>;
+		cam_vio-supply = <&pma8084_lvs4>;
+	};
 };
 
 &soc {
@@ -106,9 +137,6 @@
 	vdd-supply = <&pma8084_l20>;
 	vdd-io-supply = <&pma8084_s4>;
 
-	qcom,clk-rates = <400000 20000000 25000000 50000000 100000000 192000000 384000000>;
-	qcom,bus-speed-mode = "HS400_1p8v", "HS200_1p8v", "DDR_1p8v";
-
 	qcom,pad-pull-on = <0x0 0x3 0x3 0x1>; /* no-pull, pull-up, pull-up, pull-down */
 	qcom,pad-pull-off = <0x0 0x3 0x3 0x1>; /* no-pull, pull-up, pull-up, pull-down */
 };
@@ -172,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-regulator.dtsi b/arch/arm/boot/dts/msm8974pro-pma8084-regulator.dtsi
index 00e3b8b..49bf4ea 100644
--- a/arch/arm/boot/dts/msm8974pro-pma8084-regulator.dtsi
+++ b/arch/arm/boot/dts/msm8974pro-pma8084-regulator.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
@@ -267,7 +267,7 @@
 	rpm-regulator-ldoa11 {
 		status = "okay";
 		pma8084_l11: regulator-l11 {
-			regulator-min-microvolt = <1300000>;
+			regulator-min-microvolt = <1225000>;
 			regulator-max-microvolt = <1300000>;
 			qcom,init-voltage = <1300000>;
 			status = "okay";
@@ -481,6 +481,8 @@
 		ranges;
 		qcom,pfm-threshold = <76>;
 		qcom,use-phase-scaling-factor;
+		qcom,phase-scaling-factor-bits-pos = <16>;
+		qcom,valid-scaling-factor-versions = <0 1 1 0>;
 
 		krait0_vreg: regulator@f9088000 {
 			compatible = "qcom,krait-regulator";
@@ -494,7 +496,7 @@
 			qcom,retention-voltage = <675000>;
 			qcom,ldo-default-voltage = <750000>;
 			qcom,ldo-threshold-voltage = <850000>;
-			qcom,ldo-delta-voltage = <25000>;
+			qcom,ldo-delta-voltage = <12500>;
 			qcom,cpu-num = <0>;
 		};
 
@@ -510,7 +512,7 @@
 			qcom,retention-voltage = <675000>;
 			qcom,ldo-default-voltage = <750000>;
 			qcom,ldo-threshold-voltage = <850000>;
-			qcom,ldo-delta-voltage = <25000>;
+			qcom,ldo-delta-voltage = <12500>;
 			qcom,cpu-num = <1>;
 		};
 
@@ -526,7 +528,7 @@
 			qcom,retention-voltage = <675000>;
 			qcom,ldo-default-voltage = <750000>;
 			qcom,ldo-threshold-voltage = <850000>;
-			qcom,ldo-delta-voltage = <25000>;
+			qcom,ldo-delta-voltage = <12500>;
 			qcom,cpu-num = <2>;
 		};
 
@@ -542,7 +544,7 @@
 			qcom,retention-voltage = <675000>;
 			qcom,ldo-default-voltage = <750000>;
 			qcom,ldo-threshold-voltage = <850000>;
-			qcom,ldo-delta-voltage = <25000>;
+			qcom,ldo-delta-voltage = <12500>;
 			qcom,cpu-num = <3>;
 		};
 	};
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
old mode 100755
new mode 100644
index 41f02fe..d398f72
--- a/arch/arm/boot/dts/msm8974pro.dtsi
+++ b/arch/arm/boot/dts/msm8974pro.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
@@ -699,17 +699,17 @@
 			<  345600000  775000   87 >,
 			<  422400000  775000  108 >,
 			<  499200000  775000  129 >,
-			<  576000000  780000  150 >,
-			<  652800000  790000  171 >,
-			<  729600000  800000  193 >,
-			<  806400000  810000  215 >,
-			<  883200000  820000  237 >,
-			<  960000000  830000  260 >,
-			< 1036800000  840000  282 >,
-			< 1113600000  850000  306 >,
-			< 1190400000  860000  330 >,
-			< 1267200000  870000  354 >,
-			< 1344000000  880000  378 >,
+			<  576000000  785000  150 >,
+			<  652800000  795000  171 >,
+			<  729600000  805000  193 >,
+			<  806400000  815000  215 >,
+			<  883200000  825000  237 >,
+			<  960000000  835000  260 >,
+			< 1036800000  845000  282 >,
+			< 1113600000  855000  306 >,
+			< 1190400000  865000  330 >,
+			< 1267200000  875000  354 >,
+			< 1344000000  885000  378 >,
 			< 1420800000  895000  404 >,
 			< 1497600000  910000  431 >,
 			< 1574400000  925000  458 >,
@@ -730,18 +730,18 @@
 			<  345600000  775000   87 >,
 			<  422400000  775000  108 >,
 			<  499200000  775000  129 >,
-			<  576000000  775000  150 >,
-			<  652800000  780000  171 >,
-			<  729600000  790000  193 >,
-			<  806400000  800000  215 >,
-			<  883200000  810000  237 >,
-			<  960000000  820000  260 >,
-			< 1036800000  830000  282 >,
-			< 1113600000  840000  306 >,
-			< 1190400000  850000  330 >,
-			< 1267200000  860000  354 >,
-			< 1344000000  870000  378 >,
-			< 1420800000  885000  404 >,
+			<  576000000  780000  150 >,
+			<  652800000  790000  171 >,
+			<  729600000  800000  193 >,
+			<  806400000  810000  215 >,
+			<  883200000  820000  237 >,
+			<  960000000  830000  260 >,
+			< 1036800000  840000  282 >,
+			< 1113600000  850000  306 >,
+			< 1190400000  860000  330 >,
+			< 1267200000  870000  354 >,
+			< 1344000000  880000  378 >,
+			< 1420800000  890000  404 >,
 			< 1497600000  900000  431 >,
 			< 1574400000  915000  458 >,
 			< 1651200000  930000  486 >,
@@ -762,17 +762,17 @@
 			<  422400000  775000  108 >,
 			<  499200000  775000  129 >,
 			<  576000000  775000  150 >,
-			<  652800000  775000  171 >,
-			<  729600000  780000  193 >,
-			<  806400000  790000  215 >,
-			<  883200000  800000  237 >,
-			<  960000000  810000  260 >,
-			< 1036800000  820000  282 >,
-			< 1113600000  830000  306 >,
-			< 1190400000  840000  330 >,
-			< 1267200000  850000  354 >,
-			< 1344000000  860000  378 >,
-			< 1420800000  875000  404 >,
+			<  652800000  780000  171 >,
+			<  729600000  790000  193 >,
+			<  806400000  800000  215 >,
+			<  883200000  810000  237 >,
+			<  960000000  820000  260 >,
+			< 1036800000  830000  282 >,
+			< 1113600000  840000  306 >,
+			< 1190400000  850000  330 >,
+			< 1267200000  860000  354 >,
+			< 1344000000  870000  378 >,
+			< 1420800000  880000  404 >,
 			< 1497600000  890000  431 >,
 			< 1574400000  905000  458 >,
 			< 1651200000  920000  486 >,
@@ -794,17 +794,17 @@
 			<  499200000  775000  129 >,
 			<  576000000  775000  150 >,
 			<  652800000  775000  171 >,
-			<  729600000  775000  193 >,
-			<  806400000  780000  215 >,
-			<  883200000  790000  237 >,
-			<  960000000  800000  260 >,
-			< 1036800000  810000  282 >,
-			< 1113600000  820000  306 >,
-			< 1190400000  830000  330 >,
-			< 1267200000  840000  354 >,
-			< 1344000000  850000  378 >,
-			< 1420800000  865000  404 >,
-			< 1497600000  880000  431 >,
+			<  729600000  785000  193 >,
+			<  806400000  795000  215 >,
+			<  883200000  805000  237 >,
+			<  960000000  815000  260 >,
+			< 1036800000  825000  282 >,
+			< 1113600000  835000  306 >,
+			< 1190400000  845000  330 >,
+			< 1267200000  855000  354 >,
+			< 1344000000  865000  378 >,
+			< 1420800000  875000  404 >,
+			< 1497600000  885000  431 >,
 			< 1574400000  895000  458 >,
 			< 1651200000  910000  486 >,
 			< 1728000000  925000  515 >,
@@ -825,18 +825,18 @@
 			<  499200000  775000  129 >,
 			<  576000000  775000  150 >,
 			<  652800000  775000  171 >,
-			<  729600000  775000  193 >,
-			<  806400000  775000  215 >,
-			<  883200000  780000  237 >,
-			<  960000000  790000  260 >,
-			< 1036800000  800000  282 >,
-			< 1113600000  810000  306 >,
-			< 1190400000  820000  330 >,
-			< 1267200000  830000  354 >,
-			< 1344000000  840000  378 >,
-			< 1420800000  855000  404 >,
-			< 1497600000  870000  431 >,
-			< 1574400000  885000  458 >,
+			<  729600000  780000  193 >,
+			<  806400000  790000  215 >,
+			<  883200000  800000  237 >,
+			<  960000000  810000  260 >,
+			< 1036800000  820000  282 >,
+			< 1113600000  830000  306 >,
+			< 1190400000  840000  330 >,
+			< 1267200000  850000  354 >,
+			< 1344000000  860000  378 >,
+			< 1420800000  870000  404 >,
+			< 1497600000  880000  431 >,
+			< 1574400000  890000  458 >,
 			< 1651200000  900000  486 >,
 			< 1728000000  915000  515 >,
 			< 1804800000  930000  543 >,
@@ -857,18 +857,18 @@
 			<  576000000  775000  150 >,
 			<  652800000  775000  171 >,
 			<  729600000  775000  193 >,
-			<  806400000  775000  215 >,
-			<  883200000  775000  237 >,
-			<  960000000  780000  260 >,
-			< 1036800000  790000  282 >,
-			< 1113600000  800000  306 >,
-			< 1190400000  810000  330 >,
-			< 1267200000  820000  354 >,
-			< 1344000000  830000  378 >,
-			< 1420800000  845000  404 >,
-			< 1497600000  860000  431 >,
-			< 1574400000  875000  458 >,
-			< 1651200000  890000  486 >,
+			<  806400000  785000  215 >,
+			<  883200000  795000  237 >,
+			<  960000000  805000  260 >,
+			< 1036800000  815000  282 >,
+			< 1113600000  825000  306 >,
+			< 1190400000  835000  330 >,
+			< 1267200000  845000  354 >,
+			< 1344000000  855000  378 >,
+			< 1420800000  865000  404 >,
+			< 1497600000  875000  431 >,
+			< 1574400000  885000  458 >,
+			< 1651200000  895000  486 >,
 			< 1728000000  905000  515 >,
 			< 1804800000  920000  543 >,
 			< 1881600000  935000  572 >,
@@ -888,19 +888,19 @@
 			<  576000000  775000  150 >,
 			<  652800000  775000  171 >,
 			<  729600000  775000  193 >,
-			<  806400000  775000  215 >,
-			<  883200000  775000  237 >,
-			<  960000000  775000  260 >,
-			< 1036800000  780000  282 >,
-			< 1113600000  790000  306 >,
-			< 1190400000  800000  330 >,
-			< 1267200000  810000  354 >,
-			< 1344000000  820000  378 >,
-			< 1420800000  835000  404 >,
-			< 1497600000  850000  431 >,
-			< 1574400000  865000  458 >,
-			< 1651200000  880000  486 >,
-			< 1728000000  895000  515 >,
+			<  806400000  780000  215 >,
+			<  883200000  790000  237 >,
+			<  960000000  800000  260 >,
+			< 1036800000  810000  282 >,
+			< 1113600000  820000  306 >,
+			< 1190400000  830000  330 >,
+			< 1267200000  840000  354 >,
+			< 1344000000  850000  378 >,
+			< 1420800000  860000  404 >,
+			< 1497600000  870000  431 >,
+			< 1574400000  880000  458 >,
+			< 1651200000  890000  486 >,
+			< 1728000000  900000  515 >,
 			< 1804800000  910000  543 >,
 			< 1881600000  925000  572 >,
 			< 1958400000  940000  604 >,
@@ -920,19 +920,19 @@
 			<  652800000  775000  171 >,
 			<  729600000  775000  193 >,
 			<  806400000  775000  215 >,
-			<  883200000  775000  237 >,
-			<  960000000  775000  260 >,
-			< 1036800000  775000  282 >,
-			< 1113600000  780000  306 >,
-			< 1190400000  790000  330 >,
-			< 1267200000  800000  354 >,
-			< 1344000000  810000  378 >,
-			< 1420800000  825000  404 >,
-			< 1497600000  840000  431 >,
-			< 1574400000  855000  458 >,
-			< 1651200000  870000  486 >,
-			< 1728000000  885000  515 >,
-			< 1804800000  900000  543 >,
+			<  883200000  785000  237 >,
+			<  960000000  795000  260 >,
+			< 1036800000  805000  282 >,
+			< 1113600000  815000  306 >,
+			< 1190400000  825000  330 >,
+			< 1267200000  835000  354 >,
+			< 1344000000  845000  378 >,
+			< 1420800000  855000  404 >,
+			< 1497600000  865000  431 >,
+			< 1574400000  875000  458 >,
+			< 1651200000  885000  486 >,
+			< 1728000000  895000  515 >,
+			< 1804800000  905000  543 >,
 			< 1881600000  915000  572 >,
 			< 1958400000  930000  604 >,
 			< 2035200000  945000  636 >,
@@ -949,22 +949,22 @@
 			<  499200000  750000  129 >,
 			<  576000000  750000  150 >,
 			<  652800000  750000  171 >,
-			<  729600000  750000  193 >,
-			<  806400000  750000  215 >,
-			<  883200000  750000  237 >,
-			<  960000000  750000  260 >,
-			< 1036800000  760000  282 >,
-			< 1113600000  770000  306 >,
-			< 1190400000  780000  330 >,
-			< 1267200000  790000  354 >,
-			< 1344000000  800000  378 >,
-			< 1420800000  815000  404 >,
-			< 1497600000  830000  431 >,
-			< 1574400000  845000  458 >,
-			< 1651200000  860000  486 >,
-			< 1728000000  875000  515 >,
-			< 1804800000  890000  543 >,
-			< 1881600000  905000  572 >,
+			<  729600000  760000  193 >,
+			<  806400000  770000  215 >,
+			<  883200000  780000  237 >,
+			<  960000000  790000  260 >,
+			< 1036800000  800000  282 >,
+			< 1113600000  810000  306 >,
+			< 1190400000  820000  330 >,
+			< 1267200000  830000  354 >,
+			< 1344000000  840000  378 >,
+			< 1420800000  850000  404 >,
+			< 1497600000  860000  431 >,
+			< 1574400000  870000  458 >,
+			< 1651200000  880000  486 >,
+			< 1728000000  890000  515 >,
+			< 1804800000  900000  543 >,
+			< 1881600000  910000  572 >,
 			< 1958400000  920000  604 >,
 			< 2035200000  935000  636 >,
 			< 2112000000  950000  669 >,
@@ -980,23 +980,23 @@
 			<  499200000  750000  129 >,
 			<  576000000  750000  150 >,
 			<  652800000  750000  171 >,
-			<  729600000  750000  193 >,
-			<  806400000  750000  215 >,
-			<  883200000  750000  237 >,
-			<  960000000  750000  260 >,
-			< 1036800000  750000  282 >,
-			< 1113600000  760000  306 >,
-			< 1190400000  770000  330 >,
-			< 1267200000  780000  354 >,
-			< 1344000000  790000  378 >,
-			< 1420800000  805000  404 >,
-			< 1497600000  820000  431 >,
-			< 1574400000  835000  458 >,
-			< 1651200000  850000  486 >,
-			< 1728000000  865000  515 >,
-			< 1804800000  880000  543 >,
-			< 1881600000  895000  572 >,
-			< 1958400000  910000  604 >,
+			<  729600000  755000  193 >,
+			<  806400000  765000  215 >,
+			<  883200000  775000  237 >,
+			<  960000000  785000  260 >,
+			< 1036800000  795000  282 >,
+			< 1113600000  805000  306 >,
+			< 1190400000  815000  330 >,
+			< 1267200000  825000  354 >,
+			< 1344000000  835000  378 >,
+			< 1420800000  845000  404 >,
+			< 1497600000  855000  431 >,
+			< 1574400000  865000  458 >,
+			< 1651200000  875000  486 >,
+			< 1728000000  885000  515 >,
+			< 1804800000  895000  543 >,
+			< 1881600000  905000  572 >,
+			< 1958400000  915000  604 >,
 			< 2035200000  925000  636 >,
 			< 2112000000  940000  669 >,
 			< 2150400000  955000  703 >,
@@ -1249,18 +1249,18 @@
 			<  499200000  775000  126 >,
 			<  576000000  775000  147 >,
 			<  652800000  775000  168 >,
-			<  729600000  775000  189 >,
-			<  806400000  780000  211 >,
-			<  883200000  790000  233 >,
-			<  960000000  800000  256 >,
-			< 1036800000  810000  278 >,
-			< 1113600000  820000  301 >,
-			< 1190400000  830000  324 >,
-			< 1267200000  840000  348 >,
-			< 1344000000  850000  372 >,
-			< 1420800000  860000  396 >,
-			< 1497600000  870000  421 >,
-			< 1574400000  880000  446 >,
+			<  729600000  780000  189 >,
+			<  806400000  785000  211 >,
+			<  883200000  795000  233 >,
+			<  960000000  805000  256 >,
+			< 1036800000  815000  278 >,
+			< 1113600000  825000  301 >,
+			< 1190400000  835000  324 >,
+			< 1267200000  845000  348 >,
+			< 1344000000  855000  372 >,
+			< 1420800000  865000  396 >,
+			< 1497600000  875000  421 >,
+			< 1574400000  885000  446 >,
 			< 1651200000  895000  473 >,
 			< 1728000000  910000  501 >,
 			< 1804800000  925000  529 >,
@@ -1284,17 +1284,17 @@
 			<  576000000  775000  147 >,
 			<  652800000  775000  168 >,
 			<  729600000  775000  189 >,
-			<  806400000  775000  211 >,
-			<  883200000  780000  233 >,
-			<  960000000  790000  256 >,
-			< 1036800000  800000  278 >,
-			< 1113600000  810000  301 >,
-			< 1190400000  820000  324 >,
-			< 1267200000  830000  348 >,
-			< 1344000000  840000  372 >,
-			< 1420800000  850000  396 >,
-			< 1497600000  860000  421 >,
-			< 1574400000  870000  446 >,
+			<  806400000  780000  211 >,
+			<  883200000  785000  233 >,
+			<  960000000  795000  256 >,
+			< 1036800000  805000  278 >,
+			< 1113600000  815000  301 >,
+			< 1190400000  825000  324 >,
+			< 1267200000  835000  348 >,
+			< 1344000000  845000  372 >,
+			< 1420800000  855000  396 >,
+			< 1497600000  865000  421 >,
+			< 1574400000  875000  446 >,
 			< 1651200000  885000  473 >,
 			< 1728000000  900000  501 >,
 			< 1804800000  915000  529 >,
@@ -1319,17 +1319,17 @@
 			<  652800000  775000  168 >,
 			<  729600000  775000  189 >,
 			<  806400000  775000  211 >,
-			<  883200000  775000  233 >,
-			<  960000000  780000  256 >,
-			< 1036800000  790000  278 >,
-			< 1113600000  800000  301 >,
-			< 1190400000  810000  324 >,
-			< 1267200000  820000  348 >,
-			< 1344000000  830000  372 >,
-			< 1420800000  840000  396 >,
-			< 1497600000  850000  421 >,
-			< 1574400000  860000  446 >,
-			< 1651200000  875000  473 >,
+			<  883200000  780000  233 >,
+			<  960000000  790000  256 >,
+			< 1036800000  800000  278 >,
+			< 1113600000  810000  301 >,
+			< 1190400000  820000  324 >,
+			< 1267200000  830000  348 >,
+			< 1344000000  840000  372 >,
+			< 1420800000  850000  396 >,
+			< 1497600000  860000  421 >,
+			< 1574400000  870000  446 >,
+			< 1651200000  880000  473 >,
 			< 1728000000  890000  501 >,
 			< 1804800000  905000  529 >,
 			< 1881600000  920000  558 >,
@@ -1353,18 +1353,18 @@
 			<  652800000  775000  168 >,
 			<  729600000  775000  189 >,
 			<  806400000  775000  211 >,
-			<  883200000  775000  233 >,
-			<  960000000  775000  256 >,
-			< 1036800000  780000  278 >,
-			< 1113600000  790000  301 >,
-			< 1190400000  800000  324 >,
-			< 1267200000  810000  348 >,
-			< 1344000000  820000  372 >,
-			< 1420800000  830000  396 >,
-			< 1497600000  840000  421 >,
-			< 1574400000  850000  446 >,
-			< 1651200000  865000  473 >,
-			< 1728000000  880000  501 >,
+			<  883200000  780000  233 >,
+			<  960000000  785000  256 >,
+			< 1036800000  795000  278 >,
+			< 1113600000  805000  301 >,
+			< 1190400000  815000  324 >,
+			< 1267200000  825000  348 >,
+			< 1344000000  835000  372 >,
+			< 1420800000  845000  396 >,
+			< 1497600000  855000  421 >,
+			< 1574400000  865000  446 >,
+			< 1651200000  875000  473 >,
+			< 1728000000  885000  501 >,
 			< 1804800000  895000  529 >,
 			< 1881600000  910000  558 >,
 			< 1958400000  925000  588 >,
@@ -1388,18 +1388,18 @@
 			<  729600000  775000  189 >,
 			<  806400000  775000  211 >,
 			<  883200000  775000  233 >,
-			<  960000000  775000  256 >,
-			< 1036800000  775000  278 >,
-			< 1113600000  780000  301 >,
-			< 1190400000  790000  324 >,
-			< 1267200000  800000  348 >,
-			< 1344000000  810000  372 >,
-			< 1420800000  820000  396 >,
-			< 1497600000  830000  421 >,
-			< 1574400000  840000  446 >,
-			< 1651200000  855000  473 >,
-			< 1728000000  870000  501 >,
-			< 1804800000  885000  529 >,
+			<  960000000  780000  256 >,
+			< 1036800000  790000  278 >,
+			< 1113600000  800000  301 >,
+			< 1190400000  810000  324 >,
+			< 1267200000  820000  348 >,
+			< 1344000000  830000  372 >,
+			< 1420800000  840000  396 >,
+			< 1497600000  850000  421 >,
+			< 1574400000  860000  446 >,
+			< 1651200000  870000  473 >,
+			< 1728000000  880000  501 >,
+			< 1804800000  890000  529 >,
 			< 1881600000  900000  558 >,
 			< 1958400000  915000  588 >,
 			< 2035200000  930000  617 >,
@@ -1422,19 +1422,19 @@
 			<  729600000  775000  189 >,
 			<  806400000  775000  211 >,
 			<  883200000  775000  233 >,
-			<  960000000  775000  256 >,
-			< 1036800000  775000  278 >,
-			< 1113600000  775000  301 >,
-			< 1190400000  780000  324 >,
-			< 1267200000  790000  348 >,
-			< 1344000000  800000  372 >,
-			< 1420800000  810000  396 >,
-			< 1497600000  820000  421 >,
-			< 1574400000  830000  446 >,
-			< 1651200000  845000  473 >,
-			< 1728000000  860000  501 >,
-			< 1804800000  875000  529 >,
-			< 1881600000  890000  558 >,
+			<  960000000  780000  256 >,
+			< 1036800000  785000  278 >,
+			< 1113600000  795000  301 >,
+			< 1190400000  805000  324 >,
+			< 1267200000  815000  348 >,
+			< 1344000000  825000  372 >,
+			< 1420800000  835000  396 >,
+			< 1497600000  845000  421 >,
+			< 1574400000  855000  446 >,
+			< 1651200000  865000  473 >,
+			< 1728000000  875000  501 >,
+			< 1804800000  885000  529 >,
+			< 1881600000  895000  558 >,
 			< 1958400000  905000  588 >,
 			< 2035200000  920000  617 >,
 			< 2112000000  935000  649 >,
@@ -1457,19 +1457,19 @@
 			<  806400000  775000  211 >,
 			<  883200000  775000  233 >,
 			<  960000000  775000  256 >,
-			< 1036800000  775000  278 >,
-			< 1113600000  775000  301 >,
-			< 1190400000  775000  324 >,
-			< 1267200000  780000  348 >,
-			< 1344000000  790000  372 >,
-			< 1420800000  800000  396 >,
-			< 1497600000  810000  421 >,
-			< 1574400000  820000  446 >,
-			< 1651200000  835000  473 >,
-			< 1728000000  850000  501 >,
-			< 1804800000  865000  529 >,
-			< 1881600000  880000  558 >,
-			< 1958400000  895000  588 >,
+			< 1036800000  780000  278 >,
+			< 1113600000  790000  301 >,
+			< 1190400000  800000  324 >,
+			< 1267200000  810000  348 >,
+			< 1344000000  820000  372 >,
+			< 1420800000  830000  396 >,
+			< 1497600000  840000  421 >,
+			< 1574400000  850000  446 >,
+			< 1651200000  860000  473 >,
+			< 1728000000  870000  501 >,
+			< 1804800000  880000  529 >,
+			< 1881600000  890000  558 >,
+			< 1958400000  900000  588 >,
 			< 2035200000  910000  617 >,
 			< 2112000000  925000  649 >,
 			< 2150400000  940000  682 >,
@@ -1489,22 +1489,22 @@
 			<  652800000  750000  168 >,
 			<  729600000  750000  189 >,
 			<  806400000  750000  211 >,
-			<  883200000  750000  233 >,
-			<  960000000  750000  256 >,
-			< 1036800000  750000  278 >,
-			< 1113600000  750000  301 >,
-			< 1190400000  760000  324 >,
-			< 1267200000  770000  348 >,
-			< 1344000000  780000  372 >,
-			< 1420800000  790000  396 >,
-			< 1497600000  800000  421 >,
-			< 1574400000  810000  446 >,
-			< 1651200000  825000  473 >,
-			< 1728000000  840000  501 >,
-			< 1804800000  855000  529 >,
-			< 1881600000  870000  558 >,
-			< 1958400000  885000  588 >,
-			< 2035200000  900000  617 >,
+			<  883200000  755000  233 >,
+			<  960000000  765000  256 >,
+			< 1036800000  775000  278 >,
+			< 1113600000  785000  301 >,
+			< 1190400000  795000  324 >,
+			< 1267200000  805000  348 >,
+			< 1344000000  815000  372 >,
+			< 1420800000  825000  396 >,
+			< 1497600000  835000  421 >,
+			< 1574400000  845000  446 >,
+			< 1651200000  855000  473 >,
+			< 1728000000  865000  501 >,
+			< 1804800000  875000  529 >,
+			< 1881600000  885000  558 >,
+			< 1958400000  895000  588 >,
+			< 2035200000  905000  617 >,
 			< 2112000000  915000  649 >,
 			< 2150400000  930000  682 >,
 			< 2188800000  930000  682 >,
@@ -1523,23 +1523,23 @@
 			<  652800000  750000  168 >,
 			<  729600000  750000  189 >,
 			<  806400000  750000  211 >,
-			<  883200000  750000  233 >,
-			<  960000000  750000  256 >,
-			< 1036800000  750000  278 >,
-			< 1113600000  750000  301 >,
-			< 1190400000  750000  324 >,
-			< 1267200000  760000  348 >,
-			< 1344000000  770000  372 >,
-			< 1420800000  780000  396 >,
-			< 1497600000  790000  421 >,
-			< 1574400000  800000  446 >,
-			< 1651200000  815000  473 >,
-			< 1728000000  830000  501 >,
-			< 1804800000  845000  529 >,
-			< 1881600000  860000  558 >,
-			< 1958400000  875000  588 >,
-			< 2035200000  890000  617 >,
-			< 2112000000  905000  649 >,
+			<  883200000  755000  233 >,
+			<  960000000  760000  256 >,
+			< 1036800000  770000  278 >,
+			< 1113600000  780000  301 >,
+			< 1190400000  790000  324 >,
+			< 1267200000  800000  348 >,
+			< 1344000000  810000  372 >,
+			< 1420800000  820000  396 >,
+			< 1497600000  830000  421 >,
+			< 1574400000  840000  446 >,
+			< 1651200000  850000  473 >,
+			< 1728000000  860000  501 >,
+			< 1804800000  870000  529 >,
+			< 1881600000  880000  558 >,
+			< 1958400000  890000  588 >,
+			< 2035200000  900000  617 >,
+			< 2112000000  910000  649 >,
 			< 2150400000  920000  682 >,
 			< 2188800000  920000  682 >,
 			< 2265600000  935000  716 >,
@@ -1548,25 +1548,6 @@
 			< 2457600000  970000  802 >;
 	};
 
-	qcom,msm-cpufreq@0 {
-		qcom,cpufreq-table =
-			<  300000  300000 300 /* 37.5 MHz */ >,
-			<  422400  422400 300 /* 37.5 MHz */ >,
-			<  652800  499200 300 /* 37.5 MHz */ >,
-			<  729600  576000 300 /* 37.5 MHz */ >,
-			<  883200  576000 300 /* 37.5 MHz */ >,
-			<  960000  960000 300 /* 37.5 MHz */ >,
-			< 1036800 1036800 300 /* 37.5 MHz */ >,
-			< 1190400 1036800 300 /* 37.5 MHz */ >,
-			< 1267200 1267200 300 /* 37.5 MHz */ >,
-			< 1497600 1497600 300 /* 37.5 MHz */ >,
-			< 1574400 1574400 300 /* 37.5 MHz */ >,
-			< 1728000 1651200 300 /* 37.5 MHz */ >,
-			< 1958400 1728000 300 /* 37.5 MHz */ >,
-			< 2265600 1728000 300 /* 37.5 MHz */ >,
-			< 2496000 1728000 300 /* 37.5 MHz */ >;
-	};
-
 	i2c@f9928000 { /* BLSP-1 QUP-6 */
 		cell-index = <3>;
 		compatible = "qcom,i2c-qup";
@@ -1597,13 +1578,13 @@
 		/* Off */
 		<26 512 0 0>, <89 604 0 0>,
 		/* Sub-SVS / SVS */
-		<26 512 0 1600000>, <89 604 0 3200000>,
+		<26 512 1200000 2456000>, <89 604 0 3200000>,
 		/* SVS */
-		<26 512 0 2456000>, <89 604 0 3200000>,
+		<26 512 1200000 2456000>, <89 604 0 3200000>,
 		/* low Nominal / SVS */
 		<26 512 0 3680000>, <89 604 0 3200000>,
 		/* SVS / low Nominal */
-		<26 512 0 2456000>, <89 604 0 5280000>,
+		<26 512 1200000 2456000>, <89 604 0 5280000>,
 		/* low Nominal / low Nominal */
 		<26 512 0 3680000>, <89 604 0 5280000>,
 		/* Nominal / low Nominal */
@@ -1635,47 +1616,48 @@
                        reg = <0>;
                        qcom,gpu-freq = <578000000>;
                        qcom,bus-freq = <14>;
-                       qcom,io-fraction = <33>;
+                       qcom,io-fraction = <101>;
                };
 
                qcom,gpu-pwrlevel@1 {
                        reg = <1>;
                        qcom,gpu-freq = <462400000>;
                        qcom,bus-freq = <11>;
-                       qcom,io-fraction = <66>;
+                       qcom,io-fraction = <101>;
                };
 
                qcom,gpu-pwrlevel@2 {
                        reg = <2>;
                        qcom,gpu-freq = <389000000>;
                        qcom,bus-freq = <8>;
-                       qcom,io-fraction = <66>;
+                       qcom,io-fraction = <101>;
                };
 
                qcom,gpu-pwrlevel@3 {
                        reg = <3>;
-                       qcom,gpu-freq = <320000000>;
+                       qcom,gpu-freq = <330000000>;
                        qcom,bus-freq = <5>;
-                       qcom,io-fraction = <100>;
+                       qcom,io-fraction = <101>;
                };
 
                qcom,gpu-pwrlevel@4 {
                        reg = <4>;
                        qcom,gpu-freq = <200000000>;
                        qcom,bus-freq = <2>;
-                       qcom,io-fraction = <100>;
+                       qcom,io-fraction = <101>;
                };
 
                qcom,gpu-pwrlevel@5 {
                        reg = <5>;
                        qcom,gpu-freq = <27000000>;
                        qcom,bus-freq = <0>;
-                       qcom,io-fraction = <0>;
+                       qcom,io-fraction = <101>;
                };
        };
 };
 
 &mdss_mdp {
+	qcom,max-bandwidth-low-kbps = <2750000>;
 	qcom,vbif-settings = <0x0004 0x00000001>;
 
 	qcom,mdss-wb-off = <0x00011100 0x00011500
@@ -1720,7 +1702,7 @@
 	qcom,dec-ocmem-ab-ib = <0 0>,
 		<176000 519000>,
 		<456000 519000>,
-		<864000 519000>,
+		<864000 629000>,
 		<1728000 1038000>,
 		<2766000 1661000>,
 		<3456000 2076000>,
@@ -1741,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>;
@@ -1770,3 +1752,14 @@
 	qcom,memblock-remove = <0x05a00000 0x7800000
 				0x0fa00000 0x500000>; /* Address and size of the hole */
 };
+
+&gdsc_venus {
+	qcom,skip-logic-collapse;
+};
+
+&sdhc_1 {
+	reg = <0xf9824900 0x1a0>, <0xf9824000 0x800>;
+
+	qcom,clk-rates = <400000 20000000 25000000 50000000 100000000 192000000 384000000>;
+	qcom,bus-speed-mode = "HS400_1p8v", "HS200_1p8v", "DDR_1p8v";
+};
diff --git a/arch/arm/boot/dts/msm9625-pm.dtsi b/arch/arm/boot/dts/msm9625-pm.dtsi
index 1e6cdf2..ec62cd4 100644
--- a/arch/arm/boot/dts/msm9625-pm.dtsi
+++ b/arch/arm/boot/dts/msm9625-pm.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
@@ -28,7 +28,7 @@
 		3e 0f];
 	};
 
-	qcom,lpm-levels {
+	lpm_levels: qcom,lpm-levels {
 		compatible = "qcom,lpm-levels";
 		qcom,no-l2-saw;
 		#address-cells = <1>;
@@ -167,6 +167,7 @@
 		reg = <0xfe805664 0x40>;
 		qcom,pc-mode = "tz_l2_ext";
 		qcom,use-sync-timer;
+		qcom,lpm-levels = <&lpm_levels>;
 	};
 
 	qcom,rpm-log@fc19dc00 {
diff --git a/arch/arm/boot/dts/msmsamarium-camera-sensor-cdp-interposer.dtsi b/arch/arm/boot/dts/msmsamarium-camera-sensor-cdp-interposer.dtsi
new file mode 100644
index 0000000..0c25060
--- /dev/null
+++ b/arch/arm/boot/dts/msmsamarium-camera-sensor-cdp-interposer.dtsi
@@ -0,0 +1,175 @@
+/*
+ * 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.
+ */
+
+&cci {
+	actuator0: qcom,actuator@18 {
+		cell-index = <0>;
+		reg = <0x18>;
+		compatible = "qcom,actuator";
+		qcom,cci-master = <0>;
+	};
+
+	actuator1: qcom,actuator@36 {
+		cell-index = <1>;
+		reg = <0x36>;
+		compatible = "qcom,actuator";
+		qcom,cci-master = <0>;
+	};
+
+    qcom,camera@20 {
+		compatible = "qcom,imx135";
+		reg = <0x20>;
+		qcom,slave-id = <0x20 0x0016 0x0135>;
+		qcom,csiphy-sd-index = <0>;
+		qcom,csid-sd-index = <0>;
+		qcom,mount-angle = <90>;
+		qcom,sensor-name = "imx135";
+		qcom,vdd-cx-supply = <&pma8084_s2>;
+		qcom,vdd-cx-name = "qcom,vdd-cx";
+		cam_vdig-supply = <&pma8084_l27>;
+		cam_vana-supply = <&pma8084_l17>;
+		cam_vio-supply = <&pma8084_lvs4>;
+		cam_vaf-supply = <&pma8084_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 = <1050000 0 2850000 2850000>;
+		qcom,cam-vreg-max-voltage = <1050000 0 2850000 2850000>;
+		qcom,cam-vreg-op-mode = <135000 0 44000 124000>;
+		qcom,gpio-no-mux = <0>;
+		gpios = <&msmgpio 15 0>,
+			<&msmgpio 81 0>,
+			<&msmgpio 80 0>;
+		qcom,gpio-reset = <1>;
+		qcom,gpio-standby = <2>;
+		qcom,gpio-req-tbl-num = <0 1 2>;
+		qcom,gpio-req-tbl-flags = <1 0 0>;
+		qcom,gpio-req-tbl-label = "CAMIF_MCLK",
+					  "CAM_RESET1",
+					  "CAM_STANDBY";
+		qcom,gpio-set-tbl-num = <1 1>;
+		qcom,gpio-set-tbl-flags = <0 2>;
+		qcom,gpio-set-tbl-delay = <1000 30000>;
+		qcom,csi-lane-assign = <0x4320>;
+		qcom,csi-lane-mask = <0x1F>;
+		qcom,sensor-position = <0>;
+		qcom,sensor-mode = <0>;
+	        qcom,sensor-type = <0>;
+		qcom,cci-master = <0>;
+		status = "ok";
+	};
+
+   qcom,camera@6d {
+               compatible = "qcom,imx132";
+               reg = <0x6d>;
+               qcom,slave-id = <0x6c 0x0 0x0132>;
+               qcom,csiphy-sd-index = <1>;
+               qcom,csid-sd-index = <1>;
+               qcom,mount-angle = <270>;
+               qcom,sensor-name = "imx132";
+               qcom,vdd-cx-supply = <&pma8084_s2>;
+               qcom,vdd-cx-name = "qcom,vdd-cx";
+               cam_vdig-supply = <&pma8084_l3>;
+               cam_vana-supply = <&pma8084_l17>;
+               cam_vio-supply = <&pma8084_lvs4>;
+               qcom,cam-vreg-name =  "cam_vana", "cam_vdig", "cam_vio";
+               qcom,cam-vreg-type = <0 0 1>;
+               qcom,cam-vreg-min-voltage = <2850000 1200000 0>;
+               qcom,cam-vreg-max-voltage = <2850000 1200000 0>;
+               qcom,cam-vreg-op-mode = <44000 98000 0>;
+               qcom,gpio-no-mux = <0>;
+               gpios = <&msmgpio 16 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_MCLK2",
+                                         "CAM_XSHUTDOWN";
+               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>;
+      };
+
+    qcom,camera@0 {
+		cell-index = <0>;
+		compatible = "qcom,camera";
+		reg = <0x00>;
+		qcom,csiphy-sd-index = <0>;
+		qcom,csid-sd-index = <0>;
+		qcom,mount-angle = <90>;
+		qcom,vdd-cx-supply = <&pma8084_s2>;
+		qcom,vdd-cx-name = "qcom,vdd-cx";
+		cam_vdig-supply = <&pma8084_l27>;
+		cam_vana-supply = <&pma8084_l17>;
+		cam_vio-supply = <&pma8084_lvs4>;
+		cam_vaf-supply = <&pma8084_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 = <1050000 0 2850000 2850000>;
+		qcom,cam-vreg-max-voltage = <1050000 0 2850000 2850000>;
+		qcom,cam-vreg-op-mode = <135000 0 44000 124000>;
+		qcom,gpio-no-mux = <0>;
+		gpios = <&msmgpio 15 0>,
+			<&msmgpio 81 0>,
+			<&msmgpio 80 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,sensor-position = <0>;
+		qcom,sensor-mode = <0>;
+		qcom,cci-master = <0>;
+		status = "ok";
+	};
+
+   qcom,camera@1 {
+		cell-index = <0>;
+		compatible = "qcom,camera";
+		reg = <0x01>;
+		qcom,slave-id = <0x6c 0x0 0x0132>;
+		qcom,csiphy-sd-index = <1>;
+		qcom,csid-sd-index = <1>;
+		qcom,mount-angle = <270>;
+		qcom,vdd-cx-supply = <&pma8084_s2>;
+		qcom,vdd-cx-name = "qcom,vdd-cx";
+		cam_vdig-supply = <&pma8084_l3>;
+		cam_vana-supply = <&pma8084_l17>;
+		cam_vio-supply = <&pma8084_lvs4>;
+		qcom,cam-vreg-name =  "cam_vana", "cam_vdig", "cam_vio";
+		qcom,cam-vreg-type = <0 0 1>;
+		qcom,cam-vreg-min-voltage = <2850000 1200000 0>;
+		qcom,cam-vreg-max-voltage = <2850000 1200000 0>;
+		qcom,cam-vreg-op-mode = <44000 98000 0>;
+		qcom,gpio-no-mux = <0>;
+		gpios = <&msmgpio 16 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_MCLK2",
+		                          "CAM_XSHUTDOWN";
+		qcom,sensor-position = <1>;
+		qcom,sensor-mode = <0>;
+		qcom,cci-master = <0>;
+		status = "ok";
+      };
+};
diff --git a/arch/arm/boot/dts/msmsamarium-camera-sensor-cdp.dtsi b/arch/arm/boot/dts/msmsamarium-camera-sensor-cdp.dtsi
new file mode 100644
index 0000000..637356b
--- /dev/null
+++ b/arch/arm/boot/dts/msmsamarium-camera-sensor-cdp.dtsi
@@ -0,0 +1,176 @@
+/*
+ * 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.
+ */
+
+&cci {
+
+	actuator0: qcom,actuator@18 {
+		cell-index = <0>;
+		reg = <0x18>;
+		compatible = "qcom,actuator";
+		qcom,cci-master = <0>;
+	};
+
+	actuator1: qcom,actuator@36 {
+		cell-index = <1>;
+		reg = <0x36>;
+		compatible = "qcom,actuator";
+		qcom,cci-master = <0>;
+	};
+
+    qcom,camera@20 {
+		compatible = "qcom,imx135";
+		reg = <0x20>;
+		qcom,slave-id = <0x20 0x0016 0x0135>;
+		qcom,csiphy-sd-index = <0>;
+		qcom,csid-sd-index = <0>;
+		qcom,mount-angle = <90>;
+		qcom,sensor-name = "imx135";
+		qcom,vdd-cx-supply = <&pma8084_s2_corner>;
+		qcom,vdd-cx-name = "qcom,vdd-cx";
+		cam_vdig-supply = <&pma8084_l27>;
+		cam_vana-supply = <&pma8084_l17>;
+		cam_vio-supply = <&pma8084_lvs4>;
+		cam_vaf-supply = <&pma8084_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 = <1050000 0 2850000 2850000>;
+		qcom,cam-vreg-max-voltage = <1050000 0 2850000 2850000>;
+		qcom,cam-vreg-op-mode = <135000 0 44000 124000>;
+		qcom,gpio-no-mux = <0>;
+		gpios = <&msmgpio 15 0>,
+			<&msmgpio 30 0>,
+			<&msmgpio 29 0>;
+		qcom,gpio-reset = <1>;
+		qcom,gpio-standby = <2>;
+		qcom,gpio-req-tbl-num = <0 1 2>;
+		qcom,gpio-req-tbl-flags = <1 0 0>;
+		qcom,gpio-req-tbl-label = "CAMIF_MCLK",
+					  "CAM_RESET1",
+					  "CAM_STANDBY";
+		qcom,gpio-set-tbl-num = <1 1>;
+		qcom,gpio-set-tbl-flags = <0 2>;
+		qcom,gpio-set-tbl-delay = <1000 30000>;
+		qcom,csi-lane-assign = <0x4320>;
+		qcom,csi-lane-mask = <0x1F>;
+		qcom,sensor-position = <0>;
+		qcom,sensor-mode = <0>;
+	        qcom,sensor-type = <0>;
+		qcom,cci-master = <0>;
+		status = "ok";
+	};
+
+   qcom,camera@6d {
+               compatible = "qcom,imx132";
+               reg = <0x6d>;
+               qcom,slave-id = <0x6c 0x0 0x0132>;
+               qcom,csiphy-sd-index = <1>;
+               qcom,csid-sd-index = <1>;
+               qcom,mount-angle = <270>;
+               qcom,sensor-name = "imx132";
+               qcom,vdd-cx-supply = <&pma8084_s2_corner>;
+               qcom,vdd-cx-name = "qcom,vdd-cx";
+               cam_vdig-supply = <&pma8084_l3>;
+               cam_vana-supply = <&pma8084_l17>;
+               cam_vio-supply = <&pma8084_lvs4>;
+               qcom,cam-vreg-name =  "cam_vana", "cam_vdig", "cam_vio";
+               qcom,cam-vreg-type = <0 0 1>;
+               qcom,cam-vreg-min-voltage = <2850000 1200000 0>;
+               qcom,cam-vreg-max-voltage = <2850000 1200000 0>;
+               qcom,cam-vreg-op-mode = <44000 98000 0>;
+               qcom,gpio-no-mux = <0>;
+               gpios = <&msmgpio 16 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_MCLK2",
+                                         "CAM_XSHUTDOWN";
+               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>;
+      };
+
+	qcom,camera@0 {
+		cell-index = <0>;
+		compatible = "qcom,camera";
+		reg = <0x00>;
+		qcom,csiphy-sd-index = <0>;
+		qcom,csid-sd-index = <0>;
+		qcom,mount-angle = <90>;
+		qcom,vdd-cx-supply = <&pma8084_s2_corner>;
+		qcom,vdd-cx-name = "qcom,vdd-cx";
+		cam_vdig-supply = <&pma8084_l27>;
+		cam_vana-supply = <&pma8084_l17>;
+		cam_vio-supply = <&pma8084_lvs4>;
+		cam_vaf-supply = <&pma8084_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 = <1050000 0 2850000 2850000>;
+		qcom,cam-vreg-max-voltage = <1050000 0 2850000 2850000>;
+		qcom,cam-vreg-op-mode = <135000 0 44000 124000>;
+		qcom,gpio-no-mux = <0>;
+		gpios = <&msmgpio 15 0>,
+			<&msmgpio 30 0>,
+			<&msmgpio 29 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,sensor-position = <0>;
+		qcom,sensor-mode = <0>;
+		qcom,cci-master = <0>;
+		status = "ok";
+	};
+
+	qcom,camera@1 {
+		cell-index = <1>;
+		compatible = "qcom,camera";
+		reg = <0x01>;
+		qcom,csiphy-sd-index = <1>;
+		qcom,csid-sd-index = <1>;
+		qcom,mount-angle = <270>;
+		qcom,vdd-cx-supply = <&pma8084_s2_corner>;
+		qcom,vdd-cx-name = "qcom,vdd-cx";
+		cam_vdig-supply = <&pma8084_l3>;
+		cam_vana-supply = <&pma8084_l17>;
+		cam_vio-supply = <&pma8084_lvs4>;
+		qcom,cam-vreg-name =  "cam_vana", "cam_vdig", "cam_vio";
+		qcom,cam-vreg-type = <0 0 1>;
+		qcom,cam-vreg-min-voltage = <2850000 1200000 0>;
+		qcom,cam-vreg-max-voltage = <2850000 1200000 0>;
+		qcom,cam-vreg-op-mode = <44000 98000 0>;
+		qcom,gpio-no-mux = <0>;
+		gpios = <&msmgpio 16 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_MCLK2",
+		                          "CAM_XSHUTDOWN";
+               qcom,sensor-position = <1>;
+               qcom,sensor-mode = <0>;
+		qcom,cci-master = <0>;
+		status = "ok";
+	};
+};
+
diff --git a/arch/arm/common/cpaccess.c b/arch/arm/common/cpaccess.c
index cca0b39..6fd54ef 100644
--- a/arch/arm/common/cpaccess.c
+++ b/arch/arm/common/cpaccess.c
@@ -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
@@ -84,9 +84,10 @@
  */
 static void do_write_il2(void *ret)
 {
-	*(unsigned long *)ret =
-		set_get_l2_indirect_reg(per_cpu(cp_param.il2index, cpu),
+	set_l2_indirect_reg(per_cpu(cp_param.il2index, cpu),
 				per_cpu(cp_param.write_value, cpu));
+	*(unsigned long *)ret =
+		get_l2_indirect_reg(per_cpu(cp_param.il2index, cpu));
 }
 
 /*
diff --git a/arch/arm/configs/apq8084_defconfig b/arch/arm/configs/apq8084_defconfig
index 968a5ee..2f5e776 100644
--- a/arch/arm/configs/apq8084_defconfig
+++ b/arch/arm/configs/apq8084_defconfig
@@ -301,6 +301,11 @@
 # CONFIG_LCD_CLASS_DEVICE is not set
 CONFIG_BACKLIGHT_CLASS_DEVICE=y
 # CONFIG_BACKLIGHT_GENERIC is not set
+CONFIG_UHID=y
+CONFIG_HID_APPLE=y
+CONFIG_HID_MAGICMOUSE=y
+CONFIG_HID_MICROSOFT=y
+CONFIG_HID_ELECOM=y
 CONFIG_USB=y
 CONFIG_USB_SUSPEND=y
 CONFIG_USB_EHCI_HCD=y
@@ -360,6 +365,7 @@
 CONFIG_QPNP_CLKDIV=y
 CONFIG_MSM_IOMMU_V1=y
 CONFIG_IOMMU_PGTABLES_L2=y
+CONFIG_MSM_IOMMU_VBIF_CHECK=y
 CONFIG_IOMMU_NON_SECURE=y
 CONFIG_EXT2_FS=y
 CONFIG_EXT2_FS_XATTR=y
diff --git a/arch/arm/configs/msm8226-perf_defconfig b/arch/arm/configs/msm8226-perf_defconfig
index 1e32cfa..dd355af 100644
--- a/arch/arm/configs/msm8226-perf_defconfig
+++ b/arch/arm/configs/msm8226-perf_defconfig
@@ -216,10 +216,12 @@
 CONFIG_BT_HCISMD=y
 CONFIG_CFG80211=y
 CONFIG_NL80211_TESTMODE=y
+CONFIG_CFG80211_INTERNAL_REGDB=y
 CONFIG_CMA=y
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_RAM=y
 CONFIG_QSEECOM=y
+CONFIG_USB_HSIC_SMSC_HUB=y
 CONFIG_SCSI=y
 CONFIG_SCSI_TGT=y
 CONFIG_BLK_DEV_SD=y
@@ -250,6 +252,7 @@
 CONFIG_WCNSS_CORE=y
 CONFIG_WCNSS_CORE_PRONTO=y
 CONFIG_WCNSS_MEM_PRE_ALLOC=y
+CONFIG_WCNSS_REGISTER_DUMP_ON_BITE=y
 CONFIG_INPUT_EVDEV=y
 CONFIG_INPUT_EVBUG=m
 CONFIG_KEYBOARD_GPIO=y
@@ -260,13 +263,17 @@
 CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4=y
 CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_RMI4_DEV=y
 CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE=y
+CONFIG_TOUCHSCREEN_GT9XX=y
+CONFIG_GT9XX_TOUCHPANEL_DRIVER=y
+CONFIG_GT9XX_TOUCHPANEL_UPDATE=y
+CONFIG_GT9XX_TOUCHPANEL_DEBUG=y
 CONFIG_TOUCHSCREEN_FT5X06=y
 CONFIG_TOUCHSCREEN_GEN_VKEYS=y
 CONFIG_INPUT_MISC=y
 CONFIG_INPUT_UINPUT=y
 CONFIG_INPUT_GPIO=m
-CONFIG_SERIAL_MSM_HSL=y
-CONFIG_SERIAL_MSM_HSL_CONSOLE=y
+#CONFIG_SERIAL_MSM_HSL is not set
+#CONFIG_SERIAL_MSM_HSL_CONSOLE is not set
 CONFIG_DIAG_CHAR=y
 CONFIG_HW_RANDOM=y
 CONFIG_HW_RANDOM_MSM=y
@@ -296,6 +303,9 @@
 CONFIG_THERMAL_QPNP_ADC_TM=y
 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
 CONFIG_MEDIA_SUPPORT=y
@@ -348,6 +358,8 @@
 CONFIG_UHID=y
 CONFIG_HID_APPLE=y
 CONFIG_HID_MAGICMOUSE=y
+CONFIG_HID_MICROSOFT=y
+CONFIG_HID_ELECOM=y
 CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
 CONFIG_USB_SUSPEND=y
 CONFIG_USB_MON=y
@@ -356,6 +368,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
@@ -384,6 +397,7 @@
 CONFIG_MMC_PARANOID_SD_INIT=y
 CONFIG_MMC_BLOCK_MINORS=32
 CONFIG_MMC_TEST=m
+CONFIG_MMC_BLOCK_DEFERRED_RESUME=y
 CONFIG_MMC_BLOCK_TEST=m
 CONFIG_MMC_SDHCI=y
 CONFIG_MMC_SDHCI_PLTFM=y
@@ -415,6 +429,7 @@
 CONFIG_QPNP_VIBRATOR=y
 CONFIG_QPNP_REVID=y
 CONFIG_MSM_IOMMU_V1=y
+CONFIG_MSM_IOMMU_VBIF_CHECK=y
 CONFIG_EXT2_FS=y
 CONFIG_EXT2_FS_XATTR=y
 CONFIG_EXT3_FS=y
@@ -455,8 +470,6 @@
 CONFIG_MOBICORE_SUPPORT=m
 CONFIG_MOBICORE_API=m
 CONFIG_MSM_RPM_RBCPR_STATS_V2_LOG=y
-CONFIG_TOUCHSCREEN_GT9XX=y
-CONFIG_GT9XX_TOUCHPANEL_DRIVER=y
 CONFIG_MSM_RDBG=m
 CONFIG_DEVMEM=n
 CONFIG_DEVKMEM=n
diff --git a/arch/arm/configs/msm8226_defconfig b/arch/arm/configs/msm8226_defconfig
index cedb6dc..5f008d5 100644
--- a/arch/arm/configs/msm8226_defconfig
+++ b/arch/arm/configs/msm8226_defconfig
@@ -221,6 +221,7 @@
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_RAM=y
 CONFIG_QSEECOM=y
+CONFIG_USB_HSIC_SMSC_HUB=y
 CONFIG_SCSI=y
 CONFIG_SCSI_TGT=y
 CONFIG_BLK_DEV_SD=y
@@ -251,6 +252,7 @@
 CONFIG_WCNSS_CORE=y
 CONFIG_WCNSS_CORE_PRONTO=y
 CONFIG_WCNSS_MEM_PRE_ALLOC=y
+CONFIG_WCNSS_REGISTER_DUMP_ON_BITE=y
 CONFIG_INPUT_EVDEV=y
 CONFIG_INPUT_EVBUG=m
 CONFIG_KEYBOARD_GPIO=y
@@ -261,6 +263,10 @@
 CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4=y
 CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_RMI4_DEV=y
 CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE=y
+CONFIG_TOUCHSCREEN_GT9XX=y
+CONFIG_GT9XX_TOUCHPANEL_DRIVER=y
+CONFIG_GT9XX_TOUCHPANEL_UPDATE=y
+CONFIG_GT9XX_TOUCHPANEL_DEBUG=y
 CONFIG_TOUCHSCREEN_FT5X06=y
 CONFIG_TOUCHSCREEN_GEN_VKEYS=y
 CONFIG_INPUT_MISC=y
@@ -299,6 +305,9 @@
 CONFIG_THERMAL_QPNP_ADC_TM=y
 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
 CONFIG_MEDIA_SUPPORT=y
@@ -325,6 +334,7 @@
 CONFIG_MSMB_JPEG=y
 CONFIG_MSM_VIDC_V4L2=y
 CONFIG_MSM_WFD=y
+CONFIG_MSM_COMMON_LOG=y
 # CONFIG_MEDIA_TUNER_SIMPLE is not set
 # CONFIG_MEDIA_TUNER_TDA8290 is not set
 # CONFIG_MEDIA_TUNER_TDA827X is not set
@@ -373,6 +383,8 @@
 CONFIG_UHID=y
 CONFIG_HID_APPLE=y
 CONFIG_HID_MAGICMOUSE=y
+CONFIG_HID_MICROSOFT=y
+CONFIG_HID_ELECOM=y
 CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
 CONFIG_USB_SUSPEND=y
 CONFIG_USB_MON=y
@@ -381,6 +393,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
@@ -409,6 +422,7 @@
 CONFIG_MMC_PARANOID_SD_INIT=y
 CONFIG_MMC_BLOCK_MINORS=32
 CONFIG_MMC_TEST=m
+CONFIG_MMC_BLOCK_DEFERRED_RESUME=y
 CONFIG_MMC_BLOCK_TEST=m
 CONFIG_MMC_SDHCI=y
 CONFIG_MMC_SDHCI_PLTFM=y
@@ -440,6 +454,7 @@
 CONFIG_QPNP_VIBRATOR=y
 CONFIG_QPNP_REVID=y
 CONFIG_MSM_IOMMU_V1=y
+CONFIG_MSM_IOMMU_VBIF_CHECK=y
 CONFIG_CORESIGHT=y
 CONFIG_CORESIGHT_FUSE=y
 CONFIG_CORESIGHT_TMC=y
@@ -453,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
@@ -472,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
@@ -509,6 +525,4 @@
 CONFIG_MOBICORE_SUPPORT=m
 CONFIG_MOBICORE_API=m
 CONFIG_MSM_RPM_RBCPR_STATS_V2_LOG=y
-CONFIG_TOUCHSCREEN_GT9XX=y
-CONFIG_GT9XX_TOUCHPANEL_DRIVER=y
 CONFIG_MSM_RDBG=m
diff --git a/arch/arm/configs/msm8610-perf_defconfig b/arch/arm/configs/msm8610-perf_defconfig
index e46bfef..55bc185 100644
--- a/arch/arm/configs/msm8610-perf_defconfig
+++ b/arch/arm/configs/msm8610-perf_defconfig
@@ -78,7 +78,6 @@
 CONFIG_KSM=y
 CONFIG_CC_STACKPROTECTOR=y
 CONFIG_KSM=y
-CONFIG_ENABLE_VMALLOC_SAVING=y
 CONFIG_CP_ACCESS=y
 CONFIG_USE_OF=y
 CONFIG_CPU_FREQ_GOV_POWERSAVE=y
@@ -207,11 +206,19 @@
 CONFIG_BT_HCISMD=y
 CONFIG_CFG80211=y
 CONFIG_NL80211_TESTMODE=y
+CONFIG_CFG80211_INTERNAL_REGDB=y
 CONFIG_CMA=y
 CONFIG_CMA_SIZE_MBYTES=4
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_RAM=y
 CONFIG_QSEECOM=y
+CONFIG_SCSI=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_CHR_DEV_SG=y
+CONFIG_CHR_DEV_SCH=y
+CONFIG_SCSI_MULTI_LUN=y
+CONFIG_SCSI_LOGGING=y
+CONFIG_SCSI_SCAN_ASYNC=y
 CONFIG_MD=y
 CONFIG_BLK_DEV_DM=y
 CONFIG_DM_CRYPT=y
@@ -223,6 +230,9 @@
 CONFIG_WCNSS_CORE=y
 CONFIG_WCNSS_CORE_PRONTO=y
 CONFIG_WCNSS_MEM_PRE_ALLOC=y
+CONFIG_WCNSS_REGISTER_DUMP_ON_BITE=y
+# CONFIG_INPUT_MOUSEDEV is not set
+>>>>>>> 3e5f4f6... defconfig: Enable WCNSS register dump on WCNSS bite
 CONFIG_INPUT_EVDEV=y
 CONFIG_INPUT_EVBUG=m
 CONFIG_KEYBOARD_GPIO=y
@@ -235,12 +245,14 @@
 CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE=y
 CONFIG_TOUCHSCREEN_GT9XX=y
 CONFIG_GT9XX_TOUCHPANEL_DRIVER=y
+CONFIG_GT9XX_TOUCHPANEL_UPDATE=y
+CONFIG_GT9XX_TOUCHPANEL_DEBUG=y
 CONFIG_INPUT_MISC=y
 CONFIG_INPUT_UINPUT=y
 CONFIG_INPUT_GPIO=m
 # CONFIG_INPUT_MOUSEDEV is not set
-CONFIG_SERIAL_MSM_HSL=y
-CONFIG_SERIAL_MSM_HSL_CONSOLE=y
+#CONFIG_SERIAL_MSM_HSL is not set
+#CONFIG_SERIAL_MSM_HSL_CONSOLE is not set
 CONFIG_DIAG_CHAR=y
 CONFIG_HW_RANDOM=y
 CONFIG_HW_RANDOM_MSM=y
@@ -328,6 +340,15 @@
 CONFIG_UHID=y
 CONFIG_HID_APPLE=y
 CONFIG_HID_MAGICMOUSE=y
+CONFIG_HID_MICROSOFT=y
+CONFIG_HID_ELECOM=y
+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
 CONFIG_USB_GADGET=y
 CONFIG_USB_GADGET_DEBUG_FILES=y
 CONFIG_USB_GADGET_DEBUG_FS=y
@@ -341,6 +362,7 @@
 CONFIG_MMC_PARANOID_SD_INIT=y
 CONFIG_MMC_BLOCK_MINORS=32
 CONFIG_MMC_TEST=m
+CONFIG_MMC_BLOCK_DEFERRED_RESUME=y
 CONFIG_MMC_BLOCK_TEST=y
 CONFIG_MMC_SDHCI=y
 CONFIG_MMC_SDHCI_PLTFM=y
@@ -405,6 +427,8 @@
 CONFIG_CRYPTO_MD4=y
 CONFIG_CRYPTO_ARC4=y
 CONFIG_CRYPTO_TWOFISH=y
+CONFIG_MOBICORE_SUPPORT=m
+CONFIG_MOBICORE_API=m
 # CONFIG_CRYPTO_HW is not set
 CONFIG_CRC_CCITT=y
 CONFIG_PPP=y
diff --git a/arch/arm/configs/msm8610_defconfig b/arch/arm/configs/msm8610_defconfig
index 899ed30..6874b28 100644
--- a/arch/arm/configs/msm8610_defconfig
+++ b/arch/arm/configs/msm8610_defconfig
@@ -79,7 +79,6 @@
 CONFIG_KSM=y
 CONFIG_CC_STACKPROTECTOR=y
 CONFIG_KSM=y
-CONFIG_ENABLE_VMALLOC_SAVING=y
 CONFIG_CP_ACCESS=y
 CONFIG_USE_OF=y
 CONFIG_CPU_FREQ_GOV_POWERSAVE=y
@@ -214,6 +213,13 @@
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_RAM=y
 CONFIG_QSEECOM=y
+CONFIG_SCSI=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_CHR_DEV_SG=y
+CONFIG_CHR_DEV_SCH=y
+CONFIG_SCSI_MULTI_LUN=y
+CONFIG_SCSI_LOGGING=y
+CONFIG_SCSI_SCAN_ASYNC=y
 CONFIG_MD=y
 CONFIG_BLK_DEV_DM=y
 CONFIG_DM_CRYPT=y
@@ -225,6 +231,9 @@
 CONFIG_WCNSS_CORE=y
 CONFIG_WCNSS_CORE_PRONTO=y
 CONFIG_WCNSS_MEM_PRE_ALLOC=y
+CONFIG_WCNSS_REGISTER_DUMP_ON_BITE=y
+# CONFIG_INPUT_MOUSEDEV is not set
+>>>>>>> 3e5f4f6... defconfig: Enable WCNSS register dump on WCNSS bite
 CONFIG_INPUT_EVDEV=y
 CONFIG_INPUT_EVBUG=m
 CONFIG_KEYBOARD_GPIO=y
@@ -237,6 +246,8 @@
 CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE=y
 CONFIG_TOUCHSCREEN_GT9XX=y
 CONFIG_GT9XX_TOUCHPANEL_DRIVER=y
+CONFIG_GT9XX_TOUCHPANEL_UPDATE=y
+CONFIG_GT9XX_TOUCHPANEL_DEBUG=y
 CONFIG_INPUT_MISC=y
 CONFIG_INPUT_UINPUT=y
 CONFIG_INPUT_GPIO=m
@@ -304,6 +315,7 @@
 CONFIG_MSMB_JPEG=y
 CONFIG_MSM_VIDC_V4L2=y
 CONFIG_MSM_WFD=y
+CONFIG_MSM_COMMON_LOG=y
 # CONFIG_MEDIA_TUNER_SIMPLE is not set
 # CONFIG_MEDIA_TUNER_TDA8290 is not set
 # CONFIG_MEDIA_TUNER_TDA827X is not set
@@ -351,6 +363,15 @@
 CONFIG_UHID=y
 CONFIG_HID_APPLE=y
 CONFIG_HID_MAGICMOUSE=y
+CONFIG_HID_MICROSOFT=y
+CONFIG_HID_ELECOM=y
+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
 CONFIG_USB_GADGET=y
 CONFIG_USB_GADGET_DEBUG_FILES=y
 CONFIG_USB_GADGET_DEBUG_FS=y
@@ -364,6 +385,7 @@
 CONFIG_MMC_PARANOID_SD_INIT=y
 CONFIG_MMC_BLOCK_MINORS=32
 CONFIG_MMC_TEST=m
+CONFIG_MMC_BLOCK_DEFERRED_RESUME=y
 CONFIG_MMC_BLOCK_TEST=y
 CONFIG_MMC_SDHCI=y
 CONFIG_MMC_SDHCI_PLTFM=y
@@ -411,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
@@ -431,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
@@ -479,3 +502,5 @@
 CONFIG_SENSORS_MMA8X5X=y
 CONFIG_SENSORS_CAPELLA_CM36283=y
 CONFIG_MSM_RDBG=m
+CONFIG_MOBICORE_SUPPORT=m
+CONFIG_MOBICORE_API=m
diff --git a/arch/arm/configs/msm8974-perf_defconfig b/arch/arm/configs/msm8974-perf_defconfig
index 10f2919..478e766 100755
--- a/arch/arm/configs/msm8974-perf_defconfig
+++ b/arch/arm/configs/msm8974-perf_defconfig
@@ -245,6 +245,7 @@
 CONFIG_MSM_BT_POWER=y
 CONFIG_CFG80211=y
 CONFIG_NL80211_TESTMODE=y
+CONFIG_CFG80211_INTERNAL_REGDB=y
 CONFIG_RFKILL=y
 CONFIG_GENLOCK=y
 CONFIG_GENLOCK_MISCDEVICE=y
@@ -282,6 +283,7 @@
 CONFIG_WCNSS_CORE=y
 CONFIG_WCNSS_CORE_PRONTO=y
 CONFIG_WCNSS_MEM_PRE_ALLOC=y
+CONFIG_WCNSS_REGISTER_DUMP_ON_BITE=y
 CONFIG_INPUT_EVDEV=y
 CONFIG_INPUT_EVBUG=m
 CONFIG_KEYBOARD_GPIO=y
@@ -293,10 +295,11 @@
 CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4=y
 CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE=y
 CONFIG_INPUT_MISC=y
+CONFIG_INPUT_HBTP_INPUT=y
 CONFIG_INPUT_UINPUT=y
 CONFIG_SERIAL_MSM_HS=y
-CONFIG_SERIAL_MSM_HSL=y
-CONFIG_SERIAL_MSM_HSL_CONSOLE=y
+#CONFIG_SERIAL_MSM_HSL is not set
+#CONFIG_SERIAL_MSM_HSL_CONSOLE is not set
 CONFIG_DIAG_CHAR=y
 CONFIG_HW_RANDOM=y
 CONFIG_HW_RANDOM_MSM=y
@@ -340,10 +343,6 @@
 CONFIG_VIDEO_V4L2_SUBDEV_API=y
 CONFIG_DVB_CORE=m
 # CONFIG_MSM_CAMERA is not set
-CONFIG_MT9M114=y
-CONFIG_OV2720=y
-CONFIG_IMX135=y
-CONFIG_IMX132=y
 CONFIG_MSM_CAMERA_SENSOR=y
 CONFIG_MSM_EEPROM=y
 CONFIG_MSM_CPP=y
@@ -352,7 +351,6 @@
 CONFIG_MSM_CSIPHY=y
 CONFIG_MSM_CSID=y
 CONFIG_MSM_ISPIF=y
-CONFIG_S5K3L1YX=y
 CONFIG_MSMB_CAMERA=y
 CONFIG_MSMB_JPEG=y
 CONFIG_MSM_VIDC_V4L2=y
@@ -389,6 +387,7 @@
 CONFIG_HID_APPLE=y
 CONFIG_HID_MAGICMOUSE=y
 CONFIG_HID_MICROSOFT=y
+CONFIG_HID_ELECOM=y
 CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
 CONFIG_USB_SUSPEND=y
 CONFIG_USB_XHCI_HCD=y
@@ -397,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
@@ -459,6 +459,7 @@
 CONFIG_QPNP_COINCELL=y
 CONFIG_MSM_IOMMU_V1=y
 CONFIG_IOMMU_PGTABLES_L2=y
+CONFIG_MSM_IOMMU_VBIF_CHECK=y
 CONFIG_MOBICORE_SUPPORT=m
 CONFIG_MOBICORE_API=m
 CONFIG_BIF=y
diff --git a/arch/arm/configs/msm8974_defconfig b/arch/arm/configs/msm8974_defconfig
index 0b9ba76..c5c16c2 100755
--- a/arch/arm/configs/msm8974_defconfig
+++ b/arch/arm/configs/msm8974_defconfig
@@ -82,7 +82,6 @@
 CONFIG_MSM_L1_ERR_LOG=y
 CONFIG_MSM_L2_ERP_PRINT_ACCESS_ERRORS=y
 CONFIG_MSM_L2_ERP_PORT_PANIC=y
-CONFIG_MSM_L2_ERP_1BIT_PANIC=y
 CONFIG_MSM_L2_ERP_2BIT_PANIC=y
 CONFIG_MSM_CACHE_DUMP=y
 CONFIG_MSM_CACHE_DUMP_ON_PANIC=y
@@ -125,6 +124,7 @@
 CONFIG_PACKET=y
 CONFIG_UNIX=y
 CONFIG_XFRM_USER=y
+CONFIG_NET_KEY=y
 CONFIG_INET=y
 CONFIG_IP_ADVANCED_ROUTER=y
 CONFIG_IP_MULTIPLE_TABLES=y
@@ -133,6 +133,7 @@
 CONFIG_IP_PNP_DHCP=y
 CONFIG_INET_AH=y
 CONFIG_INET_ESP=y
+CONFIG_INET_IPCOMP=y
 # CONFIG_INET_XFRM_MODE_BEET is not set
 # CONFIG_INET_LRO is not set
 CONFIG_IPV6=y
@@ -223,6 +224,9 @@
 CONFIG_IP6_NF_RAW=y
 CONFIG_BRIDGE_NF_EBTABLES=y
 CONFIG_BRIDGE_EBT_BROUTE=y
+CONFIG_L2TP=y
+CONFIG_L2TP_DEBUGFS=y
+CONFIG_L2TP_V3=y
 CONFIG_BRIDGE=y
 CONFIG_NET_SCHED=y
 CONFIG_NET_SCH_HTB=y
@@ -277,12 +281,25 @@
 CONFIG_MD=y
 CONFIG_BLK_DEV_DM=y
 CONFIG_DM_CRYPT=y
+CONFIG_DM_REQ_CRYPT=y
 CONFIG_NETDEVICES=y
 CONFIG_DUMMY=y
 CONFIG_TUN=y
 CONFIG_KS8851=m
 # CONFIG_MSM_RMNET is not set
 CONFIG_MSM_RMNET_BAM=y
+CONFIG_PPP=y
+CONFIG_PPP_BSDCOMP=y
+CONFIG_PPP_DEFLATE=y
+CONFIG_PPP_FILTER=y
+CONFIG_PPP_MPPE=y
+CONFIG_PPP_MULTILINK=y
+CONFIG_PPPOE=y
+CONFIG_PPPOL2TP=y
+CONFIG_PPPOLAC=y
+CONFIG_PPPOPNS=y
+CONFIG_PPP_ASYNC=y
+CONFIG_PPP_SYNC_TTY=y
 CONFIG_SLIP=y
 CONFIG_SLIP_COMPRESSED=y
 CONFIG_SLIP_MODE_SLIP6=y
@@ -290,6 +307,7 @@
 CONFIG_WCNSS_CORE=y
 CONFIG_WCNSS_CORE_PRONTO=y
 CONFIG_WCNSS_MEM_PRE_ALLOC=y
+CONFIG_WCNSS_REGISTER_DUMP_ON_BITE=y
 CONFIG_INPUT_EVDEV=y
 CONFIG_INPUT_EVBUG=m
 CONFIG_KEYBOARD_GPIO=y
@@ -301,6 +319,7 @@
 CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4=y
 CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE=y
 CONFIG_INPUT_MISC=y
+CONFIG_INPUT_HBTP_INPUT=y
 CONFIG_INPUT_UINPUT=y
 CONFIG_SERIAL_MSM_HS=y
 CONFIG_SERIAL_MSM_HSL=y
@@ -348,10 +367,6 @@
 CONFIG_VIDEO_V4L2_SUBDEV_API=y
 CONFIG_DVB_CORE=m
 # CONFIG_MSM_CAMERA is not set
-CONFIG_MT9M114=y
-CONFIG_OV2720=y
-CONFIG_IMX135=y
-CONFIG_IMX132=y
 CONFIG_MSM_CAMERA_SENSOR=y
 CONFIG_MSM_EEPROM=y
 CONFIG_MSM_CPP=y
@@ -360,7 +375,6 @@
 CONFIG_MSM_CSIPHY=y
 CONFIG_MSM_CSID=y
 CONFIG_MSM_ISPIF=y
-CONFIG_S5K3L1YX=y
 CONFIG_MSMB_CAMERA=y
 CONFIG_MSMB_JPEG=y
 CONFIG_MSM_VIDC_V4L2=y
@@ -397,6 +411,7 @@
 CONFIG_HID_APPLE=y
 CONFIG_HID_MAGICMOUSE=y
 CONFIG_HID_MICROSOFT=y
+CONFIG_HID_ELECOM=y
 CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
 CONFIG_USB_SUSPEND=y
 CONFIG_USB_XHCI_HCD=y
@@ -405,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
@@ -468,6 +484,7 @@
 CONFIG_MSM_IOMMU_V1=y
 CONFIG_MSM_IOMMU_PMON=y
 CONFIG_IOMMU_PGTABLES_L2=y
+CONFIG_MSM_IOMMU_VBIF_CHECK=y
 CONFIG_MOBICORE_SUPPORT=m
 CONFIG_MOBICORE_API=m
 CONFIG_CORESIGHT=y
@@ -484,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
@@ -507,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
@@ -538,8 +556,9 @@
 CONFIG_CRYPTO_MD4=y
 CONFIG_CRYPTO_ARC4=y
 CONFIG_CRYPTO_TWOFISH=y
+CONFIG_CRYPTO_XTS=y
 CONFIG_NFC_QNCI=y
-CONFIG_CRYPTO_DEV_QCRYPTO=m
+CONFIG_CRYPTO_DEV_QCRYPTO=y
 CONFIG_CRYPTO_DEV_QCE=y
 CONFIG_CRYPTO_DEV_QCEDEV=y
 CONFIG_SND_SOC_MSM_HDMI_CODEC_RX=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/include/asm/pmu.h b/arch/arm/include/asm/pmu.h
index e1fc42f..d3e2eb6 100644
--- a/arch/arm/include/asm/pmu.h
+++ b/arch/arm/include/asm/pmu.h
@@ -141,6 +141,8 @@
 	struct pmu_hw_events	*(*get_hw_events)(void);
 	int	(*test_set_event_constraints)(struct perf_event *event);
 	int	(*clear_event_constraints)(struct perf_event *event);
+	void		(*save_pm_registers)(void *hcpu);
+	void		(*restore_pm_registers)(void *hcpu);
 };
 
 #define to_arm_pmu(p) (container_of(p, struct arm_pmu, pmu))
diff --git a/arch/arm/include/asm/system_misc.h b/arch/arm/include/asm/system_misc.h
index 71f4827..0827df7 100644
--- a/arch/arm/include/asm/system_misc.h
+++ b/arch/arm/include/asm/system_misc.h
@@ -24,6 +24,7 @@
 extern void disable_hlt(void);
 extern void enable_hlt(void);
 extern int get_hlt(void);
+extern char* (*arch_read_hardware_id)(void);
 
 #endif /* !__ASSEMBLY__ */
 
diff --git a/arch/arm/include/asm/thread_info.h b/arch/arm/include/asm/thread_info.h
index 2eb0c2c..7013a5c 100644
--- a/arch/arm/include/asm/thread_info.h
+++ b/arch/arm/include/asm/thread_info.h
@@ -148,6 +148,7 @@
 #define TIF_NOTIFY_RESUME	2	/* callback before returning to user */
 #define TIF_SYSCALL_TRACE	8
 #define TIF_SYSCALL_AUDIT	9
+#define TIF_SYSCALL_RESTARTSYS	10
 #define TIF_POLLING_NRFLAG	16
 #define TIF_USING_IWMMXT	17
 #define TIF_MEMDIE		18	/* is terminating due to OOM killer */
@@ -163,9 +164,11 @@
 #define _TIF_USING_IWMMXT	(1 << TIF_USING_IWMMXT)
 #define _TIF_RESTORE_SIGMASK	(1 << TIF_RESTORE_SIGMASK)
 #define _TIF_SECCOMP		(1 << TIF_SECCOMP)
+#define _TIF_SYSCALL_RESTARTSYS	(1 << TIF_SYSCALL_RESTARTSYS)
 
 /* Checks for any syscall work in entry-common.S */
-#define _TIF_SYSCALL_WORK (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT)
+#define _TIF_SYSCALL_WORK (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT | \
+			   _TIF_SYSCALL_RESTARTSYS)
 
 /*
  * Change these and you break ASM code in entry-common.S
diff --git a/arch/arm/kernel/arch_timer.c b/arch/arm/kernel/arch_timer.c
index 8c0a923..5a1ed75 100644
--- a/arch/arm/kernel/arch_timer.c
+++ b/arch/arm/kernel/arch_timer.c
@@ -493,8 +493,8 @@
 	clockevents_config_and_register(clk, arch_timer_rate,
 					0xf, 0x7fffffff);
 
-	err = request_irq(arch_timer_spi, arch_timer_handler_mem, 0,
-		"arch_timer", clk);
+	err = request_irq(arch_timer_spi, arch_timer_handler_mem,
+			IRQF_TIMER, "arch_timer", clk);
 
 	return err;
 }
diff --git a/arch/arm/kernel/perf_event.c b/arch/arm/kernel/perf_event.c
index 2a3ab6e..1a09188 100644
--- a/arch/arm/kernel/perf_event.c
+++ b/arch/arm/kernel/perf_event.c
@@ -197,6 +197,9 @@
 	struct arm_pmu *armpmu = to_arm_pmu(event->pmu);
 	u64 delta, prev_raw_count, new_raw_count;
 
+	if (event->state <= PERF_EVENT_STATE_OFF)
+		return 0;
+
 again:
 	prev_raw_count = local64_read(&hwc->prev_count);
 	new_raw_count = armpmu->read_counter(idx);
@@ -425,15 +428,37 @@
 	return err;
 }
 
-void
+#ifdef CONFIG_SMP
+static __ref int armpmu_cpu_up(int cpu)
+{
+	int ret = 0;
+
+	if (!cpumask_test_cpu(cpu, cpu_online_mask)) {
+		ret = cpu_up(cpu);
+		if (ret)
+			pr_err("Failed to bring up CPU: %d, ret: %d\n",
+			       cpu, ret);
+	}
+	return ret;
+}
+#else
+static inline int armpmu_cpu_up(int cpu)
+{
+	return 0;
+}
+#endif
+
+void __ref
 multicore_free_irq(int irq)
 {
 	int cpu;
+	struct irq_desc *desc = irq_to_desc(irq);
 
 	if (irq >= 0) {
-		for_each_cpu(cpu, cpu_online_mask) {
-			smp_call_function_single(cpu,
-					disable_irq_callback, &irq, 1);
+		for_each_cpu(cpu, desc->percpu_enabled) {
+			if (!armpmu_cpu_up(cpu))
+				smp_call_function_single(cpu,
+						disable_irq_callback, &irq, 1);
 		}
 		free_percpu_irq(irq, &pmu_irq_cookie);
 	}
@@ -716,6 +741,7 @@
 	armpmu->pmu.start = armpmu_start;
 	armpmu->pmu.stop = armpmu_stop;
 	armpmu->pmu.read = armpmu_read;
+	armpmu->pmu.events_across_hotplug = 1;
 }
 
 int armpmu_register(struct arm_pmu *armpmu, char *name, int type)
@@ -826,62 +852,6 @@
 	return 0;
 }
 
-/*
- * PMU hardware loses all context when a CPU goes offline.
- * When a CPU is hotplugged back in, since some hardware registers are
- * UNKNOWN at reset, the PMU must be explicitly reset to avoid reading
- * junk values out of them.
- */
-static int __cpuinit pmu_cpu_notify(struct notifier_block *b,
-					unsigned long action, void *hcpu)
-{
-	int irq;
-
-	if (cpu_has_active_perf((int)hcpu)) {
-		switch ((action & ~CPU_TASKS_FROZEN)) {
-
-		case CPU_DOWN_PREPARE:
-			/*
-			 * If this is on a multicore CPU, we need
-			 * to disarm the PMU IRQ before disappearing.
-			 */
-			if (cpu_pmu &&
-				cpu_pmu->plat_device->dev.platform_data) {
-				irq = platform_get_irq(cpu_pmu->plat_device, 0);
-				smp_call_function_single((int)hcpu,
-						disable_irq_callback, &irq, 1);
-			}
-			return NOTIFY_DONE;
-
-		case CPU_UP_PREPARE:
-			/*
-			 * If this is on a multicore CPU, we need
-			 * to arm the PMU IRQ before appearing.
-			 */
-			if (cpu_pmu &&
-				cpu_pmu->plat_device->dev.platform_data) {
-				irq = platform_get_irq(cpu_pmu->plat_device, 0);
-				smp_call_function_single((int)hcpu,
-						enable_irq_callback, &irq, 1);
-			}
-			return NOTIFY_DONE;
-
-		case CPU_STARTING:
-			if (cpu_pmu && cpu_pmu->reset) {
-				cpu_pmu->reset(NULL);
-				return NOTIFY_OK;
-			}
-		default:
-			return NOTIFY_DONE;
-		}
-	}
-
-	if ((action & ~CPU_TASKS_FROZEN) != CPU_STARTING)
-		return NOTIFY_DONE;
-
-	return NOTIFY_OK;
-}
-
 static void armpmu_update_counters(void)
 {
 	struct pmu_hw_events *hw_events;
@@ -902,6 +872,80 @@
 	}
 }
 
+/*
+ * PMU hardware loses all context when a CPU goes offline.
+ * When a CPU is hotplugged back in, since some hardware registers are
+ * UNKNOWN at reset, the PMU must be explicitly reset to avoid reading
+ * junk values out of them.
+ */
+static int __cpuinit pmu_cpu_notify(struct notifier_block *b,
+					unsigned long action, void *hcpu)
+{
+	int irq;
+	struct pmu *pmu;
+	int cpu = (int)hcpu;
+
+	switch ((action & ~CPU_TASKS_FROZEN)) {
+	case CPU_DOWN_PREPARE:
+		if (cpu_pmu && cpu_pmu->save_pm_registers)
+			smp_call_function_single(cpu,
+						 cpu_pmu->save_pm_registers,
+						 hcpu, 1);
+		break;
+	case CPU_STARTING:
+		if (cpu_pmu && cpu_pmu->reset)
+			cpu_pmu->reset(NULL);
+		if (cpu_pmu && cpu_pmu->restore_pm_registers)
+			smp_call_function_single(cpu,
+						 cpu_pmu->restore_pm_registers,
+						 hcpu, 1);
+	}
+
+	if (cpu_has_active_perf((int)hcpu)) {
+		switch ((action & ~CPU_TASKS_FROZEN)) {
+
+		case CPU_DOWN_PREPARE:
+			armpmu_update_counters();
+			/*
+			 * If this is on a multicore CPU, we need
+			 * to disarm the PMU IRQ before disappearing.
+			 */
+			if (cpu_pmu &&
+				cpu_pmu->plat_device->dev.platform_data) {
+				irq = platform_get_irq(cpu_pmu->plat_device, 0);
+				smp_call_function_single((int)hcpu,
+						disable_irq_callback, &irq, 1);
+			}
+			return NOTIFY_DONE;
+
+		case CPU_STARTING:
+			/*
+			 * If this is on a multicore CPU, we need
+			 * to arm the PMU IRQ before appearing.
+			 */
+			if (cpu_pmu &&
+				cpu_pmu->plat_device->dev.platform_data) {
+				irq = platform_get_irq(cpu_pmu->plat_device, 0);
+				enable_irq_callback(&irq);
+			}
+
+			if (cpu_pmu) {
+				__get_cpu_var(from_idle) = 1;
+				pmu = &cpu_pmu->pmu;
+				pmu->pmu_enable(pmu);
+				return NOTIFY_OK;
+			}
+		default:
+			return NOTIFY_DONE;
+		}
+	}
+
+	if ((action & ~CPU_TASKS_FROZEN) != CPU_STARTING)
+		return NOTIFY_DONE;
+
+	return NOTIFY_OK;
+}
+
 static struct notifier_block __cpuinitdata pmu_cpu_notifier = {
 	.notifier_call = pmu_cpu_notify,
 };
@@ -913,6 +957,8 @@
 	struct pmu *pmu;
 	switch (cmd) {
 	case CPU_PM_ENTER:
+		if (cpu_pmu && cpu_pmu->save_pm_registers)
+			cpu_pmu->save_pm_registers((void *)smp_processor_id());
 		if (cpu_has_active_perf((int)v)) {
 			armpmu_update_counters();
 			pmu = &cpu_pmu->pmu;
@@ -922,6 +968,9 @@
 
 	case CPU_PM_ENTER_FAILED:
 	case CPU_PM_EXIT:
+		if (cpu_pmu && cpu_pmu->restore_pm_registers)
+			cpu_pmu->restore_pm_registers(
+				(void *)smp_processor_id());
 		if (cpu_has_active_perf((int)v) && cpu_pmu->reset) {
 			/*
 			 * Flip this bit so armpmu_enable knows it needs
diff --git a/arch/arm/kernel/perf_event_msm_krait.c b/arch/arm/kernel/perf_event_msm_krait.c
index 5708d74..1c338f7 100644
--- a/arch/arm/kernel/perf_event_msm_krait.c
+++ b/arch/arm/kernel/perf_event_msm_krait.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011-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
@@ -454,37 +454,29 @@
 	/* Disable counter */
 	armv7_pmnc_disable_counter(idx);
 
-	/*
-	 * Set event (if destined for PMNx counters)
-	 * We don't need to set the event if it's a cycle count
-	 */
-	if (idx != ARMV7_IDX_CYCLE_COUNTER) {
-		val = hwc->config_base;
-		val &= KRAIT_EVENT_MASK;
+	val = hwc->config_base;
+	val &= KRAIT_EVENT_MASK;
 
-		if (val < 0x40) {
-			armv7_pmnc_write_evtsel(idx, hwc->config_base);
-		} else {
-			event = get_krait_evtinfo(val, &evtinfo);
+	/* set event for ARM-architected events, and filter for CC */
+	if ((val < 0x40) || (idx == ARMV7_IDX_CYCLE_COUNTER)) {
+		armv7_pmnc_write_evtsel(idx, hwc->config_base);
+	} else {
+		event = get_krait_evtinfo(val, &evtinfo);
 
-			if (event == -EINVAL)
-				goto krait_out;
+		if (event == -EINVAL)
+			goto krait_out;
 
-			/* Restore Mode-exclusion bits */
-			event |= (hwc->config_base & KRAIT_MODE_EXCL_MASK);
+		/* Restore Mode-exclusion bits */
+		event |= (hwc->config_base & KRAIT_MODE_EXCL_MASK);
 
-			/*
-			 * Set event (if destined for PMNx counters)
-			 * We don't need to set the event if it's a cycle count
-			 */
-			armv7_pmnc_write_evtsel(idx, event);
-			val = 0x0;
-			asm volatile("mcr p15, 0, %0, c9, c15, 0" : :
-				"r" (val));
-			val = evtinfo.group_setval;
-			gr = evtinfo.groupcode;
-			krait_evt_setup(gr, val, evtinfo.armv7_evt_type);
-		}
+		/* Set event (if destined for PMNx counters) */
+		armv7_pmnc_write_evtsel(idx, event);
+		val = 0x0;
+		asm volatile("mcr p15, 0, %0, c9, c15, 0" : :
+			"r" (val));
+		val = evtinfo.group_setval;
+		gr = evtinfo.groupcode;
+		krait_evt_setup(gr, val, evtinfo.armv7_evt_type);
 	}
 
 	/* Enable interrupt for this counter */
@@ -572,6 +564,33 @@
 	return 1;
 }
 
+static DEFINE_PER_CPU(u32, krait_pm_pmactlr);
+
+static void krait_save_pm_registers(void *hcpu)
+{
+	u32 val;
+	u32 cpu = (int)hcpu;
+
+	/* Read PMACTLR */
+	asm volatile("mrc p15, 0, %0, c9, c15, 5" : "=r" (val));
+	per_cpu(krait_pm_pmactlr, cpu) = val;
+
+	armv7pmu_save_pm_registers(hcpu);
+}
+
+static void krait_restore_pm_registers(void *hcpu)
+{
+	u32 val;
+	u32 cpu = (int)hcpu;
+
+	val = per_cpu(krait_pm_pmactlr, cpu);
+	if (val != 0)
+		/* Restore PMACTLR */
+		asm volatile("mcr p15, 0, %0, c9, c15, 5" : : "r" (val));
+
+	armv7pmu_restore_pm_registers(hcpu);
+}
+
 static struct arm_pmu krait_pmu = {
 	.handle_irq		= armv7pmu_handle_irq,
 	.enable			= krait_pmu_enable_event,
@@ -585,6 +604,8 @@
 	.test_set_event_constraints	= msm_test_set_ev_constraint,
 	.clear_event_constraints	= msm_clear_ev_constraint,
 	.max_period		= (1LLU << 32) - 1,
+	.save_pm_registers	= krait_save_pm_registers,
+	.restore_pm_registers	= krait_restore_pm_registers,
 };
 
 /* NRCCG format for perf RAW codes. */
diff --git a/arch/arm/kernel/perf_event_v7.c b/arch/arm/kernel/perf_event_v7.c
index 58e9068..7c7a9d1 100644
--- a/arch/arm/kernel/perf_event_v7.c
+++ b/arch/arm/kernel/perf_event_v7.c
@@ -1238,6 +1238,29 @@
 				&armv7_a7_perf_cache_map, 0xFF);
 }
 
+static DEFINE_PER_CPU(u32, armv7_pm_pmuserenr);
+
+static void armv7pmu_save_pm_registers(void *hcpu)
+{
+	u32 val;
+	u32 cpu = (int)hcpu;
+
+	/* Read PMUSERENR */
+	asm volatile("mrc p15, 0, %0, c9, c14, 0" : "=r" (val));
+	per_cpu(armv7_pm_pmuserenr, cpu) = val;
+}
+
+static void armv7pmu_restore_pm_registers(void *hcpu)
+{
+	u32 val;
+	u32 cpu = (int)hcpu;
+
+	val = per_cpu(armv7_pm_pmuserenr, cpu);
+	if (val != 0)
+		/* Restore PMUSERENR */
+		asm volatile("mcr p15, 0, %0, c9, c14, 0" : : "r" (val));
+}
+
 static struct arm_pmu armv7pmu = {
 	.handle_irq		= armv7pmu_handle_irq,
 	.enable			= armv7pmu_enable_event,
@@ -1249,6 +1272,8 @@
 	.stop			= armv7pmu_stop,
 	.reset			= armv7pmu_reset,
 	.max_period		= (1LLU << 32) - 1,
+	.save_pm_registers	= armv7pmu_save_pm_registers,
+	.restore_pm_registers	= armv7pmu_restore_pm_registers,
 };
 
 static u32 __init armv7_read_num_pmnc_events(void)
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/kernel/ptrace.c b/arch/arm/kernel/ptrace.c
index c6c6be7..6533c4b 100644
--- a/arch/arm/kernel/ptrace.c
+++ b/arch/arm/kernel/ptrace.c
@@ -24,6 +24,7 @@
 #include <linux/hw_breakpoint.h>
 #include <linux/regset.h>
 #include <linux/audit.h>
+#include <linux/unistd.h>
 
 #include <asm/pgtable.h>
 #include <asm/traps.h>
@@ -916,6 +917,8 @@
 		audit_syscall_entry(AUDIT_ARCH_ARM, scno, regs->ARM_r0,
 				    regs->ARM_r1, regs->ARM_r2, regs->ARM_r3);
 
+	if (why == 0 && test_and_clear_thread_flag(TIF_SYSCALL_RESTARTSYS))
+		scno = __NR_restart_syscall - __NR_SYSCALL_BASE;
 	if (!test_thread_flag(TIF_SYSCALL_TRACE))
 		return scno;
 	if (!(current->ptrace & PT_PTRACED))
diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c
index 7298f9a..c110f0f 100644
--- a/arch/arm/kernel/setup.c
+++ b/arch/arm/kernel/setup.c
@@ -110,6 +110,9 @@
 unsigned int cold_boot;
 EXPORT_SYMBOL(cold_boot);
 
+char* (*arch_read_hardware_id)(void);
+EXPORT_SYMBOL(arch_read_hardware_id);
+
 #ifdef MULTI_CPU
 struct processor processor __read_mostly;
 #endif
@@ -1108,7 +1111,10 @@
 
 	seq_puts(m, "\n");
 
-	seq_printf(m, "Hardware\t: %s\n", machine_name);
+	if (!arch_read_hardware_id)
+		seq_printf(m, "Hardware\t: %s\n", machine_name);
+	else
+		seq_printf(m, "Hardware\t: %s\n", arch_read_hardware_id());
 	seq_printf(m, "Revision\t: %04x\n", system_rev);
 	seq_printf(m, "Serial\t\t: %08x%08x\n",
 		   system_serial_high, system_serial_low);
diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c
index edb73b4..7f9d4ee 100644
--- a/arch/arm/kernel/signal.c
+++ b/arch/arm/kernel/signal.c
@@ -649,12 +649,10 @@
 		case -ERESTARTNOHAND:
 		case -ERESTARTSYS:
 		case -ERESTARTNOINTR:
+		case -ERESTART_RESTARTBLOCK:
 			regs->ARM_r0 = regs->ARM_ORIG_r0;
 			regs->ARM_pc = restart_addr;
 			break;
-		case -ERESTART_RESTARTBLOCK:
-			regs->ARM_r0 = -EINTR;
-			break;
 		}
 	}
 
@@ -675,12 +673,14 @@
 		 * debugger has chosen to restart at a different PC.
 		 */
 		if (regs->ARM_pc == restart_addr) {
-			if (retval == -ERESTARTNOHAND
+			if (retval == -ERESTARTNOHAND ||
+			    retval == -ERESTART_RESTARTBLOCK
 			    || (retval == -ERESTARTSYS
 				&& !(ka.sa.sa_flags & SA_RESTART))) {
 				regs->ARM_r0 = -EINTR;
 				regs->ARM_pc = continue_addr;
 			}
+			clear_thread_flag(TIF_SYSCALL_RESTARTSYS);
 		}
 
 		if (test_thread_flag(TIF_RESTORE_SIGMASK))
@@ -708,38 +708,15 @@
 		 * ignore the restart.
 		 */
 		if (retval == -ERESTART_RESTARTBLOCK
-		    && regs->ARM_pc == continue_addr) {
-			if (thumb_mode(regs)) {
-				regs->ARM_r7 = __NR_restart_syscall - __NR_SYSCALL_BASE;
-				regs->ARM_pc -= 2;
-			} else {
-#if defined(CONFIG_AEABI) && !defined(CONFIG_OABI_COMPAT)
-				regs->ARM_r7 = __NR_restart_syscall;
-				regs->ARM_pc -= 4;
-#else
-				u32 __user *usp;
-
-				regs->ARM_sp -= 4;
-				usp = (u32 __user *)regs->ARM_sp;
-
-				if (put_user(regs->ARM_pc, usp) == 0) {
-					regs->ARM_pc = KERN_RESTART_CODE;
-				} else {
-					regs->ARM_sp += 4;
-					force_sigsegv(0, current);
-				}
-#endif
-			}
-		}
-
-		/* If there's no signal to deliver, we just put the saved sigmask
-		 * back.
-		 */
-		if (test_thread_flag(TIF_RESTORE_SIGMASK)) {
-			clear_thread_flag(TIF_RESTORE_SIGMASK);
-			sigprocmask(SIG_SETMASK, &current->saved_sigmask, NULL);
-		}
+		    && regs->ARM_pc == restart_addr)
+			set_thread_flag(TIF_SYSCALL_RESTARTSYS);
 	}
+
+	/* If there's no signal to deliver, we just put the saved sigmask
+	 * back.
+	 */
+	if (test_and_clear_thread_flag(TIF_RESTORE_SIGMASK))
+		set_current_blocked(&current->saved_sigmask);
 }
 
 asmlinkage void
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index 5bca467..4a6e6db 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -696,6 +696,7 @@
 
 void smp_send_reschedule(int cpu)
 {
+	BUG_ON(cpu_is_offline(cpu));
 	smp_cross_call(cpumask_of(cpu), IPI_RESCHEDULE);
 }
 
diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c
index bd49b1f..3be4085 100644
--- a/arch/arm/kernel/traps.c
+++ b/arch/arm/kernel/traps.c
@@ -25,6 +25,7 @@
 #include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/sched.h>
+#include <linux/bug.h>
 
 #include <linux/atomic.h>
 #include <asm/cacheflush.h>
@@ -765,6 +766,7 @@
 asmlinkage void __div0(void)
 {
 	printk("Division by zero in kernel.\n");
+	BUG_ON(PANIC_CORRUPTION);
 	dump_stack();
 }
 EXPORT_SYMBOL(__div0);
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index 4b8d443..6b551cd 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -261,6 +261,8 @@
 	select MSM_GPIOMUX
 	select MULTI_IRQ_HANDLER
 	select MSM_MULTIMEDIA_USE_ION
+	select PM_DEVFREQ
+	select MSM_DEVFREQ_CPUBW
 	select MSM_PIL
 	select MSM_SPM_V2
 	select MSM_L2_SPM
@@ -309,11 +311,15 @@
 	select MSM_SPM_V2
 	select MSM_L2_SPM
 	select MSM_RPM_SMD
+	select PM_DEVFREQ
+	select MSM_DEVFREQ_CPUBW
 	select ENABLE_VMALLOC_SAVINGS
 
 config ARCH_MPQ8092
 	bool "MPQ8092"
 	select ARCH_MSM_KRAITMP
+	select PM_DEVFREQ
+	select MSM_DEVFREQ_CPUBW
 	select GPIO_MSM_V3
 	select ARM_GIC
 	select MULTI_IRQ_HANDLER
@@ -332,6 +338,7 @@
 	select MSM_SCM
 	select MSM_GPIOMUX
 	select MULTI_IRQ_HANDLER
+	select PM_DEVFREQ
 	select MSM_PIL
 	select MSM_NATIVE_RESTART
 	select MSM_RESTART_V2
@@ -435,6 +442,8 @@
 	select MEMORY_HOLE_CARVEOUT
 	select QMI_ENCDEC
 	select MSM_CORTEX_A7
+	select PM_DEVFREQ
+	select MSM_DEVFREQ_CPUBW
 
 config ARCH_MSM8610
 	bool "MSM8610"
@@ -464,6 +473,8 @@
 	select MSM_CORTEX_A7
 	select CPU_FREQ_MSM
 	select CPU_FREQ
+	select PM_DEVFREQ
+	select MSM_DEVFREQ_CPUBW
 	select MSM_PIL
 	select MSM_RUN_QUEUE_STATS
 	select ARM_HAS_SG_CHAIN
@@ -475,7 +486,6 @@
 	select MSM_RPM_LOG
 	select MSM_IOMMU_SYNC
 	select MSM_RPM_STATS_LOG
-	select ENABLE_VMALLOC_SAVINGS
 
 config ARCH_MSM8226
 	bool "MSM8226"
@@ -505,6 +515,8 @@
 	select MSM_CORTEX_A7
 	select CPU_FREQ_MSM
 	select CPU_FREQ
+	select PM_DEVFREQ
+	select MSM_DEVFREQ_CPUBW
 	select MSM_PIL
 	select MSM_RUN_QUEUE_STATS
 	select ARM_HAS_SG_CHAIN
@@ -525,6 +537,8 @@
 	select ARM_GIC
 	select CPU_V7
 	select MSM_SCM
+	select PM_DEVFREQ
+	select MSM_DEVFREQ_CPUBW
 	select MSM_PIL
 	select MSM_GPIOMUX
 	select MULTI_IRQ_HANDLER
@@ -574,6 +588,7 @@
 config  ARCH_MSM_KRAIT
 	bool
 	select ARM_L1_CACHE_SHIFT_6
+	select DEVFREQ_GOV_MSM_CPUBW_HWMON
 
 config  MSM_CORTEX_A7
 	bool
@@ -1563,20 +1578,6 @@
 	  Enables the PCIe functionality by configures PCIe core on
 	  MSM chipset and by enabling the ARM PCI framework extension.
 
-config MSM_RPC_SDIO_XPRT
-	depends on MSM_SDIO_AL
-	default y
-	bool "MSM SDIO XPRT Layer"
-	help
-	  SDIO Transport Layer for RPC Rouer
-
-config MSM_RPC_SDIO_DEBUG
-	depends on MSM_RPC_SDIO_XPRT
-	default y
-	bool "MSM SDIO XPRT debug support"
-	help
-	  Support for debugging SDIO XPRT
-
 config MSM_SMD_DEBUG
 	depends on MSM_SMD
 	default y
@@ -1585,21 +1586,6 @@
 	  Support for debugging the SMD for communication
 	  between the ARM9 and ARM11
 
-config MSM_SDIO_AL
-	depends on ((ARCH_MSM7X30 || MACH_MSM8X60_FUSN_FFA || MACH_TYPE_MSM8X60_FUSION) && HAS_WAKELOCK)
-	default y
-	tristate "SDIO-Abstraction-Layer"
-	help
-	  Support MSM<->MDM Communication over SDIO bus.
-	  MDM SDIO-Client should have pipes support.
-
-config MSM_SDIO_DMUX
-	bool "SDIO Data Mux Driver"
-	depends on MSM_SDIO_AL
-	default n
-	help
-	  Support Muxed Data Channels over SDIO interface.
-
 config MSM_BAM_DMUX
 	bool "BAM Data Mux Driver"
 	depends on SPS
@@ -1680,16 +1666,6 @@
 
 	  If in doubt, say yes.
 
-config MSM_SDIO_TTY
-	bool "SDIO TTY Driver"
-	depends on MSM_SDIO_AL
-	default n
-	help
-	  Provides a TTY driver SDIO TTY
-	  This driver can be used by user space
-	  applications for passing data through the
-	  SDIO interface.
-
 config MSM_SMD_TTY
 	bool "SMD TTY Driver"
 	depends on MSM_SMD
@@ -1717,13 +1693,6 @@
 
 	  If in doubt, say yes.
 
-config MSM_SDIO_CMUX
-	bool "SDIO CMUX Driver"
-	depends on MSM_SDIO_AL
-	default n
-	help
-	  Provides a Muxed port interface over SDIO QMI
-
 config MSM_DSPS
 	bool "Sensors DSPS driver"
 	depends on (MSM_PIL && (ARCH_MSM8X60 || ARCH_MSM8960))
@@ -1736,13 +1705,6 @@
 	  The number of clocks and their name may vary between targets.
 	  It also triggers the PIL to load the DSPS firmware.
 
-config MSM_SDIO_CTL
-	bool "SDIO CTL Driver"
-	depends on MSM_SDIO_CMUX
-	default n
-	help
-	  Provides a binary SDIO control port interface.
-
 config MSM_ONCRPCROUTER
 	depends on MSM_SMD
 	default n
@@ -1891,15 +1853,6 @@
 	  Collects performance statistics and shows this information
 	  through a debugfs file rmt_storage_stats.
 
-config MSM_SDIO_SMEM
-        depends on MSM_SDIO_AL
-        default n
-        bool "SDIO SMEM for remote storage"
-        help
-          Copies data from remote MDM9K memory to local MSM8x60
-	  memory. Used by remote storage client to shadow
-	  MDM9K filesystem.
-
 config MSM_DALRPC
 	bool "DAL RPC support"
 	default n
@@ -1934,6 +1887,20 @@
 
 endif # CPU_FREQ_MSM
 
+config MSM_DEVFREQ_CPUBW
+	bool "Devfreq device for CPU<->DDR IB/AB BW voting"
+	depends on PM_DEVFREQ
+	select DEVFREQ_GOV_PERFORMANCE
+	select DEVFREQ_GOV_POWERSAVE
+	select DEVFREQ_GOV_USERSPACE
+	select DEVFREQ_GOV_MSM_CPUFREQ
+	default n
+	help
+	  Different devfreq governors use this devfreq device to make CPU to
+	  DDR IB/AB bandwidth votes. This driver provides a SoC topology
+	  agnostic interface to so that some of the devfreq governors can be
+	  shared across SoCs.
+
 config MSM_AVS_HW
 	bool "Enable Adaptive Voltage Scaling (AVS)"
 	default n
@@ -3038,6 +3005,13 @@
 	help
 		Select if BLSP based UART Core v.14 or higher is present.
 
+config MSM_COMMON_LOG
+	bool "Use to export symbols for parsing memory dump"
+	help
+	 Use this to export symbols to a memory dump table. This table
+	 can be used by post analysis tools to extract information from
+	 memory when device crashes.
+
 config MSM_BOOT_STATS
 	bool "Use MSM boot stats reporting"
 	help
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index 4e60414..5f7f0d9 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -98,12 +98,9 @@
 obj-$(CONFIG_ARCH_FSM9XXX) += sirc-fsm9xxx.o
 obj-$(CONFIG_MSM_FIQ_SUPPORT) += fiq_glue.o
 obj-$(CONFIG_MACH_TROUT) += board-trout-rfkill.o
-obj-$(CONFIG_MSM_SDIO_AL) += sdio_al.o
-obj-$(CONFIG_MSM_SDIO_AL) += sdio_al_test.o
-obj-$(CONFIG_MSM_SDIO_AL) += sdio_al_dloader.o
-obj-$(CONFIG_MSM_SDIO_DMUX) += sdio_dmux.o
 obj-$(CONFIG_MSM_BAM_DMUX) += bam_dmux.o
 obj-$(CONFIG_MSM_SMD_LOGGING) += smem_log.o
+obj-$(CONFIG_MSM_COMMON_LOG) += common_log.o
 obj-$(CONFIG_MSM_IPC_LOGGING) += ipc_logging.o
 ifdef CONFIG_DEBUG_FS
 obj-$(CONFIG_MSM_IPC_LOGGING) += ipc_logging_debug.o
@@ -118,13 +115,10 @@
 obj-$(CONFIG_ARCH_MSM9615) += nand_partitions.o
 obj-$(CONFIG_ARCH_MSM8625) += nand_partitions.o
 obj-$(CONFIG_ARCH_MSM7X27A) += nand_partitions.o
-obj-$(CONFIG_MSM_SDIO_TTY) += sdio_tty.o
 obj-$(CONFIG_MSM_SMD_TTY) += smd_tty.o
 obj-$(CONFIG_MSM_SMD_QMI) += smd_qmi.o
 obj-$(CONFIG_MSM_SMD_PKT) += smd_pkt.o
-obj-$(CONFIG_MSM_SDIO_CMUX) += sdio_cmux.o
 obj-$(CONFIG_MSM_DSPS) += msm_dsps.o
-obj-$(CONFIG_MSM_SDIO_CTL) += sdio_ctl.o
 obj-$(CONFIG_MSM_SMD_NMEA) += smd_nmea.o
 obj-$(CONFIG_MSM_RESET_MODEM) += reset_modem.o
 obj-$(CONFIG_MSM_IPC_ROUTER_SMD_XPRT) += ipc_router_smd_xprt.o
@@ -141,7 +135,6 @@
 obj-$(CONFIG_MSM_ONCRPCROUTER) += smd_rpcrouter_clients.o
 obj-$(CONFIG_MSM_ONCRPCROUTER) += smd_rpcrouter_xdr.o
 obj-$(CONFIG_MSM_ONCRPCROUTER) += rpcrouter_smd_xprt.o
-obj-$(CONFIG_MSM_RPC_SDIO_XPRT) += rpcrouter_sdio_xprt.o
 obj-$(CONFIG_MSM_RPC_PING) += ping_mdm_rpc_client.o
 obj-$(CONFIG_MSM_RPC_PROC_COMM_TEST) += proc_comm_test.o
 obj-$(CONFIG_MSM_RPC_PING) += ping_mdm_rpc_client.o ping_apps_server.o
@@ -305,7 +298,7 @@
 obj-$(CONFIG_ARCH_MSM8610) += clock-dsi-8610.o
 obj-$(CONFIG_ARCH_MSMKRYPTON) += clock-local2.o clock-pll.o clock-krypton.o clock-rpm.o clock-voter.o
 
-obj-$(CONFIG_MSM_PM) += msm-pm.o pm-data.o
+obj-$(CONFIG_MSM_PM) += msm-pm.o pm-data.o ext-buck-control.o
 
 obj-$(CONFIG_MACH_SAPPHIRE) += board-sapphire.o board-sapphire-gpio.o
 obj-$(CONFIG_MACH_SAPPHIRE) += board-sapphire-keypad.o board-sapphire-panel.o
@@ -322,7 +315,6 @@
 obj-$(CONFIG_HTC_PWRSINK) += htc_pwrsink.o
 obj-$(CONFIG_HTC_HEADSET) += htc_headset.o
 obj-$(CONFIG_MSM_RMT_STORAGE_CLIENT) += rmt_storage_client.o
-obj-$(CONFIG_MSM_SDIO_SMEM) += sdio_smem.o
 obj-$(CONFIG_MSM_RPM) += rpm.o rpm_resources.o
 obj-$(CONFIG_MSM_LPM_TEST) += test-lpm.o
 obj-$(CONFIG_MSM_RPM_SMD) += rpm-smd.o lpm_levels.o
@@ -422,9 +414,9 @@
 obj-$(CONFIG_ARCH_MSM8974) += msm_mpmctr.o
 obj-$(CONFIG_MSM_CPR_REGULATOR) += cpr-regulator.o
 obj-$(CONFIG_CPU_FREQ_MSM) += cpufreq.o
+obj-$(CONFIG_MSM_DEVFREQ_CPUBW) += devfreq_cpubw.o
 
 obj-$(CONFIG_WALL_CLK) += wallclk.o
 obj-$(CONFIG_WALL_CLK_SYSFS) += wallclk_sysfs.o
 obj-$(CONFIG_ARCH_RANDOM) += early_random.o
 obj-$(CONFIG_PERFMAP) += perfmap.o
-obj-$(CONFIG_ARCH_MSM8974) += cpubw-krait.o
diff --git a/arch/arm/mach-msm/Makefile.boot b/arch/arm/mach-msm/Makefile.boot
index 83c1d4c..c0e9efc 100644
--- a/arch/arm/mach-msm/Makefile.boot
+++ b/arch/arm/mach-msm/Makefile.boot
@@ -69,6 +69,7 @@
         dtb-$(CONFIG_ARCH_MSM8974)	+= msm8974-v2.2-mtp.dtb
         dtb-$(CONFIG_ARCH_MSM8974)	+= msm8974pro-ab-pm8941-cdp.dtb
         dtb-$(CONFIG_ARCH_MSM8974)	+= msm8974pro-ab-pm8941-fluid.dtb
+        dtb-$(CONFIG_ARCH_MSM8974)	+= msm8974pro-ab-pm8941-fluid-hbtp.dtb
         dtb-$(CONFIG_ARCH_MSM8974)	+= msm8974pro-ab-pm8941-liquid.dtb
         dtb-$(CONFIG_ARCH_MSM8974)	+= msm8974pro-ab-pm8941-mtp.dtb
         dtb-$(CONFIG_ARCH_MSM8974)	+= msm8974pro-ac-pm8941-cdp.dtb
@@ -111,12 +112,22 @@
 	dtb-$(CONFIG_ARCH_MSM8226)	+= msm8226-v2-1080p-mtp.dtb
 	dtb-$(CONFIG_ARCH_MSM8226)	+= msm8226-v2-qrd-evt.dtb
 	dtb-$(CONFIG_ARCH_MSM8226)	+= msm8226-v2-qrd-dvt.dtb
-	dtb-$(CONFIG_ARCH_MSM8226)	+= msm8926-720p-cdp.dtb
-	dtb-$(CONFIG_ARCH_MSM8226)	+= msm8926-1080p-cdp.dtb
-	dtb-$(CONFIG_ARCH_MSM8226)	+= msm8926-720p-mtp.dtb
-	dtb-$(CONFIG_ARCH_MSM8226)	+= msm8926-1080p-mtp.dtb
-	dtb-$(CONFIG_ARCH_MSM8226)	+= msm8926-qrd.dtb
-	dtb-$(CONFIG_ARCH_MSM8226)	+= msm8926-qrd-skug.dtb
+	dtb-$(CONFIG_ARCH_MSM8226)	+= msm8926-v1-720p-cdp.dtb
+	dtb-$(CONFIG_ARCH_MSM8226)	+= msm8926-v1-1080p-cdp.dtb
+	dtb-$(CONFIG_ARCH_MSM8226)	+= msm8926-v1-720p-mtp.dtb
+	dtb-$(CONFIG_ARCH_MSM8226)	+= msm8926-v1-1080p-mtp.dtb
+	dtb-$(CONFIG_ARCH_MSM8226)	+= msm8926-v1-qrd.dtb
+	dtb-$(CONFIG_ARCH_MSM8226)	+= msm8926-v1-qrd-skug.dtb
+	dtb-$(CONFIG_ARCH_MSM8226)	+= msm8926-v1-qrd-skug-pvt.dtb
+	dtb-$(CONFIG_ARCH_MSM8226)	+= msm8926-v2-720p-cdp.dtb
+	dtb-$(CONFIG_ARCH_MSM8226)	+= msm8926-v2-1080p-cdp.dtb
+	dtb-$(CONFIG_ARCH_MSM8226)	+= msm8926-v2-1080p-ext-buck-cdp.dtb
+	dtb-$(CONFIG_ARCH_MSM8226)	+= msm8926-v2-720p-mtp.dtb
+	dtb-$(CONFIG_ARCH_MSM8226)	+= msm8926-v2-1080p-mtp.dtb
+	dtb-$(CONFIG_ARCH_MSM8226)	+= msm8926-v2-1080p-ext-buck-mtp.dtb
+	dtb-$(CONFIG_ARCH_MSM8226)	+= msm8926-v2-qrd.dtb
+	dtb-$(CONFIG_ARCH_MSM8226)	+= msm8926-v2-qrd-skug.dtb
+	dtb-$(CONFIG_ARCH_MSM8226)	+= msm8926-v2-qrd-skug-pvt.dtb
 	dtb-$(CONFIG_ARCH_MSM8226)	+= msm8226-v1-qrd-skuf.dtb
 	dtb-$(CONFIG_ARCH_MSM8226)	+= msm8226-v2-qrd-skuf.dtb
 	dtb-$(CONFIG_ARCH_MSM8226)	+= apq8026-v1-xpm.dtb
diff --git a/arch/arm/mach-msm/acpuclock-8226.c b/arch/arm/mach-msm/acpuclock-8226.c
index da3cfba..d42e798 100644
--- a/arch/arm/mach-msm/acpuclock-8226.c
+++ b/arch/arm/mach-msm/acpuclock-8226.c
@@ -60,64 +60,64 @@
 };
 
 static struct clkctl_acpu_speed acpu_freq_tbl_8226_1p1[] = {
-	{ 1,  300000, PLL0,    4, 2,   CPR_CORNER_SVS,    0, 4 },
-	{ 1,  384000, ACPUPLL, 5, 2,   CPR_CORNER_SVS,    0, 4 },
-	{ 1,  600000, PLL0,    4, 0,   CPR_CORNER_NORMAL, 0, 6 },
-	{ 1,  787200, ACPUPLL, 5, 0,   CPR_CORNER_NORMAL, 0, 6 },
-	{ 1,  998400, ACPUPLL, 5, 0,   CPR_CORNER_TURBO,  0, 7 },
-	{ 1, 1094400, ACPUPLL, 5, 0,   CPR_CORNER_TURBO,  0, 7 },
-	{ 0, 1190400, ACPUPLL, 5, 0,   CPR_CORNER_TURBO,  0, 7 },
+	{ 1,  300000, PLL0,    4, 2,   CPR_CORNER_2,    0, 4 },
+	{ 1,  384000, ACPUPLL, 5, 2,   CPR_CORNER_2,    0, 4 },
+	{ 1,  600000, PLL0,    4, 0,   CPR_CORNER_4, 0, 6 },
+	{ 1,  787200, ACPUPLL, 5, 0,   CPR_CORNER_4, 0, 6 },
+	{ 1,  998400, ACPUPLL, 5, 0,   CPR_CORNER_12,  0, 7 },
+	{ 1, 1094400, ACPUPLL, 5, 0,   CPR_CORNER_12,  0, 7 },
+	{ 0, 1190400, ACPUPLL, 5, 0,   CPR_CORNER_12,  0, 7 },
 	{ 0 }
 };
 
 static struct clkctl_acpu_speed acpu_freq_tbl_8226_1p2[] = {
-	{ 1,  300000, PLL0,    4, 2,   CPR_CORNER_SVS,    0, 4 },
-	{ 1,  384000, ACPUPLL, 5, 2,   CPR_CORNER_SVS,    0, 4 },
-	{ 1,  600000, PLL0,    4, 0,   CPR_CORNER_NORMAL, 0, 6 },
-	{ 1,  787200, ACPUPLL, 5, 0,   CPR_CORNER_NORMAL, 0, 6 },
-	{ 1,  998400, ACPUPLL, 5, 0,   CPR_CORNER_TURBO,  0, 7 },
-	{ 1, 1094400, ACPUPLL, 5, 0,   CPR_CORNER_TURBO,  0, 7 },
-	{ 1, 1190400, ACPUPLL, 5, 0,   CPR_CORNER_TURBO,  0, 7 },
+	{ 1,  300000, PLL0,    4, 2,   CPR_CORNER_2,    0, 4 },
+	{ 1,  384000, ACPUPLL, 5, 2,   CPR_CORNER_2,    0, 4 },
+	{ 1,  600000, PLL0,    4, 0,   CPR_CORNER_4, 0, 6 },
+	{ 1,  787200, ACPUPLL, 5, 0,   CPR_CORNER_4, 0, 6 },
+	{ 1,  998400, ACPUPLL, 5, 0,   CPR_CORNER_12,  0, 7 },
+	{ 1, 1094400, ACPUPLL, 5, 0,   CPR_CORNER_12,  0, 7 },
+	{ 1, 1190400, ACPUPLL, 5, 0,   CPR_CORNER_12,  0, 7 },
 	{ 0 }
 };
 
 static struct clkctl_acpu_speed acpu_freq_tbl_8226_1p4[] = {
-	{ 1,  300000, PLL0,    4, 2,   CPR_CORNER_SVS,    0, 4 },
-	{ 1,  384000, ACPUPLL, 5, 2,   CPR_CORNER_SVS,    0, 4 },
-	{ 1,  600000, PLL0,    4, 0,   CPR_CORNER_NORMAL, 0, 6 },
-	{ 1,  787200, ACPUPLL, 5, 0,   CPR_CORNER_NORMAL, 0, 6 },
-	{ 1,  998400, ACPUPLL, 5, 0,   CPR_CORNER_TURBO,  0, 7 },
-	{ 1, 1094400, ACPUPLL, 5, 0,   CPR_CORNER_TURBO,  0, 7 },
-	{ 1, 1190400, ACPUPLL, 5, 0,   CPR_CORNER_TURBO,  0, 7 },
-	{ 1, 1305600, ACPUPLL, 5, 0,   CPR_CORNER_TURBO,  0, 7 },
-	{ 1, 1344000, ACPUPLL, 5, 0,   CPR_CORNER_TURBO,  0, 7 },
-	{ 1, 1401600, ACPUPLL, 5, 0,   CPR_CORNER_TURBO,  0, 7 },
+	{ 1,  300000, PLL0,    4, 2,   CPR_CORNER_2,    0, 4 },
+	{ 1,  384000, ACPUPLL, 5, 2,   CPR_CORNER_2,    0, 4 },
+	{ 1,  600000, PLL0,    4, 0,   CPR_CORNER_4, 0, 6 },
+	{ 1,  787200, ACPUPLL, 5, 0,   CPR_CORNER_4, 0, 6 },
+	{ 1,  998400, ACPUPLL, 5, 0,   CPR_CORNER_12,  0, 7 },
+	{ 1, 1094400, ACPUPLL, 5, 0,   CPR_CORNER_12,  0, 7 },
+	{ 1, 1190400, ACPUPLL, 5, 0,   CPR_CORNER_12,  0, 7 },
+	{ 1, 1305600, ACPUPLL, 5, 0,   CPR_CORNER_12,  0, 7 },
+	{ 1, 1344000, ACPUPLL, 5, 0,   CPR_CORNER_12,  0, 7 },
+	{ 1, 1401600, ACPUPLL, 5, 0,   CPR_CORNER_12,  0, 7 },
 	{ 0 }
 };
 
 static struct clkctl_acpu_speed acpu_freq_tbl_8226_1p6[] = {
-	{ 1,  300000, PLL0,    4, 2,   CPR_CORNER_SVS,    0, 4 },
-	{ 1,  384000, ACPUPLL, 5, 2,   CPR_CORNER_SVS,    0, 4 },
-	{ 1,  600000, PLL0,    4, 0,   CPR_CORNER_NORMAL, 0, 6 },
-	{ 1,  787200, ACPUPLL, 5, 0,   CPR_CORNER_NORMAL, 0, 6 },
-	{ 1,  998400, ACPUPLL, 5, 0,   CPR_CORNER_TURBO,  0, 7 },
-	{ 1, 1094400, ACPUPLL, 5, 0,   CPR_CORNER_TURBO,  0, 7 },
-	{ 1, 1190400, ACPUPLL, 5, 0,   CPR_CORNER_TURBO,  0, 7 },
-	{ 1, 1305600, ACPUPLL, 5, 0,   CPR_CORNER_TURBO,  0, 7 },
-	{ 1, 1344000, ACPUPLL, 5, 0,   CPR_CORNER_TURBO,  0, 7 },
-	{ 1, 1401600, ACPUPLL, 5, 0,   CPR_CORNER_TURBO,  0, 7 },
-	{ 1, 1497600, ACPUPLL, 5, 0,   CPR_CORNER_TURBO,  0, 7 },
-	{ 1, 1593600, ACPUPLL, 5, 0,   CPR_CORNER_TURBO,  0, 7 },
+	{ 1,  300000, PLL0,    4, 2,   CPR_CORNER_2,    0, 4 },
+	{ 1,  384000, ACPUPLL, 5, 2,   CPR_CORNER_2,    0, 4 },
+	{ 1,  600000, PLL0,    4, 0,   CPR_CORNER_4, 0, 6 },
+	{ 1,  787200, ACPUPLL, 5, 0,   CPR_CORNER_4, 0, 6 },
+	{ 1,  998400, ACPUPLL, 5, 0,   CPR_CORNER_5,  0, 7 },
+	{ 1, 1094400, ACPUPLL, 5, 0,   CPR_CORNER_6,  0, 7 },
+	{ 1, 1190400, ACPUPLL, 5, 0,   CPR_CORNER_7,  0, 7 },
+	{ 1, 1305600, ACPUPLL, 5, 0,   CPR_CORNER_8,  0, 7 },
+	{ 1, 1344000, ACPUPLL, 5, 0,   CPR_CORNER_9,  0, 7 },
+	{ 1, 1401600, ACPUPLL, 5, 0,   CPR_CORNER_10,  0, 7 },
+	{ 1, 1497600, ACPUPLL, 5, 0,   CPR_CORNER_11,  0, 7 },
+	{ 1, 1593600, ACPUPLL, 5, 0,   CPR_CORNER_12,  0, 7 },
 	{ 0 }
 };
 
 static struct clkctl_acpu_speed acpu_freq_tbl_8610[] = {
-	{ 1,  300000, PLL0,    4, 2,   CPR_CORNER_SVS,    0, 3 },
-	{ 1,  384000, ACPUPLL, 5, 2,   CPR_CORNER_SVS,    0, 3 },
-	{ 1,  600000, PLL0,    4, 0,   CPR_CORNER_NORMAL, 0, 4 },
-	{ 1,  787200, ACPUPLL, 5, 0,   CPR_CORNER_NORMAL, 0, 4 },
-	{ 1,  998400, ACPUPLL, 5, 0,   CPR_CORNER_TURBO,  0, 5 },
-	{ 1, 1190400, ACPUPLL, 5, 0,   CPR_CORNER_TURBO,  0, 5 },
+	{ 1,  300000, PLL0,    4, 2,   CPR_CORNER_2,    0, 3 },
+	{ 1,  384000, ACPUPLL, 5, 2,   CPR_CORNER_2,    0, 3 },
+	{ 1,  600000, PLL0,    4, 0,   CPR_CORNER_4, 0, 4 },
+	{ 1,  787200, ACPUPLL, 5, 0,   CPR_CORNER_4, 0, 4 },
+	{ 1,  998400, ACPUPLL, 5, 0,   CPR_CORNER_12,  0, 5 },
+	{ 1, 1190400, ACPUPLL, 5, 0,   CPR_CORNER_12,  0, 5 },
 	{ 0 }
 };
 
@@ -135,7 +135,7 @@
 	.freq_tbl = acpu_freq_tbl_8226_1p1,
 	.pvs_tables = pvs_tables_8226,
 	.bus_scale = &bus_client_pdata,
-	.vdd_max_cpu = CPR_CORNER_TURBO,
+	.vdd_max_cpu = CPR_CORNER_12,
 	.src_clocks = {
 		[PLL0].name = "gpll0",
 		[ACPUPLL].name = "a7sspll",
diff --git a/arch/arm/mach-msm/bam_dmux.c b/arch/arm/mach-msm/bam_dmux.c
index 6281395..b618cd4 100644
--- a/arch/arm/mach-msm/bam_dmux.c
+++ b/arch/arm/mach-msm/bam_dmux.c
@@ -28,6 +28,7 @@
 #include <linux/wakelock.h>
 #include <linux/kfifo.h>
 #include <linux/of.h>
+#include <linux/srcu.h>
 #include <mach/msm_ipc_logging.h>
 #include <mach/sps.h>
 #include <mach/bam_dmux.h>
@@ -36,19 +37,12 @@
 #include <mach/socinfo.h>
 #include <mach/subsystem_restart.h>
 
+#include "bam_dmux_private.h"
+
 #define BAM_CH_LOCAL_OPEN       0x1
 #define BAM_CH_REMOTE_OPEN      0x2
 #define BAM_CH_IN_RESET         0x4
 
-#define BAM_MUX_HDR_MAGIC_NO    0x33fc
-
-#define BAM_MUX_HDR_CMD_DATA		0
-#define BAM_MUX_HDR_CMD_OPEN		1
-#define BAM_MUX_HDR_CMD_CLOSE		2
-#define BAM_MUX_HDR_CMD_STATUS		3 /* unused */
-#define BAM_MUX_HDR_CMD_OPEN_NO_A2_PC	4
-
-
 #define LOW_WATERMARK		2
 #define HIGH_WATERMARK		4
 #define DEFAULT_POLLING_MIN_SLEEP (950)
@@ -58,20 +52,47 @@
 static int msm_bam_dmux_debug_enable;
 module_param_named(debug_enable, msm_bam_dmux_debug_enable,
 		   int, S_IRUGO | S_IWUSR | S_IWGRP);
-static int POLLING_MIN_SLEEP = 950;
+static int POLLING_MIN_SLEEP = 2950;
 module_param_named(min_sleep, POLLING_MIN_SLEEP,
 		   int, S_IRUGO | S_IWUSR | S_IWGRP);
-static int POLLING_MAX_SLEEP = 1050;
+static int POLLING_MAX_SLEEP = 3050;
 module_param_named(max_sleep, POLLING_MAX_SLEEP,
 		   int, S_IRUGO | S_IWUSR | S_IWGRP);
-static int POLLING_INACTIVITY = 40;
+static int POLLING_INACTIVITY = 1;
 module_param_named(inactivity, POLLING_INACTIVITY,
 		   int, S_IRUGO | S_IWUSR | S_IWGRP);
-static int bam_adaptive_timer_enabled = 1;
+static int bam_adaptive_timer_enabled;
 module_param_named(adaptive_timer_enabled,
 			bam_adaptive_timer_enabled,
 		   int, S_IRUGO | S_IWUSR | S_IWGRP);
 
+static struct bam_ops_if bam_default_ops = {
+	/* smsm */
+	.smsm_change_state_ptr = &smsm_change_state,
+	.smsm_get_state_ptr = &smsm_get_state,
+	.smsm_state_cb_register_ptr = &smsm_state_cb_register,
+	.smsm_state_cb_deregister_ptr = &smsm_state_cb_deregister,
+
+	/* sps */
+	.sps_connect_ptr = &sps_connect,
+	.sps_disconnect_ptr = &sps_disconnect,
+	.sps_register_bam_device_ptr = &sps_register_bam_device,
+	.sps_deregister_bam_device_ptr = &sps_deregister_bam_device,
+	.sps_alloc_endpoint_ptr = &sps_alloc_endpoint,
+	.sps_free_endpoint_ptr = &sps_free_endpoint,
+	.sps_set_config_ptr = &sps_set_config,
+	.sps_get_config_ptr = &sps_get_config,
+	.sps_device_reset_ptr = &sps_device_reset,
+	.sps_register_event_ptr = &sps_register_event,
+	.sps_transfer_one_ptr = &sps_transfer_one,
+	.sps_get_iovec_ptr = &sps_get_iovec,
+	.sps_get_unused_desc_num_ptr = &sps_get_unused_desc_num,
+
+	.dma_to = DMA_TO_DEVICE,
+	.dma_from = DMA_FROM_DEVICE,
+};
+static struct bam_ops_if *bam_ops = &bam_default_ops;
+
 #if defined(DEBUG)
 static uint32_t bam_dmux_read_cnt;
 static uint32_t bam_dmux_write_cnt;
@@ -151,29 +172,10 @@
 	int use_wm;
 };
 
-struct tx_pkt_info {
-	struct sk_buff *skb;
-	dma_addr_t dma_address;
-	char is_cmd;
-	uint32_t len;
-	struct work_struct work;
-	struct list_head list_node;
-	unsigned ts_sec;
-	unsigned long ts_nsec;
-};
-
-struct rx_pkt_info {
-	struct sk_buff *skb;
-	dma_addr_t dma_address;
-	struct work_struct work;
-	struct list_head list_node;
-};
-
 #define A2_NUM_PIPES		6
 #define A2_SUMMING_THRESHOLD	4096
 #define A2_PHYS_BASE		0x124C2000
 #define A2_PHYS_SIZE		0x2000
-#define BUFFER_SIZE		2048
 #define DEFAULT_NUM_BUFFERS	32
 
 #ifndef A2_BAM_IRQ
@@ -210,26 +212,20 @@
 static DEFINE_SPINLOCK(bam_tx_pool_spinlock);
 static DEFINE_MUTEX(bam_pdev_mutexlock);
 
-struct bam_mux_hdr {
-	uint16_t magic_num;
-	uint8_t reserved;
-	uint8_t cmd;
-	uint8_t pad_len;
-	uint8_t ch_id;
-	uint16_t pkt_len;
-};
-
 static void notify_all(int event, unsigned long data);
 static void bam_mux_write_done(struct work_struct *work);
 static void handle_bam_mux_cmd(struct work_struct *work);
 static void rx_timer_work_func(struct work_struct *work);
+static void queue_rx_work_func(struct work_struct *work);
 
 static DECLARE_WORK(rx_timer_work, rx_timer_work_func);
-static struct delayed_work queue_rx_work;
+static DECLARE_WORK(queue_rx_work, queue_rx_work_func);
 
 static struct workqueue_struct *bam_mux_rx_workqueue;
 static struct workqueue_struct *bam_mux_tx_workqueue;
 
+static struct srcu_struct bam_dmux_srcu;
+
 /* A2 power collaspe */
 #define UL_TIMEOUT_DELAY 1000	/* in ms */
 #define ENABLE_DISCONNECT_ACK	0x1
@@ -390,7 +386,7 @@
 	spin_unlock_irqrestore(&bam_tx_pool_spinlock, flags);
 }
 
-static void queue_rx(void)
+static void __queue_rx(gfp_t alloc_flags)
 {
 	void *ptr;
 	struct rx_pkt_info *info;
@@ -405,29 +401,29 @@
 		if (in_global_reset)
 			goto fail;
 
-		info = kmalloc(sizeof(struct rx_pkt_info),
-						GFP_NOWAIT | __GFP_NOWARN);
+		info = kmalloc(sizeof(struct rx_pkt_info), alloc_flags);
 		if (!info) {
 			DMUX_LOG_KERR(
-			"%s: unable to alloc rx_pkt_info, will retry later\n",
-								__func__);
+			"%s: unable to alloc rx_pkt_info w/ flags %x, will retry later\n",
+								__func__,
+								alloc_flags);
 			goto fail;
 		}
 
 		INIT_WORK(&info->work, handle_bam_mux_cmd);
 
-		info->skb = __dev_alloc_skb(BUFFER_SIZE,
-						GFP_NOWAIT | __GFP_NOWARN);
+		info->skb = __dev_alloc_skb(BUFFER_SIZE, alloc_flags);
 		if (info->skb == NULL) {
 			DMUX_LOG_KERR(
-				"%s: unable to alloc skb, will retry later\n",
-								__func__);
+				"%s: unable to alloc skb w/ flags %x, will retry later\n",
+								__func__,
+								alloc_flags);
 			goto fail_info;
 		}
 		ptr = skb_put(info->skb, BUFFER_SIZE);
 
 		info->dma_address = dma_map_single(NULL, ptr, BUFFER_SIZE,
-							DMA_FROM_DEVICE);
+							bam_ops->dma_from);
 		if (info->dma_address == 0 || info->dma_address == ~0) {
 			DMUX_LOG_KERR("%s: dma_map_single failure %p for %p\n",
 				__func__, (void *)info->dma_address, ptr);
@@ -437,8 +433,8 @@
 		mutex_lock(&bam_rx_pool_mutexlock);
 		list_add_tail(&info->list_node, &bam_rx_pool);
 		rx_len_cached = ++bam_rx_pool_len;
-		ret = sps_transfer_one(bam_rx_pipe, info->dma_address,
-			BUFFER_SIZE, info, 0);
+		ret = bam_ops->sps_transfer_one_ptr(bam_rx_pipe,
+				info->dma_address, BUFFER_SIZE, info, 0);
 		if (ret) {
 			list_del(&info->list_node);
 			rx_len_cached = --bam_rx_pool_len;
@@ -447,7 +443,7 @@
 				__func__, ret);
 
 			dma_unmap_single(NULL, info->dma_address, BUFFER_SIZE,
-						DMA_FROM_DEVICE);
+						bam_ops->dma_from);
 
 			goto fail_skb;
 		}
@@ -463,15 +459,30 @@
 	kfree(info);
 
 fail:
-	if (rx_len_cached == 0 && !in_global_reset) {
+	if (!in_global_reset) {
 		DMUX_LOG_KERR("%s: rescheduling\n", __func__);
-		schedule_delayed_work(&queue_rx_work, msecs_to_jiffies(100));
+		schedule_work(&queue_rx_work);
 	}
 }
 
+static void queue_rx(void)
+{
+	/*
+	 * Hot path.  Delays waiting for the allocation to find memory if its
+	 * not immediately available, and delays from logging allocation
+	 * failures which cannot be tolerated at this time.
+	 */
+	__queue_rx(GFP_NOWAIT | __GFP_NOWARN);
+}
+
 static void queue_rx_work_func(struct work_struct *work)
 {
-	queue_rx();
+	/*
+	 * Cold path.  Delays can be tolerated.  Use of GFP_KERNEL should
+	 * guarentee the requested memory will be found, after some ammount of
+	 * delay.
+	 */
+	__queue_rx(GFP_KERNEL);
 }
 
 static void bam_mux_process_data(struct sk_buff *rx_skb)
@@ -535,7 +546,8 @@
 
 	info = container_of(work, struct rx_pkt_info, work);
 	rx_skb = info->skb;
-	dma_unmap_single(NULL, info->dma_address, BUFFER_SIZE, DMA_FROM_DEVICE);
+	dma_unmap_single(NULL, info->dma_address, BUFFER_SIZE,
+			bam_ops->dma_from);
 	kfree(info);
 
 	rx_hdr = (struct bam_mux_hdr *)rx_skb->data;
@@ -644,7 +656,7 @@
 	}
 
 	dma_address = dma_map_single(NULL, data, len,
-					DMA_TO_DEVICE);
+					bam_ops->dma_to);
 	if (!dma_address) {
 		pr_err("%s: dma_map_single() failed\n", __func__);
 		kfree(pkt);
@@ -659,7 +671,7 @@
 	INIT_WORK(&pkt->work, bam_mux_write_done);
 	spin_lock_irqsave(&bam_tx_pool_spinlock, flags);
 	list_add_tail(&pkt->list_node, &bam_tx_pool);
-	rc = sps_transfer_one(bam_tx_pipe, dma_address, len,
+	rc = bam_ops->sps_transfer_one_ptr(bam_tx_pipe, dma_address, len,
 				pkt, SPS_IOVEC_FLAG_EOT);
 	if (rc) {
 		DMUX_LOG_KERR("%s sps_transfer_one failed rc=%d\n",
@@ -669,7 +681,7 @@
 		spin_unlock_irqrestore(&bam_tx_pool_spinlock, flags);
 		dma_unmap_single(NULL, pkt->dma_address,
 					pkt->len,
-					DMA_TO_DEVICE);
+					bam_ops->dma_to);
 		kfree(pkt);
 	} else {
 		spin_unlock_irqrestore(&bam_tx_pool_spinlock, flags);
@@ -746,6 +758,7 @@
 	struct sk_buff *new_skb = NULL;
 	dma_addr_t dma_address;
 	struct tx_pkt_info *pkt;
+	int rcu_id;
 
 	if (id >= BAM_DMUX_NUM_CHANNELS)
 		return -EINVAL;
@@ -754,11 +767,19 @@
 	if (!bam_mux_initialized)
 		return -ENODEV;
 
+	rcu_id = srcu_read_lock(&bam_dmux_srcu);
+	if (in_global_reset) {
+		BAM_DMUX_LOG("%s: In SSR... ch_id[%d]\n", __func__, id);
+		srcu_read_unlock(&bam_dmux_srcu, rcu_id);
+		return -EFAULT;
+	}
+
 	DBG("%s: writing to ch %d len %d\n", __func__, id, skb->len);
 	spin_lock_irqsave(&bam_ch[id].lock, flags);
 	if (!bam_ch_is_open(id)) {
 		spin_unlock_irqrestore(&bam_ch[id].lock, flags);
 		pr_err("%s: port not open: %d\n", __func__, bam_ch[id].status);
+		srcu_read_unlock(&bam_dmux_srcu, rcu_id);
 		return -ENODEV;
 	}
 
@@ -766,6 +787,7 @@
 	    (bam_ch[id].num_tx_pkts >= HIGH_WATERMARK)) {
 		spin_unlock_irqrestore(&bam_ch[id].lock, flags);
 		pr_err("%s: watermark exceeded: %d\n", __func__, id);
+		srcu_read_unlock(&bam_dmux_srcu, rcu_id);
 		return -EAGAIN;
 	}
 	spin_unlock_irqrestore(&bam_ch[id].lock, flags);
@@ -774,8 +796,10 @@
 	if (!bam_is_connected) {
 		read_unlock(&ul_wakeup_lock);
 		ul_wakeup();
-		if (unlikely(in_global_reset == 1))
+		if (unlikely(in_global_reset == 1)) {
+			srcu_read_unlock(&bam_dmux_srcu, rcu_id);
 			return -EFAULT;
+		}
 		read_lock(&ul_wakeup_lock);
 		notify_all(BAM_DMUX_UL_CONNECTED, (unsigned long)(NULL));
 	}
@@ -820,7 +844,7 @@
 	}
 
 	dma_address = dma_map_single(NULL, skb->data, skb->len,
-					DMA_TO_DEVICE);
+					bam_ops->dma_to);
 	if (!dma_address) {
 		pr_err("%s: dma_map_single() failed\n", __func__);
 		goto write_fail3;
@@ -832,7 +856,7 @@
 	INIT_WORK(&pkt->work, bam_mux_write_done);
 	spin_lock_irqsave(&bam_tx_pool_spinlock, flags);
 	list_add_tail(&pkt->list_node, &bam_tx_pool);
-	rc = sps_transfer_one(bam_tx_pipe, dma_address, skb->len,
+	rc = bam_ops->sps_transfer_one_ptr(bam_tx_pipe, dma_address, skb->len,
 				pkt, SPS_IOVEC_FLAG_EOT);
 	if (rc) {
 		DMUX_LOG_KERR("%s sps_transfer_one failed rc=%d\n",
@@ -841,7 +865,7 @@
 		DBG_INC_TX_SPS_FAILURE_CNT();
 		spin_unlock_irqrestore(&bam_tx_pool_spinlock, flags);
 		dma_unmap_single(NULL, pkt->dma_address,
-					pkt->skb->len,	DMA_TO_DEVICE);
+					pkt->skb->len,	bam_ops->dma_to);
 		kfree(pkt);
 		if (new_skb)
 			dev_kfree_skb_any(new_skb);
@@ -853,6 +877,7 @@
 	}
 	ul_packet_written = 1;
 	read_unlock(&ul_wakeup_lock);
+	srcu_read_unlock(&bam_dmux_srcu, rcu_id);
 	return rc;
 
 write_fail3:
@@ -863,6 +888,7 @@
 		dev_kfree_skb_any(new_skb);
 write_fail:
 	read_unlock(&ul_wakeup_lock);
+	srcu_read_unlock(&bam_dmux_srcu, rcu_id);
 	return -ENOMEM;
 }
 
@@ -1049,14 +1075,14 @@
 	 * Attempt to enable interrupts - if this fails,
 	 * continue polling and we will retry later.
 	 */
-	ret = sps_get_config(bam_rx_pipe, &cur_rx_conn);
+	ret = bam_ops->sps_get_config_ptr(bam_rx_pipe, &cur_rx_conn);
 	if (ret) {
 		pr_err("%s: sps_get_config() failed %d\n", __func__, ret);
 		goto fail;
 	}
 
 	rx_register_event.options = SPS_O_EOT;
-	ret = sps_register_event(bam_rx_pipe, &rx_register_event);
+	ret = bam_ops->sps_register_event_ptr(bam_rx_pipe, &rx_register_event);
 	if (ret) {
 		pr_err("%s: sps_register_event() failed %d\n", __func__, ret);
 		goto fail;
@@ -1064,7 +1090,7 @@
 
 	cur_rx_conn.options = SPS_O_AUTO_ENABLE |
 		SPS_O_EOT | SPS_O_ACK_TRANSFERS;
-	ret = sps_set_config(bam_rx_pipe, &cur_rx_conn);
+	ret = bam_ops->sps_set_config_ptr(bam_rx_pipe, &cur_rx_conn);
 	if (ret) {
 		pr_err("%s: sps_set_config() failed %d\n", __func__, ret);
 		goto fail;
@@ -1075,7 +1101,7 @@
 
 	/* handle any rx packets before interrupt was enabled */
 	while (bam_connection_is_active && !polling_mode) {
-		ret = sps_get_iovec(bam_rx_pipe, &iov);
+		ret = bam_ops->sps_get_iovec_ptr(bam_rx_pipe, &iov);
 		if (ret) {
 			pr_err("%s: sps_get_iovec failed %d\n",
 					__func__, ret);
@@ -1160,7 +1186,7 @@
 				return;
 			}
 
-			ret = sps_get_iovec(bam_rx_pipe, &iov);
+			ret = bam_ops->sps_get_iovec_ptr(bam_rx_pipe, &iov);
 			if (ret) {
 				DMUX_LOG_KERR("%s: sps_get_iovec failed %d\n",
 						__func__, ret);
@@ -1209,7 +1235,7 @@
 		if (bam_adaptive_timer_enabled) {
 			usleep_range(rx_timer_interval, rx_timer_interval + 50);
 
-			ret = sps_get_unused_desc_num(bam_rx_pipe,
+			ret = bam_ops->sps_get_unused_desc_num_ptr(bam_rx_pipe,
 						&buffs_unused);
 
 			if (ret) {
@@ -1261,11 +1287,11 @@
 		if (!pkt->is_cmd)
 			dma_unmap_single(NULL, pkt->dma_address,
 						pkt->skb->len,
-						DMA_TO_DEVICE);
+						bam_ops->dma_to);
 		else
 			dma_unmap_single(NULL, pkt->dma_address,
 						pkt->len,
-						DMA_TO_DEVICE);
+						bam_ops->dma_to);
 		queue_work(bam_mux_tx_workqueue, &pkt->work);
 		break;
 	default:
@@ -1288,7 +1314,8 @@
 	case SPS_EVENT_EOT:
 		/* attempt to disable interrupts in this pipe */
 		if (!polling_mode) {
-			ret = sps_get_config(bam_rx_pipe, &cur_rx_conn);
+			ret = bam_ops->sps_get_config_ptr(bam_rx_pipe,
+					&cur_rx_conn);
 			if (ret) {
 				pr_err("%s: sps_get_config() failed %d, interrupts"
 					" not disabled\n", __func__, ret);
@@ -1296,7 +1323,8 @@
 			}
 			cur_rx_conn.options = SPS_O_AUTO_ENABLE |
 				SPS_O_ACK_TRANSFERS | SPS_O_POLL;
-			ret = sps_set_config(bam_rx_pipe, &cur_rx_conn);
+			ret = bam_ops->sps_set_config_ptr(bam_rx_pipe,
+					&cur_rx_conn);
 			if (ret) {
 				pr_err("%s: sps_set_config() failed %d, interrupts"
 					" not disabled\n", __func__, ret);
@@ -1476,9 +1504,11 @@
 
 	bam_dmux_uplink_vote = vote;
 	if (vote)
-		smsm_change_state(SMSM_APPS_STATE, 0, SMSM_A2_POWER_CONTROL);
+		bam_ops->smsm_change_state_ptr(SMSM_APPS_STATE,
+			0, SMSM_A2_POWER_CONTROL);
 	else
-		smsm_change_state(SMSM_APPS_STATE, SMSM_A2_POWER_CONTROL, 0);
+		bam_ops->smsm_change_state_ptr(SMSM_APPS_STATE,
+			SMSM_A2_POWER_CONTROL, 0);
 }
 
 /*
@@ -1747,29 +1777,31 @@
 	if (!power_management_only_mode) {
 		if (ssr_skipped_disconnect) {
 			/* delayed to here to prevent bus stall */
-			sps_disconnect(bam_tx_pipe);
-			sps_disconnect(bam_rx_pipe);
+			bam_ops->sps_disconnect_ptr(bam_tx_pipe);
+			bam_ops->sps_disconnect_ptr(bam_rx_pipe);
 			__memzero(rx_desc_mem_buf.base, rx_desc_mem_buf.size);
 			__memzero(tx_desc_mem_buf.base, tx_desc_mem_buf.size);
 		}
 		ssr_skipped_disconnect = 0;
-		i = sps_device_reset(a2_device_handle);
+		i = bam_ops->sps_device_reset_ptr(a2_device_handle);
 		if (i)
 			pr_err("%s: device reset failed rc = %d\n", __func__,
 									i);
-		i = sps_connect(bam_tx_pipe, &tx_connection);
+		i = bam_ops->sps_connect_ptr(bam_tx_pipe, &tx_connection);
 		if (i)
 			pr_err("%s: tx connection failed rc = %d\n", __func__,
 									i);
-		i = sps_connect(bam_rx_pipe, &rx_connection);
+		i = bam_ops->sps_connect_ptr(bam_rx_pipe, &rx_connection);
 		if (i)
 			pr_err("%s: rx connection failed rc = %d\n", __func__,
 									i);
-		i = sps_register_event(bam_tx_pipe, &tx_register_event);
+		i = bam_ops->sps_register_event_ptr(bam_tx_pipe,
+				&tx_register_event);
 		if (i)
 			pr_err("%s: tx event reg failed rc = %d\n", __func__,
 									i);
-		i = sps_register_event(bam_rx_pipe, &rx_register_event);
+		i = bam_ops->sps_register_event_ptr(bam_rx_pipe,
+				&rx_register_event);
 		if (i)
 			pr_err("%s: rx event reg failed rc = %d\n", __func__,
 									i);
@@ -1823,9 +1855,9 @@
 	if (!power_management_only_mode) {
 		if (likely(!in_ssr)) {
 			BAM_DMUX_LOG("%s: disconnect tx\n", __func__);
-			sps_disconnect(bam_tx_pipe);
+			bam_ops->sps_disconnect_ptr(bam_tx_pipe);
 			BAM_DMUX_LOG("%s: disconnect rx\n", __func__);
-			sps_disconnect(bam_rx_pipe);
+			bam_ops->sps_disconnect_ptr(bam_rx_pipe);
 			__memzero(rx_desc_mem_buf.base, rx_desc_mem_buf.size);
 			__memzero(tx_desc_mem_buf.base, tx_desc_mem_buf.size);
 			BAM_DMUX_LOG("%s: device reset\n", __func__);
@@ -1842,7 +1874,7 @@
 		list_del(node);
 		info = container_of(node, struct rx_pkt_info, list_node);
 		dma_unmap_single(NULL, info->dma_address, BUFFER_SIZE,
-							DMA_FROM_DEVICE);
+							bam_ops->dma_from);
 		dev_kfree_skb_any(info->skb);
 		kfree(info);
 	}
@@ -1957,9 +1989,12 @@
 	 * because a watchdog crash from a bus stall would likely occur.
 	 */
 	if (code == SUBSYS_BEFORE_SHUTDOWN) {
+		BAM_DMUX_LOG("%s: begin\n", __func__);
 		in_global_reset = 1;
 		in_ssr = 1;
-		BAM_DMUX_LOG("%s: begin\n", __func__);
+		/* wait till all bam_dmux writes completes */
+		synchronize_srcu(&bam_dmux_srcu);
+		BAM_DMUX_LOG("%s: ssr signaling complete\n", __func__);
 		flush_workqueue(bam_mux_rx_workqueue);
 	}
 	if (code != SUBSYS_AFTER_SHUTDOWN)
@@ -2008,12 +2043,12 @@
 		if (!info->is_cmd) {
 			dma_unmap_single(NULL, info->dma_address,
 						info->skb->len,
-						DMA_TO_DEVICE);
+						bam_ops->dma_to);
 			dev_kfree_skb_any(info->skb);
 		} else {
 			dma_unmap_single(NULL, info->dma_address,
 						info->len,
-						DMA_TO_DEVICE);
+						bam_ops->dma_to);
 			kfree(info->skb);
 		}
 		kfree(info);
@@ -2053,20 +2088,20 @@
 	if (cpu_is_msm9615() || satellite_mode)
 		a2_props.manage = SPS_BAM_MGR_DEVICE_REMOTE;
 	/* need to free on tear down */
-	ret = sps_register_bam_device(&a2_props, &h);
+	ret = bam_ops->sps_register_bam_device_ptr(&a2_props, &h);
 	if (ret < 0) {
 		pr_err("%s: register bam error %d\n", __func__, ret);
 		goto register_bam_failed;
 	}
 	a2_device_handle = h;
 
-	bam_tx_pipe = sps_alloc_endpoint();
+	bam_tx_pipe = bam_ops->sps_alloc_endpoint_ptr();
 	if (bam_tx_pipe == NULL) {
 		pr_err("%s: tx alloc endpoint failed\n", __func__);
 		ret = -ENOMEM;
 		goto tx_alloc_endpoint_failed;
 	}
-	ret = sps_get_config(bam_tx_pipe, &tx_connection);
+	ret = bam_ops->sps_get_config_ptr(bam_tx_pipe, &tx_connection);
 	if (ret) {
 		pr_err("%s: tx get config failed %d\n", __func__, ret);
 		goto tx_get_config_failed;
@@ -2091,19 +2126,19 @@
 	tx_connection.desc = tx_desc_mem_buf;
 	tx_connection.event_thresh = 0x10;
 
-	ret = sps_connect(bam_tx_pipe, &tx_connection);
+	ret = bam_ops->sps_connect_ptr(bam_tx_pipe, &tx_connection);
 	if (ret < 0) {
 		pr_err("%s: tx connect error %d\n", __func__, ret);
 		goto tx_connect_failed;
 	}
 
-	bam_rx_pipe = sps_alloc_endpoint();
+	bam_rx_pipe = bam_ops->sps_alloc_endpoint_ptr();
 	if (bam_rx_pipe == NULL) {
 		pr_err("%s: rx alloc endpoint failed\n", __func__);
 		ret = -ENOMEM;
 		goto rx_alloc_endpoint_failed;
 	}
-	ret = sps_get_config(bam_rx_pipe, &rx_connection);
+	ret = bam_ops->sps_get_config_ptr(bam_rx_pipe, &rx_connection);
 	if (ret) {
 		pr_err("%s: rx get config failed %d\n", __func__, ret);
 		goto rx_get_config_failed;
@@ -2129,7 +2164,7 @@
 	rx_connection.desc = rx_desc_mem_buf;
 	rx_connection.event_thresh = 0x10;
 
-	ret = sps_connect(bam_rx_pipe, &rx_connection);
+	ret = bam_ops->sps_connect_ptr(bam_rx_pipe, &rx_connection);
 	if (ret < 0) {
 		pr_err("%s: rx connect error %d\n", __func__, ret);
 		goto rx_connect_failed;
@@ -2140,7 +2175,7 @@
 	tx_register_event.xfer_done = NULL;
 	tx_register_event.callback = bam_mux_tx_notify;
 	tx_register_event.user = NULL;
-	ret = sps_register_event(bam_tx_pipe, &tx_register_event);
+	ret = bam_ops->sps_register_event_ptr(bam_tx_pipe, &tx_register_event);
 	if (ret < 0) {
 		pr_err("%s: tx register event error %d\n", __func__, ret);
 		goto rx_event_reg_failed;
@@ -2151,7 +2186,7 @@
 	rx_register_event.xfer_done = NULL;
 	rx_register_event.callback = bam_mux_rx_notify;
 	rx_register_event.user = NULL;
-	ret = sps_register_event(bam_rx_pipe, &rx_register_event);
+	ret = bam_ops->sps_register_event_ptr(bam_rx_pipe, &rx_register_event);
 	if (ret < 0) {
 		pr_err("%s: tx register event error %d\n", __func__, ret);
 		goto rx_event_reg_failed;
@@ -2171,22 +2206,22 @@
 	return 0;
 
 rx_event_reg_failed:
-	sps_disconnect(bam_rx_pipe);
+	bam_ops->sps_disconnect_ptr(bam_rx_pipe);
 rx_connect_failed:
 	dma_free_coherent(NULL, rx_desc_mem_buf.size, rx_desc_mem_buf.base,
 				rx_desc_mem_buf.phys_base);
 rx_mem_failed:
 rx_get_config_failed:
-	sps_free_endpoint(bam_rx_pipe);
+	bam_ops->sps_free_endpoint_ptr(bam_rx_pipe);
 rx_alloc_endpoint_failed:
-	sps_disconnect(bam_tx_pipe);
+	bam_ops->sps_disconnect_ptr(bam_tx_pipe);
 tx_connect_failed:
 	dma_free_coherent(NULL, tx_desc_mem_buf.size, tx_desc_mem_buf.base,
 				tx_desc_mem_buf.phys_base);
 tx_get_config_failed:
-	sps_free_endpoint(bam_tx_pipe);
+	bam_ops->sps_free_endpoint_ptr(bam_tx_pipe);
 tx_alloc_endpoint_failed:
-	sps_deregister_bam_device(h);
+	bam_ops->sps_deregister_bam_device_ptr(h);
 	/*
 	 * sps_deregister_bam_device() calls iounmap.  calling iounmap on the
 	 * same handle below will cause a crash, so skip it if we've freed
@@ -2224,7 +2259,7 @@
 	a2_props.summing_threshold = A2_SUMMING_THRESHOLD;
 	if (cpu_is_msm9615() || satellite_mode)
 		a2_props.manage = SPS_BAM_MGR_DEVICE_REMOTE;
-	ret = sps_register_bam_device(&a2_props, &h);
+	ret = bam_ops->sps_register_bam_device_ptr(&a2_props, &h);
 	if (ret < 0) {
 		pr_err("%s: register bam error %d\n", __func__, ret);
 		goto register_bam_failed;
@@ -2276,7 +2311,7 @@
 
 	BAM_DMUX_LOG("%s: apps ack %d->%d\n", __func__,
 			clear_bit & 0x1, ~clear_bit & 0x1);
-	smsm_change_state(SMSM_APPS_STATE,
+	bam_ops->smsm_change_state_ptr(SMSM_APPS_STATE,
 				clear_bit & SMSM_A2_POWER_CONTROL_ACK,
 				~clear_bit & SMSM_A2_POWER_CONTROL_ACK);
 	clear_bit = ~clear_bit;
@@ -2333,6 +2368,51 @@
 	complete_all(&ul_wakeup_ack_completion);
 }
 
+/**
+ * msm_bam_dmux_set_bam_ops() - sets the bam_ops
+ * @ops: bam_ops_if to set
+ *
+ * Sets bam_ops to allow switching of runtime behavior. Preconditon, bam dmux
+ * must be in an idle state. If input ops is NULL, then bam_ops will be
+ * restored to their default state.
+ */
+void msm_bam_dmux_set_bam_ops(struct bam_ops_if *ops)
+{
+	if (ops != NULL)
+		bam_ops = ops;
+	else
+		bam_ops = &bam_default_ops;
+}
+EXPORT_SYMBOL(msm_bam_dmux_set_bam_ops);
+
+/**
+ * msm_bam_dmux_deinit() - puts bam dmux into a deinited state
+ *
+ * Puts bam dmux into a deinitialized state by simulating an ssr.
+ */
+void msm_bam_dmux_deinit(void)
+{
+	restart_notifier_cb(NULL, SUBSYS_BEFORE_SHUTDOWN, NULL);
+	restart_notifier_cb(NULL, SUBSYS_AFTER_SHUTDOWN, NULL);
+}
+EXPORT_SYMBOL(msm_bam_dmux_deinit);
+
+/**
+ * msm_bam_dmux_reinit() - reinitializes bam dmux
+ */
+void msm_bam_dmux_reinit(void)
+{
+	bam_ops->smsm_state_cb_register_ptr(SMSM_MODEM_STATE,
+			SMSM_A2_POWER_CONTROL,
+			bam_dmux_smsm_cb, NULL);
+	bam_ops->smsm_state_cb_register_ptr(SMSM_MODEM_STATE,
+			SMSM_A2_POWER_CONTROL_ACK,
+			bam_dmux_smsm_ack_cb, NULL);
+	bam_mux_initialized = 0;
+	bam_init();
+}
+EXPORT_SYMBOL(msm_bam_dmux_reinit);
+
 static int bam_dmux_probe(struct platform_device *pdev)
 {
 	int rc;
@@ -2432,11 +2512,12 @@
 	init_completion(&shutdown_completion);
 	complete_all(&shutdown_completion);
 	INIT_DELAYED_WORK(&ul_timeout_work, ul_timeout);
-	INIT_DELAYED_WORK(&queue_rx_work, queue_rx_work_func);
 	wake_lock_init(&bam_wakelock, WAKE_LOCK_SUSPEND, "bam_dmux_wakelock");
+	init_srcu_struct(&bam_dmux_srcu);
 
-	rc = smsm_state_cb_register(SMSM_MODEM_STATE, SMSM_A2_POWER_CONTROL,
-					bam_dmux_smsm_cb, NULL);
+	rc = bam_ops->smsm_state_cb_register_ptr(SMSM_MODEM_STATE,
+			SMSM_A2_POWER_CONTROL,
+			bam_dmux_smsm_cb, NULL);
 
 	if (rc) {
 		destroy_workqueue(bam_mux_rx_workqueue);
@@ -2445,13 +2526,14 @@
 		return -ENOMEM;
 	}
 
-	rc = smsm_state_cb_register(SMSM_MODEM_STATE, SMSM_A2_POWER_CONTROL_ACK,
-					bam_dmux_smsm_ack_cb, NULL);
+	rc = bam_ops->smsm_state_cb_register_ptr(SMSM_MODEM_STATE,
+			SMSM_A2_POWER_CONTROL_ACK,
+			bam_dmux_smsm_ack_cb, NULL);
 
 	if (rc) {
 		destroy_workqueue(bam_mux_rx_workqueue);
 		destroy_workqueue(bam_mux_tx_workqueue);
-		smsm_state_cb_deregister(SMSM_MODEM_STATE,
+		bam_ops->smsm_state_cb_deregister_ptr(SMSM_MODEM_STATE,
 					SMSM_A2_POWER_CONTROL,
 					bam_dmux_smsm_cb, NULL);
 		pr_err("%s: smsm ack cb register failed, rc: %d\n", __func__,
@@ -2461,8 +2543,10 @@
 		return -ENOMEM;
 	}
 
-	if (smsm_get_state(SMSM_MODEM_STATE) & SMSM_A2_POWER_CONTROL)
-		bam_dmux_smsm_cb(NULL, 0, smsm_get_state(SMSM_MODEM_STATE));
+	if (bam_ops->smsm_get_state_ptr(SMSM_MODEM_STATE) &
+			SMSM_A2_POWER_CONTROL)
+		bam_dmux_smsm_cb(NULL, 0,
+			bam_ops->smsm_get_state_ptr(SMSM_MODEM_STATE));
 
 	return 0;
 }
diff --git a/arch/arm/mach-msm/bam_dmux_private.h b/arch/arm/mach-msm/bam_dmux_private.h
new file mode 100644
index 0000000..871dd64
--- /dev/null
+++ b/arch/arm/mach-msm/bam_dmux_private.h
@@ -0,0 +1,173 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _BAM_DMUX_PRIVATE_H
+#define _BAM_DMUX_PRIVATE_H
+
+#include <linux/types.h>
+#include <linux/dma-mapping.h>
+
+#include <mach/sps.h>
+
+#define BAM_MUX_HDR_MAGIC_NO			0x33fc
+#define BAM_MUX_HDR_CMD_DATA			0
+#define BAM_MUX_HDR_CMD_OPEN			1
+#define BAM_MUX_HDR_CMD_CLOSE			2
+#define BAM_MUX_HDR_CMD_STATUS			3 /* unused */
+#define BAM_MUX_HDR_CMD_OPEN_NO_A2_PC		4
+#define BUFFER_SIZE				2048
+
+/**
+ * struct bam_ops_if - collection of function pointers to allow swappable
+ * runtime functionality
+ * @smsm_change_state_ptr: pointer to smsm_change_state function
+ * @smsm_get_state_ptr: pointer to smsm_get_state function
+ * @smsm_state_cb_register_ptr: pointer to smsm_state_cb_register function
+ * @smsm_state_cb_deregister_ptr: pointer to smsm_state_cb_deregister function
+ * @sps_connect_ptr: pointer to sps_connect function
+ * @sps_disconnect_ptr: pointer to sps_disconnect function
+ * @sps_register_bam_device_ptr: pointer to sps_register_bam_device
+ * @sps_deregister_bam_device_ptr: pointer to sps_deregister_bam_device
+ * function
+ * @sps_alloc_endpoint_ptr: pointer to sps_alloc_endpoint function
+ * @sps_free_endpoint_ptr: pointer to sps_free_endpoint function
+ * @sps_set_config_ptr: pointer to sps_set_config function
+ * @sps_get_config_ptr: pointer to sps_get_config function
+ * @sps_device_reset_ptr: pointer to sps_device_reset function
+ * @sps_register_event_ptr: pointer to sps_register_event function
+ * @sps_transfer_one_ptr: pointer to sps_transfer_one function
+ * @sps_get_iovec_ptr: pointer to sps_get_iovec function
+ * @sps_get_unused_desc_num_ptr: pointer to sps_get_unused_desc_num function
+ * @dma_to: enum for the direction of dma operations to device
+ * @dma_from: enum for the direction of dma operations from device
+ *
+ * This struct contains the interface from bam_dmux to smsm and sps. The
+ * pointers can be swapped out at run time to provide different functionality.
+ */
+struct bam_ops_if {
+	/* smsm */
+	int (*smsm_change_state_ptr)(uint32_t smsm_entry,
+		uint32_t clear_mask, uint32_t set_mask);
+
+	uint32_t (*smsm_get_state_ptr)(uint32_t smsm_entry);
+
+	int (*smsm_state_cb_register_ptr)(uint32_t smsm_entry, uint32_t mask,
+		void (*notify)(void *, uint32_t old_state, uint32_t new_state),
+		void *data);
+
+	int (*smsm_state_cb_deregister_ptr)(uint32_t smsm_entry, uint32_t mask,
+		void (*notify)(void *, uint32_t, uint32_t), void *data);
+
+	/* sps */
+	int (*sps_connect_ptr)(struct sps_pipe *h, struct sps_connect *connect);
+
+	int (*sps_disconnect_ptr)(struct sps_pipe *h);
+
+	int (*sps_register_bam_device_ptr)(
+		const struct sps_bam_props *bam_props,
+		u32 *dev_handle);
+
+	int (*sps_deregister_bam_device_ptr)(u32 dev_handle);
+
+	struct sps_pipe *(*sps_alloc_endpoint_ptr)(void);
+
+	int (*sps_free_endpoint_ptr)(struct sps_pipe *h);
+
+	int (*sps_set_config_ptr)(struct sps_pipe *h,
+		struct sps_connect *config);
+
+	int (*sps_get_config_ptr)(struct sps_pipe *h,
+		struct sps_connect *config);
+
+	int (*sps_device_reset_ptr)(u32 dev);
+
+	int (*sps_register_event_ptr)(struct sps_pipe *h,
+		struct sps_register_event *reg);
+
+	int (*sps_transfer_one_ptr)(struct sps_pipe *h,
+		u32 addr, u32 size,
+		void *user, u32 flags);
+
+	int (*sps_get_iovec_ptr)(struct sps_pipe *h,
+		struct sps_iovec *iovec);
+
+	int (*sps_get_unused_desc_num_ptr)(struct sps_pipe *h,
+		u32 *desc_num);
+
+	enum dma_data_direction dma_to;
+
+	enum dma_data_direction dma_from;
+};
+
+/**
+ * struct bam_mux_hdr - struct which contains bam dmux header info
+ * @magic_num: magic number placed at start to ensure that it is actually a
+ * valid bam dmux header
+ * @reserved: for later use
+ * @cmd: the command
+ * @pad_len: the length of padding
+ * @ch_id: the id of the bam dmux channel that this is sent on
+ * @pkt_len: the length of the packet that this is the header of
+ */
+struct bam_mux_hdr {
+	uint16_t magic_num;
+	uint8_t reserved;
+	uint8_t cmd;
+	uint8_t pad_len;
+	uint8_t ch_id;
+	uint16_t pkt_len;
+};
+
+/**
+ * struct rx_pkt_info - struct describing an rx packet
+ * @skb: socket buffer containing the packet
+ * @dma_address: dma mapped address of the packet
+ * @work: work_struct for processing the packet
+ * @list_node: list_head for placing this on a list
+ */
+struct rx_pkt_info {
+	struct sk_buff *skb;
+	dma_addr_t dma_address;
+	struct work_struct work;
+	struct list_head list_node;
+};
+
+/**
+ * struct tx_pkt_info - struct describing a tx packet
+ * @skb: socket buffer containing the packet
+ * @dma_address: dma mapped address of the packet
+ * @is_cmd: signifies whether this is a command or data packet
+ * @len: length og the packet
+ * @work: work_struct for processing this packet
+ * @list_node: list_head for placing this on a list
+ * @ts_sec: seconds portion of the timestamp
+ * @ts_nsec: nanoseconds portion of the timestamp
+ *
+ */
+struct tx_pkt_info {
+	struct sk_buff *skb;
+	dma_addr_t dma_address;
+	char is_cmd;
+	uint32_t len;
+	struct work_struct work;
+	struct list_head list_node;
+	unsigned ts_sec;
+	unsigned long ts_nsec;
+};
+
+void msm_bam_dmux_set_bam_ops(struct bam_ops_if *ops);
+
+void msm_bam_dmux_deinit(void);
+
+void msm_bam_dmux_reinit(void);
+
+#endif /* _BAM_DMUX_PRIVATE_H */
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-8226-gpiomux.c b/arch/arm/mach-msm/board-8226-gpiomux.c
index 9767746..08566bb 100644
--- a/arch/arm/mach-msm/board-8226-gpiomux.c
+++ b/arch/arm/mach-msm/board-8226-gpiomux.c
@@ -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
@@ -11,6 +11,7 @@
  *
  */
 
+#include <linux/gpio.h>
 #include <linux/init.h>
 #include <linux/ioport.h>
 #include <mach/board.h>
@@ -18,6 +19,12 @@
 #include <mach/gpiomux.h>
 #include <mach/socinfo.h>
 
+#define WLAN_CLK	44
+#define WLAN_SET	43
+#define WLAN_DATA0	42
+#define WLAN_DATA1	41
+#define WLAN_DATA2	40
+
 #ifdef CONFIG_USB_EHCI_MSM_HSIC
 static struct gpiomux_setting hsic_sus_cfg = {
 	.func = GPIOMUX_FUNC_GPIO,
@@ -50,6 +57,42 @@
 };
 #endif
 
+static struct gpiomux_setting smsc_hub_act_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting smsc_hub_susp_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+static struct msm_gpiomux_config smsc_hub_configs[] = {
+	{
+		.gpio = 114, /* reset_n */
+		.settings = {
+			[GPIOMUX_ACTIVE] = &smsc_hub_act_cfg,
+			[GPIOMUX_SUSPENDED] = &smsc_hub_susp_cfg,
+		},
+	},
+	{
+		.gpio = 8, /* clk_en */
+		.settings = {
+			[GPIOMUX_ACTIVE] = &smsc_hub_act_cfg,
+			[GPIOMUX_SUSPENDED] = &smsc_hub_susp_cfg,
+		},
+	},
+	{
+		.gpio = 9, /* int_n */
+		.settings = {
+			[GPIOMUX_ACTIVE] = &smsc_hub_act_cfg,
+			[GPIOMUX_SUSPENDED] = &smsc_hub_susp_cfg,
+		},
+	},
+};
+
 #define KS8851_IRQ_GPIO 115
 
 #if defined(CONFIG_KS8851) || defined(CONFIG_KS8851_MODULE)
@@ -140,6 +183,18 @@
 	.pull = GPIOMUX_PULL_DOWN,
 };
 
+static struct gpiomux_setting wcnss_5gpio_suspend_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv  = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting wcnss_5gpio_active_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv  = GPIOMUX_DRV_6MA,
+	.pull = GPIOMUX_PULL_DOWN,
+};
+
 static struct gpiomux_setting gpio_i2c_config = {
 	.func = GPIOMUX_FUNC_3,
 	.drv = GPIOMUX_DRV_2MA,
@@ -216,13 +271,6 @@
 		},
 	},
 	{
-		.gpio      = 2,		/* BLSP1 QUP1 SPI_CS1 */
-		.settings = {
-			[GPIOMUX_ACTIVE] = &gpio_spi_cs_act_config,
-			[GPIOMUX_SUSPENDED] = &gpio_spi_susp_config,
-		},
-	},
-	{
 		.gpio      = 3,		/* BLSP1 QUP1 SPI_CLK */
 		.settings = {
 			[GPIOMUX_ACTIVE] = &gpio_spi_act_config,
@@ -279,6 +327,16 @@
 	},
 };
 
+static struct msm_gpiomux_config msm_blsp_spi_cs_config[] __initdata = {
+	{
+		.gpio      = 2,		/* BLSP1 QUP1 SPI_CS1 */
+		.settings = {
+			[GPIOMUX_ACTIVE] = &gpio_spi_cs_act_config,
+			[GPIOMUX_SUSPENDED] = &gpio_spi_susp_config,
+		},
+	},
+};
+
 static struct msm_gpiomux_config msm_synaptics_configs[] __initdata = {
 	{
 		.gpio = 16,
@@ -539,6 +597,44 @@
 	},
 };
 
+static struct msm_gpiomux_config wcnss_5gpio_interface[] = {
+	{
+		.gpio = 40,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &wcnss_5gpio_active_cfg,
+			[GPIOMUX_SUSPENDED] = &wcnss_5gpio_suspend_cfg,
+		},
+	},
+	{
+		.gpio = 41,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &wcnss_5gpio_active_cfg,
+			[GPIOMUX_SUSPENDED] = &wcnss_5gpio_suspend_cfg,
+		},
+	},
+	{
+		.gpio = 42,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &wcnss_5gpio_active_cfg,
+			[GPIOMUX_SUSPENDED] = &wcnss_5gpio_suspend_cfg,
+		},
+	},
+	{
+		.gpio = 43,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &wcnss_5gpio_active_cfg,
+			[GPIOMUX_SUSPENDED] = &wcnss_5gpio_suspend_cfg,
+		},
+	},
+	{
+		.gpio = 44,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &wcnss_5gpio_active_cfg,
+			[GPIOMUX_SUSPENDED] = &wcnss_5gpio_suspend_cfg,
+		},
+	},
+};
+
 static struct gpiomux_setting gpio_suspend_config[] = {
 	{
 		.func = GPIOMUX_FUNC_GPIO,  /* IN-NP */
@@ -827,9 +923,13 @@
 	if (of_board_is_skuf())
 		msm_gpiomux_install(msm_skuf_blsp_configs,
 			ARRAY_SIZE(msm_skuf_blsp_configs));
-	else
+	else {
 		msm_gpiomux_install(msm_blsp_configs,
 			ARRAY_SIZE(msm_blsp_configs));
+		if (machine_is_msm8226())
+			msm_gpiomux_install(msm_blsp_spi_cs_config,
+				ARRAY_SIZE(msm_blsp_spi_cs_config));
+	}
 
 	msm_gpiomux_install(wcnss_5wire_interface,
 				ARRAY_SIZE(wcnss_5wire_interface));
@@ -876,4 +976,113 @@
 	}
 	msm_gpiomux_install(msm_hsic_configs, ARRAY_SIZE(msm_hsic_configs));
 #endif
+	if (machine_is_msm8926() && of_board_is_mtp())
+		msm_gpiomux_install(smsc_hub_configs,
+			ARRAY_SIZE(smsc_hub_configs));
+}
+
+static void wcnss_switch_to_gpio(void)
+{
+	/* Switch MUX to GPIO */
+	msm_gpiomux_install(wcnss_5gpio_interface,
+			ARRAY_SIZE(wcnss_5gpio_interface));
+
+	/* Ensure GPIO config */
+	gpio_direction_input(WLAN_DATA2);
+	gpio_direction_input(WLAN_DATA1);
+	gpio_direction_input(WLAN_DATA0);
+	gpio_direction_output(WLAN_SET, 0);
+	gpio_direction_output(WLAN_CLK, 0);
+}
+
+static void wcnss_switch_to_5wire(void)
+{
+	msm_gpiomux_install(wcnss_5wire_interface,
+			ARRAY_SIZE(wcnss_5wire_interface));
+}
+
+u32 wcnss_rf_read_reg(u32 rf_reg_addr)
+{
+	int count = 0;
+	u32 rf_cmd_and_addr = 0;
+	u32 rf_data_received = 0;
+	u32 rf_bit = 0;
+
+	wcnss_switch_to_gpio();
+
+	/* Reset the signal if it is already being used. */
+	gpio_set_value(WLAN_SET, 0);
+	gpio_set_value(WLAN_CLK, 0);
+
+	/* We start with cmd_set high WLAN_SET = 1. */
+	gpio_set_value(WLAN_SET, 1);
+
+	gpio_direction_output(WLAN_DATA0, 1);
+	gpio_direction_output(WLAN_DATA1, 1);
+	gpio_direction_output(WLAN_DATA2, 1);
+
+	gpio_set_value(WLAN_DATA0, 0);
+	gpio_set_value(WLAN_DATA1, 0);
+	gpio_set_value(WLAN_DATA2, 0);
+
+	/* Prepare command and RF register address that need to sent out.
+	 * Make sure that we send only 14 bits from LSB.
+	 */
+	rf_cmd_and_addr  = (((WLAN_RF_READ_REG_CMD) |
+		(rf_reg_addr << WLAN_RF_REG_ADDR_START_OFFSET)) &
+		WLAN_RF_READ_CMD_MASK);
+
+	for (count = 0; count < 5; count++) {
+		gpio_set_value(WLAN_CLK, 0);
+
+		rf_bit = (rf_cmd_and_addr & 0x1);
+		gpio_set_value(WLAN_DATA0, rf_bit ? 1 : 0);
+		rf_cmd_and_addr = (rf_cmd_and_addr >> 1);
+
+		rf_bit = (rf_cmd_and_addr & 0x1);
+		gpio_set_value(WLAN_DATA1, rf_bit ? 1 : 0);
+		rf_cmd_and_addr = (rf_cmd_and_addr >> 1);
+
+		rf_bit = (rf_cmd_and_addr & 0x1);
+		gpio_set_value(WLAN_DATA2, rf_bit ? 1 : 0);
+		rf_cmd_and_addr = (rf_cmd_and_addr >> 1);
+
+		/* Send the data out WLAN_CLK = 1 */
+		gpio_set_value(WLAN_CLK, 1);
+	}
+
+	/* Pull down the clock signal */
+	gpio_set_value(WLAN_CLK, 0);
+
+	/* Configure data pins to input IO pins */
+	gpio_direction_input(WLAN_DATA0);
+	gpio_direction_input(WLAN_DATA1);
+	gpio_direction_input(WLAN_DATA2);
+
+	for (count = 0; count < 2; count++) {
+		gpio_set_value(WLAN_CLK, 1);
+		gpio_set_value(WLAN_CLK, 0);
+	}
+
+	rf_bit = 0;
+	for (count = 0; count < 6; count++) {
+		gpio_set_value(WLAN_CLK, 1);
+		gpio_set_value(WLAN_CLK, 0);
+
+		rf_bit = gpio_get_value(WLAN_DATA0);
+		rf_data_received |= (rf_bit << (count * 3 + 0));
+
+		if (count != 5) {
+			rf_bit = gpio_get_value(WLAN_DATA1);
+			rf_data_received |= (rf_bit << (count * 3 + 1));
+
+			rf_bit = gpio_get_value(WLAN_DATA2);
+			rf_data_received |= (rf_bit << (count * 3 + 2));
+		}
+	}
+
+	gpio_set_value(WLAN_SET, 0);
+	wcnss_switch_to_5wire();
+
+	return rf_data_received;
 }
diff --git a/arch/arm/mach-msm/board-8226.c b/arch/arm/mach-msm/board-8226.c
index 5244918..43646cd 100644
--- a/arch/arm/mach-msm/board-8226.c
+++ b/arch/arm/mach-msm/board-8226.c
@@ -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
@@ -15,6 +15,7 @@
 #include <linux/errno.h>
 #include <linux/platform_device.h>
 #include <linux/io.h>
+#include <linux/i2c/i2c-qup.h>
 #include <linux/gpio.h>
 #include <linux/irq.h>
 #include <linux/irqdomain.h>
@@ -24,6 +25,9 @@
 #include <linux/of_fdt.h>
 #include <linux/of_irq.h>
 #include <linux/memory.h>
+#include <linux/regulator/cpr-regulator.h>
+#include <linux/regulator/fan53555.h>
+#include <linux/regulator/onsemi-ncp6335d.h>
 #include <linux/regulator/qpnp-regulator.h>
 #include <linux/msm_tsens.h>
 #include <asm/mach/map.h>
@@ -31,6 +35,7 @@
 #include <asm/mach/arch.h>
 #include <asm/mach/time.h>
 #include <mach/board.h>
+#include <mach/msm_bus.h>
 #include <mach/gpiomux.h>
 #include <mach/msm_iomap.h>
 #include <mach/restart.h>
@@ -52,6 +57,7 @@
 #include "spm.h"
 #include "pm.h"
 #include "modem_notifier.h"
+#include "spm-regulator.h"
 
 static struct memtype_reserve msm8226_reserve_table[] __initdata = {
 	[MEMTYPE_SMI] = {
@@ -69,6 +75,11 @@
 	return MEMTYPE_EBI1;
 }
 
+static struct of_dev_auxdata msm_hsic_host_adata[] = {
+	OF_DEV_AUXDATA("qcom,hsic-host", 0xF9A00000, "msm_hsic_host", NULL),
+	{}
+};
+
 static struct of_dev_auxdata msm8226_auxdata_lookup[] __initdata = {
 	OF_DEV_AUXDATA("qcom,msm-sdcc", 0xF9824000, \
 			"msm_sdcc.1", NULL),
@@ -83,6 +94,8 @@
 	OF_DEV_AUXDATA("qcom,sdhci-msm", 0xF9864900, \
 			"msm_sdcc.3", NULL),
 	OF_DEV_AUXDATA("qcom,hsic-host", 0xF9A00000, "msm_hsic_host", NULL),
+	OF_DEV_AUXDATA("qcom,hsic-smsc-hub", 0, "msm_smsc_hub",
+			msm_hsic_host_adata),
 
 	{}
 };
@@ -121,10 +134,16 @@
 	msm_pm_sleep_status_init();
 	rpm_regulator_smd_driver_init();
 	qpnp_regulator_init();
+	spm_regulator_init();
 	if (of_board_is_rumi())
 		msm_clock_init(&msm8226_rumi_clock_init_data);
 	else
 		msm_clock_init(&msm8226_clock_init_data);
+	msm_bus_fabric_init_driver();
+	qup_i2c_init_driver();
+	ncp6335d_regulator_init();
+	fan53555_regulator_init();
+	cpr_regulator_init();
 	tsens_tm_init_driver();
 	msm_thermal_device_init();
 }
@@ -148,7 +167,7 @@
 	NULL
 };
 
-DT_MACHINE_START(MSM8226_DT, "Qualcomm MSM 8226 (Flattened Device Tree)")
+DT_MACHINE_START(MSM8226_DT, "Qualcomm MSM 8x26 / MSM 8x28 (Flattened Device Tree)")
 	.map_io = msm_map_msm8226_io,
 	.init_irq = msm_dt_init_irq,
 	.init_machine = msm8226_init,
diff --git a/arch/arm/mach-msm/board-8610-gpiomux.c b/arch/arm/mach-msm/board-8610-gpiomux.c
index affe6bd..c91deb2 100644
--- a/arch/arm/mach-msm/board-8610-gpiomux.c
+++ b/arch/arm/mach-msm/board-8610-gpiomux.c
@@ -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
@@ -11,6 +11,7 @@
  *
  */
 
+#include <linux/gpio.h>
 #include <linux/init.h>
 #include <linux/ioport.h>
 #include <mach/board.h>
@@ -18,6 +19,12 @@
 #include <mach/gpiomux.h>
 #include <mach/socinfo.h>
 
+#define WLAN_CLK	27
+#define WLAN_SET	26
+#define WLAN_DATA0	25
+#define WLAN_DATA1	24
+#define WLAN_DATA2	23
+
 static struct gpiomux_setting gpio_spi_config = {
 	.func = GPIOMUX_FUNC_1,
 	.drv = GPIOMUX_DRV_6MA,
@@ -112,6 +119,18 @@
 	.pull = GPIOMUX_PULL_DOWN,
 };
 
+static struct gpiomux_setting wcnss_5gpio_suspend_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv  = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting wcnss_5gpio_active_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv  = GPIOMUX_DRV_6MA,
+	.pull = GPIOMUX_PULL_DOWN,
+};
+
 static struct gpiomux_setting lcd_en_act_cfg = {
 	.func = GPIOMUX_FUNC_GPIO,
 	.drv = GPIOMUX_DRV_8MA,
@@ -405,6 +424,44 @@
 	},
 };
 
+static struct msm_gpiomux_config wcnss_5gpio_interface[] = {
+	{
+		.gpio = 23,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &wcnss_5gpio_active_cfg,
+			[GPIOMUX_SUSPENDED] = &wcnss_5gpio_suspend_cfg,
+		},
+	},
+	{
+		.gpio = 24,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &wcnss_5gpio_active_cfg,
+			[GPIOMUX_SUSPENDED] = &wcnss_5gpio_suspend_cfg,
+		},
+	},
+	{
+		.gpio = 25,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &wcnss_5gpio_active_cfg,
+			[GPIOMUX_SUSPENDED] = &wcnss_5gpio_suspend_cfg,
+		},
+	},
+	{
+		.gpio = 26,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &wcnss_5gpio_active_cfg,
+			[GPIOMUX_SUSPENDED] = &wcnss_5gpio_suspend_cfg,
+		},
+	},
+	{
+		.gpio = 27,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &wcnss_5gpio_active_cfg,
+			[GPIOMUX_SUSPENDED] = &wcnss_5gpio_suspend_cfg,
+		},
+	},
+};
+
 static struct gpiomux_setting gpio_suspend_config[] = {
 	{
 		.func = GPIOMUX_FUNC_GPIO,  /* IN-NP */
@@ -451,6 +508,12 @@
 	},
 };
 
+static struct gpiomux_setting accel_interrupt_config = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_6MA,
+	.pull = GPIOMUX_PULL_DOWN,
+};
+
 static struct msm_gpiomux_config msm_non_qrd_configs[] __initdata = {
 	{
 		.gpio = 8, /* CAM1_STANDBY_N */
@@ -459,6 +522,13 @@
 			[GPIOMUX_SUSPENDED] = &gpio_suspend_config[1],
 		},
 	},
+	{
+		.gpio = 81,	/*ACCEL_INT1 */
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &accel_interrupt_config,
+			[GPIOMUX_SUSPENDED] = &accel_interrupt_config,
+		},
+	},
 };
 
 static struct msm_gpiomux_config msm_sensor_configs[] __initdata = {
@@ -602,6 +672,13 @@
 
 static struct msm_gpiomux_config msm_interrupt_configs[] __initdata = {
 	{
+		.gpio = 75,	/* NFC_CLK_REQ_IRQ*/
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &interrupt_gpio_active,
+			[GPIOMUX_SUSPENDED] = &interrupt_gpio_suspend_pullup,
+		},
+	},
+	{
 		.gpio = 77,	/* NFC_IRQ */
 		.settings = {
 			[GPIOMUX_ACTIVE]    = &interrupt_gpio_active,
@@ -653,6 +730,61 @@
 	},
 };
 
+static struct gpiomux_setting ice40_spi_cs_act_config = {
+	.func = GPIOMUX_FUNC_1,
+	.drv = GPIOMUX_DRV_6MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting ice40_spi_cs_susp_config = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_6MA,
+	.pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting ice40_act_config = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting ice40_susp_config = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+static struct msm_gpiomux_config ice40_spi_usb_configs[] __initdata = {
+	{
+		.gpio = 85,
+		.settings = {
+			[GPIOMUX_ACTIVE] = &ice40_spi_cs_act_config,
+			[GPIOMUX_SUSPENDED] = &ice40_spi_cs_susp_config,
+		},
+	},
+	{
+		.gpio = 94,
+		.settings = {
+			[GPIOMUX_ACTIVE] = &ice40_act_config,
+			[GPIOMUX_SUSPENDED] = &ice40_susp_config,
+		},
+	},
+	{
+		.gpio = 95,
+		.settings = {
+			[GPIOMUX_ACTIVE] = &ice40_act_config,
+			[GPIOMUX_SUSPENDED] = &ice40_susp_config,
+		},
+	},
+	{
+		.gpio = 96,
+		.settings = {
+			[GPIOMUX_ACTIVE] = &ice40_act_config,
+			[GPIOMUX_SUSPENDED] = &ice40_susp_config,
+		},
+	},
+};
+
 void __init msm8610_init_gpiomux(void)
 {
 	int rc;
@@ -693,4 +825,114 @@
 	if (of_board_is_cdp())
 		msm_gpiomux_install(msm_cdc_dmic_configs,
 			ARRAY_SIZE(msm_cdc_dmic_configs));
+
+	if (of_board_is_cdp())
+		msm_gpiomux_install(ice40_spi_usb_configs,
+			ARRAY_SIZE(ice40_spi_usb_configs));
+}
+
+static void wcnss_switch_to_gpio(void)
+{
+	/* Switch MUX to GPIO */
+	msm_gpiomux_install(wcnss_5gpio_interface,
+			ARRAY_SIZE(wcnss_5gpio_interface));
+
+	/* Ensure GPIO config */
+	gpio_direction_input(WLAN_DATA2);
+	gpio_direction_input(WLAN_DATA1);
+	gpio_direction_input(WLAN_DATA0);
+	gpio_direction_output(WLAN_SET, 0);
+	gpio_direction_output(WLAN_CLK, 0);
+}
+
+static void wcnss_switch_to_5wire(void)
+{
+	msm_gpiomux_install(wcnss_5wire_interface,
+			ARRAY_SIZE(wcnss_5wire_interface));
+}
+
+u32 wcnss_rf_read_reg(u32 rf_reg_addr)
+{
+	int count = 0;
+	u32 rf_cmd_and_addr = 0;
+	u32 rf_data_received = 0;
+	u32 rf_bit = 0;
+
+	wcnss_switch_to_gpio();
+
+	/* Reset the signal if it is already being used. */
+	gpio_set_value(WLAN_SET, 0);
+	gpio_set_value(WLAN_CLK, 0);
+
+	/* We start with cmd_set high WLAN_SET = 1. */
+	gpio_set_value(WLAN_SET, 1);
+
+	gpio_direction_output(WLAN_DATA0, 1);
+	gpio_direction_output(WLAN_DATA1, 1);
+	gpio_direction_output(WLAN_DATA2, 1);
+
+	gpio_set_value(WLAN_DATA0, 0);
+	gpio_set_value(WLAN_DATA1, 0);
+	gpio_set_value(WLAN_DATA2, 0);
+
+	/* Prepare command and RF register address that need to sent out.
+	 * Make sure that we send only 14 bits from LSB.
+	 */
+	rf_cmd_and_addr  = (((WLAN_RF_READ_REG_CMD) |
+		(rf_reg_addr << WLAN_RF_REG_ADDR_START_OFFSET)) &
+		WLAN_RF_READ_CMD_MASK);
+
+	for (count = 0; count < 5; count++) {
+		gpio_set_value(WLAN_CLK, 0);
+
+		rf_bit = (rf_cmd_and_addr & 0x1);
+		gpio_set_value(WLAN_DATA0, rf_bit ? 1 : 0);
+		rf_cmd_and_addr = (rf_cmd_and_addr >> 1);
+
+		rf_bit = (rf_cmd_and_addr & 0x1);
+		gpio_set_value(WLAN_DATA1, rf_bit ? 1 : 0);
+		rf_cmd_and_addr = (rf_cmd_and_addr >> 1);
+
+		rf_bit = (rf_cmd_and_addr & 0x1);
+		gpio_set_value(WLAN_DATA2, rf_bit ? 1 : 0);
+		rf_cmd_and_addr = (rf_cmd_and_addr >> 1);
+
+		/* Send the data out WLAN_CLK = 1 */
+		gpio_set_value(WLAN_CLK, 1);
+	}
+
+	/* Pull down the clock signal */
+	gpio_set_value(WLAN_CLK, 0);
+
+	/* Configure data pins to input IO pins */
+	gpio_direction_input(WLAN_DATA0);
+	gpio_direction_input(WLAN_DATA1);
+	gpio_direction_input(WLAN_DATA2);
+
+	for (count = 0; count < 2; count++) {
+		gpio_set_value(WLAN_CLK, 1);
+		gpio_set_value(WLAN_CLK, 0);
+	}
+
+	rf_bit = 0;
+	for (count = 0; count < 6; count++) {
+		gpio_set_value(WLAN_CLK, 1);
+		gpio_set_value(WLAN_CLK, 0);
+
+		rf_bit = gpio_get_value(WLAN_DATA0);
+		rf_data_received |= (rf_bit << (count * 3 + 0));
+
+		if (count != 5) {
+			rf_bit = gpio_get_value(WLAN_DATA1);
+			rf_data_received |= (rf_bit << (count * 3 + 1));
+
+			rf_bit = gpio_get_value(WLAN_DATA2);
+			rf_data_received |= (rf_bit << (count * 3 + 2));
+		}
+	}
+
+	gpio_set_value(WLAN_SET, 0);
+	wcnss_switch_to_5wire();
+
+	return rf_data_received;
 }
diff --git a/arch/arm/mach-msm/board-8610.c b/arch/arm/mach-msm/board-8610.c
index d175bb4..cd9b82e 100644
--- a/arch/arm/mach-msm/board-8610.c
+++ b/arch/arm/mach-msm/board-8610.c
@@ -136,7 +136,7 @@
 	NULL
 };
 
-DT_MACHINE_START(MSM8610_DT, "Qualcomm MSM 8610 (Flattened Device Tree)")
+DT_MACHINE_START(MSM8610_DT, "Qualcomm MSM 8x10 / MSM 8x12 (Flattened Device Tree)")
 	.map_io = msm_map_msm8610_io,
 	.init_irq = msm_dt_init_irq,
 	.init_machine = msm8610_init,
diff --git a/arch/arm/mach-msm/board-8974-gpiomux.c b/arch/arm/mach-msm/board-8974-gpiomux.c
index 8ab916c..5d4d379 100755
--- a/arch/arm/mach-msm/board-8974-gpiomux.c
+++ b/arch/arm/mach-msm/board-8974-gpiomux.c
@@ -11,6 +11,7 @@
  *
  */
 
+#include <linux/gpio.h>
 #include <linux/init.h>
 #include <linux/ioport.h>
 #include <mach/board.h>
@@ -20,29 +21,36 @@
 
 #define KS8851_IRQ_GPIO 94
 
+#define WLAN_CLK	40
+#define WLAN_SET	39
+#define WLAN_DATA0	38
+#define WLAN_DATA1	37
+#define WLAN_DATA2	36
+
 static struct gpiomux_setting ap2mdm_cfg = {
 	.func = GPIOMUX_FUNC_GPIO,
-	.drv = GPIOMUX_DRV_8MA,
+	.drv = GPIOMUX_DRV_2MA,
 	.pull = GPIOMUX_PULL_NONE,
+	.dir = GPIOMUX_OUT_LOW,
 };
 
 static struct gpiomux_setting mdm2ap_status_cfg = {
 	.func = GPIOMUX_FUNC_GPIO,
-	.drv = GPIOMUX_DRV_8MA,
-	.pull = GPIOMUX_PULL_DOWN,
-	.dir = GPIOMUX_IN,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_NONE,
+	.dir = GPIOMUX_OUT_LOW,
 };
 
 static struct gpiomux_setting mdm2ap_errfatal_cfg = {
 	.func = GPIOMUX_FUNC_GPIO,
-	.drv = GPIOMUX_DRV_8MA,
-	.pull = GPIOMUX_PULL_DOWN,
-	.dir = GPIOMUX_IN,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_NONE,
+	.dir = GPIOMUX_OUT_LOW,
 };
 
 static struct gpiomux_setting mdm2ap_pblrdy = {
 	.func = GPIOMUX_FUNC_GPIO,
-	.drv = GPIOMUX_DRV_8MA,
+	.drv = GPIOMUX_DRV_2MA,
 	.pull = GPIOMUX_PULL_NONE,
 	.dir = GPIOMUX_IN,
 };
@@ -50,14 +58,16 @@
 
 static struct gpiomux_setting ap2mdm_soft_reset_cfg = {
 	.func = GPIOMUX_FUNC_GPIO,
-	.drv = GPIOMUX_DRV_8MA,
+	.drv = GPIOMUX_DRV_2MA,
 	.pull = GPIOMUX_PULL_NONE,
+	.dir = GPIOMUX_OUT_LOW,
 };
 
 static struct gpiomux_setting ap2mdm_wakeup = {
 	.func = GPIOMUX_FUNC_GPIO,
-	.drv = GPIOMUX_DRV_8MA,
-	.pull = GPIOMUX_PULL_DOWN,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_NONE,
+	.dir = GPIOMUX_OUT_LOW,
 };
 
 static struct msm_gpiomux_config mdm_configs[] __initdata = {
@@ -205,6 +215,18 @@
 	.pull = GPIOMUX_PULL_DOWN,
 };
 
+static struct gpiomux_setting wcnss_5gpio_suspend_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv  = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting wcnss_5gpio_active_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv  = GPIOMUX_DRV_6MA,
+	.pull = GPIOMUX_PULL_DOWN,
+};
+
 static struct gpiomux_setting ath_gpio_active_cfg = {
 	.func = GPIOMUX_FUNC_GPIO,
 	.drv = GPIOMUX_DRV_2MA,
@@ -1155,6 +1177,43 @@
 	},
 };
 
+static struct msm_gpiomux_config wcnss_5gpio_interface[] = {
+	{
+		.gpio = 36,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &wcnss_5gpio_active_cfg,
+			[GPIOMUX_SUSPENDED] = &wcnss_5gpio_suspend_cfg,
+		},
+	},
+	{
+		.gpio = 37,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &wcnss_5gpio_active_cfg,
+			[GPIOMUX_SUSPENDED] = &wcnss_5gpio_suspend_cfg,
+		},
+	},
+	{
+		.gpio = 38,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &wcnss_5gpio_active_cfg,
+			[GPIOMUX_SUSPENDED] = &wcnss_5gpio_suspend_cfg,
+		},
+	},
+	{
+		.gpio = 39,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &wcnss_5gpio_active_cfg,
+			[GPIOMUX_SUSPENDED] = &wcnss_5gpio_suspend_cfg,
+		},
+	},
+	{
+		.gpio = 40,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &wcnss_5gpio_active_cfg,
+			[GPIOMUX_SUSPENDED] = &wcnss_5gpio_suspend_cfg,
+		},
+	},
+};
 
 static struct msm_gpiomux_config ath_gpio_configs[] = {
 	{
@@ -1464,3 +1523,109 @@
 		msm_gpiomux_install(apq8074_dragonboard_ts_config,
 			ARRAY_SIZE(apq8074_dragonboard_ts_config));
 }
+
+static void wcnss_switch_to_gpio(void)
+{
+	/* Switch MUX to GPIO */
+	msm_gpiomux_install(wcnss_5gpio_interface,
+			ARRAY_SIZE(wcnss_5gpio_interface));
+
+	/* Ensure GPIO config */
+	gpio_direction_input(WLAN_DATA2);
+	gpio_direction_input(WLAN_DATA1);
+	gpio_direction_input(WLAN_DATA0);
+	gpio_direction_output(WLAN_SET, 0);
+	gpio_direction_output(WLAN_CLK, 0);
+}
+
+static void wcnss_switch_to_5wire(void)
+{
+	msm_gpiomux_install(wcnss_5wire_interface,
+			ARRAY_SIZE(wcnss_5wire_interface));
+}
+
+u32 wcnss_rf_read_reg(u32 rf_reg_addr)
+{
+	int count = 0;
+	u32 rf_cmd_and_addr = 0;
+	u32 rf_data_received = 0;
+	u32 rf_bit = 0;
+
+	wcnss_switch_to_gpio();
+
+	/* Reset the signal if it is already being used. */
+	gpio_set_value(WLAN_SET, 0);
+	gpio_set_value(WLAN_CLK, 0);
+
+	/* We start with cmd_set high WLAN_SET = 1. */
+	gpio_set_value(WLAN_SET, 1);
+
+	gpio_direction_output(WLAN_DATA0, 1);
+	gpio_direction_output(WLAN_DATA1, 1);
+	gpio_direction_output(WLAN_DATA2, 1);
+
+	gpio_set_value(WLAN_DATA0, 0);
+	gpio_set_value(WLAN_DATA1, 0);
+	gpio_set_value(WLAN_DATA2, 0);
+
+	/* Prepare command and RF register address that need to sent out.
+	 * Make sure that we send only 14 bits from LSB.
+	 */
+	rf_cmd_and_addr  = (((WLAN_RF_READ_REG_CMD) |
+		(rf_reg_addr << WLAN_RF_REG_ADDR_START_OFFSET)) &
+		WLAN_RF_READ_CMD_MASK);
+
+	for (count = 0; count < 5; count++) {
+		gpio_set_value(WLAN_CLK, 0);
+
+		rf_bit = (rf_cmd_and_addr & 0x1);
+		gpio_set_value(WLAN_DATA0, rf_bit ? 1 : 0);
+		rf_cmd_and_addr = (rf_cmd_and_addr >> 1);
+
+		rf_bit = (rf_cmd_and_addr & 0x1);
+		gpio_set_value(WLAN_DATA1, rf_bit ? 1 : 0);
+		rf_cmd_and_addr = (rf_cmd_and_addr >> 1);
+
+		rf_bit = (rf_cmd_and_addr & 0x1);
+		gpio_set_value(WLAN_DATA2, rf_bit ? 1 : 0);
+		rf_cmd_and_addr = (rf_cmd_and_addr >> 1);
+
+		/* Send the data out WLAN_CLK = 1 */
+		gpio_set_value(WLAN_CLK, 1);
+	}
+
+	/* Pull down the clock signal */
+	gpio_set_value(WLAN_CLK, 0);
+
+	/* Configure data pins to input IO pins */
+	gpio_direction_input(WLAN_DATA0);
+	gpio_direction_input(WLAN_DATA1);
+	gpio_direction_input(WLAN_DATA2);
+
+	for (count = 0; count < 2; count++) {
+		gpio_set_value(WLAN_CLK, 1);
+		gpio_set_value(WLAN_CLK, 0);
+	}
+
+	rf_bit = 0;
+	for (count = 0; count < 6; count++) {
+		gpio_set_value(WLAN_CLK, 1);
+		gpio_set_value(WLAN_CLK, 0);
+
+		rf_bit = gpio_get_value(WLAN_DATA0);
+		rf_data_received |= (rf_bit << (count * 3 + 0));
+
+		if (count != 5) {
+			rf_bit = gpio_get_value(WLAN_DATA1);
+			rf_data_received |= (rf_bit << (count * 3 + 1));
+
+			rf_bit = gpio_get_value(WLAN_DATA2);
+			rf_data_received |= (rf_bit << (count * 3 + 2));
+		}
+	}
+
+	gpio_set_value(WLAN_SET, 0);
+	wcnss_switch_to_5wire();
+
+	return rf_data_received;
+}
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-8226.c b/arch/arm/mach-msm/clock-8226.c
index 3a0c152..e16bcb1 100644
--- a/arch/arm/mach-msm/clock-8226.c
+++ b/arch/arm/mach-msm/clock-8226.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
@@ -1555,6 +1555,8 @@
 	},
 };
 
+static DEFINE_CLK_MEASURE(wcnss_m_clk);
+
 #ifdef CONFIG_DEBUG_FS
 struct measure_mux_entry {
 	struct clk *c;
@@ -1610,6 +1612,7 @@
 	{ &pnoc_clk.c, GCC_BASE, 0x010},
 	{ &snoc_clk.c, GCC_BASE, 0x000},
 	{ &cnoc_clk.c, GCC_BASE, 0x008},
+	{ &wcnss_m_clk, GCC_BASE, 0x0198},
 	/*
 	 * measure the gcc_bimc_kpss_axi_clk instead to account for the DDR
 	 * rate being gcc_bimc_clk/2.
@@ -2580,17 +2583,6 @@
 	},
 };
 
-static struct branch_clk mmss_mmssnoc_bto_ahb_clk = {
-	.cbcr_reg = MMSS_MMSSNOC_BTO_AHB_CBCR,
-	.has_sibling = 1,
-	.base = &virt_bases[MMSS_BASE],
-	.c = {
-		.dbg_name = "mmss_mmssnoc_bto_ahb_clk",
-		.ops = &clk_ops_branch,
-		CLK_INIT(mmss_mmssnoc_bto_ahb_clk.c),
-	},
-};
-
 static struct branch_clk mmss_mmssnoc_axi_clk = {
 	.cbcr_reg = MMSS_MMSSNOC_AXI_CBCR,
 	.has_sibling = 1,
@@ -2692,7 +2684,6 @@
 
 #ifdef CONFIG_DEBUG_FS
 static struct measure_mux_entry measure_mux_MMSS[] = {
-	{ &mmss_mmssnoc_bto_ahb_clk.c,  MMSS_BASE, 0x0002 },
 	{ &mmss_misc_ahb_clk.c,  MMSS_BASE, 0x0003 },
 	{ &mmss_mmssnoc_axi_clk.c,  MMSS_BASE, 0x0004 },
 	{ &mmss_s0_axi_clk.c,  MMSS_BASE, 0x0005 },
@@ -2843,6 +2834,8 @@
 	F_APCS_PLL(1401600000, 73, 0x0, 0x1, 0x0, 0x0, 0x0),
 	F_APCS_PLL(1497600000, 78, 0x0, 0x1, 0x0, 0x0, 0x0),
 	F_APCS_PLL(1593600000, 83, 0x0, 0x1, 0x0, 0x0, 0x0),
+	F_APCS_PLL(1689600000, 88, 0x0, 0x1, 0x0, 0x0, 0x0),
+	F_APCS_PLL(1785600000, 93, 0x0, 0x1, 0x0, 0x0, 0x0),
 	PLL_F_END
 };
 
@@ -3134,6 +3127,10 @@
 	CLK_LOOKUP("apc3_m_clk", apc3_m_clk, ""),
 	CLK_LOOKUP("l2_m_clk", l2_m_clk, ""),
 
+	/* Measure clocks for WCNSS */
+	CLK_LOOKUP("measure",   measure_clk.c, "fb000000.qcom,wcnss-wlan"),
+	CLK_LOOKUP("wcnss_debug", wcnss_m_clk, "fb000000.qcom,wcnss-wlan"),
+
 	/* LPM Resources */
 	CLK_LOOKUP("xo",          cxo_lpm_clk.c, "fc4281d0.qcom,mpm"),
 
@@ -3149,8 +3146,11 @@
 	CLK_LOOKUP("bus_clk", gcc_mss_q6_bimc_axi_clk.c, "fc880000.qcom,mss"),
 	CLK_LOOKUP("iface_clk",   gcc_mss_cfg_ahb_clk.c, "fc880000.qcom,mss"),
 	CLK_LOOKUP("mem_clk",    gcc_boot_rom_ahb_clk.c, "fc880000.qcom,mss"),
+
 	/* NFC */
+	CLK_LOOKUP("ref_clk",            cxo_d1_a_pin.c, ""),
 	CLK_LOOKUP("ref_clk",            cxo_d1_pin.c, "2-000e"),
+
 	/* PIL-PRONTO */
 	CLK_LOOKUP("xo", cxo_pil_pronto_clk.c, "fb21b000.qcom,pronto"),
 
@@ -3386,6 +3386,8 @@
 	CLK_LOOKUP("iface_clk", mdss_ahb_clk.c, "fd922800.qcom,mdss_dsi"),
 	CLK_LOOKUP("bus_clk", mdss_axi_clk.c, "fd922800.qcom,mdss_dsi"),
 	CLK_LOOKUP("mdp_core_clk", mdss_mdp_clk.c, "fd922800.qcom,mdss_dsi"),
+	CLK_LOOKUP("core_mmss_clk", mmss_misc_ahb_clk.c,
+		"fd922800.qcom,mdss_dsi"),
 
 	CLK_LOOKUP("core_clk", mdss_mdp_clk.c, "fd900000.qcom,mdss_mdp"),
 	CLK_LOOKUP("lut_clk", mdss_mdp_lut_clk.c, "fd900000.qcom,mdss_mdp"),
@@ -3408,17 +3410,21 @@
 
 	/* MM sensor clocks */
 	CLK_LOOKUP("cam_src_clk", mclk0_clk_src.c, "6f.qcom,camera"),
-	CLK_LOOKUP("cam_src_clk", mclk0_clk_src.c, "90.qcom,camera"),
+	CLK_LOOKUP("cam_src_clk", mclk1_clk_src.c, "90.qcom,camera"),
 	CLK_LOOKUP("cam_src_clk", mclk0_clk_src.c, "6d.qcom,camera"),
 	CLK_LOOKUP("cam_src_clk", mclk0_clk_src.c, "6a.qcom,camera"),
 	CLK_LOOKUP("cam_src_clk", mclk0_clk_src.c, "6c.qcom,camera"),
 	CLK_LOOKUP("cam_src_clk", mclk0_clk_src.c, "20.qcom,camera"),
 	CLK_LOOKUP("cam_clk", camss_mclk0_clk.c, "6f.qcom,camera"),
-	CLK_LOOKUP("cam_clk", camss_mclk0_clk.c, "90.qcom,camera"),
+	CLK_LOOKUP("cam_clk", camss_mclk1_clk.c, "90.qcom,camera"),
 	CLK_LOOKUP("cam_clk", camss_mclk0_clk.c, "6d.qcom,camera"),
 	CLK_LOOKUP("cam_clk", camss_mclk0_clk.c, "6a.qcom,camera"),
 	CLK_LOOKUP("cam_clk", camss_mclk0_clk.c, "6c.qcom,camera"),
 	CLK_LOOKUP("cam_clk", camss_mclk0_clk.c, "20.qcom,camera"),
+	CLK_LOOKUP("cam_src_clk", mclk0_clk_src.c, "0.qcom,camera"),
+	CLK_LOOKUP("cam_src_clk", mclk0_clk_src.c, "1.qcom,camera"),
+	CLK_LOOKUP("cam_clk", camss_mclk0_clk.c, "0.qcom,camera"),
+	CLK_LOOKUP("cam_clk", camss_mclk0_clk.c, "1.qcom,camera"),
 
 	/* eeprom clocks */
 	CLK_LOOKUP("cam_src_clk", mclk0_clk_src.c, "6c.qcom,eeprom"),
@@ -3491,8 +3497,36 @@
 					"fda08400.qcom,csid"),
 
 	/* ISPIF clocks */
+
 	CLK_LOOKUP("ispif_ahb_clk", camss_ispif_ahb_clk.c,
-		"fda0a000.qcom,ispif"),
+					"fda0a000.qcom,ispif"),
+	CLK_LOOKUP("camss_top_ahb_clk", camss_top_ahb_clk.c,
+					"fda0a000.qcom,ispif"),
+	CLK_LOOKUP("csi0_ahb_clk", camss_csi0_ahb_clk.c,
+					"fda0a000.qcom,ispif"),
+	CLK_LOOKUP("csi0_src_clk", csi0_clk_src.c,
+					"fda0a000.qcom,ispif"),
+	CLK_LOOKUP("csi0_phy_clk", camss_csi0phy_clk.c,
+					"fda0a000.qcom,ispif"),
+	CLK_LOOKUP("csi0_clk", camss_csi0_clk.c,
+					"fda0a000.qcom,ispif"),
+	CLK_LOOKUP("csi0_pix_clk", camss_csi0pix_clk.c,
+					"fda0a000.qcom,ispif"),
+	CLK_LOOKUP("csi0_rdi_clk", camss_csi0rdi_clk.c,
+					"fda0a000.qcom,ispif"),
+
+	CLK_LOOKUP("csi1_ahb_clk", camss_csi1_ahb_clk.c,
+					"fda0a000.qcom,ispif"),
+	CLK_LOOKUP("csi1_src_clk", csi1_clk_src.c,
+					"fda0a000.qcom,ispif"),
+	CLK_LOOKUP("csi1_phy_clk", camss_csi1phy_clk.c,
+					"fda0a000.qcom,ispif"),
+	CLK_LOOKUP("csi1_clk", camss_csi1_clk.c,
+					"fda0a000.qcom,ispif"),
+	CLK_LOOKUP("csi1_pix_clk", camss_csi1pix_clk.c,
+					"fda0a000.qcom,ispif"),
+	CLK_LOOKUP("csi1_rdi_clk", camss_csi1rdi_clk.c,
+					"fda0a000.qcom,ispif"),
 	CLK_LOOKUP("camss_vfe_vfe_clk", camss_vfe_vfe0_clk.c,
 		"fda0a000.qcom,ispif"),
 	CLK_LOOKUP("camss_csi_vfe_clk", camss_csi_vfe0_clk.c,
@@ -3568,7 +3602,6 @@
 	CLK_LOOKUP("cam_gp1_clk", camss_gp1_clk.c, ""),
 	CLK_LOOKUP("iface_clk", camss_micro_ahb_clk.c, ""),
 
-	CLK_LOOKUP("", mmss_mmssnoc_bto_ahb_clk.c, ""),
 	CLK_LOOKUP("", mmss_mmssnoc_axi_clk.c, ""),
 	CLK_LOOKUP("", mmss_s0_axi_clk.c, ""),
 
diff --git a/arch/arm/mach-msm/clock-8610.c b/arch/arm/mach-msm/clock-8610.c
index c7bf92c..e9c749a 100644
--- a/arch/arm/mach-msm/clock-8610.c
+++ b/arch/arm/mach-msm/clock-8610.c
@@ -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
@@ -527,6 +527,7 @@
 static DEFINE_CLK_MEASURE(apc2_m_clk);
 static DEFINE_CLK_MEASURE(apc3_m_clk);
 static DEFINE_CLK_MEASURE(l2_m_clk);
+static DEFINE_CLK_MEASURE(wcnss_m_clk);
 
 #define APCS_SH_PLL_MODE        0x000
 #define APCS_SH_PLL_L_VAL       0x004
@@ -2346,17 +2347,6 @@
 	},
 };
 
-static struct branch_clk mmss_mmssnoc_bto_ahb_clk = {
-	.cbcr_reg = MMSS_MMSSNOC_BTO_AHB_CBCR,
-	.has_sibling = 1,
-	.base = &virt_bases[MMSS_BASE],
-	.c = {
-		.dbg_name = "mmss_mmssnoc_bto_ahb_clk",
-		.ops = &clk_ops_branch,
-		CLK_INIT(mmss_mmssnoc_bto_ahb_clk.c),
-	},
-};
-
 static struct branch_clk oxili_ahb_clk = {
 	.cbcr_reg = OXILI_AHB_CBCR,
 	.bcr_reg = OXILI_AHB_BCR,
@@ -2509,6 +2499,7 @@
 	{                   &bimc_clk.c, GCC_BASE, 0x0155},
 	{          &gcc_bimc_smmu_clk.c, GCC_BASE, 0x015e},
 	{       &gcc_lpass_q6_axi_clk.c, GCC_BASE, 0x0160},
+	{                  &wcnss_m_clk, GCC_BASE, 0x0198},
 
 	{     &mmssnoc_ahb_clk.c, MMSS_BASE, 0x0001},
 	{   &mmss_misc_ahb_clk.c, MMSS_BASE, 0x0003},
@@ -2989,7 +2980,6 @@
 	CLK_LOOKUP("core_clk",                mdp_vsync_clk.c, ""),
 	CLK_LOOKUP("core_clk",            mmss_misc_ahb_clk.c, ""),
 	CLK_LOOKUP("core_clk",              mmss_s0_axi_clk.c, ""),
-	CLK_LOOKUP("core_clk",     mmss_mmssnoc_bto_ahb_clk.c, ""),
 	CLK_LOOKUP("core_clk",         mmss_mmssnoc_axi_clk.c, ""),
 	CLK_LOOKUP("core_clk",                      vfe_clk.c, ""),
 	CLK_LOOKUP("core_clk",                  vfe_ahb_clk.c, ""),
@@ -3027,15 +3017,19 @@
 	/* MM sensor clocks */
 	CLK_LOOKUP("cam_src_clk", mclk0_clk_src.c, "6-006f"),
 	CLK_LOOKUP("cam_src_clk", mclk0_clk_src.c, "6-0034"),
+	CLK_LOOKUP("cam_src_clk", mclk0_clk_src.c, "6-0001"),
 	CLK_LOOKUP("cam_src_clk", mclk0_clk_src.c, "6-007d"),
 	CLK_LOOKUP("cam_src_clk", mclk0_clk_src.c, "6-006d"),
+	CLK_LOOKUP("cam_src_clk", mclk1_clk_src.c, "6-0002"),
 	CLK_LOOKUP("cam_src_clk", mclk1_clk_src.c, "6-0078"),
 	CLK_LOOKUP("cam_src_clk", mclk0_clk_src.c, "6-0020"),
 	CLK_LOOKUP("cam_src_clk", mclk0_clk_src.c, "6-006a"),
 	CLK_LOOKUP("cam_clk", mclk0_clk.c, "6-006f"),
 	CLK_LOOKUP("cam_clk", mclk0_clk.c, "6-0034"),
+	CLK_LOOKUP("cam_clk", mclk0_clk.c, "6-0001"),
 	CLK_LOOKUP("cam_clk", mclk0_clk.c, "6-007d"),
 	CLK_LOOKUP("cam_clk", mclk0_clk.c, "6-006d"),
+	CLK_LOOKUP("cam_clk", mclk1_clk.c, "6-0002"),
 	CLK_LOOKUP("cam_clk", mclk1_clk.c, "6-0078"),
 	CLK_LOOKUP("cam_clk", mclk0_clk.c, "6-0020"),
 	CLK_LOOKUP("cam_clk", mclk0_clk.c, "6-006a"),
@@ -3111,6 +3105,8 @@
 	CLK_LOOKUP("xo",        cxo_acpu_clk.c, "f9011050.qcom,acpuclk"),
 	CLK_LOOKUP("gpll0", gpll0_ao_clk_src.c, "f9011050.qcom,acpuclk"),
 	CLK_LOOKUP("a7sspll",        a7sspll.c, "f9011050.qcom,acpuclk"),
+	CLK_LOOKUP("clk-4",  gpll0_ao_clk_src.c, "f9011050.qcom,clock-a7"),
+	CLK_LOOKUP("clk-5", a7sspll.c, "f9011050.qcom,clock-a7"),
 
 	CLK_LOOKUP("measure_clk", apc0_m_clk, ""),
 	CLK_LOOKUP("measure_clk", apc1_m_clk, ""),
@@ -3118,6 +3114,9 @@
 	CLK_LOOKUP("measure_clk", apc3_m_clk, ""),
 	CLK_LOOKUP("measure_clk",   l2_m_clk, ""),
 
+	CLK_LOOKUP("measure",   measure_clk.c, "fb000000.qcom,wcnss-wlan"),
+	CLK_LOOKUP("wcnss_debug", wcnss_m_clk, "fb000000.qcom,wcnss-wlan"),
+
 	CLK_LOOKUP("xo",     cxo_wlan_clk.c, "fb000000.qcom,wcnss-wlan"),
 	CLK_LOOKUP("rf_clk",       cxo_a1.c, "fb000000.qcom,wcnss-wlan"),
 
@@ -3143,6 +3142,12 @@
 	CLK_LOOKUP("bus_clk",      gcc_ce1_axi_clk.c,  "scm"),
 	CLK_LOOKUP("core_clk_src", ce1_clk_src.c,      "scm"),
 
+	/* GUD Clocks */
+	CLK_LOOKUP("core_clk",     gcc_ce1_clk.c,      "mcd"),
+	CLK_LOOKUP("iface_clk",    gcc_ce1_ahb_clk.c,  "mcd"),
+	CLK_LOOKUP("bus_clk",      gcc_ce1_axi_clk.c,  "mcd"),
+	CLK_LOOKUP("core_clk_src", ce1_clk_src.c,      "mcd"),
+
 	/* Add QCEDEV clocks */
 	CLK_LOOKUP("core_clk",     gcc_ce1_clk.c,      "fd400000.qcom,qcedev"),
 	CLK_LOOKUP("iface_clk",    gcc_ce1_ahb_clk.c,  "fd400000.qcom,qcedev"),
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 0051578..1847bf4
--- a/arch/arm/mach-msm/clock-8974.c
+++ b/arch/arm/mach-msm/clock-8974.c
@@ -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
@@ -579,17 +579,6 @@
 			| BVAL(10, 8, s##_mm_source_val), \
 	}
 
-#define F_HDMI(f, s, div, m, n) \
-	{ \
-		.freq_hz = (f), \
-		.src_clk = &s##_clk_src, \
-		.m_val = (m), \
-		.n_val = ~((n)-(m)) * !!(n), \
-		.d_val = ~(n),\
-		.div_src_val = BVAL(4, 0, (int)(2*(div) - 1)) \
-			| BVAL(10, 8, s##_mm_source_val), \
-	}
-
 #define F_EDP(f, s, div, m, n) \
 	{ \
 		.freq_hz = (f), \
@@ -1557,7 +1546,7 @@
 	},
 };
 
-/* This table is for MSM8974Pro AC SDCC1 */
+/* For MSM8974Pro SDCC1 */
 static struct clk_freq_tbl ftbl_gcc_sdcc1_apps_clk_ac[] = {
 	F(   144000,    cxo,  16,   3,  25),
 	F(   400000,    cxo,  12,   1,   4),
@@ -1570,11 +1559,7 @@
 	F_END
 };
 
-/*
- * This table is for:
- * 1) SDCC[1-4] on MSM8974Pro AB, MSM8974 v2 and before
- * 2) SDCC[2-4] on MSM8974Pro AC
- */
+/* For SDCC1 on MSM8974 v2 and SDCC[2-4] on all MSM8974 */
 static struct clk_freq_tbl ftbl_gcc_sdcc1_4_apps_clk[] = {
 	F(   144000,    cxo,  16,   3,  25),
 	F(   400000,    cxo,  12,   1,   4),
@@ -1668,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
 };
@@ -2212,6 +2198,7 @@
 	.en_mask = BIT(5),
 	.base = &virt_bases[GCC_BASE],
 	.c = {
+		.parent = &ce1_clk_src.c,
 		.dbg_name = "gcc_ce1_clk",
 		.ops = &clk_ops_vote,
 		CLK_INIT(gcc_ce1_clk.c),
@@ -2248,6 +2235,7 @@
 	.en_mask = BIT(2),
 	.base = &virt_bases[GCC_BASE],
 	.c = {
+		.parent = &ce2_clk_src.c,
 		.dbg_name = "gcc_ce2_clk",
 		.ops = &clk_ops_vote,
 		CLK_INIT(gcc_ce2_clk.c),
@@ -3267,60 +3255,19 @@
 	},
 };
 
-static int hdmi_pll_clk_enable(struct clk *c)
-{
-	return hdmi_pll_enable();
-}
-
-static void hdmi_pll_clk_disable(struct clk *c)
-{
-	hdmi_pll_disable();
-}
-
-static int hdmi_pll_clk_set_rate(struct clk *c, unsigned long rate)
-{
-	return hdmi_pll_set_rate(rate);
-}
-
-static struct clk_ops clk_ops_hdmi_pll = {
-	.enable = hdmi_pll_clk_enable,
-	.disable = hdmi_pll_clk_disable,
-	.set_rate = hdmi_pll_clk_set_rate,
-};
-
-static struct clk hdmipll_clk_src = {
-	.parent = &cxo_clk_src.c,
-	.dbg_name = "hdmipll_clk_src",
-	.ops = &clk_ops_hdmi_pll,
-	CLK_INIT(hdmipll_clk_src),
-};
-
 static struct clk_freq_tbl ftbl_mdss_extpclk_clk[] = {
-	/*
-	 * The zero rate is required since suspend/resume wipes out the HDMI PHY
-	 * registers. This entry allows the HDMI driver to switch the cached
-	 * rate to zero before suspend and back to the real rate after resume.
-	 */
-	F_HDMI(        0, hdmipll, 1, 0, 0),
-	F_HDMI( 25200000, hdmipll, 1, 0, 0),
-	F_HDMI( 27000000, hdmipll, 1, 0, 0),
-	F_HDMI( 27030000, hdmipll, 1, 0, 0),
-	F_HDMI( 65000000, hdmipll, 1, 0, 0),
-	F_HDMI( 74250000, hdmipll, 1, 0, 0),
-	F_HDMI(108000000, hdmipll, 1, 0, 0),
-	F_HDMI(148500000, hdmipll, 1, 0, 0),
-	F_HDMI(268500000, hdmipll, 1, 0, 0),
-	F_HDMI(297000000, hdmipll, 1, 0, 0),
+	F_MM(148500000, hdmipll, 1, 0, 0),
 	F_END
 };
 
 static struct rcg_clk extpclk_clk_src = {
 	.cmd_rcgr_reg = EXTPCLK_CMD_RCGR,
 	.freq_tbl = ftbl_mdss_extpclk_clk,
-	.current_freq = &rcg_dummy_freq,
+	.current_freq = ftbl_mdss_extpclk_clk,
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
 		.dbg_name = "extpclk_clk_src",
+		.parent = &hdmipll_clk_src.c,
 		.ops = &clk_ops_rcg_hdmi,
 		VDD_DIG_FMAX_MAP2(LOW, 148500000, NOMINAL, 297000000),
 		CLK_INIT(extpclk_clk_src.c),
@@ -4293,17 +4240,6 @@
 	},
 };
 
-static struct branch_clk mmss_mmssnoc_bto_ahb_clk = {
-	.cbcr_reg = MMSS_MMSSNOC_BTO_AHB_CBCR,
-	.has_sibling = 1,
-	.base = &virt_bases[MMSS_BASE],
-	.c = {
-		.dbg_name = "mmss_mmssnoc_bto_ahb_clk",
-		.ops = &clk_ops_branch,
-		CLK_INIT(mmss_mmssnoc_bto_ahb_clk.c),
-	},
-};
-
 static struct branch_clk mmss_mmssnoc_axi_clk = {
 	.cbcr_reg = MMSS_MMSSNOC_AXI_CBCR,
 	.has_sibling = 1,
@@ -4490,6 +4426,7 @@
 static DEFINE_CLK_MEASURE(krait1_m_clk);
 static DEFINE_CLK_MEASURE(krait2_m_clk);
 static DEFINE_CLK_MEASURE(krait3_m_clk);
+static DEFINE_CLK_MEASURE(wcnss_m_clk);
 
 #ifdef CONFIG_DEBUG_FS
 
@@ -4590,6 +4527,7 @@
 	{&pnoc_clk.c,                           GCC_BASE, 0x0010},
 	{&snoc_clk.c,                           GCC_BASE, 0x0000},
 	{&bimc_clk.c,                           GCC_BASE, 0x0155},
+	{&wcnss_m_clk,                          GCC_BASE, 0x0198},
 	{&mmss_mmssnoc_axi_clk.c,		MMSS_BASE, 0x0004},
 	{&ocmemnoc_clk.c,			MMSS_BASE, 0x0007},
 	{&ocmemcx_ocmemnoc_clk.c,		MMSS_BASE, 0x0009},
@@ -4933,25 +4871,25 @@
 	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"),
+	CLK_LOOKUP("cam_src_clk", mclk2_clk_src.c, "2.qcom,camera"),
+	CLK_LOOKUP("cam_clk", camss_mclk0_clk.c, "0.qcom,camera"),
+	CLK_LOOKUP("cam_clk", camss_mclk1_clk.c, "1.qcom,camera"),
+	CLK_LOOKUP("cam_clk", camss_mclk2_clk.c, "2.qcom,camera"),
 };
 
 static struct clk_lookup msm_clocks_8974_only[] __initdata = {
-	CLK_LOOKUP("cam_src_clk", mmss_gp0_clk_src.c, "6e.qcom,camera"),
-	CLK_LOOKUP("cam_src_clk", mmss_gp0_clk_src.c, "20.qcom,camera"),
-	CLK_LOOKUP("cam_src_clk", gp1_clk_src.c, "6c.qcom,camera"),
 	CLK_LOOKUP("cam_src_clk", mmss_gp1_clk_src.c, "90.qcom,camera"),
-	CLK_LOOKUP("cam_clk", camss_gp0_clk.c, "6e.qcom,camera"),
-	CLK_LOOKUP("cam_clk", camss_gp0_clk.c, "20.qcom,camera"),
-	CLK_LOOKUP("cam_clk", gcc_gp1_clk.c, "6c.qcom,camera"),
 	CLK_LOOKUP("cam_clk", camss_gp1_clk.c, "90.qcom,camera"),
+	CLK_LOOKUP("cam_src_clk", mmss_gp0_clk_src.c, "0.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", 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 = {
@@ -5038,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"),
@@ -5086,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"),
@@ -5106,6 +5051,9 @@
 	CLK_LOOKUP("sleep_clk", gcc_usb2b_phy_sleep_clk.c, "msm_ehci_host"),
 	CLK_LOOKUP("pwm_clk", div_clk2.c, "0-0048"),
 
+	CLK_LOOKUP("measure",   measure_clk.c, "fb000000.qcom,wcnss-wlan"),
+	CLK_LOOKUP("wcnss_debug", wcnss_m_clk, "fb000000.qcom,wcnss-wlan"),
+
 	/* Multimedia clocks */
 	CLK_LOOKUP("bus_clk_src", axi_clk_src.c, ""),
 	CLK_LOOKUP("bus_clk", mmss_mmssnoc_axi_clk.c, ""),
@@ -5113,6 +5061,7 @@
 	CLK_LOOKUP("core_clk", mdss_edpaux_clk.c, "fd923400.qcom,mdss_edp"),
 	CLK_LOOKUP("pixel_clk", mdss_edppixel_clk.c, "fd923400.qcom,mdss_edp"),
 	CLK_LOOKUP("link_clk", mdss_edplink_clk.c, "fd923400.qcom,mdss_edp"),
+	CLK_LOOKUP("mdp_core_clk", mdss_mdp_clk.c, "fd923400.qcom,mdss_edp"),
 	CLK_LOOKUP("byte_clk", mdss_byte0_clk.c, "fd922800.qcom,mdss_dsi"),
 	CLK_LOOKUP("byte_clk", mdss_byte1_clk.c, "fd922e00.qcom,mdss_dsi"),
 	CLK_LOOKUP("core_clk", mdss_esc0_clk.c, "fd922800.qcom,mdss_dsi"),
@@ -5125,6 +5074,10 @@
 	CLK_LOOKUP("pixel_clk", mdss_pclk1_clk.c, "fd922e00.qcom,mdss_dsi"),
 	CLK_LOOKUP("mdp_core_clk", mdss_mdp_clk.c, "fd922800.qcom,mdss_dsi"),
 	CLK_LOOKUP("mdp_core_clk", mdss_mdp_clk.c, "fd922e00.qcom,mdss_dsi"),
+	CLK_LOOKUP("core_mmss_clk", mmss_misc_ahb_clk.c,
+		"fd922800.qcom,mdss_dsi"),
+	CLK_LOOKUP("core_mmss_clk", mmss_misc_ahb_clk.c,
+		"fd922e00.qcom,mdss_dsi"),
 	CLK_LOOKUP("iface_clk", mdss_ahb_clk.c, "fd922100.qcom,hdmi_tx"),
 	CLK_LOOKUP("alt_iface_clk", mdss_hdmi_ahb_clk.c,
 		"fd922100.qcom,hdmi_tx"),
@@ -5809,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];
@@ -5824,11 +5779,9 @@
 	ce2_clk_src.c.fmax[VDD_DIG_NOMINAL] = 150000000;
 	ce2_clk_src.freq_tbl = ftbl_gcc_ce2_pro_clk;
 
-	if (cpu_is_msm8974pro_ac()) {
-		sdcc1_apps_clk_src.c.fmax[VDD_DIG_LOW] = 200000000;
-		sdcc1_apps_clk_src.c.fmax[VDD_DIG_NOMINAL] = 400000000;
-		sdcc1_apps_clk_src.freq_tbl = ftbl_gcc_sdcc1_apps_clk_ac;
-	}
+	sdcc1_apps_clk_src.c.fmax[VDD_DIG_LOW] = 200000000;
+	sdcc1_apps_clk_src.c.fmax[VDD_DIG_NOMINAL] = 400000000;
+	sdcc1_apps_clk_src.freq_tbl = ftbl_gcc_sdcc1_apps_clk_ac;
 
 	vfe0_clk_src.c.fmax[VDD_DIG_LOW] = 150000000;
 	vfe0_clk_src.c.fmax[VDD_DIG_NOMINAL] = 320000000;
diff --git a/arch/arm/mach-msm/clock-a7.c b/arch/arm/mach-msm/clock-a7.c
index 5b8dc4e..a610a23 100644
--- a/arch/arm/mach-msm/clock-a7.c
+++ b/arch/arm/mach-msm/clock-a7.c
@@ -97,9 +97,7 @@
 
 static int cortex_enable(struct mux_div_clk *md)
 {
-	u32 src_sel = parent_to_src_sel(md->parents, md->num_parents,
-							md->c.parent);
-	return cortex_set_config(md, src_sel, md->data.div);
+	return cortex_set_config(md, md->src_sel, md->data.div);
 }
 
 static void cortex_disable(struct mux_div_clk *md)
@@ -193,7 +191,8 @@
 	if (!c->fmax)
 		return -ENOMEM;
 
-	array = devm_kzalloc(&pdev->dev, prop_len * sizeof(u32), GFP_KERNEL);
+	array = devm_kzalloc(&pdev->dev,
+			prop_len * sizeof(u32) * 2, GFP_KERNEL);
 	if (!array)
 		return -ENOMEM;
 
diff --git a/arch/arm/mach-msm/clock-krait-8974.c b/arch/arm/mach-msm/clock-krait-8974.c
index 24fe303..4f133fc 100644
--- a/arch/arm/mach-msm/clock-krait-8974.c
+++ b/arch/arm/mach-msm/clock-krait-8974.c
@@ -414,7 +414,7 @@
 };
 
 static void get_krait_bin_format_b(struct platform_device *pdev,
-					int *speed, int *pvs, int *ver)
+					int *speed, int *pvs, int *pvs_ver)
 {
 	u32 pte_efuse, redundant_sel;
 	struct resource *res;
@@ -422,7 +422,7 @@
 
 	*speed = 0;
 	*pvs = 0;
-	*ver = 0;
+	*pvs_ver = 0;
 
 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "efuse");
 	if (!res) {
@@ -443,7 +443,7 @@
 	*speed = pte_efuse & 0x7;
 	/* 4 bits of PVS are in efuse register bits 31, 8-6. */
 	*pvs = ((pte_efuse >> 28) & 0x8) | ((pte_efuse >> 6) & 0x7);
-	*ver = (pte_efuse >> 4) & 0x3;
+	*pvs_ver = (pte_efuse >> 4) & 0x3;
 
 	switch (redundant_sel) {
 	case 1:
@@ -471,7 +471,7 @@
 		*pvs = 0;
 	}
 
-	dev_info(&pdev->dev, "PVS version: %d\n", *ver);
+	dev_info(&pdev->dev, "PVS version: %d\n", *pvs_ver);
 
 	devm_iounmap(&pdev->dev, base);
 }
@@ -585,12 +585,16 @@
 	}
 }
 
+static char table_name[] = "qcom,speedXX-pvsXX-bin-vXX";
+module_param_string(table_name, table_name, sizeof(table_name), S_IRUGO);
+static unsigned int pvs_config_ver;
+module_param(pvs_config_ver, uint, S_IRUGO);
+
 static int clock_krait_8974_driver_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
 	struct clk *c;
-	int speed, pvs, ver, rows, cpu;
-	char prop_name[] = "qcom,speedXX-pvsXX-bin-vXX";
+	int speed, pvs, pvs_ver, config_ver, rows, cpu;
 	unsigned long *freq, cur_rate, aux_rate;
 	int *uv, *ua;
 	u32 *dscr, vco_mask, config_val;
@@ -673,15 +677,22 @@
 	if (!ret)
 		hdata.user_vco_mask = vco_mask;
 
-	get_krait_bin_format_b(pdev, &speed, &pvs, &ver);
-	snprintf(prop_name, ARRAY_SIZE(prop_name),
-			"qcom,speed%d-pvs%d-bin-v%d", speed, pvs, ver);
+	ret = of_property_read_u32(dev->of_node, "qcom,pvs-config-ver",
+			&config_ver);
+	if (!ret) {
+		pvs_config_ver = config_ver;
+		dev_info(&pdev->dev, "PVS config version: %d\n", config_ver);
+	}
 
-	rows = parse_tbl(dev, prop_name, 3,
+	get_krait_bin_format_b(pdev, &speed, &pvs, &pvs_ver);
+	snprintf(table_name, ARRAY_SIZE(table_name),
+			"qcom,speed%d-pvs%d-bin-v%d", speed, pvs, pvs_ver);
+
+	rows = parse_tbl(dev, table_name, 3,
 			(u32 **) &freq, (u32 **) &uv, (u32 **) &ua);
 	if (rows < 0) {
 		/* Fall back to most conservative PVS table */
-		dev_err(dev, "Unable to load voltage plan %s!\n", prop_name);
+		dev_err(dev, "Unable to load voltage plan %s!\n", table_name);
 		ret = parse_tbl(dev, "qcom,speed0-pvs0-bin-v0", 3,
 				(u32 **) &freq, (u32 **) &uv, (u32 **) &ua);
 		if (ret < 0) {
diff --git a/arch/arm/mach-msm/clock-local2.c b/arch/arm/mach-msm/clock-local2.c
index cc6f290..e3693ee 100644
--- a/arch/arm/mach-msm/clock-local2.c
+++ b/arch/arm/mach-msm/clock-local2.c
@@ -843,23 +843,16 @@
  */
 static int rcg_clk_set_rate_hdmi(struct clk *c, unsigned long rate)
 {
-	struct clk_freq_tbl *nf;
 	struct rcg_clk *rcg = to_rcg_clk(c);
+	struct clk_freq_tbl *nf = rcg->freq_tbl;
 	int rc;
 
-	for (nf = rcg->freq_tbl; nf->freq_hz != rate; nf++)
-		if (nf->freq_hz == FREQ_END) {
-			rc = -EINVAL;
-			goto out;
-		}
-
 	rc = clk_set_rate(nf->src_clk, rate);
 	if (rc < 0)
 		goto out;
 	set_rate_hid(rcg, nf);
 
 	rcg->current_freq = nf;
-	c->parent = nf->src_clk;
 out:
 	return rc;
 }
@@ -870,12 +863,6 @@
 	struct clk *clk;
 	struct clk_freq_tbl *freq;
 	uint32_t rate;
-	u32 cmd_rcgr_regval;
-
-	/* Is there a pending configuration? */
-	cmd_rcgr_regval = readl_relaxed(CMD_RCGR_REG(rcg));
-	if (cmd_rcgr_regval & CMD_RCGR_CONFIG_DIRTY_MASK)
-		return NULL;
 
 	/* Figure out what rate the rcg is running at */
 	for (freq = rcg->freq_tbl; freq->freq_hz != FREQ_END; freq++) {
@@ -895,6 +882,21 @@
 	return freq->src_clk;
 }
 
+static struct clk *rcg_hdmi_clk_get_parent(struct clk *c)
+{
+	struct rcg_clk *rcg = to_rcg_clk(c);
+	struct clk_freq_tbl *freq = rcg->freq_tbl;
+	u32 cmd_rcgr_regval;
+
+	/* Is there a pending configuration? */
+	cmd_rcgr_regval = readl_relaxed(CMD_RCGR_REG(rcg));
+	if (cmd_rcgr_regval & CMD_RCGR_CONFIG_DIRTY_MASK)
+		return NULL;
+
+	rcg->current_freq->freq_hz = clk_get_rate(c->parent);
+
+	return freq->src_clk;
+}
 
 static DEFINE_SPINLOCK(mux_reg_lock);
 
@@ -1007,7 +1009,7 @@
 	.list_rate = rcg_clk_list_rate,
 	.round_rate = rcg_clk_round_rate,
 	.handoff = rcg_clk_handoff,
-	.get_parent = rcg_clk_get_parent,
+	.get_parent = rcg_hdmi_clk_get_parent,
 };
 
 struct clk_ops clk_ops_rcg_edp = {
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/clock-mdss-8974.c b/arch/arm/mach-msm/clock-mdss-8974.c
index b500e1d..b63008f 100644
--- a/arch/arm/mach-msm/clock-mdss-8974.c
+++ b/arch/arm/mach-msm/clock-mdss-8974.c
@@ -151,6 +151,7 @@
 
 #define PLL_POLL_MAX_READS	10
 #define PLL_POLL_TIMEOUT_US	50
+#define SEQ_M_MAX_COUNTER	7
 
 static long vco_cached_rate;
 static unsigned char *mdss_dsi_base;
@@ -171,23 +172,71 @@
 		(!(readl_relaxed(gdsc_base) & BIT(0)));
 }
 
-void hdmi_pll_disable(void)
+/* Auto PLL calibaration */
+static int mdss_ahb_clk_enable(int enable)
 {
-	clk_enable(mdss_ahb_clk);
+	int rc = 0;
+
+	/* todo: Ideally, we should enable/disable GDSC whenever we are
+	 * attempting to enable/disable MDSS AHB clock.
+	 * For now, just return error if  GDSC is not enabled.
+	 */
+	if (!mdss_gdsc_enabled()) {
+		pr_err("%s: mdss GDSC is not enabled\n", __func__);
+		return -EPERM;
+	}
+
+	if (enable)
+		rc = clk_prepare_enable(mdss_ahb_clk);
+	else
+		clk_disable_unprepare(mdss_ahb_clk);
+
+	return rc;
+}
+
+static void hdmi_vco_disable(struct clk *c)
+{
+	u32 rc;
+
+	if (!mdss_gdsc_enabled()) {
+		pr_err("%s: mdss GDSC is not enabled\n", __func__);
+		return;
+	}
+
+	rc = clk_enable(mdss_ahb_clk);
+	if (rc) {
+		pr_err("%s: failed to enable mdss ahb clock. rc=%d\n",
+			__func__, rc);
+		return;
+	}
+
 	REG_W(0x0, hdmi_phy_pll_base + HDMI_UNI_PLL_GLB_CFG);
 	udelay(5);
 	REG_W(0x0, hdmi_phy_base + HDMI_PHY_GLB_CFG);
+
 	clk_disable(mdss_ahb_clk);
 
 	hdmi_pll_on = 0;
-} /* hdmi_pll_disable */
+} /* hdmi_vco_disable */
 
-int hdmi_pll_enable(void)
+static int hdmi_vco_enable(struct clk *c)
 {
 	u32 status;
+	u32 rc;
 	u32 max_reads, timeout_us;
 
-	clk_enable(mdss_ahb_clk);
+	if (!mdss_gdsc_enabled()) {
+		pr_err("%s: mdss GDSC is not enabled\n", __func__);
+		return -EPERM;
+	}
+
+	rc = clk_enable(mdss_ahb_clk);
+	if (rc) {
+		pr_err("%s: failed to enable mdss ahb clock. rc=%d\n",
+			__func__, rc);
+		return rc;
+	}
+
 	/* Global Enable */
 	REG_W(0x81, hdmi_phy_base + HDMI_PHY_GLB_CFG);
 	/* Power up power gen */
@@ -212,7 +261,7 @@
 		status, ((status & BIT(0)) == 1), max_reads, timeout_us)) {
 		pr_err("%s: hdmi phy pll status=%x failed to Lock\n",
 		       __func__, status);
-		hdmi_pll_disable();
+		hdmi_vco_disable(c);
 		clk_disable(mdss_ahb_clk);
 		return -EINVAL;
 	}
@@ -226,7 +275,7 @@
 		status, ((status & BIT(0)) == 1), max_reads, timeout_us)) {
 		pr_err("%s: hdmi phy status=%x failed to Lock\n",
 		       __func__, status);
-		hdmi_pll_disable();
+		hdmi_vco_disable(c);
 		clk_disable(mdss_ahb_clk);
 		return -EINVAL;
 	}
@@ -236,25 +285,173 @@
 	hdmi_pll_on = 1;
 
 	return 0;
-} /* hdmi_pll_enable */
+} /* hdmi_vco_enable */
 
-int hdmi_pll_set_rate(unsigned long rate)
+static inline struct hdmi_pll_vco_clk *to_hdmi_vco_clk(struct clk *clk)
+{
+	return container_of(clk, struct hdmi_pll_vco_clk, c);
+}
+
+static void hdmi_phy_pll_calculator(u32 vco_freq)
+{
+	u32 ref_clk             = 19200000;
+	u32 sdm_mode            = 1;
+	u32 ref_clk_multiplier  = sdm_mode == 1 ? 2 : 1;
+	u32 int_ref_clk_freq    = ref_clk * ref_clk_multiplier;
+	u32 fbclk_pre_div       = 1;
+	u32 ssc_mode            = 0;
+	u32 kvco                = 270;
+	u32 vdd                 = 95;
+	u32 ten_power_six       = 1000000;
+	u32 ssc_ds_ppm          = ssc_mode ? 5000 : 0;
+	u32 sdm_res             = 16;
+	u32 ssc_tri_step        = 32;
+	u32 ssc_freq            = 2;
+	u64 ssc_ds              = vco_freq * ssc_ds_ppm;
+	u32 div_in_freq         = vco_freq / fbclk_pre_div;
+	u64 dc_offset           = (div_in_freq / int_ref_clk_freq - 1) *
+					ten_power_six * 10;
+	u32 ssc_kdiv            = (int_ref_clk_freq / ssc_freq) -
+					ten_power_six;
+	u64 sdm_freq_seed;
+	u32 ssc_tri_inc;
+	u64 fb_div_n;
+
+	u32 val;
+
+	pr_debug("%s: vco_freq = %u\n", __func__, vco_freq);
+
+	do_div(ssc_ds, (u64)ten_power_six);
+
+	fb_div_n = (u64)div_in_freq * (u64)ten_power_six * 10;
+	do_div(fb_div_n, int_ref_clk_freq);
+
+	sdm_freq_seed = ((fb_div_n - dc_offset - ten_power_six * 10) *
+				(1 << sdm_res)  * 10) + 5;
+	do_div(sdm_freq_seed, ((u64)ten_power_six * 100));
+
+	ssc_tri_inc = (u32)ssc_ds;
+	ssc_tri_inc = (ssc_tri_inc / int_ref_clk_freq) * (1 << 16) /
+			ssc_tri_step;
+
+	val = (ref_clk_multiplier == 2 ? 1 : 0) +
+		((fbclk_pre_div == 2 ? 1 : 0) * 16);
+	pr_debug("%s: HDMI_UNI_PLL_REFCLK_CFG = 0x%x\n", __func__, val);
+	REG_W(val, hdmi_phy_pll_base + HDMI_UNI_PLL_REFCLK_CFG);
+
+	REG_W(0x02, hdmi_phy_pll_base + HDMI_UNI_PLL_CHFPUMP_CFG);
+	REG_W(0x19, hdmi_phy_pll_base + HDMI_UNI_PLL_VCOLPF_CFG);
+	REG_W(0x04, hdmi_phy_pll_base + HDMI_UNI_PLL_VREG_CFG);
+	REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_PWRGEN_CFG);
+	REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV2_CFG);
+	REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV3_CFG);
+	REG_W(0x0E, hdmi_phy_pll_base + HDMI_UNI_PLL_LPFR_CFG);
+	REG_W(0x20, hdmi_phy_pll_base + HDMI_UNI_PLL_LPFC1_CFG);
+	REG_W(0x0D, hdmi_phy_pll_base + HDMI_UNI_PLL_LPFC2_CFG);
+
+	do_div(dc_offset, (u64)ten_power_six * 10);
+	val = sdm_mode == 0 ? 64 + dc_offset : 0;
+	pr_debug("%s: HDMI_UNI_PLL_SDM_CFG0 = 0x%x\n", __func__, val);
+	REG_W(val, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG0);
+
+	val = 64 + dc_offset;
+	pr_debug("%s: HDMI_UNI_PLL_SDM_CFG1 = 0x%x\n", __func__, val);
+	REG_W(val, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG1);
+
+	val = sdm_freq_seed & 0xFF;
+	pr_debug("%s: HDMI_UNI_PLL_SDM_CFG2 = 0x%x\n", __func__, val);
+	REG_W(val, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG2);
+
+	val = (sdm_freq_seed >> 8) & 0xFF;
+	pr_debug("%s: HDMI_UNI_PLL_SDM_CFG3 = 0x%x\n", __func__, val);
+	REG_W(val, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG3);
+
+	val = (sdm_freq_seed >> 16) & 0xFF;
+	pr_debug("%s: HDMI_UNI_PLL_SDM_CFG4 = 0x%x\n", __func__, val);
+	REG_W(val, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG4);
+
+	val = (ssc_mode == 0 ? 128 : 0) + (ssc_kdiv / ten_power_six);
+	pr_debug("%s: HDMI_UNI_PLL_SSC_CFG0 = 0x%x\n", __func__, val);
+	REG_W(val, hdmi_phy_pll_base + HDMI_UNI_PLL_SSC_CFG0);
+
+	val = ssc_tri_inc & 0xFF;
+	pr_debug("%s: HDMI_UNI_PLL_SSC_CFG1 = 0x%x\n", __func__, val);
+	REG_W(val, hdmi_phy_pll_base + HDMI_UNI_PLL_SSC_CFG1);
+
+	val = (ssc_tri_inc >> 8) & 0xFF;
+	pr_debug("%s: HDMI_UNI_PLL_SSC_CFG2 = 0x%x\n", __func__, val);
+	REG_W(val, hdmi_phy_pll_base + HDMI_UNI_PLL_SSC_CFG2);
+
+	pr_debug("%s: HDMI_UNI_PLL_SSC_CFG3 = 0x%x\n", __func__, ssc_tri_step);
+	REG_W(ssc_tri_step, hdmi_phy_pll_base + HDMI_UNI_PLL_SSC_CFG3);
+
+	REG_W(0x10, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG0);
+	REG_W(0x1A, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG1);
+	REG_W(0x05, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG2);
+	REG_W(0x0A, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG0);
+	REG_W(0x04, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG1);
+	REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG2);
+	REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG3);
+	REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG4);
+	REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG5);
+
+	val = (kvco * vdd * 10000) / 6;
+	val += 500000;
+	val /= ten_power_six;
+	pr_debug("%s: HDMI_UNI_PLL_CAL_CFG6 = 0x%x\n", __func__, val);
+	REG_W(val & 0xFF, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG6);
+
+	val = (kvco * vdd * 10000) / 6;
+	val -= ten_power_six;
+	val /= ten_power_six;
+	val = (val >> 8) & 0xFF;
+	pr_debug("%s: HDMI_UNI_PLL_CAL_CFG7 = 0x%x\n", __func__, val);
+	REG_W(val, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG7);
+
+	val = (ref_clk * 5) / ten_power_six;
+	pr_debug("%s: HDMI_UNI_PLL_CAL_CFG8 = 0x%x\n", __func__, val);
+	REG_W(val, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG8);
+
+	val = ((ref_clk * 5) / ten_power_six) >> 8;
+	pr_debug("%s: HDMI_UNI_PLL_CAL_CFG9 = 0x%x\n", __func__, val);
+	REG_W(val, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG9);
+
+	vco_freq /= ten_power_six;
+	val = vco_freq & 0xFF;
+	pr_debug("%s: HDMI_UNI_PLL_CAL_CFG10 = 0x%x\n", __func__, val);
+	REG_W(val, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG10);
+
+	val = vco_freq >> 8;
+	pr_debug("%s: HDMI_UNI_PLL_CAL_CFG11 = 0x%x\n", __func__, val);
+	REG_W(val, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG11);
+} /* hdmi_phy_pll_calculator */
+
+static int hdmi_vco_set_rate(struct clk *c, unsigned long rate)
 {
 	unsigned int set_power_dwn = 0;
+	int rc = 0;
+
+	struct hdmi_pll_vco_clk *vco = to_hdmi_vco_clk(c);
 
 	if (hdmi_pll_on) {
-		hdmi_pll_disable();
+		hdmi_vco_disable(c);
 		set_power_dwn = 1;
 	}
 
-	clk_enable(mdss_ahb_clk);
+	rc = mdss_ahb_clk_enable(1);
+	if (rc) {
+		pr_err("%s: failed to enable mdss ahb clock. rc=%d\n",
+			__func__, rc);
+		return rc;
+	}
+
 	pr_debug("%s: rate=%ld\n", __func__, rate);
+
 	switch (rate) {
 	case 0:
-		/* This case is needed for suspend/resume. */
-	break;
+		break;
 
-	case 25200000:
+	case 756000000:
 		/* 640x480p60 */
 		REG_W(0x81, hdmi_phy_base + HDMI_PHY_GLB_CFG);
 		REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_GLB_CFG);
@@ -271,7 +468,6 @@
 		REG_W(0x10, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG0);
 		REG_W(0x1A, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG1);
 		REG_W(0x05, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG2);
-		REG_W(0x03, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV1_CFG);
 		REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV2_CFG);
 		REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV3_CFG);
 		REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG2);
@@ -299,7 +495,7 @@
 		udelay(200);
 	break;
 
-	case 27000000:
+	case 810000000:
 		/* 576p50/576i50 case */
 		REG_W(0x81, hdmi_phy_base + HDMI_PHY_GLB_CFG);
 		REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_GLB_CFG);
@@ -316,7 +512,6 @@
 		REG_W(0x10, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG0);
 		REG_W(0X1A, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG1);
 		REG_W(0x05, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG2);
-		REG_W(0x03, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV1_CFG);
 		REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV2_CFG);
 		REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV3_CFG);
 		REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG2);
@@ -344,7 +539,7 @@
 		udelay(200);
 	break;
 
-	case 27030000:
+	case 810900000:
 		/* 480p60/480i60 case */
 		REG_W(0x81, hdmi_phy_base + HDMI_PHY_GLB_CFG);
 		REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_GLB_CFG);
@@ -361,7 +556,6 @@
 		REG_W(0x10, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG0);
 		REG_W(0x1A, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG1);
 		REG_W(0x05, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG2);
-		REG_W(0x03, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV1_CFG);
 		REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV2_CFG);
 		REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV3_CFG);
 		REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG2);
@@ -388,7 +582,7 @@
 		REG_W(0x05, hdmi_phy_base + HDMI_PHY_TXCAL_CFG3);
 		udelay(200);
 	break;
-	case 65000000:
+	case 650000000:
 		REG_W(0x81, hdmi_phy_base + HDMI_PHY_GLB_CFG);
 		REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_GLB_CFG);
 		REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_REFCLK_CFG);
@@ -404,7 +598,6 @@
 		REG_W(0x10, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG0);
 		REG_W(0x1A, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG1);
 		REG_W(0x05, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG2);
-		REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV1_CFG);
 		REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV2_CFG);
 		REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV3_CFG);
 		REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG2);
@@ -431,7 +624,7 @@
 		REG_W(0x05, hdmi_phy_base + HDMI_PHY_TXCAL_CFG3);
 		udelay(200);
 	break;
-	case 74250000:
+	case 742500000:
 		/*
 		 * 720p60/720p50/1080i60/1080i50
 		 * 1080p24/1080p30/1080p25 case
@@ -451,7 +644,6 @@
 		REG_W(0x10, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG0);
 		REG_W(0x1A, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG1);
 		REG_W(0x05, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG2);
-		REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV1_CFG);
 		REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV2_CFG);
 		REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV3_CFG);
 		REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG2);
@@ -479,7 +671,7 @@
 		udelay(200);
 	break;
 
-	case 108000000:
+	case 1080000000:
 		REG_W(0x81, hdmi_phy_base + HDMI_PHY_GLB_CFG);
 		REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_GLB_CFG);
 		REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_REFCLK_CFG);
@@ -495,7 +687,6 @@
 		REG_W(0x10, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG0);
 		REG_W(0x1A, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG1);
 		REG_W(0x05, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG2);
-		REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV1_CFG);
 		REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV2_CFG);
 		REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV3_CFG);
 		REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG2);
@@ -523,51 +714,7 @@
 		udelay(200);
 	break;
 
-	case 148500000:
-		REG_W(0x81, hdmi_phy_base + HDMI_PHY_GLB_CFG);
-		REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_GLB_CFG);
-		REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_REFCLK_CFG);
-		REG_W(0x19, hdmi_phy_pll_base + HDMI_UNI_PLL_VCOLPF_CFG);
-		REG_W(0x0E, hdmi_phy_pll_base + HDMI_UNI_PLL_LPFR_CFG);
-		REG_W(0x20, hdmi_phy_pll_base + HDMI_UNI_PLL_LPFC1_CFG);
-		REG_W(0x0D, hdmi_phy_pll_base + HDMI_UNI_PLL_LPFC2_CFG);
-		REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG0);
-		REG_W(0x52, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG1);
-		REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG2);
-		REG_W(0x56, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG3);
-		REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG4);
-		REG_W(0x10, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG0);
-		REG_W(0x1A, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG1);
-		REG_W(0x05, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG2);
-		REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV1_CFG);
-		REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV2_CFG);
-		REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV3_CFG);
-		REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG2);
-		REG_W(0x60, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG8);
-		REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG9);
-		REG_W(0xE6, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG10);
-		REG_W(0x02, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG11);
-		REG_W(0x1F, hdmi_phy_base + HDMI_PHY_PD_CTRL0);
-		udelay(50);
-
-		REG_W(0x0F, hdmi_phy_pll_base + HDMI_UNI_PLL_GLB_CFG);
-		REG_W(0x00, hdmi_phy_base + HDMI_PHY_PD_CTRL1);
-		REG_W(0x10, hdmi_phy_base + HDMI_PHY_ANA_CFG2);
-		REG_W(0xDB, hdmi_phy_base + HDMI_PHY_ANA_CFG0);
-		REG_W(0x43, hdmi_phy_base + HDMI_PHY_ANA_CFG1);
-		REG_W(0x02, hdmi_phy_base + HDMI_PHY_ANA_CFG2);
-		REG_W(0x00, hdmi_phy_base + HDMI_PHY_ANA_CFG3);
-		REG_W(0x04, hdmi_phy_pll_base + HDMI_UNI_PLL_VREG_CFG);
-		REG_W(0xD0, hdmi_phy_base + HDMI_PHY_DCC_CFG0);
-		REG_W(0x1A, hdmi_phy_base + HDMI_PHY_DCC_CFG1);
-		REG_W(0x00, hdmi_phy_base + HDMI_PHY_TXCAL_CFG0);
-		REG_W(0x00, hdmi_phy_base + HDMI_PHY_TXCAL_CFG1);
-		REG_W(0x02, hdmi_phy_base + HDMI_PHY_TXCAL_CFG2);
-		REG_W(0x05, hdmi_phy_base + HDMI_PHY_TXCAL_CFG3);
-		udelay(200);
-	break;
-
-	case 268500000:
+	case 1342500000:
 		REG_W(0x81, hdmi_phy_base + HDMI_PHY_GLB_CFG);
 		REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_GLB_CFG);
 		REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_REFCLK_CFG);
@@ -583,7 +730,6 @@
 		REG_W(0x10, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG0);
 		REG_W(0x1A, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG1);
 		REG_W(0x05, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG2);
-		REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV1_CFG);
 		REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV2_CFG);
 		REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV3_CFG);
 		REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG2);
@@ -611,7 +757,7 @@
 		udelay(200);
 	break;
 
-	case 297000000:
+	case 1485000000:
 		REG_W(0x81, hdmi_phy_base + HDMI_PHY_GLB_CFG);
 		REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_GLB_CFG);
 		REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_REFCLK_CFG);
@@ -627,7 +773,6 @@
 		REG_W(0x10, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG0);
 		REG_W(0x1A, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG1);
 		REG_W(0x05, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG2);
-		REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV1_CFG);
 		REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV2_CFG);
 		REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV3_CFG);
 		REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG2);
@@ -656,40 +801,68 @@
 	break;
 
 	default:
-		pr_err("%s: not supported rate=%ld\n", __func__, rate);
+		pr_debug("%s: Use pll settings calculator for rate=%ld\n",
+			__func__, rate);
+
+		REG_W(0x81, hdmi_phy_base + HDMI_PHY_GLB_CFG);
+		hdmi_phy_pll_calculator(rate);
+		REG_W(0x1F, hdmi_phy_base + HDMI_PHY_PD_CTRL0);
+		udelay(50);
+
+		REG_W(0x0F, hdmi_phy_pll_base + HDMI_UNI_PLL_GLB_CFG);
+		REG_W(0x00, hdmi_phy_base + HDMI_PHY_PD_CTRL1);
+		REG_W(0x10, hdmi_phy_base + HDMI_PHY_ANA_CFG2);
+		REG_W(0xDB, hdmi_phy_base + HDMI_PHY_ANA_CFG0);
+		REG_W(0x43, hdmi_phy_base + HDMI_PHY_ANA_CFG1);
+
+		if (rate < 825000000) {
+			REG_W(0x01, hdmi_phy_base + HDMI_PHY_ANA_CFG2);
+			REG_W(0x00, hdmi_phy_base + HDMI_PHY_ANA_CFG3);
+		} else if (rate >= 825000000 && rate < 1342500000) {
+			REG_W(0x05, hdmi_phy_base + HDMI_PHY_ANA_CFG2);
+			REG_W(0x03, hdmi_phy_base + HDMI_PHY_ANA_CFG3);
+		} else {
+			REG_W(0x06, hdmi_phy_base + HDMI_PHY_ANA_CFG2);
+			REG_W(0x03, hdmi_phy_base + HDMI_PHY_ANA_CFG3);
+		}
+
+		REG_W(0x04, hdmi_phy_pll_base + HDMI_UNI_PLL_VREG_CFG);
+		REG_W(0xD0, hdmi_phy_base + HDMI_PHY_DCC_CFG0);
+		REG_W(0x1A, hdmi_phy_base + HDMI_PHY_DCC_CFG1);
+		REG_W(0x00, hdmi_phy_base + HDMI_PHY_TXCAL_CFG0);
+		REG_W(0x00, hdmi_phy_base + HDMI_PHY_TXCAL_CFG1);
+
+		if (rate < 825000000)
+			REG_W(0x01, hdmi_phy_base + HDMI_PHY_TXCAL_CFG2);
+		else
+			REG_W(0x00, hdmi_phy_base + HDMI_PHY_TXCAL_CFG2);
+
+		REG_W(0x05, hdmi_phy_base + HDMI_PHY_TXCAL_CFG3);
+		REG_W(0x62, hdmi_phy_base + HDMI_PHY_BIST_PATN0);
+		REG_W(0x03, hdmi_phy_base + HDMI_PHY_BIST_PATN1);
+		REG_W(0x69, hdmi_phy_base + HDMI_PHY_BIST_PATN2);
+		REG_W(0x02, hdmi_phy_base + HDMI_PHY_BIST_PATN3);
+
+		udelay(200);
+
+		REG_W(0x00, hdmi_phy_base + HDMI_PHY_BIST_CFG1);
+		REG_W(0x00, hdmi_phy_base + HDMI_PHY_BIST_CFG0);
 	}
 
 	/* Make sure writes complete before disabling iface clock */
 	mb();
 
-	clk_disable(mdss_ahb_clk);
+	mdss_ahb_clk_enable(0);
 
 	if (set_power_dwn)
-		hdmi_pll_enable();
+		hdmi_vco_enable(c);
+
+	vco->rate = rate;
+	vco->rate_set = true;
 
 	return 0;
 } /* hdmi_pll_set_rate */
 
-/* Auto PLL calibaration */
-int mdss_ahb_clk_enable(int enable)
-{
-	int rc = 0;
-
-	/* todo: Ideally, we should enable/disable GDSC whenever we are
-	 * attempting to enable/disable MDSS AHB clock.
-	 * For now, just return error if  GDSC is not enabled.
-	 */
-	if (!mdss_gdsc_enabled())
-		return -EPERM;
-
-	if (enable)
-		rc = clk_prepare_enable(mdss_ahb_clk);
-	else
-		clk_disable_unprepare(mdss_ahb_clk);
-
-	return rc;
-}
-
 int set_byte_mux_sel(struct mux_clk *clk, int sel)
 {
 	pr_debug("%s: byte mux set to %s mode\n", __func__,
@@ -862,12 +1035,12 @@
 static void dsi_pll_toggle_lock_detect(void)
 {
 	DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_LKDET_CFG2,
-		0x05);
+		0x0d);
 	DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_LKDET_CFG2,
-		0x04);
+		0x0c);
 	udelay(1);
 	DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_LKDET_CFG2,
-		0x05);
+		0x0d);
 }
 
 static int dsi_pll_lock_status(void)
@@ -904,9 +1077,9 @@
 	 * reset bit off and back on.
 	 */
 	DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_TEST_CFG, 0x01);
-	udelay(1000);
+	udelay(1);
 	DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_TEST_CFG, 0x00);
-	udelay(1000);
+	udelay(1);
 }
 
 static int dsi_pll_enable_seq_m(void)
@@ -921,24 +1094,25 @@
 	 * the updates to take effect. These delays are necessary for the
 	 * PLL to successfully lock
 	 */
+	DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_CAL_CFG1, 0x34);
 	DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x01);
 	udelay(200);
 	DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x05);
 	udelay(200);
 	DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x0f);
-	udelay(1000);
+	udelay(600);
 
 	pll_locked = dsi_pll_toggle_lock_detect_and_check_status();
-	for (i = 0; (i < 4) && !pll_locked; i++) {
+	for (i = 0; (i < SEQ_M_MAX_COUNTER) && !pll_locked; i++) {
+		DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_PWRGEN_CFG,
+			0x00);
+		udelay(50);
 		DSS_REG_W(mdss_dsi_base,
-			DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x07);
-		if (i != 0)
-			DSS_REG_W(mdss_dsi_base,
-				DSI_0_PHY_PLL_UNIPHY_PLL_CAL_CFG1, 0x34);
-		udelay(1);
+			DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x05);
+		udelay(100);
 		DSS_REG_W(mdss_dsi_base,
 			DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x0f);
-		udelay(1000);
+		udelay(600);
 		pll_locked = dsi_pll_toggle_lock_detect_and_check_status();
 	}
 
@@ -962,6 +1136,8 @@
 	 * the updates to take effect. These delays are necessary for the
 	 * PLL to successfully lock
 	 */
+	DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_PWRGEN_CFG, 0x00);
+	udelay(50);
 	DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x01);
 	udelay(200);
 	DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x05);
@@ -973,7 +1149,7 @@
 	DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x07);
 	udelay(200);
 	DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x0f);
-	udelay(1000);
+	udelay(600);
 
 	pll_locked = dsi_pll_toggle_lock_detect_and_check_status();
 	pr_debug("%s: PLL status = %s\n", __func__,
@@ -993,6 +1169,8 @@
 	 * the updates to take effect. These delays are necessary for the
 	 * PLL to successfully lock
 	 */
+	DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_PWRGEN_CFG, 0x00);
+	udelay(50);
 	DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x01);
 	udelay(200);
 	DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x05);
@@ -1002,7 +1180,7 @@
 	DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x0d);
 	udelay(200);
 	DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x0f);
-	udelay(1000);
+	udelay(600);
 
 	pll_locked = dsi_pll_toggle_lock_detect_and_check_status();
 	pr_debug("%s: PLL status = %s\n", __func__,
@@ -1022,12 +1200,14 @@
 	 * the updates to take effect. These delays are necessary for the
 	 * PLL to successfully lock
 	 */
+	DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_PWRGEN_CFG, 0x00);
+	udelay(50);
 	DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x01);
 	udelay(200);
 	DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x05);
 	udelay(200);
 	DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x0f);
-	udelay(1000);
+	udelay(600);
 
 	pll_locked = dsi_pll_toggle_lock_detect_and_check_status();
 	pr_debug("%s: PLL status = %s\n", __func__,
@@ -1047,6 +1227,8 @@
 	 * the updates to take effect. These delays are necessary for the
 	 * PLL to successfully lock
 	 */
+	DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_PWRGEN_CFG, 0x00);
+	udelay(50);
 	DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x01);
 	udelay(200);
 	DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x05);
@@ -1054,7 +1236,7 @@
 	DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x0d);
 	udelay(1);
 	DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x0f);
-	udelay(1000);
+	udelay(600);
 
 	pll_locked = dsi_pll_toggle_lock_detect_and_check_status();
 	pr_debug("%s: PLL status = %s\n", __func__,
@@ -1075,22 +1257,22 @@
 	 * Add necessary delays recommeded by hardware.
 	 */
 	DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x01);
-	udelay(1000);
+	udelay(1);
 	DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x05);
-	udelay(1000);
+	udelay(200);
 	DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x07);
-	udelay(1000);
+	udelay(500);
 	DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x0f);
-	udelay(1000);
+	udelay(500);
 
-	for (i = 0; i < 3; i++) {
+	for (i = 0; i < 2; i++) {
+		udelay(100);
 		/* DSI Uniphy lock detect setting */
 		DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_LKDET_CFG2,
-			0x04);
+			0x0c);
 		udelay(100);
 		DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_LKDET_CFG2,
-			0x05);
-		udelay(500);
+			0x0d);
 		/* poll for PLL ready status */
 		max_reads = 5;
 		timeout_us = 100;
@@ -1113,17 +1295,17 @@
 		 * Add necessary delays recommeded by hardware.
 		 */
 		DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x1);
-		udelay(1000);
+		udelay(1);
 		DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x5);
-		udelay(1000);
+		udelay(200);
 		DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x7);
-		udelay(1000);
+		udelay(250);
 		DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x5);
-		udelay(1000);
+		udelay(200);
 		DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x7);
-		udelay(1000);
+		udelay(500);
 		DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0xf);
-		udelay(2000);
+		udelay(500);
 
 	}
 
@@ -1287,7 +1469,7 @@
 	DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_CHGPUMP_CFG, 0x02);
 	DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_CAL_CFG3, 0x2b);
 	DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_CAL_CFG4, 0x66);
-	DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_LKDET_CFG2, 0x05);
+	DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_LKDET_CFG2, 0x0d);
 
 	DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_SDM_CFG1,
 		(u32)(sdm_cfg1 & 0xff));
@@ -1298,7 +1480,7 @@
 	DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_SDM_CFG4, 0x00);
 
 	/* Add hardware recommended delay for correct PLL configuration */
-	udelay(1000);
+	udelay(1);
 
 	DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_REFCLK_CFG,
 		(u32)refclk_cfg);
@@ -1306,7 +1488,7 @@
 	DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_VCOLPF_CFG, 0x71);
 	DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_SDM_CFG0,
 		(u32)sdm_cfg0);
-	DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_CAL_CFG0, 0x0a);
+	DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_CAL_CFG0, 0x12);
 	DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_CAL_CFG6, 0x30);
 	DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_CAL_CFG7, 0x00);
 	DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_CAL_CFG8, 0x60);
@@ -1468,13 +1650,14 @@
 	.ref_clk_rate = 19200000,
 	.min_rate = 350000000,
 	.max_rate = 750000000,
-	.pll_en_seq_cnt = 6,
+	.pll_en_seq_cnt = 7,
 	.pll_enable_seqs[0] = dsi_pll_enable_seq_m,
-	.pll_enable_seqs[1] = dsi_pll_enable_seq_d,
+	.pll_enable_seqs[1] = dsi_pll_enable_seq_m,
 	.pll_enable_seqs[2] = dsi_pll_enable_seq_d,
-	.pll_enable_seqs[3] = dsi_pll_enable_seq_f1,
-	.pll_enable_seqs[4] = dsi_pll_enable_seq_c,
-	.pll_enable_seqs[5] = dsi_pll_enable_seq_e,
+	.pll_enable_seqs[3] = dsi_pll_enable_seq_d,
+	.pll_enable_seqs[4] = dsi_pll_enable_seq_f1,
+	.pll_enable_seqs[5] = dsi_pll_enable_seq_c,
+	.pll_enable_seqs[6] = dsi_pll_enable_seq_e,
 	.lpfr_lut_size = 10,
 	.lpfr_lut = (struct lpfr_cfg[]){
 		{479500000, 8},
@@ -1694,7 +1877,7 @@
 	if (vco_rate == 810000000) {
 		DSS_REG_W(mdss_edp_base, 0x0c, 0x18);
 		/* UNIPHY_PLL_LKDET_CFG2 */
-		DSS_REG_W(mdss_edp_base, 0x64, 0x05);
+		DSS_REG_W(mdss_edp_base, 0x64, 0x0d);
 		/* UNIPHY_PLL_REFCLK_CFG */
 		DSS_REG_W(mdss_edp_base, 0x00, 0x00);
 		/* UNIPHY_PLL_SDM_CFG0 */
@@ -1716,7 +1899,7 @@
 		/* UNIPHY_PLL_SSC_CFG3 */
 		DSS_REG_W(mdss_edp_base, 0x58, 0x00);
 		/* UNIPHY_PLL_CAL_CFG0 */
-		DSS_REG_W(mdss_edp_base, 0x6c, 0x0a);
+		DSS_REG_W(mdss_edp_base, 0x6c, 0x12);
 		/* UNIPHY_PLL_CAL_CFG2 */
 		DSS_REG_W(mdss_edp_base, 0x74, 0x01);
 		/* UNIPHY_PLL_CAL_CFG6 */
@@ -1741,7 +1924,7 @@
 		DSS_REG_W(mdss_edp_base, 0x28, 0x00);
 	} else if (vco_rate == 1350000000) {
 		/* UNIPHY_PLL_LKDET_CFG2 */
-		DSS_REG_W(mdss_edp_base, 0x64, 0x05);
+		DSS_REG_W(mdss_edp_base, 0x64, 0x0d);
 		/* UNIPHY_PLL_REFCLK_CFG */
 		DSS_REG_W(mdss_edp_base, 0x00, 0x01);
 		/* UNIPHY_PLL_SDM_CFG0 */
@@ -1763,7 +1946,7 @@
 		/* UNIPHY_PLL_SSC_CFG3 */
 		DSS_REG_W(mdss_edp_base, 0x58, 0x00);
 		/* UNIPHY_PLL_CAL_CFG0 */
-		DSS_REG_W(mdss_edp_base, 0x6c, 0x0a);
+		DSS_REG_W(mdss_edp_base, 0x6c, 0x12);
 		/* UNIPHY_PLL_CAL_CFG2 */
 		DSS_REG_W(mdss_edp_base, 0x74, 0x01);
 		/* UNIPHY_PLL_CAL_CFG6 */
@@ -1827,7 +2010,6 @@
 	if (status)
 		return 1;
 
-	pr_err("%s: PLL NOT ready\n", __func__);
 	return 0;
 }
 
@@ -2126,6 +2308,291 @@
 	},
 };
 
+/* HDMI PLL DIV CLK */
+
+static unsigned long hdmi_vco_get_rate(struct clk *c)
+{
+	unsigned long freq = 0;
+
+	if (mdss_ahb_clk_enable(1)) {
+		pr_err("%s: Failed to enable mdss ahb clock\n", __func__);
+		return freq;
+	}
+
+	freq = DSS_REG_R(hdmi_phy_pll_base, HDMI_UNI_PLL_CAL_CFG11) << 8 |
+		DSS_REG_R(hdmi_phy_pll_base, HDMI_UNI_PLL_CAL_CFG10);
+
+	switch (freq) {
+	case 742:
+		freq = 742500000;
+		break;
+	case 810:
+		if (DSS_REG_R(hdmi_phy_pll_base, HDMI_UNI_PLL_SDM_CFG3) == 0x18)
+			freq = 810000000;
+		else
+			freq = 810900000;
+		break;
+	case 1342:
+		freq = 1342500000;
+		break;
+	default:
+		freq *= 1000000;
+	}
+
+	mdss_ahb_clk_enable(0);
+
+	return freq;
+}
+
+static long hdmi_vco_round_rate(struct clk *c, unsigned long rate)
+{
+	unsigned long rrate = rate;
+	struct hdmi_pll_vco_clk *vco = to_hdmi_vco_clk(c);
+
+	if (rate < vco->min_rate)
+		rrate = vco->min_rate;
+	if (rate > vco->max_rate)
+		rrate = vco->max_rate;
+
+	pr_debug("%s: rrate=%ld\n", __func__, rrate);
+
+	return rrate;
+}
+
+static int hdmi_vco_prepare(struct clk *c)
+{
+	struct hdmi_pll_vco_clk *vco = to_hdmi_vco_clk(c);
+	int ret = 0;
+
+	pr_debug("%s: rate=%ld\n", __func__, vco->rate);
+
+	if (!vco->rate_set && vco->rate)
+		ret = hdmi_vco_set_rate(c, vco->rate);
+
+	if (!ret)
+		ret = clk_prepare(mdss_ahb_clk);
+
+	return ret;
+}
+
+static void hdmi_vco_unprepare(struct clk *c)
+{
+	struct hdmi_pll_vco_clk *vco = to_hdmi_vco_clk(c);
+
+	vco->rate_set = false;
+
+	clk_unprepare(mdss_ahb_clk);
+}
+
+static int hdmi_pll_lock_status(void)
+{
+	u32 status;
+	int pll_locked = 0;
+	int rc;
+
+	rc = mdss_ahb_clk_enable(1);
+	if (rc) {
+		pr_err("%s: failed to enable mdss ahb clock. rc=%d\n",
+			__func__, rc);
+		return 0;
+	}
+	/* poll for PLL ready status */
+	if (readl_poll_timeout_noirq((hdmi_phy_base + HDMI_PHY_STATUS),
+			status, ((status & BIT(0)) == 1),
+			PLL_POLL_MAX_READS, PLL_POLL_TIMEOUT_US)) {
+		pr_debug("%s: HDMI PLL status=%x failed to Lock\n",
+				__func__, status);
+		pll_locked = 0;
+	} else {
+		pll_locked = 1;
+	}
+	mdss_ahb_clk_enable(0);
+
+	return pll_locked;
+}
+
+static enum handoff hdmi_vco_handoff(struct clk *c)
+{
+	enum handoff ret = HANDOFF_DISABLED_CLK;
+
+	if (hdmi_pll_lock_status()) {
+		c->rate = hdmi_vco_get_rate(c);
+		ret = HANDOFF_ENABLED_CLK;
+	}
+
+	pr_debug("%s: done, ret=%d\n", __func__, ret);
+	return ret;
+}
+
+static struct clk_ops hdmi_vco_clk_ops = {
+	.enable = hdmi_vco_enable,
+	.set_rate = hdmi_vco_set_rate,
+	.get_rate = hdmi_vco_get_rate,
+	.round_rate = hdmi_vco_round_rate,
+	.prepare = hdmi_vco_prepare,
+	.unprepare = hdmi_vco_unprepare,
+	.disable = hdmi_vco_disable,
+	.handoff = hdmi_vco_handoff,
+};
+
+static struct hdmi_pll_vco_clk hdmi_vco_clk = {
+	.min_rate = 600000000,
+	.max_rate = 1800000000,
+	.c = {
+		.dbg_name = "hdmi_vco_clk",
+		.ops = &hdmi_vco_clk_ops,
+		CLK_INIT(hdmi_vco_clk.c),
+	},
+};
+
+struct div_clk hdmipll_div1_clk = {
+	.data = {
+		.div = 1,
+		.min_div = 1,
+		.max_div = 1,
+	},
+	.c = {
+		.parent = &hdmi_vco_clk.c,
+		.dbg_name = "hdmipll_div1_clk",
+		.ops = &clk_ops_div,
+		.flags = CLKFLAG_NO_RATE_CACHE,
+		CLK_INIT(hdmipll_div1_clk.c),
+	},
+};
+
+struct div_clk hdmipll_div2_clk = {
+	.data = {
+		.div = 2,
+		.min_div = 2,
+		.max_div = 2,
+	},
+	.c = {
+		.parent = &hdmi_vco_clk.c,
+		.dbg_name = "hdmipll_div2_clk",
+		.ops = &clk_ops_div,
+		.flags = CLKFLAG_NO_RATE_CACHE,
+		CLK_INIT(hdmipll_div2_clk.c),
+	},
+};
+
+struct div_clk hdmipll_div4_clk = {
+	.data = {
+		.div = 4,
+		.min_div = 4,
+		.max_div = 4,
+	},
+	.c = {
+		.parent = &hdmi_vco_clk.c,
+		.dbg_name = "hdmipll_div4_clk",
+		.ops = &clk_ops_div,
+		.flags = CLKFLAG_NO_RATE_CACHE,
+		CLK_INIT(hdmipll_div4_clk.c),
+	},
+};
+
+struct div_clk hdmipll_div6_clk = {
+	.data = {
+		.div = 6,
+		.min_div = 6,
+		.max_div = 6,
+	},
+	.c = {
+		.parent = &hdmi_vco_clk.c,
+		.dbg_name = "hdmipll_div6_clk",
+		.ops = &clk_ops_div,
+		.flags = CLKFLAG_NO_RATE_CACHE,
+		CLK_INIT(hdmipll_div6_clk.c),
+	},
+};
+
+static int hdmipll_set_mux_sel(struct mux_clk *clk, int mux_sel)
+{
+	int rc;
+
+	if (!mdss_gdsc_enabled()) {
+		pr_err("%s: mdss GDSC is not enabled\n", __func__);
+		return -EPERM;
+	}
+
+	rc = clk_enable(mdss_ahb_clk);
+	if (rc) {
+		pr_err("%s: Failed to enable mdss ahb clock\n", __func__);
+		return rc;
+	}
+
+	pr_debug("%s: mux_sel=%d\n", __func__, mux_sel);
+	DSS_REG_W(hdmi_phy_pll_base, HDMI_UNI_PLL_POSTDIV1_CFG, mux_sel);
+
+	clk_disable(mdss_ahb_clk);
+
+	return 0;
+}
+
+static int hdmipll_get_mux_sel(struct mux_clk *clk)
+{
+	int mux_sel = 0;
+
+	if (mdss_ahb_clk_enable(1)) {
+		pr_err("%s: Failed to enable mdss ahb clock\n", __func__);
+		return mux_sel;
+	}
+
+	mux_sel = DSS_REG_R(hdmi_phy_pll_base, HDMI_UNI_PLL_POSTDIV1_CFG);
+	mux_sel &= 0x03;
+	pr_debug("%s: mux_sel=%d\n", __func__, mux_sel);
+
+	mdss_ahb_clk_enable(0);
+
+	return mux_sel;
+}
+
+static struct clk_mux_ops hdmipll_mux_ops = {
+	.set_mux_sel = hdmipll_set_mux_sel,
+	.get_mux_sel = hdmipll_get_mux_sel,
+};
+
+static struct clk_ops hdmi_mux_ops;
+
+static int hdmi_mux_prepare(struct clk *c)
+{
+	int ret = 0;
+
+	if (c && c->ops && c->ops->set_rate)
+		ret = c->ops->set_rate(c, c->rate);
+
+	return ret;
+}
+
+static struct mux_clk hdmipll_mux_clk = {
+	MUX_SRC_LIST(
+		{ &hdmipll_div1_clk.c, 0 },
+		{ &hdmipll_div2_clk.c, 1 },
+		{ &hdmipll_div4_clk.c, 2 },
+		{ &hdmipll_div6_clk.c, 3 },
+	),
+	.ops = &hdmipll_mux_ops,
+	.c = {
+		.parent = &hdmipll_div1_clk.c,
+		.dbg_name = "hdmipll_mux_clk",
+		.ops = &hdmi_mux_ops,
+		CLK_INIT(hdmipll_mux_clk.c),
+	},
+};
+
+struct div_clk hdmipll_clk_src = {
+	.data = {
+		.div = 5,
+		.min_div = 5,
+		.max_div = 5,
+	},
+	.c = {
+		.parent = &hdmipll_mux_clk.c,
+		.dbg_name = "hdmipll_clk_src",
+		.ops = &clk_ops_div,
+		CLK_INIT(hdmipll_clk_src.c),
+	},
+};
+
 void __init mdss_clk_ctrl_pre_init(struct clk *ahb_clk)
 {
 	BUG_ON(ahb_clk == NULL);
@@ -2170,4 +2637,7 @@
 
 	edp_pixel_clk_ops = clk_ops_slave_div;
 	edp_pixel_clk_ops.prepare = div_prepare;
+
+	hdmi_mux_ops = clk_ops_gen_mux;
+	hdmi_mux_ops.prepare = hdmi_mux_prepare;
 }
diff --git a/arch/arm/mach-msm/clock-mdss-8974.h b/arch/arm/mach-msm/clock-mdss-8974.h
index da24b0d..f9286f1 100644
--- a/arch/arm/mach-msm/clock-mdss-8974.h
+++ b/arch/arm/mach-msm/clock-mdss-8974.h
@@ -22,9 +22,15 @@
 
 void mdss_clk_ctrl_pre_init(struct clk *ahb_clk);
 void mdss_clk_ctrl_post_init(void);
-int hdmi_pll_enable(void);
-void hdmi_pll_disable(void);
-int hdmi_pll_set_rate(unsigned long rate);
+
+struct hdmi_pll_vco_clk {
+	unsigned long rate;	/* current vco rate */
+	unsigned long min_rate;	/* min vco rate */
+	unsigned long max_rate;	/* max vco rate */
+	bool rate_set;
+
+	struct clk c;
+};
 
 struct edp_pll_vco_clk {
 	unsigned long ref_clk_rate;
@@ -67,5 +73,6 @@
 
 extern struct div_clk edp_mainlink_clk_src;
 extern struct div_clk edp_pixel_clk_src;
+extern struct div_clk hdmipll_clk_src;
 
 #endif
diff --git a/arch/arm/mach-msm/clock-samarium.c b/arch/arm/mach-msm/clock-samarium.c
new file mode 100644
index 0000000..4c5c0c7
--- /dev/null
+++ b/arch/arm/mach-msm/clock-samarium.c
@@ -0,0 +1,3919 @@
+/* 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/kernel.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/ctype.h>
+#include <linux/io.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/iopoll.h>
+#include <linux/regulator/consumer.h>
+
+#include <mach/rpm-regulator-smd.h>
+#include <mach/rpm-smd.h>
+#include <mach/clock-generic.h>
+
+#include "clock-local2.h"
+#include "clock-pll.h"
+#include "clock-rpm.h"
+#include "clock-voter.h"
+#include "clock.h"
+#include "clock-krait.h"
+#include "clock-mdss-8974.h"
+
+enum {
+	GCC_BASE,
+	MMSS_BASE,
+	LPASS_BASE,
+	APCS_BASE,
+	N_BASES,
+};
+
+static void __iomem *virt_bases[N_BASES];
+
+#define GCC_REG_BASE(x) (void __iomem *)(virt_bases[GCC_BASE] + (x))
+#define MMSS_REG_BASE(x) (void __iomem *)(virt_bases[MMSS_BASE] + (x))
+#define LPASS_REG_BASE(x) (void __iomem *)(virt_bases[LPASS_BASE] + (x))
+#define APCS_REG_BASE(x) (void __iomem *)(virt_bases[APCS_BASE] + (x))
+
+#define xo_source_val 0
+#define gpll0_source_val 1
+#define gpll4_source_val 5
+#define xo_mm_source_val 0
+#define mmpll0_mm_source_val 1
+#define mmpll1_mm_source_val 2
+#define mmpll3_mm_source_val 3
+#define mmpll4_mm_source_val 3
+#define gpll0_mm_source_val 5
+#define dsipll0_pixel_mm_source_val 1
+#define dsipll0_byte_mm_source_val 1
+
+#define FIXDIV(div) (div ? (2 * (div) - 1) : (0))
+
+#define F(f, s, div, m, n) \
+	{ \
+		.freq_hz = (f), \
+		.src_clk = &s.c, \
+		.m_val = (m), \
+		.n_val = ~((n)-(m)) * !!(n), \
+		.d_val = ~(n),\
+		.div_src_val = BVAL(4, 0, (int)(2*(div) - 1)) \
+			| BVAL(10, 8, s##_source_val), \
+	}
+
+#define F_MM(f, s, div, m, n) \
+	{ \
+		.freq_hz = (f), \
+		.src_clk = &s.c, \
+		.m_val = (m), \
+		.n_val = ~((n)-(m)) * !!(n), \
+		.d_val = ~(n),\
+		.div_src_val = BVAL(4, 0, (int)(2*(div) - 1)) \
+			| BVAL(10, 8, s##_mm_source_val), \
+	}
+
+#define VDD_DIG_FMAX_MAP1(l1, f1) \
+	.vdd_class = &vdd_dig,			\
+	.fmax = (unsigned long[VDD_DIG_NUM]) {	\
+		[VDD_DIG_##l1] = (f1),		\
+	},					\
+	.num_fmax = VDD_DIG_NUM
+#define VDD_DIG_FMAX_MAP2(l1, f1, l2, f2) \
+	.vdd_class = &vdd_dig,			\
+	.fmax = (unsigned long[VDD_DIG_NUM]) {	\
+		[VDD_DIG_##l1] = (f1),		\
+		[VDD_DIG_##l2] = (f2),		\
+	},					\
+	.num_fmax = VDD_DIG_NUM
+#define VDD_DIG_FMAX_MAP3(l1, f1, l2, f2, l3, f3) \
+	.vdd_class = &vdd_dig,			\
+	.fmax = (unsigned long[VDD_DIG_NUM]) {	\
+		[VDD_DIG_##l1] = (f1),		\
+		[VDD_DIG_##l2] = (f2),		\
+		[VDD_DIG_##l3] = (f3),		\
+	},					\
+	.num_fmax = VDD_DIG_NUM
+
+enum vdd_dig_levels {
+	VDD_DIG_NONE,
+	VDD_DIG_LOW,
+	VDD_DIG_NOMINAL,
+	VDD_DIG_HIGH,
+	VDD_DIG_NUM
+};
+
+static int vdd_corner[] = {
+	RPM_REGULATOR_CORNER_NONE,		/* VDD_DIG_NONE */
+	RPM_REGULATOR_CORNER_SVS_SOC,		/* VDD_DIG_LOW */
+	RPM_REGULATOR_CORNER_NORMAL,		/* VDD_DIG_NOMINAL */
+	RPM_REGULATOR_CORNER_SUPER_TURBO,	/* VDD_DIG_HIGH */
+};
+
+static DEFINE_VDD_REGULATORS(vdd_dig, VDD_DIG_NUM, 1, vdd_corner, NULL);
+
+#define RPM_MISC_CLK_TYPE	0x306b6c63
+#define RPM_BUS_CLK_TYPE	0x316b6c63
+#define RPM_MEM_CLK_TYPE	0x326b6c63
+
+#define CXO_ID		0x0
+#define QDSS_ID		0x1
+#define PNOC_ID		0x0
+#define SNOC_ID		0x1
+#define CNOC_ID		0x2
+#define BIMC_ID		0x0
+#define OCMEM_ID	0x2
+#define OXILI_ID	0x1
+#define MMSSNOC_AHB_ID  0x3
+
+#define BB_CLK1_ID	 1
+#define BB_CLK2_ID	 2
+#define RF_CLK1_ID	 4
+#define RF_CLK2_ID	 5
+#define RF_CLK3_ID	 6
+#define DIFF_CLK1_ID	 7
+#define DIV_CLK1_ID	11
+#define DIV_CLK2_ID	12
+#define DIV_CLK3_ID	13
+
+#define GPLL0_STATUS                                       (0x001C)
+#define GPLL4_STATUS                                       (0x1DDC)
+#define MSS_CFG_AHB_CBCR                                   (0x0280)
+#define MSS_Q6_BIMC_AXI_CBCR                               (0x0284)
+#define USB_HS_BCR                                         (0x0480)
+#define USB_HS_SYSTEM_CBCR                                 (0x0484)
+#define USB_HS_AHB_CBCR                                    (0x0488)
+#define USB_HS_SYSTEM_CMD_RCGR                             (0x0490)
+#define USB2A_PHY_SLEEP_CBCR                               (0x04AC)
+#define SDCC1_APPS_CMD_RCGR                                (0x04D0)
+#define SDCC1_APPS_CBCR                                    (0x04C4)
+#define SDCC1_AHB_CBCR                                     (0x04C8)
+#define SDCC1_CDCCAL_SLEEP_CBCR                            (0x04E4)
+#define SDCC1_CDCCAL_FF_CBCR                               (0x04E8)
+#define SDCC2_APPS_CMD_RCGR                                (0x0510)
+#define SDCC2_APPS_CBCR                                    (0x0504)
+#define SDCC2_AHB_CBCR                                     (0x0508)
+#define SDCC3_APPS_CMD_RCGR                                (0x0550)
+#define SDCC3_APPS_CBCR                                    (0x0544)
+#define SDCC3_AHB_CBCR                                     (0x0548)
+#define SDCC4_APPS_CMD_RCGR                                (0x0590)
+#define SDCC4_APPS_CBCR                                    (0x0584)
+#define SDCC4_AHB_CBCR                                     (0x0588)
+#define BLSP1_AHB_CBCR                                     (0x05C4)
+#define BLSP1_QUP1_SPI_APPS_CBCR                           (0x0644)
+#define BLSP1_QUP1_I2C_APPS_CBCR                           (0x0648)
+#define BLSP1_QUP1_I2C_APPS_CMD_RCGR                       (0x0660)
+#define BLSP1_QUP2_I2C_APPS_CMD_RCGR                       (0x06E0)
+#define BLSP1_QUP3_I2C_APPS_CMD_RCGR                       (0x0760)
+#define BLSP1_QUP4_I2C_APPS_CMD_RCGR                       (0x07E0)
+#define BLSP2_QUP1_I2C_APPS_CMD_RCGR                       (0x09A0)
+#define BLSP2_QUP2_I2C_APPS_CMD_RCGR                       (0x0A20)
+#define BLSP2_QUP3_I2C_APPS_CMD_RCGR                       (0x0AA0)
+#define BLSP2_QUP4_I2C_APPS_CMD_RCGR                       (0x0B20)
+#define BLSP1_QUP1_SPI_APPS_CMD_RCGR                       (0x064C)
+#define BLSP1_UART1_APPS_CBCR                              (0x0684)
+#define BLSP1_UART1_APPS_CMD_RCGR                          (0x068C)
+#define BLSP1_QUP2_SPI_APPS_CBCR                           (0x06C4)
+#define BLSP1_QUP2_I2C_APPS_CBCR                           (0x06C8)
+#define BLSP1_QUP2_SPI_APPS_CMD_RCGR                       (0x06CC)
+#define BLSP1_UART2_APPS_CBCR                              (0x0704)
+#define BLSP1_UART2_APPS_CMD_RCGR                          (0x070C)
+#define BLSP1_QUP3_SPI_APPS_CBCR                           (0x0744)
+#define BLSP1_QUP3_I2C_APPS_CBCR                           (0x0748)
+#define BLSP1_QUP3_SPI_APPS_CMD_RCGR                       (0x074C)
+#define BLSP1_UART3_APPS_CBCR                              (0x0784)
+#define BLSP1_UART3_APPS_CMD_RCGR                          (0x078C)
+#define BLSP1_QUP4_SPI_APPS_CBCR                           (0x07C4)
+#define BLSP1_QUP4_I2C_APPS_CBCR                           (0x07C8)
+#define BLSP1_QUP4_SPI_APPS_CMD_RCGR                       (0x07CC)
+#define BLSP1_UART4_APPS_CBCR                              (0x0804)
+#define BLSP1_UART4_APPS_CMD_RCGR                          (0x080C)
+#define BLSP2_AHB_CBCR                                     (0x0944)
+#define BLSP2_QUP1_SPI_APPS_CBCR                           (0x0984)
+#define BLSP2_QUP1_I2C_APPS_CBCR                           (0x0988)
+#define BLSP2_QUP1_SPI_APPS_CMD_RCGR                       (0x098C)
+#define BLSP2_UART1_APPS_CBCR                              (0x09C4)
+#define BLSP2_UART1_APPS_CMD_RCGR                          (0x09CC)
+#define BLSP2_QUP2_SPI_APPS_CBCR                           (0x0A04)
+#define BLSP2_QUP2_I2C_APPS_CBCR                           (0x0A08)
+#define BLSP2_QUP2_SPI_APPS_CMD_RCGR                       (0x0A0C)
+#define BLSP2_UART2_APPS_CBCR                              (0x0A44)
+#define BLSP2_UART2_APPS_CMD_RCGR                          (0x0A4C)
+#define BLSP2_QUP3_SPI_APPS_CBCR                           (0x0A84)
+#define BLSP2_QUP3_I2C_APPS_CBCR                           (0x0A88)
+#define BLSP2_QUP3_SPI_APPS_CMD_RCGR                       (0x0A8C)
+#define BLSP2_UART3_APPS_CBCR                              (0x0AC4)
+#define BLSP2_UART3_APPS_CMD_RCGR                          (0x0ACC)
+#define BLSP2_QUP4_SPI_APPS_CBCR                           (0x0B04)
+#define BLSP2_QUP4_I2C_APPS_CBCR                           (0x0B08)
+#define BLSP2_QUP4_SPI_APPS_CMD_RCGR                       (0x0B0C)
+#define BLSP2_UART4_APPS_CBCR                              (0x0B44)
+#define BLSP2_UART4_APPS_CMD_RCGR                          (0x0B4C)
+#define PDM_AHB_CBCR                                       (0x0CC4)
+#define PDM2_CBCR                                          (0x0CCC)
+#define PDM2_CMD_RCGR                                      (0x0CD0)
+#define PRNG_AHB_CBCR                                      (0x0D04)
+#define BAM_DMA_AHB_CBCR                                   (0x0D44)
+#define TSIF_AHB_CBCR                                      (0x0D84)
+#define TSIF_REF_CBCR                                      (0x0D88)
+#define TSIF_REF_CMD_RCGR                                  (0x0D90)
+#define BOOT_ROM_AHB_CBCR                                  (0x0E04)
+#define RPM_MISC                                           (0x0F24)
+#define CE1_CMD_RCGR                                       (0x1050)
+#define CE1_CBCR                                           (0x1044)
+#define CE1_AXI_CBCR                                       (0x1048)
+#define CE1_AHB_CBCR                                       (0x104C)
+#define GCC_XO_DIV4_CBCR                                   (0x10C8)
+#define LPASS_Q6_AXI_CBCR                                  (0x11C0)
+#define LPASS_SYS_NOC_MPORT_CBCR                           (0x11C4)
+#define LPASS_SYS_NOC_SWAY_CBCR                            (0x11C8)
+#define APCS_GPLL_ENA_VOTE                                 (0x1480)
+#define APCS_CLOCK_BRANCH_ENA_VOTE                         (0x1484)
+#define GCC_DEBUG_CLK_CTL                                  (0x1880)
+#define CLOCK_FRQ_MEASURE_CTL                              (0x1884)
+#define CLOCK_FRQ_MEASURE_STATUS                           (0x1888)
+#define PLLTEST_PAD_CFG                                    (0x188C)
+#define GP1_CBCR                                           (0x1900)
+#define GP1_CMD_RCGR                                       (0x1904)
+#define GLB_CLK_DIAG                                       (0x001C)
+#define SLEEP_CBCR                                         (0x0038)
+#define L2_CBCR                                            (0x004C)
+#define MMPLL0_MODE                                        (0x0000)
+#define MMPLL0_L_VAL                                       (0x0004)
+#define MMPLL0_M_VAL                                       (0x0008)
+#define MMPLL0_N_VAL                                       (0x000C)
+#define MMPLL0_USER_CTL                                    (0x0010)
+#define MMPLL0_STATUS                                      (0x001C)
+#define MMPLL1_MODE                                        (0x0040)
+#define MMPLL1_L_VAL                                       (0x0044)
+#define MMPLL1_M_VAL                                       (0x0048)
+#define MMPLL1_N_VAL                                       (0x004C)
+#define MMPLL1_USER_CTL                                    (0x0050)
+#define MMPLL1_STATUS                                      (0x005C)
+#define MMPLL3_MODE                                        (0x0080)
+#define MMPLL3_L_VAL                                       (0x0084)
+#define MMPLL3_M_VAL                                       (0x0088)
+#define MMPLL3_N_VAL                                       (0x008C)
+#define MMPLL3_USER_CTL                                    (0x0090)
+#define MMPLL3_STATUS                                      (0x009C)
+#define MMPLL4_MODE                                        (0x00A0)
+#define MMPLL4_L_VAL                                       (0x00A4)
+#define MMPLL4_M_VAL                                       (0x00A8)
+#define MMPLL4_N_VAL                                       (0x00AC)
+#define MMPLL4_USER_CTL                                    (0x00B0)
+#define MMPLL4_STATUS                                      (0x00BC)
+#define MMSS_PLL_VOTE_APCS                                 (0x0100)
+#define VCODEC0_CMD_RCGR                                   (0x1000)
+#define VENUS0_VCODEC0_CBCR                                (0x1028)
+#define VENUS0_AHB_CBCR                                    (0x1030)
+#define VENUS0_AXI_CBCR                                    (0x1034)
+#define VENUS0_OCMEMNOC_CBCR                               (0x1038)
+#define PCLK0_CMD_RCGR                                     (0x2000)
+#define MDP_CMD_RCGR                                       (0x2040)
+#define VSYNC_CMD_RCGR                                     (0x2080)
+#define BYTE0_CMD_RCGR                                     (0x2120)
+#define ESC0_CMD_RCGR                                      (0x2160)
+#define MDSS_AHB_CBCR                                      (0x2308)
+#define MDSS_AXI_CBCR                                      (0x2310)
+#define MDSS_PCLK0_CBCR                                    (0x2314)
+#define MDSS_MDP_CBCR                                      (0x231C)
+#define MDSS_MDP_LUT_CBCR                                  (0x2320)
+#define MDSS_VSYNC_CBCR                                    (0x2328)
+#define MDSS_BYTE0_CBCR                                    (0x233C)
+#define MDSS_ESC0_CBCR                                     (0x2344)
+#define CSI0PHYTIMER_CMD_RCGR                              (0x3000)
+#define CAMSS_PHY0_CSI0PHYTIMER_CBCR                       (0x3024)
+#define CSI1PHYTIMER_CMD_RCGR                              (0x3030)
+#define CAMSS_PHY1_CSI1PHYTIMER_CBCR                       (0x3054)
+#define CSI0_CMD_RCGR                                      (0x3090)
+#define CAMSS_CSI0_CBCR                                    (0x30B4)
+#define CAMSS_CSI0_AHB_CBCR                                (0x30BC)
+#define CAMSS_CSI0PHY_CBCR                                 (0x30C4)
+#define CAMSS_CSI0RDI_CBCR                                 (0x30D4)
+#define CAMSS_CSI0PIX_CBCR                                 (0x30E4)
+#define CSI1_CMD_RCGR                                      (0x3100)
+#define CAMSS_CSI1_CBCR                                    (0x3124)
+#define CAMSS_CSI1_AHB_CBCR                                (0x3128)
+#define CAMSS_CSI1PHY_CBCR                                 (0x3134)
+#define CAMSS_CSI1RDI_CBCR                                 (0x3144)
+#define CAMSS_CSI1PIX_CBCR                                 (0x3154)
+#define CSI2_CMD_RCGR                                      (0x3160)
+#define CAMSS_CSI2_CBCR                                    (0x3184)
+#define CAMSS_CSI2_AHB_CBCR                                (0x3188)
+#define CAMSS_CSI2PHY_CBCR                                 (0x3194)
+#define CAMSS_CSI2RDI_CBCR                                 (0x31A4)
+#define CAMSS_CSI2PIX_CBCR                                 (0x31B4)
+#define CAMSS_ISPIF_AHB_CBCR                               (0x3224)
+#define CCI_CMD_RCGR                                       (0x3300)
+#define CAMSS_CCI_CCI_CBCR                                 (0x3344)
+#define CAMSS_CCI_CCI_AHB_CBCR                             (0x3348)
+#define MCLK0_CMD_RCGR                                     (0x3360)
+#define CAMSS_MCLK0_CBCR                                   (0x3384)
+#define MCLK1_CMD_RCGR                                     (0x3390)
+#define CAMSS_MCLK1_CBCR                                   (0x33B4)
+#define MCLK2_CMD_RCGR                                     (0x33C0)
+#define CAMSS_MCLK2_CBCR                                   (0x33E4)
+#define MMSS_GP0_CMD_RCGR                                  (0x3420)
+#define CAMSS_GP0_CBCR                                     (0x3444)
+#define MMSS_GP1_CMD_RCGR                                  (0x3450)
+#define CAMSS_GP1_CBCR                                     (0x3474)
+#define CAMSS_TOP_AHB_CBCR                                 (0x3484)
+#define CAMSS_AHB_CBCR                                     (0x348C)
+#define CAMSS_MICRO_BCR                                    (0x3490)
+#define CAMSS_MICRO_AHB_CBCR                               (0x3494)
+#define JPEG0_CMD_RCGR                                     (0x3500)
+#define CAMSS_JPEG_JPEG0_CBCR                              (0x35A8)
+#define CAMSS_JPEG_JPEG_AHB_CBCR                           (0x35B4)
+#define CAMSS_JPEG_JPEG_AXI_CBCR                           (0x35B8)
+#define VFE0_CMD_RCGR                                      (0x3600)
+#define VFE1_CMD_RCGR                                      (0x3620)
+#define CPP_CMD_RCGR                                       (0x3640)
+#define CAMSS_VFE_VFE0_CBCR                                (0x36A8)
+#define CAMSS_VFE_VFE1_CBCR                                (0x36AC)
+#define CAMSS_VFE_CPP_CBCR                                 (0x36B0)
+#define CAMSS_VFE_CPP_AHB_CBCR                             (0x36B4)
+#define CAMSS_VFE_VFE_AHB_CBCR                             (0x36B8)
+#define CAMSS_VFE_VFE_AXI_CBCR                             (0x36BC)
+#define CAMSS_CSI_VFE0_CBCR                                (0x3704)
+#define CAMSS_CSI_VFE1_CBCR                                (0x3714)
+#define OXILI_GFX3D_CBCR                                   (0x4028)
+#define OXILICX_AHB_CBCR                                   (0x403C)
+#define OCMEMCX_OCMEMNOC_CBCR                              (0x4058)
+#define MMSS_MISC_AHB_CBCR                                 (0x502C)
+#define AXI_CMD_RCGR                                       (0x5040)
+#define MMSS_S0_AXI_CBCR                                   (0x5064)
+#define MMSS_MMSSNOC_AXI_CBCR                              (0x506C)
+#define OCMEMNOC_CMD_RCGR                                  (0x5090)
+#define MMSS_DEBUG_CLK_CTL                                 (0x0900)
+#define LPASS_DBG_CLK                                      (0x32000)
+
+DEFINE_CLK_RPM_SMD_BRANCH(xo, xo_a_clk, RPM_MISC_CLK_TYPE, CXO_ID, 19200000);
+DEFINE_CLK_RPM_SMD(cnoc, cnoc_a_clk, RPM_BUS_CLK_TYPE, CNOC_ID, NULL);
+DEFINE_CLK_RPM_SMD(pnoc, pnoc_a_clk, RPM_BUS_CLK_TYPE, PNOC_ID, NULL);
+DEFINE_CLK_RPM_SMD(snoc, snoc_a_clk, RPM_BUS_CLK_TYPE, SNOC_ID, NULL);
+DEFINE_CLK_RPM_SMD(bimc, bimc_a_clk, RPM_MEM_CLK_TYPE, BIMC_ID, NULL);
+DEFINE_CLK_RPM_SMD_QDSS(qdss, qdss_a_clk, RPM_MISC_CLK_TYPE, QDSS_ID);
+DEFINE_CLK_RPM_SMD(gfx3d, gfx3d_a_clk, RPM_MEM_CLK_TYPE, OXILI_ID, NULL);
+DEFINE_CLK_RPM_SMD(mmssnoc_ahb, mmssnoc_ahb_a_clk, RPM_BUS_CLK_TYPE,
+	MMSSNOC_AHB_ID, NULL);
+DEFINE_CLK_RPM_SMD(ocmemgx, ocmemgx_a_clk, RPM_MEM_CLK_TYPE, OCMEM_ID, NULL);
+
+DEFINE_CLK_RPM_SMD_XO_BUFFER(bb_clk1, bb_clk1_a, BB_CLK1_ID);
+DEFINE_CLK_RPM_SMD_XO_BUFFER(bb_clk2, bb_clk2_a, BB_CLK2_ID);
+DEFINE_CLK_RPM_SMD_XO_BUFFER(rf_clk1, rf_clk1_a, RF_CLK1_ID);
+DEFINE_CLK_RPM_SMD_XO_BUFFER(rf_clk2, rf_clk2_a, RF_CLK2_ID);
+DEFINE_CLK_RPM_SMD_XO_BUFFER(rf_clk3, rf_clk3_a, RF_CLK3_ID);
+DEFINE_CLK_RPM_SMD_XO_BUFFER(diff_clk1, diff_clk1_a, DIFF_CLK1_ID);
+DEFINE_CLK_RPM_SMD_XO_BUFFER(div_clk1, div_clk1_a, DIV_CLK1_ID);
+DEFINE_CLK_RPM_SMD_XO_BUFFER(div_clk2, div_clk2_a, DIV_CLK2_ID);
+DEFINE_CLK_RPM_SMD_XO_BUFFER(div_clk3, div_clk3_a, DIV_CLK3_ID);
+
+DEFINE_CLK_RPM_SMD_XO_BUFFER_PINCTRL(bb_clk1_pin, bb_clk1_a_pin, BB_CLK1_ID);
+DEFINE_CLK_RPM_SMD_XO_BUFFER_PINCTRL(bb_clk2_pin, bb_clk2_a_pin, BB_CLK2_ID);
+DEFINE_CLK_RPM_SMD_XO_BUFFER_PINCTRL(rf_clk1_pin, rf_clk1_a_pin, RF_CLK1_ID);
+DEFINE_CLK_RPM_SMD_XO_BUFFER_PINCTRL(rf_clk2_pin, rf_clk2_a_pin, RF_CLK2_ID);
+DEFINE_CLK_RPM_SMD_XO_BUFFER_PINCTRL(rf_clk3_pin, rf_clk3_a_pin, RF_CLK3_ID);
+
+static DEFINE_CLK_VOTER(pnoc_msmbus_clk, &pnoc.c, LONG_MAX);
+static DEFINE_CLK_VOTER(snoc_msmbus_clk, &snoc.c, LONG_MAX);
+static DEFINE_CLK_VOTER(cnoc_msmbus_clk, &cnoc.c, LONG_MAX);
+static DEFINE_CLK_VOTER(pnoc_msmbus_a_clk, &pnoc_a_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(snoc_msmbus_a_clk, &snoc_a_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(cnoc_msmbus_a_clk, &cnoc_a_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(bimc_msmbus_clk, &bimc.c, LONG_MAX);
+static DEFINE_CLK_VOTER(bimc_msmbus_a_clk, &bimc_a_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(oxili_gfx3d_clk_src, &gfx3d.c, LONG_MAX);
+static DEFINE_CLK_VOTER(ocmemgx_msmbus_clk, &ocmemgx.c, LONG_MAX);
+static DEFINE_CLK_VOTER(ocmemgx_msmbus_a_clk, &ocmemgx_a_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(ocmemgx_core_clk, &ocmemgx.c, LONG_MAX);
+
+static DEFINE_CLK_VOTER(pnoc_keepalive_a_clk, &pnoc_a_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(pnoc_sps_clk, &pnoc.c, 0);
+
+static DEFINE_CLK_BRANCH_VOTER(xo_otg_clk, &xo.c);
+static DEFINE_CLK_BRANCH_VOTER(xo_pil_lpass_clk, &xo.c);
+static DEFINE_CLK_BRANCH_VOTER(xo_pil_mss_clk, &xo.c);
+static DEFINE_CLK_BRANCH_VOTER(xo_wlan_clk, &xo.c);
+static DEFINE_CLK_BRANCH_VOTER(xo_pil_pronto_clk, &xo.c);
+static DEFINE_CLK_BRANCH_VOTER(xo_ehci_host_clk, &xo.c);
+static DEFINE_CLK_BRANCH_VOTER(xo_lpm_clk, &xo.c);
+
+/*
+ * RPM manages gcc_bimc_gpu_clk automatically. This clock is created
+ * for measurement only.
+ */
+DEFINE_CLK_DUMMY(bimc_gpu, 0);
+
+static unsigned int soft_vote_gpll0;
+
+static struct pll_vote_clk gpll0 = {
+	.en_reg = (void __iomem *)APCS_GPLL_ENA_VOTE,
+	.en_mask = BIT(0),
+	.status_reg = (void __iomem *)GPLL0_STATUS,
+	.status_mask = BIT(17),
+	.soft_vote = &soft_vote_gpll0,
+	.soft_vote_mask = PLL_SOFT_VOTE_PRIMARY,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.rate = 600000000,
+		.parent = &xo.c,
+		.dbg_name = "gpll0",
+		.ops = &clk_ops_pll_acpu_vote,
+		CLK_INIT(gpll0.c),
+	},
+};
+
+static struct pll_vote_clk gpll0_ao = {
+	.en_reg = (void __iomem *)APCS_GPLL_ENA_VOTE,
+	.en_mask = BIT(0),
+	.status_reg = (void __iomem *)GPLL0_STATUS,
+	.status_mask = BIT(17),
+	.soft_vote = &soft_vote_gpll0,
+	.soft_vote_mask = PLL_SOFT_VOTE_ACPU,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.rate = 600000000,
+		.parent = &xo_a_clk.c,
+		.dbg_name = "gpll0_ao",
+		.ops = &clk_ops_pll_acpu_vote,
+		CLK_INIT(gpll0_ao.c),
+	},
+};
+
+static struct pll_vote_clk gpll4 = {
+	.en_reg = (void __iomem *)APCS_GPLL_ENA_VOTE,
+	.en_mask = BIT(4),
+	.status_reg = (void __iomem *)GPLL4_STATUS,
+	.status_mask = BIT(17),
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.rate = 768000000,
+		.parent = &xo.c,
+		.dbg_name = "gpll4",
+		.ops = &clk_ops_pll_vote,
+		CLK_INIT(gpll4.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_blsp1_2_qup1_6_i2c_apps_clk[] = {
+	F(  19200000,         xo,    1,    0,     0),
+	F(  37500000,      gpll0,   16,    0,     0),
+	F(  50000000,      gpll0,   12,    0,     0),
+	F_END
+};
+
+static struct rcg_clk blsp1_qup1_i2c_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP1_QUP1_I2C_APPS_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_gcc_blsp1_2_qup1_6_i2c_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_qup1_i2c_apps_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(LOW, 50000000),
+		CLK_INIT(blsp1_qup1_i2c_apps_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_blsp1_2_qup1_4_spi_apps_clk[] = {
+	F(    960000,         xo,   10,    1,     2),
+	F(   4800000,         xo,    4,    0,     0),
+	F(   9600000,         xo,    2,    0,     0),
+	F(  15000000,      gpll0,   10,    1,     4),
+	F(  19200000,         xo,    1,    0,     0),
+	F(  25000000,      gpll0,   12,    1,     2),
+	F(  50000000,      gpll0,   12,    0,     0),
+	F_END
+};
+
+static struct rcg_clk blsp1_qup1_spi_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP1_QUP1_SPI_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_blsp1_2_qup1_4_spi_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_qup1_spi_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 25000000, NOMINAL, 50000000),
+		CLK_INIT(blsp1_qup1_spi_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp1_qup2_i2c_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP1_QUP2_I2C_APPS_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_gcc_blsp1_2_qup1_6_i2c_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_qup2_i2c_apps_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(LOW, 50000000),
+		CLK_INIT(blsp1_qup2_i2c_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp1_qup2_spi_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP1_QUP2_SPI_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_blsp1_2_qup1_4_spi_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_qup2_spi_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 25000000, NOMINAL, 50000000),
+		CLK_INIT(blsp1_qup2_spi_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp1_qup3_i2c_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP1_QUP3_I2C_APPS_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_gcc_blsp1_2_qup1_6_i2c_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_qup3_i2c_apps_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(LOW, 50000000),
+		CLK_INIT(blsp1_qup3_i2c_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp1_qup3_spi_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP1_QUP3_SPI_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_blsp1_2_qup1_4_spi_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_qup3_spi_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 25000000, NOMINAL, 50000000),
+		CLK_INIT(blsp1_qup3_spi_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp1_qup4_i2c_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP1_QUP4_I2C_APPS_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_gcc_blsp1_2_qup1_6_i2c_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_qup4_i2c_apps_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(LOW, 50000000),
+		CLK_INIT(blsp1_qup4_i2c_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp1_qup4_spi_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP1_QUP4_SPI_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_blsp1_2_qup1_4_spi_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_qup4_spi_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 25000000, NOMINAL, 50000000),
+		CLK_INIT(blsp1_qup4_spi_apps_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_blsp1_2_uart1_4_apps_clk[] = {
+	F(   3686400,      gpll0,    1,   96, 15625),
+	F(   7372800,      gpll0,    1,  192, 15625),
+	F(  14745600,      gpll0,    1,  384, 15625),
+	F(  16000000,      gpll0,    5,    2,    15),
+	F(  19200000,         xo,    1,    0,     0),
+	F(  24000000,      gpll0,    5,    1,     5),
+	F(  32000000,      gpll0,    1,    4,    75),
+	F(  40000000,      gpll0,   15,    0,     0),
+	F(  46400000,      gpll0,    1,   29,   375),
+	F(  48000000,      gpll0, 12.5,    0,     0),
+	F(  51200000,      gpll0,    1,   32,   375),
+	F(  56000000,      gpll0,    1,    7,    75),
+	F(  58982400,      gpll0,    1, 1536, 15625),
+	F(  60000000,      gpll0,   10,    0,     0),
+	F(  63160000,      gpll0,  9.5,    0,     0),
+	F_END
+};
+
+static struct rcg_clk blsp1_uart1_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP1_UART1_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_blsp1_2_uart1_4_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_uart1_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 31580000, NOMINAL, 63160000),
+		CLK_INIT(blsp1_uart1_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp1_uart2_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP1_UART2_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_blsp1_2_uart1_4_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_uart2_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 31580000, NOMINAL, 63160000),
+		CLK_INIT(blsp1_uart2_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp1_uart3_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP1_UART3_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_blsp1_2_uart1_4_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_uart3_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 31580000, NOMINAL, 63160000),
+		CLK_INIT(blsp1_uart3_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp1_uart4_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP1_UART4_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_blsp1_2_uart1_4_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_uart4_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 31580000, NOMINAL, 63160000),
+		CLK_INIT(blsp1_uart4_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp2_qup1_i2c_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP2_QUP1_I2C_APPS_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_gcc_blsp1_2_qup1_6_i2c_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp2_qup1_i2c_apps_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(LOW, 50000000),
+		CLK_INIT(blsp2_qup1_i2c_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp2_qup1_spi_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP2_QUP1_SPI_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_blsp1_2_qup1_4_spi_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp2_qup1_spi_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 25000000, NOMINAL, 50000000),
+		CLK_INIT(blsp2_qup1_spi_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp2_qup2_i2c_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP2_QUP2_I2C_APPS_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_gcc_blsp1_2_qup1_6_i2c_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp2_qup2_i2c_apps_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(LOW, 50000000),
+		CLK_INIT(blsp2_qup2_i2c_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp2_qup2_spi_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP2_QUP2_SPI_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_blsp1_2_qup1_4_spi_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp2_qup2_spi_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 25000000, NOMINAL, 50000000),
+		CLK_INIT(blsp2_qup2_spi_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp2_qup3_i2c_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP2_QUP3_I2C_APPS_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_gcc_blsp1_2_qup1_6_i2c_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp2_qup3_i2c_apps_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(LOW, 50000000),
+		CLK_INIT(blsp2_qup3_i2c_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp2_qup3_spi_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP2_QUP3_SPI_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_blsp1_2_qup1_4_spi_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp2_qup3_spi_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 25000000, NOMINAL, 50000000),
+		CLK_INIT(blsp2_qup3_spi_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp2_qup4_i2c_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP2_QUP4_I2C_APPS_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_gcc_blsp1_2_qup1_6_i2c_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp2_qup4_i2c_apps_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(LOW, 50000000),
+		CLK_INIT(blsp2_qup4_i2c_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp2_qup4_spi_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP2_QUP4_SPI_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_blsp1_2_qup1_4_spi_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp2_qup4_spi_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 25000000, NOMINAL, 50000000),
+		CLK_INIT(blsp2_qup4_spi_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp2_uart1_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP2_UART1_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_blsp1_2_uart1_4_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp2_uart1_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 31580000, NOMINAL, 63160000),
+		CLK_INIT(blsp2_uart1_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp2_uart2_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP2_UART2_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_blsp1_2_uart1_4_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp2_uart2_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 31580000, NOMINAL, 63160000),
+		CLK_INIT(blsp2_uart2_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp2_uart3_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP2_UART3_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_blsp1_2_uart1_4_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp2_uart3_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 31580000, NOMINAL, 63160000),
+		CLK_INIT(blsp2_uart3_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp2_uart4_apps_clk_src = {
+	.cmd_rcgr_reg = BLSP2_UART4_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_blsp1_2_uart1_4_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp2_uart4_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 31580000, NOMINAL, 63160000),
+		CLK_INIT(blsp2_uart4_apps_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_ce1_clk[] = {
+	F(  75000000,      gpll0,    8,    0,     0),
+	F( 171430000,      gpll0,  3.5,    0,     0),
+	F_END
+};
+
+static struct rcg_clk ce1_clk_src = {
+	.cmd_rcgr_reg = CE1_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_gcc_ce1_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "ce1_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP2(LOW, 75000000, NOMINAL, 171430000),
+		CLK_INIT(ce1_clk_src.c),
+	},
+};
+
+static DEFINE_CLK_VOTER(scm_ce1_clk_src, &ce1_clk_src.c, 171430000);
+
+static struct clk_freq_tbl ftbl_gcc_pdm2_clk[] = {
+	F(  60000000,      gpll0,   10,    0,     0),
+	F_END
+};
+
+static struct rcg_clk pdm2_clk_src = {
+	.cmd_rcgr_reg = PDM2_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_gcc_pdm2_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "pdm2_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(LOW, 60000000),
+		CLK_INIT(pdm2_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_sdcc1_apps_clk[] = {
+	F(    144000,         xo,   16,    3,    25),
+	F(    400000,         xo,   12,    1,     4),
+	F(  20000000,      gpll0,   15,    1,     2),
+	F(  25000000,      gpll0,   12,    1,     2),
+	F(  50000000,      gpll0,   12,    0,     0),
+	F( 100000000,      gpll0,    6,    0,     0),
+	F( 192000000,      gpll4,    4,    0,     0),
+	F( 384000000,      gpll4,    2,    0,     0),
+	F_END
+};
+
+static struct clk_freq_tbl ftbl_gcc_sdcc2_4_apps_clk[] = {
+	F(    144000,         xo,   16,    3,    25),
+	F(    400000,         xo,   12,    1,     4),
+	F(  20000000,      gpll0,   15,    1,     2),
+	F(  25000000,      gpll0,   12,    1,     2),
+	F(  50000000,      gpll0,   12,    0,     0),
+	F( 100000000,      gpll0,    6,    0,     0),
+	F( 200000000,      gpll0,    3,    0,     0),
+	F_END
+};
+
+static struct rcg_clk sdcc1_apps_clk_src = {
+	.cmd_rcgr_reg = SDCC1_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_sdcc1_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "sdcc1_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 50000000, NOMINAL, 400000000),
+		CLK_INIT(sdcc1_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk sdcc2_apps_clk_src = {
+	.cmd_rcgr_reg = SDCC2_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_sdcc2_4_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "sdcc2_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 50000000, NOMINAL, 200000000),
+		CLK_INIT(sdcc2_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk sdcc3_apps_clk_src = {
+	.cmd_rcgr_reg = SDCC3_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_sdcc2_4_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "sdcc3_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 50000000, NOMINAL, 100000000),
+		CLK_INIT(sdcc3_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk sdcc4_apps_clk_src = {
+	.cmd_rcgr_reg = SDCC4_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_sdcc2_4_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "sdcc4_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 50000000, NOMINAL, 100000000),
+		CLK_INIT(sdcc4_apps_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_tsif_ref_clk[] = {
+	F(    105000,         xo,    2,    1,    91),
+	F_END
+};
+
+static struct rcg_clk tsif_ref_clk_src = {
+	.cmd_rcgr_reg = TSIF_REF_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_tsif_ref_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "tsif_ref_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP1(LOW, 105500),
+		CLK_INIT(tsif_ref_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_usb_hs_system_clk[] = {
+	F(  75000000,      gpll0,    8,    0,     0),
+	F_END
+};
+
+static struct rcg_clk usb_hs_system_clk_src = {
+	.cmd_rcgr_reg = USB_HS_SYSTEM_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_gcc_usb_hs_system_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "usb_hs_system_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP2(LOW, 37500000, NOMINAL, 75000000),
+		CLK_INIT(usb_hs_system_clk_src.c),
+	},
+};
+
+static struct local_vote_clk gcc_bam_dma_ahb_clk = {
+	.cbcr_reg = BAM_DMA_AHB_CBCR,
+	.vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
+	.en_mask = BIT(12),
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_bam_dma_ahb_clk",
+		.ops = &clk_ops_vote,
+		CLK_INIT(gcc_bam_dma_ahb_clk.c),
+	},
+};
+
+static struct local_vote_clk gcc_blsp1_ahb_clk = {
+	.cbcr_reg = BLSP1_AHB_CBCR,
+	.vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
+	.en_mask = BIT(17),
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_ahb_clk",
+		.ops = &clk_ops_vote,
+		CLK_INIT(gcc_blsp1_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_qup1_i2c_apps_clk = {
+	.cbcr_reg = BLSP1_QUP1_I2C_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_qup1_i2c_apps_clk",
+		.parent = &blsp1_qup1_i2c_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_qup1_i2c_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_qup1_spi_apps_clk = {
+	.cbcr_reg = BLSP1_QUP1_SPI_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_qup1_spi_apps_clk",
+		.parent = &blsp1_qup1_spi_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_qup1_spi_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_qup2_i2c_apps_clk = {
+	.cbcr_reg = BLSP1_QUP2_I2C_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_qup2_i2c_apps_clk",
+		.parent = &blsp1_qup2_i2c_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_qup2_i2c_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_qup2_spi_apps_clk = {
+	.cbcr_reg = BLSP1_QUP2_SPI_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_qup2_spi_apps_clk",
+		.parent = &blsp1_qup2_spi_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_qup2_spi_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_qup3_i2c_apps_clk = {
+	.cbcr_reg = BLSP1_QUP3_I2C_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_qup3_i2c_apps_clk",
+		.parent = &blsp1_qup3_i2c_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_qup3_i2c_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_qup3_spi_apps_clk = {
+	.cbcr_reg = BLSP1_QUP3_SPI_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_qup3_spi_apps_clk",
+		.parent = &blsp1_qup3_spi_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_qup3_spi_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_qup4_i2c_apps_clk = {
+	.cbcr_reg = BLSP1_QUP4_I2C_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_qup4_i2c_apps_clk",
+		.parent = &blsp1_qup4_i2c_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_qup4_i2c_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_qup4_spi_apps_clk = {
+	.cbcr_reg = BLSP1_QUP4_SPI_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_qup4_spi_apps_clk",
+		.parent = &blsp1_qup4_spi_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_qup4_spi_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_uart1_apps_clk = {
+	.cbcr_reg = BLSP1_UART1_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_uart1_apps_clk",
+		.parent = &blsp1_uart1_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_uart1_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_uart2_apps_clk = {
+	.cbcr_reg = BLSP1_UART2_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_uart2_apps_clk",
+		.parent = &blsp1_uart2_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_uart2_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_uart3_apps_clk = {
+	.cbcr_reg = BLSP1_UART3_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_uart3_apps_clk",
+		.parent = &blsp1_uart3_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_uart3_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_uart4_apps_clk = {
+	.cbcr_reg = BLSP1_UART4_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_uart4_apps_clk",
+		.parent = &blsp1_uart4_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_uart4_apps_clk.c),
+	},
+};
+
+static struct local_vote_clk gcc_blsp2_ahb_clk = {
+	.cbcr_reg = BLSP2_AHB_CBCR,
+	.vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
+	.en_mask = BIT(15),
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp2_ahb_clk",
+		.ops = &clk_ops_vote,
+		CLK_INIT(gcc_blsp2_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp2_qup1_i2c_apps_clk = {
+	.cbcr_reg = BLSP2_QUP1_I2C_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp2_qup1_i2c_apps_clk",
+		.parent = &blsp2_qup1_i2c_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp2_qup1_i2c_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp2_qup1_spi_apps_clk = {
+	.cbcr_reg = BLSP2_QUP1_SPI_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp2_qup1_spi_apps_clk",
+		.parent = &blsp2_qup1_spi_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp2_qup1_spi_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp2_qup2_i2c_apps_clk = {
+	.cbcr_reg = BLSP2_QUP2_I2C_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp2_qup2_i2c_apps_clk",
+		.parent = &blsp2_qup2_i2c_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp2_qup2_i2c_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp2_qup2_spi_apps_clk = {
+	.cbcr_reg = BLSP2_QUP2_SPI_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp2_qup2_spi_apps_clk",
+		.parent = &blsp2_qup2_spi_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp2_qup2_spi_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp2_qup3_i2c_apps_clk = {
+	.cbcr_reg = BLSP2_QUP3_I2C_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp2_qup3_i2c_apps_clk",
+		.parent = &blsp2_qup3_i2c_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp2_qup3_i2c_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp2_qup3_spi_apps_clk = {
+	.cbcr_reg = BLSP2_QUP3_SPI_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp2_qup3_spi_apps_clk",
+		.parent = &blsp2_qup3_spi_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp2_qup3_spi_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp2_qup4_i2c_apps_clk = {
+	.cbcr_reg = BLSP2_QUP4_I2C_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp2_qup4_i2c_apps_clk",
+		.parent = &blsp2_qup4_i2c_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp2_qup4_i2c_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp2_qup4_spi_apps_clk = {
+	.cbcr_reg = BLSP2_QUP4_SPI_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp2_qup4_spi_apps_clk",
+		.parent = &blsp2_qup4_spi_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp2_qup4_spi_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp2_uart1_apps_clk = {
+	.cbcr_reg = BLSP2_UART1_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp2_uart1_apps_clk",
+		.parent = &blsp2_uart1_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp2_uart1_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp2_uart2_apps_clk = {
+	.cbcr_reg = BLSP2_UART2_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp2_uart2_apps_clk",
+		.parent = &blsp2_uart2_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp2_uart2_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp2_uart3_apps_clk = {
+	.cbcr_reg = BLSP2_UART3_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp2_uart3_apps_clk",
+		.parent = &blsp2_uart3_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp2_uart3_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp2_uart4_apps_clk = {
+	.cbcr_reg = BLSP2_UART4_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp2_uart4_apps_clk",
+		.parent = &blsp2_uart4_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp2_uart4_apps_clk.c),
+	},
+};
+
+static struct local_vote_clk gcc_boot_rom_ahb_clk = {
+	.cbcr_reg = BOOT_ROM_AHB_CBCR,
+	.vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
+	.en_mask = BIT(10),
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_boot_rom_ahb_clk",
+		.ops = &clk_ops_vote,
+		CLK_INIT(gcc_boot_rom_ahb_clk.c),
+	},
+};
+
+static struct local_vote_clk gcc_ce1_ahb_clk = {
+	.cbcr_reg = CE1_AHB_CBCR,
+	.vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
+	.en_mask = BIT(3),
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_ce1_ahb_clk",
+		.ops = &clk_ops_vote,
+		CLK_INIT(gcc_ce1_ahb_clk.c),
+	},
+};
+
+static struct local_vote_clk gcc_ce1_axi_clk = {
+	.cbcr_reg = CE1_AXI_CBCR,
+	.vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
+	.en_mask = BIT(4),
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_ce1_axi_clk",
+		.ops = &clk_ops_vote,
+		CLK_INIT(gcc_ce1_axi_clk.c),
+	},
+};
+
+static struct local_vote_clk gcc_ce1_clk = {
+	.cbcr_reg = CE1_CBCR,
+	.vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
+	.en_mask = BIT(5),
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_ce1_clk",
+		.parent = &ce1_clk_src.c,
+		.ops = &clk_ops_vote,
+		CLK_INIT(gcc_ce1_clk.c),
+	},
+};
+
+static struct branch_clk gcc_lpass_q6_axi_clk = {
+	.cbcr_reg = LPASS_Q6_AXI_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_lpass_q6_axi_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_lpass_q6_axi_clk.c),
+	},
+};
+
+static struct branch_clk gcc_lpass_sys_noc_mport_clk = {
+	.cbcr_reg = LPASS_SYS_NOC_MPORT_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_lpass_sys_noc_mport_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_lpass_sys_noc_mport_clk.c),
+	},
+};
+
+static struct branch_clk gcc_lpass_sys_noc_sway_clk = {
+	.cbcr_reg = LPASS_SYS_NOC_SWAY_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_lpass_sys_noc_sway_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_lpass_sys_noc_sway_clk.c),
+	},
+};
+
+static struct branch_clk gcc_mss_cfg_ahb_clk = {
+	.cbcr_reg = MSS_CFG_AHB_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_mss_cfg_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_mss_cfg_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_mss_q6_bimc_axi_clk = {
+	.cbcr_reg = MSS_Q6_BIMC_AXI_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_mss_q6_bimc_axi_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_mss_q6_bimc_axi_clk.c),
+	},
+};
+
+static struct branch_clk gcc_pdm2_clk = {
+	.cbcr_reg = PDM2_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_pdm2_clk",
+		.parent = &pdm2_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_pdm2_clk.c),
+	},
+};
+
+static struct branch_clk gcc_pdm_ahb_clk = {
+	.cbcr_reg = PDM_AHB_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_pdm_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_pdm_ahb_clk.c),
+	},
+};
+
+static struct local_vote_clk gcc_prng_ahb_clk = {
+	.cbcr_reg = PRNG_AHB_CBCR,
+	.vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
+	.en_mask = BIT(13),
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_prng_ahb_clk",
+		.ops = &clk_ops_vote,
+		CLK_INIT(gcc_prng_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_sdcc1_ahb_clk = {
+	.cbcr_reg = SDCC1_AHB_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_sdcc1_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_sdcc1_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_sdcc1_apps_clk = {
+	.cbcr_reg = SDCC1_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_sdcc1_apps_clk",
+		.parent = &sdcc1_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_sdcc1_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_sdcc1_cdccal_ff_clk = {
+	.cbcr_reg = SDCC1_CDCCAL_FF_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_sdcc1_cdccal_ff_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_sdcc1_cdccal_ff_clk.c),
+	},
+};
+
+static struct branch_clk gcc_sdcc1_cdccal_sleep_clk = {
+	.cbcr_reg = SDCC1_CDCCAL_SLEEP_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_sdcc1_cdccal_sleep_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_sdcc1_cdccal_sleep_clk.c),
+	},
+};
+
+static struct branch_clk gcc_sdcc2_ahb_clk = {
+	.cbcr_reg = SDCC2_AHB_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_sdcc2_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_sdcc2_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_sdcc2_apps_clk = {
+	.cbcr_reg = SDCC2_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_sdcc2_apps_clk",
+		.parent = &sdcc2_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_sdcc2_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_sdcc3_ahb_clk = {
+	.cbcr_reg = SDCC3_AHB_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_sdcc3_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_sdcc3_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_sdcc3_apps_clk = {
+	.cbcr_reg = SDCC3_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_sdcc3_apps_clk",
+		.parent = &sdcc3_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_sdcc3_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_sdcc4_ahb_clk = {
+	.cbcr_reg = SDCC4_AHB_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_sdcc4_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_sdcc4_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_sdcc4_apps_clk = {
+	.cbcr_reg = SDCC4_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_sdcc4_apps_clk",
+		.parent = &sdcc4_apps_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_sdcc4_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_tsif_ahb_clk = {
+	.cbcr_reg = TSIF_AHB_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_tsif_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_tsif_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_tsif_ref_clk = {
+	.cbcr_reg = TSIF_REF_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_tsif_ref_clk",
+		.parent = &tsif_ref_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_tsif_ref_clk.c),
+	},
+};
+
+static struct branch_clk gcc_usb2a_phy_sleep_clk = {
+	.cbcr_reg = USB2A_PHY_SLEEP_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_usb2a_phy_sleep_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_usb2a_phy_sleep_clk.c),
+	},
+};
+
+static struct branch_clk gcc_usb_hs_ahb_clk = {
+	.cbcr_reg = USB_HS_AHB_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_usb_hs_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_usb_hs_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_usb_hs_system_clk = {
+	.cbcr_reg = USB_HS_SYSTEM_CBCR,
+	.bcr_reg = USB_HS_BCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_usb_hs_system_clk",
+		.parent = &usb_hs_system_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_usb_hs_system_clk.c),
+	},
+};
+
+static struct pll_vote_clk mmpll0 = {
+	.en_reg = (void __iomem *)MMSS_PLL_VOTE_APCS,
+	.en_mask = BIT(0),
+	.status_reg = (void __iomem *)MMPLL0_STATUS,
+	.status_mask = BIT(17),
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.rate = 800000000,
+		.parent = &xo.c,
+		.dbg_name = "mmpll0",
+		.ops = &clk_ops_pll_vote,
+		CLK_INIT(mmpll0.c),
+	},
+};
+
+static struct pll_vote_clk mmpll1 = {
+	.en_reg = (void __iomem *)MMSS_PLL_VOTE_APCS,
+	.en_mask = BIT(1),
+	.status_reg = (void __iomem *)MMPLL1_STATUS,
+	.status_mask = BIT(17),
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.rate = 900000000,
+		.parent = &xo.c,
+		.dbg_name = "mmpll1",
+		.ops = &clk_ops_pll_vote,
+		CLK_INIT(mmpll1.c),
+	},
+};
+
+static struct pll_clk mmpll4 = {
+	.mode_reg = (void __iomem *)MMPLL4_MODE,
+	.status_reg = (void __iomem *)MMPLL4_STATUS,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "mmpll4",
+		.parent = &xo.c,
+		.rate = 930000000,
+		.ops = &clk_ops_local_pll,
+		CLK_INIT(mmpll4.c),
+	},
+};
+
+static struct pll_clk mmpll3 = {
+	.mode_reg = (void __iomem *)MMPLL3_MODE,
+	.status_reg = (void __iomem *)MMPLL3_STATUS,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "mmpll3",
+		.parent = &xo.c,
+		.rate = 930000000,
+		.ops = &clk_ops_local_pll,
+		CLK_INIT(mmpll3.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_mmss_mmssnoc_axi_clk[] = {
+	F_MM(  19200000,         xo,    1,    0,     0),
+	F_MM(  37500000,      gpll0,   16,    0,     0),
+	F_MM(  50000000,      gpll0,   12,    0,     0),
+	F_MM(  75000000,      gpll0,    8,    0,     0),
+	F_MM( 100000000,      gpll0,    6,    0,     0),
+	F_MM( 133330000,      gpll0,  4.5,    0,     0),
+	F_MM( 266670000,     mmpll0,    3,    0,     0),
+	F_MM( 300000000,     mmpll1,    3,    0,     0),
+	F_END
+};
+
+static struct rcg_clk axi_clk_src = {
+	.cmd_rcgr_reg = AXI_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_mmss_mmssnoc_axi_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "axi_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP3(LOW, 133330000, NOMINAL, 266670000, HIGH,
+			300000000),
+		CLK_INIT(axi_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_camss_csi0_2_clk[] = {
+	F_MM( 100000000,      gpll0,    6,    0,     0),
+	F_MM( 200000000,     mmpll0,    4,    0,     0),
+	F_END
+};
+
+static struct rcg_clk csi0_clk_src = {
+	.cmd_rcgr_reg = CSI0_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_camss_csi0_2_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "csi0_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP2(LOW, 100000000, NOMINAL, 200000000),
+		CLK_INIT(csi0_clk_src.c),
+	},
+};
+
+static struct rcg_clk csi1_clk_src = {
+	.cmd_rcgr_reg = CSI1_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_camss_csi0_2_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "csi1_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP2(LOW, 100000000, NOMINAL, 200000000),
+		CLK_INIT(csi1_clk_src.c),
+	},
+};
+
+static struct rcg_clk csi2_clk_src = {
+	.cmd_rcgr_reg = CSI2_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_camss_csi0_2_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "csi2_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP2(LOW, 100000000, NOMINAL, 200000000),
+		CLK_INIT(csi2_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_camss_vfe_vfe0_1_clk[] = {
+	F_MM(  37500000,      gpll0,   16,    0,     0),
+	F_MM(  50000000,      gpll0,   12,    0,     0),
+	F_MM(  60000000,      gpll0,   10,    0,     0),
+	F_MM(  80000000,      gpll0,  7.5,    0,     0),
+	F_MM( 100000000,      gpll0,    6,    0,     0),
+	F_MM( 109090000,      gpll0,  5.5,    0,     0),
+	F_MM( 133330000,      gpll0,  4.5,    0,     0),
+	F_MM( 150000000,      gpll0,    4,    0,     0),
+	F_MM( 200000000,      gpll0,    3,    0,     0),
+	F_MM( 228570000,     mmpll0,  3.5,    0,     0),
+	F_MM( 266670000,     mmpll0,    3,    0,     0),
+	F_MM( 320000000,     mmpll0,  2.5,    0,     0),
+	F_MM( 400000000,     mmpll0,    2,    0,     0),
+	F_MM( 465000000,     mmpll4,    2,    0,     0),
+	F_END
+};
+
+static struct rcg_clk vfe0_clk_src = {
+	.cmd_rcgr_reg = VFE0_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_camss_vfe_vfe0_1_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "vfe0_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP3(LOW, 150000000, NOMINAL, 320000000, HIGH,
+			465000000),
+		CLK_INIT(vfe0_clk_src.c),
+	},
+};
+
+static struct rcg_clk vfe1_clk_src = {
+	.cmd_rcgr_reg = VFE1_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_camss_vfe_vfe0_1_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "vfe1_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP3(LOW, 133330000, NOMINAL, 266670000, HIGH,
+			320000000),
+		CLK_INIT(vfe1_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_mdss_mdp_clk[] = {
+	F_MM(  37500000,      gpll0,   16,    0,     0),
+	F_MM(  60000000,      gpll0,   10,    0,     0),
+	F_MM(  75000000,      gpll0,    8,    0,     0),
+	F_MM(  85710000,      gpll0,    7,    0,     0),
+	F_MM( 100000000,      gpll0,    6,    0,     0),
+	F_MM( 150000000,      gpll0,    4,    0,     0),
+	F_MM( 160000000,     mmpll0,    5,    0,     0),
+	F_MM( 200000000,     mmpll0,    4,    0,     0),
+	F_MM( 228570000,     mmpll0,  3.5,    0,     0),
+	F_MM( 266670000,     mmpll0,    3,    0,     0),
+	F_MM( 320000000,     mmpll0,  2.5,    0,     0),
+	F_END
+};
+
+static struct rcg_clk mdp_clk_src = {
+	.cmd_rcgr_reg = MDP_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_mdss_mdp_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "mdp_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP3(LOW, 150000000, NOMINAL, 266670000, HIGH,
+			320000000),
+		CLK_INIT(mdp_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_camss_jpeg_jpeg0_clk[] = {
+	F_MM(  75000000,      gpll0,    8,    0,     0),
+	F_MM( 133330000,      gpll0,  4.5,    0,     0),
+	F_MM( 200000000,      gpll0,    3,    0,     0),
+	F_MM( 228570000,     mmpll0,  3.5,    0,     0),
+	F_MM( 266670000,     mmpll0,    3,    0,     0),
+	F_MM( 320000000,     mmpll0,  2.5,    0,     0),
+	F_END
+};
+
+static struct rcg_clk jpeg0_clk_src = {
+	.cmd_rcgr_reg = JPEG0_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_camss_jpeg_jpeg0_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "jpeg0_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP3(LOW, 133330000, NOMINAL, 266670000, HIGH,
+			320000000),
+		CLK_INIT(jpeg0_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl pixel_freq_tbl[] = {
+	{
+		.src_clk = &pixel_clk_src_samarium.c,
+		.div_src_val = BVAL(10, 8, dsipll0_pixel_mm_source_val)
+				| BVAL(4, 0, 0),
+	},
+	F_END
+};
+
+static struct rcg_clk pclk0_clk_src = {
+	.cmd_rcgr_reg = PCLK0_CMD_RCGR,
+	.current_freq = pixel_freq_tbl,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.parent = &pixel_clk_src_samarium.c,
+		.dbg_name = "pclk0_clk_src",
+		.ops = &clk_ops_pixel,
+		VDD_DIG_FMAX_MAP2(LOW, 148500000, NOMINAL, 250000000),
+		CLK_INIT(pclk0_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_ocmemcx_ocmemnoc_clk[] = {
+	F_MM(  19200000,         xo,    1,    0,     0),
+	F_MM(  37500000,      gpll0,   16,    0,     0),
+	F_MM(  50000000,      gpll0,   12,    0,     0),
+	F_MM(  75000000,      gpll0,    8,    0,     0),
+	F_MM( 109090000,      gpll0,  5.5,    0,     0),
+	F_MM( 150000000,      gpll0,    4,    0,     0),
+	F_MM( 266670000,     mmpll0,    3,    0,     0),
+	F_MM( 300000000,     mmpll1,    3,    0,     0),
+	F_END
+};
+
+static struct rcg_clk ocmemnoc_clk_src = {
+	.cmd_rcgr_reg = OCMEMNOC_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_ocmemcx_ocmemnoc_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "ocmemnoc_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP3(LOW, 133330000, NOMINAL, 266670000, HIGH,
+			300000000),
+		CLK_INIT(ocmemnoc_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_camss_cci_cci_clk[] = {
+	F_MM(  19200000,         xo,    1,    0,     0),
+	F_END
+};
+
+static struct rcg_clk cci_clk_src = {
+	.cmd_rcgr_reg = CCI_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_camss_cci_cci_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "cci_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP1(LOW, 19200000),
+		CLK_INIT(cci_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_camss_gp0_1_clk[] = {
+	F_MM(     10000,         xo,   16,    1,   120),
+	F_MM(     24000,         xo,   16,    1,    50),
+	F_MM(   6000000,      gpll0,   10,    1,    10),
+	F_MM(  12000000,      gpll0,   10,    1,     5),
+	F_MM(  13000000,      gpll0,    4,   13,   150),
+	F_MM(  24000000,      gpll0,    5,    1,     5),
+	F_END
+};
+
+static struct rcg_clk mmss_gp0_clk_src = {
+	.cmd_rcgr_reg = MMSS_GP0_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_camss_gp0_1_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "mmss_gp0_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 100000000, NOMINAL, 200000000),
+		CLK_INIT(mmss_gp0_clk_src.c),
+	},
+};
+
+static struct rcg_clk mmss_gp1_clk_src = {
+	.cmd_rcgr_reg = MMSS_GP1_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_camss_gp0_1_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "mmss_gp1_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 100000000, NOMINAL, 200000000),
+		CLK_INIT(mmss_gp1_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_camss_mclk0_2_clk[] = {
+	F_MM(   4800000,         xo,    4,    0,     0),
+	F_MM(   6000000,      gpll0,   10,    1,    10),
+	F_MM(   8000000,      gpll0,   15,    1,     5),
+	F_MM(   9600000,         xo,    2,    0,     0),
+	F_MM(  16000000,      gpll0, 12.5,    1,     3),
+	F_MM(  19200000,         xo,    1,    0,     0),
+	F_MM(  24000000,      gpll0,    5,    1,     5),
+	F_MM(  32000000,     mmpll0,    5,    1,     5),
+	F_MM(  48000000,      gpll0, 12.5,    0,     0),
+	F_MM(  64000000,     mmpll0, 12.5,    0,     0),
+	F_MM(  66670000,      gpll0,    9,    0,     0),
+	F_END
+};
+
+static struct rcg_clk mclk0_clk_src = {
+	.cmd_rcgr_reg = MCLK0_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_camss_mclk0_2_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "mclk0_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP1(LOW, 66670000),
+		CLK_INIT(mclk0_clk_src.c),
+	},
+};
+
+static struct rcg_clk mclk1_clk_src = {
+	.cmd_rcgr_reg = MCLK1_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_camss_mclk0_2_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "mclk1_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP1(LOW, 66670000),
+		CLK_INIT(mclk1_clk_src.c),
+	},
+};
+
+static struct rcg_clk mclk2_clk_src = {
+	.cmd_rcgr_reg = MCLK2_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_camss_mclk0_2_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "mclk2_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP1(LOW, 66670000),
+		CLK_INIT(mclk2_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_camss_phy0_1_csi0_1phytimer_clk[] = {
+	F_MM( 100000000,      gpll0,    6,    0,     0),
+	F_MM( 200000000,     mmpll0,    4,    0,     0),
+	F_END
+};
+
+static struct rcg_clk csi0phytimer_clk_src = {
+	.cmd_rcgr_reg = CSI0PHYTIMER_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_camss_phy0_1_csi0_1phytimer_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "csi0phytimer_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP2(LOW, 100000000, NOMINAL, 200000000),
+		CLK_INIT(csi0phytimer_clk_src.c),
+	},
+};
+
+static struct rcg_clk csi1phytimer_clk_src = {
+	.cmd_rcgr_reg = CSI1PHYTIMER_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_camss_phy0_1_csi0_1phytimer_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "csi1phytimer_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP2(LOW, 100000000, NOMINAL, 200000000),
+		CLK_INIT(csi1phytimer_clk_src.c),
+	},
+};
+
+static struct branch_clk camss_vfe_vfe0_clk = {
+	.cbcr_reg = CAMSS_VFE_VFE0_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_vfe_vfe0_clk",
+		.parent = &vfe0_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_vfe_vfe0_clk.c),
+	},
+};
+
+static struct branch_clk camss_vfe_vfe1_clk = {
+	.cbcr_reg = CAMSS_VFE_VFE1_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_vfe_vfe1_clk",
+		.parent = &vfe1_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_vfe_vfe1_clk.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_camss_vfe_cpp_clk[] = {
+	F_MM( 150000000,      gpll0,    4,    0,     0),
+	F_MM( 266670000,     mmpll0,    3,    0,     0),
+	F_MM( 320000000,     mmpll0,  2.5,    0,     0),
+	F_MM( 400000000,     mmpll0,    2,    0,     0),
+	F_MM( 465000000,     mmpll4,    2,    0,     0),
+	F_END
+};
+
+static struct rcg_clk cpp_clk_src = {
+	.cmd_rcgr_reg = CPP_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_camss_vfe_cpp_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "cpp_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP3(LOW, 150000000, NOMINAL, 320000000, HIGH,
+			465000000),
+		CLK_INIT(cpp_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl byte_freq_tbl[] = {
+	{
+		.src_clk = &byte_clk_src_samarium.c,
+		.div_src_val = BVAL(10, 8, dsipll0_byte_mm_source_val),
+	},
+	F_END
+};
+
+static struct rcg_clk byte0_clk_src = {
+	.cmd_rcgr_reg = BYTE0_CMD_RCGR,
+	.current_freq = byte_freq_tbl,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.parent = &byte_clk_src_samarium.c,
+		.dbg_name = "byte0_clk_src",
+		.ops = &clk_ops_byte,
+		VDD_DIG_FMAX_MAP2(LOW, 111370000, NOMINAL, 187500000),
+		CLK_INIT(byte0_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_mdss_esc0_clk[] = {
+	F_MM(  19200000,         xo,    1,    0,     0),
+	F_END
+};
+
+static struct rcg_clk esc0_clk_src = {
+	.cmd_rcgr_reg = ESC0_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_mdss_esc0_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "esc0_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(LOW, 19200000),
+		CLK_INIT(esc0_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_mdss_vsync_clk[] = {
+	F_MM(  19200000,         xo,    1,    0,     0),
+	F_END
+};
+
+static struct rcg_clk vsync_clk_src = {
+	.cmd_rcgr_reg = VSYNC_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_mdss_vsync_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "vsync_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(LOW, 19200000),
+		CLK_INIT(vsync_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_venus0_vcodec0_clk[] = {
+	F_MM(  50000000,      gpll0,   12,    0,     0),
+	F_MM( 100000000,      gpll0,    6,    0,     0),
+	F_MM( 133330000,     mmpll0,    6,    0,     0),
+	F_MM( 200000000,     mmpll0,    4,    0,     0),
+	F_MM( 266670000,     mmpll0,    3,    0,     0),
+	F_END
+};
+
+static struct rcg_clk vcodec0_clk_src = {
+	.cmd_rcgr_reg = VCODEC0_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_venus0_vcodec0_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "vcodec0_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 133330000, NOMINAL, 266670000),
+		CLK_INIT(vcodec0_clk_src.c),
+	},
+};
+
+static struct branch_clk camss_ahb_clk = {
+	.cbcr_reg = CAMSS_AHB_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_ahb_clk.c),
+	},
+};
+
+static struct branch_clk camss_cci_cci_ahb_clk = {
+	.cbcr_reg = CAMSS_CCI_CCI_AHB_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_cci_cci_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_cci_cci_ahb_clk.c),
+	},
+};
+
+static struct branch_clk camss_cci_cci_clk = {
+	.cbcr_reg = CAMSS_CCI_CCI_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_cci_cci_clk",
+		.parent = &cci_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_cci_cci_clk.c),
+	},
+};
+
+static struct branch_clk camss_csi0_ahb_clk = {
+	.cbcr_reg = CAMSS_CSI0_AHB_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_csi0_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_csi0_ahb_clk.c),
+	},
+};
+
+static struct branch_clk camss_csi0_clk = {
+	.cbcr_reg = CAMSS_CSI0_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_csi0_clk",
+		.parent = &csi0_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_csi0_clk.c),
+	},
+};
+
+static struct branch_clk camss_csi0phy_clk = {
+	.cbcr_reg = CAMSS_CSI0PHY_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_csi0phy_clk",
+		.parent = &csi0_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_csi0phy_clk.c),
+	},
+};
+
+static struct branch_clk camss_csi0pix_clk = {
+	.cbcr_reg = CAMSS_CSI0PIX_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_csi0pix_clk",
+		.parent = &csi0_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_csi0pix_clk.c),
+	},
+};
+
+static struct branch_clk camss_csi0rdi_clk = {
+	.cbcr_reg = CAMSS_CSI0RDI_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_csi0rdi_clk",
+		.parent = &csi0_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_csi0rdi_clk.c),
+	},
+};
+
+static struct branch_clk camss_csi1_ahb_clk = {
+	.cbcr_reg = CAMSS_CSI1_AHB_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_csi1_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_csi1_ahb_clk.c),
+	},
+};
+
+static struct branch_clk camss_csi1_clk = {
+	.cbcr_reg = CAMSS_CSI1_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_csi1_clk",
+		.parent = &csi1_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_csi1_clk.c),
+	},
+};
+
+static struct branch_clk camss_csi1phy_clk = {
+	.cbcr_reg = CAMSS_CSI1PHY_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_csi1phy_clk",
+		.parent = &csi1_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_csi1phy_clk.c),
+	},
+};
+
+static struct branch_clk camss_csi1pix_clk = {
+	.cbcr_reg = CAMSS_CSI1PIX_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_csi1pix_clk",
+		.parent = &csi1_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_csi1pix_clk.c),
+	},
+};
+
+static struct branch_clk camss_csi1rdi_clk = {
+	.cbcr_reg = CAMSS_CSI1RDI_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_csi1rdi_clk",
+		.parent = &csi1_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_csi1rdi_clk.c),
+	},
+};
+
+static struct branch_clk camss_csi2_ahb_clk = {
+	.cbcr_reg = CAMSS_CSI2_AHB_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_csi2_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_csi2_ahb_clk.c),
+	},
+};
+
+static struct branch_clk camss_csi2_clk = {
+	.cbcr_reg = CAMSS_CSI2_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_csi2_clk",
+		.parent = &csi2_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_csi2_clk.c),
+	},
+};
+
+static struct branch_clk camss_csi2phy_clk = {
+	.cbcr_reg = CAMSS_CSI2PHY_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_csi2phy_clk",
+		.parent = &csi2_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_csi2phy_clk.c),
+	},
+};
+
+static struct branch_clk camss_csi2pix_clk = {
+	.cbcr_reg = CAMSS_CSI2PIX_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_csi2pix_clk",
+		.parent = &csi2_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_csi2pix_clk.c),
+	},
+};
+
+static struct branch_clk camss_csi2rdi_clk = {
+	.cbcr_reg = CAMSS_CSI2RDI_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_csi2rdi_clk",
+		.parent = &csi2_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_csi2rdi_clk.c),
+	},
+};
+
+static struct branch_clk camss_csi_vfe0_clk = {
+	.cbcr_reg = CAMSS_CSI_VFE0_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_csi_vfe0_clk",
+		.parent = &vfe0_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_csi_vfe0_clk.c),
+	},
+};
+
+static struct branch_clk camss_csi_vfe1_clk = {
+	.cbcr_reg = CAMSS_CSI_VFE1_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_csi_vfe1_clk",
+		.parent = &vfe1_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_csi_vfe1_clk.c),
+	},
+};
+
+static struct branch_clk camss_gp0_clk = {
+	.cbcr_reg = CAMSS_GP0_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_gp0_clk",
+		.parent = &mmss_gp0_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_gp0_clk.c),
+	},
+};
+
+static struct branch_clk camss_gp1_clk = {
+	.cbcr_reg = CAMSS_GP1_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_gp1_clk",
+		.parent = &mmss_gp1_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_gp1_clk.c),
+	},
+};
+
+static struct branch_clk camss_ispif_ahb_clk = {
+	.cbcr_reg = CAMSS_ISPIF_AHB_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_ispif_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_ispif_ahb_clk.c),
+	},
+};
+
+static struct branch_clk camss_jpeg_jpeg0_clk = {
+	.cbcr_reg = CAMSS_JPEG_JPEG0_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_jpeg_jpeg0_clk",
+		.parent = &jpeg0_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_jpeg_jpeg0_clk.c),
+	},
+};
+
+static struct branch_clk camss_jpeg_jpeg_ahb_clk = {
+	.cbcr_reg = CAMSS_JPEG_JPEG_AHB_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_jpeg_jpeg_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_jpeg_jpeg_ahb_clk.c),
+	},
+};
+
+static struct branch_clk camss_jpeg_jpeg_axi_clk = {
+	.cbcr_reg = CAMSS_JPEG_JPEG_AXI_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_jpeg_jpeg_axi_clk",
+		.parent = &axi_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_jpeg_jpeg_axi_clk.c),
+	},
+};
+
+static struct branch_clk camss_mclk0_clk = {
+	.cbcr_reg = CAMSS_MCLK0_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_mclk0_clk",
+		.parent = &mclk0_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_mclk0_clk.c),
+	},
+};
+
+static struct branch_clk camss_mclk1_clk = {
+	.cbcr_reg = CAMSS_MCLK1_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_mclk1_clk",
+		.parent = &mclk1_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_mclk1_clk.c),
+	},
+};
+
+static struct branch_clk camss_mclk2_clk = {
+	.cbcr_reg = CAMSS_MCLK2_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_mclk2_clk",
+		.parent = &mclk2_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_mclk2_clk.c),
+	},
+};
+
+static struct branch_clk camss_micro_ahb_clk = {
+	.cbcr_reg = CAMSS_MICRO_AHB_CBCR,
+	.bcr_reg = CAMSS_MICRO_BCR,
+	.has_sibling = 1,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_micro_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_micro_ahb_clk.c),
+	},
+};
+
+static struct branch_clk camss_phy0_csi0phytimer_clk = {
+	.cbcr_reg = CAMSS_PHY0_CSI0PHYTIMER_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_phy0_csi0phytimer_clk",
+		.parent = &csi0phytimer_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_phy0_csi0phytimer_clk.c),
+	},
+};
+
+static struct branch_clk camss_phy1_csi1phytimer_clk = {
+	.cbcr_reg = CAMSS_PHY1_CSI1PHYTIMER_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_phy1_csi1phytimer_clk",
+		.parent = &csi1phytimer_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_phy1_csi1phytimer_clk.c),
+	},
+};
+
+static struct branch_clk camss_top_ahb_clk = {
+	.cbcr_reg = CAMSS_TOP_AHB_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_top_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_top_ahb_clk.c),
+	},
+};
+
+static struct branch_clk camss_vfe_cpp_ahb_clk = {
+	.cbcr_reg = CAMSS_VFE_CPP_AHB_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_vfe_cpp_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_vfe_cpp_ahb_clk.c),
+	},
+};
+
+static struct branch_clk camss_vfe_cpp_clk = {
+	.cbcr_reg = CAMSS_VFE_CPP_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_vfe_cpp_clk",
+		.parent = &cpp_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_vfe_cpp_clk.c),
+	},
+};
+
+static struct branch_clk camss_vfe_vfe_ahb_clk = {
+	.cbcr_reg = CAMSS_VFE_VFE_AHB_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_vfe_vfe_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_vfe_vfe_ahb_clk.c),
+	},
+};
+
+static struct branch_clk camss_vfe_vfe_axi_clk = {
+	.cbcr_reg = CAMSS_VFE_VFE_AXI_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "camss_vfe_vfe_axi_clk",
+		.parent = &axi_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(camss_vfe_vfe_axi_clk.c),
+	},
+};
+
+static struct branch_clk mdss_ahb_clk = {
+	.cbcr_reg = MDSS_AHB_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "mdss_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(mdss_ahb_clk.c),
+	},
+};
+
+static struct branch_clk mdss_axi_clk = {
+	.cbcr_reg = MDSS_AXI_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "mdss_axi_clk",
+		.parent = &axi_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(mdss_axi_clk.c),
+	},
+};
+
+static struct branch_clk mdss_byte0_clk = {
+	.cbcr_reg = MDSS_BYTE0_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "mdss_byte0_clk",
+		.parent = &byte0_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(mdss_byte0_clk.c),
+	},
+};
+
+static struct branch_clk mdss_esc0_clk = {
+	.cbcr_reg = MDSS_ESC0_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "mdss_esc0_clk",
+		.parent = &esc0_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(mdss_esc0_clk.c),
+	},
+};
+
+static struct branch_clk mdss_mdp_clk = {
+	.cbcr_reg = MDSS_MDP_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "mdss_mdp_clk",
+		.parent = &mdp_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(mdss_mdp_clk.c),
+	},
+};
+
+static struct branch_clk mdss_mdp_lut_clk = {
+	.cbcr_reg = MDSS_MDP_LUT_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "mdss_mdp_lut_clk",
+		.parent = &mdp_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(mdss_mdp_lut_clk.c),
+	},
+};
+
+static struct branch_clk mdss_pclk0_clk = {
+	.cbcr_reg = MDSS_PCLK0_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "mdss_pclk0_clk",
+		.parent = &pclk0_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(mdss_pclk0_clk.c),
+	},
+};
+
+static struct branch_clk mdss_vsync_clk = {
+	.cbcr_reg = MDSS_VSYNC_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "mdss_vsync_clk",
+		.parent = &vsync_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(mdss_vsync_clk.c),
+	},
+};
+
+static struct branch_clk mmss_misc_ahb_clk = {
+	.cbcr_reg = MMSS_MISC_AHB_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "mmss_misc_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(mmss_misc_ahb_clk.c),
+	},
+};
+
+static struct branch_clk mmss_mmssnoc_axi_clk = {
+	.cbcr_reg = MMSS_MMSSNOC_AXI_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "mmss_mmssnoc_axi_clk",
+		.parent = &axi_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(mmss_mmssnoc_axi_clk.c),
+	},
+};
+
+static struct branch_clk mmss_s0_axi_clk = {
+	.cbcr_reg = MMSS_S0_AXI_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "mmss_s0_axi_clk",
+		.parent = &axi_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(mmss_s0_axi_clk.c),
+		.depends = &mmss_mmssnoc_axi_clk.c,
+	},
+};
+
+static struct branch_clk ocmemcx_ocmemnoc_clk = {
+	.cbcr_reg = OCMEMCX_OCMEMNOC_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "ocmemcx_ocmemnoc_clk",
+		.parent = &ocmemnoc_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(ocmemcx_ocmemnoc_clk.c),
+	},
+};
+
+static struct branch_clk oxili_gfx3d_clk = {
+	.cbcr_reg = OXILI_GFX3D_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "oxili_gfx3d_clk",
+		.parent = &oxili_gfx3d_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(oxili_gfx3d_clk.c),
+	},
+};
+
+static struct branch_clk oxilicx_ahb_clk = {
+	.cbcr_reg = OXILICX_AHB_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "oxilicx_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(oxilicx_ahb_clk.c),
+	},
+};
+
+static struct branch_clk venus0_ahb_clk = {
+	.cbcr_reg = VENUS0_AHB_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "venus0_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(venus0_ahb_clk.c),
+	},
+};
+
+static struct branch_clk venus0_axi_clk = {
+	.cbcr_reg = VENUS0_AXI_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "venus0_axi_clk",
+		.parent = &axi_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(venus0_axi_clk.c),
+	},
+};
+
+static struct branch_clk venus0_ocmemnoc_clk = {
+	.cbcr_reg = VENUS0_OCMEMNOC_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "venus0_ocmemnoc_clk",
+		.parent = &ocmemnoc_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(venus0_ocmemnoc_clk.c),
+	},
+};
+
+static struct branch_clk venus0_vcodec0_clk = {
+	.cbcr_reg = VENUS0_VCODEC0_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "venus0_vcodec0_clk",
+		.parent = &vcodec0_clk_src.c,
+		.ops = &clk_ops_branch,
+		CLK_INIT(venus0_vcodec0_clk.c),
+	},
+};
+
+#ifdef CONFIG_DEBUG_FS
+enum {
+	M_ACPU0 = 0,
+	M_ACPU1,
+	M_ACPU2,
+	M_ACPU3,
+	M_L2,
+};
+
+struct measure_mux_entry {
+	struct clk *c;
+	int base;
+	u32 debug_mux;
+};
+
+static struct measure_mux_entry measure_mux[] = {
+	{&snoc.c,	GCC_BASE,  0x0000},
+	{&cnoc.c,	GCC_BASE,  0x0008},
+	{&pnoc.c,	GCC_BASE,  0x0010},
+	{&bimc.c,	GCC_BASE,  0x0155},
+	{&bimc_gpu.c,	GCC_BASE,  0x015c},
+	{&mmssnoc_ahb.c,	MMSS_BASE,  0x0001},
+
+	{&gcc_mss_cfg_ahb_clk.c,	GCC_BASE, 0x0030},
+	{&gcc_mss_q6_bimc_axi_clk.c,	GCC_BASE, 0x0031},
+	{&gcc_usb_hs_system_clk.c,	GCC_BASE, 0x0060},
+	{&gcc_usb_hs_ahb_clk.c,	GCC_BASE, 0x0061},
+	{&gcc_usb2a_phy_sleep_clk.c,	GCC_BASE, 0x0063},
+	{&gcc_sdcc1_apps_clk.c,	GCC_BASE, 0x0068},
+	{&gcc_sdcc1_ahb_clk.c,	GCC_BASE, 0x0069},
+	{&gcc_sdcc1_cdccal_sleep_clk.c,	GCC_BASE, 0x006a},
+	{&gcc_sdcc1_cdccal_ff_clk.c,	GCC_BASE, 0x006b},
+	{&gcc_sdcc2_apps_clk.c,	GCC_BASE, 0x0070},
+	{&gcc_sdcc2_ahb_clk.c,	GCC_BASE, 0x0071},
+	{&gcc_sdcc3_apps_clk.c,	GCC_BASE, 0x0078},
+	{&gcc_sdcc3_ahb_clk.c,	GCC_BASE, 0x0079},
+	{&gcc_sdcc4_apps_clk.c,	GCC_BASE, 0x0080},
+	{&gcc_sdcc4_ahb_clk.c,	GCC_BASE, 0x0081},
+	{&gcc_blsp1_ahb_clk.c,	GCC_BASE, 0x0088},
+	{&gcc_blsp1_qup1_spi_apps_clk.c,	GCC_BASE, 0x008a},
+	{&gcc_blsp1_qup1_i2c_apps_clk.c,	GCC_BASE, 0x008b},
+	{&gcc_blsp1_uart1_apps_clk.c,	GCC_BASE, 0x008c},
+	{&gcc_blsp1_qup2_spi_apps_clk.c,	GCC_BASE, 0x008e},
+	{&gcc_blsp1_qup2_i2c_apps_clk.c,	GCC_BASE, 0x0090},
+	{&gcc_blsp1_uart2_apps_clk.c,	GCC_BASE, 0x0091},
+	{&gcc_blsp1_qup3_spi_apps_clk.c,	GCC_BASE, 0x0093},
+	{&gcc_blsp1_qup3_i2c_apps_clk.c,	GCC_BASE, 0x0094},
+	{&gcc_blsp1_uart3_apps_clk.c,	GCC_BASE, 0x0095},
+	{&gcc_blsp1_qup4_spi_apps_clk.c,	GCC_BASE, 0x0098},
+	{&gcc_blsp1_qup4_i2c_apps_clk.c,	GCC_BASE, 0x0099},
+	{&gcc_blsp1_uart4_apps_clk.c,	GCC_BASE, 0x009a},
+	{&gcc_blsp2_ahb_clk.c,	GCC_BASE, 0x00a8},
+	{&gcc_blsp2_qup1_spi_apps_clk.c,	GCC_BASE, 0x00aa},
+	{&gcc_blsp2_qup1_i2c_apps_clk.c,	GCC_BASE, 0x00ab},
+	{&gcc_blsp2_uart1_apps_clk.c,	GCC_BASE, 0x00ac},
+	{&gcc_blsp2_qup2_spi_apps_clk.c,	GCC_BASE, 0x00ae},
+	{&gcc_blsp2_qup2_i2c_apps_clk.c,	GCC_BASE, 0x00b0},
+	{&gcc_blsp2_uart2_apps_clk.c,	GCC_BASE, 0x00b1},
+	{&gcc_blsp2_qup3_spi_apps_clk.c,	GCC_BASE, 0x00b3},
+	{&gcc_blsp2_qup3_i2c_apps_clk.c,	GCC_BASE, 0x00b4},
+	{&gcc_blsp2_uart3_apps_clk.c,	GCC_BASE, 0x00b5},
+	{&gcc_blsp2_qup4_spi_apps_clk.c,	GCC_BASE, 0x00b8},
+	{&gcc_blsp2_qup4_i2c_apps_clk.c,	GCC_BASE, 0x00b9},
+	{&gcc_blsp2_uart4_apps_clk.c,	GCC_BASE, 0x00ba},
+	{&gcc_pdm_ahb_clk.c,	GCC_BASE, 0x00d0},
+	{&gcc_pdm2_clk.c,	GCC_BASE, 0x00d2},
+	{&gcc_prng_ahb_clk.c,	GCC_BASE, 0x00d8},
+	{&gcc_bam_dma_ahb_clk.c,	GCC_BASE, 0x00e0},
+	{&gcc_tsif_ahb_clk.c,	GCC_BASE, 0x00e8},
+	{&gcc_tsif_ref_clk.c,	GCC_BASE, 0x00e9},
+	{&gcc_boot_rom_ahb_clk.c,	GCC_BASE, 0x00f8},
+	{&gcc_ce1_clk.c,	GCC_BASE, 0x0138},
+	{&gcc_ce1_axi_clk.c,	GCC_BASE, 0x0139},
+	{&gcc_ce1_ahb_clk.c,	GCC_BASE, 0x013a},
+	{&gcc_lpass_q6_axi_clk.c,	GCC_BASE, 0x0160},
+	{&gcc_lpass_sys_noc_mport_clk.c,	GCC_BASE, 0x0162},
+	{&gcc_lpass_sys_noc_sway_clk.c,	GCC_BASE, 0x0163},
+
+	{&mmss_misc_ahb_clk.c,	MMSS_BASE, 0x0003},
+	{&mmss_mmssnoc_axi_clk.c,	MMSS_BASE, 0x0004},
+	{&mmss_s0_axi_clk.c,	MMSS_BASE, 0x0005},
+	{&ocmemcx_ocmemnoc_clk.c,	MMSS_BASE, 0x0007},
+	{&oxilicx_ahb_clk.c,	MMSS_BASE, 0x000a},
+	{&oxili_gfx3d_clk.c,	MMSS_BASE, 0x000b},
+	{&venus0_vcodec0_clk.c,	MMSS_BASE, 0x000c},
+	{&venus0_axi_clk.c,	MMSS_BASE, 0x000d},
+	{&venus0_ocmemnoc_clk.c,	MMSS_BASE, 0x000e},
+	{&venus0_ahb_clk.c,	MMSS_BASE, 0x000f},
+	{&mdss_mdp_clk.c,	MMSS_BASE, 0x0012},
+	{&mdss_mdp_lut_clk.c,	MMSS_BASE, 0x0013},
+	{&mdss_pclk0_clk.c,	MMSS_BASE, 0x0014},
+	{&mdss_vsync_clk.c,	MMSS_BASE, 0x0015},
+	{&mdss_byte0_clk.c,	MMSS_BASE, 0x0016},
+	{&mdss_esc0_clk.c,	MMSS_BASE, 0x0017},
+	{&mdss_ahb_clk.c,	MMSS_BASE, 0x0018},
+	{&mdss_axi_clk.c,	MMSS_BASE, 0x0019},
+	{&camss_top_ahb_clk.c,	MMSS_BASE, 0x001a},
+	{&camss_micro_ahb_clk.c,	MMSS_BASE, 0x001b},
+	{&camss_gp0_clk.c,	MMSS_BASE, 0x001c},
+	{&camss_gp1_clk.c,	MMSS_BASE, 0x001d},
+	{&camss_mclk0_clk.c,	MMSS_BASE, 0x001e},
+	{&camss_mclk1_clk.c,	MMSS_BASE, 0x001f},
+	{&camss_mclk2_clk.c,	MMSS_BASE, 0x0020},
+	{&camss_cci_cci_clk.c,	MMSS_BASE, 0x0021},
+	{&camss_cci_cci_ahb_clk.c,	MMSS_BASE, 0x0022},
+	{&camss_phy0_csi0phytimer_clk.c,	MMSS_BASE, 0x0023},
+	{&camss_phy1_csi1phytimer_clk.c,	MMSS_BASE, 0x0024},
+	{&camss_jpeg_jpeg0_clk.c,	MMSS_BASE, 0x0025},
+	{&camss_jpeg_jpeg_ahb_clk.c,	MMSS_BASE, 0x0026},
+	{&camss_jpeg_jpeg_axi_clk.c,	MMSS_BASE, 0x0027},
+	{&camss_vfe_vfe0_clk.c,	MMSS_BASE, 0x0028},
+	{&camss_vfe_cpp_clk.c,	MMSS_BASE, 0x0029},
+	{&camss_vfe_cpp_ahb_clk.c,	MMSS_BASE, 0x002a},
+	{&camss_vfe_vfe_ahb_clk.c,	MMSS_BASE, 0x002b},
+	{&camss_vfe_vfe_axi_clk.c,	MMSS_BASE, 0x002c},
+	{&camss_ispif_ahb_clk.c,	MMSS_BASE, 0x002d},
+	{&camss_csi_vfe0_clk.c,	MMSS_BASE, 0x002e},
+	{&camss_csi0_clk.c,	MMSS_BASE, 0x002f},
+	{&camss_csi0_ahb_clk.c,	MMSS_BASE, 0x0030},
+	{&camss_csi0phy_clk.c,	MMSS_BASE, 0x0031},
+	{&camss_csi0rdi_clk.c,	MMSS_BASE, 0x0032},
+	{&camss_csi0pix_clk.c,	MMSS_BASE, 0x0033},
+	{&camss_csi1_clk.c,	MMSS_BASE, 0x0034},
+	{&camss_csi1_ahb_clk.c,	MMSS_BASE, 0x0035},
+	{&camss_csi1phy_clk.c,	MMSS_BASE, 0x0036},
+	{&camss_csi1rdi_clk.c,	MMSS_BASE, 0x0037},
+	{&camss_csi1pix_clk.c,	MMSS_BASE, 0x0038},
+	{&camss_csi2_clk.c,	MMSS_BASE, 0x0039},
+	{&camss_csi2_ahb_clk.c,	MMSS_BASE, 0x003a},
+	{&camss_csi2phy_clk.c,	MMSS_BASE, 0x003b},
+	{&camss_csi2rdi_clk.c,	MMSS_BASE, 0x003c},
+	{&camss_csi2pix_clk.c,	MMSS_BASE, 0x003d},
+	{&camss_csi_vfe1_clk.c,	MMSS_BASE, 0x0053},
+	{&camss_vfe_vfe1_clk.c,	MMSS_BASE, 0x0055},
+	{&camss_ahb_clk.c,	MMSS_BASE, 0x0056},
+
+	{&krait0_clk.c,		APCS_BASE, M_ACPU0},
+	{&krait1_clk.c,		APCS_BASE, M_ACPU1},
+	{&krait2_clk.c,		APCS_BASE, M_ACPU2},
+	{&krait3_clk.c,		APCS_BASE, M_ACPU3},
+	{&l2_clk.c,		APCS_BASE, M_L2},
+
+	{&dummy_clk,	N_BASES, 0x0000},
+};
+
+static int measure_clk_set_parent(struct clk *c, struct clk *parent)
+{
+	struct measure_clk *clk = to_measure_clk(c);
+	unsigned long flags;
+	u32 regval, clk_sel, i;
+
+	if (!parent)
+		return -EINVAL;
+
+	for (i = 0; i < (ARRAY_SIZE(measure_mux) - 1); i++)
+		if (measure_mux[i].c == parent)
+			break;
+
+	if (measure_mux[i].c == &dummy_clk)
+		return -EINVAL;
+
+	spin_lock_irqsave(&local_clock_reg_lock, flags);
+	/*
+	 * Program the test vector, measurement period (sample_ticks)
+	 * and scaling multiplier.
+	 */
+	clk->sample_ticks = 0x10000;
+	clk->multiplier = 1;
+
+	switch (measure_mux[i].base) {
+
+	case GCC_BASE:
+		writel_relaxed(0, GCC_REG_BASE(GCC_DEBUG_CLK_CTL));
+		clk_sel = measure_mux[i].debug_mux;
+		break;
+
+	case MMSS_BASE:
+		writel_relaxed(0, MMSS_REG_BASE(MMSS_DEBUG_CLK_CTL));
+		clk_sel = 0x02C;
+		regval = BVAL(11, 0, measure_mux[i].debug_mux);
+		writel_relaxed(regval, MMSS_REG_BASE(MMSS_DEBUG_CLK_CTL));
+
+		/* Activate debug clock output */
+		regval |= BIT(16);
+		writel_relaxed(regval, MMSS_REG_BASE(MMSS_DEBUG_CLK_CTL));
+		break;
+
+	case LPASS_BASE:
+		writel_relaxed(0, LPASS_REG_BASE(LPASS_DBG_CLK));
+		clk_sel = 0x161;
+		regval = BVAL(11, 0, measure_mux[i].debug_mux);
+		writel_relaxed(regval, LPASS_REG_BASE(LPASS_DBG_CLK));
+
+		/* Activate debug clock output */
+		regval |= BIT(20);
+		writel_relaxed(regval, LPASS_REG_BASE(LPASS_DBG_CLK));
+		break;
+
+	case APCS_BASE:
+		clk->multiplier = 4;
+		clk_sel = 0x16A;
+
+		if (measure_mux[i].debug_mux == M_L2)
+			regval = BIT(12);
+		else
+			regval = measure_mux[i].debug_mux << 8;
+		writel_relaxed(BIT(0), APCS_REG_BASE(L2_CBCR));
+		writel_relaxed(regval, APCS_REG_BASE(GLB_CLK_DIAG));
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	/* Set debug mux clock index */
+	regval = BVAL(8, 0, clk_sel);
+	writel_relaxed(regval, GCC_REG_BASE(GCC_DEBUG_CLK_CTL));
+
+	/* Activate debug clock output */
+	regval |= BIT(16);
+	writel_relaxed(regval, GCC_REG_BASE(GCC_DEBUG_CLK_CTL));
+
+	/* Make sure test vector is set before starting measurements. */
+	mb();
+	spin_unlock_irqrestore(&local_clock_reg_lock, flags);
+
+	return 0;
+}
+
+/* Sample clock for 'ticks' reference clock ticks. */
+static u32 run_measurement(unsigned ticks)
+{
+	/* Stop counters and set the XO4 counter start value. */
+	writel_relaxed(ticks, GCC_REG_BASE(CLOCK_FRQ_MEASURE_CTL));
+
+	/* Wait for timer to become ready. */
+	while ((readl_relaxed(GCC_REG_BASE(CLOCK_FRQ_MEASURE_STATUS)) &
+			BIT(25)) != 0)
+		cpu_relax();
+
+	/* Run measurement and wait for completion. */
+	writel_relaxed(BIT(20)|ticks, GCC_REG_BASE(CLOCK_FRQ_MEASURE_CTL));
+	while ((readl_relaxed(GCC_REG_BASE(CLOCK_FRQ_MEASURE_STATUS)) &
+			BIT(25)) == 0)
+		cpu_relax();
+
+	/* Return measured ticks. */
+	return readl_relaxed(GCC_REG_BASE(CLOCK_FRQ_MEASURE_STATUS)) &
+				BM(24, 0);
+}
+
+/*
+ * Perform a hardware rate measurement for a given clock.
+ * FOR DEBUG USE ONLY: Measurements take ~15 ms!
+ */
+static unsigned long measure_clk_get_rate(struct clk *c)
+{
+	unsigned long flags;
+	u32 gcc_xo4_reg_backup;
+	u64 raw_count_short, raw_count_full;
+	struct measure_clk *clk = to_measure_clk(c);
+	unsigned ret;
+
+	ret = clk_prepare_enable(&xo.c);
+	if (ret) {
+		pr_warn("CXO clock failed to enable. Can't measure\n");
+		return 0;
+	}
+
+	spin_lock_irqsave(&local_clock_reg_lock, flags);
+
+	/* Enable CXO/4 and RINGOSC branch. */
+	gcc_xo4_reg_backup = readl_relaxed(GCC_REG_BASE(GCC_XO_DIV4_CBCR));
+	writel_relaxed(0x1, GCC_REG_BASE(GCC_XO_DIV4_CBCR));
+
+	/*
+	 * The ring oscillator counter will not reset if the measured clock
+	 * is not running.  To detect this, run a short measurement before
+	 * the full measurement.  If the raw results of the two are the same
+	 * then the clock must be off.
+	 */
+
+	/* Run a short measurement. (~1 ms) */
+	raw_count_short = run_measurement(0x1000);
+	/* Run a full measurement. (~14 ms) */
+	raw_count_full = run_measurement(clk->sample_ticks);
+
+	writel_relaxed(gcc_xo4_reg_backup, GCC_REG_BASE(GCC_XO_DIV4_CBCR));
+
+	/* Return 0 if the clock is off. */
+	if (raw_count_full == raw_count_short) {
+		ret = 0;
+	} else {
+		/* Compute rate in Hz. */
+		raw_count_full = ((raw_count_full * 10) + 15) * 4800000;
+		do_div(raw_count_full, ((clk->sample_ticks * 10) + 35));
+		ret = (raw_count_full * clk->multiplier);
+	}
+
+	writel_relaxed(0x51A00, GCC_REG_BASE(PLLTEST_PAD_CFG));
+	spin_unlock_irqrestore(&local_clock_reg_lock, flags);
+
+	clk_disable_unprepare(&xo.c);
+
+	return ret;
+}
+#else /* !CONFIG_DEBUG_FS */
+static int measure_clk_set_parent(struct clk *clk, struct clk *parent)
+{
+	return -EINVAL;
+}
+
+static unsigned long measure_clk_get_rate(struct clk *clk)
+{
+	return 0;
+}
+#endif /* CONFIG_DEBUG_FS */
+
+static struct clk_ops clk_ops_measure = {
+	.set_parent = measure_clk_set_parent,
+	.get_rate = measure_clk_get_rate,
+};
+
+static struct measure_clk measure_clk = {
+	.c = {
+		.dbg_name = "measure_clk",
+		.ops = &clk_ops_measure,
+		CLK_INIT(measure_clk.c),
+	},
+	.multiplier = 1,
+};
+
+static struct clk_lookup msm_clocks_samarium_rumi[] = {
+	CLK_DUMMY("xo",          cxo_pil_lpass_clk, "fe200000.qcom,lpass", OFF),
+	CLK_DUMMY("core_clk",          q6ss_xo_clk, "fe200000.qcom,lpass", OFF),
+	CLK_DUMMY("bus_clk",  gcc_lpass_q6_axi_clk, "fe200000.qcom,lpass", OFF),
+	CLK_DUMMY("iface_clk", q6ss_ahb_lfabif_clk, "fe200000.qcom,lpass", OFF),
+	CLK_DUMMY("reg_clk",         q6ss_ahbm_clk, "fe200000.qcom,lpass", OFF),
+
+	CLK_DUMMY("core_clk",  venus_vcodec0_clk,  "fdce0000.qcom,venus", OFF),
+	CLK_DUMMY("iface_clk", venus_ahb_clk,      "fdce0000.qcom,venus", OFF),
+	CLK_DUMMY("bus_clk",   venus_axi_clk,      "fdce0000.qcom,venus", OFF),
+	CLK_DUMMY("mem_clk",   venus_ocmemnoc_clk, "fdce0000.qcom,venus", OFF),
+	CLK_DUMMY("core_clk",  venus_vcodec0_clk,  "fd8c1024.qcom,gdsc",  OFF),
+
+	CLK_DUMMY("xo",                CXO_CLK, "fc880000.qcom,mss", OFF),
+	CLK_DUMMY("bus_clk",   MSS_BIMC_Q6_CLK, "fc880000.qcom,mss", OFF),
+	CLK_DUMMY("iface_clk", MSS_CFG_AHB_CLK, "fc880000.qcom,mss", OFF),
+	CLK_DUMMY("mem_clk",  BOOT_ROM_AHB_CLK, "fc880000.qcom,mss", OFF),
+	CLK_DUMMY("xo",		XO_CLK,		"fb21b000.qcom,pronto", OFF),
+	CLK_DUMMY("core_clk",   BLSP1_UART_CLK, "f991f000.serial", OFF),
+	CLK_DUMMY("iface_clk",  BLSP1_UART_CLK, "f991f000.serial", OFF),
+	CLK_DUMMY("core_clk",   BLSP1_UART_CLK, "f991e000.serial", OFF),
+	CLK_DUMMY("iface_clk",  BLSP1_UART_CLK, "f991e000.serial", OFF),
+	CLK_DUMMY("core_clk",	SDC1_CLK,	"msm_sdcc.1", OFF),
+	CLK_DUMMY("iface_clk",	SDC1_P_CLK,	"msm_sdcc.1", OFF),
+	CLK_DUMMY("core_clk",	SDC2_CLK,	"msm_sdcc.2", OFF),
+	CLK_DUMMY("iface_clk",	SDC2_P_CLK,	"msm_sdcc.2", OFF),
+	CLK_DUMMY("core_clk",	USB_HS_SYSTEM_CLK, "msm_otg", OFF),
+	CLK_DUMMY("iface_clk",	USB_HS_AHB_CLK,    "msm_otg", OFF),
+	CLK_DUMMY("xo",         CXO_OTG_CLK,       "msm_otg", OFF),
+	CLK_DUMMY("dfab_clk",	DFAB_CLK,	"msm_sps", OFF),
+	CLK_DUMMY("dma_bam_pclk",	DMA_BAM_P_CLK,	"msm_sps", OFF),
+	CLK_DUMMY("core_clk",   SPI_CLK,        "spi_qsd.1",  OFF),
+	CLK_DUMMY("iface_clk",  SPI_P_CLK,      "spi_qsd.1",  OFF),
+	CLK_DUMMY("core_clk", gcc_prng_ahb_clk.c, "f9bff000.qcom,msm-rng", OFF),
+	CLK_DUMMY("core_clk",	I2C_CLK,	"f9924000.i2c", OFF),
+	CLK_DUMMY("iface_clk",	I2C_P_CLK,	"f9924000.i2c", OFF),
+
+	/* CoreSight clocks */
+	CLK_DUMMY("core_clk", qdss_clk.c, "fc326000.tmc", OFF),
+	CLK_DUMMY("core_clk", qdss_clk.c, "fc320000.tpiu", OFF),
+	CLK_DUMMY("core_clk", qdss_clk.c, "fc324000.replicator", OFF),
+	CLK_DUMMY("core_clk", qdss_clk.c, "fc325000.tmc", OFF),
+	CLK_DUMMY("core_clk", qdss_clk.c, "fc323000.funnel", OFF),
+	CLK_DUMMY("core_clk", qdss_clk.c, "fc321000.funnel", OFF),
+	CLK_DUMMY("core_clk", qdss_clk.c, "fc322000.funnel", OFF),
+	CLK_DUMMY("core_clk", qdss_clk.c, "fc355000.funnel", OFF),
+	CLK_DUMMY("core_clk", qdss_clk.c, "fc36c000.funnel", OFF),
+	CLK_DUMMY("core_clk", qdss_clk.c, "fc302000.stm", OFF),
+	CLK_DUMMY("core_clk", qdss_clk.c, "fc34c000.etm", OFF),
+	CLK_DUMMY("core_clk", qdss_clk.c, "fc34d000.etm", OFF),
+	CLK_DUMMY("core_clk", qdss_clk.c, "fc34e000.etm", OFF),
+	CLK_DUMMY("core_clk", qdss_clk.c, "fc34f000.etm", OFF),
+	CLK_DUMMY("core_clk", qdss_clk.c, "fc310000.cti", OFF),
+	CLK_DUMMY("core_clk", qdss_clk.c, "fc311000.cti", OFF),
+	CLK_DUMMY("core_clk", qdss_clk.c, "fc312000.cti", OFF),
+	CLK_DUMMY("core_clk", qdss_clk.c, "fc313000.cti", OFF),
+	CLK_DUMMY("core_clk", qdss_clk.c, "fc314000.cti", OFF),
+	CLK_DUMMY("core_clk", qdss_clk.c, "fc315000.cti", OFF),
+	CLK_DUMMY("core_clk", qdss_clk.c, "fc316000.cti", OFF),
+	CLK_DUMMY("core_clk", qdss_clk.c, "fc317000.cti", OFF),
+	CLK_DUMMY("core_clk", qdss_clk.c, "fc318000.cti", OFF),
+	CLK_DUMMY("core_clk", qdss_clk.c, "fc351000.cti", OFF),
+	CLK_DUMMY("core_clk", qdss_clk.c, "fc352000.cti", OFF),
+	CLK_DUMMY("core_clk", qdss_clk.c, "fc353000.cti", OFF),
+	CLK_DUMMY("core_clk", qdss_clk.c, "fc354000.cti", OFF),
+	CLK_DUMMY("core_clk", qdss_clk.c, "fc350000.cti", OFF),
+	CLK_DUMMY("core_clk", qdss_clk.c, "fc330000.cti", OFF),
+	CLK_DUMMY("core_clk", qdss_clk.c, "fc33c000.cti", OFF),
+	CLK_DUMMY("core_clk", qdss_clk.c, "fc360000.cti", OFF),
+	CLK_DUMMY("core_clk", qdss_clk.c, "fc330000.cti", OFF),
+	CLK_DUMMY("core_clk", qdss_clk.c, "fc33c000.cti", OFF),
+	CLK_DUMMY("core_clk", qdss_clk.c, "fc360000.cti", OFF),
+	CLK_DUMMY("core_clk", qdss_clk.c, "fd828018.hwevent", OFF),
+
+	CLK_DUMMY("core_a_clk", qdss_a_clk.c, "fc326000.tmc", OFF),
+	CLK_DUMMY("core_a_clk", qdss_a_clk.c, "fc320000.tpiu", OFF),
+	CLK_DUMMY("core_a_clk", qdss_a_clk.c, "fc324000.replicator", OFF),
+	CLK_DUMMY("core_a_clk", qdss_a_clk.c, "fc325000.tmc", OFF),
+	CLK_DUMMY("core_a_clk", qdss_a_clk.c, "fc323000.funnel", OFF),
+	CLK_DUMMY("core_a_clk", qdss_a_clk.c, "fc321000.funnel", OFF),
+	CLK_DUMMY("core_a_clk", qdss_a_clk.c, "fc322000.funnel", OFF),
+	CLK_DUMMY("core_a_clk", qdss_a_clk.c, "fc355000.funnel", OFF),
+	CLK_DUMMY("core_a_clk", qdss_a_clk.c, "fc36c000.funnel", OFF),
+	CLK_DUMMY("core_a_clk", qdss_a_clk.c, "fc302000.stm", OFF),
+	CLK_DUMMY("core_a_clk", qdss_a_clk.c, "fc34c000.etm", OFF),
+	CLK_DUMMY("core_a_clk", qdss_a_clk.c, "fc34d000.etm", OFF),
+	CLK_DUMMY("core_a_clk", qdss_a_clk.c, "fc34e000.etm", OFF),
+	CLK_DUMMY("core_a_clk", qdss_a_clk.c, "fc34f000.etm", OFF),
+	CLK_DUMMY("core_a_clk", qdss_a_clk.c, "fc310000.cti", OFF),
+	CLK_DUMMY("core_a_clk", qdss_a_clk.c, "fc311000.cti", OFF),
+	CLK_DUMMY("core_a_clk", qdss_a_clk.c, "fc312000.cti", OFF),
+	CLK_DUMMY("core_a_clk", qdss_a_clk.c, "fc313000.cti", OFF),
+	CLK_DUMMY("core_a_clk", qdss_a_clk.c, "fc314000.cti", OFF),
+	CLK_DUMMY("core_a_clk", qdss_a_clk.c, "fc315000.cti", OFF),
+	CLK_DUMMY("core_a_clk", qdss_a_clk.c, "fc316000.cti", OFF),
+	CLK_DUMMY("core_a_clk", qdss_a_clk.c, "fc317000.cti", OFF),
+	CLK_DUMMY("core_a_clk", qdss_a_clk.c, "fc318000.cti", OFF),
+	CLK_DUMMY("core_a_clk", qdss_a_clk.c, "fc351000.cti", OFF),
+	CLK_DUMMY("core_a_clk", qdss_a_clk.c, "fc352000.cti", OFF),
+	CLK_DUMMY("core_a_clk", qdss_a_clk.c, "fc353000.cti", OFF),
+	CLK_DUMMY("core_a_clk", qdss_a_clk.c, "fc354000.cti", OFF),
+	CLK_DUMMY("core_a_clk", qdss_a_clk.c, "fc350000.cti", OFF),
+	CLK_DUMMY("core_a_clk", qdss_a_clk.c, "fc330000.cti", OFF),
+	CLK_DUMMY("core_a_clk", qdss_a_clk.c, "fc33c000.cti", OFF),
+	CLK_DUMMY("core_a_clk", qdss_a_clk.c, "fc360000.cti", OFF),
+	CLK_DUMMY("core_a_clk", qdss_a_clk.c, "fc330000.cti", OFF),
+	CLK_DUMMY("core_a_clk", qdss_a_clk.c, "fc33c000.cti", OFF),
+	CLK_DUMMY("core_a_clk", qdss_a_clk.c, "fc360000.cti", OFF),
+	CLK_DUMMY("core_a_clk", qdss_a_clk.c, "fd828018.hwevent", OFF),
+
+	CLK_DUMMY("core_mmss_clk", mmss_misc_ahb_clk.c, "fd828018.hwevent",
+		  OFF),
+	CLK_DUMMY("core_clk", gcc_ce1_clk.c, "qseecom", OFF),
+	CLK_DUMMY("iface_clk", gcc_ce1_ahb_clk.c, "qseecom", OFF),
+	CLK_DUMMY("bus_clk",  gcc_ce1_axi_clk.c, "qseecom", OFF),
+	CLK_DUMMY("core_clk_src", qseecom_ce1_clk_src.c, "qseecom", OFF),
+};
+
+static struct clk_lookup msm_clocks_samarium[] = {
+	/* XO and PLL */
+	CLK_LOOKUP("", xo.c, ""),
+	CLK_LOOKUP("hfpll_src", xo_a_clk.c, "f9016000.qcom,clock-krait"),
+	CLK_LOOKUP("", gpll0.c, ""),
+	CLK_LOOKUP("aux_clk", gpll0_ao.c, "f9016000.qcom,clock-krait"),
+	CLK_LOOKUP("", gpll4.c, ""),
+	CLK_LOOKUP("", mmpll0.c, ""),
+	CLK_LOOKUP("", mmpll1.c, ""),
+	CLK_LOOKUP("", mmpll3.c, ""),
+	CLK_LOOKUP("", mmpll4.c, ""),
+
+	/* measure */
+	CLK_LOOKUP("measure", measure_clk.c, "debug"),
+
+	/* RPM and voter */
+	CLK_LOOKUP("xo", xo_otg_clk.c, "msm_otg"),
+	CLK_LOOKUP("xo", xo_pil_lpass_clk.c, "fe200000.qcom,lpass"),
+	CLK_LOOKUP("xo", xo_pil_mss_clk.c, "fc880000.qcom,mss"),
+	CLK_LOOKUP("xo", xo_wlan_clk.c, "fb000000.qcom,wcnss-wlan"),
+	CLK_LOOKUP("rf_clk", rf_clk3.c, "fb000000.qcom,wcnss-wlan"),
+	CLK_LOOKUP("xo", xo_pil_pronto_clk.c, "fb21b000.qcom,pronto"),
+	CLK_LOOKUP("xo", xo_ehci_host_clk.c, "msm_ehci_host"),
+	CLK_LOOKUP("xo", xo_lpm_clk.c, "fc4281d0.qcom,mpm"),
+
+	CLK_LOOKUP("", bb_clk1.c, ""),
+	CLK_LOOKUP("", bb_clk1_a.c, ""),
+	CLK_LOOKUP("", bb_clk2.c, ""),
+	CLK_LOOKUP("", bb_clk2_a.c, ""),
+	CLK_LOOKUP("", rf_clk1.c, ""),
+	CLK_LOOKUP("", rf_clk1_a.c, ""),
+	CLK_LOOKUP("", rf_clk2.c, ""),
+	CLK_LOOKUP("", rf_clk2_a.c, ""),
+	CLK_LOOKUP("", rf_clk3_a.c, ""),
+	CLK_LOOKUP("", div_clk1.c, ""),
+	CLK_LOOKUP("", div_clk1_a.c, ""),
+	CLK_LOOKUP("", div_clk2.c, ""),
+	CLK_LOOKUP("", div_clk2_a.c, ""),
+	CLK_LOOKUP("", div_clk3.c, ""),
+	CLK_LOOKUP("", div_clk3_a.c, ""),
+	CLK_LOOKUP("", diff_clk1.c, ""),
+	CLK_LOOKUP("", diff_clk1_a.c, ""),
+	CLK_LOOKUP("", bb_clk1_pin.c, ""),
+	CLK_LOOKUP("", bb_clk1_a_pin.c, ""),
+	CLK_LOOKUP("", bb_clk2_pin.c, ""),
+	CLK_LOOKUP("ref_clk", bb_clk2_a_pin.c, "3-000e"),
+	CLK_LOOKUP("", rf_clk1_pin.c, ""),
+	CLK_LOOKUP("", rf_clk1_a_pin.c, ""),
+	CLK_LOOKUP("", rf_clk2_pin.c, ""),
+	CLK_LOOKUP("", rf_clk2_a_pin.c, ""),
+	CLK_LOOKUP("", rf_clk3_pin.c, ""),
+	CLK_LOOKUP("", rf_clk3_a_pin.c, ""),
+	CLK_LOOKUP("", cnoc.c, ""),
+	CLK_LOOKUP("", cnoc_a_clk.c, ""),
+	CLK_LOOKUP("", pnoc.c, ""),
+	CLK_LOOKUP("", pnoc_a_clk.c, ""),
+	CLK_LOOKUP("dfab_clk", pnoc_sps_clk.c, "msm_sps"),
+	CLK_LOOKUP("", snoc.c, ""),
+	CLK_LOOKUP("", snoc_a_clk.c, ""),
+	CLK_LOOKUP("", bimc.c, ""),
+	CLK_LOOKUP("", bimc_a_clk.c, ""),
+	CLK_LOOKUP("", bimc_gpu.c, ""),
+	CLK_LOOKUP("", pnoc_keepalive_a_clk.c, ""),
+	CLK_LOOKUP("", mmssnoc_ahb.c, ""),
+	CLK_LOOKUP("", mmssnoc_ahb_a_clk.c, ""),
+
+	/* Bus driver */
+	CLK_LOOKUP("bus_clk", cnoc_msmbus_clk.c, "msm_config_noc"),
+	CLK_LOOKUP("bus_a_clk", cnoc_msmbus_a_clk.c, "msm_config_noc"),
+	CLK_LOOKUP("bus_clk", snoc_msmbus_clk.c, "msm_sys_noc"),
+	CLK_LOOKUP("bus_a_clk", snoc_msmbus_a_clk.c, "msm_sys_noc"),
+	CLK_LOOKUP("bus_clk", pnoc_msmbus_clk.c, "msm_periph_noc"),
+	CLK_LOOKUP("bus_a_clk", pnoc_msmbus_a_clk.c, "msm_periph_noc"),
+	CLK_LOOKUP("mem_clk", bimc_msmbus_clk.c, "msm_bimc"),
+	CLK_LOOKUP("mem_a_clk", bimc_msmbus_a_clk.c, "msm_bimc"),
+	CLK_LOOKUP("ocmem_clk", ocmemgx_msmbus_clk.c, "msm_bus"),
+	CLK_LOOKUP("ocmem_a_clk", ocmemgx_msmbus_a_clk.c, "msm_bus"),
+	CLK_LOOKUP("bus_clk", mmss_s0_axi_clk.c, "msm_mmss_noc"),
+	CLK_LOOKUP("bus_a_clk", mmss_s0_axi_clk.c, "msm_mmss_noc"),
+
+	/* CoreSight clocks */
+	CLK_LOOKUP("core_clk", qdss.c, "fc326000.tmc"),
+	CLK_LOOKUP("core_clk", qdss.c, "fc320000.tpiu"),
+	CLK_LOOKUP("core_clk", qdss.c, "fc324000.replicator"),
+	CLK_LOOKUP("core_clk", qdss.c, "fc325000.tmc"),
+	CLK_LOOKUP("core_clk", qdss.c, "fc323000.funnel"),
+	CLK_LOOKUP("core_clk", qdss.c, "fc321000.funnel"),
+	CLK_LOOKUP("core_clk", qdss.c, "fc322000.funnel"),
+	CLK_LOOKUP("core_clk", qdss.c, "fc355000.funnel"),
+	CLK_LOOKUP("core_clk", qdss.c, "fc36c000.funnel"),
+	CLK_LOOKUP("core_clk", qdss.c, "fc302000.stm"),
+	CLK_LOOKUP("core_clk", qdss.c, "fc34c000.etm"),
+	CLK_LOOKUP("core_clk", qdss.c, "fc34d000.etm"),
+	CLK_LOOKUP("core_clk", qdss.c, "fc34e000.etm"),
+	CLK_LOOKUP("core_clk", qdss.c, "fc34f000.etm"),
+	CLK_LOOKUP("core_clk", qdss.c, "fc310000.cti"),
+	CLK_LOOKUP("core_clk", qdss.c, "fc311000.cti"),
+	CLK_LOOKUP("core_clk", qdss.c, "fc312000.cti"),
+	CLK_LOOKUP("core_clk", qdss.c, "fc313000.cti"),
+	CLK_LOOKUP("core_clk", qdss.c, "fc314000.cti"),
+	CLK_LOOKUP("core_clk", qdss.c, "fc315000.cti"),
+	CLK_LOOKUP("core_clk", qdss.c, "fc316000.cti"),
+	CLK_LOOKUP("core_clk", qdss.c, "fc317000.cti"),
+	CLK_LOOKUP("core_clk", qdss.c, "fc318000.cti"),
+	CLK_LOOKUP("core_clk", qdss.c, "fc351000.cti"),
+	CLK_LOOKUP("core_clk", qdss.c, "fc352000.cti"),
+	CLK_LOOKUP("core_clk", qdss.c, "fc353000.cti"),
+	CLK_LOOKUP("core_clk", qdss.c, "fc354000.cti"),
+	CLK_LOOKUP("core_clk", qdss.c, "fc350000.cti"),
+	CLK_LOOKUP("core_clk", qdss.c, "fc330000.cti"),
+	CLK_LOOKUP("core_clk", qdss.c, "fc33c000.cti"),
+	CLK_LOOKUP("core_clk", qdss.c, "fc360000.cti"),
+	CLK_LOOKUP("core_clk", qdss.c, "fd828018.hwevent"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc326000.tmc"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc320000.tpiu"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc324000.replicator"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc325000.tmc"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc323000.funnel"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc321000.funnel"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc322000.funnel"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc355000.funnel"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc36c000.funnel"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc302000.stm"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc34c000.etm"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc34d000.etm"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc34e000.etm"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc34f000.etm"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc310000.cti"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc311000.cti"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc312000.cti"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc313000.cti"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc314000.cti"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc315000.cti"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc316000.cti"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc317000.cti"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc318000.cti"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc351000.cti"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc352000.cti"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc353000.cti"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc354000.cti"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc350000.cti"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc330000.cti"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc33c000.cti"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc360000.cti"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fd828018.hwevent"),
+
+	CLK_LOOKUP("osr_clk", div_clk1.c, "msm-dai-q6-dev.16384"),
+
+	/* BLSP */
+	CLK_LOOKUP("iface_clk", gcc_blsp1_ahb_clk.c, "f991f000.serial"),
+	CLK_LOOKUP("iface_clk", gcc_blsp1_ahb_clk.c, "f9924000.i2c"),
+	CLK_LOOKUP("iface_clk", gcc_blsp1_ahb_clk.c, "f991e000.serial"),
+	CLK_LOOKUP("iface_clk", gcc_blsp1_ahb_clk.c, "f9923000.i2c"),
+	CLK_LOOKUP("core_clk", gcc_blsp1_qup1_i2c_apps_clk.c, "f9923000.i2c"),
+	CLK_LOOKUP("iface_clk", gcc_blsp2_ahb_clk.c, "f9963000.i2c"),
+	CLK_LOOKUP("core_clk", gcc_blsp2_qup1_i2c_apps_clk.c, "f9963000.i2c"),
+	CLK_LOOKUP("iface_clk", gcc_blsp2_ahb_clk.c, "f9964000.i2c"),
+	CLK_LOOKUP("core_clk", gcc_blsp2_qup2_i2c_apps_clk.c, "f9964000.i2c"),
+	CLK_LOOKUP("", gcc_blsp1_qup1_spi_apps_clk.c, ""),
+	CLK_LOOKUP("core_clk", gcc_blsp1_qup2_i2c_apps_clk.c, "f9924000.i2c"),
+	CLK_LOOKUP("", gcc_blsp1_qup2_spi_apps_clk.c, ""),
+	CLK_LOOKUP("", gcc_blsp1_qup3_i2c_apps_clk.c, ""),
+	CLK_LOOKUP("", gcc_blsp1_qup3_spi_apps_clk.c, ""),
+	CLK_LOOKUP("", gcc_blsp1_qup4_i2c_apps_clk.c, ""),
+	CLK_LOOKUP("", gcc_blsp1_qup4_spi_apps_clk.c, ""),
+	CLK_LOOKUP("", gcc_blsp1_uart1_apps_clk.c, ""),
+	CLK_LOOKUP("core_clk", gcc_blsp1_uart2_apps_clk.c, "f991e000.serial"),
+	CLK_LOOKUP("core_clk", gcc_blsp1_uart3_apps_clk.c, "f991f000.serial"),
+	CLK_LOOKUP("", gcc_blsp1_uart4_apps_clk.c, ""),
+	CLK_LOOKUP("", gcc_blsp2_ahb_clk.c, ""),
+	CLK_LOOKUP("", gcc_blsp2_qup1_i2c_apps_clk.c, ""),
+	CLK_LOOKUP("", gcc_blsp2_qup1_spi_apps_clk.c, ""),
+	CLK_LOOKUP("", gcc_blsp2_qup2_i2c_apps_clk.c, ""),
+	CLK_LOOKUP("", gcc_blsp2_qup2_spi_apps_clk.c, ""),
+	CLK_LOOKUP("", gcc_blsp2_qup3_i2c_apps_clk.c, ""),
+	CLK_LOOKUP("", gcc_blsp2_qup3_spi_apps_clk.c, ""),
+	CLK_LOOKUP("", gcc_blsp2_qup4_i2c_apps_clk.c, ""),
+	CLK_LOOKUP("", gcc_blsp2_qup4_spi_apps_clk.c, ""),
+	CLK_LOOKUP("", gcc_blsp2_uart1_apps_clk.c, ""),
+	CLK_LOOKUP("", gcc_blsp2_uart2_apps_clk.c, ""),
+	CLK_LOOKUP("", gcc_blsp2_uart3_apps_clk.c, ""),
+	CLK_LOOKUP("", gcc_blsp2_uart4_apps_clk.c, ""),
+
+	/* SDCC */
+	CLK_LOOKUP("iface_clk", gcc_sdcc1_ahb_clk.c, "msm_sdcc.1"),
+	CLK_LOOKUP("core_clk", gcc_sdcc1_apps_clk.c, "msm_sdcc.1"),
+	CLK_LOOKUP("cal_clk", gcc_sdcc1_cdccal_ff_clk.c, "msm_sdcc.1"),
+	CLK_LOOKUP("sleep_clk", gcc_sdcc1_cdccal_sleep_clk.c, "msm_sdcc.1"),
+	CLK_LOOKUP("iface_clk", gcc_sdcc2_ahb_clk.c, "msm_sdcc.2"),
+	CLK_LOOKUP("core_clk", gcc_sdcc2_apps_clk.c, "msm_sdcc.2"),
+	CLK_LOOKUP("iface_clk", gcc_sdcc3_ahb_clk.c, "msm_sdcc.3"),
+	CLK_LOOKUP("core_clk", gcc_sdcc3_apps_clk.c, "msm_sdcc.3"),
+	CLK_LOOKUP("iface_clk", gcc_sdcc4_ahb_clk.c, "msm_sdcc.4"),
+	CLK_LOOKUP("core_clk", gcc_sdcc4_apps_clk.c, "msm_sdcc.4"),
+
+	/* SCM PAS */
+	CLK_LOOKUP("core_clk",     gcc_ce1_clk.c,         "scm"),
+	CLK_LOOKUP("iface_clk",    gcc_ce1_ahb_clk.c,     "scm"),
+	CLK_LOOKUP("bus_clk",      gcc_ce1_axi_clk.c,     "scm"),
+	CLK_LOOKUP("core_clk_src", scm_ce1_clk_src.c,     "scm"),
+
+	/* Misc GCC branch */
+	CLK_LOOKUP("", ce1_clk_src.c, ""),
+	CLK_LOOKUP("dma_bam_pclk", gcc_bam_dma_ahb_clk.c, "msm_sps"),
+	CLK_LOOKUP("mem_clk", gcc_boot_rom_ahb_clk.c, "fc880000.qcom,mss"),
+	CLK_LOOKUP("", gcc_ce1_ahb_clk.c, ""),
+	CLK_LOOKUP("", gcc_ce1_axi_clk.c, ""),
+	CLK_LOOKUP("", gcc_ce1_clk.c, ""),
+	CLK_LOOKUP("bus_clk", gcc_lpass_q6_axi_clk.c, "fe200000.qcom,lpass"),
+	CLK_LOOKUP("mport_clk", gcc_lpass_sys_noc_mport_clk.c,
+					   "fe200000.qcom,lpass"),
+	CLK_LOOKUP("sway_clk", gcc_lpass_sys_noc_sway_clk.c,
+					   "fe200000.qcom,lpass"),
+	CLK_LOOKUP("core_clk", dummy_clk, "fe200000.qcom,lpass"),
+	CLK_LOOKUP("iface_clk", dummy_clk, "fe200000.qcom,lpass"),
+	CLK_LOOKUP("reg_clk", dummy_clk, "fe200000.qcom,lpass"),
+	CLK_LOOKUP("iface_clk", gcc_mss_cfg_ahb_clk.c, "fc880000.qcom,mss"),
+	CLK_LOOKUP("bus_clk", gcc_mss_q6_bimc_axi_clk.c, "fc880000.qcom,mss"),
+	CLK_LOOKUP("", gcc_pdm2_clk.c, ""),
+	CLK_LOOKUP("", gcc_pdm_ahb_clk.c, ""),
+	CLK_LOOKUP("core_clk", gcc_prng_ahb_clk.c, "f9bff000.qcom,msm-rng"),
+	CLK_LOOKUP("", gcc_tsif_ref_clk.c, ""),
+	CLK_LOOKUP("", gcc_tsif_ahb_clk.c, ""),
+	CLK_LOOKUP("", gcc_usb2a_phy_sleep_clk.c, ""),
+	CLK_LOOKUP("iface_clk", gcc_usb_hs_ahb_clk.c, "msm_otg"),
+	CLK_LOOKUP("core_clk", gcc_usb_hs_system_clk.c, "msm_otg"),
+
+	/* MM sensor clocks */
+	CLK_LOOKUP("cam_src_clk", mclk0_clk_src.c, "6e.qcom,camera"),
+	CLK_LOOKUP("cam_src_clk", mclk0_clk_src.c, "20.qcom,camera"),
+	CLK_LOOKUP("cam_src_clk", mclk0_clk_src.c, "0.qcom,camera"),
+	CLK_LOOKUP("cam_src_clk", mclk1_clk_src.c, "90.qcom,camera"),
+	CLK_LOOKUP("cam_src_clk", mclk1_clk_src.c, "6d.qcom,camera"),
+	CLK_LOOKUP("cam_src_clk", mclk1_clk_src.c, "1.qcom,camera"),
+	CLK_LOOKUP("cam_src_clk", mclk2_clk_src.c, "6c.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_mclk0_clk.c, "0.qcom,camera"),
+	CLK_LOOKUP("cam_clk", camss_mclk1_clk.c, "90.qcom,camera"),
+	CLK_LOOKUP("cam_clk", camss_mclk1_clk.c, "6d.qcom,camera"),
+	CLK_LOOKUP("cam_clk", camss_mclk1_clk.c, "1.qcom,camera"),
+	CLK_LOOKUP("cam_clk", camss_mclk2_clk.c, "6c.qcom,camera"),
+
+	/* CCI clocks */
+	CLK_LOOKUP("camss_top_ahb_clk", camss_top_ahb_clk.c,
+						"fda0c000.qcom,cci"),
+	CLK_LOOKUP("cci_ahb_clk", camss_cci_cci_ahb_clk.c, "fda0c000.qcom,cci"),
+	CLK_LOOKUP("cci_src_clk", cci_clk_src.c, "fda0c000.qcom,cci"),
+	CLK_LOOKUP("cci_clk", camss_cci_cci_clk.c, "fda0c000.qcom,cci"),
+
+	/* CSIPHY clocks */
+	CLK_LOOKUP("camss_top_ahb_clk", camss_top_ahb_clk.c,
+						"fda0ac00.qcom,csiphy"),
+	CLK_LOOKUP("ispif_ahb_clk", camss_ispif_ahb_clk.c,
+						"fda0ac00.qcom,csiphy"),
+	CLK_LOOKUP("csiphy_timer_src_clk", csi0phytimer_clk_src.c,
+						"fda0ac00.qcom,csiphy"),
+	CLK_LOOKUP("csiphy_timer_clk", camss_phy0_csi0phytimer_clk.c,
+						"fda0ac00.qcom,csiphy"),
+	CLK_LOOKUP("camss_top_ahb_clk", camss_top_ahb_clk.c,
+						"fda0b000.qcom,csiphy"),
+	CLK_LOOKUP("ispif_ahb_clk", camss_ispif_ahb_clk.c,
+						"fda0b000.qcom,csiphy"),
+	CLK_LOOKUP("csiphy_timer_src_clk", csi1phytimer_clk_src.c,
+						"fda0b000.qcom,csiphy"),
+	CLK_LOOKUP("csiphy_timer_clk", camss_phy1_csi1phytimer_clk.c,
+						"fda0b000.qcom,csiphy"),
+
+	/* CSID clocks */
+	CLK_LOOKUP("ispif_ahb_clk", camss_ispif_ahb_clk.c,
+					"fda08000.qcom,csid"),
+	CLK_LOOKUP("camss_top_ahb_clk", camss_top_ahb_clk.c,
+					"fda08000.qcom,csid"),
+	CLK_LOOKUP("csi_ahb_clk", camss_csi0_ahb_clk.c, "fda08000.qcom,csid"),
+	CLK_LOOKUP("csi_src_clk", csi0_clk_src.c, "fda08000.qcom,csid"),
+	CLK_LOOKUP("csi_phy_clk", camss_csi0phy_clk.c, "fda08000.qcom,csid"),
+	CLK_LOOKUP("csi_clk", camss_csi0_clk.c, "fda08000.qcom,csid"),
+	CLK_LOOKUP("csi_pix_clk", camss_csi0pix_clk.c, "fda08000.qcom,csid"),
+	CLK_LOOKUP("csi_rdi_clk", camss_csi0rdi_clk.c, "fda08000.qcom,csid"),
+
+	CLK_LOOKUP("ispif_ahb_clk", camss_ispif_ahb_clk.c,
+					"fda08400.qcom,csid"),
+	CLK_LOOKUP("camss_top_ahb_clk", camss_top_ahb_clk.c,
+					"fda08400.qcom,csid"),
+	CLK_LOOKUP("csi_ahb_clk", camss_csi1_ahb_clk.c, "fda08400.qcom,csid"),
+	CLK_LOOKUP("csi_src_clk", csi1_clk_src.c, "fda08400.qcom,csid"),
+	CLK_LOOKUP("csi_phy_clk", camss_csi1phy_clk.c, "fda08400.qcom,csid"),
+	CLK_LOOKUP("csi_clk", camss_csi1_clk.c, "fda08400.qcom,csid"),
+	CLK_LOOKUP("csi_pix_clk", camss_csi1pix_clk.c, "fda08400.qcom,csid"),
+	CLK_LOOKUP("csi_rdi_clk", camss_csi1rdi_clk.c, "fda08400.qcom,csid"),
+
+	CLK_LOOKUP("ispif_ahb_clk", camss_ispif_ahb_clk.c,
+					"fda08800.qcom,csid"),
+	CLK_LOOKUP("camss_top_ahb_clk", camss_top_ahb_clk.c,
+					"fda08800.qcom,csid"),
+	CLK_LOOKUP("csi_ahb_clk", camss_csi2_ahb_clk.c, "fda08800.qcom,csid"),
+	CLK_LOOKUP("csi_src_clk", csi2_clk_src.c, "fda08800.qcom,csid"),
+	CLK_LOOKUP("csi_phy_clk", camss_csi2phy_clk.c, "fda08800.qcom,csid"),
+	CLK_LOOKUP("csi_clk", camss_csi2_clk.c, "fda08800.qcom,csid"),
+	CLK_LOOKUP("csi_pix_clk", camss_csi2pix_clk.c, "fda08800.qcom,csid"),
+	CLK_LOOKUP("csi_rdi_clk", camss_csi2rdi_clk.c, "fda08800.qcom,csid"),
+
+	/* ISPIF clocks */
+	CLK_LOOKUP("ispif_ahb_clk", camss_ispif_ahb_clk.c,
+					"fda0a000.qcom,ispif"),
+	CLK_LOOKUP("vfe0_clk_src", vfe0_clk_src.c, "fda0a000.qcom,ispif"),
+	CLK_LOOKUP("camss_vfe_vfe0_clk", camss_vfe_vfe0_clk.c,
+					"fda0a000.qcom,ispif"),
+	CLK_LOOKUP("camss_csi_vfe0_clk", camss_csi_vfe0_clk.c,
+					"fda0a000.qcom,ispif"),
+	CLK_LOOKUP("vfe1_clk_src", vfe1_clk_src.c, "fda0a000.qcom,ispif"),
+	CLK_LOOKUP("camss_vfe_vfe1_clk", camss_vfe_vfe1_clk.c,
+					"fda0a000.qcom,ispif"),
+	CLK_LOOKUP("camss_csi_vfe1_clk", camss_csi_vfe1_clk.c,
+					"fda0a000.qcom,ispif"),
+	CLK_LOOKUP("csi0_src_clk", csi0_clk_src.c, "fda0a000.qcom,ispif"),
+	CLK_LOOKUP("csi0_clk", camss_csi0_clk.c, "fda0a000.qcom,ispif"),
+	CLK_LOOKUP("csi0_pix_clk", camss_csi0pix_clk.c,
+					"fda0a000.qcom,ispif"),
+	CLK_LOOKUP("csi0_rdi_clk", camss_csi0rdi_clk.c,
+					"fda0a000.qcom,ispif"),
+
+	/* CPP clocks */
+	CLK_LOOKUP("micro_iface_clk", camss_micro_ahb_clk.c,
+					"fda04000.qcom,cpp"),
+	CLK_LOOKUP("camss_top_ahb_clk", camss_top_ahb_clk.c,
+					"fda04000.qcom,cpp"),
+	CLK_LOOKUP("cpp_iface_clk", camss_vfe_cpp_ahb_clk.c,
+					"fda04000.qcom,cpp"),
+	CLK_LOOKUP("cpp_core_clk", camss_vfe_cpp_clk.c, "fda04000.qcom,cpp"),
+	CLK_LOOKUP("cpp_bus_clk", camss_vfe_vfe_axi_clk.c, "fda04000.qcom,cpp"),
+	CLK_LOOKUP("vfe_clk_src", vfe0_clk_src.c, "fda04000.qcom,cpp"),
+	CLK_LOOKUP("camss_vfe_vfe_clk", camss_vfe_vfe0_clk.c,
+					"fda04000.qcom,cpp"),
+	CLK_LOOKUP("iface_clk", camss_vfe_vfe_ahb_clk.c, "fda04000.qcom,cpp"),
+
+	/* GDSC */
+	CLK_LOOKUP("core_clk", venus0_vcodec0_clk.c, "fd8c1024.qcom,gdsc"),
+	CLK_LOOKUP("core0_clk", camss_vfe_vfe0_clk.c, "fd8c36a4.qcom,gdsc"),
+	CLK_LOOKUP("cpp_clk", camss_vfe_cpp_clk.c, "fd8c36a4.qcom,gdsc"),
+	CLK_LOOKUP("core_clk", oxili_gfx3d_clk.c, "fd8c4024.qcom,gdsc"),
+	CLK_LOOKUP("core_clk", mdss_mdp_clk.c, "fd8c2304.qcom,gdsc"),
+	CLK_LOOKUP("lut_clk", mdss_mdp_lut_clk.c, "fd8c2304.qcom,gdsc"),
+
+	/* DSI PLL clocks */
+	CLK_LOOKUP("", dsi_vco_clk_samarium.c, ""),
+	CLK_LOOKUP("", analog_postdiv_clk_samarium.c, ""),
+	CLK_LOOKUP("", indirect_path_div2_clk_samarium.c, ""),
+	CLK_LOOKUP("", pixel_clk_src_samarium.c, ""),
+	CLK_LOOKUP("", byte_mux_samarium.c, ""),
+	CLK_LOOKUP("", byte_clk_src_samarium.c, ""),
+
+	/* MMSS */
+	CLK_LOOKUP("", axi_clk_src.c, ""),
+	CLK_LOOKUP("", camss_ahb_clk.c, ""),
+	CLK_LOOKUP("", camss_gp0_clk.c, ""),
+	CLK_LOOKUP("", camss_gp1_clk.c, ""),
+	CLK_LOOKUP("", camss_jpeg_jpeg0_clk.c, ""),
+	CLK_LOOKUP("", camss_jpeg_jpeg_ahb_clk.c, ""),
+	CLK_LOOKUP("", camss_jpeg_jpeg_axi_clk.c, ""),
+	CLK_LOOKUP("", gfx3d.c, ""),
+	CLK_LOOKUP("", gfx3d_a_clk.c, ""),
+	CLK_LOOKUP("", jpeg0_clk_src.c, ""),
+	CLK_LOOKUP("core_clk_src", mdp_clk_src.c, "fd900000.qcom,mdss_mdp"),
+	CLK_LOOKUP("iface_clk", mdss_ahb_clk.c, "fd922800.qcom,mdss_dsi"),
+	CLK_LOOKUP("iface_clk", mdss_ahb_clk.c, "fd900000.qcom,mdss_mdp"),
+	CLK_LOOKUP("iface_clk", mdss_ahb_clk.c, "fd928000.qcom,iommu"),
+	CLK_LOOKUP("bus_clk", mdss_axi_clk.c, "fd922800.qcom,mdss_dsi"),
+	CLK_LOOKUP("core_clk", mdss_axi_clk.c, "fd928000.qcom,iommu"),
+	CLK_LOOKUP("bus_clk", mdss_axi_clk.c, "fd900000.qcom,mdss_mdp"),
+	CLK_LOOKUP("", byte0_clk_src.c, ""),
+	CLK_LOOKUP("", pclk0_clk_src.c, ""),
+	CLK_LOOKUP("byte_clk", mdss_byte0_clk.c, "fd922800.qcom,mdss_dsi"),
+	CLK_LOOKUP("core_clk", mdss_esc0_clk.c, "fd922800.qcom,mdss_dsi"),
+	CLK_LOOKUP("core_clk", mdss_mdp_clk.c, "fd900000.qcom,mdss_mdp"),
+	CLK_LOOKUP("mdp_core_clk", mdss_mdp_clk.c, "fd922800.qcom,mdss_dsi"),
+	CLK_LOOKUP("core_clk", mdss_mdp_clk.c, "fd8c2304.qcom,gdsc"),
+	CLK_LOOKUP("lut_clk", mdss_mdp_lut_clk.c, "fd900000.qcom,mdss_mdp"),
+	CLK_LOOKUP("lut_clk", mdss_mdp_lut_clk.c, "fd8c2304.qcom,gdsc"),
+	CLK_LOOKUP("pixel_clk", mdss_pclk0_clk.c, "fd922800.qcom,mdss_dsi"),
+	CLK_LOOKUP("vsync_clk", mdss_vsync_clk.c, "fd900000.qcom,mdss_mdp"),
+	CLK_LOOKUP("core_mmss_clk", mmss_misc_ahb_clk.c, "fd828018.hwevent"),
+	CLK_LOOKUP("", mmss_mmssnoc_axi_clk.c, ""),
+	CLK_LOOKUP("", ocmemgx.c, ""),
+	CLK_LOOKUP("", ocmemgx_a_clk.c, ""),
+	CLK_LOOKUP("core_clk", ocmemgx_core_clk.c, "fdd00000.qcom,ocmem"),
+	CLK_LOOKUP("iface_clk", ocmemcx_ocmemnoc_clk.c, "fdd00000.qcom,ocmem"),
+	CLK_LOOKUP("", ocmemnoc_clk_src.c, ""),
+	CLK_LOOKUP("core_clk", oxili_gfx3d_clk.c, "fdb00000.qcom,kgsl-3d0"),
+	CLK_LOOKUP("iface_clk", oxilicx_ahb_clk.c, "fdb00000.qcom,kgsl-3d0"),
+	CLK_LOOKUP("iface_clk", venus0_ahb_clk.c, "fdce0000.qcom,venus"),
+	CLK_LOOKUP("bus_clk", venus0_axi_clk.c, "fdce0000.qcom,venus"),
+	CLK_LOOKUP("mem_clk", venus0_ocmemnoc_clk.c, "fdce0000.qcom,venus"),
+	CLK_LOOKUP("core_clk", venus0_vcodec0_clk.c, "fdce0000.qcom,venus"),
+	CLK_LOOKUP("core_clk", venus0_vcodec0_clk.c, "fdc00000.qcom,vidc"),
+	CLK_LOOKUP("iface_clk",  venus0_ahb_clk.c, "fdc00000.qcom,vidc"),
+	CLK_LOOKUP("bus_clk",  venus0_axi_clk.c, "fdc00000.qcom,vidc"),
+	CLK_LOOKUP("mem_clk",  venus0_ocmemnoc_clk.c, "fdc00000.qcom,vidc"),
+
+	CLK_LOOKUP("iface_clk", oxilicx_ahb_clk.c, "fdb10000.qcom,iommu"),
+	CLK_LOOKUP("core_clk", oxili_gfx3d_clk.c, "fdb10000.qcom,iommu"),
+	CLK_LOOKUP("iface_clk", mdss_ahb_clk.c, "fd928000.qcom,iommu"),
+	CLK_LOOKUP("core_clk", mdss_axi_clk.c, "fd928000.qcom,iommu"),
+	CLK_LOOKUP("iface_clk", camss_vfe_vfe_ahb_clk.c, "fda44000.qcom,iommu"),
+	CLK_LOOKUP("core_clk", camss_vfe_vfe_axi_clk.c, "fda44000.qcom,iommu"),
+	CLK_LOOKUP("alt_iface_clk", camss_ahb_clk.c,  "fda44000.qcom,iommu"),
+	CLK_LOOKUP("alt_core_clk", camss_top_ahb_clk.c, "fda44000.qcom,iommu"),
+	CLK_LOOKUP("iface_clk", venus0_ahb_clk.c, "fdc84000.qcom,iommu"),
+	CLK_LOOKUP("alt_core_clk", venus0_vcodec0_clk.c, "fdc84000.qcom,iommu"),
+	CLK_LOOKUP("core_clk", venus0_axi_clk.c, "fdc84000.qcom,iommu"),
+	CLK_LOOKUP("iface_clk", camss_jpeg_jpeg_ahb_clk.c,
+					 "fda64000.qcom,iommu"),
+	CLK_LOOKUP("core_clk", camss_jpeg_jpeg_axi_clk.c,
+					 "fda64000.qcom,iommu"),
+	CLK_LOOKUP("alt_iface_clk", camss_ahb_clk.c,  "fda64000.qcom,iommu"),
+	CLK_LOOKUP("alt_core_clk", camss_top_ahb_clk.c, "fda64000.qcom,iommu"),
+};
+
+static struct pll_config_regs mmpll0_regs __initdata = {
+	.l_reg = (void __iomem *)MMPLL0_L_VAL,
+	.m_reg = (void __iomem *)MMPLL0_M_VAL,
+	.n_reg = (void __iomem *)MMPLL0_N_VAL,
+	.config_reg = (void __iomem *)MMPLL0_USER_CTL,
+	.mode_reg = (void __iomem *)MMPLL0_MODE,
+	.base = &virt_bases[MMSS_BASE],
+};
+
+/* MMPLL0 at 800 MHz, main output enabled. */
+static struct pll_config mmpll0_config __initdata = {
+	.l = 41,
+	.m = 2,
+	.n = 3,
+	.vco_val = 0x0,
+	.vco_mask = BM(21, 20),
+	.pre_div_val = 0x0,
+	.pre_div_mask = BM(14, 12),
+	.post_div_val = 0x0,
+	.post_div_mask = BM(9, 8),
+	.mn_ena_val = BIT(24),
+	.mn_ena_mask = BIT(24),
+	.main_output_val = BIT(0),
+	.main_output_mask = BIT(0),
+};
+
+static struct pll_config_regs mmpll1_regs __initdata = {
+	.l_reg = (void __iomem *)MMPLL1_L_VAL,
+	.m_reg = (void __iomem *)MMPLL1_M_VAL,
+	.n_reg = (void __iomem *)MMPLL1_N_VAL,
+	.config_reg = (void __iomem *)MMPLL1_USER_CTL,
+	.mode_reg = (void __iomem *)MMPLL1_MODE,
+	.base = &virt_bases[MMSS_BASE],
+};
+
+/* MMPLL1 at 900MHz, main output enabled. */
+static struct pll_config mmpll1_config __initdata = {
+	.l = 46,
+	.m = 7,
+	.n = 8,
+	.vco_val = 0x0,
+	.vco_mask = BM(21, 20),
+	.pre_div_val = 0x0,
+	.pre_div_mask = BM(14, 12),
+	.post_div_val = 0x0,
+	.post_div_mask = BM(9, 8),
+	.mn_ena_val = BIT(24),
+	.mn_ena_mask = BIT(24),
+	.main_output_val = BIT(0),
+	.main_output_mask = BIT(0),
+};
+
+static struct pll_config_regs mmpll3_regs __initdata = {
+	.l_reg = (void __iomem *)MMPLL3_L_VAL,
+	.m_reg = (void __iomem *)MMPLL3_M_VAL,
+	.n_reg = (void __iomem *)MMPLL3_N_VAL,
+	.config_reg = (void __iomem *)MMPLL3_USER_CTL,
+	.mode_reg = (void __iomem *)MMPLL3_MODE,
+	.base = &virt_bases[MMSS_BASE],
+};
+
+/* MMPLL3 at 930 MHz, main output enabled. */
+static struct pll_config mmpll3_config __initdata = {
+	.l = 48,
+	.m = 7,
+	.n = 16,
+	.vco_val = 0x0,
+	.vco_mask = BM(21, 20),
+	.pre_div_val = 0x0,
+	.pre_div_mask = BM(14, 12),
+	.post_div_val = 0x0,
+	.post_div_mask = BM(9, 8),
+	.mn_ena_val = BIT(24),
+	.mn_ena_mask = BIT(24),
+	.main_output_val = BIT(0),
+	.main_output_mask = BIT(0),
+};
+
+static struct pll_config_regs mmpll4_regs __initdata = {
+	.l_reg = (void __iomem *)MMPLL4_L_VAL,
+	.m_reg = (void __iomem *)MMPLL4_M_VAL,
+	.n_reg = (void __iomem *)MMPLL4_N_VAL,
+	.config_reg = (void __iomem *)MMPLL4_USER_CTL,
+	.mode_reg = (void __iomem *)MMPLL4_MODE,
+	.base = &virt_bases[MMSS_BASE],
+};
+
+/* MMPLL4 at 930 MHz, main output enabled. */
+static struct pll_config mmpll4_config __initdata = {
+	.l = 48,
+	.m = 7,
+	.n = 16,
+	.vco_val = 0x0,
+	.vco_mask = BM(21, 20),
+	.pre_div_val = 0x0,
+	.pre_div_mask = BM(14, 12),
+	.post_div_val = 0x0,
+	.post_div_mask = BM(9, 8),
+	.mn_ena_val = BIT(24),
+	.mn_ena_mask = BIT(24),
+	.main_output_val = BIT(0),
+	.main_output_mask = BIT(0),
+};
+
+static void __init reg_init(void)
+{
+	u32 regval;
+
+	/* MMPLL init */
+	configure_sr_hpm_lp_pll(&mmpll0_config, &mmpll0_regs, 1);
+	configure_sr_hpm_lp_pll(&mmpll1_config, &mmpll1_regs, 1);
+	configure_sr_hpm_lp_pll(&mmpll3_config, &mmpll3_regs, 0);
+	configure_sr_hpm_lp_pll(&mmpll4_config, &mmpll4_regs, 0);
+
+	/* Vote for GPLL0 to turn on. Needed by acpuclock. */
+	regval = readl_relaxed(GCC_REG_BASE(APCS_GPLL_ENA_VOTE));
+	regval |= BIT(0);
+	writel_relaxed(regval, GCC_REG_BASE(APCS_GPLL_ENA_VOTE));
+
+	/* Vote for LPASS and MMSS controller to use GPLL0 */
+	regval = readl_relaxed(GCC_REG_BASE(APCS_CLOCK_BRANCH_ENA_VOTE));
+	writel_relaxed(regval | BIT(26) | BIT(25),
+			GCC_REG_BASE(APCS_CLOCK_BRANCH_ENA_VOTE));
+}
+
+static void __init msmsamarium_clock_post_init(void)
+{
+	/*
+	 * Hold an active set vote at a rate of 40MHz for the MMSS NOC AHB
+	 * source. Sleep set vote is 0.
+	 */
+	/* enable for MMSS */
+	clk_set_rate(&mmssnoc_ahb_a_clk.c, 40000000);
+	clk_prepare_enable(&mmssnoc_ahb_a_clk.c);
+
+	/*
+	 * Hold an active set vote for the PNOC AHB source. Sleep set vote is 0.
+	 */
+	clk_set_rate(&pnoc_keepalive_a_clk.c, 19200000);
+	clk_prepare_enable(&pnoc_keepalive_a_clk.c);
+
+	/*
+	 * Hold an active set vote for CXO; this is because CXO is expected
+	 * to remain on whenever CPUs aren't power collapsed.
+	 */
+	clk_prepare_enable(&xo_a_clk.c);
+}
+
+#define GCC_CC_PHYS		0xFC400000
+#define GCC_CC_SIZE		SZ_8K
+
+#define MMSS_CC_PHYS		0xFD8C0000
+#define MMSS_CC_SIZE		SZ_32K
+
+#define APCS_GCC_CC_PHYS	0xF9011000
+#define APCS_GCC_CC_SIZE	SZ_4K
+
+static void __init msmsamarium_clock_pre_init(void)
+{
+	virt_bases[GCC_BASE] = ioremap(GCC_CC_PHYS, GCC_CC_SIZE);
+	if (!virt_bases[GCC_BASE])
+		panic("clock-samarium: Unable to ioremap GCC memory!");
+
+	virt_bases[MMSS_BASE] = ioremap(MMSS_CC_PHYS, MMSS_CC_SIZE);
+	if (!virt_bases[MMSS_BASE])
+		panic("clock-samarium: Unable to ioremap MMSS_CC memory!");
+
+	virt_bases[APCS_BASE] = ioremap(APCS_GCC_CC_PHYS, APCS_GCC_CC_SIZE);
+	if (!virt_bases[APCS_BASE])
+		panic("clock-samarium: Unable to ioremap APCS_GCC_CC memory!");
+
+	vdd_dig.regulator[0] = regulator_get(NULL, "vdd_dig");
+	if (IS_ERR(vdd_dig.regulator[0]))
+		panic("clock-samarium: Unable to get the vdd_dig regulator!");
+
+	enable_rpm_scaling();
+
+	reg_init();
+
+	/*
+	 * MDSS needs the ahb clock and needs to init before we register the
+	 * lookup table.
+	 */
+	mdss_clk_ctrl_pre_init(&mdss_ahb_clk.c);
+}
+
+static void __init msmsamarium_rumi_clock_pre_init(void)
+{
+	virt_bases[GCC_BASE] = ioremap(GCC_CC_PHYS, GCC_CC_SIZE);
+	if (!virt_bases[GCC_BASE])
+		panic("clock-samarium: Unable to ioremap GCC memory!");
+
+	vdd_dig.regulator[0] = regulator_get(NULL, "vdd_dig");
+	if (IS_ERR(vdd_dig.regulator[0]))
+		panic("clock-samarium: Unable to get the vdd_dig regulator!");
+}
+
+struct clock_init_data msmsamarium_rumi_clock_init_data __initdata = {
+	.table = msm_clocks_samarium_rumi,
+	.size = ARRAY_SIZE(msm_clocks_samarium_rumi),
+	.pre_init = msmsamarium_rumi_clock_pre_init,
+};
+
+struct clock_init_data msmsamarium_clock_init_data __initdata = {
+	.table = msm_clocks_samarium,
+	.size = ARRAY_SIZE(msm_clocks_samarium),
+	.pre_init = msmsamarium_clock_pre_init,
+	.post_init = msmsamarium_clock_post_init,
+};
diff --git a/arch/arm/mach-msm/common_log.c b/arch/arm/mach-msm/common_log.c
new file mode 100644
index 0000000..9491d9a
--- /dev/null
+++ b/arch/arm/mach-msm/common_log.c
@@ -0,0 +1,44 @@
+/* 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/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/kallsyms.h>
+#include <mach/msm_memory_dump.h>
+
+static void __init common_log_register(void)
+{
+	struct msm_client_dump dump;
+	char **log_bufp;
+	uint32_t *log_buf_lenp;
+
+	log_bufp = (char **)kallsyms_lookup_name("log_buf");
+	log_buf_lenp = (uint32_t *)kallsyms_lookup_name("log_buf_len");
+	if (!log_bufp || !log_buf_lenp) {
+		pr_err("common_log_register: Symbol log_buf not found!\n");
+		return;
+	}
+	dump.id = MSM_LOG_BUF;
+	dump.start_addr = virt_to_phys(*log_bufp);
+	dump.end_addr = virt_to_phys(*log_bufp + *log_buf_lenp);
+	if (msm_dump_table_register(&dump))
+		pr_err("common_log_register: Could not register log_bug.\n");
+}
+
+static int __init msm_common_log_init(void)
+{
+	common_log_register();
+	return 0;
+}
+late_initcall(msm_common_log_init);
diff --git a/arch/arm/mach-msm/cpr-regulator.c b/arch/arm/mach-msm/cpr-regulator.c
index 9ee7333..e50f865 100644
--- a/arch/arm/mach-msm/cpr-regulator.c
+++ b/arch/arm/mach-msm/cpr-regulator.c
@@ -1,5 +1,5 @@
 /*
- * 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
@@ -32,6 +32,10 @@
 
 /* Register Offsets for RB-CPR and Bit Definitions */
 
+/* RBCPR Version Register */
+#define REG_RBCPR_VERSION		0
+#define RBCPR_VER_2			0x02
+
 /* RBCPR Gate Count and Target Registers */
 #define REG_RBCPR_GCNT_TARGET(n)	(0x60 + 4 * n)
 
@@ -92,6 +96,8 @@
 /* RBCPR Result status Register */
 #define REG_RBCPR_RESULT_0		0xA0
 
+#define RBCPR_RESULT0_BUSY_SHIFT	19
+#define RBCPR_RESULT0_BUSY_MASK		BIT(RBCPR_RESULT0_BUSY_SHIFT)
 #define RBCPR_RESULT0_ERROR_STEPS_SHIFT	2
 #define RBCPR_RESULT0_ERROR_STEPS_BITS	4
 #define RBCPR_RESULT0_ERROR_STEPS_MASK	((1<<RBCPR_RESULT0_ERROR_STEPS_BITS)-1)
@@ -113,7 +119,6 @@
 #define CPR_INT_DEFAULT	(CPR_INT_UP | CPR_INT_DOWN)
 
 #define CPR_NUM_RING_OSC	8
-#define CPR_NUM_SAVE_REGS	10
 
 /* RBCPR Clock Control Register */
 #define RBCPR_CLK_SEL_MASK	BIT(0)
@@ -130,9 +135,20 @@
 
 #define BYTES_PER_FUSE_ROW		8
 
+#define FLAGS_IGNORE_1ST_IRQ_STATUS	BIT(0)
 #define FLAGS_SET_MIN_VOLTAGE		BIT(1)
 #define FLAGS_UPLIFT_QUOT_VOLT		BIT(2)
 
+struct quot_adjust_info {
+	int speed_bin;
+	int virtual_corner;
+	int quot_adjust;
+};
+
+static const char * const vdd_apc_name[] =	{"vdd-apc-optional-prim",
+						"vdd-apc-optional-sec",
+						"vdd-apc"};
+
 enum voltage_change_dir {
 	NO_CHANGE,
 	DOWN,
@@ -151,12 +167,12 @@
 	void __iomem	*efuse_base;
 
 	/* Process voltage parameters */
-	u32		pvs_init_v[CPR_PVS_EFUSE_BINS_MAX];
-	u32		pvs_corner_v[NUM_APC_PVS][CPR_CORNER_MAX];
+	u32		pvs_corner_v[CPR_FUSE_CORNER_MAX];
 	/* Process voltage variables */
 	u32		pvs_bin;
-	u32		process;
 	u32		speed_bin;
+	u32		pvs_version;
+
 	/* APC voltage regulator */
 	struct regulator	*vdd_apc;
 
@@ -165,13 +181,17 @@
 	int			vdd_mx_vmax;
 	int			vdd_mx_vmin_method;
 	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;
 	bool		cpr_fuse_local;
-	int		cpr_fuse_target_quot[CPR_CORNER_MAX];
-	int		cpr_fuse_ro_sel[CPR_CORNER_MAX];
+	int		cpr_fuse_target_quot[CPR_FUSE_CORNER_MAX];
+	int		cpr_fuse_ro_sel[CPR_FUSE_CORNER_MAX];
 	int		gcnt;
 
 	unsigned int	cpr_irq;
@@ -179,16 +199,13 @@
 	phys_addr_t	rbcpr_clk_addr;
 	struct mutex	cpr_mutex;
 
-	int		ceiling_volt[CPR_CORNER_MAX];
-	int		floor_volt[CPR_CORNER_MAX];
-	int		last_volt[CPR_CORNER_MAX];
+	int		ceiling_volt[CPR_FUSE_CORNER_MAX];
+	int		floor_volt[CPR_FUSE_CORNER_MAX];
+	int		*last_volt;
 	int		step_volt;
 
-	int		save_ctl[CPR_CORNER_MAX];
-	int		save_irq[CPR_CORNER_MAX];
-
-	u32		save_regs[CPR_NUM_SAVE_REGS];
-	u32		save_reg_val[CPR_NUM_SAVE_REGS];
+	int		*save_ctl;
+	int		*save_irq;
 
 	/* Config parameters */
 	bool		enable;
@@ -205,6 +222,11 @@
 	u32		vdd_apc_step_up_limit;
 	u32		vdd_apc_step_down_limit;
 	u32		flags;
+	int		*corner_map;
+	u32		num_corners;
+	int		*quot_adjust;
+
+	bool		is_cpr_suspended;
 };
 
 #define CPR_DEBUG_MASK_IRQ	BIT(0)
@@ -327,9 +349,27 @@
 static void cpr_ctl_enable(struct cpr_regulator *cpr_vreg, int corner)
 {
 	u32 val;
+	int fuse_corner = cpr_vreg->corner_map[corner];
+
+	if (cpr_vreg->is_cpr_suspended)
+		return;
+
+	/* Program Consecutive Up & Down */
+	val = ((cpr_vreg->timer_cons_down & RBIF_TIMER_ADJ_CONS_DOWN_MASK)
+			<< RBIF_TIMER_ADJ_CONS_DOWN_SHIFT) |
+		(cpr_vreg->timer_cons_up & RBIF_TIMER_ADJ_CONS_UP_MASK);
+	cpr_masked_write(cpr_vreg, REG_RBIF_TIMER_ADJUST,
+			RBIF_TIMER_ADJ_CONS_UP_MASK |
+			RBIF_TIMER_ADJ_CONS_DOWN_MASK, val);
+	cpr_masked_write(cpr_vreg, REG_RBCPR_CTL,
+			RBCPR_CTL_SW_AUTO_CONT_NACK_DN_EN |
+			RBCPR_CTL_SW_AUTO_CONT_ACK_EN,
+			cpr_vreg->save_ctl[corner]);
+	cpr_irq_set(cpr_vreg, cpr_vreg->save_irq[corner]);
 
 	if (cpr_is_allowed(cpr_vreg) &&
-	    (cpr_vreg->ceiling_volt[corner] > cpr_vreg->floor_volt[corner]))
+	    (cpr_vreg->ceiling_volt[fuse_corner] >
+		cpr_vreg->floor_volt[fuse_corner]))
 		val = RBCPR_CTL_LOOP_EN;
 	else
 		val = 0;
@@ -338,29 +378,35 @@
 
 static void cpr_ctl_disable(struct cpr_regulator *cpr_vreg)
 {
+	if (cpr_vreg->is_cpr_suspended)
+		return;
+
+	cpr_irq_set(cpr_vreg, 0);
+	cpr_ctl_modify(cpr_vreg, RBCPR_CTL_SW_AUTO_CONT_NACK_DN_EN |
+			RBCPR_CTL_SW_AUTO_CONT_ACK_EN, 0);
+	cpr_masked_write(cpr_vreg, REG_RBIF_TIMER_ADJUST,
+			RBIF_TIMER_ADJ_CONS_UP_MASK |
+			RBIF_TIMER_ADJ_CONS_DOWN_MASK, 0);
+	cpr_irq_clr(cpr_vreg);
+	cpr_write(cpr_vreg, REG_RBIF_CONT_ACK_CMD, 1);
+	cpr_write(cpr_vreg, REG_RBIF_CONT_NACK_CMD, 1);
 	cpr_ctl_modify(cpr_vreg, RBCPR_CTL_LOOP_EN, 0);
 }
 
-static void cpr_regs_save(struct cpr_regulator *cpr_vreg)
+static bool cpr_ctl_is_enabled(struct cpr_regulator *cpr_vreg)
 {
-	int i, offset;
+	u32 reg_val;
 
-	for (i = 0; i < CPR_NUM_SAVE_REGS; i++) {
-		offset = cpr_vreg->save_regs[i];
-		cpr_vreg->save_reg_val[i] = cpr_read(cpr_vreg, offset);
-	}
+	reg_val = cpr_read(cpr_vreg, REG_RBCPR_CTL);
+	return reg_val & RBCPR_CTL_LOOP_EN;
 }
 
-static void cpr_regs_restore(struct cpr_regulator *cpr_vreg)
+static bool cpr_ctl_is_busy(struct cpr_regulator *cpr_vreg)
 {
-	int i, offset;
-	u32 val;
+	u32 reg_val;
 
-	for (i = 0; i < CPR_NUM_SAVE_REGS; i++) {
-		offset = cpr_vreg->save_regs[i];
-		val = cpr_vreg->save_reg_val[i];
-		cpr_write(cpr_vreg, offset, val);
-	}
+	reg_val = cpr_read(cpr_vreg, REG_RBCPR_RESULT_0);
+	return reg_val & RBCPR_RESULT0_BUSY_MASK;
 }
 
 static void cpr_corner_save(struct cpr_regulator *cpr_vreg, int corner)
@@ -373,9 +419,12 @@
 static void cpr_corner_restore(struct cpr_regulator *cpr_vreg, int corner)
 {
 	u32 gcnt, ctl, irq, ro_sel;
+	int fuse_corner = cpr_vreg->corner_map[corner];
 
-	ro_sel = cpr_vreg->cpr_fuse_ro_sel[corner];
-	gcnt = cpr_vreg->gcnt | cpr_vreg->cpr_fuse_target_quot[corner];
+	ro_sel = cpr_vreg->cpr_fuse_ro_sel[fuse_corner];
+	gcnt = cpr_vreg->gcnt | (cpr_vreg->cpr_fuse_target_quot[fuse_corner] -
+					cpr_vreg->quot_adjust[corner]);
+
 	cpr_write(cpr_vreg, REG_RBCPR_GCNT_TARGET(ro_sel), gcnt);
 	ctl = cpr_vreg->save_ctl[corner];
 	cpr_write(cpr_vreg, REG_RBCPR_CTL, ctl);
@@ -413,8 +462,9 @@
 		goto _exit;
 	}
 
-	cpr_debug("%d -> %d [corner=%d]\n",
-		  old_cpr_enable, cpr_enable, the_cpr->corner);
+	cpr_debug("%d -> %d [corner=%d, fuse_corner=%d]\n",
+		  old_cpr_enable, cpr_enable, the_cpr->corner,
+		  the_cpr->corner_map[the_cpr->corner]);
 
 	if (the_cpr->cpr_fuse_disable) {
 		/* Already disabled */
@@ -460,21 +510,24 @@
 static int cpr_mx_get(struct cpr_regulator *cpr_vreg, int corner, int apc_volt)
 {
 	int vdd_mx;
+	int fuse_corner = cpr_vreg->corner_map[corner];
 
 	switch (cpr_vreg->vdd_mx_vmin_method) {
 	case VDD_MX_VMIN_APC:
 		vdd_mx = apc_volt;
 		break;
 	case VDD_MX_VMIN_APC_CORNER_CEILING:
-		vdd_mx = cpr_vreg->ceiling_volt[corner];
+		vdd_mx = cpr_vreg->ceiling_volt[fuse_corner];
 		break;
 	case VDD_MX_VMIN_APC_SLOW_CORNER_CEILING:
-		vdd_mx = cpr_vreg->pvs_corner_v[APC_PVS_SLOW]
-						[CPR_CORNER_TURBO];
+		vdd_mx = cpr_vreg->ceiling_volt[CPR_FUSE_CORNER_TURBO];
 		break;
 	case VDD_MX_VMIN_MX_VMAX:
 		vdd_mx = cpr_vreg->vdd_mx_vmax;
 		break;
+	case VDD_MX_VMIN_APC_CORNER_MAP:
+		vdd_mx = cpr_vreg->vdd_mx_corner_map[fuse_corner];
+		break;
 	default:
 		vdd_mx = 0;
 		break;
@@ -487,15 +540,19 @@
 		      int vdd_mx_vmin)
 {
 	int rc;
+	int fuse_corner = cpr_vreg->corner_map[corner];
 
 	rc = regulator_set_voltage(cpr_vreg->vdd_mx, vdd_mx_vmin,
 				   cpr_vreg->vdd_mx_vmax);
-	cpr_debug("[corner:%d] %d uV\n", corner, vdd_mx_vmin);
-	if (!rc)
+	cpr_debug("[corner:%d, fuse_corner:%d] %d uV\n", corner,
+			fuse_corner, vdd_mx_vmin);
+
+	if (!rc) {
 		cpr_vreg->vdd_mx_vmin = vdd_mx_vmin;
-	else
-		pr_err("set: vdd_mx [%d] = %d uV: rc=%d\n",
-		       corner, vdd_mx_vmin, rc);
+	} else {
+		pr_err("set: vdd_mx [corner:%d, fuse_corner:%d] = %d uV failed: rc=%d\n",
+			corner, fuse_corner, vdd_mx_vmin, rc);
+	}
 	return rc;
 }
 
@@ -503,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)
@@ -521,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);
@@ -533,9 +594,11 @@
 		      enum voltage_change_dir dir)
 {
 	u32 reg_val, error_steps, reg_mask;
-	int last_volt, new_volt, corner;
+	int last_volt, new_volt, corner, fuse_corner;
+	u32 gcnt, quot;
 
 	corner = cpr_vreg->corner;
+	fuse_corner = cpr_vreg->corner_map[corner];
 
 	reg_val = cpr_read(cpr_vreg, REG_RBCPR_RESULT_0);
 
@@ -543,23 +606,36 @@
 				& RBCPR_RESULT0_ERROR_STEPS_MASK;
 	last_volt = cpr_vreg->last_volt[corner];
 
-	cpr_debug_irq("last_volt[corner:%d] = %d uV\n", corner, last_volt);
+	cpr_debug_irq("last_volt[corner:%d, fuse_corner:%d] = %d uV\n", corner,
+			fuse_corner, last_volt);
+
+	gcnt = cpr_read(cpr_vreg, REG_RBCPR_GCNT_TARGET
+			(cpr_vreg->cpr_fuse_ro_sel[fuse_corner]));
+	quot = gcnt & ((1 << RBCPR_GCNT_TARGET_GCNT_SHIFT) - 1);
 
 	if (dir == UP) {
 		cpr_debug_irq("Up: cpr status = 0x%08x (error_steps=%d)\n",
 			      reg_val, error_steps);
 
-		if (last_volt >= cpr_vreg->ceiling_volt[corner]) {
-			cpr_debug_irq("[corn:%d] @ ceiling: %d >= %d: NACK\n",
-				      corner, last_volt,
-				      cpr_vreg->ceiling_volt[corner]);
+		if (last_volt >= cpr_vreg->ceiling_volt[fuse_corner]) {
+			cpr_debug_irq(
+			"[corn:%d, fuse_corn:%d] @ ceiling: %d >= %d: NACK\n",
+				corner, fuse_corner, last_volt,
+				cpr_vreg->ceiling_volt[fuse_corner]);
 			cpr_irq_clr_nack(cpr_vreg);
 
+			cpr_debug_irq("gcnt = 0x%08x (quot = %d)\n", gcnt,
+					quot);
+
 			/* Maximize the UP threshold */
 			reg_mask = RBCPR_CTL_UP_THRESHOLD_MASK <<
 					RBCPR_CTL_UP_THRESHOLD_SHIFT;
 			reg_val = reg_mask;
 			cpr_ctl_modify(cpr_vreg, reg_mask, reg_val);
+
+			/* Disable UP interrupt */
+			cpr_irq_set(cpr_vreg, CPR_INT_DEFAULT & ~CPR_INT_UP);
+
 			return;
 		}
 
@@ -572,11 +648,12 @@
 
 		/* Calculate new voltage */
 		new_volt = last_volt + (error_steps * cpr_vreg->step_volt);
-		if (new_volt > cpr_vreg->ceiling_volt[corner]) {
+		if (new_volt > cpr_vreg->ceiling_volt[fuse_corner]) {
 			cpr_debug_irq("new_volt(%d) >= ceiling(%d): Clamp\n",
 				      new_volt,
-				      cpr_vreg->ceiling_volt[corner]);
-			new_volt = cpr_vreg->ceiling_volt[corner];
+				      cpr_vreg->ceiling_volt[fuse_corner]);
+
+			new_volt = cpr_vreg->ceiling_volt[fuse_corner];
 		}
 
 		if (cpr_scale_voltage(cpr_vreg, corner, new_volt, dir)) {
@@ -585,13 +662,9 @@
 		}
 		cpr_vreg->last_volt[corner] = new_volt;
 
-		/* Restore default threshold for DOWN */
-		reg_mask = RBCPR_CTL_DN_THRESHOLD_MASK <<
-				RBCPR_CTL_DN_THRESHOLD_SHIFT;
-		reg_val = cpr_vreg->down_threshold <<
-				RBCPR_CTL_DN_THRESHOLD_SHIFT;
-		/* and disable auto nack down */
-		reg_mask |= RBCPR_CTL_SW_AUTO_CONT_NACK_DN_EN;
+		/* Disable auto nack down */
+		reg_mask = RBCPR_CTL_SW_AUTO_CONT_NACK_DN_EN;
+		reg_val = 0;
 
 		cpr_ctl_modify(cpr_vreg, reg_mask, reg_val);
 
@@ -601,26 +674,26 @@
 		/* Ack */
 		cpr_irq_clr_ack(cpr_vreg);
 
-		cpr_debug_irq("UP: -> new_volt[corner:%d] = %d uV\n",
-			      corner, new_volt);
+		cpr_debug_irq(
+			"UP: -> new_volt[corner:%d, fuse_corner:%d] = %d uV\n",
+			corner, fuse_corner, new_volt);
 	} else if (dir == DOWN) {
 		cpr_debug_irq("Down: cpr status = 0x%08x (error_steps=%d)\n",
 			      reg_val, error_steps);
 
-		if (last_volt <= cpr_vreg->floor_volt[corner]) {
-			cpr_debug_irq("[corn:%d] @ floor: %d <= %d: NACK\n",
-				      corner, last_volt,
-				      cpr_vreg->floor_volt[corner]);
+		if (last_volt <= cpr_vreg->floor_volt[fuse_corner]) {
+			cpr_debug_irq(
+			"[corn:%d, fuse_corner:%d] @ floor: %d <= %d: NACK\n",
+				corner, fuse_corner, last_volt,
+				cpr_vreg->floor_volt[fuse_corner]);
 			cpr_irq_clr_nack(cpr_vreg);
 
-			/* Maximize the DOWN threshold */
-			reg_mask = RBCPR_CTL_DN_THRESHOLD_MASK <<
-					RBCPR_CTL_DN_THRESHOLD_SHIFT;
-			reg_val = reg_mask;
+			cpr_debug_irq("gcnt = 0x%08x (quot = %d)\n", gcnt,
+					quot);
 
 			/* Enable auto nack down */
-			reg_mask |= RBCPR_CTL_SW_AUTO_CONT_NACK_DN_EN;
-			reg_val |= RBCPR_CTL_SW_AUTO_CONT_NACK_DN_EN;
+			reg_mask = RBCPR_CTL_SW_AUTO_CONT_NACK_DN_EN;
+			reg_val = RBCPR_CTL_SW_AUTO_CONT_NACK_DN_EN;
 
 			cpr_ctl_modify(cpr_vreg, reg_mask, reg_val);
 
@@ -639,11 +712,11 @@
 
 		/* Calculte new voltage */
 		new_volt = last_volt - (error_steps * cpr_vreg->step_volt);
-		if (new_volt < cpr_vreg->floor_volt[corner]) {
+		if (new_volt < cpr_vreg->floor_volt[fuse_corner]) {
 			cpr_debug_irq("new_volt(%d) < floor(%d): Clamp\n",
 				      new_volt,
-				      cpr_vreg->floor_volt[corner]);
-			new_volt = cpr_vreg->floor_volt[corner];
+				      cpr_vreg->floor_volt[fuse_corner]);
+			new_volt = cpr_vreg->floor_volt[fuse_corner];
 		}
 
 		if (cpr_scale_voltage(cpr_vreg, corner, new_volt, dir)) {
@@ -659,11 +732,15 @@
 				RBCPR_CTL_UP_THRESHOLD_SHIFT;
 		cpr_ctl_modify(cpr_vreg, reg_mask, reg_val);
 
+		/* Re-enable default interrupts */
+		cpr_irq_set(cpr_vreg, CPR_INT_DEFAULT);
+
 		/* Ack */
 		cpr_irq_clr_ack(cpr_vreg);
 
-		cpr_debug_irq("DOWN: -> new_volt[corner:%d] = %d uV\n",
-			      corner, new_volt);
+		cpr_debug_irq(
+		"DOWN: -> new_volt[corner:%d, fuse_corner:%d] = %d uV\n",
+			corner, fuse_corner, new_volt);
 	}
 }
 
@@ -675,9 +752,18 @@
 	mutex_lock(&cpr_vreg->cpr_mutex);
 
 	reg_val = cpr_read(cpr_vreg, REG_RBIF_IRQ_STATUS);
+	if (cpr_vreg->flags & FLAGS_IGNORE_1ST_IRQ_STATUS)
+		reg_val = cpr_read(cpr_vreg, REG_RBIF_IRQ_STATUS);
+
 	cpr_debug_irq("IRQ_STATUS = 0x%02X\n", reg_val);
 
-	if (!cpr_is_allowed(cpr_vreg)) {
+	if (!cpr_ctl_is_enabled(cpr_vreg)) {
+		cpr_debug_irq("CPR is disabled\n");
+		goto _exit;
+	} else if (cpr_ctl_is_busy(cpr_vreg)) {
+		cpr_debug_irq("CPR measurement is not ready\n");
+		goto _exit;
+	} else if (!cpr_is_allowed(cpr_vreg)) {
 		reg_val = cpr_read(cpr_vreg, REG_RBCPR_CTL);
 		pr_err("Interrupt broken? RBCPR_CTL = 0x%02X\n", reg_val);
 		goto _exit;
@@ -782,6 +868,7 @@
 	int rc;
 	int new_volt;
 	enum voltage_change_dir change_dir = NO_CHANGE;
+	int fuse_corner = cpr_vreg->corner_map[corner];
 
 	mutex_lock(&cpr_vreg->cpr_mutex);
 
@@ -789,10 +876,11 @@
 		cpr_ctl_disable(cpr_vreg);
 		new_volt = cpr_vreg->last_volt[corner];
 	} else {
-		new_volt = cpr_vreg->pvs_corner_v[cpr_vreg->process][corner];
+		new_volt = cpr_vreg->pvs_corner_v[fuse_corner];
 	}
 
-	cpr_debug("[corner:%d] = %d uV\n", corner, new_volt);
+	cpr_debug("[corner:%d, fuse_corner:%d] = %d uV\n", corner, fuse_corner,
+		new_volt);
 
 	if (corner > cpr_vreg->corner)
 		change_dir = UP;
@@ -837,12 +925,15 @@
 {
 	cpr_debug("suspend\n");
 
+	mutex_lock(&cpr_vreg->cpr_mutex);
+
 	cpr_ctl_disable(cpr_vreg);
-	disable_irq(cpr_vreg->cpr_irq);
 
 	cpr_irq_clr(cpr_vreg);
-	cpr_regs_save(cpr_vreg);
 
+	cpr_vreg->is_cpr_suspended = true;
+
+	mutex_unlock(&cpr_vreg->cpr_mutex);
 	return 0;
 }
 
@@ -851,12 +942,14 @@
 {
 	cpr_debug("resume\n");
 
-	cpr_regs_restore(cpr_vreg);
+	mutex_lock(&cpr_vreg->cpr_mutex);
+
+	cpr_vreg->is_cpr_suspended = false;
 	cpr_irq_clr(cpr_vreg);
 
-	enable_irq(cpr_vreg->cpr_irq);
 	cpr_ctl_enable(cpr_vreg, cpr_vreg->corner);
 
+	mutex_unlock(&cpr_vreg->cpr_mutex);
 	return 0;
 }
 
@@ -885,11 +978,13 @@
 #define cpr_regulator_resume NULL
 #endif
 
-static int __devinit cpr_config(struct cpr_regulator *cpr_vreg)
+static int __devinit cpr_config(struct cpr_regulator *cpr_vreg,
+				struct device *dev)
 {
 	int i;
 	u32 val, gcnt, reg;
 	void __iomem *rbcpr_clk;
+	int size;
 
 	/* Use 19.2 MHz clock for CPR. */
 	rbcpr_clk = ioremap(cpr_vreg->rbcpr_clk_addr, 4);
@@ -951,26 +1046,20 @@
 	val |= RBCPR_CTL_SW_AUTO_CONT_ACK_EN;
 	cpr_write(cpr_vreg, REG_RBCPR_CTL, val);
 
-	/* Registers to save & restore for suspend */
-	cpr_vreg->save_regs[0] = REG_RBCPR_TIMER_INTERVAL;
-	cpr_vreg->save_regs[1] = REG_RBCPR_STEP_QUOT;
-	cpr_vreg->save_regs[2] = REG_RBIF_TIMER_ADJUST;
-	cpr_vreg->save_regs[3] = REG_RBIF_LIMIT;
-	cpr_vreg->save_regs[4] = REG_RBIF_SW_VLEVEL;
-	cpr_vreg->save_regs[5] = REG_RBIF_IRQ_EN(cpr_vreg->irq_line);
-	cpr_vreg->save_regs[6] = REG_RBCPR_CTL;
-	cpr_vreg->save_regs[7] = REG_RBCPR_GCNT_TARGET
-		(cpr_vreg->cpr_fuse_ro_sel[CPR_CORNER_SVS]);
-	cpr_vreg->save_regs[8] = REG_RBCPR_GCNT_TARGET
-		(cpr_vreg->cpr_fuse_ro_sel[CPR_CORNER_NORMAL]);
-	cpr_vreg->save_regs[9] = REG_RBCPR_GCNT_TARGET
-		(cpr_vreg->cpr_fuse_ro_sel[CPR_CORNER_TURBO]);
-
 	cpr_irq_set(cpr_vreg, CPR_INT_DEFAULT);
 
-	cpr_corner_save(cpr_vreg, CPR_CORNER_SVS);
-	cpr_corner_save(cpr_vreg, CPR_CORNER_NORMAL);
-	cpr_corner_save(cpr_vreg, CPR_CORNER_TURBO);
+	val = cpr_read(cpr_vreg, REG_RBCPR_VERSION);
+	if (val <= RBCPR_VER_2)
+		cpr_vreg->flags |= FLAGS_IGNORE_1ST_IRQ_STATUS;
+
+	size = cpr_vreg->num_corners + 1;
+	cpr_vreg->save_ctl = devm_kzalloc(dev, sizeof(int) * size, GFP_KERNEL);
+	cpr_vreg->save_irq = devm_kzalloc(dev, sizeof(int) * size, GFP_KERNEL);
+	if (!cpr_vreg->save_ctl || !cpr_vreg->save_irq)
+		return -ENOMEM;
+
+	for (i = 1; i < size; i++)
+		cpr_corner_save(cpr_vreg, i);
 
 	return 0;
 }
@@ -1001,26 +1090,24 @@
 {
 	u32 uplift_voltage;
 	u32 uplift_max_volt = 0;
-	int rc, i;
+	int rc;
 
 	rc = of_property_read_u32(of_node,
-		"qti,cpr-uplift-voltage", &uplift_voltage);
+		"qcom,cpr-uplift-voltage", &uplift_voltage);
 	if (rc < 0) {
 		pr_err("cpr-uplift-voltage is missing, rc = %d", rc);
 		return rc;
 	}
 	rc = of_property_read_u32(of_node,
-		"qti,cpr-uplift-max-volt", &uplift_max_volt);
+		"qcom,cpr-uplift-max-volt", &uplift_max_volt);
 	if (rc < 0) {
 		pr_err("cpr-uplift-max-volt is missing, rc = %d", rc);
 		return rc;
 	}
 
-	for (i = 0; i < CPR_PVS_EFUSE_BINS_MAX; i++) {
-		cpr_vreg->pvs_init_v[i] += uplift_voltage;
-		if (cpr_vreg->pvs_init_v[i] > uplift_max_volt)
-			cpr_vreg->pvs_init_v[i] = uplift_max_volt;
-	}
+	cpr_vreg->pvs_corner_v[CPR_FUSE_CORNER_TURBO] += uplift_voltage;
+	if (cpr_vreg->pvs_corner_v[CPR_FUSE_CORNER_TURBO] > uplift_max_volt)
+		cpr_vreg->pvs_corner_v[CPR_FUSE_CORNER_TURBO] = uplift_max_volt;
 
 	return rc;
 }
@@ -1030,13 +1117,13 @@
 {
 	struct device_node *of_node = pdev->dev.of_node;
 	u64 efuse_bits;
-	int rc, process;
+	int rc, i, stripe_size;
 	u32 pvs_fuse[4], pvs_fuse_redun_sel[5];
-	u32 init_v;
 	bool redundant;
 	size_t pvs_bins;
+	u32 *tmp;
 
-	rc = of_property_read_u32_array(of_node, "qti,pvs-fuse-redun-sel",
+	rc = of_property_read_u32_array(of_node, "qcom,pvs-fuse-redun-sel",
 					pvs_fuse_redun_sel, 5);
 	if (rc < 0) {
 		pr_err("pvs-fuse-redun-sel missing: rc=%d\n", rc);
@@ -1046,14 +1133,14 @@
 	redundant = cpr_fuse_is_setting_expected(cpr_vreg, pvs_fuse_redun_sel);
 
 	if (redundant) {
-		rc = of_property_read_u32_array(of_node, "qti,pvs-fuse-redun",
+		rc = of_property_read_u32_array(of_node, "qcom,pvs-fuse-redun",
 						pvs_fuse, 4);
 		if (rc < 0) {
 			pr_err("pvs-fuse-redun missing: rc=%d\n", rc);
 			return rc;
 		}
 	} else {
-		rc = of_property_read_u32_array(of_node, "qti,pvs-fuse",
+		rc = of_property_read_u32_array(of_node, "qcom,pvs-fuse",
 						pvs_fuse, 4);
 		if (rc < 0) {
 			pr_err("pvs-fuse missing: rc=%d\n", rc);
@@ -1069,13 +1156,26 @@
 
 	pvs_bins = 1 << pvs_fuse[2];
 
-	rc = of_property_read_u32_array(of_node, "qti,pvs-init-voltage",
-					cpr_vreg->pvs_init_v, pvs_bins);
+	stripe_size = CPR_FUSE_CORNER_MAX - 1;
+	tmp = kzalloc(sizeof(u32) * pvs_bins * stripe_size, GFP_KERNEL);
+	if (!tmp) {
+		pr_err("memory alloc failed\n");
+		return -ENOMEM;
+	}
+
+	rc = of_property_read_u32_array(of_node, "qcom,pvs-voltage-table",
+					tmp, pvs_bins * stripe_size);
 	if (rc < 0) {
-		pr_err("pvs-init-voltage missing: rc=%d\n", rc);
+		pr_err("pvs-voltage-table missing: rc=%d\n", rc);
+		kfree(tmp);
 		return rc;
 	}
 
+	for (i = CPR_FUSE_CORNER_SVS; i < CPR_FUSE_CORNER_MAX; i++)
+		cpr_vreg->pvs_corner_v[i] = tmp[cpr_vreg->pvs_bin *
+						stripe_size + i - 1];
+	kfree(tmp);
+
 	if (cpr_vreg->flags & FLAGS_UPLIFT_QUOT_VOLT) {
 		rc = cpr_voltage_uplift_wa_inc_volt(cpr_vreg, of_node);
 		if (rc < 0) {
@@ -1084,28 +1184,31 @@
 		}
 	}
 
-	init_v = cpr_vreg->pvs_init_v[cpr_vreg->pvs_bin];
-	for (process = NUM_APC_PVS - 1; process > APC_PVS_NO; process--) {
-		if (init_v <= cpr_vreg->pvs_corner_v[process][CPR_CORNER_TURBO])
-			break;
-	}
+	if (cpr_vreg->pvs_corner_v[CPR_FUSE_CORNER_TURBO] >
+		cpr_vreg->ceiling_volt[CPR_FUSE_CORNER_TURBO])
+		cpr_vreg->ceiling_volt[CPR_FUSE_CORNER_TURBO] =
+			cpr_vreg->pvs_corner_v[CPR_FUSE_CORNER_TURBO];
 
-	if (process == APC_PVS_NO) {
-		process = APC_PVS_SLOW;
-		cpr_vreg->pvs_corner_v[process][CPR_CORNER_TURBO] = init_v;
-		cpr_vreg->ceiling_max = init_v;
-	} else if (process == APC_PVS_FAST &&
-		init_v < cpr_vreg->pvs_corner_v[APC_PVS_FAST][CPR_CORNER_SVS]) {
-		process = APC_PVS_SLOW;
-	}
+	for (i = CPR_FUSE_CORNER_SVS; i < CPR_FUSE_CORNER_TURBO; i++)
+		if (cpr_vreg->pvs_corner_v[i] > cpr_vreg->ceiling_volt[i])
+			cpr_vreg->pvs_corner_v[i] = cpr_vreg->ceiling_volt[i];
+		else if (cpr_vreg->pvs_corner_v[i] < cpr_vreg->floor_volt[i])
+			cpr_vreg->pvs_corner_v[i] = cpr_vreg->floor_volt[i];
 
-	pr_info("[row:%d] = 0x%llX, n_bits=%d, bin=%d (%d)",
-		pvs_fuse[0], efuse_bits, pvs_fuse[2],
-		cpr_vreg->pvs_bin, process);
-	pr_info("pvs initial turbo voltage_= from %u to %u\n",
-		init_v, cpr_vreg->pvs_corner_v[process][CPR_CORNER_TURBO]);
+	cpr_vreg->ceiling_max = cpr_vreg->ceiling_volt[CPR_FUSE_CORNER_TURBO];
 
-	cpr_vreg->process = process;
+	pr_info("pvs voltage: [%d %d %d] uV\n",
+			cpr_vreg->pvs_corner_v[CPR_FUSE_CORNER_SVS],
+			cpr_vreg->pvs_corner_v[CPR_FUSE_CORNER_NORMAL],
+			cpr_vreg->pvs_corner_v[CPR_FUSE_CORNER_TURBO]);
+	pr_info("ceiling voltage: [%d %d %d] uV\n",
+			cpr_vreg->ceiling_volt[CPR_FUSE_CORNER_SVS],
+			cpr_vreg->ceiling_volt[CPR_FUSE_CORNER_NORMAL],
+			cpr_vreg->ceiling_volt[CPR_FUSE_CORNER_TURBO]);
+	pr_info("floor voltage: [%d %d %d] uV\n",
+			cpr_vreg->floor_volt[CPR_FUSE_CORNER_SVS],
+			cpr_vreg->floor_volt[CPR_FUSE_CORNER_NORMAL],
+			cpr_vreg->floor_volt[CPR_FUSE_CORNER_TURBO]);
 
 	return 0;
 }
@@ -1114,7 +1217,7 @@
 do {									\
 	if (!rc) {							\
 		rc = of_property_read_u32(of_node,			\
-				"qti," cpr_property,			\
+				"qcom," cpr_property,			\
 				cpr_config);				\
 		if (rc) {						\
 			pr_err("Missing " #cpr_property			\
@@ -1127,11 +1230,17 @@
 			       struct cpr_regulator *cpr_vreg)
 {
 	struct device_node *of_node = pdev->dev.of_node;
-	int rc;
+	int i, rc = 0;
 
-	cpr_vreg->vdd_apc = devm_regulator_get(&pdev->dev, "vdd-apc");
-	if (IS_ERR_OR_NULL(cpr_vreg->vdd_apc)) {
+	for (i = 0; i < ARRAY_SIZE(vdd_apc_name); i++) {
+		cpr_vreg->vdd_apc = devm_regulator_get(&pdev->dev,
+					vdd_apc_name[i]);
 		rc = PTR_RET(cpr_vreg->vdd_apc);
+		if (!IS_ERR_OR_NULL(cpr_vreg->vdd_apc))
+			break;
+	}
+
+	if (rc) {
 		if (rc != -EPROBE_DEFER)
 			pr_err("devm_regulator_get: rc=%d\n", rc);
 		return rc;
@@ -1151,24 +1260,36 @@
 
 	/* Parse dependency parameters */
 	if (cpr_vreg->vdd_mx) {
-		rc = of_property_read_u32(of_node, "qti,vdd-mx-vmax",
+		rc = of_property_read_u32(of_node, "qcom,vdd-mx-vmax",
 				 &cpr_vreg->vdd_mx_vmax);
 		if (rc < 0) {
 			pr_err("vdd-mx-vmax missing: rc=%d\n", rc);
 			return rc;
 		}
 
-		rc = of_property_read_u32(of_node, "qti,vdd-mx-vmin-method",
+		rc = of_property_read_u32(of_node, "qcom,vdd-mx-vmin-method",
 				 &cpr_vreg->vdd_mx_vmin_method);
 		if (rc < 0) {
 			pr_err("vdd-mx-vmin-method missing: rc=%d\n", rc);
 			return rc;
 		}
-		if (cpr_vreg->vdd_mx_vmin_method > VDD_MX_VMIN_MX_VMAX) {
+		if (cpr_vreg->vdd_mx_vmin_method > VDD_MX_VMIN_APC_CORNER_MAP) {
 			pr_err("Invalid vdd-mx-vmin-method(%d)\n",
 				cpr_vreg->vdd_mx_vmin_method);
 			return -EINVAL;
 		}
+
+		rc = of_property_read_u32_array(of_node,
+					"qcom,vdd-mx-corner-map",
+					&cpr_vreg->vdd_mx_corner_map[1],
+					CPR_FUSE_CORNER_MAX - 1);
+		if (rc && cpr_vreg->vdd_mx_vmin_method ==
+			VDD_MX_VMIN_APC_CORNER_MAP) {
+			pr_err("qcom,vdd-mx-corner-map missing: rc=%d\n",
+				rc);
+			return rc;
+		}
+
 	}
 
 	return 0;
@@ -1191,16 +1312,251 @@
 	int rc, i;
 
 	rc = of_property_read_u32_array(of_node,
-			"qti,cpr-uplift-quotient", delta_quot, 3);
+			"qcom,cpr-uplift-quotient", delta_quot, 3);
 	if (rc < 0) {
 		pr_err("cpr-uplift-quotient is missing: %d", rc);
 		return rc;
 	}
-	for (i = CPR_CORNER_SVS; i < CPR_CORNER_MAX; i++)
+	for (i = CPR_FUSE_CORNER_SVS; i < CPR_FUSE_CORNER_MAX; i++)
 		cpr_vreg->cpr_fuse_target_quot[i] += delta_quot[i-1];
 	return rc;
 }
 
+static void cpr_parse_pvs_version_fuse(struct cpr_regulator *cpr_vreg,
+				struct device_node *of_node)
+{
+	int rc;
+	u64 fuse_bits;
+	u32 fuse_sel[4];
+
+	rc = of_property_read_u32_array(of_node,
+			"qcom,pvs-version-fuse-sel", fuse_sel, 4);
+	if (!rc) {
+		fuse_bits = cpr_read_efuse_row(cpr_vreg,
+				fuse_sel[0], fuse_sel[3]);
+		cpr_vreg->pvs_version = (fuse_bits >> fuse_sel[1]) &
+			((1 << fuse_sel[2]) - 1);
+		pr_info("[row: %d]: 0x%llx, pvs_version = %d\n",
+				fuse_sel[0], fuse_bits, cpr_vreg->pvs_version);
+	} else {
+		cpr_vreg->pvs_version = UINT_MAX;
+	}
+}
+
+/*
+ * cpr_get_corner_quot_adjustment() -- get the quot_adjust for each corner.
+ *
+ * Get the corner to fuse corner (SVS/NORMAL/TURBO) mappings and corner to
+ * APC clock frequency mappings from device tree.
+ * Calculate the quotient adjustment scaling factor for those corners mapping
+ * to the TURBO fuse corner.
+ * Calculate the quotient adjustment for each corner which map to the TURBO
+ * fuse corner.
+ */
+static int cpr_get_corner_quot_adjustment(struct cpr_regulator *cpr_vreg,
+					struct device *dev)
+{
+	int rc = 0;
+	int i, size;
+	struct property *prop;
+	bool corners_mapped;
+	u32 *tmp, *freq_mappings = NULL;
+	u32 scaling, max_factor;
+	u32 corner, turbo_corner = 0, normal_corner = 0, svs_corner = 0;
+	u32 freq_turbo, freq_normal, freq_corner;
+
+	prop = of_find_property(dev->of_node, "qcom,cpr-corner-map", NULL);
+
+	if (prop) {
+		size = prop->length / sizeof(u32);
+		corners_mapped = true;
+	} else {
+		size = CPR_FUSE_CORNER_MAX - 1;
+		corners_mapped = false;
+	}
+
+	cpr_vreg->corner_map = devm_kzalloc(dev, sizeof(int) * (size + 1),
+					GFP_KERNEL);
+	if (!cpr_vreg->corner_map) {
+		pr_err("Can't allocate memory for cpr_vreg->corner_map\n");
+		return -ENOMEM;
+	}
+	cpr_vreg->num_corners = size;
+
+	cpr_vreg->quot_adjust = devm_kzalloc(dev,
+			sizeof(u32) * (cpr_vreg->num_corners + 1),
+			GFP_KERNEL);
+	if (!cpr_vreg->quot_adjust) {
+		pr_err("Can't allocate memory for cpr_vreg->quot_adjust\n");
+		return -ENOMEM;
+	}
+
+	if (!corners_mapped) {
+		for (i = CPR_FUSE_CORNER_SVS; i < CPR_FUSE_CORNER_MAX; i++)
+			cpr_vreg->corner_map[i] = i;
+		return 0;
+	} else {
+		rc = of_property_read_u32_array(dev->of_node,
+			"qcom,cpr-corner-map", &cpr_vreg->corner_map[1], size);
+
+		if (rc) {
+			pr_err("qcom,cpr-corner-map missing, rc = %d\n", rc);
+			return rc;
+		}
+	}
+
+	prop = of_find_property(dev->of_node,
+			"qcom,cpr-speed-bin-max-corners", NULL);
+	if (!prop) {
+		cpr_debug("qcom,cpr-speed-bin-max-corner missing\n");
+		return 0;
+	}
+
+	size = prop->length / sizeof(u32);
+	tmp = kzalloc(size * sizeof(u32), GFP_KERNEL);
+	if (!tmp) {
+		pr_err("memory alloc failed\n");
+		return -ENOMEM;
+	}
+	rc = of_property_read_u32_array(dev->of_node,
+		"qcom,cpr-speed-bin-max-corners", tmp, size);
+	if (rc < 0) {
+		kfree(tmp);
+		pr_err("get cpr-speed-bin-max-corners failed, rc = %d\n", rc);
+		return rc;
+	}
+
+	cpr_parse_pvs_version_fuse(cpr_vreg, dev->of_node);
+
+	/*
+	 * According to speed_bin && pvs_version, get the maximum
+	 * corner corresponding to SVS/NORMAL/TURBO fuse corner.
+	 */
+	for (i = 0; i < size; i += 5) {
+		if (tmp[i] == cpr_vreg->speed_bin &&
+			tmp[i + 1] == cpr_vreg->pvs_version) {
+			svs_corner = tmp[i + 2];
+			normal_corner = tmp[i + 3];
+			turbo_corner = tmp[i + 4];
+			break;
+		}
+	}
+	kfree(tmp);
+	/*
+	 * Return success if the virtual corner values read from
+	 * qcom,cpr-speed-bin-max-corners property are incorrect,
+	 * which make sure the driver could continue run without
+	 * error.
+	 */
+	if (turbo_corner <= normal_corner ||
+			turbo_corner > cpr_vreg->num_corners) {
+		cpr_debug("turbo:%d should be larger than normal:%d\n",
+				turbo_corner, normal_corner);
+		return 0;
+	}
+
+	prop = of_find_property(dev->of_node,
+			"qcom,cpr-corner-frequency-map", NULL);
+	if (!prop) {
+		cpr_debug("qcom,cpr-corner-frequency-map missing\n");
+		return 0;
+	}
+
+	size = prop->length / sizeof(u32);
+	tmp = kzalloc(sizeof(u32) * size, GFP_KERNEL);
+	if (!tmp) {
+		pr_err("memory alloc failed\n");
+		return -ENOMEM;
+	}
+	rc = of_property_read_u32_array(dev->of_node,
+		"qcom,cpr-corner-frequency-map", tmp, size);
+	if (rc < 0) {
+		pr_err("get cpr-corner-frequency-map failed, rc = %d\n", rc);
+		kfree(tmp);
+		return rc;
+	}
+	freq_mappings = kzalloc(sizeof(u32) * (cpr_vreg->num_corners + 1),
+			GFP_KERNEL);
+	if (!freq_mappings) {
+		pr_err("memory alloc for freq_mappings failed!\n");
+		kfree(tmp);
+		return -ENOMEM;
+	}
+	for (i = 0; i < size; i += 2) {
+		corner = tmp[i];
+		if ((corner < 1) || (corner > cpr_vreg->num_corners)) {
+			pr_err("corner should be in 1~%d range: %d\n",
+					cpr_vreg->num_corners, corner);
+			continue;
+		}
+		freq_mappings[corner] = tmp[i + 1];
+		cpr_debug("Frequency at virtual corner %d is %d Hz.\n",
+				corner, freq_mappings[corner]);
+	}
+	kfree(tmp);
+
+	rc = of_property_read_u32(dev->of_node,
+		"qcom,cpr-quot-adjust-scaling-factor-max",
+		&max_factor);
+	if (rc < 0) {
+		cpr_debug("get cpr-quot-adjust-scaling-factor-max failed\n");
+		kfree(freq_mappings);
+		return 0;
+	}
+
+	/*
+	 * Get the quot adjust scaling factor, according to:
+	 * scaling =
+	 * min(1000 * (QUOT(fused @turbo) - QUOT(fused @normal)) /
+	 * (freq_turbo - freq_normal), max_factor)
+	 *
+	 * @QUOT(fused @turbo): quotient read from fuse for TURBO fuse corner;
+	 * @QUOT(fused @normal): quotient read from fuse for NORMAL fuse corner;
+	 * @freq_turbo: MHz, max frequency running at TURBO fuse corner;
+	 * @freq_normal: MHz, max frequency running at NORMAL fuse corner.
+	 */
+
+	freq_turbo = freq_mappings[turbo_corner];
+	freq_normal = freq_mappings[normal_corner];
+	if (freq_normal == 0 || freq_turbo <= freq_normal) {
+		pr_err("freq_turbo: %d should larger than freq_normal: %d\n",
+				freq_turbo, freq_normal);
+		kfree(freq_mappings);
+		return -EINVAL;
+	}
+	freq_turbo /= 1000000;	/* MHz */
+	freq_normal /= 1000000;
+	scaling = 1000 *
+		(cpr_vreg->cpr_fuse_target_quot[CPR_FUSE_CORNER_TURBO] -
+		cpr_vreg->cpr_fuse_target_quot[CPR_FUSE_CORNER_NORMAL]) /
+		(freq_turbo - freq_normal);
+	scaling = min(scaling, max_factor);
+	pr_info("quotient adjustment scaling factor: %d.%03d\n",
+			scaling / 1000, scaling % 1000);
+
+	/*
+	 * Walk through the corners mapped to the TURBO fuse corner and
+	 * calculate the quotient adjustment for each one using the following
+	 * formula:
+	 * quot_adjust = (freq_turbo - freq_corner) * scaling / 1000
+	 *
+	 * @freq_turbo: MHz, max frequency running at TURBO fuse corner;
+	 * @freq_corner: MHz, frequency running at a corner.
+	 */
+	for (i = turbo_corner; i > normal_corner; i--) {
+		freq_corner = freq_mappings[i] / 1000000; /* MHz */
+		if (freq_corner > 0) {
+			cpr_vreg->quot_adjust[i] =
+				scaling * (freq_turbo - freq_corner) / 1000;
+		}
+		pr_info("adjusted quotient[%d] = %d\n", i,
+			(cpr_vreg->cpr_fuse_target_quot[cpr_vreg->corner_map[i]]
+				- cpr_vreg->quot_adjust[i]));
+	}
+	kfree(freq_mappings);
+	return 0;
+}
+
 static int __devinit cpr_init_cpr_efuse(struct platform_device *pdev,
 				     struct cpr_regulator *cpr_vreg)
 {
@@ -1211,12 +1567,13 @@
 	char *targ_quot_str, *ro_sel_str;
 	u32 cpr_fuse_row[2];
 	u32 bp_cpr_disable, bp_scheme;
-	int bp_target_quot[CPR_CORNER_MAX];
-	int bp_ro_sel[CPR_CORNER_MAX];
+	int bp_target_quot[CPR_FUSE_CORNER_MAX];
+	int bp_ro_sel[CPR_FUSE_CORNER_MAX];
 	u32 ro_sel, val;
 	u64 fuse_bits, fuse_bits_2;
+	u32 quot_adjust[CPR_FUSE_CORNER_MAX];
 
-	rc = of_property_read_u32_array(of_node, "qti,cpr-fuse-redun-sel",
+	rc = of_property_read_u32_array(of_node, "qcom,cpr-fuse-redun-sel",
 					cpr_fuse_redun_sel, 5);
 	if (rc < 0) {
 		pr_err("cpr-fuse-redun-sel missing: rc=%d\n", rc);
@@ -1227,24 +1584,24 @@
 
 	if (redundant) {
 		rc = of_property_read_u32_array(of_node,
-				"qti,cpr-fuse-redun-row",
+				"qcom,cpr-fuse-redun-row",
 				cpr_fuse_row, 2);
-		targ_quot_str = "qti,cpr-fuse-redun-target-quot";
-		ro_sel_str = "qti,cpr-fuse-redun-ro-sel";
+		targ_quot_str = "qcom,cpr-fuse-redun-target-quot";
+		ro_sel_str = "qcom,cpr-fuse-redun-ro-sel";
 	} else {
 		rc = of_property_read_u32_array(of_node,
-				"qti,cpr-fuse-row",
+				"qcom,cpr-fuse-row",
 				cpr_fuse_row, 2);
-		targ_quot_str = "qti,cpr-fuse-target-quot";
-		ro_sel_str = "qti,cpr-fuse-ro-sel";
+		targ_quot_str = "qcom,cpr-fuse-target-quot";
+		ro_sel_str = "qcom,cpr-fuse-ro-sel";
 	}
 	if (rc)
 		return rc;
 
 	rc = of_property_read_u32_array(of_node,
 		targ_quot_str,
-		&bp_target_quot[CPR_CORNER_SVS],
-		CPR_CORNER_MAX - CPR_CORNER_SVS);
+		&bp_target_quot[CPR_FUSE_CORNER_SVS],
+		CPR_FUSE_CORNER_MAX - CPR_FUSE_CORNER_SVS);
 	if (rc < 0) {
 		pr_err("missing %s: rc=%d\n", targ_quot_str, rc);
 		return rc;
@@ -1252,8 +1609,8 @@
 
 	rc = of_property_read_u32_array(of_node,
 		ro_sel_str,
-		&bp_ro_sel[CPR_CORNER_SVS],
-		CPR_CORNER_MAX - CPR_CORNER_SVS);
+		&bp_ro_sel[CPR_FUSE_CORNER_SVS],
+		CPR_FUSE_CORNER_MAX - CPR_FUSE_CORNER_SVS);
 	if (rc < 0) {
 		pr_err("missing %s: rc=%d\n", ro_sel_str, rc);
 		return rc;
@@ -1266,7 +1623,7 @@
 
 	if (redundant) {
 		if (of_property_read_bool(of_node,
-				"qti,cpr-fuse-redun-bp-cpr-disable")) {
+				"qcom,cpr-fuse-redun-bp-cpr-disable")) {
 			CPR_PROP_READ_U32(of_node,
 					  "cpr-fuse-redun-bp-cpr-disable",
 					  &bp_cpr_disable, rc);
@@ -1285,7 +1642,7 @@
 			CPR_PROP_READ_U32(of_node, "cpr-fuse-bp-scheme",
 					  &bp_scheme, rc);
 			rc = of_property_read_u32_array(of_node,
-					"qti,cpr-fuse-row",
+					"qcom,cpr-fuse-row",
 					temp_row, 2);
 			if (rc)
 				return rc;
@@ -1311,7 +1668,7 @@
 	pr_info("disable = %d, local = %d\n",
 		cpr_vreg->cpr_fuse_disable, cpr_vreg->cpr_fuse_local);
 
-	for (i = CPR_CORNER_SVS; i < CPR_CORNER_MAX; i++) {
+	for (i = CPR_FUSE_CORNER_SVS; i < CPR_FUSE_CORNER_MAX; i++) {
 		ro_sel = (fuse_bits >> bp_ro_sel[i])
 				& CPR_FUSE_RO_SEL_BITS_MASK;
 		val = (fuse_bits >> bp_target_quot[i])
@@ -1322,14 +1679,28 @@
 			i, ro_sel, val);
 	}
 
+	rc = of_property_read_u32_array(of_node, "qcom,cpr-quotient-adjustment",
+				&quot_adjust[1], CPR_FUSE_CORNER_MAX - 1);
+	if (!rc) {
+		for (i = CPR_FUSE_CORNER_SVS; i < CPR_FUSE_CORNER_MAX; i++) {
+			cpr_vreg->cpr_fuse_target_quot[i] += quot_adjust[i];
+			pr_info("Corner[%d]: adjusted target quot = %d\n",
+				i, cpr_vreg->cpr_fuse_target_quot[i]);
+		}
+	}
+
 	if (cpr_vreg->flags & FLAGS_UPLIFT_QUOT_VOLT) {
 		cpr_voltage_uplift_wa_inc_quot(cpr_vreg, of_node);
-		for (i = CPR_CORNER_SVS; i < CPR_CORNER_MAX; i++) {
+		for (i = CPR_FUSE_CORNER_SVS; i < CPR_FUSE_CORNER_MAX; i++) {
 			pr_info("Corner[%d]: uplifted target quot = %d\n",
 				i, cpr_vreg->cpr_fuse_target_quot[i]);
 		}
 	}
 
+	rc = cpr_get_corner_quot_adjustment(cpr_vreg, &pdev->dev);
+	if (rc)
+		return rc;
+
 	cpr_vreg->cpr_fuse_bits = fuse_bits;
 	if (!cpr_vreg->cpr_fuse_bits) {
 		cpr_vreg->cpr_fuse_disable = 1;
@@ -1339,10 +1710,12 @@
 		int *quot = cpr_vreg->cpr_fuse_target_quot;
 		bool valid_fuse = true;
 
-		if ((quot[CPR_CORNER_TURBO] > quot[CPR_CORNER_NORMAL]) &&
-		    (quot[CPR_CORNER_NORMAL] > quot[CPR_CORNER_SVS])) {
-			if ((quot[CPR_CORNER_TURBO] -
-			     quot[CPR_CORNER_NORMAL])
+		if ((quot[CPR_FUSE_CORNER_TURBO] >
+			quot[CPR_FUSE_CORNER_NORMAL]) &&
+		    (quot[CPR_FUSE_CORNER_NORMAL] >
+			quot[CPR_FUSE_CORNER_SVS])) {
+			if ((quot[CPR_FUSE_CORNER_TURBO] -
+			     quot[CPR_FUSE_CORNER_NORMAL])
 					<= CPR_FUSE_MIN_QUOT_DIFF)
 				valid_fuse = false;
 		} else {
@@ -1358,18 +1731,19 @@
 	return 0;
 }
 
-static int __devinit cpr_init_cpr_voltages(struct cpr_regulator *cpr_vreg)
+static int __devinit cpr_init_cpr_voltages(struct cpr_regulator *cpr_vreg,
+			struct device *dev)
 {
 	int i;
+	int size = cpr_vreg->num_corners + 1;
 
-	/* Construct CPR voltage limits */
-	for (i = CPR_CORNER_SVS; i < CPR_CORNER_MAX; i++) {
-		cpr_vreg->floor_volt[i] =
-			cpr_vreg->pvs_corner_v[APC_PVS_FAST][i];
-		cpr_vreg->ceiling_volt[i] =
-			cpr_vreg->pvs_corner_v[APC_PVS_SLOW][i];
-		cpr_vreg->last_volt[i] =
-			cpr_vreg->pvs_corner_v[cpr_vreg->process][i];
+	cpr_vreg->last_volt = devm_kzalloc(dev, sizeof(int) * size, GFP_KERNEL);
+	if (!cpr_vreg->last_volt)
+		return -EINVAL;
+
+	for (i = 1; i < size; i++) {
+		cpr_vreg->last_volt[i] = cpr_vreg->pvs_corner_v
+						[cpr_vreg->corner_map[i]];
 	}
 
 	return 0;
@@ -1435,7 +1809,7 @@
 		return rc;
 
 	/* Init module parameter with the DT value */
-	cpr_vreg->enable = of_property_read_bool(of_node, "qti,cpr-enable");
+	cpr_vreg->enable = of_property_read_bool(of_node, "qcom,cpr-enable");
 	cpr_enable = (int) cpr_vreg->enable;
 	pr_info("CPR is %s by default.\n",
 		cpr_vreg->enable ? "enabled" : "disabled");
@@ -1469,7 +1843,9 @@
 					    resource_size(res));
 
 	/* Init all voltage set points of APC regulator for CPR */
-	cpr_init_cpr_voltages(cpr_vreg);
+	rc = cpr_init_cpr_voltages(cpr_vreg, &pdev->dev);
+	if (rc)
+		return rc;
 
 	/* Init CPR configuration parameters */
 	rc = cpr_init_cpr_parameters(pdev, cpr_vreg);
@@ -1484,7 +1860,7 @@
 	}
 
 	/* Configure CPR HW but keep it disabled */
-	rc = cpr_config(cpr_vreg);
+	rc = cpr_config(cpr_vreg, &pdev->dev);
 	if (rc)
 		return rc;
 
@@ -1514,12 +1890,12 @@
 	cpr_vreg->efuse_addr = res->start;
 	len = res->end - res->start + 1;
 
-	pr_info("efuse_addr = 0x%x (len=0x%x)\n", res->start, len);
+	pr_info("efuse_addr = %pa (len=0x%x)\n", &res->start, len);
 
 	cpr_vreg->efuse_base = ioremap(cpr_vreg->efuse_addr, len);
 	if (!cpr_vreg->efuse_base) {
-		pr_err("Unable to map efuse_addr 0x%08x\n",
-				cpr_vreg->efuse_addr);
+		pr_err("Unable to map efuse_addr %pa\n",
+				&cpr_vreg->efuse_addr);
 		return -EINVAL;
 	}
 
@@ -1538,12 +1914,12 @@
 	u32 fuse_sel[5];
 	/*
 	 * Restrict all pvs corner voltages to a minimum value of
-	 * qti,cpr-cond-min-voltage if the fuse defined in
-	 * qti,cpr-fuse-cond-min-volt-sel does not read back with
+	 * qcom,cpr-cond-min-voltage if the fuse defined in
+	 * qcom,cpr-fuse-cond-min-volt-sel does not read back with
 	 * the expected value.
 	 */
 	rc = of_property_read_u32_array(of_node,
-			"qti,cpr-fuse-cond-min-volt-sel", fuse_sel, 5);
+			"qcom,cpr-fuse-cond-min-volt-sel", fuse_sel, 5);
 	if (!rc) {
 		if (!cpr_fuse_is_setting_expected(cpr_vreg, fuse_sel))
 			cpr_vreg->flags |= FLAGS_SET_MIN_VOLTAGE;
@@ -1559,7 +1935,7 @@
 	u32 speed_bits;
 
 	rc = of_property_read_u32_array(of_node,
-			"qti,speed-bin-fuse-sel", fuse_sel, 4);
+			"qcom,speed-bin-fuse-sel", fuse_sel, 4);
 
 	if (!rc) {
 		fuse_bits = cpr_read_efuse_row(cpr_vreg,
@@ -1569,6 +1945,8 @@
 		pr_info("[row: %d]: 0x%llx, speed_bits = %d\n",
 				fuse_sel[0], fuse_bits, speed_bits);
 		cpr_vreg->speed_bin = speed_bits;
+	} else {
+		cpr_vreg->speed_bin = UINT_MAX;
 	}
 }
 
@@ -1580,13 +1958,13 @@
 	u32 uplift_speed_bin;
 
 	rc = of_property_read_u32_array(of_node,
-			"qti,cpr-fuse-uplift-sel", fuse_sel, 5);
+			"qcom,cpr-fuse-uplift-sel", fuse_sel, 5);
 	if (!rc) {
 		rc = of_property_read_u32(of_node,
-				"qti,cpr-uplift-speed-bin",
+				"qcom,cpr-uplift-speed-bin",
 				&uplift_speed_bin);
 		if (rc < 0) {
-			pr_err("qti,cpr-uplift-speed-bin missing\n");
+			pr_err("qcom,cpr-uplift-speed-bin missing\n");
 			return rc;
 		}
 		if (cpr_fuse_is_setting_expected(cpr_vreg, fuse_sel)
@@ -1602,33 +1980,22 @@
 					struct cpr_regulator *cpr_vreg)
 {
 	struct device_node *of_node = pdev->dev.of_node;
-	int rc, i, j;
+	int rc, i;
 	u32 min_uv = 0;
 
-	rc = of_property_read_u32_array(of_node,
-		"qti,pvs-corner-ceiling-slow",
-		&cpr_vreg->pvs_corner_v[APC_PVS_SLOW][CPR_CORNER_SVS],
-		CPR_CORNER_MAX - CPR_CORNER_SVS);
+	rc = of_property_read_u32_array(of_node, "qcom,cpr-voltage-ceiling",
+		&cpr_vreg->ceiling_volt[CPR_FUSE_CORNER_SVS],
+		CPR_FUSE_CORNER_MAX - 1);
 	if (rc < 0) {
-		pr_err("pvs-corner-ceiling-slow missing: rc=%d\n", rc);
+		pr_err("cpr-voltage-ceiling missing: rc=%d\n", rc);
 		return rc;
 	}
 
-	rc = of_property_read_u32_array(of_node,
-		"qti,pvs-corner-ceiling-nom",
-		&cpr_vreg->pvs_corner_v[APC_PVS_NOM][CPR_CORNER_SVS],
-		CPR_CORNER_MAX - CPR_CORNER_SVS);
+	rc = of_property_read_u32_array(of_node, "qcom,cpr-voltage-floor",
+		&cpr_vreg->floor_volt[CPR_FUSE_CORNER_SVS],
+		CPR_FUSE_CORNER_MAX - 1);
 	if (rc < 0) {
-		pr_err("pvs-corner-ceiling-norm missing: rc=%d\n", rc);
-		return rc;
-	}
-
-	rc = of_property_read_u32_array(of_node,
-		"qti,pvs-corner-ceiling-fast",
-		&cpr_vreg->pvs_corner_v[APC_PVS_FAST][CPR_CORNER_SVS],
-		CPR_CORNER_MAX - CPR_CORNER_SVS);
-	if (rc < 0) {
-		pr_err("pvs-corner-ceiling-fast missing: rc=%d\n", rc);
+		pr_err("cpr-voltage-floor missing: rc=%d\n", rc);
 		return rc;
 	}
 
@@ -1640,25 +2007,36 @@
 		return rc;
 	}
 	if (cpr_vreg->flags & FLAGS_SET_MIN_VOLTAGE) {
-		of_property_read_u32(of_node, "qti,cpr-cond-min-voltage",
+		of_property_read_u32(of_node, "qcom,cpr-cond-min-voltage",
 					&min_uv);
-		for (i = APC_PVS_SLOW; i < NUM_APC_PVS; i++)
-			for (j = CPR_CORNER_SVS; j < CPR_CORNER_MAX; j++)
-				if (cpr_vreg->pvs_corner_v[i][j] < min_uv)
-					cpr_vreg->pvs_corner_v[i][j] = min_uv;
+		for (i = CPR_FUSE_CORNER_SVS; i < CPR_FUSE_CORNER_MAX; i++)
+			if (cpr_vreg->ceiling_volt[i] < min_uv) {
+				cpr_vreg->ceiling_volt[i] = min_uv;
+				cpr_vreg->floor_volt[i] = min_uv;
+			} else if (cpr_vreg->floor_volt[i] < min_uv) {
+				cpr_vreg->floor_volt[i] = min_uv;
+			}
 	}
 
-	/* Set ceiling max and use it for APC_PVS_NO */
-	cpr_vreg->ceiling_max =
-		cpr_vreg->pvs_corner_v[APC_PVS_SLOW][CPR_CORNER_TURBO];
+	return 0;
+}
 
-	for (i = APC_PVS_SLOW; i < NUM_APC_PVS; i++) {
-		pr_info("[%d] [%d %d %d] uV\n", i,
-			cpr_vreg->pvs_corner_v[i][CPR_CORNER_SVS],
-			cpr_vreg->pvs_corner_v[i][CPR_CORNER_NORMAL],
-			cpr_vreg->pvs_corner_v[i][CPR_CORNER_TURBO]);
+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;
 }
 
@@ -1692,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/cpubw-krait.c b/arch/arm/mach-msm/cpubw-krait.c
deleted file mode 100644
index 4108754..0000000
--- a/arch/arm/mach-msm/cpubw-krait.c
+++ /dev/null
@@ -1,472 +0,0 @@
-/*
- * Copyright (c) 2013, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
-
-#define pr_fmt(fmt) "cpubw-krait: " fmt
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/io.h>
-#include <linux/delay.h>
-#include <linux/ktime.h>
-#include <linux/time.h>
-#include <linux/err.h>
-#include <linux/errno.h>
-#include <linux/mutex.h>
-#include <linux/interrupt.h>
-#include <trace/events/power.h>
-#include <mach/msm_bus.h>
-#include <mach/msm_bus_board.h>
-
-#include <mach/msm-krait-l2-accessors.h>
-
-#define L2PMRESR2		0x412
-#define L2PMCR			0x400
-#define L2PMCNTENCLR		0x402
-#define L2PMCNTENSET		0x403
-#define L2PMINTENCLR		0x404
-#define L2PMINTENSET		0x405
-#define L2PMOVSR		0x406
-#define L2PMOVSSET		0x407
-#define L2PMnEVCNTCR(n)		(0x420 + n * 0x10)
-#define L2PMnEVCNTR(n)		(0x421 + n * 0x10)
-#define L2PMnEVCNTSR(n)		(0x422 + n * 0x10)
-#define L2PMnEVFILTER(n)	(0x423 + n * 0x10)
-#define L2PMnEVTYPER(n)		(0x424 + n * 0x10)
-#define MON_INT			33
-
-#define MBYTE			(1 << 20)
-
-#define BW(_bw) \
-	{ \
-		.vectors = (struct msm_bus_vectors[]){ \
-			{\
-				.src = MSM_BUS_MASTER_AMPSS_M0, \
-				.dst = MSM_BUS_SLAVE_EBI_CH0, \
-			}, \
-			{ \
-				.src = MSM_BUS_MASTER_AMPSS_M1, \
-				.dst = MSM_BUS_SLAVE_EBI_CH0, \
-			}, \
-		}, \
-		.num_paths = 2, \
-	}
-
-/* Has to be a power of 2 to work correctly */
-static unsigned int bytes_per_beat = 8;
-module_param(bytes_per_beat, uint, 0644);
-
-static unsigned int sample_ms = 50;
-module_param(sample_ms, uint, 0644);
-
-static unsigned int tolerance_percent = 10;
-module_param(tolerance_percent, uint, 0644);
-
-static unsigned int guard_band_mbps = 100;
-module_param(guard_band_mbps, uint, 0644);
-
-static unsigned int decay_rate = 90;
-module_param(decay_rate, uint, 0644);
-
-static unsigned int io_percent = 15;
-module_param(io_percent, uint, 0644);
-
-static unsigned int bw_step = 200;
-module_param(bw_step, uint, 0644);
-
-static struct kernel_param_ops enable_ops;
-static bool enable;
-module_param_cb(enable, &enable_ops, &enable, S_IRUGO | S_IWUSR);
-
-static void mon_init(void)
-{
-	/* Set up counters 0/1 to count write/read beats */
-	set_l2_indirect_reg(L2PMRESR2, 0x8B0B0000);
-	set_l2_indirect_reg(L2PMnEVCNTCR(0), 0x0);
-	set_l2_indirect_reg(L2PMnEVCNTCR(1), 0x0);
-	set_l2_indirect_reg(L2PMnEVCNTR(0), 0xFFFFFFFF);
-	set_l2_indirect_reg(L2PMnEVCNTR(1), 0xFFFFFFFF);
-	set_l2_indirect_reg(L2PMnEVFILTER(0), 0xF003F);
-	set_l2_indirect_reg(L2PMnEVFILTER(1), 0xF003F);
-	set_l2_indirect_reg(L2PMnEVTYPER(0), 0xA);
-	set_l2_indirect_reg(L2PMnEVTYPER(1), 0xB);
-}
-
-static void global_mon_enable(bool en)
-{
-	u32 regval;
-
-	/* Global counter enable */
-	regval = get_l2_indirect_reg(L2PMCR);
-	if (en)
-		regval |= BIT(0);
-	else
-		regval &= ~BIT(0);
-	set_l2_indirect_reg(L2PMCR, regval);
-}
-
-static void mon_enable(int n)
-{
-	/* Clear previous overflow state for event counter n */
-	set_l2_indirect_reg(L2PMOVSR, BIT(n));
-
-	/* Enable event counter n */
-	set_l2_indirect_reg(L2PMCNTENSET, BIT(n));
-}
-
-static void mon_disable(int n)
-{
-	/* Disable event counter n */
-	set_l2_indirect_reg(L2PMCNTENCLR, BIT(n));
-}
-
-/* Returns start counter value to be used with mon_get_mbps() */
-static u32 mon_set_limit_mbyte(int n, unsigned int mbytes)
-{
-	u32 regval, beats;
-
-	beats = mult_frac(mbytes, MBYTE, bytes_per_beat);
-	regval = 0xFFFFFFFF - beats;
-	set_l2_indirect_reg(L2PMnEVCNTR(n), regval);
-	pr_debug("EV%d MB: %d, start val: %x\n", n, mbytes, regval);
-
-	return regval;
-}
-
-/* Returns MBps of read/writes for the sampling window. */
-static int mon_get_mbps(int n, u32 start_val, unsigned int us)
-{
-	u32 overflow, count;
-	long long beats;
-
-	count = get_l2_indirect_reg(L2PMnEVCNTR(n));
-	overflow = get_l2_indirect_reg(L2PMOVSR);
-
-	if (overflow & BIT(n))
-		beats = 0xFFFFFFFF - start_val + count;
-	else
-		beats = count - start_val;
-
-	beats *= USEC_PER_SEC;
-	beats *= bytes_per_beat;
-	do_div(beats, us);
-	beats = DIV_ROUND_UP_ULL(beats, MBYTE);
-
-	pr_debug("EV%d ov: %x, cnt: %x\n", n, overflow, count);
-
-	return beats;
-}
-
-static void do_bw_sample(struct work_struct *work);
-static DECLARE_DEFERRED_WORK(bw_sample, do_bw_sample);
-static struct workqueue_struct *bw_sample_wq;
-
-static DEFINE_MUTEX(bw_lock);
-static ktime_t prev_ts;
-static u32 prev_r_start_val;
-static u32 prev_w_start_val;
-
-static struct msm_bus_paths bw_levels[] = {
-	BW(0), BW(200),
-};
-static struct msm_bus_scale_pdata bw_data = {
-	.usecase = bw_levels,
-	.num_usecases = ARRAY_SIZE(bw_levels),
-	.name = "cpubw-krait",
-	.active_only = 1,
-};
-static u32 bus_client;
-static void compute_bw(int mbps);
-static irqreturn_t mon_intr_handler(int irq, void *dev_id);
-
-#define START_LIMIT	100 /* MBps */
-static int start_monitoring(void)
-{
-	int mb_limit;
-	int ret;
-
-	ret = request_threaded_irq(MON_INT, NULL, mon_intr_handler,
-			  IRQF_ONESHOT | IRQF_SHARED | IRQF_TRIGGER_RISING,
-			  "cpubw_krait", mon_intr_handler);
-	if (ret) {
-		pr_err("Unable to register interrupt handler\n");
-		return ret;
-	}
-
-	bw_sample_wq = alloc_workqueue("cpubw-krait", WQ_HIGHPRI, 0);
-	if (!bw_sample_wq) {
-		pr_err("Unable to alloc workqueue\n");
-		ret = -ENOMEM;
-		goto alloc_wq_fail;
-	}
-
-	bus_client = msm_bus_scale_register_client(&bw_data);
-	if (!bus_client) {
-		pr_err("Unable to register bus client\n");
-		ret = -ENODEV;
-		goto bus_reg_fail;
-	}
-
-	compute_bw(START_LIMIT);
-
-	mon_init();
-	mon_disable(0);
-	mon_disable(1);
-
-	mb_limit = mult_frac(START_LIMIT, sample_ms, MSEC_PER_SEC);
-	mb_limit /= 2;
-
-	prev_r_start_val = mon_set_limit_mbyte(0, mb_limit);
-	prev_w_start_val = mon_set_limit_mbyte(1, mb_limit);
-
-	prev_ts = ktime_get();
-
-	set_l2_indirect_reg(L2PMINTENSET, BIT(0));
-	set_l2_indirect_reg(L2PMINTENSET, BIT(1));
-	mon_enable(0);
-	mon_enable(1);
-	global_mon_enable(true);
-
-	queue_delayed_work(bw_sample_wq, &bw_sample,
-				msecs_to_jiffies(sample_ms));
-
-	return 0;
-
-bus_reg_fail:
-	destroy_workqueue(bw_sample_wq);
-alloc_wq_fail:
-	disable_irq(MON_INT);
-	free_irq(MON_INT, mon_intr_handler);
-	return ret;
-}
-
-static void stop_monitoring(void)
-{
-	global_mon_enable(false);
-	mon_disable(0);
-	mon_disable(1);
-	set_l2_indirect_reg(L2PMINTENCLR, BIT(0));
-	set_l2_indirect_reg(L2PMINTENCLR, BIT(1));
-
-	disable_irq(MON_INT);
-	free_irq(MON_INT, mon_intr_handler);
-
-	cancel_delayed_work_sync(&bw_sample);
-	destroy_workqueue(bw_sample_wq);
-
-	bw_levels[0].vectors[0].ib = 0;
-	bw_levels[0].vectors[0].ab = 0;
-	bw_levels[0].vectors[1].ib = 0;
-	bw_levels[0].vectors[1].ab = 0;
-
-	bw_levels[1].vectors[0].ib = 0;
-	bw_levels[1].vectors[0].ab = 0;
-	bw_levels[1].vectors[1].ib = 0;
-	bw_levels[1].vectors[1].ab = 0;
-	msm_bus_scale_unregister_client(bus_client);
-}
-
-static void set_bw(int mbps)
-{
-	static int cur_idx, cur_ab, cur_ib;
-	int new_ab, new_ib;
-	int i, ret;
-
-	if (!io_percent)
-		io_percent = 1;
-	new_ab = roundup(mbps, bw_step);
-	new_ib = mbps * 100 / io_percent;
-	new_ib = roundup(new_ib, bw_step);
-
-	if (cur_ib == new_ib && cur_ab == new_ab)
-		return;
-
-	i = (cur_idx + 1) % ARRAY_SIZE(bw_levels);
-
-	bw_levels[i].vectors[0].ib = new_ib * 1000000ULL;
-	bw_levels[i].vectors[0].ab = new_ab * 1000000ULL;
-	bw_levels[i].vectors[1].ib = new_ib * 1000000ULL;
-	bw_levels[i].vectors[1].ab = new_ab * 1000000ULL;
-
-	pr_debug("BW MBps: Req: %d AB: %d IB: %d\n", mbps, new_ab, new_ib);
-
-	ret = msm_bus_scale_client_update_request(bus_client, i);
-	if (ret)
-		pr_err("bandwidth request failed (%d)\n", ret);
-	else {
-		cur_idx = i;
-		cur_ib = new_ib;
-		cur_ab = new_ab;
-	}
-}
-
-static void compute_bw(int mbps)
-{
-	static int cur_bw;
-	int new_bw;
-
-	mbps += guard_band_mbps;
-
-	if (mbps > cur_bw) {
-		new_bw = mbps;
-	} else {
-		new_bw = mbps * decay_rate + cur_bw * (100 - decay_rate);
-		new_bw /= 100;
-	}
-
-	if (new_bw == cur_bw)
-		return;
-
-	set_bw(new_bw);
-	cur_bw = new_bw;
-}
-
-static int to_limit(int mbps)
-{
-	mbps *= (100 + tolerance_percent) * sample_ms;
-	mbps /= 100;
-	mbps = DIV_ROUND_UP(mbps, MSEC_PER_SEC);
-	return mbps;
-}
-
-static void measure_bw(void)
-{
-	int r_mbps, w_mbps, mbps;
-	ktime_t ts;
-	unsigned int us;
-
-	mutex_lock(&bw_lock);
-
-	/*
-	 * Since we are stopping the counters, we don't want this short work
-	 * to be interrupted by other tasks and cause the measurements to be
-	 * wrong. Not blocking interrupts to avoid affecting interrupt
-	 * latency and since they should be short anyway because they run in
-	 * atomic context.
-	 */
-	preempt_disable();
-
-	ts = ktime_get();
-	us = ktime_to_us(ktime_sub(ts, prev_ts));
-	if (!us)
-		us = 1;
-
-	mon_disable(0);
-	mon_disable(1);
-
-	r_mbps = mon_get_mbps(0, prev_r_start_val, us);
-	w_mbps = mon_get_mbps(1, prev_w_start_val, us);
-
-	prev_r_start_val = mon_set_limit_mbyte(0, to_limit(r_mbps));
-	prev_w_start_val = mon_set_limit_mbyte(1, to_limit(w_mbps));
-
-	mon_enable(0);
-	mon_enable(1);
-
-	preempt_enable();
-
-	mbps = r_mbps + w_mbps;
-	pr_debug("R/W/BW/us = %d/%d/%d/%d\n", r_mbps, w_mbps, mbps, us);
-	compute_bw(mbps);
-
-	prev_ts = ts;
-	mutex_unlock(&bw_lock);
-}
-
-static void do_bw_sample(struct work_struct *work)
-{
-	measure_bw();
-	queue_delayed_work(bw_sample_wq, &bw_sample,
-				msecs_to_jiffies(sample_ms));
-}
-
-static irqreturn_t mon_intr_handler(int irq, void *dev_id)
-{
-	bool pending;
-	u32 regval;
-
-	regval = get_l2_indirect_reg(L2PMOVSR);
-	pr_debug("Got interrupt: %x\n", regval);
-
-	pending = cancel_delayed_work_sync(&bw_sample);
-
-	/*
-	 * Don't recalc bandwidth if the interrupt came just after the end
-	 * of the sample period (!pending). This is done for two reasons:
-	 *
-	 * 1. Sampling the BW during a very short duration can result in a
-	 *    very inaccurate measurement due to very short bursts.
-	 * 2. If the limit was hit very close to the sample period, then the
-	 *    current BW estimate is not very off and can stay as such.
-	 */
-	if (pending)
-		measure_bw();
-
-	queue_delayed_work(bw_sample_wq, &bw_sample,
-				msecs_to_jiffies(sample_ms));
-
-	return IRQ_HANDLED;
-}
-
-static int set_enable(const char *arg, const struct kernel_param *kp)
-{
-	int ret;
-	bool old_val = *((bool *) kp->arg);
-	bool new_val;
-
-	if (!arg)
-		arg = "1";
-	ret = strtobool(arg, &new_val);
-	if (ret)
-		return ret;
-
-	if (!old_val && new_val) {
-		if (start_monitoring()) {
-			pr_err("L2PM counters already in use.\n");
-			return ret;
-		} else {
-			pr_info("Enabling CPU BW monitoring\n");
-		}
-	} else if (old_val && !new_val) {
-		pr_info("Disabling CPU BW monitoring\n");
-		stop_monitoring();
-	}
-
-	*(bool *) kp->arg = new_val;
-	return 0;
-}
-
-static struct kernel_param_ops enable_ops = {
-	.set = set_enable,
-	.get = param_get_bool,
-};
-
-static int cpubw_krait_init(void)
-{
-	bw_sample_wq = alloc_workqueue("cpubw-krait", WQ_HIGHPRI, 0);
-	if (!bw_sample_wq)
-		return -ENOMEM;
-
-	bus_client = msm_bus_scale_register_client(&bw_data);
-	if (!bus_client) {
-		pr_err("Unable to register bus client\n");
-		destroy_workqueue(bw_sample_wq);
-		return -ENODEV;
-	}
-
-	return 0;
-}
-late_initcall(cpubw_krait_init);
-
-MODULE_DESCRIPTION("CPU DDR bandwidth voting driver for Krait CPUs");
-MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/cpufreq.c b/arch/arm/mach-msm/cpufreq.c
index 60856c2..c81720e 100644
--- a/arch/arm/mach-msm/cpufreq.c
+++ b/arch/arm/mach-msm/cpufreq.c
@@ -32,7 +32,7 @@
 #include <linux/platform_device.h>
 #include <trace/events/power.h>
 #include <mach/socinfo.h>
-#include <mach/msm_bus.h>
+#include <mach/cpufreq.h>
 
 #include "acpuclock.h"
 
@@ -47,16 +47,12 @@
 static struct clk *cpu_clk[NR_CPUS];
 static struct clk *l2_clk;
 static unsigned int freq_index[NR_CPUS];
+static unsigned int max_freq_index;
 static struct cpufreq_frequency_table *freq_table;
 static unsigned int *l2_khz;
 static bool is_clk;
 static bool is_sync;
-static struct msm_bus_vectors *bus_vec_lst;
-static struct msm_bus_scale_pdata bus_bw = {
-	.name = "msm-cpufreq",
-	.active_only = 1,
-};
-static u32 bus_client;
+static unsigned long *mem_bw;
 
 struct cpufreq_work_struct {
 	struct work_struct work;
@@ -77,6 +73,11 @@
 
 static DEFINE_PER_CPU(struct cpufreq_suspend_t, cpufreq_suspend);
 
+unsigned long msm_cpufreq_get_bw(void)
+{
+	return mem_bw[max_freq_index];
+}
+
 static void update_l2_bw(int *also_cpu)
 {
 	int rc = 0, cpu;
@@ -98,10 +99,10 @@
 		goto out;
 	}
 
-	if (bus_client)
-		rc = msm_bus_scale_client_update_request(bus_client, index);
+	max_freq_index = index;
+	rc = devfreq_msm_cpufreq_update_bw();
 	if (rc)
-		pr_err("Bandwidth req failed (%d)\n", rc);
+		pr_err("Unable to update BW (%d)\n", rc);
 
 out:
 	mutex_unlock(&l2bw_lock);
@@ -227,6 +228,9 @@
 
 static unsigned int msm_cpufreq_get_freq(unsigned int cpu)
 {
+	if (is_clk && is_sync)
+		cpu = 0;
+
 	if (is_clk)
 		return clk_get_rate(cpu_clk[cpu]) / 1000;
 
@@ -253,6 +257,14 @@
 		|| cpu_is_msm8610() || (is_clk && is_sync))
 		cpumask_setall(policy->cpus);
 
+	cpu_work = &per_cpu(cpufreq_work, policy->cpu);
+	INIT_WORK(&cpu_work->work, set_cpu_work);
+	init_completion(&cpu_work->complete);
+
+	/* synchronous cpus share the same policy */
+	if (is_clk && !cpu_clk[policy->cpu])
+		return 0;
+
 	if (cpufreq_frequency_table_cpuinfo(policy, table)) {
 #ifdef CONFIG_MSM_CPU_FREQ_SET_MIN_MAX
 		policy->cpuinfo.min_freq = CONFIG_MSM_CPU_FREQ_MIN;
@@ -291,10 +303,6 @@
 	policy->cpuinfo.transition_latency =
 		acpuclk_get_switch_time() * NSEC_PER_USEC;
 
-	cpu_work = &per_cpu(cpufreq_work, policy->cpu);
-	INIT_WORK(&cpu_work->work, set_cpu_work);
-	init_completion(&cpu_work->complete);
-
 	return 0;
 }
 
@@ -397,33 +405,14 @@
 };
 
 #define PROP_TBL "qcom,cpufreq-table"
-#define PROP_PORTS "qcom,cpu-mem-ports"
 static int cpufreq_parse_dt(struct device *dev)
 {
-	int ret, len, nf, num_cols = 1, num_paths = 0, i, j, k;
-	u32 *data, *ports = NULL;
-	struct msm_bus_vectors *v = NULL;
+	int ret, len, nf, num_cols = 2, i, j;
+	u32 *data;
 
 	if (l2_clk)
 		num_cols++;
 
-	/* Parse optional bus ports parameter */
-	if (of_find_property(dev->of_node, PROP_PORTS, &len)) {
-		len /= sizeof(*ports);
-		if (len % 2)
-			return -EINVAL;
-
-		ports = devm_kzalloc(dev, len * sizeof(*ports), GFP_KERNEL);
-		if (!ports)
-			return -ENOMEM;
-		ret = of_property_read_u32_array(dev->of_node, PROP_PORTS,
-						 ports, len);
-		if (ret)
-			return ret;
-		num_paths = len / 2;
-		num_cols++;
-	}
-
 	/* Parse CPU freq -> L2/Mem BW map table. */
 	if (!of_find_property(dev->of_node, PROP_TBL, &len))
 		return -EINVAL;
@@ -444,7 +433,9 @@
 	/* Allocate all data structures. */
 	freq_table = devm_kzalloc(dev, (nf + 1) * sizeof(*freq_table),
 				  GFP_KERNEL);
-	if (!freq_table)
+	mem_bw = devm_kzalloc(dev, nf * sizeof(*mem_bw), GFP_KERNEL);
+
+	if (!freq_table || !mem_bw)
 		return -ENOMEM;
 
 	if (l2_clk) {
@@ -453,15 +444,6 @@
 			return -ENOMEM;
 	}
 
-	if (num_paths) {
-		int sz_u = nf * sizeof(*bus_bw.usecase);
-		int sz_v = nf * num_paths * sizeof(*bus_vec_lst);
-		bus_bw.usecase = devm_kzalloc(dev, sz_u, GFP_KERNEL);
-		v = bus_vec_lst = devm_kzalloc(dev, sz_v, GFP_KERNEL);
-		if (!bus_bw.usecase || !bus_vec_lst)
-			return -ENOMEM;
-	}
-
 	j = 0;
 	for (i = 0; i < nf; i++) {
 		unsigned long f;
@@ -504,25 +486,12 @@
 			}
 		}
 
-		if (num_paths) {
-			unsigned int bw_mbps = data[j++];
-			bus_bw.usecase[i].num_paths = num_paths;
-			bus_bw.usecase[i].vectors = v;
-			for (k = 0; k < num_paths; k++) {
-				v->src = ports[k * 2];
-				v->dst = ports[k * 2 + 1];
-				v->ib = bw_mbps * 1000000ULL;
-				v++;
-			}
-		}
+		mem_bw[i] = data[j++];
 	}
 
-	bus_bw.num_usecases = i;
 	freq_table[i].index = i;
 	freq_table[i].frequency = CPUFREQ_TABLE_END;
 
-	if (ports)
-		devm_kfree(dev, ports);
 	devm_kfree(dev, data);
 
 	return 0;
@@ -532,15 +501,12 @@
 static int msm_cpufreq_show(struct seq_file *m, void *unused)
 {
 	unsigned int i, cpu_freq;
-	uint64_t ib;
 
 	if (!freq_table)
 		return 0;
 
 	seq_printf(m, "%10s%10s", "CPU (KHz)", "L2 (KHz)");
-	if (bus_bw.usecase)
-		seq_printf(m, "%12s", "Mem (MBps)");
-	seq_printf(m, "\n");
+	seq_printf(m, "%12s\n", "Mem (MBps)");
 
 	for (i = 0; freq_table[i].frequency != CPUFREQ_TABLE_END; i++) {
 		cpu_freq = freq_table[i].frequency;
@@ -548,11 +514,7 @@
 			continue;
 		seq_printf(m, "%10d", cpu_freq);
 		seq_printf(m, "%10d", l2_khz ? l2_khz[i] : cpu_freq);
-		if (bus_bw.usecase) {
-			ib = bus_bw.usecase[i].vectors[0].ib;
-			do_div(ib, 1000000);
-			seq_printf(m, "%12llu", ib);
-		}
+		seq_printf(m, "%12lu", mem_bw[i]);
 		seq_printf(m, "\n");
 	}
 	return 0;
@@ -602,10 +564,10 @@
 		cpufreq_frequency_table_get_attr(freq_table, cpu);
 	}
 
-	if (bus_bw.usecase) {
-		bus_client = msm_bus_scale_register_client(&bus_bw);
-		if (!bus_client)
-			dev_warn(dev, "Unable to register bus client\n");
+	ret = register_devfreq_msm_cpufreq();
+	if (ret) {
+		pr_err("devfreq governor registration failed\n");
+		return ret;
 	}
 
 	is_clk = true;
diff --git a/arch/arm/mach-msm/devfreq_cpubw.c b/arch/arm/mach-msm/devfreq_cpubw.c
new file mode 100644
index 0000000..20cabc2
--- /dev/null
+++ b/arch/arm/mach-msm/devfreq_cpubw.c
@@ -0,0 +1,221 @@
+/*
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) "cpubw: " fmt
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/ktime.h>
+#include <linux/time.h>
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/mutex.h>
+#include <linux/interrupt.h>
+#include <linux/devfreq.h>
+#include <linux/of.h>
+#include <trace/events/power.h>
+#include <mach/msm_bus.h>
+#include <mach/msm_bus_board.h>
+
+/* Has to be ULL to prevent overflow where this macro is used. */
+#define MBYTE (1ULL << 20)
+#define MAX_PATHS	2
+
+static struct msm_bus_vectors vectors[MAX_PATHS * 2];
+static struct msm_bus_paths bw_levels[] = {
+	{ .vectors = &vectors[0] },
+	{ .vectors = &vectors[MAX_PATHS] },
+};
+static struct msm_bus_scale_pdata bw_data = {
+	.usecase = bw_levels,
+	.num_usecases = ARRAY_SIZE(bw_levels),
+	.name = "devfreq_cpubw",
+	.active_only = 1,
+};
+static int num_paths;
+static u32 bus_client;
+
+static int set_bw(int new_ib, int new_ab)
+{
+	static int cur_idx, cur_ab, cur_ib;
+	int i, ret;
+
+	if (cur_ib == new_ib && cur_ab == new_ab)
+		return 0;
+
+	i = (cur_idx + 1) % ARRAY_SIZE(bw_levels);
+
+	bw_levels[i].vectors[0].ib = new_ib * MBYTE;
+	bw_levels[i].vectors[0].ab = new_ab / num_paths * MBYTE;
+	bw_levels[i].vectors[1].ib = new_ib * MBYTE;
+	bw_levels[i].vectors[1].ab = new_ab / num_paths * MBYTE;
+
+	pr_debug("BW MBps: AB: %d IB: %d\n", new_ab, new_ib);
+
+	ret = msm_bus_scale_client_update_request(bus_client, i);
+	if (ret) {
+		pr_err("bandwidth request failed (%d)\n", ret);
+	} else {
+		cur_idx = i;
+		cur_ib = new_ib;
+		cur_ab = new_ab;
+	}
+
+	return ret;
+}
+
+static void find_freq(struct devfreq_dev_profile *p, unsigned long *freq,
+			u32 flags)
+{
+	int i;
+	unsigned long atmost, atleast, f;
+
+	atmost = p->freq_table[0];
+	atleast = p->freq_table[p->max_state-1];
+	for (i = 0; i < p->max_state; i++) {
+		f = p->freq_table[i];
+		if (f <= *freq)
+			atmost = max(f, atmost);
+		if (f >= *freq)
+			atleast = min(f, atleast);
+	}
+
+	if (flags & DEVFREQ_FLAG_LEAST_UPPER_BOUND)
+		*freq = atmost;
+	else
+		*freq = atleast;
+}
+
+struct devfreq_dev_profile cpubw_profile;
+static long gov_ab;
+
+int cpubw_target(struct device *dev, unsigned long *freq, u32 flags)
+{
+	find_freq(&cpubw_profile, freq, flags);
+	return set_bw(*freq, gov_ab);
+}
+
+static struct devfreq_governor_data gov_data[] = {
+	{ .name = "performance" },
+	{ .name = "powersave" },
+	{ .name = "userspace" },
+	{ .name = "msm_cpufreq" },
+	{ .name = "cpubw_hwmon", .data = &gov_ab },
+};
+
+struct devfreq_dev_profile cpubw_profile = {
+	.polling_ms = 50,
+	.target = cpubw_target,
+	.governor_data = gov_data,
+	.num_governor_data = ARRAY_SIZE(gov_data),
+};
+
+#define PROP_PORTS "qcom,cpu-mem-ports"
+#define PROP_TBL "qcom,bw-tbl"
+
+static int __init cpubw_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct devfreq_dev_profile *p = &cpubw_profile;
+	struct devfreq *df;
+	u32 *data, ports[MAX_PATHS * 2];
+	int ret, len, i;
+
+	if (of_find_property(dev->of_node, PROP_PORTS, &len)) {
+		len /= sizeof(ports[0]);
+		if (len % 2 || len > ARRAY_SIZE(ports)) {
+			dev_err(dev, "Unexpected number of ports\n");
+			return -EINVAL;
+		}
+
+		ret = of_property_read_u32_array(dev->of_node, PROP_PORTS,
+						 ports, len);
+		if (ret)
+			return ret;
+
+		num_paths = len / 2;
+	} else {
+		return -EINVAL;
+	}
+
+	for (i = 0; i < num_paths; i++) {
+		bw_levels[0].vectors[i].src = ports[2 * i];
+		bw_levels[0].vectors[i].dst = ports[2 * i + 1];
+		bw_levels[1].vectors[i].src = ports[2 * i];
+		bw_levels[1].vectors[i].dst = ports[2 * i + 1];
+	}
+	bw_levels[0].num_paths = num_paths;
+	bw_levels[1].num_paths = num_paths;
+
+	if (of_find_property(dev->of_node, PROP_TBL, &len)) {
+		len /= sizeof(*data);
+		data = devm_kzalloc(dev, len * sizeof(*data), GFP_KERNEL);
+		if (!data)
+			return -ENOMEM;
+
+		p->freq_table = devm_kzalloc(dev,
+					     len * sizeof(*p->freq_table),
+					     GFP_KERNEL);
+		if (!p->freq_table)
+			return -ENOMEM;
+
+		ret = of_property_read_u32_array(dev->of_node, PROP_TBL,
+						 data, len);
+		if (ret)
+			return ret;
+
+		for (i = 0; i < len; i++)
+			p->freq_table[i] = data[i];
+		p->max_state = len;
+	}
+
+	bus_client = msm_bus_scale_register_client(&bw_data);
+	if (!bus_client) {
+		dev_err(dev, "Unable to register bus client\n");
+		return -ENODEV;
+	}
+
+	df = devfreq_add_device(dev, &cpubw_profile, "msm_cpufreq", NULL);
+	if (IS_ERR(df)) {
+		msm_bus_scale_unregister_client(bus_client);
+		return PTR_ERR(df);
+	}
+
+	return 0;
+}
+
+static struct of_device_id match_table[] = {
+	{ .compatible = "qcom,cpubw" },
+	{}
+};
+
+static struct platform_driver cpubw_driver = {
+	.driver = {
+		.name = "cpubw",
+		.of_match_table = match_table,
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init cpubw_init(void)
+{
+	platform_driver_probe(&cpubw_driver, cpubw_probe);
+	return 0;
+}
+device_initcall(cpubw_init);
+
+MODULE_DESCRIPTION("CPU DDR bandwidth voting driver MSM CPUs");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/dfe-fsm9xxx.c b/arch/arm/mach-msm/dfe-fsm9xxx.c
index 66272d2..3470710 100644
--- a/arch/arm/mach-msm/dfe-fsm9xxx.c
+++ b/arch/arm/mach-msm/dfe-fsm9xxx.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -50,6 +50,8 @@
 					HH_IRQ_FIFO_SIZE) == \
 					(pdev)->irq_fifo_head)
 
+#define UINT32_MAX  (0xFFFFFFFFU)
+
 static struct hh_dev_node_info {
 	spinlock_t hh_lock;
 	char irq_fifo[HH_IRQ_FIFO_SIZE];
@@ -220,8 +222,9 @@
 				return -EFAULT;
 			if (!HH_OFFSET_VALID(param.offset))
 				return -EINVAL;
-			if (param.num == 0)
-				break;
+			if ((param.num == 0) ||
+			(param.num >= (UINT32_MAX / sizeof(unsigned int))))
+				return -EINVAL;
 			req_sz = sizeof(unsigned int) * param.num;
 
 			if (pdfi->array_num < param.num) {
@@ -270,8 +273,10 @@
 
 			if (copy_from_user(&param, argp, sizeof param))
 				return -EFAULT;
-			if (param.num == 0)
-				break;
+			if ((param.num == 0) ||
+			(param.num >= (UINT32_MAX  /
+			sizeof(struct dfe_command_entry))))
+				return -EINVAL;
 			req_sz = sizeof(struct dfe_command_entry) * param.num;
 
 			if (pdfi->cmd_num < param.num) {
diff --git a/arch/arm/mach-msm/ext-buck-control.c b/arch/arm/mach-msm/ext-buck-control.c
new file mode 100644
index 0000000..e0c349a
--- /dev/null
+++ b/arch/arm/mach-msm/ext-buck-control.c
@@ -0,0 +1,121 @@
+/* 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/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/of_platform.h>
+#include <mach/rpm-smd.h>
+
+#define RPM_REQUEST_TYPE_GPIO  0x6f697067 /* gpio */
+#define RPM_GPIO_NUMB_KEY      0x626d756e /* numb */
+#define RPM_GPIO_STAT_KEY      0x74617473 /* stat */
+#define RPM_GPIO_SETT_KEY      0x74746573 /* sett */
+#define RPM_GPIO_RESOURCE_ID   3
+#define GPIO_ON                1
+#define GPIO_OFF               0
+
+static int msm_send_ext_buck_votes(int gpio_num, int settling_time)
+{
+	int rc;
+	int gpio_status_sleep = GPIO_OFF;
+	int gpio_status_active = GPIO_ON;
+
+	struct msm_rpm_kvp kvp_sleep[] = {
+		{
+			.key = RPM_GPIO_STAT_KEY,
+			.data = (void *)&gpio_status_sleep,
+			.length = sizeof(gpio_status_sleep),
+		}
+	};
+
+	struct msm_rpm_kvp kvp_active[] = {
+		{
+			.key = RPM_GPIO_NUMB_KEY,
+			.data = (void *)&gpio_num,
+			.length = sizeof(gpio_num),
+		},
+		{
+			.key = RPM_GPIO_STAT_KEY,
+			.data = (void *)&gpio_status_active,
+			.length = sizeof(gpio_status_active),
+		},
+		{
+			.key = RPM_GPIO_SETT_KEY,
+			.data = (void *)&settling_time,
+			.length = sizeof(settling_time),
+		},
+	};
+
+	rc = msm_rpm_send_message(MSM_RPM_CTX_ACTIVE_SET,
+		RPM_REQUEST_TYPE_GPIO, RPM_GPIO_RESOURCE_ID, kvp_active,
+							ARRAY_SIZE(kvp_active));
+	WARN(rc < 0, "RPM GPIO toggling (active set) did not enable!\n");
+
+	rc = msm_rpm_send_message(MSM_RPM_CTX_SLEEP_SET,
+		RPM_REQUEST_TYPE_GPIO, RPM_GPIO_RESOURCE_ID, kvp_sleep,
+							ARRAY_SIZE(kvp_sleep));
+	WARN(rc < 0, "RPM GPIO toggling (sleep set) did not enable!\n");
+
+	return rc;
+}
+
+static int msm_ext_buck_probe(struct platform_device *pdev)
+{
+	char *key = NULL;
+	int gpio_num;
+	int settling_time_us;
+	int ret = 0;
+
+	key = "qcom,gpio-num";
+	ret = of_property_read_u32(pdev->dev.of_node, key, &gpio_num);
+	if (ret) {
+		pr_err("%s: Cannot read %s from dt (ret:%d)\n",
+						__func__, key, ret);
+		return ret;
+	}
+
+	key = "qcom,settling-time-us";
+	ret = of_property_read_u32(pdev->dev.of_node, key,
+					&settling_time_us);
+	if (ret) {
+		pr_err("%s: Cannot read %s from dt (ret:%d)\n",
+						__func__, key, ret);
+		return ret;
+	}
+
+	ret = msm_send_ext_buck_votes(gpio_num, settling_time_us);
+
+	return ret;
+}
+
+static struct of_device_id msm_ext_buck_table[] = {
+	{.compatible = "qcom,ext-buck-control"},
+	{},
+};
+
+static struct platform_driver msm_ext_buck_driver = {
+	.probe = msm_ext_buck_probe,
+	.driver = {
+		.name = "ext-buck-control",
+		.owner = THIS_MODULE,
+		.of_match_table = msm_ext_buck_table,
+	},
+};
+
+static int __init msm_ext_buck_init(void)
+{
+	return platform_driver_register(&msm_ext_buck_driver);
+}
+late_initcall(msm_ext_buck_init);
diff --git a/arch/arm/mach-msm/gpiomux.c b/arch/arm/mach-msm/gpiomux.c
index 1f7d56a..06eb6dc 100644
--- a/arch/arm/mach-msm/gpiomux.c
+++ b/arch/arm/mach-msm/gpiomux.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010,2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2010,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
@@ -123,6 +123,11 @@
 }
 EXPORT_SYMBOL(msm_gpiomux_put);
 
+int msm_tlmm_misc_reg_read(enum msm_tlmm_misc_reg misc_reg)
+{
+	return readl_relaxed(MSM_TLMM_BASE + misc_reg);
+}
+
 void msm_tlmm_misc_reg_write(enum msm_tlmm_misc_reg misc_reg, int val)
 {
 	writel_relaxed(val, MSM_TLMM_BASE + misc_reg);
diff --git a/arch/arm/mach-msm/include/mach/board.h b/arch/arm/mach-msm/include/mach/board.h
index 6370bd4..c7f8b74 100644
--- a/arch/arm/mach-msm/include/mach/board.h
+++ b/arch/arm/mach-msm/include/mach/board.h
@@ -27,6 +27,12 @@
 #include <linux/msm_ssbi.h>
 #include <mach/msm_bus.h>
 
+#define WLAN_RF_REG_ADDR_START_OFFSET   0x3
+#define WLAN_RF_REG_DATA_START_OFFSET   0xf
+#define WLAN_RF_READ_REG_CMD            0x3
+#define WLAN_RF_WRITE_REG_CMD           0x2
+#define WLAN_RF_READ_CMD_MASK           0x3fff
+
 struct msm_camera_io_ext {
 	uint32_t mdcphy;
 	uint32_t mdcsz;
@@ -183,7 +189,8 @@
 };
 
 struct msm_camera_gpio_num_info {
-	uint16_t gpio_num[7];
+	uint16_t gpio_num[10];
+	uint8_t valid[10];
 };
 
 struct msm_camera_gpio_conf {
@@ -513,6 +520,10 @@
 /**
  * msm_i2c_platform_data: i2c-qup driver configuration data
  *
+ * @clk_ctl_xfer : When true, the clocks's state (prepare_enable/
+ *       unprepare_disable) is controlled by i2c-transaction's begining and
+ *       ending. When false, the clock's state is controlled by runtime-pm
+ *       events.
  * @active_only when set, votes when system active and removes the vote when
  *       system goes idle (optimises for performance). When unset, voting using
  *       runtime pm (optimizes for power).
@@ -521,6 +532,7 @@
  */
 struct msm_i2c_platform_data {
 	int clk_freq;
+	bool clk_ctl_xfer;
 	uint32_t rmutex;
 	const char *rsl_id;
 	uint32_t pm_lat;
@@ -671,4 +683,5 @@
 extern phys_addr_t msm_shared_ram_phys; /* defined in arch/arm/mach-msm/io.c */
 
 
+u32 wcnss_rf_read_reg(u32 rf_reg_addr);
 #endif
diff --git a/arch/arm/mach-msm/include/mach/camera2.h b/arch/arm/mach-msm/include/mach/camera2.h
index a9da79e..7024045 100644
--- a/arch/arm/mach-msm/include/mach/camera2.h
+++ b/arch/arm/mach-msm/include/mach/camera2.h
@@ -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
@@ -37,12 +37,6 @@
 	S_EXIT
 };
 
-enum cci_i2c_master_t {
-	MASTER_0,
-	MASTER_1,
-	MASTER_MAX,
-};
-
 struct msm_camera_slave_info {
 	uint16_t sensor_slave_addr;
 	uint16_t sensor_id_reg_addr;
@@ -68,19 +62,32 @@
 	uint16_t order;
 };
 
-struct msm_camera_sensor_board_info {
-	const char *sensor_name;
-	struct msm_camera_slave_info *slave_info;
-	struct msm_camera_csi_lane_params *csi_lane_params;
+struct msm_camera_power_ctrl_t {
+	struct device *dev;
+	struct msm_sensor_power_setting *power_setting;
+	uint16_t power_setting_size;
+	struct msm_sensor_power_setting *power_down_setting;
+	uint16_t power_down_setting_size;
+	struct msm_camera_gpio_conf *gpio_conf;
 	struct camera_vreg_t *cam_vreg;
 	int num_vreg;
-	struct msm_camera_sensor_strobe_flash_data *strobe_flash_data;
-	struct msm_camera_gpio_conf *gpio_conf;
-	struct msm_actuator_info *actuator_info;
 	struct msm_camera_i2c_conf *i2c_conf;
+	struct msm_cam_clk_info *clk_info;
+	uint16_t clk_info_size;
+};
+
+struct msm_camera_sensor_board_info {
+	const char *sensor_name;
+	const char *eeprom_name;
+	const char *actuator_name;
+	struct msm_camera_slave_info *slave_info;
+	struct msm_camera_csi_lane_params *csi_lane_params;
+	struct msm_camera_sensor_strobe_flash_data *strobe_flash_data;
+	struct msm_actuator_info *actuator_info;
 	struct msm_sensor_info_t *sensor_info;
-	struct msm_sensor_init_params *sensor_init_params;
 	const char *misc_regulator;
+	struct msm_camera_power_ctrl_t power_info;
+	struct msm_camera_sensor_slave_info *cam_slave_info;
 };
 
 enum msm_camera_i2c_cmd_type {
@@ -112,31 +119,37 @@
 	uint32_t delay;
 };
 
-struct eeprom_memory_map_t {
+struct eeprom_slave_add_t {
+	uint32_t addr;
+};
+
+struct msm_eeprom_memory_map_t {
 	struct eeprom_map_t page;
 	struct eeprom_map_t pageen;
 	struct eeprom_map_t poll;
 	struct eeprom_map_t mem;
+	struct eeprom_slave_add_t saddr;
 };
 
-struct msm_camera_power_ctrl_t {
-	struct device *dev;
-	struct msm_sensor_power_setting *power_setting;
-	uint16_t power_setting_size;
-	struct msm_camera_gpio_conf *gpio_conf;
-	struct camera_vreg_t *cam_vreg;
-	int num_vreg;
-	struct msm_camera_i2c_conf *i2c_conf;
-	struct msm_cam_clk_info *clk_info;
-	uint16_t clk_info_size;
+struct msm_eeprom_memory_block_t {
+	struct msm_eeprom_memory_map_t *map;
+	uint32_t num_map;	/* number of map blocks */
+	uint8_t *mapdata;
+	uint32_t num_data;	/* size of total mapdata */
+};
+
+struct msm_eeprom_mm_t {
+	uint32_t mm_support;
+	uint32_t mm_compression;
+	uint32_t mm_offset;
+	uint32_t mm_size;
 };
 
 struct msm_eeprom_board_info {
 	const char *eeprom_name;
 	uint16_t i2c_slaveaddr;
-	uint32_t num_blocks;
-	struct eeprom_memory_map_t *eeprom_map;
 	struct msm_camera_power_ctrl_t power_info;
+	struct msm_eeprom_mm_t mm_data;
 };
 
 #endif
diff --git a/arch/arm/mach-msm/include/mach/cpufreq.h b/arch/arm/mach-msm/include/mach/cpufreq.h
new file mode 100644
index 0000000..46872d7
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/cpufreq.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2013 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#ifndef __MACH_CPUFREQ_H
+#define __MACH_CPUFREQ_H
+
+#if defined(CONFIG_DEVFREQ_GOV_MSM_CPUFREQ)
+extern int devfreq_msm_cpufreq_update_bw(void);
+extern int register_devfreq_msm_cpufreq(void);
+#else
+static int devfreq_msm_cpufreq_update_bw(void)
+{
+	return 0;
+}
+static int register_devfreq_msm_cpufreq(void)
+{
+	return 0;
+}
+#endif
+
+#if defined(CONFIG_CPU_FREQ_MSM)
+extern unsigned long msm_cpufreq_get_bw(void);
+#else
+extern unsigned long msm_cpufreq_get_bw(void)
+{
+	return ULONG_MAX;
+}
+#endif
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/ecm_ipa.h b/arch/arm/mach-msm/include/mach/ecm_ipa.h
index f6afb2a..cdcb8d8 100644
--- a/arch/arm/mach-msm/include/mach/ecm_ipa.h
+++ b/arch/arm/mach-msm/include/mach/ecm_ipa.h
@@ -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
@@ -40,6 +40,8 @@
  * with ecm_ipa APIs
  * @host_ethaddr: host Ethernet address in network order
  * @device_ethaddr: device Ethernet address in network order
+ * @skip_ep_cfg: boolean field that determines if Apps-processor
+ *  should or should not configure this end-point.
  */
 struct ecm_ipa_params {
 	ecm_ipa_callback ecm_ipa_rx_dp_notify;
@@ -47,6 +49,7 @@
 	u8 host_ethaddr[ETH_ALEN];
 	u8 device_ethaddr[ETH_ALEN];
 	void *private;
+	bool skip_ep_cfg;
 };
 
 
diff --git a/arch/arm/mach-msm/include/mach/gpiomux.h b/arch/arm/mach-msm/include/mach/gpiomux.h
index 122ffaa..2278677 100644
--- a/arch/arm/mach-msm/include/mach/gpiomux.h
+++ b/arch/arm/mach-msm/include/mach/gpiomux.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2011,2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2010-2011,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
@@ -118,8 +118,6 @@
 	TLMM_CDC_HDRV_PULL_CTL = 0x2058,
 };
 
-void msm_tlmm_misc_reg_write(enum msm_tlmm_misc_reg misc_reg, int val);
-
 #ifdef CONFIG_MSM_GPIOMUX
 
 /* Before using gpiomux, initialize the subsystem by telling it how many
@@ -170,6 +168,14 @@
  * should use msm_gpiomux_write.
  */
 void __msm_gpiomux_write(unsigned gpio, struct gpiomux_setting val);
+
+/* Functions that provide an API for drivers to read from and write to
+ * miscellaneous TLMM registers.
+ */
+int msm_tlmm_misc_reg_read(enum msm_tlmm_misc_reg misc_reg);
+
+void msm_tlmm_misc_reg_write(enum msm_tlmm_misc_reg misc_reg, int val);
+
 #else
 static inline int msm_gpiomux_init(size_t ngpio)
 {
@@ -195,5 +201,16 @@
 {
 	return -ENOSYS;
 }
+
+static inline int msm_tlmm_misc_reg_read(enum msm_tlmm_misc_reg misc_reg)
+{
+	return -ENOSYS;
+}
+
+static inline void msm_tlmm_misc_reg_write(enum msm_tlmm_misc_reg misc_reg,
+						int val)
+{
+}
+
 #endif
 #endif
diff --git a/arch/arm/mach-msm/include/mach/iommu.h b/arch/arm/mach-msm/include/mach/iommu.h
index c4db727..0f69a7b 100644
--- a/arch/arm/mach-msm/include/mach/iommu.h
+++ b/arch/arm/mach-msm/include/mach/iommu.h
@@ -86,6 +86,7 @@
  * struct msm_iommu_drvdata - A single IOMMU hardware instance
  * @base:	IOMMU config port base address (VA)
  * @glb_base:	IOMMU config port base address for global register space (VA)
+ * @phys_base:  IOMMU physical base address.
  * @ncb		The number of contexts on this IOMMU
  * @irq:	Interrupt number
  * @clk:	The bus clock for this IOMMU hardware instance
@@ -108,6 +109,7 @@
  */
 struct msm_iommu_drvdata {
 	void __iomem *base;
+	phys_addr_t phys_base;
 	void __iomem *glb_base;
 	int ncb;
 	int ttbr_split;
diff --git a/arch/arm/mach-msm/include/mach/iommu_hw-v1.h b/arch/arm/mach-msm/include/mach/iommu_hw-v1.h
index 04cd441..4509092 100644
--- a/arch/arm/mach-msm/include/mach/iommu_hw-v1.h
+++ b/arch/arm/mach-msm/include/mach/iommu_hw-v1.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
@@ -16,17 +16,19 @@
 #define CTX_SHIFT  12
 #define CTX_OFFSET 0x8000
 
-#define GET_GLOBAL_REG(reg, base) (readl_relaxed((base) + (reg)))
-#define GET_CTX_REG(reg, base, ctx) \
-	(readl_relaxed((base) + CTX_OFFSET + (reg) + ((ctx) << CTX_SHIFT)))
-#define GET_CTX_REG_L(reg, base, ctx) \
-	(readll_relaxed((base) + CTX_OFFSET + (reg) + ((ctx) << CTX_SHIFT)))
+#define CTX_REG(reg, base, ctx) \
+	((base) + CTX_OFFSET + (reg) + ((ctx) << CTX_SHIFT))
+#define GLB_REG(reg, base) \
+	((base) + (reg))
+
+#define GET_GLOBAL_REG(reg, base) (readl_relaxed(GLB_REG(reg, base)))
+#define GET_CTX_REG(reg, base, ctx) (readl_relaxed(CTX_REG(reg, base, ctx)))
+#define GET_CTX_REG_L(reg, base, ctx) (readll_relaxed(CTX_REG(reg, base, ctx)))
 
 #define SET_GLOBAL_REG(reg, base, val)	writel_relaxed((val), ((base) + (reg)))
 
 #define SET_CTX_REG(reg, base, ctx, val) \
-	writel_relaxed((val), \
-		((base) + CTX_OFFSET + (reg) + ((ctx) << CTX_SHIFT)))
+	writel_relaxed((val), (CTX_REG(reg, base, ctx)))
 
 /* Wrappers for numbered registers */
 #define SET_GLOBAL_REG_N(b, n, r, v) SET_GLOBAL_REG((b), ((r) + (n << 2)), (v))
@@ -150,6 +152,11 @@
 				SET_GLOBAL_FIELD(b, MICRO_MMU_CTRL, HALT_REQ, v)
 #define GET_MICRO_MMU_CTRL_IDLE(b) \
 				GET_GLOBAL_FIELD(b, MICRO_MMU_CTRL, IDLE)
+#define SET_MICRO_MMU_CTRL_RESERVED(b, v) \
+				SET_GLOBAL_FIELD(b, MICRO_MMU_CTRL, RESERVED, v)
+
+#define MMU_CTRL_IDLE (MICRO_MMU_CTRL_IDLE_MASK << MICRO_MMU_CTRL_IDLE_SHIFT)
+
 #define SET_PREDICTIONDIS0(b, v) SET_GLOBAL_REG(PREDICTIONDIS0, (b), (v))
 #define SET_PREDICTIONDIS1(b, v) SET_GLOBAL_REG(PREDICTIONDIS1, (b), (v))
 #define SET_S1L1BFBLP0(b, v)     SET_GLOBAL_REG(S1L1BFBLP0, (b), (v))
diff --git a/arch/arm/mach-msm/include/mach/kgsl.h b/arch/arm/mach-msm/include/mach/kgsl.h
index f398652..edfe6b4 100644
--- a/arch/arm/mach-msm/include/mach/kgsl.h
+++ b/arch/arm/mach-msm/include/mach/kgsl.h
@@ -91,6 +91,7 @@
 	struct coresight_device *csdev;
 	struct coresight_platform_data *coresight_pdata;
 	unsigned int chipid;
+	unsigned int pm_qos_latency;
 };
 
 #endif
diff --git a/arch/arm/mach-msm/include/mach/msm-krait-l2-accessors.h b/arch/arm/mach-msm/include/mach/msm-krait-l2-accessors.h
index a35ff4d..5e927cf 100644
--- a/arch/arm/mach-msm/include/mach/msm-krait-l2-accessors.h
+++ b/arch/arm/mach-msm/include/mach/msm-krait-l2-accessors.h
@@ -1,8 +1,5 @@
-#ifndef __ASM_ARCH_MSM_MSM_KRAIT_L2_ACCESSORS_H
-#define __ASM_ARCH_MSM_MSM_KRAIT_L2_ACCESSORS_H
-
 /*
- * Copyright (c) 2011,2012, 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
@@ -14,20 +11,67 @@
  * GNU General Public License for more details.
  */
 
+#ifndef __ASM_ARCH_MSM_MSM_KRAIT_L2_ACCESSORS_H
+#define __ASM_ARCH_MSM_MSM_KRAIT_L2_ACCESSORS_H
+
+#define MAX_L2_PERIOD		((1ULL << 32) - 1)
+#define MAX_KRAIT_L2_CTRS	10
+
+#define PMCR_NUM_EV_SHIFT	11
+#define PMCR_NUM_EV_MASK	0x1f
+
+#define L2_EVT_MASK		0xfffff
+
+#define L2_SLAVE_EV_PREFIX	4
+#define L2_TRACECTR_PREFIX	5
+
+#define L2PMCCNTR		0x409
+#define L2PMCCNTCR		0x408
+#define L2PMCCNTSR		0x40A
+#define L2CYCLE_CTR_BIT		31
+#define L2CYCLE_CTR_RAW_CODE	0xfe
+
+#define L2PMOVSR	0x406
+
+#define L2PMCR			0x400
+#define L2PMCR_RESET_ALL	0x6
+#define L2PMCR_GLOBAL_ENABLE	0x1
+#define L2PMCR_GLOBAL_DISABLE	0x0
+
+#define L2PMCNTENSET	0x403
+#define L2PMCNTENCLR	0x402
+
+#define L2PMINTENSET	0x405
+#define L2PMINTENCLR	0x404
+
+#define IA_L2PMXEVCNTCR_BASE	0x420
+#define IA_L2PMXEVTYPER_BASE	0x424
+#define IA_L2PMRESX_BASE	0x410
+#define IA_L2PMXEVFILTER_BASE	0x423
+#define IA_L2PMXEVCNTR_BASE	0x421
+
+/* event format is -e rsRCCG See get_event_desc() */
+
+#define EVENT_PREFIX_MASK	0xf0000
+#define EVENT_REG_MASK		0x0f000
+#define EVENT_GROUPSEL_MASK	0x0000f
+#define EVENT_GROUPCODE_MASK	0x00ff0
+
+#define EVENT_PREFIX_SHIFT		16
+#define EVENT_REG_SHIFT			12
+#define EVENT_GROUPCODE_SHIFT		4
+
+#define RESRX_VALUE_EN	0x80000000
+
 #ifdef CONFIG_ARCH_MSM_KRAIT
 extern void set_l2_indirect_reg(u32 reg_addr, u32 val);
 extern u32 get_l2_indirect_reg(u32 reg_addr);
-extern u32 set_get_l2_indirect_reg(u32 reg_addr, u32 val);
 #else
 static inline void set_l2_indirect_reg(u32 reg_addr, u32 val) {}
 static inline u32 get_l2_indirect_reg(u32 reg_addr)
 {
 	return 0;
 }
-static inline u32 set_get_l2_indirect_reg(u32 reg_addr, u32 val)
-{
-	return 0;
-}
 #endif
 
 #endif
diff --git a/arch/arm/mach-msm/include/mach/msm_bus.h b/arch/arm/mach-msm/include/mach/msm_bus.h
index ebc43da..57f781f 100644
--- a/arch/arm/mach-msm/include/mach/msm_bus.h
+++ b/arch/arm/mach-msm/include/mach/msm_bus.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2011, 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
@@ -75,6 +75,7 @@
  */
 
 #ifdef CONFIG_MSM_BUS_SCALING
+int __init msm_bus_fabric_init_driver(void);
 uint32_t msm_bus_scale_register_client(struct msm_bus_scale_pdata *pdata);
 int msm_bus_scale_client_update_request(uint32_t cl, unsigned int index);
 void msm_bus_scale_unregister_client(uint32_t cl);
@@ -83,6 +84,8 @@
 int msm_bus_axi_portunhalt(int master_port);
 
 #else
+static inline int __init msm_bus_fabric_init_driver(void) { return 0; }
+
 static inline uint32_t
 msm_bus_scale_register_client(struct msm_bus_scale_pdata *pdata)
 {
diff --git a/arch/arm/mach-msm/include/mach/msm_bus_board.h b/arch/arm/mach-msm/include/mach/msm_bus_board.h
index ef835b8..bc22517 100644
--- a/arch/arm/mach-msm/include/mach/msm_bus_board.h
+++ b/arch/arm/mach-msm/include/mach/msm_bus_board.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
@@ -41,6 +41,7 @@
 	int hw_sel;
 	void *hw_data;
 	uint32_t qos_freq;
+	uint32_t qos_baseoffset;
 	bool virt;
 };
 
diff --git a/arch/arm/mach-msm/include/mach/msm_memory_dump.h b/arch/arm/mach-msm/include/mach/msm_memory_dump.h
index 89df485..13f54bf 100644
--- a/arch/arm/mach-msm/include/mach/msm_memory_dump.h
+++ b/arch/arm/mach-msm/include/mach/msm_memory_dump.h
@@ -27,6 +27,7 @@
 	MSM_ETM3_REG,
 	MSM_TMC0_REG, /* TMC_ETR */
 	MSM_TMC1_REG, /* TMC_ETF */
+	MSM_LOG_BUF,
 	MAX_NUM_CLIENTS,
 };
 
diff --git a/arch/arm/mach-msm/include/mach/msm_qmi_interface.h b/arch/arm/mach-msm/include/mach/msm_qmi_interface.h
index 1641e8c..4bcb0e7 100644
--- a/arch/arm/mach-msm/include/mach/msm_qmi_interface.h
+++ b/arch/arm/mach-msm/include/mach/msm_qmi_interface.h
@@ -172,37 +172,44 @@
  * qmi_connect_to_service() - Connect the QMI handle with a QMI service
  * @handle: QMI handle to be connected with the QMI service.
  * @service_id: Service id to identify the QMI service.
- * @instance_id: Instance id to identify the instance of the QMI service.
+ * @service_vers: Version to identify the compatibility.
+ * @service_ins: Instance id to identify the instance of the QMI service.
  *
  * @return: 0 on success, < 0 on error.
  */
 int qmi_connect_to_service(struct qmi_handle *handle,
-			   uint32_t service_id, uint32_t instance_id);
+			   uint32_t service_id,
+			   uint32_t service_vers,
+			   uint32_t service_ins);
 
 /**
  * qmi_svc_event_notifier_register() - Register a notifier block to receive
  *                                     events regarding a QMI service
  * @service_id: Service ID to identify the QMI service.
- * @instance_id: Instance ID to identify the instance of the QMI service.
+ * @service_vers: Version to identify the compatibility.
+ * @service_ins: Instance ID to identify the instance of the QMI service.
  * @nb: Notifier block used to receive the event.
  *
  * @return: 0 if successfully registered, < 0 on error.
  */
 int qmi_svc_event_notifier_register(uint32_t service_id,
-				    uint32_t instance_id,
+				    uint32_t service_vers,
+				    uint32_t service_ins,
 				    struct notifier_block *nb);
 
 /**
  * qmi_svc_event_notifier_unregister() - Unregister service event
  *                                       notifier block
  * @service_id: Service ID to identify the QMI service.
- * @instance_id: Instance ID to identify the instance of the QMI service.
+ * @service_vers: Version to identify the compatibility.
+ * @service_ins: Instance ID to identify the instance of the QMI service.
  * @nb: Notifier block registered to receive the events.
  *
  * @return: 0 if successfully registered, < 0 on error.
  */
 int qmi_svc_event_notifier_unregister(uint32_t service_id,
-				      uint32_t instance_id,
+				      uint32_t service_vers,
+				      uint32_t service_ins,
 				      struct notifier_block *nb);
 #else
 
@@ -260,20 +267,23 @@
 
 static inline int qmi_connect_to_service(struct qmi_handle *handle,
 					 uint32_t service_id,
-					 uint32_t instance_id)
+					 uint32_t service_vers,
+					 uint32_t service_ins)
 {
 	return -ENODEV;
 }
 
 static inline int qmi_svc_event_notifier_register(uint32_t service_id,
-						  uint32_t instance_id,
+						  uint32_t service_vers,
+						  uint32_t service_ins,
 						  struct notifier_block *nb)
 {
 	return -ENODEV;
 }
 
 static inline int qmi_svc_event_notifier_unregister(uint32_t service_id,
-						    uint32_t instance_id,
+						    uint32_t service_vers,
+						    uint32_t service_ins,
 						    struct notifier_block *nb)
 {
 	return -ENODEV;
diff --git a/arch/arm/mach-msm/include/mach/msm_rtb.h b/arch/arm/mach-msm/include/mach/msm_rtb.h
index 19d171e..b33e8b6 100644
--- a/arch/arm/mach-msm/include/mach/msm_rtb.h
+++ b/arch/arm/mach-msm/include/mach/msm_rtb.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 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
@@ -25,6 +25,8 @@
 	LOGK_HOTPLUG = 4,
 	LOGK_CTXID = 5,
 	LOGK_TIMESTAMP = 6,
+	LOGK_L2CPREAD = 7,
+	LOGK_L2CPWRITE = 8,
 };
 
 #define LOGTYPE_NOPC 0x80
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/ocmem_priv.h b/arch/arm/mach-msm/include/mach/ocmem_priv.h
index 32d58d4..c94fa0e 100644
--- a/arch/arm/mach-msm/include/mach/ocmem_priv.h
+++ b/arch/arm/mach-msm/include/mach/ocmem_priv.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
@@ -206,7 +206,7 @@
 int check_notifier(int);
 const char *get_name(int);
 int get_tz_id(int);
-int ocmem_enable_sec_program(int);
+int ocmem_restore_sec_program(int);
 int ocmem_enable_dump(enum ocmem_client, unsigned long, unsigned long);
 int ocmem_disable_dump(enum ocmem_client, unsigned long, unsigned long);
 int check_id(int);
@@ -226,7 +226,6 @@
 int process_dump(int, struct ocmem_handle *, unsigned long);
 int ocmem_rdm_transfer(int, struct ocmem_map_list *,
 				unsigned long, int);
-int ocmem_clear(unsigned long, unsigned long);
 unsigned long process_quota(int);
 int ocmem_memory_off(int, unsigned long, unsigned long);
 int ocmem_memory_on(int, unsigned long, unsigned long);
diff --git a/arch/arm/mach-msm/include/mach/qcrypto.h b/arch/arm/mach-msm/include/mach/qcrypto.h
index bb8048f..f9608b3 100644
--- a/arch/arm/mach-msm/include/mach/qcrypto.h
+++ b/arch/arm/mach-msm/include/mach/qcrypto.h
@@ -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
@@ -24,6 +24,11 @@
 #define QCRYPTO_CTX_XTS_DU_SIZE_512B	0x00000100
 #define QCRYPTO_CTX_XTS_DU_SIZE_1KB	0x00000200
 
+
+int qcrypto_cipher_set_device(struct ablkcipher_request *req, unsigned int dev);
+int qcrypto_ahash_set_device(struct ahash_request *req, unsigned int dev);
+int qcrypto_aead_set_device(struct aead_request *req, unsigned int dev);
+
 int qcrypto_cipher_set_flag(struct ablkcipher_request *req, unsigned int flags);
 int qcrypto_ahash_set_flag(struct ahash_request *req, unsigned int flags);
 int qcrypto_aead_set_flag(struct aead_request *req, unsigned int flags);
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/include/mach/qdsp6v2/usf.h b/arch/arm/mach-msm/include/mach/qdsp6v2/usf.h
index 9a27fd2..faf50d2 100644
--- a/arch/arm/mach-msm/include/mach/qdsp6v2/usf.h
+++ b/arch/arm/mach-msm/include/mach/qdsp6v2/usf.h
@@ -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
@@ -132,13 +132,6 @@
 	uint8_t *params_data;
 };
 
-/* Input events sources */
-enum us_input_event_src_type {
-	US_INPUT_SRC_PEN,
-	US_INPUT_SRC_FINGER,
-	US_INPUT_SRC_UNDEF
-};
-
 struct us_input_info_type {
 	/* Touch screen dimensions: min & max;for input module */
 	int tsc_x_dim[MIN_MAX_DIM];
@@ -149,12 +142,10 @@
 	int tsc_y_tilt[MIN_MAX_DIM];
 	/* Touch screen pressure limits: min & max; for input module */
 	int tsc_pressure[MIN_MAX_DIM];
-	/* The requested side buttons bitmap */
-	uint16_t req_side_buttons_bitmap;
+	/* The requested buttons bitmap */
+	uint16_t req_buttons_bitmap;
 	/* Bitmap of types of events (USF_X_EVENT), produced by calculator */
 	uint16_t event_types;
-	/* Input event source */
-	enum us_input_event_src_type event_src;
 	/* Bitmap of types of events from devs, conflicting with USF */
 	uint16_t conflicting_event_types;
 };
@@ -179,8 +170,8 @@
 	int inclinations[TILTS_DIM];
 /* [0-1023] (10bits); 0 - pen up */
 	uint32_t pressure;
-/* Bitmap for side button state. 1 - down, 0 - up */
-	uint16_t side_buttons_state_bitmap;
+/* Bitmap for button state. 1 - down, 0 - up */
+	uint16_t buttons_state_bitmap;
 };
 
 /* Mouse buttons, supported by USF */
diff --git a/arch/arm/mach-msm/include/mach/qseecomi.h b/arch/arm/mach-msm/include/mach/qseecomi.h
index 688dea0..cb850c2 100644
--- a/arch/arm/mach-msm/include/mach/qseecomi.h
+++ b/arch/arm/mach-msm/include/mach/qseecomi.h
@@ -1,5 +1,5 @@
 /*
- * 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
@@ -18,13 +18,16 @@
 
 #define QSEECOM_KEY_ID_SIZE   32
 
-#define	QSEOS_RESULT_FAIL_LOAD_KS         -57
-#define	QSEOS_RESULT_FAIL_SAVE_KS         -58
-#define	QSEOS_RESULT_FAIL_MAX_KEYS        -59
-#define	QSEOS_RESULT_FAIL_KEY_ID_EXISTS   -60
-#define	QSEOS_RESULT_FAIL_KEY_ID_DNE      -61
-#define	QSEOS_RESULT_FAIL_KS_OP           -62
-#define	QSEOS_RESULT_FAIL_CE_PIPE_INVALID -63
+#define QSEOS_RESULT_FAIL_UNSUPPORTED_CE_PIPE -63
+#define QSEOS_RESULT_FAIL_KS_OP               -64
+#define QSEOS_RESULT_FAIL_KEY_ID_EXISTS       -65
+#define QSEOS_RESULT_FAIL_MAX_KEYS            -66
+#define QSEOS_RESULT_FAIL_SAVE_KS             -67
+#define QSEOS_RESULT_FAIL_LOAD_KS             -68
+#define QSEOS_RESULT_FAIL_KS_ALREADY_DONE     -69
+#define QSEOS_RESULT_FAIL_KEY_ID_DNE          -70
+#define QSEOS_RESULT_FAIL_INCORRECT_PSWD      -71
+#define QSEOS_RESULT_FAIL_MAX_ATTEMPT         -72
 
 enum qseecom_command_scm_resp_type {
 	QSEOS_APP_ID = 0xEE01,
@@ -52,6 +55,7 @@
 	QSEOS_DELETE_KEY,
 	QSEOS_MAX_KEY_COUNT,
 	QSEOS_SET_KEY,
+	QSEOS_UPDATE_KEY_USERINFO,
 	QSEOS_CMD_MAX     = 0xEFFFFFFF
 };
 
@@ -166,6 +170,7 @@
 	uint32_t qsee_command_id;
 	uint32_t flags;
 	uint8_t key_id[QSEECOM_KEY_ID_SIZE];
+	uint8_t hash32[QSEECOM_HASH_SIZE];
 };
 
 __packed struct qseecom_key_select_ireq {
@@ -175,13 +180,23 @@
 	uint32_t pipe_type;
 	uint32_t flags;
 	uint8_t key_id[QSEECOM_KEY_ID_SIZE];
-	unsigned char hash[QSEECOM_HASH_SIZE];
+	uint8_t hash32[QSEECOM_HASH_SIZE];
 };
 
 __packed struct qseecom_key_delete_ireq {
 	uint32_t qsee_command_id;
 	uint32_t flags;
 	uint8_t key_id[QSEECOM_KEY_ID_SIZE];
+	uint8_t hash32[QSEECOM_HASH_SIZE];
+
+};
+
+__packed struct qseecom_key_userinfo_update_ireq {
+	uint32_t qsee_command_id;
+	uint32_t flags;
+	uint8_t key_id[QSEECOM_KEY_ID_SIZE];
+	uint8_t current_hash32[QSEECOM_HASH_SIZE];
+	uint8_t new_hash32[QSEECOM_HASH_SIZE];
 };
 
 __packed struct qseecom_key_max_count_query_ireq {
@@ -192,10 +207,5 @@
 	uint32_t max_key_count;
 };
 
-struct key_id_info {
-	uint32_t	ce_hw;
-	uint32_t	pipe;
-	bool		flags;
-};
 
 #endif /* __QSEECOMI_H_ */
diff --git a/arch/arm/mach-msm/include/mach/remote_spinlock.h b/arch/arm/mach-msm/include/mach/remote_spinlock.h
index 8c8b821..8ec68a1 100644
--- a/arch/arm/mach-msm/include/mach/remote_spinlock.h
+++ b/arch/arm/mach-msm/include/mach/remote_spinlock.h
@@ -1,4 +1,5 @@
-/* Copyright (c) 2009, 2011, 2013 The Linux Foundation. All rights reserved.
+/* Copyright (c) 2009, 2011, 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 +23,9 @@
 #include <linux/io.h>
 #include <linux/types.h>
 
+#define REMOTE_SPINLOCK_NUM_PID 128
+#define REMOTE_SPINLOCK_TID_START REMOTE_SPINLOCK_NUM_PID
+
 /* Remote spinlock definitions. */
 
 struct dek_spinlock {
@@ -48,6 +52,8 @@
 int _remote_spin_trylock(_remote_spinlock_t *lock);
 int _remote_spin_release(_remote_spinlock_t *lock, uint32_t pid);
 int _remote_spin_owner(_remote_spinlock_t *lock);
+void _remote_spin_lock_rlock_id(_remote_spinlock_t *lock, uint32_t tid);
+void _remote_spin_unlock_rlock(_remote_spinlock_t *lock);
 #else
 static inline
 int _remote_spin_lock_init(remote_spinlock_id_t id, _remote_spinlock_t *lock)
@@ -69,6 +75,9 @@
 {
 	return -ENODEV;
 }
+static inline void _remote_spin_lock_rlock_id(_remote_spinlock_t *lock,
+					      uint32_t tid) {}
+static inline void _remote_spin_unlock_rlock(_remote_spinlock_t *lock) {}
 #endif
 
 
diff --git a/arch/arm/mach-msm/include/mach/socinfo.h b/arch/arm/mach-msm/include/mach/socinfo.h
index 6b3d590..24b5181 100644
--- a/arch/arm/mach-msm/include/mach/socinfo.h
+++ b/arch/arm/mach-msm/include/mach/socinfo.h
@@ -44,6 +44,7 @@
 #define of_board_is_qrd()	of_machine_is_compatible("qcom,qrd")
 #define of_board_is_xpm()	of_machine_is_compatible("qcom,xpm")
 #define of_board_is_skuf()	of_machine_is_compatible("qcom,skuf")
+#define of_board_is_sbc()	of_machine_is_compatible("qcom,sbc")
 
 #define machine_is_msm8974()	of_machine_is_compatible("qcom,msm8974")
 #define machine_is_msm9625()	of_machine_is_compatible("qcom,msm9625")
@@ -75,6 +76,7 @@
 #define of_board_is_qrd()		0
 #define of_board_is_xpm()		0
 #define of_board_is_skuf()		0
+#define of_board_is_sbc()		0
 
 #define machine_is_msm8974()		0
 #define machine_is_msm9625()		0
@@ -136,6 +138,11 @@
 	MSM_CPU_SAMARIUM,
 };
 
+struct msm_soc_info {
+	enum msm_cpu generic_soc_type;
+	char *soc_id_string;
+};
+
 enum pmic_model {
 	PMIC_MODEL_PM8058	= 13,
 	PMIC_MODEL_PM8028	= 14,
diff --git a/arch/arm/mach-msm/include/mach/subsystem_notif.h b/arch/arm/mach-msm/include/mach/subsystem_notif.h
index 5865eff..59e212f 100644
--- a/arch/arm/mach-msm/include/mach/subsystem_notif.h
+++ b/arch/arm/mach-msm/include/mach/subsystem_notif.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, 2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011, 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
@@ -25,6 +25,7 @@
 	SUBSYS_BEFORE_POWERUP,
 	SUBSYS_AFTER_POWERUP,
 	SUBSYS_RAMDUMP_NOTIFICATION,
+	SUBSYS_POWERUP_FAILURE,
 	SUBSYS_NOTIF_TYPE_COUNT
 };
 
diff --git a/arch/arm/mach-msm/include/mach/usbdiag.h b/arch/arm/mach-msm/include/mach/usbdiag.h
index 15f4783..7457993 100644
--- a/arch/arm/mach-msm/include/mach/usbdiag.h
+++ b/arch/arm/mach-msm/include/mach/usbdiag.h
@@ -1,6 +1,6 @@
 /* include/asm-arm/arch-msm/usbdiag.h
  *
- * Copyright (c) 2008-2010, 2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2008-2010, 2012-2013,The Linux Foundation. All rights reserved.
  *
  * All source code in this file is licensed under the following license except
  * where indicated.
@@ -54,7 +54,6 @@
 		void (*notify)(void *, unsigned, struct diag_request *));
 void usb_diag_close(struct usb_diag_ch *ch);
 int usb_diag_alloc_req(struct usb_diag_ch *ch, int n_write, int n_read);
-void usb_diag_free_req(struct usb_diag_ch *ch);
 int usb_diag_read(struct usb_diag_ch *ch, struct diag_request *d_req);
 int usb_diag_write(struct usb_diag_ch *ch, struct diag_request *d_req);
 #else
@@ -71,9 +70,6 @@
 {
 	return -ENODEV;
 }
-static inline void usb_diag_free_req(struct usb_diag_ch *ch)
-{
-}
 static inline
 int usb_diag_read(struct usb_diag_ch *ch, struct diag_request *d_req)
 {
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/krait-regulator.c b/arch/arm/mach-msm/krait-regulator.c
index f4456c0..b0a1a7c 100644
--- a/arch/arm/mach-msm/krait-regulator.c
+++ b/arch/arm/mach-msm/krait-regulator.c
@@ -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
@@ -708,8 +708,10 @@
 
 static int switch_to_using_ldo(struct krait_power_vreg *kvreg)
 {
-	if (kvreg->mode == LDO_MODE
-		&& get_krait_ldo_uv(kvreg) == kvreg->uV - kvreg->ldo_delta_uV)
+	int uV = kvreg->uV - kvreg->ldo_delta_uV;
+	int ldo_uV = DIV_ROUND_UP(uV, KRAIT_LDO_STEP) * KRAIT_LDO_STEP;
+
+	if (kvreg->mode == LDO_MODE && get_krait_ldo_uv(kvreg) == ldo_uV)
 		return 0;
 
 	return smp_call_function_single(kvreg->cpu_num,
@@ -1443,11 +1445,17 @@
 {
 	struct resource *res;
 	void __iomem *efuse;
-	u32 efuse_data, efuse_version;
-	bool scaling_factor_valid, use_efuse;
+	u32 efuse_data, efuse_version, efuse_version_data;
+	bool sf_valid, use_efuse;
+	int sf_pos, sf_mask;
+	struct device_node *node = pdev->dev.of_node;
+	struct device *dev = &pdev->dev;
+	int valid_sfs[4] = {0, 0, 0, 0};
+	int sf_versions_len;
+	int rc;
 
-	use_efuse = of_property_read_bool(pdev->dev.of_node,
-					  "qcom,use-phase-scaling-factor");
+	use_efuse = of_property_read_bool(node,
+				"qcom,use-phase-scaling-factor");
 	/*
 	 * Allow usage of the eFuse phase scaling factor if it is enabled in
 	 * either device tree or by module parameter.
@@ -1462,6 +1470,7 @@
 		return -EINVAL;
 	}
 
+	/* Read efuse registers */
 	efuse = ioremap(res->start, 8);
 	if (!efuse) {
 		pr_err("could not map phase scaling eFuse address\n");
@@ -1469,25 +1478,47 @@
 	}
 
 	efuse_data = readl_relaxed(efuse);
-	efuse_version = readl_relaxed(efuse + 4);
-
+	efuse_version_data = readl_relaxed(efuse + 4);
 	iounmap(efuse);
 
-	scaling_factor_valid
-		= ((efuse_version & PHASE_SCALING_EFUSE_VERSION_MASK) >>
-				PHASE_SCALING_EFUSE_VERSION_POS)
-			== PHASE_SCALING_EFUSE_VERSION_SET;
+	rc = of_property_read_u32(pdev->dev.of_node,
+					"qcom,phase-scaling-factor-bits-pos",
+					&sf_pos);
+	if (rc < 0) {
+		dev_err(dev, "qcom,phase-scaling-factor-bits-pos missing rc=%d\n",
+									rc);
+		return -EINVAL;
+	}
 
-	if (scaling_factor_valid)
+	sf_mask = KRAIT_MASK(sf_pos + 2, sf_pos);
+
+	efuse_version
+		= ((efuse_version_data & PHASE_SCALING_EFUSE_VERSION_MASK) >>
+				PHASE_SCALING_EFUSE_VERSION_POS);
+
+	if (of_find_property(node, "qcom,valid-scaling-factor-versions",
+				&sf_versions_len)
+		&& (sf_versions_len == 4 * sizeof(u32))) {
+		rc = of_property_read_u32_array(node,
+				"qcom,valid-scaling-factor-versions",
+				valid_sfs, 4);
+		sf_valid = (valid_sfs[efuse_version] == 1);
+	} else {
+		dev_err(dev, "qcom,valid-scaling-factor-versions missing or its size is incorrect rc=%d\n",
+									rc);
+		return -EINVAL;
+	}
+
+	if (sf_valid)
 		pvreg->efuse_phase_scaling_factor
-			= ((efuse_data & PHASE_SCALING_EFUSE_VALUE_MASK)
-				>> PHASE_SCALING_EFUSE_VALUE_POS) + 1;
+			= ((efuse_data & sf_mask)
+				>> sf_pos) + 1;
 	else
 		pvreg->efuse_phase_scaling_factor = PHASE_SCALING_REF;
 
 	pr_info("eFuse phase scaling factor = %d/%d%s\n",
 		pvreg->efuse_phase_scaling_factor, PHASE_SCALING_REF,
-		scaling_factor_valid ? "" : " (eFuse not blown)");
+		sf_valid ? "" : " (eFuse not blown)");
 	pr_info("initial phase scaling factor = %d/%d%s\n",
 		use_efuse_phase_scaling_factor
 			? pvreg->efuse_phase_scaling_factor : PHASE_SCALING_REF,
diff --git a/arch/arm/mach-msm/lpm_levels.c b/arch/arm/mach-msm/lpm_levels.c
index b9dcf88..bd28131 100644
--- a/arch/arm/mach-msm/lpm_levels.c
+++ b/arch/arm/mach-msm/lpm_levels.c
@@ -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
@@ -82,6 +82,7 @@
 
 static struct lpm_system_state sys_state;
 static bool suspend_in_progress;
+static int64_t suspend_time;
 
 struct lpm_lookup_table {
 	uint32_t modes;
@@ -212,7 +213,6 @@
 
 	switch (sleep_mode) {
 	case MSM_SPM_L2_MODE_POWER_COLLAPSE:
-		pr_info("Configuring for L2 power collapse\n");
 		msm_pm_set_l2_flush_flag(MSM_SCM_L2_OFF);
 		break;
 	case MSM_SPM_L2_MODE_GDHS:
@@ -272,7 +272,7 @@
 {
 	int best_level = -1;
 	int i;
-	uint32_t best_level_pwr = ~0UL;
+	uint32_t best_level_pwr = ~0U;
 	uint32_t pwr;
 	uint32_t latency_us = pm_qos_request(PM_QOS_CPU_DMA_LATENCY);
 
@@ -342,7 +342,8 @@
 	const struct cpumask *nextcpu;
 
 	spin_lock(&system_state->sync_lock);
-	if (num_powered_cores != system_state->num_cores_in_sync) {
+	if (index < 0 ||
+			num_powered_cores != system_state->num_cores_in_sync) {
 		spin_unlock(&system_state->sync_lock);
 		return;
 	}
@@ -419,7 +420,7 @@
 			system_lvl->num_cpu_votes--;
 	}
 
-	if (!first_core_up)
+	if (!first_core_up || index < 0)
 		goto unlock_and_return;
 
 	if (default_l2_mode != system_state->system_level[index].l2_mode)
@@ -430,6 +431,7 @@
 		msm_mpm_exit_sleep(from_idle);
 	}
 unlock_and_return:
+	system_state->last_entered_cluster_index = -1;
 	spin_unlock(&system_state->sync_lock);
 }
 
@@ -491,7 +493,7 @@
 static noinline int lpm_cpu_power_select(struct cpuidle_device *dev, int *index)
 {
 	int best_level = -1;
-	uint32_t best_level_pwr = ~0UL;
+	uint32_t best_level_pwr = ~0U;
 	uint32_t latency_us = pm_qos_request(PM_QOS_CPU_DMA_LATENCY);
 	uint32_t sleep_us =
 		(uint32_t)(ktime_to_us(tick_nohz_get_sleep_length()));
@@ -525,7 +527,7 @@
 		if (latency_us < pwr->latency_us)
 			continue;
 
-		if (next_event_us)
+		if (next_event_us) {
 			if (next_event_us < pwr->latency_us)
 				continue;
 
@@ -534,6 +536,7 @@
 				next_wakeup_us = next_event_us
 					- pwr->latency_us;
 			}
+		}
 
 		if (next_wakeup_us <= pwr->time_overhead_us)
 			continue;
@@ -543,11 +546,11 @@
 			if (!dev->cpu && msm_rpm_waiting_for_ack())
 					break;
 
-		if ((next_wakeup_us >> 10) > pwr->latency_us) {
+		if ((next_wakeup_us >> 10) > pwr->time_overhead_us) {
 			power = pwr->ss_power;
 		} else {
 			power = pwr->ss_power;
-			power -= (pwr->latency_us * pwr->ss_power)
+			power -= (pwr->time_overhead_us * pwr->ss_power)
 					/ next_wakeup_us;
 			power += pwr->energy_overhead / next_wakeup_us;
 		}
@@ -721,14 +724,11 @@
 	int idx;
 	struct lpm_cpu_level *cpu_level = &system_state->cpu_level[cpu_index];
 
-	cpu_level = &system_state->cpu_level[cpu_index];
-
 	lpm_cpu_prepare(system_state, cpu_index, from_idle);
 
 	idx = lpm_system_select(system_state, cpu_index, from_idle);
 
-	if (idx >= 0)
-		lpm_system_prepare(system_state, idx, from_idle);
+	lpm_system_prepare(system_state, idx, from_idle);
 
 	msm_cpu_pm_enter_sleep(cpu_level->mode, from_idle);
 
@@ -756,7 +756,7 @@
 	do_div(time, 1000);
 	dev->last_residency = (int)time;
 	local_irq_enable();
-	return index;
+	return idx;
 }
 
 static int lpm_suspend_enter(suspend_state_t state)
@@ -780,6 +780,11 @@
 
 static int lpm_suspend_prepare(void)
 {
+	struct timespec ts;
+
+	getnstimeofday(&ts);
+	suspend_time = timespec_to_ns(&ts);
+
 	suspend_in_progress = true;
 	msm_mpm_suspend_prepare();
 	return 0;
@@ -787,6 +792,12 @@
 
 static void lpm_suspend_wake(void)
 {
+	struct timespec ts;
+
+	getnstimeofday(&ts);
+	suspend_time = timespec_to_ns(&ts) - suspend_time;
+	msm_pm_add_stat(MSM_PM_STAT_SUSPEND, suspend_time);
+
 	msm_mpm_suspend_wake();
 	suspend_in_progress = false;
 }
@@ -970,9 +981,8 @@
 			goto fail;
 		}
 
-		if (l->l2_mode == MSM_SPM_L2_MODE_GDHS ||
-				l->l2_mode == MSM_SPM_L2_MODE_POWER_COLLAPSE)
-			l->notify_rpm = true;
+		key = "qcom,send-rpm-sleep-set";
+		l->notify_rpm = of_property_read_bool(node, key);
 
 		if (l->l2_mode >= MSM_SPM_L2_MODE_GDHS)
 			l->sync = true;
@@ -1014,6 +1024,7 @@
 	}
 	sys_state.system_level = level;
 	sys_state.num_system_levels = num_levels;
+	sys_state.last_entered_cluster_index = -1;
 	return ret;
 fail:
 	kfree(level);
diff --git a/arch/arm/mach-msm/mpm-of.c b/arch/arm/mach-msm/mpm-of.c
index 5b351b4..f1bf64f 100644
--- a/arch/arm/mach-msm/mpm-of.c
+++ b/arch/arm/mach-msm/mpm-of.c
@@ -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
@@ -32,6 +32,7 @@
 #include <linux/power_supply.h>
 #include <linux/regulator/consumer.h>
 #include <linux/workqueue.h>
+#include <linux/mutex.h>
 #include <asm/hardware/gic.h>
 #include <asm/arch_timer.h>
 #include <mach/gpio.h>
@@ -530,6 +531,7 @@
 void msm_mpm_exit_sleep(bool from_idle)
 {
 	unsigned long pending;
+	uint32_t *enabled_intr;
 	int i;
 	int k;
 
@@ -538,12 +540,16 @@
 		return;
 	}
 
+	enabled_intr = from_idle ? msm_mpm_enabled_irq :
+						msm_mpm_wake_irq;
+
 	for (i = 0; i < MSM_MPM_REG_WIDTH; i++) {
 		pending = msm_mpm_read(MSM_MPM_REG_STATUS, i);
+		pending &= enabled_intr[i];
 
 		if (MSM_MPM_DEBUG_PENDING_IRQ & msm_mpm_debug_mask)
-			pr_info("%s: pending.%d: 0x%08lx", __func__,
-					i, pending);
+			pr_info("%s: enabled_intr pending.%d: 0x%08x 0x%08lx\n",
+				__func__, i, enabled_intr[i], pending);
 
 		k = find_first_bit(&pending, 32);
 		while (k < 32) {
@@ -567,6 +573,9 @@
 }
 static void msm_mpm_sys_low_power_modes(bool allow)
 {
+	static DEFINE_MUTEX(enable_xo_mutex);
+
+	mutex_lock(&enable_xo_mutex);
 	if (allow) {
 		if (xo_enabled) {
 			clk_disable_unprepare(xo_clk);
@@ -582,6 +591,7 @@
 			xo_enabled = true;
 		}
 	}
+	mutex_unlock(&enable_xo_mutex);
 }
 
 void msm_mpm_suspend_prepare(void)
@@ -673,7 +683,8 @@
 		return -ENXIO;
 	}
 	ret = devm_request_irq(&pdev->dev, dev->mpm_ipc_irq, msm_mpm_irq,
-			IRQF_TRIGGER_RISING, pdev->name, msm_mpm_irq);
+			IRQF_TRIGGER_RISING | IRQF_NO_SUSPEND, pdev->name,
+			msm_mpm_irq);
 
 	if (ret) {
 		pr_info("%s(): request_irq failed errno: %d\n", __func__, ret);
diff --git a/arch/arm/mach-msm/msm-buspm-dev.h b/arch/arm/mach-msm/msm-buspm-dev.h
index a951093..45282c1 100644
--- a/arch/arm/mach-msm/msm-buspm-dev.h
+++ b/arch/arm/mach-msm/msm-buspm-dev.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, 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
@@ -23,7 +23,7 @@
 
 /* Read/write data into kernel buffer */
 struct buspm_xfer_req {
-	int size;		/* Size of this request, in bytes */
+	unsigned int  size;		/* Size of this request, in bytes */
 	void *data;		/* Data buffer to transfer data to/from */
 };
 
diff --git a/arch/arm/mach-msm/msm-krait-l2-accessors.c b/arch/arm/mach-msm/msm-krait-l2-accessors.c
index 7498e7f..0faf112 100644
--- a/arch/arm/mach-msm/msm-krait-l2-accessors.c
+++ b/arch/arm/mach-msm/msm-krait-l2-accessors.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011-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
@@ -13,38 +13,19 @@
 
 #include <linux/spinlock.h>
 #include <linux/module.h>
+#include <mach/msm_rtb.h>
 #include <asm/mach-types.h>
 #include <asm/cputype.h>
 
 DEFINE_RAW_SPINLOCK(l2_access_lock);
 
-u32 set_get_l2_indirect_reg(u32 reg_addr, u32 val)
-{
-	unsigned long flags;
-	u32 ret_val;
-
-	raw_spin_lock_irqsave(&l2_access_lock, flags);
-	mb();
-	asm volatile ("mcr     p15, 3, %[l2cpselr], c15, c0, 6\n\t"
-		      "isb\n\t"
-		      "mcr     p15, 3, %[l2cpdr],   c15, c0, 7\n\t"
-		      "isb\n\t"
-		      "mrc p15, 3, %[l2cpdr_read], c15, c0, 7\n\t"
-			: [l2cpdr_read]"=r" (ret_val)
-			: [l2cpselr]"r" (reg_addr), [l2cpdr]"r" (val)
-	);
-	raw_spin_unlock_irqrestore(&l2_access_lock, flags);
-
-	return ret_val;
-}
-EXPORT_SYMBOL(set_get_l2_indirect_reg);
-
 void set_l2_indirect_reg(u32 reg_addr, u32 val)
 {
 	unsigned long flags;
 
 	raw_spin_lock_irqsave(&l2_access_lock, flags);
 	mb();
+	uncached_logk(LOGK_L2CPWRITE, (void *)reg_addr);
 	asm volatile ("mcr     p15, 3, %[l2cpselr], c15, c0, 6\n\t"
 		      "isb\n\t"
 		      "mcr     p15, 3, %[l2cpdr],   c15, c0, 7\n\t"
@@ -62,6 +43,7 @@
 	unsigned long flags;
 
 	raw_spin_lock_irqsave(&l2_access_lock, flags);
+	uncached_logk(LOGK_L2CPREAD, (void *)reg_addr);
 	asm volatile ("mcr     p15, 3, %[l2cpselr], c15, c0, 6\n\t"
 		      "isb\n\t"
 		      "mrc     p15, 3, %[l2cpdr],   c15, c0, 7\n\t"
diff --git a/arch/arm/mach-msm/msm-pm.c b/arch/arm/mach-msm/msm-pm.c
index fab86d3..cb65a70 100644
--- a/arch/arm/mach-msm/msm-pm.c
+++ b/arch/arm/mach-msm/msm-pm.c
@@ -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
@@ -25,10 +25,12 @@
 #include <linux/platform_device.h>
 #include <linux/of_platform.h>
 #include <linux/cpu_pm.h>
+#include <linux/remote_spinlock.h>
 #include <asm/uaccess.h>
 #include <asm/suspend.h>
 #include <asm/cacheflush.h>
 #include <asm/outercache.h>
+#include <mach/remote_spinlock.h>
 #include <mach/scm.h>
 #include <mach/msm_bus.h>
 #include <mach/jtag.h>
@@ -39,6 +41,7 @@
 #include "scm-boot.h"
 #include "spm.h"
 #include "pm-boot.h"
+#include "clock.h"
 
 #define CREATE_TRACE_POINTS
 #include <mach/trace_msm_low_power.h>
@@ -116,6 +119,12 @@
 DEFINE_PER_CPU(struct clk *, cpu_clks);
 static struct clk *l2_clk;
 
+static int cpu_count;
+static DEFINE_SPINLOCK(cpu_cnt_lock);
+#define SCM_HANDOFF_LOCK_ID "S:7"
+static bool need_scm_handoff_lock;
+static remote_spinlock_t scm_handoff_lock;
+
 static void (*msm_pm_disable_l2_fn)(void);
 static void (*msm_pm_enable_l2_fn)(void);
 static void (*msm_pm_flush_l2_fn)(void);
@@ -452,8 +461,8 @@
 	if (!msm_pc_debug_counters)
 		return;
 
-	cnt = readl_relaxed(msm_pc_debug_counters + cpu * 4 + offset * 4);
-	writel_relaxed(++cnt, msm_pc_debug_counters + cpu * 4 + offset * 4);
+	cnt = readl_relaxed(msm_pc_debug_counters + cpu * 4 * MSM_PC_NUM_COUNTERS + offset * 4);
+	writel_relaxed(++cnt, msm_pc_debug_counters + cpu * 4 * MSM_PC_NUM_COUNTERS + offset * 4);
 	mb();
 }
 
@@ -477,8 +486,30 @@
 static int msm_pm_collapse(unsigned long unused)
 {
 	uint32_t cpu = smp_processor_id();
+	enum msm_pm_l2_scm_flag flag = MSM_SCM_L2_ON;
 
-	if (msm_pm_get_l2_flush_flag() == MSM_SCM_L2_OFF) {
+	spin_lock(&cpu_cnt_lock);
+	cpu_count++;
+	if (cpu_count == num_online_cpus())
+		flag = msm_pm_get_l2_flush_flag();
+
+	pr_debug("cpu:%d cores_in_pc:%d L2 flag: %d\n",
+			cpu, cpu_count, flag);
+
+	/*
+	 * The scm_handoff_lock will be release by the secure monitor.
+	 * It is used to serialize power-collapses from this point on,
+	 * so that both Linux and the secure context have a consistent
+	 * view regarding the number of running cpus (cpu_count).
+	 *
+	 * It must be acquired before releasing cpu_cnt_lock.
+	 */
+	if (need_scm_handoff_lock)
+		remote_spin_lock_rlock_id(&scm_handoff_lock,
+					  REMOTE_SPINLOCK_TID_START + cpu);
+	spin_unlock(&cpu_cnt_lock);
+
+	if (flag == MSM_SCM_L2_OFF) {
 		flush_cache_all();
 		if (msm_pm_flush_l2_fn)
 			msm_pm_flush_l2_fn();
@@ -490,8 +521,7 @@
 
 	msm_pc_inc_debug_count(cpu, MSM_PC_ENTRY_COUNTER);
 
-	scm_call_atomic1(SCM_SVC_BOOT, SCM_CMD_TERMINATE_PC,
-				msm_pm_get_l2_flush_flag());
+	scm_call_atomic1(SCM_SVC_BOOT, SCM_CMD_TERMINATE_PC, flag);
 
 	msm_pc_inc_debug_count(cpu, MSM_PC_FALLTHRU_COUNTER);
 
@@ -533,6 +563,12 @@
 	collapsed = save_cpu_regs ?
 		!cpu_suspend(0, msm_pm_collapse) : msm_pm_pc_hotplug();
 
+	if (save_cpu_regs) {
+		spin_lock(&cpu_cnt_lock);
+		cpu_count--;
+		BUG_ON(cpu_count > num_online_cpus());
+		spin_unlock(&cpu_cnt_lock);
+	}
 	msm_jtag_restore_state();
 
 	if (collapsed) {
@@ -641,6 +677,14 @@
 	if (MSM_PM_DEBUG_POWER_COLLAPSE & msm_pm_debug_mask)
 		pr_info("CPU%u: %s: pre power down\n", cpu, __func__);
 
+	/* This spews a lot of messages when a core is hotplugged. This
+	 * information is most useful from last core going down during
+	 * power collapse
+	 */
+	if ((!from_idle && cpu_online(cpu))
+			|| (MSM_PM_DEBUG_IDLE_CLK & msm_pm_debug_mask))
+		clock_debug_print_enabled();
+
 	avsdscr = avs_get_avsdscr();
 	avscsr = avs_get_avscsr();
 	avs_set_avscsr(0); /* Disable AVS */
@@ -755,17 +799,19 @@
 		pr_info("CPU%u: %s mode:%d\n",
 			smp_processor_id(), __func__, mode);
 
-	time = sched_clock();
+	if (from_idle)
+		time = sched_clock();
+
 	if (execute[mode])
 		exit_stat = execute[mode](from_idle);
-	time = sched_clock() - time;
-	if (from_idle)
+
+	if (from_idle) {
+		time = sched_clock() - time;
 		msm_pm_ftrace_lpm_exit(smp_processor_id(), mode, collapsed);
-	else
-		exit_stat = MSM_PM_STAT_SUSPEND;
-	if (exit_stat >= 0)
-		msm_pm_add_stat(exit_stat, time);
-	do_div(time, 1000);
+		if (exit_stat >= 0)
+			msm_pm_add_stat(exit_stat, time);
+	}
+
 	return collapsed;
 }
 
@@ -777,7 +823,7 @@
 		return 0;
 	if (!msm_pm_slp_sts[cpu].base_addr)
 		return 0;
-	while (timeout--) {
+	while (1) {
 		/*
 		 * Check for the SPM of the core being hotplugged to set
 		 * its sleep state.The SPM sleep state indicates that the
@@ -788,10 +834,9 @@
 		if (acc_sts & msm_pm_slp_sts[cpu].mask)
 			return 0;
 		udelay(100);
+		WARN(++timeout == 20, "CPU%u didn't collapse in 2 ms\n", cpu);
 	}
 
-	pr_info("%s(): Timed out waiting for CPU %u SPM to enter sleep state",
-		__func__, cpu);
 	return -EBUSY;
 }
 
@@ -1158,6 +1203,7 @@
 	struct resource *res = NULL;
 	int i;
 	struct msm_pm_init_data_type pdata_local;
+	struct device_node *lpm_node;
 	int ret = 0;
 
 	memset(&pdata_local, 0, sizeof(struct msm_pm_init_data_type));
@@ -1184,6 +1230,23 @@
 		msm_pc_debug_counters_phys = 0;
 	}
 
+	lpm_node = of_parse_phandle(pdev->dev.of_node, "qcom,lpm-levels", 0);
+	if (!lpm_node) {
+		pr_warn("Could not get qcom,lpm-levels handle\n");
+		return -EINVAL;
+	}
+	need_scm_handoff_lock = of_property_read_bool(lpm_node,
+						      "qcom,allow-synced-levels");
+	if (need_scm_handoff_lock) {
+		ret = remote_spin_lock_init(&scm_handoff_lock,
+					    SCM_HANDOFF_LOCK_ID);
+		if (ret) {
+			pr_err("%s: Failed initializing scm_handoff_lock (%d)\n",
+				__func__, ret);
+			return ret;
+		}
+	}
+
 	if (pdev->dev.of_node) {
 		enum msm_pm_pc_mode_type pc_mode;
 
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_arb.c b/arch/arm/mach-msm/msm_bus/msm_bus_arb.c
index 058e409..72e3ec3 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_arb.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_arb.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
@@ -297,6 +297,21 @@
 	return CREATE_PNODE_ID(src, pnode_num);
 }
 
+static uint64_t get_node_maxib(struct msm_bus_inode_info *info)
+{
+	int i, ctx;
+	uint64_t maxib = 0;
+
+	for (i = 0; i <= info->num_pnodes; i++) {
+		for (ctx = 0; ctx < NUM_CTX; ctx++)
+			maxib = max(info->pnode[i].clk[ctx], maxib);
+	}
+
+	MSM_BUS_DBG("%s: Node %d numpnodes %d maxib %llu", __func__,
+		info->num_pnodes, info->node_info->id, maxib);
+	return maxib;
+}
+
 /**
  * update_path() - Update the path with the bandwidth and clock values, as
  * requested by the client.
@@ -344,15 +359,6 @@
 		return -ENXIO;
 	}
 
-	/**
-	 * If master supports dual configuration, check if
-	 * the configuration needs to be changed based on
-	 * incoming requests
-	 */
-	if (info->node_info->dual_conf)
-		fabdev->algo->config_master(fabdev, info,
-			req_clk, req_bw);
-
 	info->link_info.sel_bw = &info->link_info.bw[ctx];
 	info->link_info.sel_clk = &info->link_info.clk[ctx];
 	*info->link_info.sel_bw += add_bw;
@@ -366,6 +372,19 @@
 	info->pnode[index].sel_clk = &info->pnode[index].clk[ctx &
 		cl_active_flag];
 	*info->pnode[index].sel_bw += add_bw;
+	*info->pnode[index].sel_clk = req_clk;
+
+	/**
+	 * If master supports dual configuration, check if
+	 * the configuration needs to be changed based on
+	 * incoming requests
+	 */
+	if (info->node_info->dual_conf) {
+		uint64_t node_maxib = 0;
+		node_maxib = get_node_maxib(info);
+		fabdev->algo->config_master(fabdev, info,
+			node_maxib, req_bw);
+	}
 
 	info->link_info.num_tiers = info->node_info->num_tiers;
 	info->link_info.tier = info->node_info->tier;
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_bimc.c b/arch/arm/mach-msm/msm_bus/msm_bus_bimc.c
index c745f92..8cb3cf3 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_bimc.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_bimc.c
@@ -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
@@ -1828,6 +1828,53 @@
 		set_qos_mode(baddr, mas_index, 0, 0, 0);
 }
 
+static void bimc_set_static_qos_bw(struct msm_bus_bimc_info *binfo,
+	int mport, struct msm_bus_bimc_qos_bw *qbw)
+{
+	int32_t bw_mbps, thh = 0, thm, thl, gc;
+	int32_t gp;
+	u64 temp;
+
+	if (binfo->qos_freq == 0) {
+		MSM_BUS_DBG("Zero QoS Frequency\n");
+		return;
+	}
+
+	if (!(qbw->bw && qbw->ws)) {
+		MSM_BUS_DBG("No QoS Bandwidth or Window size\n");
+		return;
+	}
+
+	/* Convert bandwidth to MBPS */
+	temp = qbw->bw;
+	bimc_div(&temp, 1000000);
+	bw_mbps = temp;
+
+	/* Grant period in clock cycles
+	 * Grant period from bandwidth structure
+	 * is in nano seconds, QoS freq is in KHz.
+	 * Divide by 1000 to get clock cycles */
+	gp = (binfo->qos_freq * qbw->gp) / (1000 * NSEC_PER_USEC);
+
+	/* Grant count = BW in MBps * Grant period
+	 * in micro seconds */
+	gc = bw_mbps * (qbw->gp / NSEC_PER_USEC);
+
+	/* Medium threshold = -((Medium Threshold percentage *
+	 * Grant count) / 100) */
+	thm = -((qbw->thmp * gc) / 100);
+	qbw->thm = thm;
+
+	/* Low threshold = -(Grant count) */
+	thl = -gc;
+	qbw->thl = thl;
+
+	MSM_BUS_DBG("%s: BKE parameters: gp %d, gc %d, thm %d thl %d thh %d",
+			__func__, gp, gc, thm, thl, thh);
+
+	set_qos_bw_regs(binfo->base, mport, thh, thm, thl, gp, gc);
+}
+
 static void msm_bus_bimc_config_master(
 	struct msm_bus_fabric_registration *fab_pdata,
 	struct msm_bus_inode_info *info,
@@ -1835,6 +1882,7 @@
 {
 	int mode, i, ports;
 	struct msm_bus_bimc_info *binfo;
+	uint64_t bw = 0;
 
 	binfo = (struct msm_bus_bimc_info *)fab_pdata->hw_data;
 	ports = info->node_info->num_mports;
@@ -1843,11 +1891,17 @@
 	 * Here check the details of dual configuration.
 	 * Take actions based on different modes.
 	 * Check for threshold if limiter mode, etc.
-	 */
-	if (req_clk > info->node_info->th)
-		mode = info->node_info->mode_thresh;
-	else
+	*/
+
+	if (req_clk <= info->node_info->th[0]) {
 		mode = info->node_info->mode;
+		bw = info->node_info->bimc_bw[0];
+	} else if ((info->node_info->num_thresh > 1) &&
+			(req_clk <= info->node_info->th[1])) {
+		mode = info->node_info->mode;
+		bw = info->node_info->bimc_bw[1];
+	} else
+		mode = info->node_info->mode_thresh;
 
 	switch (mode) {
 	case BIMC_QOS_MODE_BYPASS:
@@ -1858,9 +1912,24 @@
 		break;
 	case BIMC_QOS_MODE_REGULATOR:
 	case BIMC_QOS_MODE_LIMITER:
-		for (i = 0; i < ports; i++)
+		for (i = 0; i < ports; i++) {
+			/* If not in fixed mode, update bandwidth */
+			if ((info->node_info->cur_lim_bw != bw)
+					&& (mode != BIMC_QOS_MODE_FIXED)) {
+				struct msm_bus_bimc_qos_bw qbw;
+				qbw.ws = info->node_info->ws;
+				qbw.bw = bw;
+				qbw.gp = info->node_info->bimc_gp;
+				qbw.thmp = info->node_info->bimc_thmp;
+				bimc_set_static_qos_bw(binfo,
+					info->node_info->qport[i], &qbw);
+				info->node_info->cur_lim_bw = bw;
+				MSM_BUS_DBG("%s: Qos is %d reqclk %llu bw %llu",
+						__func__, mode, req_clk, bw);
+			}
 			bke_switch(binfo->base, info->node_info->qport[i],
 				BKE_ON, mode);
+		}
 		break;
 	default:
 		break;
@@ -1919,10 +1988,12 @@
 			qbw.thh = div_s64((110 * bw), 100);
 			/* Check if info is a shared master.
 			 * If it is, mark it dirty
-			 * If it isn't, then set QOS Bandwidth
+			 * If it isn't, then set QOS Bandwidth.
+			 * Also if dual-conf is set, don't program bw regs.
 			 **/
-			msm_bus_bimc_set_qos_bw(binfo,
-				info->node_info->qport[i], &qbw);
+			if (!info->node_info->dual_conf)
+				msm_bus_bimc_set_qos_bw(binfo,
+					info->node_info->qport[i], &qbw);
 		}
 	}
 
@@ -1930,13 +2001,9 @@
 	ports = hop->node_info->num_sports;
 	MSM_BUS_DBG("BIMC: ID: %d, Sports: %d\n", hop->node_info->priv_id,
 		ports);
-	if (ports)
-		bw = INTERLEAVED_BW(fab_pdata, add_bw, ports);
-	else
-		return;
 
 	for (i = 0; i < ports; i++) {
-		sel_cd->slv[hop->node_info->slavep[i]].bw += bw;
+		sel_cd->slv[hop->node_info->slavep[i]].bw += add_bw;
 		sel_cd->slv[hop->node_info->slavep[i]].hw_id =
 			hop->node_info->slv_hw_id;
 		MSM_BUS_DBG("BIMC: Update slave_bw: ID: %d -> %llu\n",
@@ -1966,52 +2033,6 @@
 	return 0;
 }
 
-static void bimc_set_static_qos_bw(struct msm_bus_bimc_info *binfo,
-	int mport, struct msm_bus_bimc_qos_bw *qbw)
-{
-	int32_t bw_mbps, thh = 0, thm, thl, gc;
-	int32_t gp;
-	u64 temp;
-
-	if (binfo->qos_freq == 0) {
-		MSM_BUS_DBG("Zero QoS Frequency\n");
-		return;
-	}
-
-	if (!(qbw->bw && qbw->ws)) {
-		MSM_BUS_DBG("No QoS Bandwidth or Window size\n");
-		return;
-	}
-
-	/* Convert bandwidth to MBPS */
-	temp = qbw->bw;
-	bimc_div(&temp, 1000000);
-	bw_mbps = temp;
-
-	/* Grant period in clock cycles
-	 * Grant period from bandwidth structure
-	 * is in nano seconds, QoS freq is in KHz.
-	 * Divide by 1000 to get clock cycles */
-	gp = (binfo->qos_freq * qbw->gp) / (1000 * NSEC_PER_USEC);
-
-	/* Grant count = BW in MBps * Grant period
-	 * in micro seconds */
-	gc = bw_mbps * (qbw->gp / NSEC_PER_USEC);
-
-	/* Medium threshold = -((Medium Threshold percentage *
-	 * Grant count) / 100) */
-	thm = -((qbw->thmp * gc) / 100);
-	qbw->thm = thm;
-
-	/* Low threshold = -(Grant count) */
-	thl = -gc;
-	qbw->thl = thl;
-
-	MSM_BUS_DBG("%s: BKE parameters: gp %d, gc %d, thm %d thl %d thh %d",
-			__func__, gp, gc, thm, thl, thh);
-
-	set_qos_bw_regs(binfo->base, mport, thh, thm, thl, gp, gc);
-}
 
 static void bimc_init_mas_reg(struct msm_bus_bimc_info *binfo,
 	struct msm_bus_inode_info *info,
@@ -2050,7 +2071,7 @@
 			if (mode != BIMC_QOS_MODE_FIXED) {
 				struct msm_bus_bimc_qos_bw qbw;
 				qbw.ws = info->node_info->ws;
-				qbw.bw = info->node_info->bimc_bw;
+				qbw.bw = info->node_info->bimc_bw[0];
 				qbw.gp = info->node_info->bimc_gp;
 				qbw.thmp = info->node_info->bimc_thmp;
 				bimc_set_static_qos_bw(binfo,
@@ -2083,9 +2104,11 @@
 	 * If the master supports dual configuration,
 	 * configure registers for both modes
 	 */
-	if (info->node_info->dual_conf)
+	if (info->node_info->dual_conf) {
 		bimc_init_mas_reg(binfo, info, qmode,
 			info->node_info->mode_thresh);
+		info->node_info->cur_lim_bw = 0;
+	}
 
 	bimc_init_mas_reg(binfo, info, qmode, info->node_info->mode);
 	return 0;
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_core.h b/arch/arm/mach-msm/msm_bus/msm_bus_core.h
index 7e4a513..557bcca 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_core.h
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_core.h
@@ -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
@@ -82,10 +82,12 @@
 	unsigned int prio_wr;
 	unsigned int prio1;
 	unsigned int prio0;
-	u64 th;
+	unsigned int num_thresh;
+	u64 *th;
+	u64 cur_lim_bw;
 	unsigned int mode_thresh;
 	bool dual_conf;
-	u64 bimc_bw;
+	u64 *bimc_bw;
 	u32 bimc_gp;
 	u32 bimc_thmp;
 	const char *name;
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_fabric.c b/arch/arm/mach-msm/msm_bus/msm_bus_fabric.c
index 7c694a7..0ffc194 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_fabric.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_fabric.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2013, Linux Foundation. All rights reserved.
+/* Copyright (c) 2010-2014, 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
@@ -364,7 +364,7 @@
 {
 	struct msm_bus_fabric *fabric = to_msm_bus_fabric(fabdev);
 	void *sel_cdata;
-	long rounded_rate;
+	long rounded_rate, cur_rate;
 
 	sel_cdata = fabric->cdata[ctx];
 
@@ -379,16 +379,20 @@
 	}
 
 	/* Enable clocks before accessing QoS registers */
-	if (fabric->info.nodeclk[DUAL_CTX].clk)
+	if (fabric->info.nodeclk[DUAL_CTX].clk) {
 		if (fabric->info.nodeclk[DUAL_CTX].rate == 0) {
-			rounded_rate = clk_round_rate(fabric->
-				info.nodeclk[DUAL_CTX].clk, 1);
+			cur_rate = clk_get_rate(
+					fabric->info.nodeclk[DUAL_CTX].clk);
+			rounded_rate = clk_round_rate(
+					fabric->info.nodeclk[DUAL_CTX].clk,
+					cur_rate ? cur_rate : 1);
 		if (clk_set_rate(fabric->info.nodeclk[DUAL_CTX].clk,
 				rounded_rate))
 			MSM_BUS_ERR("Error: clk: en: Node: %d rate: %ld",
 				fabric->fabdev.id, rounded_rate);
 
 		clk_prepare_enable(fabric->info.nodeclk[DUAL_CTX].clk);
+		}
 	}
 
 	if (info->iface_clk.clk)
@@ -514,22 +518,26 @@
 	struct msm_bus_inode_info *info, uint64_t req_clk, uint64_t req_bw)
 {
 	struct msm_bus_fabric *fabric = to_msm_bus_fabric(fabdev);
-	long rounded_rate;
+	long rounded_rate, cur_rate;
 
 	if (fabdev->hw_algo.config_master == NULL)
 		return;
 
 	/* Enable clocks before accessing QoS registers */
-	if (fabric->info.nodeclk[DUAL_CTX].clk)
+	if (fabric->info.nodeclk[DUAL_CTX].clk) {
 		if (fabric->info.nodeclk[DUAL_CTX].rate == 0) {
-			rounded_rate = clk_round_rate(fabric->
-				info.nodeclk[DUAL_CTX].clk, 1);
+			cur_rate = clk_get_rate(
+					fabric->info.nodeclk[DUAL_CTX].clk);
+			rounded_rate = clk_round_rate(
+					fabric->info.nodeclk[DUAL_CTX].clk,
+					cur_rate ? cur_rate : 1);
 		if (clk_set_rate(fabric->info.nodeclk[DUAL_CTX].clk,
 				rounded_rate))
 			MSM_BUS_ERR("Error: clk: en: Node: %d rate: %ld",
 				fabric->fabdev.id, rounded_rate);
 
 		clk_prepare_enable(fabric->info.nodeclk[DUAL_CTX].clk);
+		}
 	}
 
 	if (info->iface_clk.clk)
@@ -896,9 +904,17 @@
 	},
 };
 
-static int __init msm_bus_fabric_init_driver(void)
+int __init msm_bus_fabric_init_driver(void)
 {
+	static bool initialized;
+
+	if (initialized)
+		return 0;
+	else
+		initialized = true;
+
 	MSM_BUS_ERR("msm_bus_fabric_init_driver\n");
 	return platform_driver_register(&msm_bus_fabric_driver);
 }
+EXPORT_SYMBOL(msm_bus_fabric_init_driver);
 subsys_initcall(msm_bus_fabric_init_driver);
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_noc.c b/arch/arm/mach-msm/msm_bus/msm_bus_noc.c
index 8f7b7f2..988d720 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_noc.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_noc.c
@@ -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
@@ -22,12 +22,14 @@
 #define __CLZ(x) ((8 * sizeof(uint32_t)) - 1 - __fls(x))
 #define SAT_SCALE 16	/* 16 bytes minimum for saturation */
 #define BW_SCALE  256	/* 1/256 byte per cycle unit */
+#define QOS_DEFAULT_BASEOFFSET		0x00003000
 #define MAX_BW_FIELD (NOC_QOS_BWn_BW_BMSK >> NOC_QOS_BWn_BW_SHFT)
 #define MAX_SAT_FIELD (NOC_QOS_SATn_SAT_BMSK >> NOC_QOS_SATn_SAT_SHFT)
 
-#define NOC_QOS_REG_BASE(b)		((b) + 0x00003000)
+#define NOC_QOS_REG_BASE(b, o)		((b) + (o))
 
-#define NOC_QOS_ID_COREIDn_ADDR(b, n)	(NOC_QOS_REG_BASE(b) + 0x80 * (n))
+#define NOC_QOS_ID_COREIDn_ADDR(b, o, n) \
+	(NOC_QOS_REG_BASE(b, o) + 0x80 * (n))
 enum noc_qos_id_coreidn {
 	NOC_QOS_ID_COREIDn_RMSK			= 0xffffffff,
 	NOC_QOS_ID_COREIDn_MAXn			= 32,
@@ -37,8 +39,8 @@
 	NOC_QOS_ID_COREIDn_CORETYPEID_SHFT	= 0x0,
 };
 
-#define NOC_QOS_ID_REVISIONIDn_ADDR(b, n) \
-	(NOC_QOS_REG_BASE(b) + 0x4 + 0x80 * (n))
+#define NOC_QOS_ID_REVISIONIDn_ADDR(b, o, n) \
+	(NOC_QOS_REG_BASE(b, o) + 0x4 + 0x80 * (n))
 enum noc_qos_id_revisionidn {
 	NOC_QOS_ID_REVISIONIDn_RMSK		= 0xffffffff,
 	NOC_QOS_ID_REVISIONIDn_MAXn		= 32,
@@ -48,8 +50,8 @@
 	NOC_QOS_ID_REVISIONIDn_USERID_SHFT	= 0x0,
 };
 
-#define NOC_QOS_PRIORITYn_ADDR(b, n)	\
-	(NOC_QOS_REG_BASE(b) + 0x8 + 0x80 * (n))
+#define NOC_QOS_PRIORITYn_ADDR(b, o, n)	\
+	(NOC_QOS_REG_BASE(b, o) + 0x8 + 0x80 * (n))
 enum noc_qos_id_priorityn {
 	NOC_QOS_PRIORITYn_RMSK		= 0x0000000f,
 	NOC_QOS_PRIORITYn_MAXn		= 32,
@@ -59,8 +61,8 @@
 	NOC_QOS_PRIORITYn_P0_SHFT	= 0x0,
 };
 
-#define NOC_QOS_MODEn_ADDR(b, n) \
-	(NOC_QOS_REG_BASE(b) + 0xC + 0x80 * (n))
+#define NOC_QOS_MODEn_ADDR(b, o, n) \
+	(NOC_QOS_REG_BASE(b, o) + 0xC + 0x80 * (n))
 enum noc_qos_id_moden_rmsk {
 	NOC_QOS_MODEn_RMSK		= 0x00000003,
 	NOC_QOS_MODEn_MAXn		= 32,
@@ -68,8 +70,8 @@
 	NOC_QOS_MODEn_MODE_SHFT		= 0x0,
 };
 
-#define NOC_QOS_BWn_ADDR(b, n) \
-	(NOC_QOS_REG_BASE(b) + 0x10 + 0x80 * (n))
+#define NOC_QOS_BWn_ADDR(b, o, n) \
+	(NOC_QOS_REG_BASE(b, o) + 0x10 + 0x80 * (n))
 enum noc_qos_id_bwn {
 	NOC_QOS_BWn_RMSK		= 0x0000ffff,
 	NOC_QOS_BWn_MAXn		= 32,
@@ -78,8 +80,8 @@
 };
 
 /* QOS Saturation registers */
-#define NOC_QOS_SATn_ADDR(b, n) \
-	(NOC_QOS_REG_BASE(b) + 0x14 + 0x80 * (n))
+#define NOC_QOS_SATn_ADDR(b, o, n) \
+	(NOC_QOS_REG_BASE(b, o) + 0x14 + 0x80 * (n))
 enum noc_qos_id_saturationn {
 	NOC_QOS_SATn_RMSK		= 0x000003ff,
 	NOC_QOS_SATn_MAXn		= 32,
@@ -196,10 +198,11 @@
 		uint32_t reg_val;
 
 		reg_val = readl_relaxed(NOC_QOS_MODEn_ADDR(ninfo->base,
-			mport)) & NOC_QOS_MODEn_RMSK;
+			ninfo->qos_baseoffset, mport)) & NOC_QOS_MODEn_RMSK;
 		writel_relaxed(((reg_val & (~(NOC_QOS_MODEn_MODE_BMSK))) |
 			(mode & NOC_QOS_MODEn_MODE_BMSK)),
-			NOC_QOS_MODEn_ADDR(ninfo->base, mport));
+			NOC_QOS_MODEn_ADDR(ninfo->base, ninfo->qos_baseoffset,
+						mport));
 	}
 	/* Ensure qos mode is set before exiting */
 	wmb();
@@ -210,18 +213,23 @@
 {
 	uint32_t reg_val, val;
 
-	reg_val = readl_relaxed(NOC_QOS_PRIORITYn_ADDR(ninfo->base, mport))
-		& NOC_QOS_PRIORITYn_RMSK;
+	reg_val = readl_relaxed(NOC_QOS_PRIORITYn_ADDR(ninfo->base,
+						ninfo->qos_baseoffset, mport))
+				& NOC_QOS_PRIORITYn_RMSK;
 	val = priority->p1 << NOC_QOS_PRIORITYn_P1_SHFT;
 	writel_relaxed(((reg_val & (~(NOC_QOS_PRIORITYn_P1_BMSK))) |
 		(val & NOC_QOS_PRIORITYn_P1_BMSK)),
-		NOC_QOS_PRIORITYn_ADDR(ninfo->base, mport));
+		NOC_QOS_PRIORITYn_ADDR(ninfo->base, ninfo->qos_baseoffset,
+								mport));
 
-	reg_val = readl_relaxed(NOC_QOS_PRIORITYn_ADDR(ninfo->base, mport))
-		& NOC_QOS_PRIORITYn_RMSK;
+	reg_val = readl_relaxed(NOC_QOS_PRIORITYn_ADDR(ninfo->base,
+							ninfo->qos_baseoffset,
+							mport))
+				& NOC_QOS_PRIORITYn_RMSK;
 	writel_relaxed(((reg_val & (~(NOC_QOS_PRIORITYn_P0_BMSK))) |
 		(priority->p0 & NOC_QOS_PRIORITYn_P0_BMSK)),
-		NOC_QOS_PRIORITYn_ADDR(ninfo->base, mport));
+		NOC_QOS_PRIORITYn_ADDR(ninfo->base, ninfo->qos_baseoffset,
+						mport));
 	/* Ensure qos priority is set before exiting */
 	wmb();
 }
@@ -251,33 +259,38 @@
 		 * Clear QoS accumulator
 		 **/
 		mode = readl_relaxed(NOC_QOS_MODEn_ADDR(ninfo->base,
-			mport)) & NOC_QOS_MODEn_MODE_BMSK;
+			ninfo->qos_baseoffset, mport))
+					& NOC_QOS_MODEn_MODE_BMSK;
 		if (mode == NOC_QOS_MODE_REGULATOR || mode ==
 			NOC_QOS_MODE_LIMITER) {
 			reg_val = readl_relaxed(NOC_QOS_MODEn_ADDR(ninfo->
-				base, mport));
+				base, ninfo->qos_baseoffset, mport));
 			val = NOC_QOS_MODE_FIXED;
 			writel_relaxed((reg_val & (~(NOC_QOS_MODEn_MODE_BMSK)))
 				| (val & NOC_QOS_MODEn_MODE_BMSK),
-				NOC_QOS_MODEn_ADDR(ninfo->base, mport));
+				NOC_QOS_MODEn_ADDR(ninfo->base,
+						ninfo->qos_baseoffset, mport));
 		}
 
-		reg_val = readl_relaxed(NOC_QOS_BWn_ADDR(ninfo->base, mport));
+		reg_val = readl_relaxed(NOC_QOS_BWn_ADDR(ninfo->base,
+						ninfo->qos_baseoffset, mport));
 		val = bw_val << NOC_QOS_BWn_BW_SHFT;
 		writel_relaxed(((reg_val & (~(NOC_QOS_BWn_BW_BMSK))) |
 			(val & NOC_QOS_BWn_BW_BMSK)),
-			NOC_QOS_BWn_ADDR(ninfo->base, mport));
+			NOC_QOS_BWn_ADDR(ninfo->base, ninfo->qos_baseoffset,
+								mport));
 
 		MSM_BUS_DBG("NOC: BW: Wrote value: 0x%x\n", ((reg_val &
 			(~NOC_QOS_BWn_BW_BMSK)) | (val &
 			NOC_QOS_BWn_BW_BMSK)));
 
 		reg_val = readl_relaxed(NOC_QOS_SATn_ADDR(ninfo->base,
-			mport));
+			ninfo->qos_baseoffset, mport));
 		val = sat_val << NOC_QOS_SATn_SAT_SHFT;
 		writel_relaxed(((reg_val & (~(NOC_QOS_SATn_SAT_BMSK))) |
 			(val & NOC_QOS_SATn_SAT_BMSK)),
-			NOC_QOS_SATn_ADDR(ninfo->base, mport));
+			NOC_QOS_SATn_ADDR(ninfo->base, ninfo->qos_baseoffset,
+									mport));
 
 		MSM_BUS_DBG("NOC: SAT: Wrote value: 0x%x\n", ((reg_val &
 			(~NOC_QOS_SATn_SAT_BMSK)) | (val &
@@ -285,10 +298,11 @@
 
 		/* Set mode back to what it was initially */
 		reg_val = readl_relaxed(NOC_QOS_MODEn_ADDR(ninfo->base,
-			mport));
+				ninfo->qos_baseoffset, mport));
 		writel_relaxed((reg_val & (~(NOC_QOS_MODEn_MODE_BMSK)))
 			| (mode & NOC_QOS_MODEn_MODE_BMSK),
-			NOC_QOS_MODEn_ADDR(ninfo->base, mport));
+			NOC_QOS_MODEn_ADDR(ninfo->base, ninfo->qos_baseoffset,
+							mport));
 		/* Ensure that all writes for bandwidth registers have
 		 * completed before returning
 		 */
@@ -301,7 +315,8 @@
 {
 	if (NOC_QOS_MODES_ALL_PERM == perm_mode)
 		return readl_relaxed(NOC_QOS_MODEn_ADDR(ninfo->base,
-			mport)) & NOC_QOS_MODEn_MODE_BMSK;
+			ninfo->qos_baseoffset, mport)) &
+						NOC_QOS_MODEn_MODE_BMSK;
 	else
 		return 31 - __CLZ(mode &
 			NOC_QOS_MODES_ALL_PERM);
@@ -311,11 +326,11 @@
 	uint32_t mport, struct msm_bus_noc_qos_priority *priority)
 {
 	priority->p1 = (readl_relaxed(NOC_QOS_PRIORITYn_ADDR(ninfo->base,
-		mport)) & NOC_QOS_PRIORITYn_P1_BMSK) >>
+		ninfo->qos_baseoffset, mport)) & NOC_QOS_PRIORITYn_P1_BMSK) >>
 		NOC_QOS_PRIORITYn_P1_SHFT;
 
 	priority->p0 = (readl_relaxed(NOC_QOS_PRIORITYn_ADDR(ninfo->base,
-		mport)) & NOC_QOS_PRIORITYn_P0_BMSK) >>
+		ninfo->qos_baseoffset, mport)) & NOC_QOS_PRIORITYn_P0_BMSK) >>
 		NOC_QOS_PRIORITYn_P0_SHFT;
 }
 
@@ -325,9 +340,11 @@
 	if (perm_mode & (NOC_QOS_PERM_MODE_LIMITER |
 		NOC_QOS_PERM_MODE_REGULATOR)) {
 		uint32_t bw_val = readl_relaxed(NOC_QOS_BWn_ADDR(ninfo->
-			base, mport)) & NOC_QOS_BWn_BW_BMSK;
+			base, ninfo->qos_baseoffset, mport)) &
+							NOC_QOS_BWn_BW_BMSK;
 		uint32_t sat = readl_relaxed(NOC_QOS_SATn_ADDR(ninfo->
-			base, mport)) & NOC_QOS_SATn_SAT_BMSK;
+			base, ninfo->qos_baseoffset, mport)) &
+						NOC_QOS_SATn_SAT_BMSK;
 
 		qbw->bw = noc_bw(bw_val, ninfo->qos_freq);
 		qbw->ws = noc_ws(qbw->bw, sat, ninfo->qos_freq);
@@ -431,6 +448,12 @@
 	ninfo->nqos_masters = fab_pdata->nmasters;
 	ninfo->nslaves = fab_pdata->nslaves;
 	ninfo->qos_freq = fab_pdata->qos_freq;
+
+	if (!fab_pdata->qos_baseoffset)
+		ninfo->qos_baseoffset = QOS_DEFAULT_BASEOFFSET;
+	else
+		ninfo->qos_baseoffset = fab_pdata->qos_baseoffset;
+
 	ninfo->mas_modes = kzalloc(sizeof(uint32_t) * fab_pdata->nmasters,
 		GFP_KERNEL);
 	if (!ninfo->mas_modes) {
@@ -563,14 +586,8 @@
 
 skip_mas_bw:
 	ports = hop->node_info->num_sports;
-	if (ports == 0) {
-		MSM_BUS_DBG("\nDIVIDE BY 0, hop: %d\n",
-			hop->node_info->priv_id);
-		return;
-	}
-	bw = INTERLEAVED_BW(fab_pdata, add_bw, ports);
 	for (i = 0; i < ports; i++) {
-		sel_cd->slv[hop->node_info->slavep[i]].bw += bw;
+		sel_cd->slv[hop->node_info->slavep[i]].bw += add_bw;
 		sel_cd->slv[hop->node_info->slavep[i]].hw_id =
 			hop->node_info->slv_hw_id;
 		MSM_BUS_DBG("NOC: Update slave_bw for ID: %d -> %llu\n",
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_noc.h b/arch/arm/mach-msm/msm_bus/msm_bus_noc.h
index 00479c6..6ba3a24 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_noc.h
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_noc.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, 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
@@ -44,6 +44,7 @@
 	uint32_t nqos_masters;
 	uint32_t nslaves;
 	uint32_t qos_freq; /* QOS Clock in KHz */
+	uint32_t qos_baseoffset;
 	uint32_t *mas_modes;
 	struct msm_bus_noc_commit cdata[NUM_CTX];
 };
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_of.c b/arch/arm/mach-msm/msm_bus/msm_bus_of.c
index 06894c6..f857920 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_of.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_of.c
@@ -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
@@ -173,7 +173,7 @@
 	of_node = pdev->dev.of_node;
 	pdata = get_pdata(pdev, of_node);
 	if (!pdata) {
-		pr_err("Error getting bus pdata!\n");
+		pr_err("client has to provide missing entry for successful registration\n");
 		return NULL;
 	}
 
@@ -214,7 +214,7 @@
 
 	pdata = get_pdata(pdev, of_node);
 	if (!pdata) {
-		pr_err("Error getting bus pdata!\n");
+		pr_err("client has to provide missing entry for successful registration\n");
 		return NULL;
 	}
 
@@ -271,6 +271,54 @@
 	return NULL;
 }
 
+static u64 *get_th_params(struct platform_device *pdev,
+		const struct device_node *node, const char *prop,
+		int *nports)
+{
+	int size = 0, ret;
+	u64 *ret_arr = NULL;
+	int *arr = NULL;
+	int i;
+
+	if (of_get_property(node, prop, &size)) {
+		*nports = size / sizeof(int);
+	} else {
+		pr_debug("Property %s not available\n", prop);
+		*nports = 0;
+		return NULL;
+	}
+
+	ret_arr = devm_kzalloc(&pdev->dev, (*nports * sizeof(u64)),
+							GFP_KERNEL);
+	arr = kzalloc(size, GFP_KERNEL);
+	if ((size > 0) && (ZERO_OR_NULL_PTR(arr)
+				|| ZERO_OR_NULL_PTR(ret_arr))) {
+		pr_err("Error: Failed to alloc mem for %s\n", prop);
+		return NULL;
+	}
+
+	ret = of_property_read_u32_array(node, prop, (u32 *)arr, *nports);
+	if (ret) {
+		pr_err("Error in reading property: %s\n", prop);
+		goto err;
+	}
+
+	for (i = 0; i < *nports; i++)
+		ret_arr[i] = (uint64_t)KBTOB(arr[i]);
+
+	MSM_BUS_DBG("%s: num entries %d prop %s", __func__, *nports, prop);
+
+	for (i = 0; i < *nports; i++)
+		MSM_BUS_DBG("Th %d val %llu", i, ret_arr[i]);
+
+	kfree(arr);
+	return ret_arr;
+err:
+	devm_kfree(&pdev->dev, arr);
+	devm_kfree(&pdev->dev, ret_arr);
+	return NULL;
+}
+
 static struct msm_bus_node_info *get_nodes(struct device_node *of_node,
 	struct platform_device *pdev,
 	struct msm_bus_fabric_registration *pdata)
@@ -278,7 +326,7 @@
 	struct msm_bus_node_info *info;
 	struct device_node *child_node = NULL;
 	int i = 0, ret;
-	u32 temp;
+	int num_bw = 0;
 
 	for_each_child_of_node(of_node, child_node) {
 		i++;
@@ -353,36 +401,29 @@
 		of_property_read_u32(child_node, "qcom,buswidth",
 			&info[i].buswidth);
 		of_property_read_u32(child_node, "qcom,ws", &info[i].ws);
-		ret = of_property_read_u32(child_node, "qcom,thresh",
-			&temp);
-		if (!ret)
-			info[i].th = (uint64_t)KBTOB(temp);
 
-		ret = of_property_read_u32(child_node, "qcom,bimc,bw",
-			&temp);
-		if (!ret)
-			info[i].bimc_bw = (uint64_t)KBTOB(temp);
+		info[i].dual_conf =
+			of_property_read_bool(child_node, "qcom,dual-conf");
+
+
+		info[i].th = get_th_params(pdev, child_node, "qcom,thresh",
+						&info[i].num_thresh);
+
+		info[i].bimc_bw = get_th_params(pdev, child_node,
+						"qcom,bimc,bw", &num_bw);
+
+		if (num_bw != info[i].num_thresh) {
+			pr_err("%s:num_bw %d must equal num_thresh %d",
+				__func__, num_bw, info[i].num_thresh);
+			pr_err("%s:Err setting up dual conf for %s",
+				__func__, info[i].name);
+			goto err;
+		}
 
 		of_property_read_u32(child_node, "qcom,bimc,gp",
 			&info[i].bimc_gp);
 		of_property_read_u32(child_node, "qcom,bimc,thmp",
 			&info[i].bimc_thmp);
-		ret = of_property_read_string(child_node, "qcom,mode",
-			&sel_str);
-		if (ret)
-			info[i].mode = 0;
-		else {
-			ret = get_num(mode_sel_name, sel_str);
-			if (ret < 0) {
-				pr_err("Unknown mode :%s\n", sel_str);
-				goto err;
-			}
-
-			info[i].mode = ret;
-		}
-
-		info[i].dual_conf =
-			of_property_read_bool(child_node, "qcom,dual-conf");
 
 		ret = of_property_read_string(child_node, "qcom,mode-thresh",
 			&sel_str);
@@ -397,7 +438,21 @@
 
 			info[i].mode_thresh = ret;
 			MSM_BUS_DBG("AXI: THreshold mode set: %d\n",
-				info[i].mode_thresh);
+					info[i].mode_thresh);
+		}
+
+		ret = of_property_read_string(child_node, "qcom,mode",
+				&sel_str);
+		if (ret)
+			info[i].mode = 0;
+		else {
+			ret = get_num(mode_sel_name, sel_str);
+			if (ret < 0) {
+				pr_err("Unknown mode :%s\n", sel_str);
+				goto err;
+			}
+
+			info[i].mode = ret;
 		}
 
 		ret = of_property_read_string(child_node, "qcom,perm-mode",
@@ -552,6 +607,11 @@
 	if (of_property_read_bool(of_node, "qcom,virt"))
 		pdata->virt = true;
 
+	ret = of_property_read_u32(of_node, "qcom,qos-baseoffset",
+						&pdata->qos_baseoffset);
+	if (ret)
+		pr_debug("%s:qos_baseoffset not available\n", __func__);
+
 	if (of_property_read_bool(of_node, "qcom,rpm-en"))
 		pdata->rpm_enabled = 1;
 
diff --git a/arch/arm/mach-msm/msm_qmi_interface.c b/arch/arm/mach-msm/msm_qmi_interface.c
index e2ff0f4..7c5adc1 100644
--- a/arch/arm/mach-msm/msm_qmi_interface.c
+++ b/arch/arm/mach-msm/msm_qmi_interface.c
@@ -33,6 +33,9 @@
 
 #include "msm_qmi_interface_priv.h"
 
+#define BUILD_INSTANCE_ID(vers, ins) (((vers) & 0xFF) | (((ins) & 0xFF) << 8))
+#define LOOKUP_MASK 0xFFFFFFFF
+
 static LIST_HEAD(svc_event_nb_list);
 static DEFINE_MUTEX(svc_event_nb_list_lock);
 static DEFINE_MUTEX(msm_qmi_init_lock);
@@ -625,12 +628,15 @@
 EXPORT_SYMBOL(qmi_recv_msg);
 
 int qmi_connect_to_service(struct qmi_handle *handle,
-			   uint32_t service_id, uint32_t instance_id)
+			   uint32_t service_id,
+			   uint32_t service_vers,
+			   uint32_t service_ins)
 {
 	struct msm_ipc_port_name svc_name;
 	struct msm_ipc_server_info svc_info;
 	struct msm_ipc_addr *svc_dest_addr;
 	int rc;
+	uint32_t instance_id;
 
 	if (!handle)
 		return -EINVAL;
@@ -642,12 +648,15 @@
 		return -ENOMEM;
 	}
 
+	instance_id = BUILD_INSTANCE_ID(service_vers, service_ins);
 	svc_name.service = service_id;
 	svc_name.instance = instance_id;
 
-	rc = msm_ipc_router_lookup_server_name(&svc_name, &svc_info, 1, 0xFF);
+	rc = msm_ipc_router_lookup_server_name(&svc_name, &svc_info,
+						1, LOOKUP_MASK);
 	if (rc <= 0) {
-		pr_err("%s: Server not found\n", __func__);
+		pr_err("%s: Server %08x:%08x not found\n",
+			__func__, service_id, instance_id);
 		return -ENODEV;
 	}
 	svc_dest_addr->addrtype = MSM_IPC_ADDR_ID;
@@ -780,13 +789,16 @@
 }
 
 int qmi_svc_event_notifier_register(uint32_t service_id,
-				    uint32_t instance_id,
+				    uint32_t service_vers,
+				    uint32_t service_ins,
 				    struct notifier_block *nb)
 {
 	struct svc_event_nb *temp;
 	unsigned long flags;
 	int ret;
+	uint32_t instance_id;
 
+	instance_id = BUILD_INSTANCE_ID(service_vers, service_ins);
 	temp = find_and_add_svc_event_nb(service_id, instance_id);
 	if (!temp)
 		return -EFAULT;
@@ -810,13 +822,16 @@
 EXPORT_SYMBOL(qmi_svc_event_notifier_register);
 
 int qmi_svc_event_notifier_unregister(uint32_t service_id,
-				      uint32_t instance_id,
+				      uint32_t service_vers,
+				      uint32_t service_ins,
 				      struct notifier_block *nb)
 {
 	int ret;
 	struct svc_event_nb *temp;
 	unsigned long flags;
+	uint32_t instance_id;
 
+	instance_id = BUILD_INSTANCE_ID(service_vers, service_ins);
 	mutex_lock(&svc_event_nb_list_lock);
 	temp = find_svc_event_nb(service_id, instance_id);
 	if (!temp) {
diff --git a/arch/arm/mach-msm/msm_rq_stats.c b/arch/arm/mach-msm/msm_rq_stats.c
index f70022e..af4a6d2 100644
--- a/arch/arm/mach-msm/msm_rq_stats.c
+++ b/arch/arm/mach-msm/msm_rq_stats.c
@@ -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
@@ -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;
 	}
@@ -376,11 +375,12 @@
 	int ret;
 	int i;
 	struct cpufreq_policy cpu_policy;
+
+#ifndef CONFIG_SMP
 	/* Bail out if this is not an SMP Target */
-	if (!is_smp()) {
-		rq_info.init = 0;
-		return -ENOSYS;
-	}
+	rq_info.init = 0;
+	return -ENOSYS;
+#endif
 
 	rq_wq = create_singlethread_workqueue("rq_stats");
 	BUG_ON(!rq_wq);
@@ -401,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;
@@ -416,11 +416,11 @@
 
 static int __init msm_rq_stats_early_init(void)
 {
+#ifndef CONFIG_SMP
 	/* Bail out if this is not an SMP Target */
-	if (!is_smp()) {
-		rq_info.init = 0;
-		return -ENOSYS;
-	}
+	rq_info.init = 0;
+	return -ENOSYS;
+#endif
 
 	pm_notifier(system_suspend_handler, 0);
 	return 0;
diff --git a/arch/arm/mach-msm/msm_watchdog_v2.c b/arch/arm/mach-msm/msm_watchdog_v2.c
index ead2e95..979c5bb 100644
--- a/arch/arm/mach-msm/msm_watchdog_v2.c
+++ b/arch/arm/mach-msm/msm_watchdog_v2.c
@@ -478,8 +478,9 @@
 	wdog_resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	pdata->size = resource_size(wdog_resource);
 	pdata->phys_base = wdog_resource->start;
-	if (unlikely(!(devm_request_region(&pdev->dev, pdata->phys_base,
-					pdata->size, "msm-watchdog")))) {
+	if (unlikely(!(devm_request_mem_region(&pdev->dev, pdata->phys_base,
+					       pdata->size, "msm-watchdog")))) {
+
 		dev_err(&pdev->dev, "%s cannot reserve watchdog region\n",
 								__func__);
 		return -ENXIO;
diff --git a/arch/arm/mach-msm/ocmem.c b/arch/arm/mach-msm/ocmem.c
index 99e54b7..4a8cc39 100644
--- a/arch/arm/mach-msm/ocmem.c
+++ b/arch/arm/mach-msm/ocmem.c
@@ -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
@@ -788,6 +788,7 @@
 	struct device   *dev = &pdev->dev;
 	struct clk *ocmem_core_clk = NULL;
 	struct clk *ocmem_iface_clk = NULL;
+	int rc;
 
 	if (!pdev->dev.of_node) {
 		dev_info(dev, "Missing Configuration in Device Tree\n");
@@ -830,10 +831,23 @@
 
 	platform_set_drvdata(pdev, ocmem_pdata);
 
+	rc = ocmem_enable_core_clock();
+	if (rc < 0)
+		goto core_clk_fail;
+
+	rc = ocmem_enable_iface_clock();
+	if (rc < 0)
+		goto iface_clk_fail;
+
 	/* Parameter to be updated based on TZ */
 	/* Allow the OCMEM CSR to be programmed */
-	if (ocmem_enable_sec_program(OCMEM_SECURE_DEV_ID))
+	if (ocmem_restore_sec_program(OCMEM_SECURE_DEV_ID)) {
+		ocmem_disable_iface_clock();
+		ocmem_disable_core_clock();
 		return -EBUSY;
+	}
+	ocmem_disable_iface_clock();
+	ocmem_disable_core_clock();
 
 	if (ocmem_debugfs_init(pdev))
 		dev_err(dev, "ocmem: No debugfs node available\n");
@@ -860,6 +874,11 @@
 
 	dev_dbg(dev, "initialized successfully\n");
 	return 0;
+
+iface_clk_fail:
+	ocmem_disable_core_clock();
+core_clk_fail:
+	return rc;
 }
 
 static int __devexit msm_ocmem_remove(struct platform_device *pdev)
diff --git a/arch/arm/mach-msm/ocmem_core.c b/arch/arm/mach-msm/ocmem_core.c
index c186a5e..9c2afb9 100644
--- a/arch/arm/mach-msm/ocmem_core.c
+++ b/arch/arm/mach-msm/ocmem_core.c
@@ -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
@@ -51,6 +51,7 @@
 static struct ocmem_hw_region *region_ctrl;
 static struct mutex region_ctrl_lock;
 static void *ocmem_base;
+static void *ocmem_vbase;
 
 #define OCMEM_V1_MACROS 8
 #define OCMEM_V1_MACRO_SZ (SZ_64K)
@@ -562,6 +563,13 @@
 	ocmem_write(0x0, ocmem_base + OC_GFX_MPU_END);
 }
 
+int ocmem_clear(unsigned long start, unsigned long size)
+{
+	memset((ocmem_vbase + start), 0x4D4D434F, size);
+	mb();
+	return 0;
+}
+
 static int do_lock(enum ocmem_client id, unsigned long offset,
 			unsigned long len, enum region_mode mode)
 {
@@ -575,7 +583,7 @@
 	return 0;
 }
 
-int ocmem_enable_sec_program(int sec_id)
+int ocmem_restore_sec_program(int sec_id)
 {
 	return 0;
 }
@@ -694,7 +702,7 @@
 	return rc;
 }
 
-int ocmem_enable_sec_program(int sec_id)
+int ocmem_restore_sec_program(int sec_id)
 {
 	int rc, scm_ret = 0;
 	struct msm_scm_sec_cfg {
@@ -945,7 +953,6 @@
 	unsigned end_m = num_banks;
 	unsigned long region_offset = 0;
 	struct ocmem_hw_region *region;
-	int rc = 0;
 
 	if (offset < 0)
 		return -EINVAL;
@@ -966,14 +973,6 @@
 		(region_end >= num_regions))
 			return -EINVAL;
 
-	rc = ocmem_enable_core_clock();
-
-	if (rc < 0) {
-		pr_err("ocmem: Power transistion request for client %s (id: %d) failed\n",
-				get_name(id), id);
-		return rc;
-	}
-
 	mutex_lock(&region_ctrl_lock);
 
 	for (i = region_start; i <= region_end; i++) {
@@ -1027,11 +1026,10 @@
 
 	}
 	mutex_unlock(&region_ctrl_lock);
-	ocmem_disable_core_clock();
+
 	return 0;
 invalid_transition:
 	mutex_unlock(&region_ctrl_lock);
-	ocmem_disable_core_clock();
 	pr_err("ocmem_core: Invalid state transition detected for %d\n", id);
 	pr_err("ocmem_core: Offset %lx Len %lx curr_state %x new_state %x\n",
 			offset, len, curr_state, new_state);
@@ -1114,9 +1112,37 @@
 
 static int ocmem_power_show(struct seq_file *f, void *dummy)
 {
+	int rc = 0;
+
+	rc = ocmem_enable_core_clock();
+
+	if (rc < 0)
+		goto core_clock_fail;
+
+	rc = ocmem_enable_iface_clock();
+
+	if (rc < 0)
+		goto iface_clock_fail;
+
+	rc = ocmem_restore_sec_program(OCMEM_SECURE_DEV_ID);
+	if (rc < 0) {
+		pr_err("ocmem: Failed to restore security programming\n");
+		goto restore_config_fail;
+	}
 	ocmem_power_show_sw_state(f, dummy);
 	ocmem_power_show_hw_state(f, dummy);
+
+	ocmem_disable_iface_clock();
+	ocmem_disable_core_clock();
+
 	return 0;
+
+restore_config_fail:
+	ocmem_disable_iface_clock();
+iface_clock_fail:
+	ocmem_disable_core_clock();
+core_clock_fail:
+	return -EINVAL;
 }
 
 static int ocmem_power_open(struct inode *inode, struct file *file)
@@ -1144,6 +1170,7 @@
 
 	pdata = platform_get_drvdata(pdev);
 	ocmem_base = pdata->reg_base;
+	ocmem_vbase = pdata->vbase;
 
 	rc = ocmem_enable_core_clock();
 
diff --git a/arch/arm/mach-msm/ocmem_rdm.c b/arch/arm/mach-msm/ocmem_rdm.c
index 4ff7212..9eac050 100644
--- a/arch/arm/mach-msm/ocmem_rdm.c
+++ b/arch/arm/mach-msm/ocmem_rdm.c
@@ -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
@@ -149,38 +149,6 @@
 	return IRQ_HANDLED;
 }
 
-#ifdef CONFIG_MSM_OCMEM_NONSECURE
-int ocmem_clear(unsigned long start, unsigned long size)
-{
-	INIT_COMPLETION(dm_clear_event);
-	/* Clear DM Mask */
-	ocmem_write(DM_MASK_RESET, dm_base + DM_INTR_MASK);
-	/* Clear DM Interrupts */
-	ocmem_write(DM_INTR_RESET, dm_base + DM_INTR_CLR);
-	/* DM CLR offset */
-	ocmem_write(start, dm_base + DM_CLR_OFFSET);
-	/* DM CLR size */
-	ocmem_write(size, dm_base + DM_CLR_SIZE);
-	/* Wipe out memory as "OCMM" */
-	ocmem_write(0x4D4D434F, dm_base + DM_CLR_PATTERN);
-	/* The offset, size and pattern for clearing must be set
-	 * before triggering the clearing engine
-	 */
-	mb();
-	/* Trigger Data Clear */
-	ocmem_write(DM_CLR_ENABLE, dm_base + DM_CLR_TRIGGER);
-
-	wait_for_completion(&dm_clear_event);
-
-	return 0;
-}
-#else
-int ocmem_clear(unsigned long start, unsigned long size)
-{
-	return 0;
-}
-#endif
-
 /* Lock during transfers */
 int ocmem_rdm_transfer(int id, struct ocmem_map_list *clist,
 			unsigned long start, int direction)
diff --git a/arch/arm/mach-msm/ocmem_sched.c b/arch/arm/mach-msm/ocmem_sched.c
index cbf7933..78279ed 100644
--- a/arch/arm/mach-msm/ocmem_sched.c
+++ b/arch/arm/mach-msm/ocmem_sched.c
@@ -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
@@ -634,17 +634,11 @@
 {
 	int rc = 0;
 
-	rc = ocmem_enable_core_clock();
+	rc = ocmem_restore_sec_program(OCMEM_SECURE_DEV_ID);
 
-	if (rc < 0)
-		goto core_clock_fail;
-
-
-	if (is_iface_access(req->owner)) {
-		rc = ocmem_enable_iface_clock();
-
-		if (rc < 0)
-			goto iface_clock_fail;
+	if (rc < 0) {
+		pr_err("ocmem: Failed to restore security programming\n");
+		goto lock_failed;
 	}
 
 	rc = ocmem_lock(req->owner, phys_to_offset(req->req_start), req->req_sz,
@@ -670,11 +664,6 @@
 process_map_fail:
 	ocmem_unlock(req->owner, phys_to_offset(req->req_start), req->req_sz);
 lock_failed:
-	if (is_iface_access(req->owner))
-		ocmem_disable_iface_clock();
-iface_clock_fail:
-	ocmem_disable_core_clock();
-core_clock_fail:
 	pr_err("ocmem: Failed to map ocmem request\n");
 	return rc;
 }
@@ -698,9 +687,6 @@
 		goto unlock_failed;
 	}
 
-	if (is_iface_access(req->owner))
-		ocmem_disable_iface_clock();
-	ocmem_disable_core_clock();
 	pr_debug("ocmem: Unmapped request %p\n", req);
 	return 0;
 
@@ -1345,9 +1331,21 @@
 	if (rc < 0)
 		return -EINVAL;
 
+	rc = ocmem_enable_core_clock();
+
+	if (rc < 0)
+		goto core_clock_fail;
+
+	if (is_iface_access(req->owner)) {
+		rc = ocmem_enable_iface_clock();
+
+		if (rc < 0)
+			goto iface_clock_fail;
+	}
+
 	rc = process_map(req, req->req_start, req->req_end);
 	if (rc < 0)
-		return -EINVAL;
+		goto map_error;
 
 	offset = phys_to_offset(req->req_start);
 
@@ -1366,7 +1364,14 @@
 		BUG();
 	}
 	return 0;
+
 power_ctl_error:
+map_error:
+if (is_iface_access(req->owner))
+	ocmem_disable_iface_clock();
+iface_clock_fail:
+	ocmem_disable_core_clock();
+core_clock_fail:
 	return -EINVAL;
 }
 
@@ -1536,6 +1541,10 @@
 				}
 			}
 
+			if (is_iface_access(req->owner))
+				ocmem_disable_iface_clock();
+			ocmem_disable_core_clock();
+
 			rc = do_free(req);
 			if (rc < 0) {
 				pr_err("ocmem: Failed to free %p\n", req);
@@ -1556,6 +1565,9 @@
 				pr_err("Failed to switch OFF memory macros\n");
 				goto free_fail;
 			}
+			if (is_iface_access(req->owner))
+				ocmem_disable_iface_clock();
+			ocmem_disable_core_clock();
 		}
 
 		/* free the allocation */
@@ -1658,6 +1670,10 @@
 		rc = process_unmap(req, req->req_start, req->req_end);
 		if (rc < 0)
 			return -EINVAL;
+
+		if (is_iface_access(req->owner))
+			ocmem_disable_iface_clock();
+		ocmem_disable_core_clock();
 	} else
 		return -EINVAL;
 
@@ -1768,6 +1784,9 @@
 			rc = process_unmap(req, req->req_start, req->req_end);
 			if (rc < 0)
 				goto shrink_fail;
+			if (is_iface_access(req->owner))
+				ocmem_disable_iface_clock();
+			ocmem_disable_core_clock();
 		}
 		rc = do_free(req);
 		if (rc < 0)
@@ -2104,7 +2123,6 @@
 
 	down_write(&req->rw_sem);
 
-	mutex_lock(&allocation_mutex);
 retry_allocate:
 
 	/* Take the scheduler mutex */
@@ -2114,12 +2132,14 @@
 
 	if (rc == OP_EVICT) {
 
+		mutex_lock(&allocation_mutex);
 		ret = run_evict(req);
 
 		if (ret == 0) {
 			rc = sched_restore(req);
 			if (rc < 0) {
 				pr_err("Failed to restore for req %p\n", req);
+				mutex_unlock(&allocation_mutex);
 				goto err_allocate_fail;
 			}
 			req->edata = NULL;
@@ -2127,14 +2147,14 @@
 			pr_debug("Attempting to re-allocate req %p\n", req);
 			req->req_start = 0x0;
 			req->req_end = 0x0;
+			mutex_unlock(&allocation_mutex);
 			goto retry_allocate;
 		} else {
+			mutex_unlock(&allocation_mutex);
 			goto err_allocate_fail;
 		}
 	}
 
-	mutex_unlock(&allocation_mutex);
-
 	if (rc == OP_FAIL) {
 		inc_ocmem_stat(zone_of(req), NR_ALLOCATION_FAILS);
 		goto err_allocate_fail;
@@ -2159,7 +2179,6 @@
 	up_write(&req->rw_sem);
 	return 0;
 err_allocate_fail:
-	mutex_unlock(&allocation_mutex);
 	up_write(&req->rw_sem);
 	return -EINVAL;
 }
@@ -2254,6 +2273,17 @@
 
 	if (req->req_sz != 0) {
 
+		rc = ocmem_enable_core_clock();
+
+		if (rc < 0)
+			goto core_clock_fail;
+
+		if (is_iface_access(req->owner)) {
+			rc = ocmem_enable_iface_clock();
+
+			if (rc < 0)
+				goto iface_clock_fail;
+		}
 		rc = process_map(req, req->req_start, req->req_end);
 		if (rc < 0)
 			goto map_error;
@@ -2275,6 +2305,11 @@
 map_error:
 	handle->req = NULL;
 	do_free(req);
+	if (is_iface_access(req->owner))
+		ocmem_disable_iface_clock();
+iface_clock_fail:
+	ocmem_disable_core_clock();
+core_clock_fail:
 do_allocate_error:
 	ocmem_destroy_req(req);
 	return -EINVAL;
@@ -2303,6 +2338,17 @@
 	inc_ocmem_stat(zone_of(req), NR_ASYNC_ALLOCATIONS);
 
 	if (req->req_sz != 0) {
+		rc = ocmem_enable_core_clock();
+
+		if (rc < 0)
+			goto core_clock_fail;
+
+		if (is_iface_access(req->owner)) {
+			rc = ocmem_enable_iface_clock();
+
+			if (rc < 0)
+				goto iface_clock_fail;
+		}
 
 		rc = process_map(req, req->req_start, req->req_end);
 		if (rc < 0)
@@ -2333,6 +2379,11 @@
 map_error:
 	handle->req = NULL;
 	do_free(req);
+	if (is_iface_access(req->owner))
+		ocmem_disable_iface_clock();
+iface_clock_fail:
+	ocmem_disable_core_clock();
+core_clock_fail:
 do_allocate_error:
 	ocmem_destroy_req(req);
 	return -EINVAL;
diff --git a/arch/arm/mach-msm/perf_debug.c b/arch/arm/mach-msm/perf_debug.c
index 28d8e42..c4f7d45 100644
--- a/arch/arm/mach-msm/perf_debug.c
+++ b/arch/arm/mach-msm/perf_debug.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
@@ -35,6 +35,20 @@
 	"10 Perf: Fix counts across power collapse\n"
 	"11 ARM: dts: msm: add perf-events support for msm8x10, msm8x12\n"
 	"12 Perf: Make per-process counters configurable\n"
+	"13 msm: perf: Add L2 support for tracecounters\n"
+	"14 Perf: keep events across hotplug\n"
+	"15 Perf: bring CPU online if needed when disabling irq\n"
+	"16 Perf: Support sw events across hotplug\n"
+	"17 msm: perf: initialise krait perf L2 counter enables\n"
+	"18 msm: perf: clean up duplicate constraint events\n"
+	"19 Perf: Make per-process counters cumulative\n"
+	"20 Perf: Fix PID for tracepoints\n"
+	"21 Perf: preserve registers across hotplug\n"
+	"22 msm: perf: fix formatting of trace entry\n"
+	"23 msm: perf: Fix cpu id logic in tracectr notifier\n"
+	"24 msm: perf: tracectr: Initialize cnts after hotplug\n"
+	"25 Perf: Reset pmu after hotplug\n"
+	"26 msm: perf: set filter bits for cycle counter on krait\n"
 ;
 
 static ssize_t desc_read(struct file *fp, char __user *buf,
diff --git a/arch/arm/mach-msm/perf_event_msm_krait_l2.c b/arch/arm/mach-msm/perf_event_msm_krait_l2.c
index ad34457..c9e2b8f 100644
--- a/arch/arm/mach-msm/perf_event_msm_krait_l2.c
+++ b/arch/arm/mach-msm/perf_event_msm_krait_l2.c
@@ -18,54 +18,6 @@
 
 #include <mach/msm-krait-l2-accessors.h>
 
-#define MAX_L2_PERIOD	((1ULL << 32) - 1)
-#define MAX_KRAIT_L2_CTRS 10
-
-#define PMCR_NUM_EV_SHIFT 11
-#define PMCR_NUM_EV_MASK 0x1f
-
-#define L2_EVT_MASK 0xfffff
-
-#define L2_SLAVE_EV_PREFIX 4
-
-#define L2PMCCNTR 0x409
-#define L2PMCCNTCR 0x408
-#define L2PMCCNTSR 0x40A
-#define L2CYCLE_CTR_BIT 31
-#define L2CYCLE_CTR_RAW_CODE 0xfe
-
-#define L2PMOVSR	0x406
-
-#define L2PMCR	0x400
-#define L2PMCR_RESET_ALL	0x6
-#define L2PMCR_GLOBAL_ENABLE	0x1
-#define L2PMCR_GLOBAL_DISABLE	0x0
-
-#define L2PMCNTENSET	0x403
-#define L2PMCNTENCLR	0x402
-
-#define L2PMINTENSET	0x405
-#define L2PMINTENCLR	0x404
-
-#define IA_L2PMXEVCNTCR_BASE	0x420
-#define IA_L2PMXEVTYPER_BASE	0x424
-#define IA_L2PMRESX_BASE	0x410
-#define IA_L2PMXEVFILTER_BASE	0x423
-#define IA_L2PMXEVCNTR_BASE	0x421
-
-/* event format is -e rsRCCG See get_event_desc() */
-
-#define EVENT_PREFIX_MASK	0xf0000
-#define EVENT_REG_MASK		0x0f000
-#define EVENT_GROUPSEL_MASK	0x0000f
-#define	EVENT_GROUPCODE_MASK	0x00ff0
-
-#define EVENT_PREFIX_SHIFT	16
-#define EVENT_REG_SHIFT		12
-#define EVENT_GROUPCODE_SHIFT	4
-
-#define	RESRX_VALUE_EN	0x80000000
-
 /*
  * The L2 PMU is shared between all CPU's, so protect
  * its bitmap access.
@@ -197,13 +149,16 @@
 	set_l2_indirect_reg(filter_reg, filter_val);
 }
 
-static void set_evfilter_sys_mode(int ctr, unsigned int is_slv)
+static void set_evfilter_sys_mode(int ctr, unsigned int is_slv, int cpu,
+		unsigned int is_tracectr)
 {
 	u32 filter_reg = (ctr * 16) + IA_L2PMXEVFILTER_BASE;
 	u32 filter_val = l2_orig_filter_prefix | 0xf;
 
-	if (is_slv)
+	if (is_slv == 1)
 		filter_val = l2_slv_filter_prefix;
+	if (is_tracectr == 1)
+		filter_val = l2_orig_filter_prefix | 1 << cpu;
 
 	set_l2_indirect_reg(filter_reg, filter_val);
 }
@@ -277,6 +232,7 @@
 	struct event_desc evdesc;
 	unsigned long iflags;
 	unsigned int is_slv = 0;
+	unsigned int is_tracectr = 0;
 	unsigned int evt_prefix;
 
 	raw_spin_lock_irqsave(&krait_l2_pmu_hw_events.pmu_lock, iflags);
@@ -290,6 +246,8 @@
 
 	if (evt_prefix == L2_SLAVE_EV_PREFIX)
 		is_slv = 1;
+	else if (evt_prefix == L2_TRACECTR_PREFIX)
+		is_tracectr = 1;
 
 	set_evcntcr(idx);
 
@@ -305,7 +263,7 @@
 	if (cpu < 0)
 		set_evfilter_task_mode(idx, is_slv);
 	else
-		set_evfilter_sys_mode(idx, is_slv);
+		set_evfilter_sys_mode(idx, is_slv, cpu, is_tracectr);
 
 out:
 	enable_intenset(idx);
@@ -456,6 +414,7 @@
 static int msm_l2_test_set_ev_constraint(struct perf_event *event)
 {
 	u32 evt_type = event->attr.config & L2_EVT_MASK;
+	u8 evt_prefix = (evt_type & EVENT_PREFIX_MASK) >> EVENT_PREFIX_SHIFT;
 	u8 reg   = (evt_type & 0x0F000) >> 12;
 	u8 group = evt_type & 0x0000F;
 	u8 code = (evt_type & 0x00FF0) >> 4;
@@ -464,6 +423,8 @@
 	u64 bitmap_t;
 	u32 shift_idx;
 
+	if (evt_prefix == L2_TRACECTR_PREFIX)
+		return err;
 	/*
 	 * Cycle counter collision is detected in
 	 * get_event_idx().
@@ -496,8 +457,10 @@
 			 * This sets the event OFF on all but one
 			 * CPU.
 			 */
-			if (!(event->cpu < 0))
+			if (!(event->cpu < 0)) {
 				event->state = PERF_EVENT_STATE_OFF;
+				event->attr.constraint_duplicate = 1;
+			}
 	}
 out:
 	raw_spin_unlock_irqrestore(&l2_pmu_constraints.lock, flags);
@@ -507,12 +470,15 @@
 static int msm_l2_clear_ev_constraint(struct perf_event *event)
 {
 	u32 evt_type = event->attr.config & L2_EVT_MASK;
+	u8 evt_prefix = (evt_type & EVENT_PREFIX_MASK) >> EVENT_PREFIX_SHIFT;
 	u8 reg   = (evt_type & 0x0F000) >> 12;
 	u8 group =  evt_type & 0x0000F;
 	unsigned long flags;
 	u64 bitmap_t;
 	u32 shift_idx;
 
+	if (evt_prefix == L2_TRACECTR_PREFIX)
+		return 1;
 	raw_spin_lock_irqsave(&l2_pmu_constraints.lock, flags);
 
 	shift_idx = ((reg * 4) + group);
@@ -592,6 +558,8 @@
 
 static int __init register_krait_l2_pmu_driver(void)
 {
+	int i;
+
 	/* Reset all ctrs */
 	set_l2_indirect_reg(L2PMCR, L2PMCR_RESET_ALL);
 
@@ -613,6 +581,11 @@
 	/* Avoid spurious interrupt if any */
 	get_reset_pmovsr();
 
+	/* Clear counter enables */
+	disable_counter(l2_cycle_ctr_idx);
+	for (i = 0; i < total_l2_ctrs; i++)
+		disable_counter(i);
+
 	return platform_driver_register(&krait_l2_pmu_driver);
 }
 device_initcall(register_krait_l2_pmu_driver);
diff --git a/arch/arm/mach-msm/perf_trace_counters.c b/arch/arm/mach-msm/perf_trace_counters.c
index 8fa73ae..8eb1244 100644
--- a/arch/arm/mach-msm/perf_trace_counters.c
+++ b/arch/arm/mach-msm/perf_trace_counters.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
@@ -17,21 +17,78 @@
 
 static unsigned int tp_pid_state;
 
+DEFINE_PER_CPU(u32, previous_ccnt);
+DEFINE_PER_CPU(u32[NUM_L1_CTRS], previous_l1_cnts);
+DEFINE_PER_CPU(u32[NUM_L2_PERCPU], previous_l2_cnts);
+DEFINE_PER_CPU(u32, old_pid);
+DEFINE_PER_CPU(u32, hotplug_flag);
+/* Reset per_cpu variables that store counter values uppn CPU hotplug */
+static int tracectr_cpu_hotplug_notifier(struct notifier_block *self,
+				    unsigned long action, void *hcpu)
+{
+	int ret = NOTIFY_OK;
+	int cpu = (int)hcpu;
+
+	if ((action & (~CPU_TASKS_FROZEN)) == CPU_STARTING)
+		per_cpu(hotplug_flag, cpu) = 1;
+
+	return ret;
+}
+
+static struct notifier_block tracectr_cpu_hotplug_notifier_block = {
+	.notifier_call = tracectr_cpu_hotplug_notifier,
+};
+
+static void setup_prev_cnts(u32 cpu)
+{
+	int i;
+	u32 cnten_val;
+
+	/* Read PMCNTENSET */
+	asm volatile("mrc p15, 0, %0, c9, c12, 1" : "=r"(cnten_val));
+	/* Disable all the counters that were enabled */
+	asm volatile("mcr p15, 0, %0, c9, c12, 2" : : "r"(cnten_val));
+	if (cnten_val & CC) {
+		/* Read value */
+		asm volatile("mrc p15, 0, %0, c9, c13, 0"
+			: "=r"(per_cpu(previous_ccnt, cpu)));
+	}
+
+	for (i = 0; i < NUM_L1_CTRS; i++) {
+		if (cnten_val & (1 << i)) {
+			/* Select */
+			asm volatile("mcr p15, 0, %0, c9, c12, 5"
+				: : "r"(i));
+			/* Read value */
+			asm volatile("mrc p15, 0, %0, c9, c13, 2"
+				: "=r"(per_cpu(previous_l1_cnts[i], cpu)));
+		}
+	}
+	/* Enable all the counters that were disabled */
+	asm volatile("mcr p15, 0, %0, c9, c12, 1" : : "r"(cnten_val));
+}
+
 static int tracectr_notifier(struct notifier_block *self, unsigned long cmd,
 		void *v)
 {
-	static int old_pid = -1;
 	struct thread_info *thread = v;
 	int current_pid;
+	u32 cpu = thread->cpu;
 
 	if (cmd != THREAD_NOTIFY_SWITCH)
-		return old_pid;
+		return -EFAULT;
 
 	current_pid = thread->task->pid;
-	if (old_pid != -1)
-		trace_sched_switch_with_ctrs(old_pid, current_pid);
-	old_pid = current_pid;
-	return old_pid;
+	if (per_cpu(old_pid, cpu) != -1) {
+		if (per_cpu(hotplug_flag, cpu) == 1) {
+			per_cpu(hotplug_flag, cpu) = 0;
+			setup_prev_cnts(cpu);
+		} else
+			trace_sched_switch_with_ctrs(per_cpu(old_pid, cpu),
+				current_pid);
+	}
+	per_cpu(old_pid, cpu) = current_pid;
+	return NOTIFY_OK;
 }
 
 static struct notifier_block tracectr_notifier_block = {
@@ -102,6 +159,7 @@
 	struct dentry *dir;
 	struct dentry *file;
 	unsigned int value = 1;
+	int cpu;
 
 	dir = debugfs_create_dir("perf_debug_tp", NULL);
 	if (!dir)
@@ -112,6 +170,15 @@
 		debugfs_remove(dir);
 		return -ENOMEM;
 	}
+	register_cpu_notifier(&tracectr_cpu_hotplug_notifier_block);
+	for_each_possible_cpu(cpu)
+		per_cpu(old_pid, cpu) = -1;
+	return 0;
+}
+
+int __exit exit_tracecounters(void)
+{
+	unregister_cpu_notifier(&tracectr_cpu_hotplug_notifier_block);
 	return 0;
 }
 late_initcall(init_tracecounters);
diff --git a/arch/arm/mach-msm/perf_trace_counters.h b/arch/arm/mach-msm/perf_trace_counters.h
index 8f77bad..fce176e 100644
--- a/arch/arm/mach-msm/perf_trace_counters.h
+++ b/arch/arm/mach-msm/perf_trace_counters.h
@@ -19,14 +19,21 @@
 /* Ctr index for PMCNTENSET/CLR */
 #define CC 0x80000000
 #define C0 0x1
-#define C1 0x10
-#define C2 0x100
-#define C3 0x1000
-
+#define C1 0x2
+#define C2 0x4
+#define C3 0x8
+#define C_ALL (CC | C0 | C1 | C2 | C3)
+#define NUM_L1_CTRS 4
+#define NUM_L2_PERCPU 2
 
 #include <linux/sched.h>
+#include <linux/cpumask.h>
 #include <linux/tracepoint.h>
+#include <mach/msm-krait-l2-accessors.h>
 
+DECLARE_PER_CPU(u32, previous_ccnt);
+DECLARE_PER_CPU(u32[NUM_L1_CTRS], previous_l1_cnts);
+DECLARE_PER_CPU(u32[NUM_L2_PERCPU], previous_l2_cnts);
 TRACE_EVENT(sched_switch_with_ctrs,
 
 		TP_PROTO(pid_t prev, pid_t next),
@@ -41,82 +48,112 @@
 			__field(u32, ctr1)
 			__field(u32, ctr2)
 			__field(u32, ctr3)
+			__field(u32, lctr0)
+			__field(u32, lctr1)
 		),
 
 		TP_fast_assign(
+			u32 cpu = smp_processor_id();
+			u32 idx;
+			u32 i;
+			u32 counter_reg;
+			u32 val;
+			u32 cnten_val;
+			u32 num_l2ctrs;
+			u32 num_cores = nr_cpu_ids;
+			u32 total_ccnt = 0;
+			u32 total_cnt = 0;
+			u32 delta_l1_cnts[NUM_L1_CTRS];
+			u32 delta_l2_cnts[NUM_L2_PERCPU];
 			__entry->old_pid	= prev;
 			__entry->new_pid	= next;
 
-			/* cycle counter */
-			/* Disable */
-			asm volatile("mcr p15, 0, %0, c9, c12, 2" : : "r"(CC));
-			/* Read value */
-			asm volatile("mrc p15, 0, %0, c9, c13, 0"
-				: "=r"(__entry->cctr));
-			/* Reset */
-			asm volatile("mcr p15, 0, %0, c9, c13, 0" : : "r"(0));
-			/* Enable */
-			asm volatile("mcr p15, 0, %0, c9, c12, 1" : : "r"(CC));
+			val = get_l2_indirect_reg(L2PMCR);
+			num_l2ctrs = ((val >> 11) & 0x1f) + 1;
 
-			/* ctr 0 */
-			/* Disable */
-			asm volatile("mcr p15, 0, %0, c9, c12, 2" : : "r"(C0));
-			/* Select */
-			asm volatile("mcr p15, 0, %0, c9, c12, 5" : : "r"(0));
-			/* Read value */
-			asm volatile("mrc p15, 0, %0, c9, c13, 2"
-					: "=r"(__entry->ctr0));
-			/* Reset */
-			asm volatile("mcr p15, 0, %0, c9, c13, 2" : : "r"(0));
-			/* Enable */
-			asm volatile("mcr p15, 0, %0, c9, c12, 1" : : "r"(C0));
+			/* Read PMCNTENSET */
+			asm volatile("mrc p15, 0, %0, c9, c12, 1"
+						: "=r"(cnten_val));
+			/* Disable all the counters that were enabled */
+			asm volatile("mcr p15, 0, %0, c9, c12, 2"
+					: : "r"(cnten_val));
+			if (cnten_val & CC) {
+				/* Read value */
+				asm volatile("mrc p15, 0, %0, c9, c13, 0"
+					: "=r"(total_ccnt));
+				__entry->cctr = total_ccnt -
+					per_cpu(previous_ccnt, cpu);
+				per_cpu(previous_ccnt, cpu) = total_ccnt;
+			}
+			for (i = 0; i < NUM_L1_CTRS; i++) {
+				if (cnten_val & (1 << i)) {
+					/* Select */
+					asm volatile(
+						"mcr p15, 0, %0, c9, c12, 5"
+						: : "r"(i));
+					/* Read value */
+					asm volatile(
+						"mrc p15, 0, %0, c9, c13, 2"
+						: "=r"(total_cnt));
 
-			/* ctr 1 */
-			/* Disable */
-			asm volatile("mcr p15, 0, %0, c9, c12, 2" : : "r"(C1));
-			/* Select */
-			asm volatile("mcr p15, 0, %0, c9, c12, 5" : : "r"(1));
-			/* Read value */
-			asm volatile("mrc p15, 0, %0, c9, c13, 2"
-					: "=r"(__entry->ctr1));
-			/* Reset */
-			asm volatile("mcr p15, 0, %0, c9, c13, 2" : : "r"(0));
-			/* Enable */
-			asm volatile("mcr p15, 0, %0, c9, c12, 1" : : "r"(C1));
+					delta_l1_cnts[i] = total_cnt -
+					  per_cpu(previous_l1_cnts[i], cpu);
+					per_cpu(previous_l1_cnts[i], cpu) =
+						total_cnt;
+				} else
+					delta_l1_cnts[i] = 0;
+			}
+			/* Enable all the counters that were disabled */
+			asm volatile("mcr p15, 0, %0, c9, c12, 1"
+					: : "r"(cnten_val));
 
-			/* ctr 2 */
-			/* Disable */
-			asm volatile("mcr p15, 0, %0, c9, c12, 2" : : "r"(C2));
-			/* Select */
-			asm volatile("mcr p15, 0, %0, c9, c12, 5" : : "r"(2));
-			/* Read value */
-			asm volatile("mrc p15, 0, %0, c9, c13, 2"
-					: "=r"(__entry->ctr2));
-			/* Reset */
-			asm volatile("mcr p15, 0, %0, c9, c13, 2" : : "r"(0));
-			/* Enable */
-			asm volatile("mcr p15, 0, %0, c9, c12, 1" : : "r"(C2));
-
-			/* ctr 3 */
-			/* Disable */
-			asm volatile("mcr p15, 0, %0, c9, c12, 2" : : "r"(C3));
-			/* Select */
-			asm volatile("mcr p15, 0, %0, c9, c12, 5" : : "r"(3));
-			/* Read value */
-			asm volatile("mrc p15, 0, %0, c9, c13, 2"
-					: "=r"(__entry->ctr3));
-			/* Reset */
-			asm volatile("mcr p15, 0, %0, c9, c13, 2" : : "r"(0));
-			/* Enable */
-			asm volatile("mcr p15, 0, %0, c9, c12, 1" : : "r"(C3));
-
+			/* L2 counters */
+			/* Assign L2 counters to cores sequentially starting
+			 * from zero. A core could have multiple L2 counters
+			 * allocated if # L2 counters is more than the # cores
+			 */
+			cnten_val = get_l2_indirect_reg(L2PMCNTENSET);
+			for (i = 0; i < NUM_L2_PERCPU; i++) {
+				idx = cpu + (num_cores * i);
+				if (idx < num_l2ctrs &&
+						(cnten_val & (1 << idx))) {
+					/* Disable */
+					set_l2_indirect_reg(L2PMCNTENCLR,
+						(1 << idx));
+					/* L2PMEVCNTR values go from 0x421,
+					 * 0x431..
+					 * So we multiply idx by 16 to get the
+					 * counter reg value
+					 */
+					counter_reg = (idx * 16) +
+						IA_L2PMXEVCNTR_BASE;
+					total_cnt =
+					  get_l2_indirect_reg(counter_reg);
+					/* Enable */
+					set_l2_indirect_reg(L2PMCNTENSET,
+						(1 << idx));
+					delta_l2_cnts[i] = total_cnt -
+					  per_cpu(previous_l2_cnts[i], cpu);
+					per_cpu(previous_l2_cnts[i], cpu) =
+						total_cnt;
+				} else
+					delta_l2_cnts[i] = 0;
+			}
+			__entry->ctr0 = delta_l1_cnts[0];
+			__entry->ctr1 = delta_l1_cnts[1];
+			__entry->ctr2 = delta_l1_cnts[2];
+			__entry->ctr3 = delta_l1_cnts[3];
+			__entry->lctr0 = delta_l2_cnts[0];
+			__entry->lctr1 = delta_l2_cnts[1];
 		),
 
 		TP_printk("prev_pid=%d, next_pid=%d, CCNTR: %u, CTR0: %u," \
-				" CTR1: %u, CTR2: %u, CTR3: %u",
+				" CTR1: %u, CTR2: %u, CTR3: %u," \
+				" L2CTR0: %u, L2CTR1: %u",
 				__entry->old_pid, __entry->new_pid,
 				__entry->cctr, __entry->ctr0, __entry->ctr1,
-				__entry->ctr2, __entry->ctr3)
+				__entry->ctr2, __entry->ctr3,
+				__entry->lctr0, __entry->lctr1)
 );
 
 #endif
diff --git a/arch/arm/mach-msm/peripheral-loader.c b/arch/arm/mach-msm/peripheral-loader.c
index 157dc01..285c02a 100644
--- a/arch/arm/mach-msm/peripheral-loader.c
+++ b/arch/arm/mach-msm/peripheral-loader.c
@@ -515,7 +515,7 @@
 	}
 }
 
-#define IOMAP_SIZE SZ_4M
+#define IOMAP_SIZE SZ_1M
 
 static int pil_load_seg(struct pil_desc *desc, struct pil_seg *seg)
 {
diff --git a/arch/arm/mach-msm/pil-pronto.c b/arch/arm/mach-msm/pil-pronto.c
index 69df3ae..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
@@ -85,6 +88,7 @@
 	bool crash;
 	struct delayed_work cancel_vote_work;
 	struct ramdump_device *ramdump_dev;
+	struct work_struct wcnss_wdog_bite_work;
 };
 
 static int pil_pronto_make_proxy_vote(struct pil_desc *pil)
@@ -322,6 +326,16 @@
 	return IRQ_HANDLED;
 }
 
+static void wcnss_wdog_bite_work_hdlr(struct work_struct *wcnss_work)
+{
+	struct pronto_data *drv = container_of(wcnss_work, struct pronto_data,
+		wcnss_wdog_bite_work);
+
+	wcnss_log_debug_regs_on_bite();
+
+	restart_wcnss(drv);
+}
+
 static irqreturn_t wcnss_wdog_bite_irq_hdlr(int irq, void *dev_id)
 {
 	struct pronto_data *drv = subsys_to_drv(dev_id);
@@ -334,10 +348,9 @@
 		pr_err("Ignoring wcnss bite irq, restart in progress\n");
 		return IRQ_HANDLED;
 	}
-	wcnss_log_debug_regs_on_bite();
 
 	drv->restart_inprogress = true;
-	restart_wcnss(drv);
+	schedule_work(&drv->wcnss_wdog_bite_work);
 
 	return IRQ_HANDLED;
 }
@@ -366,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,
@@ -490,6 +511,7 @@
 	drv->subsys_desc.wdog_bite_handler = wcnss_wdog_bite_irq_hdlr;
 
 	INIT_DELAYED_WORK(&drv->cancel_vote_work, wcnss_post_bootup);
+	INIT_WORK(&drv->wcnss_wdog_bite_work, wcnss_wdog_bite_work_hdlr);
 
 	drv->subsys = subsys_register(&drv->subsys_desc);
 	if (IS_ERR(drv->subsys)) {
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/pm-stats.c b/arch/arm/mach-msm/pm-stats.c
index c4e52be..5614ddd 100644
--- a/arch/arm/mach-msm/pm-stats.c
+++ b/arch/arm/mach-msm/pm-stats.c
@@ -225,6 +225,14 @@
 			stats[i].total_time = 0;
 		}
 	}
+	memset(suspend_stats.bucket,
+		0, sizeof(suspend_stats.bucket));
+	memset(suspend_stats.min_time,
+		0, sizeof(suspend_stats.min_time));
+	memset(suspend_stats.max_time,
+		0, sizeof(suspend_stats.max_time));
+	suspend_stats.count = 0;
+	suspend_stats.total_time = 0;
 
 	spin_unlock_irqrestore(&msm_pm_stats_lock, flags);
 	return count;
diff --git a/arch/arm/mach-msm/qdsp6v2/Makefile b/arch/arm/mach-msm/qdsp6v2/Makefile
index 6bd3efb..3d7638d 100644
--- a/arch/arm/mach-msm/qdsp6v2/Makefile
+++ b/arch/arm/mach-msm/qdsp6v2/Makefile
@@ -12,7 +12,7 @@
 obj-$(CONFIG_FB_MSM_HDMI_MSM_PANEL) += lpa_if_hdmi.o
 endif
 obj-$(CONFIG_MSM_QDSP6_APR) += apr.o apr_v1.o apr_tal.o q6core.o dsp_debug.o
-obj-$(CONFIG_MSM_QDSP6_APRV2) += apr.o apr_v2.o apr_tal.o dsp_debug.o
+obj-$(CONFIG_MSM_QDSP6_APRV2) += apr.o apr_v2.o apr_tal.o dsp_debug.o voice_svc.o
 ifdef CONFIG_ARCH_MSM9615
 obj-y += audio_acdb.o
 obj-y += rtac.o
diff --git a/arch/arm/mach-msm/qdsp6v2/apr.c b/arch/arm/mach-msm/qdsp6v2/apr.c
index 8d9ad29..937eeda 100644
--- a/arch/arm/mach-msm/qdsp6v2/apr.c
+++ b/arch/arm/mach-msm/qdsp6v2/apr.c
@@ -436,7 +436,7 @@
 	if (data.payload_size > 0)
 		data.payload = (char *)hdr + hdr_size;
 
-	temp_port = ((data.src_port >> 8) * 8) + (data.src_port & 0xFF);
+	temp_port = ((data.dest_port >> 8) * 8) + (data.dest_port & 0xFF);
 	pr_debug("port = %d t_port = %d\n", data.src_port, temp_port);
 	if (c_svc->port_cnt && c_svc->port_fn[temp_port])
 		c_svc->port_fn[temp_port](&data,  c_svc->port_priv[temp_port]);
diff --git a/arch/arm/mach-msm/qdsp6v2/apr_tal.c b/arch/arm/mach-msm/qdsp6v2/apr_tal.c
index 8826a35..e917f31 100644
--- a/arch/arm/mach-msm/qdsp6v2/apr_tal.c
+++ b/arch/arm/mach-msm/qdsp6v2/apr_tal.c
@@ -190,6 +190,9 @@
 		apr_tal_close(&apr_svc_ch[dl][dest][svc]);
 		return NULL;
 	}
+
+	smd_disable_read_intr(apr_svc_ch[dl][dest][svc].ch);
+
 	if (!apr_svc_ch[dl][dest][svc].dest_state) {
 		apr_svc_ch[dl][dest][svc].dest_state = 1;
 		pr_debug("apr_tal:Waiting for apr svc init\n");
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_utils.c b/arch/arm/mach-msm/qdsp6v2/audio_utils.c
index 2f1ff3e..109e120 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_utils.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_utils.c
@@ -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
@@ -23,6 +23,11 @@
 #include <asm/ioctls.h>
 #include "audio_utils.h"
 
+#define MIN_FRAME_SIZE  1536
+#define NUM_FRAMES      5
+#define META_SIZE       (sizeof(struct meta_out_dsp))
+#define FRAME_SIZE      (1 + ((MIN_FRAME_SIZE + META_SIZE) * NUM_FRAMES))
+
 static int audio_in_pause(struct q6audio_in  *audio)
 {
 	int rc;
@@ -258,6 +263,11 @@
 			rc = -EINVAL;
 			break;
 		}
+		if ((cfg.buffer_size > FRAME_SIZE) ||
+			(cfg.buffer_count != FRAME_NUM)) {
+			rc = -EINVAL;
+			break;
+		}
 		audio->str_cfg.buffer_size = cfg.buffer_size;
 		audio->str_cfg.buffer_count = cfg.buffer_count;
 		if(audio->opened){
diff --git a/arch/arm/mach-msm/qdsp6v2/msm_audio_ion.c b/arch/arm/mach-msm/qdsp6v2/msm_audio_ion.c
index fc6de64..df7760a 100644
--- a/arch/arm/mach-msm/qdsp6v2/msm_audio_ion.c
+++ b/arch/arm/mach-msm/qdsp6v2/msm_audio_ion.c
@@ -1,5 +1,5 @@
 /*
- * 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
@@ -344,7 +344,7 @@
 		pr_err("%s: ion import dma buffer failed\n",
 			__func__);
 		rc = -EINVAL;
-		goto err_destroy_client;
+		goto err;
 	}
 
 	if (ionflag != NULL) {
@@ -380,10 +380,6 @@
 
 err_ion_handle:
 	ion_free(client, *handle);
-err_destroy_client:
-	msm_audio_ion_client_destroy(client);
-	client = NULL;
-	*handle = NULL;
 err:
 	return rc;
 }
@@ -391,7 +387,9 @@
 int msm_audio_ion_free_legacy(struct ion_client *client,
 			      struct ion_handle *handle)
 {
-	/* To add condition for SMMU enabled */
+	if (msm_audio_ion_data.smmu_enabled)
+		ion_unmap_iommu(client, handle,
+		msm_audio_ion_data.domain_id, 0);
 	ion_unmap_kernel(client, handle);
 
 	ion_free(client, handle);
diff --git a/arch/arm/mach-msm/qdsp6v2/ultrasound/usf.c b/arch/arm/mach-msm/qdsp6v2/ultrasound/usf.c
index a18d0f3..192aaf9 100644
--- a/arch/arm/mach-msm/qdsp6v2/ultrasound/usf.c
+++ b/arch/arm/mach-msm/qdsp6v2/ultrasound/usf.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
@@ -27,8 +27,8 @@
 #include "usfcdev.h"
 
 /* The driver version*/
-#define DRV_VERSION "1.5.1"
-#define USF_VERSION_ID 0x0151
+#define DRV_VERSION "1.6.1"
+#define USF_VERSION_ID 0x0161
 
 /* Standard timeout in the asynchronous ops */
 #define USF_TIMEOUT_JIFFIES (1*HZ) /* 1 sec */
@@ -70,6 +70,7 @@
 	USF_OPENED_STATE,
 	USF_CONFIGURED_STATE,
 	USF_WORK_STATE,
+	USF_ADSP_RESTART_STATE,
 	USF_ERROR_STATE
 };
 
@@ -118,14 +119,12 @@
 	uint16_t event_types;
 	/*  The input devices are "input" module registered clients */
 	struct input_dev *input_ifs[USF_MAX_EVENT_IND];
-	/*  The event source */
-	int event_src;
 	/* Bitmap of types of events, conflicting to USF's ones */
 	uint16_t conflicting_event_types;
 	/* Bitmap of types of events from devs, conflicting with USF */
 	uint16_t conflicting_event_filters;
-	/* The requested side buttons bitmap */
-	uint16_t req_side_buttons_bitmap;
+	/* The requested buttons bitmap */
+	uint16_t req_buttons_bitmap;
 };
 
 struct usf_input_dev_type {
@@ -148,17 +147,22 @@
 /* The MAX number of the supported devices */
 #define MAX_DEVS_NUMBER	1
 
-/* The opened devices container */
-static const int s_event_src_map[] = {
-	BTN_TOOL_PEN, /* US_INPUT_SRC_PEN*/
-	0,            /* US_INPUT_SRC_FINGER */
-	0,            /* US_INPUT_SRC_UNDEF */
-};
+/*
+ * code for a special button that is used to show/hide a
+ * hovering cursor in the input framework. Must be in
+ * sync with the button code definition in the framework
+ * (EventHub.h)
+ */
+#define BTN_USF_HOVERING_CURSOR         0x230
 
 /* Supported buttons container */
 static const int s_button_map[] = {
 	BTN_STYLUS,
-	BTN_STYLUS2
+	BTN_STYLUS2,
+	BTN_TOOL_PEN,
+	BTN_TOOL_RUBBER,
+	BTN_TOOL_FINGER,
+	BTN_USF_HOVERING_CURSOR
 };
 
 /* The opened devices container */
@@ -192,31 +196,32 @@
 				const char *name)
 {
 	int i = 0;
-	int num_side_buttons = min(ARRAY_SIZE(s_button_map),
-		sizeof(input_info->req_side_buttons_bitmap) *
+
+	int num_buttons = min(ARRAY_SIZE(s_button_map),
+		sizeof(input_info->req_buttons_bitmap) *
 		BITS_IN_BYTE);
-	uint16_t max_side_button_bitmap = ((1 << ARRAY_SIZE(s_button_map)) - 1);
+	uint16_t max_buttons_bitmap = ((1 << ARRAY_SIZE(s_button_map)) - 1);
+
 	struct input_dev *in_dev = allocate_dev(ind, name);
 	if (in_dev == NULL)
 		return -ENOMEM;
 
-	if (input_info->req_side_buttons_bitmap > max_side_button_bitmap) {
-		pr_err("%s: Requested side buttons[%d] exceeds max side buttons available[%d]\n",
+	if (input_info->req_buttons_bitmap > max_buttons_bitmap) {
+		pr_err("%s: Requested buttons[%d] exceeds max buttons available[%d]\n",
 		__func__,
-		input_info->req_side_buttons_bitmap,
-		max_side_button_bitmap);
+		input_info->req_buttons_bitmap,
+		max_buttons_bitmap);
 		return -EINVAL;
 	}
 
 	usf_info->input_ifs[ind] = in_dev;
-	usf_info->req_side_buttons_bitmap =
-		input_info->req_side_buttons_bitmap;
+	usf_info->req_buttons_bitmap =
+		input_info->req_buttons_bitmap;
 	in_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
 	in_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
 
-
-	for (i = 0; i < num_side_buttons; i++)
-		if (input_info->req_side_buttons_bitmap & (1 << i))
+	for (i = 0; i < num_buttons; i++)
+		if (input_info->req_buttons_bitmap & (1 << i))
 			in_dev->keybit[BIT_WORD(s_button_map[i])] |=
 			BIT_MASK(s_button_map[i]);
 
@@ -297,8 +302,8 @@
 
 {
 	int i = 0;
-	int num_side_buttons = min(ARRAY_SIZE(s_button_map),
-		sizeof(usf_info->req_side_buttons_bitmap) *
+	int num_buttons = min(ARRAY_SIZE(s_button_map),
+		sizeof(usf_info->req_buttons_bitmap) *
 		BITS_IN_BYTE);
 
 	struct input_dev *input_if = usf_info->input_ifs[if_ind];
@@ -314,19 +319,16 @@
 	input_report_abs(input_if, ABS_PRESSURE, pe->pressure);
 	input_report_key(input_if, BTN_TOUCH, !!(pe->pressure));
 
-	for (i = 0; i < num_side_buttons; i++) {
+	for (i = 0; i < num_buttons; i++) {
 		uint16_t mask = (1 << i),
-		btn_state = !!(pe->side_buttons_state_bitmap & mask);
-		if (usf_info->req_side_buttons_bitmap & mask)
+		btn_state = !!(pe->buttons_state_bitmap & mask);
+		if (usf_info->req_buttons_bitmap & mask)
 			input_report_key(input_if, s_button_map[i], btn_state);
 	}
 
-	if (usf_info->event_src)
-		input_report_key(input_if, usf_info->event_src, 1);
-
 	input_sync(input_if);
 
-	pr_debug("%s: TSC event: xyz[%d;%d;%d], incl[%d;%d], pressure[%d], side_buttons[%d]\n",
+	pr_debug("%s: TSC event: xyz[%d;%d;%d], incl[%d;%d], pressure[%d], buttons[%d]\n",
 		 __func__,
 		 pe->coordinates[X_IND],
 		 pe->coordinates[Y_IND],
@@ -334,7 +336,7 @@
 		 pe->inclinations[X_IND],
 		 pe->inclinations[Y_IND],
 		 pe->pressure,
-		 pe->side_buttons_state_bitmap);
+		 pe->buttons_state_bitmap);
 }
 
 static void notify_mouse_event(struct usf_type *usf_info,
@@ -405,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;
 	}
@@ -444,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;
 	}
@@ -663,12 +678,6 @@
 		return -EINVAL;
 	}
 
-	if (input_info->event_src < ARRAY_SIZE(s_event_src_map))
-		usf_info->event_src =
-			s_event_src_map[input_info->event_src];
-	else
-		usf_info->event_src = 0;
-
 	for (ind = 0; ind < USF_MAX_EVENT_IND; ++ind) {
 		if (usf_info->input_ifs[ind] != NULL) {
 			pr_err("%s: input_if[%d] is already allocated\n",
@@ -686,12 +695,6 @@
 			if (rc)
 				return rc;
 
-
-			if (usf_info->event_src)
-				input_set_capability(usf_info->input_ifs[ind],
-						     EV_KEY,
-						     usf_info->event_src);
-
 			rc = input_register_device(usf_info->input_ifs[ind]);
 			if (rc) {
 				pr_err("%s: input_reg_dev() failed; rc=%d\n",
@@ -876,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;
@@ -885,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",
@@ -1347,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",
@@ -1360,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/qdsp6v2/voice_svc.c b/arch/arm/mach-msm/qdsp6v2/voice_svc.c
new file mode 100644
index 0000000..92b3003
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/voice_svc.c
@@ -0,0 +1,593 @@
+/* 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/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/uaccess.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/cdev.h>
+#include <sound/voice_svc.h>
+#include <mach/qdsp6v2/apr_tal.h>
+#include <mach/qdsp6v2/apr.h>
+
+#define DRIVER_NAME "voice_svc"
+#define MINOR_NUMBER 1
+#define APR_MAX_RESPONSE 10
+
+#define MAX(a, b) ((a) >= (b) ? (a) : (b))
+
+struct voice_svc_device {
+	struct cdev *cdev;
+	struct device *dev;
+	int major;
+};
+
+struct voice_svc_prvt {
+	void* apr_q6_mvm;
+	void* apr_q6_cvs;
+	uint16_t response_count;
+	struct list_head response_queue;
+	wait_queue_head_t response_wait;
+	spinlock_t response_lock;
+};
+
+struct apr_data {
+	struct apr_hdr hdr;
+	__u8 payload[0];
+} __packed;
+
+struct apr_response_list {
+	struct list_head list;
+	struct voice_svc_cmd_response resp;
+};
+
+static struct voice_svc_device *voice_svc_dev;
+static struct class *voice_svc_class;
+dev_t device_num;
+
+static int32_t qdsp_apr_callback(struct apr_client_data *data, void *priv)
+{
+	struct voice_svc_prvt *prtd;
+	struct apr_response_list *response_list;
+	unsigned long spin_flags;
+
+	if ((data == NULL) || (priv == NULL)) {
+		pr_err("%s: data or priv is NULL\n", __func__);
+		return -EINVAL;
+	}
+
+	prtd = (struct voice_svc_prvt*)priv;
+
+	pr_debug("%s: data->opcode %x\n", __func__,
+		 data->opcode);
+
+	if (data->opcode == RESET_EVENTS) {
+		if (data->reset_proc == APR_DEST_QDSP6) {
+			pr_debug("%s: Received reset event\n", __func__);
+
+			if (prtd->apr_q6_mvm != NULL) {
+				apr_reset(prtd->apr_q6_mvm);
+				prtd->apr_q6_mvm = NULL;
+			}
+
+			if (prtd->apr_q6_cvs != NULL) {
+				apr_reset(prtd->apr_q6_cvs);
+				prtd->apr_q6_cvs = NULL;
+			}
+		} else if (data->reset_proc ==APR_DEST_MODEM) {
+			pr_debug("%s: Received Modem reset event\n", __func__);
+		}
+	}
+
+	spin_lock_irqsave(&prtd->response_lock, spin_flags);
+
+	if (prtd->response_count < APR_MAX_RESPONSE) {
+		response_list = (struct apr_response_list *)kmalloc(
+			sizeof(struct apr_response_list) + data->payload_size,
+			GFP_ATOMIC);
+		if (response_list == NULL) {
+			pr_err("%s: kmalloc failed\n", __func__);
+
+			return -ENOMEM;
+		}
+
+		response_list->resp.src_port = data->src_port;
+		response_list->resp.dest_port = ((data->dest_port) >> 8);
+		response_list->resp.token = data->token;
+		response_list->resp.opcode = data->opcode;
+		response_list->resp.payload_size = data->payload_size;
+		if (data->payload != NULL && data->payload_size > 0) {
+			memcpy(response_list->resp.payload, data->payload,
+				data->payload_size);
+		}
+
+		list_add_tail(&response_list->list, &prtd->response_queue);
+		prtd->response_count++;
+
+		wake_up(&prtd->response_wait);
+	} else {
+		pr_err("%s: Response dropped since the queue is full\n", __func__);
+	}
+
+	spin_unlock_irqrestore(&prtd->response_lock, spin_flags);
+
+	return 0;
+}
+
+static void voice_svc_update_hdr(struct voice_svc_cmd_request* apr_req_data,
+			    struct apr_data *aprdata,
+			    struct voice_svc_prvt *prtd)
+{
+
+	aprdata->hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD, \
+				       APR_HDR_LEN(sizeof(struct apr_hdr)),\
+				       APR_PKT_VER);
+	aprdata->hdr.src_port = ((apr_req_data->src_port) << 8 | 0x0001);
+	aprdata->hdr.dest_port = apr_req_data->dest_port;
+	aprdata->hdr.token = apr_req_data->token;
+	aprdata->hdr.opcode = apr_req_data->opcode;
+	aprdata->hdr.pkt_size  = APR_PKT_SIZE(APR_HDR_SIZE,
+					apr_req_data->payload_size);
+	memcpy(aprdata->payload, apr_req_data->payload,
+	       apr_req_data->payload_size);
+}
+
+static int voice_svc_send_req(struct voice_svc_cmd_request *apr_request,
+			      struct voice_svc_prvt *prtd)
+{
+	int ret = 0;
+	void *apr_handle = NULL;
+	struct apr_data *aprdata = NULL;
+	uint32_t user_payload_size = 0;
+
+	if (apr_request == NULL) {
+		pr_err("%s: apr_request is NULL\n", __func__);
+
+		ret = -EINVAL;
+		goto done;
+	}
+
+	user_payload_size = apr_request->payload_size;
+
+	aprdata = kmalloc(sizeof(struct apr_data) + user_payload_size,
+			  GFP_KERNEL);
+
+	if (aprdata == NULL) {
+		pr_err("%s: aprdata kmalloc failed.", __func__);
+
+		ret = -ENOMEM;
+		goto done;
+	}
+
+	voice_svc_update_hdr(apr_request, aprdata, prtd);
+
+	if (!strncmp(apr_request->svc_name, VOICE_SVC_CVS_STR,
+	    MAX(sizeof(apr_request->svc_name), sizeof(VOICE_SVC_CVS_STR)))) {
+		apr_handle = prtd->apr_q6_cvs;
+	} else if (!strncmp(apr_request->svc_name, VOICE_SVC_MVM_STR,
+	    MAX(sizeof(apr_request->svc_name), sizeof(VOICE_SVC_MVM_STR)))) {
+		apr_handle = prtd->apr_q6_mvm;
+	} else {
+		pr_err("%s: Invalid service %s\n", __func__,
+			apr_request->svc_name);
+
+		ret = -EINVAL;
+		goto done;
+	}
+
+	ret = apr_send_pkt(apr_handle, (uint32_t *)aprdata);
+
+	if (ret < 0) {
+		pr_err("%s: Fail in sending SNDRV_VOICE_SVC_REQUEST\n",
+			__func__);
+		ret = -EINVAL;
+	} else {
+		pr_debug("%s: apr packet sent successfully %d\n",
+				__func__, ret);
+		ret = 0;
+	}
+
+done:
+	if (aprdata != NULL)
+		kfree(aprdata);
+
+	return ret;
+}
+static int voice_svc_reg(char *svc, uint32_t src_port,
+			 struct voice_svc_prvt *prtd, void **handle)
+{
+	int ret = 0;
+
+	if (handle == NULL) {
+		pr_err("%s: handle is NULL\n", __func__);
+		ret = -EINVAL;
+		goto done;
+	}
+
+	if (*handle != NULL) {
+		pr_err("%s: svc handle not NULL\n", __func__);
+		ret = -EINVAL;
+		goto done;
+	}
+
+	*handle = apr_register("ADSP",
+		svc, qdsp_apr_callback,
+		((src_port) << 8 | 0x0001),
+		prtd);
+
+	if (*handle == NULL) {
+		pr_err("%s: Unable to register %s\n",
+		__func__, svc);
+
+		ret = -EFAULT;
+		goto done;
+	}
+	pr_debug("%s: register %s successful\n",
+		__func__, svc);
+done:
+	return ret;
+}
+
+static int voice_svc_dereg(char *svc, void **handle)
+{
+	int ret = 0;
+	if (handle == NULL) {
+		pr_err("%s: handle is NULL\n", __func__);
+		ret = -EINVAL;
+		goto done;
+	}
+
+	apr_deregister(*handle);
+	*handle = NULL;
+	pr_debug("%s: deregister %s successful\n",
+		__func__, svc);
+
+done:
+	return 0;
+}
+
+static int process_reg_cmd(struct voice_svc_register apr_reg_svc,
+			     struct voice_svc_prvt *prtd)
+{
+	int ret = 0;
+	char *svc = NULL;
+	void **handle = NULL;
+
+	if (!strncmp(apr_reg_svc.svc_name, VOICE_SVC_MVM_STR,
+	    MAX(sizeof(apr_reg_svc.svc_name), sizeof(VOICE_SVC_MVM_STR)))) {
+		svc = VOICE_SVC_MVM_STR;
+		handle = &prtd->apr_q6_mvm;
+	} else if (!strncmp(apr_reg_svc.svc_name, VOICE_SVC_CVS_STR,
+            MAX(sizeof(apr_reg_svc.svc_name), sizeof(VOICE_SVC_CVS_STR)))) {
+		svc = VOICE_SVC_CVS_STR;
+		handle = &prtd->apr_q6_cvs;
+	} else {
+		pr_err("%s: Invalid Service: %s\n", __func__,
+				apr_reg_svc.svc_name);
+		ret = -EINVAL;
+		goto done;
+	}
+
+	if (*handle == NULL &&
+	    apr_reg_svc.reg_flag) {
+		ret = voice_svc_reg(svc, apr_reg_svc.src_port, prtd,
+				    handle);
+	} else if (handle != NULL &&
+		   !apr_reg_svc.reg_flag) {
+		ret = voice_svc_dereg(svc, handle);
+	}
+
+done:
+	return ret;
+}
+
+static long voice_svc_ioctl(struct file *file, unsigned int cmd,
+			    unsigned long u_arg)
+{
+	int ret = 0;
+	struct voice_svc_prvt *prtd;
+	struct voice_svc_register apr_reg_svc;
+	struct voice_svc_cmd_request *apr_request = NULL;
+	struct voice_svc_cmd_response *apr_response = NULL;
+	struct apr_response_list *resp;
+	void __user *arg = (void __user *)u_arg;
+	uint32_t user_payload_size = 0;
+	unsigned long spin_flags;
+
+	pr_debug("%s: cmd: %u\n", __func__, cmd);
+
+	prtd = (struct voice_svc_prvt*)file->private_data;
+
+	switch (cmd) {
+	case SNDRV_VOICE_SVC_REGISTER_SVC:
+		pr_debug("%s: size of struct: %d\n", __func__,
+				sizeof(apr_reg_svc));
+		if (copy_from_user(&apr_reg_svc, arg, sizeof(apr_reg_svc))) {
+			pr_err("%s: copy_from_user failed\n", __func__);
+
+			ret = -EFAULT;
+			goto done;
+		}
+
+		ret = process_reg_cmd(apr_reg_svc, prtd);
+
+		break;
+	case SNDRV_VOICE_SVC_CMD_REQUEST:
+		if (!access_ok(VERIFY_READ, arg,
+				sizeof(struct voice_svc_cmd_request))) {
+			pr_err("%s: Unable to read user data", __func__);
+
+			ret = -EFAULT;
+			goto done;
+		}
+
+		user_payload_size =
+			((struct voice_svc_cmd_request*)arg)->payload_size;
+
+		apr_request = kmalloc(sizeof(struct voice_svc_cmd_request) +
+				      user_payload_size, GFP_KERNEL);
+
+		if (apr_request == NULL) {
+			pr_err("%s: apr_request kmalloc failed.", __func__);
+
+			ret = -ENOMEM;
+			goto done;
+		}
+
+		if (copy_from_user(apr_request, arg,
+				sizeof(struct voice_svc_cmd_request) +
+				user_payload_size)) {
+			pr_err("%s: copy from user failed, size %d\n", __func__,
+				sizeof(struct voice_svc_cmd_request) +
+				user_payload_size);
+
+			ret = -EFAULT;
+			goto done;
+		}
+
+		ret = voice_svc_send_req(apr_request, prtd);
+
+		break;
+
+	case SNDRV_VOICE_SVC_CMD_RESPONSE:
+		do {
+			if (!access_ok(VERIFY_READ, arg,
+				sizeof(struct voice_svc_cmd_response))) {
+				pr_err("%s: Unable to read user data",
+				       __func__);
+
+				ret = -EFAULT;
+				goto done;
+			}
+
+			user_payload_size =
+			    ((struct voice_svc_cmd_response*)arg)->payload_size;
+			pr_debug("%s: RESPONSE: user payload size %d",
+				 __func__, user_payload_size);
+
+			spin_lock_irqsave(&prtd->response_lock, spin_flags);
+			if (!list_empty(&prtd->response_queue)) {
+				resp = list_first_entry(&prtd->response_queue,
+						struct apr_response_list, list);
+
+				if (user_payload_size <
+					resp->resp.payload_size) {
+					pr_err("%s: Invalid payload size %d,%d",
+					       __func__, user_payload_size,
+					       resp->resp.payload_size);
+					ret = -ENOMEM;
+					spin_unlock_irqrestore(
+						&prtd->response_lock,
+						spin_flags);
+					goto done;
+				}
+
+				if (!access_ok(VERIFY_WRITE, arg,
+					sizeof(struct voice_svc_cmd_response) +
+					resp->resp.payload_size)) {
+					ret = -EFAULT;
+					spin_unlock_irqrestore(
+						&prtd->response_lock,
+						spin_flags);
+					goto done;
+				}
+
+				if (copy_to_user(arg, &resp->resp,
+					sizeof(struct voice_svc_cmd_response) +
+					resp->resp.payload_size)) {
+					pr_err("%s: copy to user failed, size \
+						%d\n", __func__,
+					sizeof(struct voice_svc_cmd_response) +
+						resp->resp.payload_size);
+
+					ret = -EFAULT;
+					spin_unlock_irqrestore(
+						&prtd->response_lock,
+						spin_flags);
+					goto done;
+				}
+
+				prtd->response_count--;
+
+				list_del(&resp->list);
+				kfree(resp);
+				spin_unlock_irqrestore(&prtd->response_lock,
+							spin_flags);
+				goto done;
+			} else {
+				spin_unlock_irqrestore(&prtd->response_lock,
+							spin_flags);
+				wait_event_interruptible(prtd->response_wait,
+					!list_empty(&prtd->response_queue));
+				pr_debug("%s: Interupt recieved for response",
+					 __func__);
+			}
+		} while(!apr_response);
+		break;
+	default:
+		pr_debug("%s: cmd: %u\n", __func__, cmd);
+		ret = -EINVAL;
+	}
+
+done:
+	if (apr_request != NULL)
+		kfree(apr_request);
+
+	return ret;
+}
+
+static int voice_svc_open(struct inode *inode, struct file *file)
+{
+	struct voice_svc_prvt *prtd = NULL;
+
+	prtd = kmalloc(sizeof(struct voice_svc_prvt), GFP_KERNEL);
+
+	if (prtd == NULL) {
+		pr_err("%s: kmalloc failed", __func__);
+
+		return -ENOMEM;
+	}
+
+	memset(prtd, 0, sizeof(struct voice_svc_prvt));
+	prtd->apr_q6_cvs = NULL;
+	prtd->apr_q6_mvm = NULL;
+	prtd->response_count = 0;
+
+	INIT_LIST_HEAD(&prtd->response_queue);
+	init_waitqueue_head(&prtd->response_wait);
+	spin_lock_init(&prtd->response_lock);
+
+	file->private_data = (void*)prtd;
+
+	return 0;
+}
+
+static int voice_svc_release(struct inode *inode, struct file *file)
+{
+	kfree(file->private_data);
+	return 0;
+}
+
+static const struct file_operations voice_svc_fops = {
+	.owner =                THIS_MODULE,
+	.open =                 voice_svc_open,
+	.unlocked_ioctl =       voice_svc_ioctl,
+	.release =              voice_svc_release,
+};
+
+
+static int voice_svc_probe(struct platform_device *pdev)
+{
+	int ret = 0;
+
+	voice_svc_dev = devm_kzalloc(&pdev->dev, sizeof(struct voice_svc_device),
+			GFP_KERNEL);
+	if (!voice_svc_dev) {
+		pr_err("%s: kzalloc failed\n", __func__);
+		ret = -ENOMEM;
+		goto done;
+	}
+
+	ret = alloc_chrdev_region(&device_num, 0, MINOR_NUMBER, DRIVER_NAME);
+	if (ret) {
+		pr_err("%s: Failed to alloc chrdev\n", __func__);
+		ret = -ENODEV;
+		goto done;
+	}
+
+	voice_svc_dev->major = MAJOR(device_num);
+	voice_svc_class = class_create(THIS_MODULE, DRIVER_NAME);
+	if (IS_ERR(voice_svc_class)) {
+		ret = PTR_ERR(voice_svc_class);
+		pr_err("%s: Failed to create class; err = %d\n", __func__,
+			ret);
+		goto class_err;
+	}
+
+	voice_svc_dev->dev = device_create(voice_svc_class, NULL, device_num,
+					   NULL, DRIVER_NAME);
+	if (IS_ERR(voice_svc_dev->dev)) {
+		ret = PTR_ERR(voice_svc_dev->dev);
+		pr_err("%s: Failed to create device; err = %d\n", __func__,
+			ret);
+		goto dev_err;
+	}
+
+	voice_svc_dev->cdev = cdev_alloc();
+	cdev_init(voice_svc_dev->cdev, &voice_svc_fops);
+	ret = cdev_add(voice_svc_dev->cdev, device_num, MINOR_NUMBER);
+	if (ret) {
+		pr_err("%s: Failed to register chrdev; err = %d\n", __func__,
+			ret);
+		goto add_err;
+	}
+	pr_debug("%s: Device created\n", __func__);
+	goto done;
+
+add_err:
+	cdev_del(voice_svc_dev->cdev);
+	device_destroy(voice_svc_class, device_num);
+dev_err:
+	class_destroy(voice_svc_class);
+class_err:
+	unregister_chrdev_region(0, MINOR_NUMBER);
+done:
+	return ret;
+}
+
+static int voice_svc_remove(struct platform_device *pdev)
+{
+	cdev_del(voice_svc_dev->cdev);
+	kfree(voice_svc_dev->cdev);
+	device_destroy(voice_svc_class, device_num);
+	class_destroy(voice_svc_class);
+	unregister_chrdev_region(0, MINOR_NUMBER);
+	kfree(voice_svc_dev);
+
+	return 0;
+}
+
+static struct of_device_id voice_svc_of_match[] = {
+	{.compatible = "qcom,msm-voice-svc"},
+	{ }
+};
+MODULE_DEVICE_TABLE(of, voice_svc_of_match);
+
+static struct platform_driver voice_svc_driver = {
+	.probe          = voice_svc_probe,
+	.remove         = voice_svc_remove,
+	.driver         = {
+		.name   = "msm-voice-svc",
+		.owner  = THIS_MODULE,
+		.of_match_table = voice_svc_of_match,
+	},
+};
+
+static int __init voice_svc_init(void)
+{
+	return platform_driver_register(&voice_svc_driver);
+}
+
+static void __exit voice_svc_exit(void)
+{
+	platform_driver_unregister(&voice_svc_driver);
+}
+
+module_init(voice_svc_init);
+module_exit(voice_svc_exit);
+
+MODULE_DESCRIPTION("Soc QDSP6v2 Audio APR driver");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/remote_spinlock.c b/arch/arm/mach-msm/remote_spinlock.c
index a9ebd7c..0a953ac 100644
--- a/arch/arm/mach-msm/remote_spinlock.c
+++ b/arch/arm/mach-msm/remote_spinlock.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2009, 2011-2013 The Linux Foundation. All rights reserved.
+/* Copyright (c) 2008-2009, 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
@@ -81,6 +81,8 @@
 	int (*trylock)(raw_remote_spinlock_t *lock);
 	int (*release)(raw_remote_spinlock_t *lock, uint32_t pid);
 	int (*owner)(raw_remote_spinlock_t *lock);
+	void (*lock_rlock_id)(raw_remote_spinlock_t *lock, uint32_t tid);
+	void (*unlock_rlock)(raw_remote_spinlock_t *lock);
 };
 
 static struct spinlock_ops current_ops;
@@ -364,6 +366,27 @@
 	writel_relaxed(0, lock);
 	smp_mb();
 }
+
+static void __raw_remote_sfpb_spin_lock_rlock_id(raw_remote_spinlock_t *lock,
+						 uint32_t tid)
+{
+	if (unlikely(!tid)) {
+		pr_err("%s: unsupported rlock tid=0\n", __func__);
+		BUG();
+	}
+
+	do {
+		writel_relaxed(tid, lock);
+		smp_mb();
+	} while (readl_relaxed(lock) != tid);
+}
+
+static void __raw_remote_sfpb_spin_unlock_rlock(raw_remote_spinlock_t *lock)
+{
+	writel_relaxed(0, lock);
+	smp_mb();
+}
+
 /* end sfpb implementation -------------------------------------------------- */
 
 /* common spinlock API ------------------------------------------------------ */
@@ -458,6 +481,9 @@
 		current_ops.trylock = __raw_remote_sfpb_spin_trylock;
 		current_ops.release = __raw_remote_gen_spin_release;
 		current_ops.owner = __raw_remote_gen_spin_owner;
+		current_ops.lock_rlock_id =
+				__raw_remote_sfpb_spin_lock_rlock_id;
+		current_ops.unlock_rlock = __raw_remote_sfpb_spin_unlock_rlock;
 		is_hw_lock_type = 1;
 		break;
 	case AUTO_MODE:
@@ -474,6 +500,10 @@
 			current_ops.trylock = __raw_remote_sfpb_spin_trylock;
 			current_ops.release = __raw_remote_gen_spin_release;
 			current_ops.owner = __raw_remote_gen_spin_owner;
+			current_ops.lock_rlock_id =
+					__raw_remote_sfpb_spin_lock_rlock_id;
+			current_ops.unlock_rlock =
+					__raw_remote_sfpb_spin_unlock_rlock;
 			is_hw_lock_type = 1;
 			break;
 		}
@@ -517,6 +547,11 @@
 	int n;
 	 _remote_spinlock_t lock;
 
+	if (pid >= REMOTE_SPINLOCK_NUM_PID) {
+		pr_err("%s: unsupported PID %d\n", __func__, pid);
+		return;
+	}
+
 	for (n = 0; n < count; ++n) {
 		if (remote_spinlock_init_address(n, &lock) == 0)
 			_remote_spin_release(&lock, pid);
@@ -671,6 +706,23 @@
 	return current_ops.owner((raw_remote_spinlock_t *)(*lock));
 }
 EXPORT_SYMBOL(_remote_spin_owner);
+
+void _remote_spin_lock_rlock_id(_remote_spinlock_t *lock, uint32_t tid)
+{
+	if (unlikely(!current_ops.lock_rlock_id))
+		BUG();
+	current_ops.lock_rlock_id((raw_remote_spinlock_t *)(*lock), tid);
+}
+EXPORT_SYMBOL(_remote_spin_lock_rlock_id);
+
+void _remote_spin_unlock_rlock(_remote_spinlock_t *lock)
+{
+	if (unlikely(!current_ops.unlock_rlock))
+		BUG();
+	current_ops.unlock_rlock((raw_remote_spinlock_t *)(*lock));
+}
+EXPORT_SYMBOL(_remote_spin_unlock_rlock);
+
 /* end common spinlock API -------------------------------------------------- */
 
 /* remote mutex implementation ---------------------------------------------- */
diff --git a/arch/arm/mach-msm/restart.c b/arch/arm/mach-msm/restart.c
index 37fd650..a96b02f 100644
--- a/arch/arm/mach-msm/restart.c
+++ b/arch/arm/mach-msm/restart.c
@@ -115,6 +115,10 @@
 		__raw_writel(EMERGENCY_DLOAD_MAGIC3,
 				emergency_dload_mode_addr +
 				(2 * sizeof(unsigned int)));
+
+		/* Need disable the pmic wdt, then the emergency dload mode
+		 * will not auto reset. */
+		qpnp_pon_wd_config(0);
 		mb();
 	}
 }
@@ -276,6 +280,8 @@
 			__raw_writel(0x77665500, restart_reason);
 		} else if (!strncmp(cmd, "recovery", 8)) {
 			__raw_writel(0x77665502, restart_reason);
+		} else if (!strcmp(cmd, "rtc")) {
+			__raw_writel(0x77665503, restart_reason);
 		} else if (!strncmp(cmd, "oem-", 4)) {
 			unsigned long code;
 			code = simple_strtoul(cmd + 4, NULL, 16) & 0xff;
diff --git a/arch/arm/mach-msm/rpcrouter_sdio_xprt.c b/arch/arm/mach-msm/rpcrouter_sdio_xprt.c
deleted file mode 100644
index e9818e5..0000000
--- a/arch/arm/mach-msm/rpcrouter_sdio_xprt.c
+++ /dev/null
@@ -1,655 +0,0 @@
-/* Copyright (c) 2010-2011, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
-
-/*
- * RPCROUTER SDIO XPRT module.
- */
-
-#include <linux/platform_device.h>
-#include <linux/types.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/device.h>
-#include <linux/delay.h>
-#include <linux/fs.h>
-#include <linux/err.h>
-#include <linux/sched.h>
-#include <linux/poll.h>
-#include <linux/wakelock.h>
-#include <asm/uaccess.h>
-#include <linux/slab.h>
-
-#include <mach/sdio_al.h>
-#include "smd_rpcrouter.h"
-
-enum {
-	MSM_SDIO_XPRT_DEBUG = 1U << 0,
-	MSM_SDIO_XPRT_INFO = 1U << 1,
-};
-
-static int msm_sdio_xprt_debug_mask;
-module_param_named(debug_mask, msm_sdio_xprt_debug_mask,
-		   int, S_IRUGO | S_IWUSR | S_IWGRP);
-
-#if defined(CONFIG_MSM_RPC_SDIO_DEBUG)
-#define SDIO_XPRT_DBG(x...) do {                \
-	if (msm_sdio_xprt_debug_mask & MSM_SDIO_XPRT_DEBUG)     \
-		printk(KERN_DEBUG x);           \
-	} while (0)
-
-#define SDIO_XPRT_INFO(x...) do {               \
-	if (msm_sdio_xprt_debug_mask & MSM_SDIO_XPRT_INFO)      \
-		printk(KERN_INFO x);            \
-	} while (0)
-#else
-#define SDIO_XPRT_DBG(x...) do { } while (0)
-#define SDIO_XPRT_INFO(x...) do { } while (0)
-#endif
-
-#define MAX_SDIO_WRITE_RETRY 5
-#define SDIO_BUF_SIZE (RPCROUTER_MSGSIZE_MAX + sizeof(struct rr_header) - 8)
-#define NUM_SDIO_BUFS 20
-#define MAX_TX_BUFS 10
-#define MAX_RX_BUFS 10
-
-struct sdio_xprt {
-	struct sdio_channel *handle;
-
-	struct list_head write_list;
-	spinlock_t write_list_lock;
-
-	struct list_head read_list;
-	spinlock_t read_list_lock;
-
-	struct list_head free_list;
-	spinlock_t free_list_lock;
-
-	struct wake_lock read_wakelock;
-};
-
-struct rpcrouter_sdio_xprt {
-	struct rpcrouter_xprt xprt;
-	struct sdio_xprt *channel;
-};
-
-static struct rpcrouter_sdio_xprt sdio_remote_xprt;
-
-static void sdio_xprt_read_data(struct work_struct *work);
-static DECLARE_DELAYED_WORK(work_read_data, sdio_xprt_read_data);
-static struct workqueue_struct *sdio_xprt_read_workqueue;
-
-struct sdio_buf_struct {
-	struct list_head list;
-	uint32_t size;
-	uint32_t read_index;
-	uint32_t write_index;
-	unsigned char data[SDIO_BUF_SIZE];
-};
-
-static void sdio_xprt_write_data(struct work_struct *work);
-static DECLARE_WORK(work_write_data, sdio_xprt_write_data);
-static wait_queue_head_t write_avail_wait_q;
-static uint32_t num_free_bufs;
-static uint32_t num_tx_bufs;
-static uint32_t num_rx_bufs;
-
-static DEFINE_MUTEX(modem_reset_lock);
-static uint32_t modem_reset;
-
-static void free_sdio_xprt(struct sdio_xprt *chnl)
-{
-	struct sdio_buf_struct *buf;
-	unsigned long flags;
-
-	if (!chnl) {
-		printk(KERN_ERR "Invalid chnl to free\n");
-		return;
-	}
-
-	spin_lock_irqsave(&chnl->free_list_lock, flags);
-	while (!list_empty(&chnl->free_list)) {
-		buf = list_first_entry(&chnl->free_list,
-					struct sdio_buf_struct, list);
-		list_del(&buf->list);
-		kfree(buf);
-	}
-	num_free_bufs = 0;
-	spin_unlock_irqrestore(&chnl->free_list_lock, flags);
-
-	spin_lock_irqsave(&chnl->write_list_lock, flags);
-	while (!list_empty(&chnl->write_list)) {
-		buf = list_first_entry(&chnl->write_list,
-					struct sdio_buf_struct, list);
-		list_del(&buf->list);
-		kfree(buf);
-	}
-	num_tx_bufs = 0;
-	spin_unlock_irqrestore(&chnl->write_list_lock, flags);
-
-	spin_lock_irqsave(&chnl->read_list_lock, flags);
-	while (!list_empty(&chnl->read_list)) {
-		buf = list_first_entry(&chnl->read_list,
-					struct sdio_buf_struct, list);
-		list_del(&buf->list);
-		kfree(buf);
-	}
-	num_rx_bufs = 0;
-	spin_unlock_irqrestore(&chnl->read_list_lock, flags);
-	wake_unlock(&chnl->read_wakelock);
-}
-
-static struct sdio_buf_struct *alloc_from_free_list(struct sdio_xprt *chnl)
-{
-	struct sdio_buf_struct *buf;
-	unsigned long flags;
-
-	spin_lock_irqsave(&chnl->free_list_lock, flags);
-	if (list_empty(&chnl->free_list)) {
-		spin_unlock_irqrestore(&chnl->free_list_lock, flags);
-		SDIO_XPRT_DBG("%s: Free list empty\n", __func__);
-		return NULL;
-	}
-	buf = list_first_entry(&chnl->free_list, struct sdio_buf_struct, list);
-	list_del(&buf->list);
-	num_free_bufs--;
-	spin_unlock_irqrestore(&chnl->free_list_lock, flags);
-
-	buf->size = 0;
-	buf->read_index = 0;
-	buf->write_index = 0;
-
-	return buf;
-}
-
-static void return_to_free_list(struct sdio_xprt *chnl,
-				struct sdio_buf_struct *buf)
-{
-	unsigned long flags;
-
-	if (!chnl || !buf) {
-		pr_err("%s: Invalid chnl or buf\n", __func__);
-		return;
-	}
-
-	buf->size = 0;
-	buf->read_index = 0;
-	buf->write_index = 0;
-
-	spin_lock_irqsave(&chnl->free_list_lock, flags);
-	list_add_tail(&buf->list, &chnl->free_list);
-	num_free_bufs++;
-	spin_unlock_irqrestore(&chnl->free_list_lock, flags);
-
-}
-
-static int rpcrouter_sdio_remote_read_avail(void)
-{
-	int read_avail = 0;
-	unsigned long flags;
-	struct sdio_buf_struct *buf;
-
-	spin_lock_irqsave(&sdio_remote_xprt.channel->read_list_lock, flags);
-	list_for_each_entry(buf, &sdio_remote_xprt.channel->read_list, list) {
-		read_avail += buf->size;
-	}
-	spin_unlock_irqrestore(&sdio_remote_xprt.channel->read_list_lock,
-				flags);
-	return read_avail;
-}
-
-static int rpcrouter_sdio_remote_read(void *data, uint32_t len)
-{
-	struct sdio_buf_struct *buf;
-	unsigned char *buf_data;
-	unsigned long flags;
-
-	SDIO_XPRT_DBG("sdio_xprt Called %s\n", __func__);
-	if (len < 0 || !data)
-		return -EINVAL;
-	else if (len == 0)
-		return 0;
-
-	spin_lock_irqsave(&sdio_remote_xprt.channel->read_list_lock, flags);
-	if (list_empty(&sdio_remote_xprt.channel->read_list)) {
-		spin_unlock_irqrestore(
-			&sdio_remote_xprt.channel->read_list_lock, flags);
-		return -EINVAL;
-	}
-
-	buf = list_first_entry(&sdio_remote_xprt.channel->read_list,
-				struct sdio_buf_struct, list);
-	if (buf->size < len) {
-		spin_unlock_irqrestore(
-			&sdio_remote_xprt.channel->read_list_lock, flags);
-		return -EINVAL;
-	}
-
-	buf_data = buf->data + buf->read_index;
-	memcpy(data, buf_data, len);
-	buf->read_index += len;
-	buf->size -= len;
-	if (buf->size == 0) {
-		list_del(&buf->list);
-		num_rx_bufs--;
-		return_to_free_list(sdio_remote_xprt.channel, buf);
-	}
-
-	if (list_empty(&sdio_remote_xprt.channel->read_list))
-		wake_unlock(&sdio_remote_xprt.channel->read_wakelock);
-	spin_unlock_irqrestore(&sdio_remote_xprt.channel->read_list_lock,
-				flags);
-	return len;
-}
-
-static int rpcrouter_sdio_remote_write_avail(void)
-{
-	uint32_t write_avail = 0;
-	unsigned long flags;
-
-	SDIO_XPRT_DBG("sdio_xprt Called %s\n", __func__);
-	spin_lock_irqsave(&sdio_remote_xprt.channel->write_list_lock, flags);
-	write_avail = (MAX_TX_BUFS - num_tx_bufs) * SDIO_BUF_SIZE;
-	spin_unlock_irqrestore(&sdio_remote_xprt.channel->write_list_lock,
-				flags);
-	return write_avail;
-}
-
-static int rpcrouter_sdio_remote_write(void *data, uint32_t len,
-					enum write_data_type type)
-{
-	unsigned long flags;
-	static struct sdio_buf_struct *buf;
-	unsigned char *buf_data;
-
-	switch (type) {
-	case HEADER:
-		spin_lock_irqsave(&sdio_remote_xprt.channel->write_list_lock,
-				  flags);
-		if (num_tx_bufs == MAX_TX_BUFS) {
-			spin_unlock_irqrestore(
-				&sdio_remote_xprt.channel->write_list_lock,
-				flags);
-			return -ENOMEM;
-		}
-		spin_unlock_irqrestore(
-			&sdio_remote_xprt.channel->write_list_lock, flags);
-
-		SDIO_XPRT_DBG("sdio_xprt WRITE HEADER %s\n", __func__);
-		buf = alloc_from_free_list(sdio_remote_xprt.channel);
-		if (!buf) {
-			pr_err("%s: alloc_from_free_list failed\n", __func__);
-			return -ENOMEM;
-		}
-		buf_data = buf->data + buf->write_index;
-		memcpy(buf_data, data, len);
-		buf->write_index += len;
-		buf->size += len;
-		return len;
-	case PACKMARK:
-		SDIO_XPRT_DBG("sdio_xprt WRITE PACKMARK %s\n",	__func__);
-		if (!buf) {
-			pr_err("%s: HEADER not written or alloc failed\n",
-				__func__);
-			return -ENOMEM;
-		}
-		buf_data = buf->data + buf->write_index;
-		memcpy(buf_data, data, len);
-		buf->write_index += len;
-		buf->size += len;
-		return len;
-	case PAYLOAD:
-		SDIO_XPRT_DBG("sdio_xprt WRITE PAYLOAD %s\n",	__func__);
-		if (!buf) {
-			pr_err("%s: HEADER not written or alloc failed\n",
-				__func__);
-			return -ENOMEM;
-		}
-		buf_data = buf->data + buf->write_index;
-		memcpy(buf_data, data, len);
-		buf->write_index += len;
-		buf->size += len;
-
-		SDIO_XPRT_DBG("sdio_xprt flush %d bytes\n", buf->size);
-		spin_lock_irqsave(&sdio_remote_xprt.channel->write_list_lock,
-				   flags);
-		list_add_tail(&buf->list,
-			      &sdio_remote_xprt.channel->write_list);
-		num_tx_bufs++;
-		spin_unlock_irqrestore(
-			&sdio_remote_xprt.channel->write_list_lock, flags);
-		queue_work(sdio_xprt_read_workqueue, &work_write_data);
-		buf = NULL;
-		return len;
-	default:
-		return -EINVAL;
-	}
-}
-
-static void sdio_xprt_write_data(struct work_struct *work)
-{
-	int rc = 0, sdio_write_retry = 0;
-	unsigned long flags;
-	struct sdio_buf_struct *buf;
-
-	mutex_lock(&modem_reset_lock);
-	if (modem_reset) {
-		mutex_unlock(&modem_reset_lock);
-		return;
-	}
-
-	spin_lock_irqsave(&sdio_remote_xprt.channel->write_list_lock, flags);
-	while (!list_empty(&sdio_remote_xprt.channel->write_list)) {
-		buf = list_first_entry(&sdio_remote_xprt.channel->write_list,
-					struct sdio_buf_struct, list);
-		list_del(&buf->list);
-		spin_unlock_irqrestore(
-			&sdio_remote_xprt.channel->write_list_lock, flags);
-		mutex_unlock(&modem_reset_lock);
-
-		wait_event(write_avail_wait_q,
-			   (!(modem_reset) && (sdio_write_avail(
-			   sdio_remote_xprt.channel->handle) >=
-			   buf->size)));
-
-		mutex_lock(&modem_reset_lock);
-		while (!(modem_reset) &&
-			((rc = sdio_write(sdio_remote_xprt.channel->handle,
-					buf->data, buf->size)) < 0) &&
-			(sdio_write_retry++ < MAX_SDIO_WRITE_RETRY)) {
-			printk(KERN_ERR "sdio_write failed with RC %d\n", rc);
-			mutex_unlock(&modem_reset_lock);
-			msleep(250);
-			mutex_lock(&modem_reset_lock);
-		}
-		if (modem_reset) {
-			mutex_unlock(&modem_reset_lock);
-			kfree(buf);
-			return;
-		} else {
-			return_to_free_list(sdio_remote_xprt.channel, buf);
-		}
-
-		if (!rc)
-			SDIO_XPRT_DBG("sdio_write %d bytes completed\n",
-					buf->size);
-
-		spin_lock_irqsave(&sdio_remote_xprt.channel->write_list_lock,
-				   flags);
-		num_tx_bufs--;
-	}
-	spin_unlock_irqrestore(&sdio_remote_xprt.channel->write_list_lock,
-				flags);
-	mutex_unlock(&modem_reset_lock);
-}
-
-static int rpcrouter_sdio_remote_close(void)
-{
-	SDIO_XPRT_DBG("sdio_xprt Called %s\n", __func__);
-	flush_workqueue(sdio_xprt_read_workqueue);
-	sdio_close(sdio_remote_xprt.channel->handle);
-	free_sdio_xprt(sdio_remote_xprt.channel);
-	return 0;
-}
-
-static void sdio_xprt_read_data(struct work_struct *work)
-{
-	int size = 0, read_avail;
-	unsigned long flags;
-	struct sdio_buf_struct *buf;
-	SDIO_XPRT_DBG("sdio_xprt Called %s\n", __func__);
-
-	mutex_lock(&modem_reset_lock);
-	while (!(modem_reset) &&
-		((read_avail =
-		sdio_read_avail(sdio_remote_xprt.channel->handle)) > 0)) {
-		spin_lock_irqsave(&sdio_remote_xprt.channel->read_list_lock,
-				  flags);
-		if (num_rx_bufs == MAX_RX_BUFS) {
-			spin_unlock_irqrestore(
-				&sdio_remote_xprt.channel->read_list_lock,
-				flags);
-			queue_delayed_work(sdio_xprt_read_workqueue,
-					   &work_read_data,
-					   msecs_to_jiffies(100));
-			break;
-		}
-		spin_unlock_irqrestore(
-			&sdio_remote_xprt.channel->read_list_lock, flags);
-
-		buf = alloc_from_free_list(sdio_remote_xprt.channel);
-		if (!buf) {
-			SDIO_XPRT_DBG("%s: Failed to alloc_from_free_list"
-				      " Try again later\n", __func__);
-			queue_delayed_work(sdio_xprt_read_workqueue,
-					   &work_read_data,
-					   msecs_to_jiffies(100));
-			break;
-		}
-
-		size = sdio_read(sdio_remote_xprt.channel->handle,
-				 buf->data, read_avail);
-		if (size < 0) {
-			printk(KERN_ERR "sdio_read failed,"
-					" read %d bytes, expected %d\n",
-					size, read_avail);
-			return_to_free_list(sdio_remote_xprt.channel, buf);
-			queue_delayed_work(sdio_xprt_read_workqueue,
-					   &work_read_data,
-					   msecs_to_jiffies(100));
-			break;
-		}
-
-		if (size == 0)
-			size = read_avail;
-
-		buf->size = size;
-		buf->write_index = size;
-		spin_lock_irqsave(&sdio_remote_xprt.channel->read_list_lock,
-				   flags);
-		list_add_tail(&buf->list,
-			      &sdio_remote_xprt.channel->read_list);
-		num_rx_bufs++;
-		spin_unlock_irqrestore(
-			&sdio_remote_xprt.channel->read_list_lock, flags);
-		wake_lock(&sdio_remote_xprt.channel->read_wakelock);
-	}
-
-	if (!modem_reset && !list_empty(&sdio_remote_xprt.channel->read_list))
-		msm_rpcrouter_xprt_notify(&sdio_remote_xprt.xprt,
-				  RPCROUTER_XPRT_EVENT_DATA);
-	mutex_unlock(&modem_reset_lock);
-}
-
-static void rpcrouter_sdio_remote_notify(void *_dev, unsigned event)
-{
-	if (event == SDIO_EVENT_DATA_READ_AVAIL) {
-		SDIO_XPRT_DBG("%s Received Notify"
-			      "SDIO_EVENT_DATA_READ_AVAIL\n", __func__);
-		queue_delayed_work(sdio_xprt_read_workqueue,
-				   &work_read_data, 0);
-	}
-	if (event == SDIO_EVENT_DATA_WRITE_AVAIL) {
-		SDIO_XPRT_DBG("%s Received Notify"
-			      "SDIO_EVENT_DATA_WRITE_AVAIL\n", __func__);
-		wake_up(&write_avail_wait_q);
-	}
-}
-
-static int allocate_sdio_xprt(struct sdio_xprt **sdio_xprt_chnl)
-{
-	struct sdio_buf_struct *buf;
-	struct sdio_xprt *chnl;
-	int i;
-	unsigned long flags;
-	int rc = -ENOMEM;
-
-	if (!(*sdio_xprt_chnl)) {
-		chnl = kmalloc(sizeof(struct sdio_xprt), GFP_KERNEL);
-		if (!chnl) {
-			printk(KERN_ERR "sdio_xprt channel"
-					" allocation failed\n");
-			return rc;
-		}
-
-		spin_lock_init(&chnl->write_list_lock);
-		spin_lock_init(&chnl->read_list_lock);
-		spin_lock_init(&chnl->free_list_lock);
-
-		INIT_LIST_HEAD(&chnl->write_list);
-		INIT_LIST_HEAD(&chnl->read_list);
-		INIT_LIST_HEAD(&chnl->free_list);
-		wake_lock_init(&chnl->read_wakelock,
-				WAKE_LOCK_SUSPEND, "rpc_sdio_xprt_read");
-	} else {
-		chnl = *sdio_xprt_chnl;
-	}
-
-	for (i = 0; i < NUM_SDIO_BUFS; i++) {
-		buf = kzalloc(sizeof(struct sdio_buf_struct), GFP_KERNEL);
-		if (!buf) {
-			printk(KERN_ERR "sdio_buf_struct alloc failed\n");
-			goto alloc_failure;
-		}
-		spin_lock_irqsave(&chnl->free_list_lock, flags);
-		list_add_tail(&buf->list, &chnl->free_list);
-		spin_unlock_irqrestore(&chnl->free_list_lock, flags);
-	}
-	num_free_bufs = NUM_SDIO_BUFS;
-
-	*sdio_xprt_chnl = chnl;
-	return 0;
-
-alloc_failure:
-	spin_lock_irqsave(&chnl->free_list_lock, flags);
-	while (!list_empty(&chnl->free_list)) {
-		buf = list_first_entry(&chnl->free_list,
-					struct sdio_buf_struct,
-					list);
-		list_del(&buf->list);
-		kfree(buf);
-	}
-	spin_unlock_irqrestore(&chnl->free_list_lock, flags);
-	wake_lock_destroy(&chnl->read_wakelock);
-
-	kfree(chnl);
-	*sdio_xprt_chnl = NULL;
-	return rc;
-}
-
-static int rpcrouter_sdio_remote_probe(struct platform_device *pdev)
-{
-	int rc;
-
-	SDIO_XPRT_INFO("%s Called\n", __func__);
-
-	mutex_lock(&modem_reset_lock);
-	if (!modem_reset) {
-		sdio_xprt_read_workqueue =
-			create_singlethread_workqueue("sdio_xprt");
-		if (!sdio_xprt_read_workqueue) {
-			mutex_unlock(&modem_reset_lock);
-			return -ENOMEM;
-		}
-
-		sdio_remote_xprt.xprt.name = "rpcrotuer_sdio_xprt";
-		sdio_remote_xprt.xprt.read_avail =
-			rpcrouter_sdio_remote_read_avail;
-		sdio_remote_xprt.xprt.read = rpcrouter_sdio_remote_read;
-		sdio_remote_xprt.xprt.write_avail =
-			rpcrouter_sdio_remote_write_avail;
-		sdio_remote_xprt.xprt.write = rpcrouter_sdio_remote_write;
-		sdio_remote_xprt.xprt.close = rpcrouter_sdio_remote_close;
-		sdio_remote_xprt.xprt.priv = NULL;
-
-		init_waitqueue_head(&write_avail_wait_q);
-	}
-	modem_reset = 0;
-
-	rc = allocate_sdio_xprt(&sdio_remote_xprt.channel);
-	if (rc) {
-		destroy_workqueue(sdio_xprt_read_workqueue);
-		mutex_unlock(&modem_reset_lock);
-		return rc;
-	}
-
-	/* Open up SDIO channel */
-	rc = sdio_open("SDIO_RPC", &sdio_remote_xprt.channel->handle, NULL,
-		      rpcrouter_sdio_remote_notify);
-
-	if (rc < 0) {
-		free_sdio_xprt(sdio_remote_xprt.channel);
-		destroy_workqueue(sdio_xprt_read_workqueue);
-		mutex_unlock(&modem_reset_lock);
-		return rc;
-	}
-	mutex_unlock(&modem_reset_lock);
-
-	msm_rpcrouter_xprt_notify(&sdio_remote_xprt.xprt,
-				  RPCROUTER_XPRT_EVENT_OPEN);
-
-	SDIO_XPRT_INFO("%s Completed\n", __func__);
-
-	return 0;
-}
-
-static int rpcrouter_sdio_remote_remove(struct platform_device *pdev)
-{
-	SDIO_XPRT_INFO("%s Called\n", __func__);
-
-	mutex_lock(&modem_reset_lock);
-	modem_reset = 1;
-	wake_up(&write_avail_wait_q);
-	free_sdio_xprt(sdio_remote_xprt.channel);
-	mutex_unlock(&modem_reset_lock);
-
-	msm_rpcrouter_xprt_notify(&sdio_remote_xprt.xprt,
-				  RPCROUTER_XPRT_EVENT_CLOSE);
-
-	SDIO_XPRT_INFO("%s Completed\n", __func__);
-
-	return 0;
-}
-
-/*Remove this platform driver after mainline of SDIO_AL update*/
-static struct platform_driver rpcrouter_sdio_remote_driver = {
-	.probe		= rpcrouter_sdio_remote_probe,
-	.driver		= {
-			.name	= "SDIO_AL",
-			.owner	= THIS_MODULE,
-	},
-};
-
-static struct platform_driver rpcrouter_sdio_driver = {
-	.probe		= rpcrouter_sdio_remote_probe,
-	.remove		= rpcrouter_sdio_remote_remove,
-	.driver		= {
-			.name	= "SDIO_RPC",
-			.owner	= THIS_MODULE,
-	},
-};
-
-static int __init rpcrouter_sdio_init(void)
-{
-	int rc;
-	msm_sdio_xprt_debug_mask = 0x2;
-	rc = platform_driver_register(&rpcrouter_sdio_remote_driver);
-	if (rc < 0)
-		return rc;
-	return platform_driver_register(&rpcrouter_sdio_driver);
-}
-
-module_init(rpcrouter_sdio_init);
-MODULE_DESCRIPTION("RPC Router SDIO XPRT");
-MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/rpm-regulator-smd.c b/arch/arm/mach-msm/rpm-regulator-smd.c
index 7995e9a..c7e9e75 100644
--- a/arch/arm/mach-msm/rpm-regulator-smd.c
+++ b/arch/arm/mach-msm/rpm-regulator-smd.c
@@ -163,6 +163,7 @@
 	struct mutex		mlock;
 	unsigned long		flags;
 	bool			sleep_request_sent;
+	bool			apps_only;
 	struct msm_rpm_request	*handle_active;
 	struct msm_rpm_request	*handle_sleep;
 };
@@ -241,6 +242,16 @@
 					& BIT(RPM_REGULATOR_PARAM_ENABLE)));
 }
 
+static inline bool rpm_vreg_shared_active_or_sleep_enabled_valid
+						(struct rpm_vreg *rpm_vreg)
+{
+	return !rpm_vreg->apps_only &&
+		((rpm_vreg->aggr_req_active.valid
+					& BIT(RPM_REGULATOR_PARAM_ENABLE))
+		 || (rpm_vreg->aggr_req_sleep.valid
+					& BIT(RPM_REGULATOR_PARAM_ENABLE)));
+}
+
 /*
  * This is used when voting for LPM or HPM by subtracting or adding to the
  * hpm_min_load of a regulator.  It has units of uA.
@@ -660,7 +671,8 @@
 	 * if the regulator has been configured to always send voltage updates.
 	 */
 	if (reg->always_send_voltage
-	    || rpm_vreg_active_or_sleep_enabled(reg->rpm_vreg))
+	    || rpm_vreg_active_or_sleep_enabled(reg->rpm_vreg)
+	    || rpm_vreg_shared_active_or_sleep_enabled_valid(reg->rpm_vreg))
 		rc = rpm_vreg_aggregate_requests(reg);
 
 	if (rc) {
@@ -719,7 +731,8 @@
 	 * updates.
 	 */
 	if (reg->always_send_voltage
-	    || rpm_vreg_active_or_sleep_enabled(reg->rpm_vreg))
+	    || rpm_vreg_active_or_sleep_enabled(reg->rpm_vreg)
+	    || rpm_vreg_shared_active_or_sleep_enabled_valid(reg->rpm_vreg))
 		rc = rpm_vreg_aggregate_requests(reg);
 
 	if (rc) {
@@ -774,7 +787,8 @@
 	 * voltage updates.
 	 */
 	if (reg->always_send_voltage
-	    || rpm_vreg_active_or_sleep_enabled(reg->rpm_vreg))
+	    || rpm_vreg_active_or_sleep_enabled(reg->rpm_vreg)
+	    || rpm_vreg_shared_active_or_sleep_enabled_valid(reg->rpm_vreg))
 		rc = rpm_vreg_aggregate_requests(reg);
 
 	if (rc) {
@@ -829,7 +843,8 @@
 	 * current updates.
 	 */
 	if (reg->always_send_current
-	    || rpm_vreg_active_or_sleep_enabled(reg->rpm_vreg))
+	    || rpm_vreg_active_or_sleep_enabled(reg->rpm_vreg)
+	    || rpm_vreg_shared_active_or_sleep_enabled_valid(reg->rpm_vreg))
 		rc = rpm_vreg_aggregate_requests(reg);
 
 	if (rc) {
@@ -1579,6 +1594,7 @@
 	of_property_read_u32(node, "qcom,enable-time", &rpm_vreg->enable_time);
 	of_property_read_u32(node, "qcom,hpm-min-load",
 		&rpm_vreg->hpm_min_load);
+	rpm_vreg->apps_only = of_property_read_bool(node, "qcom,apps-only");
 
 	rpm_vreg->handle_active = msm_rpm_create_request(RPM_SET_ACTIVE,
 		resource_type, rpm_vreg->resource_id, RPM_REGULATOR_PARAM_MAX);
diff --git a/arch/arm/mach-msm/rpm-smd.c b/arch/arm/mach-msm/rpm-smd.c
index 54576a9..2a01a36 100644
--- a/arch/arm/mach-msm/rpm-smd.c
+++ b/arch/arm/mach-msm/rpm-smd.c
@@ -130,8 +130,7 @@
 	bool valid;
 };
 static struct rb_root tr_root = RB_ROOT;
-
-static int msm_rpm_send_smd_buffer(char *buf, int size, bool noirq);
+static int msm_rpm_send_smd_buffer(char *buf, uint32_t size, bool noirq);
 static uint32_t msm_rpm_get_next_msg_id(void);
 
 static inline unsigned int get_rsc_type(char *buf)
@@ -187,7 +186,8 @@
 static void delete_kvp(char *msg, struct kvp *d)
 {
 	struct kvp *n;
-	int dec, size;
+	int dec;
+	uint32_t size;
 
 	n = get_next_kvp(d);
 	dec = (void *)n - (void *)d;
@@ -206,7 +206,7 @@
 
 static void add_kvp(char *buf, struct kvp *n)
 {
-	int inc = sizeof(*n) + n->s;
+	uint32_t inc = sizeof(*n) + n->s;
 	BUG_ON((get_req_len(buf) + inc) > MAX_SLEEP_BUFFER);
 
 	memcpy(buf + get_buf_len(buf), n, inc);
@@ -311,7 +311,7 @@
 	}
 }
 
-int msm_rpm_smd_buffer_request(char *buf, int size, gfp_t flag)
+int msm_rpm_smd_buffer_request(char *buf, uint32_t size, gfp_t flag)
 {
 	struct slp_buf *slp;
 	static DEFINE_SPINLOCK(slp_buffer_lock);
@@ -367,7 +367,7 @@
 	pos += scnprintf(buf + pos, buflen - pos, " id = 0%x",
 			get_rsc_id(s->buf));
 	for_each_kvp(s->buf, e) {
-		int i;
+		uint32_t i;
 		char *data = get_data(e);
 
 		memcpy(ch, &e->k, sizeof(u32));
@@ -482,14 +482,17 @@
 static int msm_rpm_add_kvp_data_common(struct msm_rpm_request *handle,
 		uint32_t key, const uint8_t *data, int size, bool noirq)
 {
-	int i;
-	int data_size, msg_size;
+	uint32_t i;
+	uint32_t data_size, msg_size;
 
 	if (!handle) {
 		pr_err("%s(): Invalid handle\n", __func__);
 		return -EINVAL;
 	}
 
+	if (size < 0)
+		return  -EINVAL;
+
 	data_size = ALIGN(size, SZ_4);
 	msg_size = data_size + sizeof(struct rpm_request_header);
 
@@ -813,7 +816,7 @@
 
 static int msm_rpm_read_smd_data(char *buf)
 {
-	int pkt_sz;
+	uint32_t pkt_sz;
 	int bytes_read = 0;
 
 	pkt_sz = smd_cur_packet_size(msm_rpm_data.ch_info);
@@ -867,7 +870,8 @@
 	size_t buflen = DEBUG_PRINT_BUFFER_SIZE;
 	char name[5];
 	u32 value;
-	int i, j, prev_valid;
+	uint32_t i;
+	int j, prev_valid;
 	int valid_count = 0;
 	int pos = 0;
 
@@ -992,7 +996,7 @@
 	pos += scnprintf(buf + pos, buflen - pos, "\n");
 	printk(buf);
 }
-static int msm_rpm_send_smd_buffer(char *buf, int size, bool noirq)
+static int msm_rpm_send_smd_buffer(char *buf, uint32_t size, bool noirq)
 {
 	unsigned long flags;
 	int ret;
@@ -1027,8 +1031,9 @@
 		int msg_type, bool noirq)
 {
 	uint8_t *tmpbuff;
-	int i, ret, msg_size;
-
+	int ret;
+	uint32_t i;
+	uint32_t msg_size;
 	int req_hdr_sz, msg_hdr_sz;
 
 	if (!cdata->msg_hdr.data_len)
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/sdio_al.c b/arch/arm/mach-msm/sdio_al.c
deleted file mode 100644
index bcfc556..0000000
--- a/arch/arm/mach-msm/sdio_al.c
+++ /dev/null
@@ -1,4365 +0,0 @@
-/* Copyright (c) 2010-2011, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
-
-/*
- * SDIO-Abstraction-Layer Module.
- *
- * To be used with Qualcomm's SDIO-Client connected to this host.
- */
-#include "sdio_al_private.h"
-
-#include <linux/module.h>
-#include <linux/scatterlist.h>
-#include <linux/workqueue.h>
-#include <linux/wait.h>
-#include <linux/delay.h>
-#include <linux/fs.h>
-#include <linux/slab.h>
-#include <linux/wakelock.h>
-#include <linux/mmc/core.h>
-#include <linux/mmc/card.h>
-#include <linux/mmc/host.h>
-#include <linux/mmc/mmc.h>
-#include <linux/mmc/sdio.h>
-#include <linux/mmc/sdio_func.h>
-#include <linux/mmc/sdio_ids.h>
-#include <linux/gpio.h>
-#include <linux/dma-mapping.h>
-#include <linux/earlysuspend.h>
-#include <linux/debugfs.h>
-#include <linux/uaccess.h>
-#include <linux/syscalls.h>
-#include <linux/time.h>
-#include <linux/spinlock.h>
-
-#include <mach/dma.h>
-#include <mach/gpio.h>
-#include <mach/subsystem_notif.h>
-
-#include "../../../drivers/mmc/host/msm_sdcc.h"
-
-/**
- *  Func#0 has SDIO standard registers
- *  Func#1 is for Mailbox.
- *  Functions 2..7 are for channels.
- *  Currently only functions 2..5 are active due to SDIO-Client
- *  number of pipes.
- *
- */
-#define SDIO_AL_MAX_CHANNELS 6
-
-/** Func 1..5 */
-#define SDIO_AL_MAX_FUNCS    (SDIO_AL_MAX_CHANNELS+1)
-#define SDIO_AL_WAKEUP_FUNC  6
-
-/** Number of SDIO-Client pipes */
-#define SDIO_AL_MAX_PIPES    16
-#define SDIO_AL_ACTIVE_PIPES 8
-
-/** CMD53/CMD54 Block size */
-#define SDIO_AL_BLOCK_SIZE   256
-
-/** Func#1 hardware Mailbox base address	 */
-#define HW_MAILBOX_ADDR			0x1000
-
-/** Func#1 peer sdioc software version.
- *  The header is duplicated also to the mailbox of the other
- *  functions. It can be used before other functions are enabled. */
-#define SDIOC_SW_HEADER_ADDR		0x0400
-
-/** Func#2..7 software Mailbox base address at 16K */
-#define SDIOC_SW_MAILBOX_ADDR			0x4000
-
-/** Some Mailbox registers address, written by host for
- control */
-#define PIPES_THRESHOLD_ADDR		0x01000
-
-#define PIPES_0_7_IRQ_MASK_ADDR 	0x01048
-
-#define PIPES_8_15_IRQ_MASK_ADDR	0x0104C
-
-#define FUNC_1_4_MASK_IRQ_ADDR		0x01040
-#define FUNC_5_7_MASK_IRQ_ADDR		0x01044
-#define FUNC_1_4_USER_IRQ_ADDR		0x01050
-#define FUNC_5_7_USER_IRQ_ADDR		0x01054
-
-#define EOT_PIPES_ENABLE		0x00
-
-/** Maximum read/write data available is SDIO-Client limitation */
-#define MAX_DATA_AVAILABLE   		(16*1024)
-#define INVALID_DATA_AVAILABLE  	(0x8000)
-
-/** SDIO-Client HW threshold to generate interrupt to the
- *  SDIO-Host on write available bytes.
- */
-#define DEFAULT_WRITE_THRESHOLD 	(1024)
-
-/** SDIO-Client HW threshold to generate interrupt to the
- *  SDIO-Host on read available bytes, for streaming (non
- *  packet) rx data.
- */
-#define DEFAULT_READ_THRESHOLD  	(1024)
-#define LOW_LATENCY_THRESHOLD		(1)
-
-/* Extra bytes to ensure getting the rx threshold interrupt on stream channels
-   when restoring the threshold after sleep */
-#define THRESHOLD_CHANGE_EXTRA_BYTES (100)
-
-/** SW threshold to trigger reading the mailbox. */
-#define DEFAULT_MIN_WRITE_THRESHOLD 	(1024)
-#define DEFAULT_MIN_WRITE_THRESHOLD_STREAMING	(1600)
-
-#define THRESHOLD_DISABLE_VAL  		(0xFFFFFFFF)
-
-/** Mailbox polling time for packet channels */
-#define DEFAULT_POLL_DELAY_MSEC		10
-/** Mailbox polling time for streaming channels */
-#define DEFAULT_POLL_DELAY_NOPACKET_MSEC 30
-
-/** The SDIO-Client prepares N buffers of size X per Tx pipe.
- *  Even when the transfer fills a partial buffer,
- *  that buffer becomes unusable for the next transfer. */
-#define DEFAULT_PEER_TX_BUF_SIZE	(128)
-
-#define ROUND_UP(x, n) (((x + n - 1) / n) * n)
-
-/** Func#2..7 FIFOs are r/w via
- sdio_readsb() & sdio_writesb(),when inc_addr=0 */
-#define PIPE_RX_FIFO_ADDR   0x00
-#define PIPE_TX_FIFO_ADDR   0x00
-
-/** Inactivity time to go to sleep in mseconds */
-#define INACTIVITY_TIME_MSEC 30
-#define INITIAL_INACTIVITY_TIME_MSEC 5000
-
-/** Context validity check */
-#define SDIO_AL_SIGNATURE 0xAABBCCDD
-
-/* Vendor Specific Command */
-#define SD_IO_RW_EXTENDED_QCOM 54
-
-#define TIME_TO_WAIT_US 500
-#define SDIO_CLOSE_FLUSH_TIMEOUT_MSEC   (10000)
-#define RX_FLUSH_BUFFER_SIZE (16*1024)
-
-#define SDIO_TEST_POSTFIX "_TEST"
-
-#define DATA_DEBUG(x, y...)						\
-	do {								\
-		if (sdio_al->debug.debug_data_on)			\
-			pr_info(y);					\
-		sdio_al_log(x, y);					\
-	} while (0)
-
-#define LPM_DEBUG(x, y...)						\
-	do {								\
-		if (sdio_al->debug.debug_lpm_on)			\
-			pr_info(y);					\
-		sdio_al_log(x, y);					\
-	} while (0)
-
-#define sdio_al_loge(x, y...)						\
-	do {								\
-		pr_err(y);						\
-		sdio_al_log(x, y);					\
-	} while (0)
-
-#define sdio_al_logi(x, y...)						\
-	do {								\
-		pr_info(y);						\
-		sdio_al_log(x, y);					\
-	} while (0)
-
-#define CLOSE_DEBUG(x, y...)						\
-	do {								\
-		if (sdio_al->debug.debug_close_on)			\
-			pr_info(y);					\
-		sdio_al_log(x, y);					\
-	} while (0)
-
-/* The index of the SDIO card used for the sdio_al_dloader */
-#define SDIO_BOOTLOADER_CARD_INDEX 1
-
-
-/* SDIO card state machine */
-enum sdio_al_device_state {
-	CARD_INSERTED,
-	CARD_REMOVED,
-	MODEM_RESTART
-};
-
-struct sdio_al_debug {
-	u8 debug_lpm_on;
-	u8 debug_data_on;
-	u8 debug_close_on;
-	struct dentry *sdio_al_debug_root;
-	struct dentry *sdio_al_debug_lpm_on;
-	struct dentry *sdio_al_debug_data_on;
-	struct dentry *sdio_al_debug_close_on;
-	struct dentry *sdio_al_debug_info;
-	struct dentry *sdio_al_debug_log_buffers[MAX_NUM_OF_SDIO_DEVICES + 1];
-};
-
-/* Polling time for the inactivity timer for devices that doesn't have
- * a streaming channel
- */
-#define SDIO_AL_POLL_TIME_NO_STREAMING 30
-
-#define CHAN_TO_FUNC(x) ((x) + 2 - 1)
-
-/**
- *  Mailbox structure.
- *  The Mailbox is located on the SDIO-Client Function#1.
- *  The mailbox size is 128 bytes, which is one block.
- *  The mailbox allows the host ton:
- *  1. Get the number of available bytes on the pipes.
- *  2. Enable/Disable SDIO-Client interrupt, related to pipes.
- *  3. Set the Threshold for generating interrupt.
- *
- */
-struct sdio_mailbox {
-	u32 pipe_bytes_threshold[SDIO_AL_MAX_PIPES]; /* Addr 0x1000 */
-
-	/* Mask USER interrupts generated towards host - Addr 0x1040 */
-	u32 mask_irq_func_1:8; /* LSB */
-	u32 mask_irq_func_2:8;
-	u32 mask_irq_func_3:8;
-	u32 mask_irq_func_4:8;
-
-	u32 mask_irq_func_5:8;
-	u32 mask_irq_func_6:8;
-	u32 mask_irq_func_7:8;
-	u32 mask_mutex_irq:8;
-
-	/* Mask PIPE interrupts generated towards host - Addr 0x1048 */
-	u32 mask_eot_pipe_0_7:8;
-	u32 mask_thresh_above_limit_pipe_0_7:8;
-	u32 mask_overflow_pipe_0_7:8;
-	u32 mask_underflow_pipe_0_7:8;
-
-	u32 mask_eot_pipe_8_15:8;
-	u32 mask_thresh_above_limit_pipe_8_15:8;
-	u32 mask_overflow_pipe_8_15:8;
-	u32 mask_underflow_pipe_8_15:8;
-
-	/* Status of User interrupts generated towards host - Addr 0x1050 */
-	u32 user_irq_func_1:8;
-	u32 user_irq_func_2:8;
-	u32 user_irq_func_3:8;
-	u32 user_irq_func_4:8;
-
-	u32 user_irq_func_5:8;
-	u32 user_irq_func_6:8;
-	u32 user_irq_func_7:8;
-	u32 user_mutex_irq:8;
-
-	/* Status of PIPE interrupts generated towards host */
-	/* Note: All sources are cleared once they read. - Addr 0x1058 */
-	u32 eot_pipe_0_7:8;
-	u32 thresh_above_limit_pipe_0_7:8;
-	u32 overflow_pipe_0_7:8;
-	u32 underflow_pipe_0_7:8;
-
-	u32 eot_pipe_8_15:8;
-	u32 thresh_above_limit_pipe_8_15:8;
-	u32 overflow_pipe_8_15:8;
-	u32 underflow_pipe_8_15:8;
-
-	u16 pipe_bytes_avail[SDIO_AL_MAX_PIPES];
-};
-
-/** Track pending Rx Packet size */
-struct rx_packet_size {
-	u32 size; /* in bytes */
-	struct list_head	list;
-};
-
-#define PEER_SDIOC_SW_MAILBOX_SIGNATURE 0xFACECAFE
-#define PEER_SDIOC_SW_MAILBOX_UT_SIGNATURE 0x5D107E57
-#define PEER_SDIOC_SW_MAILBOX_BOOT_SIGNATURE 0xDEADBEEF
-
-/* Allow support in old sdio version */
-#define PEER_SDIOC_OLD_VERSION_MAJOR	0x0002
-#define INVALID_SDIO_CHAN		0xFF
-
-/**
- * Peer SDIO-Client software header.
- */
-struct peer_sdioc_sw_header {
-	u32 signature;
-	u32 version;
-	u32 max_channels;
-	char channel_names[SDIO_AL_MAX_CHANNELS][PEER_CHANNEL_NAME_SIZE];
-	u32 reserved[23];
-};
-
-struct peer_sdioc_boot_sw_header {
-	u32 signature;
-	u32 version;
-	u32 boot_ch_num;
-	u32 reserved[29]; /* 32 - previous fields */
-};
-
-/**
- * Peer SDIO-Client software mailbox.
- */
-struct peer_sdioc_sw_mailbox {
-	struct peer_sdioc_sw_header sw_header;
-	struct peer_sdioc_channel_config ch_config[SDIO_AL_MAX_CHANNELS];
-};
-
-#define SDIO_AL_DEBUG_LOG_SIZE 3000
-struct sdio_al_local_log {
-	char buffer[SDIO_AL_DEBUG_LOG_SIZE];
-	unsigned int buf_cur_pos;
-	spinlock_t log_lock;
-};
-
-#define SDIO_AL_DEBUG_TMP_LOG_SIZE 250
-static int sdio_al_log(struct sdio_al_local_log *, const char *fmt, ...);
-
-/**
- *  SDIO Abstraction Layer driver context.
- *
- *  @pdata -
- *  @debug -
- *  @devices - an array of the the devices claimed by sdio_al
- *  @unittest_mode - a flag to indicate if sdio_al is in
- *		   unittest mode
- *  @bootloader_dev - the device which is used for the
- *                 bootloader
- *  @subsys_notif_handle - handle for modem restart
- *                 notifications
- *
- */
-struct sdio_al {
-	struct sdio_al_local_log gen_log;
-	struct sdio_al_local_log device_log[MAX_NUM_OF_SDIO_DEVICES];
-	struct sdio_al_platform_data *pdata;
-	struct sdio_al_debug debug;
-	struct sdio_al_device *devices[MAX_NUM_OF_SDIO_DEVICES];
-	int unittest_mode;
-	struct sdio_al_device *bootloader_dev;
-	void *subsys_notif_handle;
-	int sdioc_major;
-	int skip_print_info;
-};
-
-struct sdio_al_work {
-	struct work_struct work;
-	struct sdio_al_device *sdio_al_dev;
-};
-
-
-/**
- *  SDIO Abstraction Layer device context.
- *
- *  @card - card claimed.
- *
- *  @mailbox - A shadow of the SDIO-Client mailbox.
- *
- *  @channel - Channels context.
- *
- *  @workqueue - workqueue to read the mailbox and handle
- *     pending requests. Reading the mailbox should not happen
- *     in interrupt context.
- *
- *  @work - work to submit to workqueue.
- *
- *  @is_ready - driver is ready.
- *
- *  @ask_mbox - Flag to request reading the mailbox,
- *					  for different reasons.
- *
- *  @wake_lock - Lock when can't sleep.
- *
- *  @lpm_chan - Channel to use for LPM (low power mode)
- *            communication.
- *
- *  @is_ok_to_sleep - Mark if driver is OK with going to sleep
- * 			(no pending transactions).
- *
- *  @inactivity_time - time allowed to be in inactivity before
- * 		going to sleep
- *
- *  @timer - timer to use for polling the mailbox.
- *
- *  @poll_delay_msec - timer delay for polling the mailbox.
- *
- *  @is_err - error detected.
- *
- *  @signature - Context Validity Check.
- *
- *  @flashless_boot_on - flag to indicate if sdio_al is in
- *    flshless boot mode
- *
- */
-struct sdio_al_device {
-	struct sdio_al_local_log *dev_log;
-	struct mmc_card *card;
-	struct mmc_host *host;
-	struct sdio_mailbox *mailbox;
-	struct sdio_channel channel[SDIO_AL_MAX_CHANNELS];
-
-	struct peer_sdioc_sw_header *sdioc_sw_header;
-	struct peer_sdioc_boot_sw_header *sdioc_boot_sw_header;
-
-	struct workqueue_struct *workqueue;
-	struct sdio_al_work sdio_al_work;
-	struct sdio_al_work boot_work;
-
-	int is_ready;
-
-	wait_queue_head_t   wait_mbox;
-	int ask_mbox;
-	int bootloader_done;
-
-	struct wake_lock wake_lock;
-	int lpm_chan;
-	int is_ok_to_sleep;
-	unsigned long inactivity_time;
-
-	struct timer_list timer;
-	u32 poll_delay_msec;
-	int is_timer_initialized;
-
-	int is_err;
-
-	u32 signature;
-
-	unsigned int is_suspended;
-
-	int flashless_boot_on;
-	int ch_close_supported;
-	int state;
-	int (*lpm_callback)(void *, int);
-
-	int print_after_interrupt;
-
-	u8 *rx_flush_buf;
-};
-
-/*
- * Host operation:
- *   lower 16bits are operation code
- *   upper 16bits are operation state
- */
-#define PEER_OPERATION(op_code , op_state) ((op_code) | ((op_state) << 16))
-#define GET_PEER_OPERATION_CODE(op) ((op) & 0xffff)
-#define GET_PEER_OPERATION_STATE(op) ((op) >> 16)
-
-enum peer_op_code {
-	PEER_OP_CODE_CLOSE = 1
-};
-
-enum peer_op_state {
-	PEER_OP_STATE_INIT = 0,
-	PEER_OP_STATE_START = 1
-};
-
-
-/*
- * On the kernel command line specify
- * sdio_al.debug_lpm_on=1 to enable the LPM debug messages
- * By default the LPM debug messages are turned off
- */
-static int debug_lpm_on;
-module_param(debug_lpm_on, int, 0);
-
-/*
- * On the kernel command line specify
- * sdio_al.debug_data_on=1 to enable the DATA debug messages
- * By default the DATA debug messages are turned off
- */
-static int debug_data_on;
-module_param(debug_data_on, int, 0);
-
-/*
- * Enables / disables open close debug messages
- */
-static int debug_close_on = 1;
-module_param(debug_close_on, int, 0);
-
-/** The driver context */
-static struct sdio_al *sdio_al;
-
-/* Static functions declaration */
-static int enable_eot_interrupt(struct sdio_al_device *sdio_al_dev,
-				int pipe_index, int enable);
-static int enable_threshold_interrupt(struct sdio_al_device *sdio_al_dev,
-				      int pipe_index, int enable);
-static void sdio_func_irq(struct sdio_func *func);
-static void sdio_al_timer_handler(unsigned long data);
-static int get_min_poll_time_msec(struct sdio_al_device *sdio_al_dev);
-static u32 check_pending_rx_packet(struct sdio_channel *ch, u32 eot);
-static u32 remove_handled_rx_packet(struct sdio_channel *ch);
-static int set_pipe_threshold(struct sdio_al_device *sdio_al_dev,
-			      int pipe_index, int threshold);
-static int sdio_al_wake_up(struct sdio_al_device *sdio_al_dev,
-			   u32 not_from_int, struct sdio_channel *ch);
-static int sdio_al_client_setup(struct sdio_al_device *sdio_al_dev);
-static int enable_mask_irq(struct sdio_al_device *sdio_al_dev,
-			   int func_num, int enable, u8 bit_offset);
-static int sdio_al_enable_func_retry(struct sdio_func *func, const char *name);
-static void sdio_al_print_info(void);
-static int sdio_read_internal(struct sdio_channel *ch, void *data, int len);
-static int sdio_read_from_closed_ch(struct sdio_channel *ch, int len);
-static void stop_and_del_timer(struct sdio_al_device *sdio_al_dev);
-
-#define SDIO_AL_ERR(func)					\
-	do {							\
-		printk_once(KERN_ERR MODULE_NAME		\
-			":In Error state, ignore %s\n",		\
-			func);					\
-		sdio_al_print_info();				\
-	} while (0)
-
-#ifdef CONFIG_DEBUG_FS
-static int debug_info_open(struct inode *inode, struct file *file)
-{
-	file->private_data = inode->i_private;
-	return 0;
-}
-
-static ssize_t debug_info_write(struct file *file,
-		const char __user *buf, size_t count, loff_t *ppos)
-{
-	sdio_al_print_info();
-	return 1;
-}
-
-const struct file_operations debug_info_ops = {
-	.open = debug_info_open,
-	.write = debug_info_write,
-};
-
-struct debugfs_blob_wrapper sdio_al_dbgfs_log[MAX_NUM_OF_SDIO_DEVICES + 1];
-
-/*
-*
-* Trigger on/off for debug messages
-* for trigger off the data messages debug level use:
-* echo 0 > /sys/kernel/debugfs/sdio_al/debug_data_on
-* for trigger on the data messages debug level use:
-* echo 1 > /sys/kernel/debugfs/sdio_al/debug_data_on
-* for trigger off the lpm messages debug level use:
-* echo 0 > /sys/kernel/debugfs/sdio_al/debug_lpm_on
-* for trigger on the lpm messages debug level use:
-* echo 1 > /sys/kernel/debugfs/sdio_al/debug_lpm_on
-*/
-static int sdio_al_debugfs_init(void)
-{
-	int i, blob_errs = 0;
-
-	sdio_al->debug.sdio_al_debug_root = debugfs_create_dir("sdio_al", NULL);
-	if (!sdio_al->debug.sdio_al_debug_root)
-		return -ENOENT;
-
-	sdio_al->debug.sdio_al_debug_lpm_on = debugfs_create_u8("debug_lpm_on",
-					S_IRUGO | S_IWUGO,
-					sdio_al->debug.sdio_al_debug_root,
-					&sdio_al->debug.debug_lpm_on);
-
-	sdio_al->debug.sdio_al_debug_data_on = debugfs_create_u8(
-					"debug_data_on",
-					S_IRUGO | S_IWUGO,
-					sdio_al->debug.sdio_al_debug_root,
-					&sdio_al->debug.debug_data_on);
-
-	sdio_al->debug.sdio_al_debug_close_on = debugfs_create_u8(
-					"debug_close_on",
-					S_IRUGO | S_IWUGO,
-					sdio_al->debug.sdio_al_debug_root,
-					&sdio_al->debug.debug_close_on);
-
-	sdio_al->debug.sdio_al_debug_info = debugfs_create_file(
-					"sdio_debug_info",
-					S_IRUGO | S_IWUGO,
-					sdio_al->debug.sdio_al_debug_root,
-					NULL,
-					&debug_info_ops);
-
-	for (i = 0; i < MAX_NUM_OF_SDIO_DEVICES; ++i) {
-		char temp[18];
-
-		scnprintf(temp, 18, "sdio_al_log_dev_%d", i + 1);
-		sdio_al->debug.sdio_al_debug_log_buffers[i] =
-			debugfs_create_blob(temp,
-					S_IRUGO | S_IWUGO,
-					sdio_al->debug.sdio_al_debug_root,
-					&sdio_al_dbgfs_log[i]);
-	}
-
-	sdio_al->debug.sdio_al_debug_log_buffers[MAX_NUM_OF_SDIO_DEVICES] =
-			debugfs_create_blob("sdio_al_gen_log",
-				S_IRUGO | S_IWUGO,
-				sdio_al->debug.sdio_al_debug_root,
-				&sdio_al_dbgfs_log[MAX_NUM_OF_SDIO_DEVICES]);
-
-	for (i = 0; i < (MAX_NUM_OF_SDIO_DEVICES + 1); ++i) {
-		if (!sdio_al->debug.sdio_al_debug_log_buffers[i]) {
-			pr_err(MODULE_NAME ": Failed to create debugfs buffer"
-				   " entry for "
-				   "sdio_al->debug.sdio_al_debug_log_buffers[%d]",
-				   i);
-			blob_errs = 1;
-		}
-	}
-
-	if (blob_errs) {
-		for (i = 0; i < (MAX_NUM_OF_SDIO_DEVICES + 1); ++i)
-			if (sdio_al->debug.sdio_al_debug_log_buffers[i])
-				debugfs_remove(
-					sdio_al->
-					debug.sdio_al_debug_log_buffers[i]);
-	}
-
-
-	if ((!sdio_al->debug.sdio_al_debug_data_on) &&
-	    (!sdio_al->debug.sdio_al_debug_lpm_on) &&
-	    (!sdio_al->debug.sdio_al_debug_close_on) &&
-	    (!sdio_al->debug.sdio_al_debug_info) &&
-		blob_errs) {
-		debugfs_remove(sdio_al->debug.sdio_al_debug_root);
-		sdio_al->debug.sdio_al_debug_root = NULL;
-		return -ENOENT;
-	}
-
-	sdio_al_dbgfs_log[MAX_NUM_OF_SDIO_DEVICES].data =
-						sdio_al->gen_log.buffer;
-	sdio_al_dbgfs_log[MAX_NUM_OF_SDIO_DEVICES].size =
-						SDIO_AL_DEBUG_LOG_SIZE;
-
-	return 0;
-}
-
-static void sdio_al_debugfs_cleanup(void)
-{
-	int i;
-
-	debugfs_remove(sdio_al->debug.sdio_al_debug_lpm_on);
-	debugfs_remove(sdio_al->debug.sdio_al_debug_data_on);
-	debugfs_remove(sdio_al->debug.sdio_al_debug_close_on);
-	debugfs_remove(sdio_al->debug.sdio_al_debug_info);
-
-	for (i = 0; i < (MAX_NUM_OF_SDIO_DEVICES + 1); ++i)
-		debugfs_remove(sdio_al->debug.sdio_al_debug_log_buffers[i]);
-
-	debugfs_remove(sdio_al->debug.sdio_al_debug_root);
-}
-#endif
-
-static int sdio_al_log(struct sdio_al_local_log *log, const char *fmt, ...)
-{
-	va_list args;
-	int r;
-	char *tp, *log_buf;
-	unsigned int *log_cur_pos;
-	struct timeval kt;
-	unsigned long flags;
-	static char sdio_al_log_tmp[SDIO_AL_DEBUG_TMP_LOG_SIZE];
-
-	spin_lock_irqsave(&log->log_lock, flags);
-
-	kt = ktime_to_timeval(ktime_get());
-	r = scnprintf(sdio_al_log_tmp, SDIO_AL_DEBUG_TMP_LOG_SIZE,
-			"[%8ld.%6ld] ", kt.tv_sec, kt.tv_usec);
-
-	va_start(args, fmt);
-	r += vscnprintf(&sdio_al_log_tmp[r], (SDIO_AL_DEBUG_TMP_LOG_SIZE - r),
-			fmt, args);
-	va_end(args);
-
-	log_buf = log->buffer;
-	log_cur_pos = &(log->buf_cur_pos);
-
-	for (tp = sdio_al_log_tmp; tp < (sdio_al_log_tmp + r); tp++) {
-		log_buf[(*log_cur_pos)++] = *tp;
-		if ((*log_cur_pos) == SDIO_AL_DEBUG_LOG_SIZE)
-			*log_cur_pos = 0;
-	}
-
-	spin_unlock_irqrestore(&log->log_lock, flags);
-
-	return r;
-}
-
-static int sdio_al_verify_func1(struct sdio_al_device *sdio_al_dev,
-				char const *func)
-{
-	if (sdio_al_dev == NULL) {
-		sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s: NULL "
-				"sdio_al_dev\n", func);
-		return -ENODEV;
-	}
-
-	if (sdio_al_dev->signature != SDIO_AL_SIGNATURE) {
-		sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": %s: Invalid "
-				"signature\n", func);
-		return -ENODEV;
-	}
-
-	if (!sdio_al_dev->card) {
-		sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": %s: NULL "
-				"card\n", func);
-		return -ENODEV;
-	}
-	if (!sdio_al_dev->card->sdio_func[0]) {
-		sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": %s: NULL "
-				"func1\n", func);
-		return -ENODEV;
-	}
-	return 0;
-}
-
-static int sdio_al_claim_mutex(struct sdio_al_device *sdio_al_dev,
-			       char const *func)
-{
-	if (!sdio_al_dev) {
-		sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s: NULL "
-					"device\n", func);
-		return -ENODEV;
-	}
-
-	if (sdio_al_dev->signature != SDIO_AL_SIGNATURE) {
-		sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": %s: Invalid "
-					"device signature\n", func);
-		return -ENODEV;
-	}
-
-	if (!sdio_al_dev->host) {
-		sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": %s: NULL "
-					"host\n", func);
-		return -ENODEV;
-	}
-
-	mmc_claim_host(sdio_al_dev->host);
-
-	return 0;
-}
-
-static int sdio_al_release_mutex(struct sdio_al_device *sdio_al_dev,
-			       char const *func)
-{
-	if (!sdio_al_dev) {
-		sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s: NULL "
-					"device\n", func);
-		return -ENODEV;
-	}
-
-	if (sdio_al_dev->signature != SDIO_AL_SIGNATURE) {
-		sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": %s: Invalid "
-					"device signature\n", func);
-		return -ENODEV;
-	}
-
-	if (!sdio_al_dev->host) {
-		sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": %s: NULL "
-					"host\n", func);
-		return -ENODEV;
-	}
-
-	mmc_release_host(sdio_al_dev->host);
-
-	return 0;
-}
-
-static int sdio_al_claim_mutex_and_verify_dev(
-	struct sdio_al_device *sdio_al_dev,
-	char const *func)
-{
-	if (sdio_al_claim_mutex(sdio_al_dev, __func__))
-		return -ENODEV;
-
-	if (sdio_al_dev->state != CARD_INSERTED) {
-		sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": %s: Invalid "
-				"device state %d\n", func, sdio_al_dev->state);
-		sdio_al_release_mutex(sdio_al_dev, __func__);
-		return -ENODEV;
-	}
-
-	return 0;
-}
-
-static void sdio_al_get_into_err_state(struct sdio_al_device *sdio_al_dev)
-{
-	if ((!sdio_al) || (!sdio_al_dev))
-		return;
-
-	sdio_al_dev->is_err = true;
-	sdio_al->debug.debug_data_on = 0;
-	sdio_al->debug.debug_lpm_on = 0;
-	sdio_al_print_info();
-}
-
-void sdio_al_register_lpm_cb(void *device_handle,
-				       int(*lpm_callback)(void *, int))
-{
-	struct sdio_al_device *sdio_al_dev =
-		(struct sdio_al_device *) device_handle;
-
-	if (!sdio_al_dev) {
-		sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s - "
-				"device_handle is NULL\n", __func__);
-		return;
-	}
-
-	if (lpm_callback) {
-		sdio_al_dev->lpm_callback = lpm_callback;
-		lpm_callback((void *)sdio_al_dev,
-					   sdio_al_dev->is_ok_to_sleep);
-	}
-
-	LPM_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ": %s - device %d "
-			"registered for wakeup callback\n", __func__,
-			sdio_al_dev->host->index);
-}
-
-void sdio_al_unregister_lpm_cb(void *device_handle)
-{
-	struct sdio_al_device *sdio_al_dev =
-		(struct sdio_al_device *) device_handle;
-
-	if (!sdio_al_dev) {
-		sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s - "
-				"device_handle is NULL\n", __func__);
-		return;
-	}
-
-	sdio_al_dev->lpm_callback = NULL;
-	LPM_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ": %s - device %d "
-		"unregister for wakeup callback\n", __func__,
-		sdio_al_dev->host->index);
-}
-
-static void sdio_al_vote_for_sleep(struct sdio_al_device *sdio_al_dev,
-				   int is_vote_for_sleep)
-{
-	pr_debug(MODULE_NAME ": %s()", __func__);
-
-	if (!sdio_al_dev) {
-		sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s - sdio_al_dev"
-				" is NULL\n", __func__);
-		return;
-	}
-
-	if (is_vote_for_sleep) {
-		pr_debug(MODULE_NAME ": %s - sdio vote for Sleep", __func__);
-		wake_unlock(&sdio_al_dev->wake_lock);
-	} else {
-		pr_debug(MODULE_NAME ": %s - sdio vote against sleep",
-			  __func__);
-		wake_lock(&sdio_al_dev->wake_lock);
-	}
-
-	if (sdio_al_dev->lpm_callback != NULL) {
-		LPM_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ": %s - "
-				"is_vote_for_sleep=%d for card#%d, "
-				"calling callback...", __func__,
-				is_vote_for_sleep,
-				sdio_al_dev->host->index);
-		sdio_al_dev->lpm_callback((void *)sdio_al_dev,
-					   is_vote_for_sleep);
-	}
-}
-
-/**
- *  Write SDIO-Client lpm information
- *  Should only be called with host claimed.
- */
-static int write_lpm_info(struct sdio_al_device *sdio_al_dev)
-{
-	struct sdio_func *lpm_func = NULL;
-	int offset = offsetof(struct peer_sdioc_sw_mailbox, ch_config)+
-		sizeof(struct peer_sdioc_channel_config) *
-		sdio_al_dev->lpm_chan+
-		offsetof(struct peer_sdioc_channel_config, is_host_ok_to_sleep);
-	int ret;
-
-	if (sdio_al_dev->lpm_chan == INVALID_SDIO_CHAN) {
-		sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":Invalid "
-				"lpm_chan for card %d\n",
-				sdio_al_dev->host->index);
-		return -EINVAL;
-	}
-
-	if (!sdio_al_dev->card ||
-		!sdio_al_dev->card->sdio_func[sdio_al_dev->lpm_chan+1]) {
-		sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
-				": NULL card or lpm_func\n");
-		return -ENODEV;
-	}
-	lpm_func = sdio_al_dev->card->sdio_func[sdio_al_dev->lpm_chan+1];
-
-	pr_debug(MODULE_NAME ":write_lpm_info is_ok_to_sleep=%d, device %d\n",
-		 sdio_al_dev->is_ok_to_sleep,
-		 sdio_al_dev->host->index);
-
-	ret = sdio_memcpy_toio(lpm_func, SDIOC_SW_MAILBOX_ADDR+offset,
-				&sdio_al_dev->is_ok_to_sleep, sizeof(u32));
-	if (ret) {
-		sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":failed to "
-				"write lpm info for card %d\n",
-				sdio_al_dev->host->index);
-		return ret;
-	}
-
-	return 0;
-}
-
-/* Set inactivity counter to intial value to allow clients come up */
-static inline void start_inactive_time(struct sdio_al_device *sdio_al_dev)
-{
-	sdio_al_dev->inactivity_time = jiffies +
-		msecs_to_jiffies(INITIAL_INACTIVITY_TIME_MSEC);
-}
-
-static inline void restart_inactive_time(struct sdio_al_device *sdio_al_dev)
-{
-	sdio_al_dev->inactivity_time = jiffies +
-		msecs_to_jiffies(INACTIVITY_TIME_MSEC);
-}
-
-static inline int is_inactive_time_expired(struct sdio_al_device *sdio_al_dev)
-{
-	return time_after(jiffies, sdio_al_dev->inactivity_time);
-}
-
-
-static int is_user_irq_enabled(struct sdio_al_device *sdio_al_dev,
-			       int func_num)
-{
-	int ret = 0;
-	struct sdio_func *func1;
-	u32 user_irq = 0;
-	u32 addr = 0;
-	u32 offset = 0;
-	u32 masked_user_irq = 0;
-
-	if (sdio_al_verify_func1(sdio_al_dev, __func__))
-		return 0;
-	func1 = sdio_al_dev->card->sdio_func[0];
-
-	if (func_num < 4) {
-		addr = FUNC_1_4_USER_IRQ_ADDR;
-		offset = func_num * 8;
-	} else {
-		addr = FUNC_5_7_USER_IRQ_ADDR;
-		offset = (func_num - 4) * 8;
-	}
-
-	user_irq = sdio_readl(func1, addr, &ret);
-	if (ret) {
-		pr_debug(MODULE_NAME ":read_user_irq fail\n");
-		return 0;
-	}
-
-	masked_user_irq = (user_irq >> offset) && 0xFF;
-	if (masked_user_irq == 0x1) {
-		sdio_al_logi(sdio_al_dev->dev_log, MODULE_NAME ":user_irq "
-				"enabled\n");
-		return 1;
-	}
-
-	return 0;
-}
-
-static void sdio_al_sleep(struct sdio_al_device *sdio_al_dev,
-			  struct mmc_host *host)
-{
-	int i;
-
-	/* Go to sleep */
-	pr_debug(MODULE_NAME  ":Inactivity timer expired."
-		" Going to sleep\n");
-	/* Stop mailbox timer */
-	stop_and_del_timer(sdio_al_dev);
-	/* Make sure we get interrupt for non-packet-mode right away */
-	for (i = 0; i < SDIO_AL_MAX_CHANNELS; i++) {
-		struct sdio_channel *ch = &sdio_al_dev->channel[i];
-		if ((ch->state != SDIO_CHANNEL_STATE_OPEN) &&
-		    (ch->state != SDIO_CHANNEL_STATE_CLOSED)) {
-			pr_debug(MODULE_NAME  ":continue for channel %s in"
-					" state %d\n", ch->name, ch->state);
-			continue;
-		}
-		if (ch->is_packet_mode == false) {
-			ch->read_threshold = LOW_LATENCY_THRESHOLD;
-			set_pipe_threshold(sdio_al_dev,
-					   ch->rx_pipe_index,
-					   ch->read_threshold);
-		}
-	}
-	/* Prevent modem to go to sleep until we get the PROG_DONE on
-	   the dummy CMD52 */
-	msmsdcc_set_pwrsave(sdio_al_dev->host, 0);
-	/* Mark HOST_OK_TOSLEEP */
-	sdio_al_dev->is_ok_to_sleep = 1;
-	write_lpm_info(sdio_al_dev);
-
-	msmsdcc_lpm_enable(host);
-	LPM_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ":Finished sleep sequence"
-			" for card %d. Sleep now.\n",
-		sdio_al_dev->host->index);
-	/* Release wakelock */
-	sdio_al_vote_for_sleep(sdio_al_dev, 1);
-}
-
-
-/**
- *  Read SDIO-Client Mailbox from Function#1.thresh_pipe
- *
- *  The mailbox contain the bytes available per pipe,
- *  and the End-Of-Transfer indication per pipe (if available).
- *
- * WARNING: Each time the Mailbox is read from the client, the
- * read_bytes_avail is incremented with another pending
- * transfer. Therefore, a pending rx-packet should be added to a
- * list before the next read of the mailbox.
- *
- * This function should run from a workqueue context since it
- * notifies the clients.
- *
- * This function assumes that sdio_al_claim_mutex was called before
- * calling it.
- *
- */
-static int read_mailbox(struct sdio_al_device *sdio_al_dev, int from_isr)
-{
-	int ret;
-	struct sdio_func *func1 = NULL;
-	struct sdio_mailbox *mailbox = sdio_al_dev->mailbox;
-	struct mmc_host *host = sdio_al_dev->host;
-	u32 new_write_avail = 0;
-	u32 old_write_avail = 0;
-	u32 any_read_avail = 0;
-	u32 any_write_pending = 0;
-	int i;
-	u32 rx_notify_bitmask = 0;
-	u32 tx_notify_bitmask = 0;
-	u32 eot_pipe = 0;
-	u32 thresh_pipe = 0;
-	u32 overflow_pipe = 0;
-	u32 underflow_pipe = 0;
-	u32 thresh_intr_mask = 0;
-	int is_closing = 0;
-
-	if (sdio_al_dev->is_err) {
-		SDIO_AL_ERR(__func__);
-		return 0;
-	}
-
-	if (sdio_al_verify_func1(sdio_al_dev, __func__))
-		return -ENODEV;
-	func1 = sdio_al_dev->card->sdio_func[0];
-
-	pr_debug(MODULE_NAME ":start %s from_isr = %d for card %d.\n"
-		 , __func__, from_isr, sdio_al_dev->host->index);
-
-	pr_debug(MODULE_NAME ":before sdio_memcpy_fromio.\n");
-	memset(mailbox, 0, sizeof(struct sdio_mailbox));
-	ret = sdio_memcpy_fromio(func1, mailbox,
-			HW_MAILBOX_ADDR, sizeof(*mailbox));
-	pr_debug(MODULE_NAME ":after sdio_memcpy_fromio.\n");
-	if (ret) {
-		sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":Fail to read "
-				"Mailbox for card %d, goto error state\n",
-				sdio_al_dev->host->index);
-		sdio_al_get_into_err_state(sdio_al_dev);
-		goto exit_err;
-	}
-
-	eot_pipe =	(mailbox->eot_pipe_0_7) |
-			(mailbox->eot_pipe_8_15<<8);
-	thresh_pipe = 	(mailbox->thresh_above_limit_pipe_0_7) |
-			(mailbox->thresh_above_limit_pipe_8_15<<8);
-
-	overflow_pipe = (mailbox->overflow_pipe_0_7) |
-			(mailbox->overflow_pipe_8_15<<8);
-	underflow_pipe = mailbox->underflow_pipe_0_7 |
-			(mailbox->underflow_pipe_8_15<<8);
-	thresh_intr_mask =
-		(mailbox->mask_thresh_above_limit_pipe_0_7) |
-		(mailbox->mask_thresh_above_limit_pipe_8_15<<8);
-
-	if (overflow_pipe || underflow_pipe)
-		sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":Mailbox ERROR "
-				"overflow=0x%x, underflow=0x%x\n",
-				overflow_pipe, underflow_pipe);
-
-	/* In case of modem reset we would like to read the daya from the modem
-	   to clear the interrupts but do not process it */
-	if (sdio_al_dev->state != CARD_INSERTED) {
-		sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":sdio_al_device"
-				" (card %d) is in invalid state %d\n",
-				sdio_al_dev->host->index,
-				sdio_al_dev->state);
-		return -ENODEV;
-	}
-
-	pr_debug(MODULE_NAME ":card %d: eot=0x%x, thresh=0x%x\n",
-			sdio_al_dev->host->index,
-			eot_pipe, thresh_pipe);
-
-	/* Scan for Rx Packets available and update read available bytes */
-	for (i = 0; i < SDIO_AL_MAX_CHANNELS; i++) {
-		struct sdio_channel *ch = &sdio_al_dev->channel[i];
-		u32 old_read_avail;
-		u32 read_avail;
-		u32 new_packet_size = 0;
-
-		if (ch->state == SDIO_CHANNEL_STATE_CLOSING)
-			is_closing = true; /* used to prevent sleep */
-
-		old_read_avail = ch->read_avail;
-		read_avail = mailbox->pipe_bytes_avail[ch->rx_pipe_index];
-
-		if ((ch->state == SDIO_CHANNEL_STATE_CLOSED) &&
-			(read_avail > 0)) {
-			sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
-				 ":%s: Invalid read_avail 0x%x, for CLOSED ch %s\n",
-				 __func__, read_avail, ch->name);
-			sdio_read_from_closed_ch(ch, read_avail);
-		}
-		if ((ch->state != SDIO_CHANNEL_STATE_OPEN) &&
-		    (ch->state != SDIO_CHANNEL_STATE_CLOSING))
-			continue;
-
-		if (read_avail > INVALID_DATA_AVAILABLE) {
-			sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
-				 ":Invalid read_avail 0x%x for pipe %d\n",
-				 read_avail, ch->rx_pipe_index);
-			continue;
-		}
-		any_read_avail |= read_avail | old_read_avail;
-		ch->statistics.last_any_read_avail = any_read_avail;
-		ch->statistics.last_read_avail = read_avail;
-		ch->statistics.last_old_read_avail = old_read_avail;
-
-		if (ch->is_packet_mode) {
-			if ((eot_pipe & (1<<ch->rx_pipe_index)) &&
-			    sdio_al_dev->print_after_interrupt) {
-				LPM_DEBUG(sdio_al_dev->dev_log, MODULE_NAME
-					":Interrupt on ch %s, "
-					"card %d", ch->name,
-					sdio_al_dev->host->index);
-			}
-			new_packet_size = check_pending_rx_packet(ch, eot_pipe);
-		} else {
-			if ((thresh_pipe & (1<<ch->rx_pipe_index)) &&
-			    sdio_al_dev->print_after_interrupt) {
-				LPM_DEBUG(sdio_al_dev->dev_log, MODULE_NAME
-					":Interrupt on ch %s, "
-					"card %d", ch->name,
-					sdio_al_dev->host->index);
-			}
-			ch->read_avail = read_avail;
-
-			/*
-			 * Restore default thresh for non packet channels.
-			 * in case it IS low latency channel then read_threshold
-			 * and def_read_threshold are both
-			 * LOW_LATENCY_THRESHOLD
-			 */
-			if ((ch->read_threshold != ch->def_read_threshold) &&
-			    (read_avail >= ch->threshold_change_cnt)) {
-				if (!ch->is_low_latency_ch) {
-					ch->read_threshold =
-						ch->def_read_threshold;
-					set_pipe_threshold(sdio_al_dev,
-							   ch->rx_pipe_index,
-							   ch->read_threshold);
-				}
-			}
-		}
-
-		if ((ch->is_packet_mode) && (new_packet_size > 0)) {
-			rx_notify_bitmask |= (1<<ch->num);
-			ch->statistics.total_notifs++;
-		}
-
-		if ((!ch->is_packet_mode) && (ch->read_avail > 0) &&
-		    (old_read_avail == 0)) {
-			rx_notify_bitmask |= (1<<ch->num);
-			ch->statistics.total_notifs++;
-		}
-	}
-	sdio_al_dev->print_after_interrupt = 0;
-
-	/* Update Write available */
-	for (i = 0; i < SDIO_AL_MAX_CHANNELS; i++) {
-		struct sdio_channel *ch = &sdio_al_dev->channel[i];
-
-		if ((ch->state != SDIO_CHANNEL_STATE_OPEN) &&
-		    (ch->state != SDIO_CHANNEL_STATE_CLOSING))
-			continue;
-
-		new_write_avail = mailbox->pipe_bytes_avail[ch->tx_pipe_index];
-
-		if (new_write_avail > INVALID_DATA_AVAILABLE) {
-			sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
-				 ":Invalid write_avail 0x%x for pipe %d\n",
-				 new_write_avail, ch->tx_pipe_index);
-			continue;
-		}
-
-		old_write_avail = ch->write_avail;
-		ch->write_avail = new_write_avail;
-
-		if ((old_write_avail <= ch->min_write_avail) &&
-			(new_write_avail >= ch->min_write_avail))
-			tx_notify_bitmask |= (1<<ch->num);
-
-		/* There is not enough write avail for this channel.
-		   We need to keep reading mailbox to wait for the appropriate
-		   write avail and cannot sleep. Ignore SMEM channel that has
-		   only one direction. */
-		if (strncmp(ch->name, "SDIO_SMEM", CHANNEL_NAME_SIZE))
-			any_write_pending |=
-			(new_write_avail < ch->ch_config.max_tx_threshold);
-	}
-	/* notify clients */
-	for (i = 0; i < SDIO_AL_MAX_CHANNELS; i++) {
-		struct sdio_channel *ch = &sdio_al_dev->channel[i];
-
-		if ((ch->state != SDIO_CHANNEL_STATE_OPEN) ||
-				(ch->notify == NULL))
-			continue;
-
-		if (rx_notify_bitmask & (1<<ch->num))
-			ch->notify(ch->priv,
-					   SDIO_EVENT_DATA_READ_AVAIL);
-
-		if (tx_notify_bitmask & (1<<ch->num))
-			ch->notify(ch->priv,
-					   SDIO_EVENT_DATA_WRITE_AVAIL);
-	}
-
-
-	if ((rx_notify_bitmask == 0) && (tx_notify_bitmask == 0) &&
-	    !any_read_avail && !any_write_pending) {
-		DATA_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ":Nothing to "
-				"Notify for card %d, is_closing=%d\n",
-				sdio_al_dev->host->index, is_closing);
-		if (is_closing)
-			restart_inactive_time(sdio_al_dev);
-		else if (is_inactive_time_expired(sdio_al_dev))
-			sdio_al_sleep(sdio_al_dev, host);
-	} else {
-		DATA_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ":Notify bitmask"
-				" for card %d rx=0x%x, tx=0x%x.\n",
-				sdio_al_dev->host->index,
-				rx_notify_bitmask, tx_notify_bitmask);
-		/* Restart inactivity timer if any activity on the channel */
-		restart_inactive_time(sdio_al_dev);
-	}
-
-	pr_debug(MODULE_NAME ":end %s.\n", __func__);
-
-exit_err:
-	return ret;
-}
-
-/**
- *  Check pending rx packet when reading the mailbox.
- */
-static u32 check_pending_rx_packet(struct sdio_channel *ch, u32 eot)
-{
-	u32 rx_pending;
-	u32 rx_avail;
-	u32 new_packet_size = 0;
-	struct sdio_al_device *sdio_al_dev = ch->sdio_al_dev;
-
-
-	if (sdio_al_dev == NULL) {
-		sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": NULL sdio_al_dev"
-				" for channel %s\n", ch->name);
-		return -EINVAL;
-	}
-
-	mutex_lock(&ch->ch_lock);
-
-	rx_pending = ch->rx_pending_bytes;
-	rx_avail = sdio_al_dev->mailbox->pipe_bytes_avail[ch->rx_pipe_index];
-
-	pr_debug(MODULE_NAME ":pipe %d of card %d rx_avail=0x%x, "
-			     "rx_pending=0x%x\n",
-	   ch->rx_pipe_index, sdio_al_dev->host->index, rx_avail,
-		 rx_pending);
-
-
-	/* new packet detected */
-	if (eot & (1<<ch->rx_pipe_index)) {
-		struct rx_packet_size *p = NULL;
-		new_packet_size = rx_avail - rx_pending;
-
-		if ((rx_avail <= rx_pending)) {
-			sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
-					": Invalid new packet size."
-					" rx_avail=%d.\n", rx_avail);
-			new_packet_size = 0;
-			goto exit_err;
-		}
-
-		p = kzalloc(sizeof(*p), GFP_KERNEL);
-		if (p == NULL) {
-			sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
-					": failed to allocate item for "
-					"rx_pending list. rx_avail=%d, "
-					"rx_pending=%d.\n",
-					rx_avail, rx_pending);
-			new_packet_size = 0;
-			goto exit_err;
-		}
-		p->size = new_packet_size;
-		/* Add new packet as last */
-		list_add_tail(&p->list, &ch->rx_size_list_head);
-		ch->rx_pending_bytes += new_packet_size;
-
-		if (ch->read_avail == 0)
-			ch->read_avail = new_packet_size;
-	}
-
-exit_err:
-	mutex_unlock(&ch->ch_lock);
-
-	return new_packet_size;
-}
-
-
-
-/**
- *  Remove first pending packet from the list.
- */
-static u32 remove_handled_rx_packet(struct sdio_channel *ch)
-{
-	struct rx_packet_size *p = NULL;
-
-	mutex_lock(&ch->ch_lock);
-
-	ch->rx_pending_bytes -= ch->read_avail;
-
-	if (!list_empty(&ch->rx_size_list_head)) {
-		p = list_first_entry(&ch->rx_size_list_head,
-			struct rx_packet_size, list);
-		list_del(&p->list);
-		kfree(p);
-	} else {
-		sdio_al_loge(ch->sdio_al_dev->dev_log, MODULE_NAME ":%s: ch "
-				"%s: unexpected empty list!!\n",
-				__func__, ch->name);
-	}
-
-	if (list_empty(&ch->rx_size_list_head))	{
-		ch->read_avail = 0;
-	} else {
-		p = list_first_entry(&ch->rx_size_list_head,
-			struct rx_packet_size, list);
-		ch->read_avail = p->size;
-	}
-
-	mutex_unlock(&ch->ch_lock);
-
-	return ch->read_avail;
-}
-
-
-/**
- *  Bootloader worker function.
- *
- *  @note: clear the bootloader_done flag only after reading the
- *  mailbox, to ignore more requests while reading the mailbox.
- */
-static void boot_worker(struct work_struct *work)
-{
-	int ret = 0;
-	int func_num = 0;
-	int i;
-	struct sdio_al_device *sdio_al_dev = NULL;
-	struct sdio_al_work *sdio_al_work = container_of(work,
-							 struct sdio_al_work,
-							 work);
-
-	if (sdio_al_work == NULL) {
-		sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s: NULL "
-				"sdio_al_work\n", __func__);
-		return;
-	}
-
-	sdio_al_dev = sdio_al_work->sdio_al_dev;
-	if (sdio_al_dev == NULL) {
-		sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s: NULL "
-				"sdio_al_dev\n", __func__);
-		return;
-	}
-	sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ":Bootloader Worker Started"
-			", wait for bootloader_done event..\n");
-	wait_event(sdio_al_dev->wait_mbox,
-		   sdio_al_dev->bootloader_done);
-	sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ":Got bootloader_done "
-			"event..\n");
-	/* Do polling until MDM is up */
-	for (i = 0; i < 5000; ++i) {
-		if (sdio_al_claim_mutex_and_verify_dev(sdio_al_dev, __func__))
-			return;
-		if (is_user_irq_enabled(sdio_al_dev, func_num)) {
-			sdio_al_release_mutex(sdio_al_dev, __func__);
-			sdio_al_dev->bootloader_done = 0;
-			ret = sdio_al_client_setup(sdio_al_dev);
-			if (ret) {
-				sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
-					": sdio_al_client_setup failed, "
-					"for card %d ret=%d\n",
-					sdio_al_dev->host->index, ret);
-				sdio_al_get_into_err_state(sdio_al_dev);
-			}
-			goto done;
-		}
-		sdio_al_release_mutex(sdio_al_dev, __func__);
-		msleep(100);
-	}
-	sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":Timeout waiting for "
-			"user_irq for card %d\n",
-			sdio_al_dev->host->index);
-	sdio_al_get_into_err_state(sdio_al_dev);
-
-done:
-	pr_debug(MODULE_NAME ":Boot Worker for card %d Exit!\n",
-		sdio_al_dev->host->index);
-}
-
-/**
- *  Worker function.
- *
- *  @note: clear the ask_mbox flag only after
- *  	 reading the mailbox, to ignore more requests while
- *  	 reading the mailbox.
- */
-static void worker(struct work_struct *work)
-{
-	int ret = 0;
-	struct sdio_al_device *sdio_al_dev = NULL;
-	struct sdio_al_work *sdio_al_work = container_of(work,
-							 struct sdio_al_work,
-							 work);
-	if (sdio_al_work == NULL) {
-		sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": worker: NULL "
-				"sdio_al_work\n");
-		return;
-	}
-
-	sdio_al_dev = sdio_al_work->sdio_al_dev;
-	if (sdio_al_dev == NULL) {
-		sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": worker: NULL "
-				"sdio_al_dev\n");
-		return;
-	}
-	pr_debug(MODULE_NAME ":Worker Started..\n");
-	while ((sdio_al_dev->is_ready) && (ret == 0)) {
-		pr_debug(MODULE_NAME ":Wait for read mailbox request..\n");
-		wait_event(sdio_al_dev->wait_mbox, sdio_al_dev->ask_mbox);
-		if (!sdio_al_dev->is_ready)
-			break;
-		if (sdio_al_claim_mutex_and_verify_dev(sdio_al_dev, __func__))
-			break;
-		if (sdio_al_dev->is_ok_to_sleep) {
-			ret = sdio_al_wake_up(sdio_al_dev, 1, NULL);
-			if (ret) {
-				sdio_al_release_mutex(sdio_al_dev, __func__);
-				return;
-			}
-		}
-		ret = read_mailbox(sdio_al_dev, false);
-		sdio_al_release_mutex(sdio_al_dev, __func__);
-		sdio_al_dev->ask_mbox = false;
-	}
-
-	pr_debug(MODULE_NAME ":Worker Exit!\n");
-}
-
-/**
- *  Write command using CMD54 rather than CMD53.
- *  Writing with CMD54 generate EOT interrupt at the
- *  SDIO-Client.
- *  Based on mmc_io_rw_extended()
- */
-static int sdio_write_cmd54(struct mmc_card *card, unsigned fn,
-	unsigned addr, const u8 *buf,
-	unsigned blocks, unsigned blksz)
-{
-	struct mmc_request mrq;
-	struct mmc_command cmd;
-	struct mmc_data data;
-	struct scatterlist sg;
-	int incr_addr = 1; /* MUST */
-	int write = 1;
-
-	BUG_ON(!card);
-	BUG_ON(fn > 7);
-	BUG_ON(blocks == 1 && blksz > 512);
-	WARN_ON(blocks == 0);
-	WARN_ON(blksz == 0);
-
-	write = true;
-	pr_debug(MODULE_NAME ":sdio_write_cmd54()"
-		"fn=%d,buf=0x%x,blocks=%d,blksz=%d\n",
-		fn, (u32) buf, blocks, blksz);
-
-	memset(&mrq, 0, sizeof(struct mmc_request));
-	memset(&cmd, 0, sizeof(struct mmc_command));
-	memset(&data, 0, sizeof(struct mmc_data));
-
-	mrq.cmd = &cmd;
-	mrq.data = &data;
-
-	cmd.opcode = SD_IO_RW_EXTENDED_QCOM;
-
-	cmd.arg = write ? 0x80000000 : 0x00000000;
-	cmd.arg |= fn << 28;
-	cmd.arg |= incr_addr ? 0x04000000 : 0x00000000;
-	cmd.arg |= addr << 9;
-	if (blocks == 1 && blksz <= 512)
-		cmd.arg |= (blksz == 512) ? 0 : blksz;  /* byte mode */
-	else
-		cmd.arg |= 0x08000000 | blocks; 	/* block mode */
-	cmd.flags = MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_ADTC;
-
-	data.blksz = blksz;
-	data.blocks = blocks;
-	data.flags = write ? MMC_DATA_WRITE : MMC_DATA_READ;
-	data.sg = &sg;
-	data.sg_len = 1;
-
-	sg_init_one(&sg, buf, blksz * blocks);
-
-	mmc_set_data_timeout(&data, card);
-
-	mmc_wait_for_req(card->host, &mrq);
-
-	if (cmd.error)
-		return cmd.error;
-	if (data.error)
-		return data.error;
-
-	if (mmc_host_is_spi(card->host)) {
-		/* host driver already reported errors */
-	} else {
-		if (cmd.resp[0] & R5_ERROR) {
-			sdio_al_loge(&sdio_al->gen_log, MODULE_NAME
-						":%s: R5_ERROR for card %d",
-						__func__, card->host->index);
-			return -EIO;
-		}
-		if (cmd.resp[0] & R5_FUNCTION_NUMBER) {
-			sdio_al_loge(&sdio_al->gen_log, MODULE_NAME
-						":%s: R5_FUNCTION_NUMBER for card %d",
-						__func__, card->host->index);
-			return -EINVAL;
-		}
-		if (cmd.resp[0] & R5_OUT_OF_RANGE) {
-			sdio_al_loge(&sdio_al->gen_log, MODULE_NAME
-						":%s: R5_OUT_OF_RANGE for card %d",
-						__func__, card->host->index);
-			return -ERANGE;
-		}
-	}
-
-	return 0;
-}
-
-
-/**
- *  Write data to channel.
- *  Handle different data size types.
- *
- */
-static int sdio_ch_write(struct sdio_channel *ch, const u8 *buf, u32 len)
-{
-	int ret = 0;
-	unsigned blksz = ch->func->cur_blksize;
-	int blocks = len / blksz;
-	int remain_bytes = len % blksz;
-	struct mmc_card *card = NULL;
-	u32 fn = ch->func->num;
-
-	if (!ch) {
-		sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s: NULL "
-				"channel\n", __func__);
-		return -ENODEV;
-	}
-
-	if (!ch->sdio_al_dev) {
-		sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s: NULL "
-				"sdio_al_dev\n", __func__);
-		return -ENODEV;
-	}
-
-	if (len == 0) {
-		sdio_al_loge(ch->sdio_al_dev->dev_log, MODULE_NAME ":channel "
-				"%s trying to write 0 bytes\n", ch->name);
-		return -EINVAL;
-	}
-
-	card = ch->func->card;
-
-	if (remain_bytes) {
-		/* CMD53 */
-		if (blocks) {
-			ret = sdio_memcpy_toio(ch->func, PIPE_TX_FIFO_ADDR,
-					       (void *) buf, blocks*blksz);
-			if (ret != 0) {
-				sdio_al_loge(ch->sdio_al_dev->dev_log,
-					MODULE_NAME ":%s: sdio_memcpy_toio "
-					"failed for channel %s\n",
-					__func__, ch->name);
-				sdio_al_get_into_err_state(ch->sdio_al_dev);
-				return ret;
-			}
-		}
-
-		buf += (blocks*blksz);
-
-		ret = sdio_write_cmd54(card, fn, PIPE_TX_FIFO_ADDR,
-				buf, 1, remain_bytes);
-	} else {
-		ret = sdio_write_cmd54(card, fn, PIPE_TX_FIFO_ADDR,
-				buf, blocks, blksz);
-	}
-
-	if (ret != 0) {
-		sdio_al_loge(ch->sdio_al_dev->dev_log, MODULE_NAME ":%s: "
-				"sdio_write_cmd54 failed for channel %s\n",
-				__func__, ch->name);
-		ch->sdio_al_dev->is_err = true;
-		return ret;
-	}
-
-	return ret;
-}
-
-static int sdio_al_bootloader_completed(void)
-{
-	int i;
-
-	pr_debug(MODULE_NAME ":sdio_al_bootloader_completed was called\n");
-
-	for (i = 0; i < MAX_NUM_OF_SDIO_DEVICES; ++i) {
-		struct sdio_al_device *dev = NULL;
-		if (sdio_al->devices[i] == NULL)
-			continue;
-		dev = sdio_al->devices[i];
-		dev->bootloader_done = 1;
-		wake_up(&dev->wait_mbox);
-	}
-
-	return 0;
-}
-
-static int sdio_al_wait_for_bootloader_comp(struct sdio_al_device *sdio_al_dev)
-{
-	int ret = 0;
-
-	if (sdio_al_claim_mutex_and_verify_dev(sdio_al_dev, __func__))
-		return -ENODEV;
-
-	/*
-	 * Enable function 0 interrupt mask to allow 9k to raise this interrupt
-	 * in power-up. When sdio_downloader will notify its completion
-	 * we will poll on this interrupt to wait for 9k power-up
-	 */
-	ret = enable_mask_irq(sdio_al_dev, 0, 1, 0);
-	if (ret) {
-		sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
-				": Enable_mask_irq for card %d failed, "
-				"ret=%d\n",
-				sdio_al_dev->host->index, ret);
-		sdio_al_release_mutex(sdio_al_dev, __func__);
-		return ret;
-	}
-
-	sdio_al_release_mutex(sdio_al_dev, __func__);
-
-	/*
-	 * Start bootloader worker that will wait for the bootloader
-	 * completion
-	 */
-	sdio_al_dev->boot_work.sdio_al_dev = sdio_al_dev;
-	INIT_WORK(&sdio_al_dev->boot_work.work, boot_worker);
-	sdio_al_dev->bootloader_done = 0;
-	queue_work(sdio_al_dev->workqueue, &sdio_al_dev->boot_work.work);
-
-	return 0;
-}
-
-static int sdio_al_bootloader_setup(void)
-{
-	int ret = 0;
-	struct sdio_al_device *bootloader_dev = sdio_al->bootloader_dev;
-	struct sdio_func *func1 = NULL;
-
-	if (sdio_al_claim_mutex_and_verify_dev(bootloader_dev, __func__))
-		return -ENODEV;
-
-	if (bootloader_dev->flashless_boot_on) {
-		sdio_al_loge(bootloader_dev->dev_log, MODULE_NAME ":Already "
-			"in boot process.\n");
-		sdio_al_release_mutex(bootloader_dev, __func__);
-		return 0;
-	}
-
-	bootloader_dev->sdioc_boot_sw_header
-		= kzalloc(sizeof(*bootloader_dev->sdioc_boot_sw_header),
-			  GFP_KERNEL);
-	if (bootloader_dev->sdioc_boot_sw_header == NULL) {
-		sdio_al_loge(bootloader_dev->dev_log, MODULE_NAME ":fail to "
-			"allocate sdioc boot sw header.\n");
-		sdio_al_release_mutex(bootloader_dev, __func__);
-		return -ENOMEM;
-	}
-
-	if (sdio_al_verify_func1(bootloader_dev, __func__)) {
-		sdio_al_release_mutex(bootloader_dev, __func__);
-		goto exit_err;
-	}
-	func1 = bootloader_dev->card->sdio_func[0];
-
-	ret = sdio_memcpy_fromio(func1,
-				 bootloader_dev->sdioc_boot_sw_header,
-				 SDIOC_SW_HEADER_ADDR,
-				 sizeof(struct peer_sdioc_boot_sw_header));
-	if (ret) {
-		sdio_al_loge(bootloader_dev->dev_log, MODULE_NAME ":fail to "
-			"read sdioc boot sw header.\n");
-		sdio_al_release_mutex(bootloader_dev, __func__);
-		goto exit_err;
-	}
-
-	if (bootloader_dev->sdioc_boot_sw_header->signature !=
-	    (u32) PEER_SDIOC_SW_MAILBOX_BOOT_SIGNATURE) {
-		sdio_al_loge(bootloader_dev->dev_log, MODULE_NAME ":invalid "
-			"mailbox signature 0x%x.\n",
-			bootloader_dev->sdioc_boot_sw_header->signature);
-		sdio_al_release_mutex(bootloader_dev, __func__);
-		ret = -EINVAL;
-		goto exit_err;
-	}
-
-	/* Upper byte has to be equal - no backward compatibility for unequal */
-	if ((bootloader_dev->sdioc_boot_sw_header->version >> 16) !=
-	    (sdio_al->pdata->peer_sdioc_boot_version_major)) {
-		sdio_al_loge(bootloader_dev->dev_log, MODULE_NAME ": HOST(0x%x)"
-			" and CLIENT(0x%x) SDIO_AL BOOT VERSION don't match\n",
-			((sdio_al->pdata->peer_sdioc_boot_version_major<<16)+
-			sdio_al->pdata->peer_sdioc_boot_version_minor),
-			bootloader_dev->sdioc_boot_sw_header->version);
-		sdio_al_release_mutex(bootloader_dev, __func__);
-		ret = -EIO;
-		goto exit_err;
-	}
-
-	sdio_al_logi(bootloader_dev->dev_log, MODULE_NAME ": SDIOC BOOT SW "
-			"version 0x%x\n",
-			bootloader_dev->sdioc_boot_sw_header->version);
-
-	bootloader_dev->flashless_boot_on = true;
-
-	sdio_al_release_mutex(bootloader_dev, __func__);
-
-	ret = sdio_al_wait_for_bootloader_comp(bootloader_dev);
-	if (ret) {
-		sdio_al_loge(bootloader_dev->dev_log, MODULE_NAME
-				": sdio_al_wait_for_bootloader_comp failed, "
-				"err=%d\n", ret);
-		goto exit_err;
-	}
-
-	ret = sdio_downloader_setup(bootloader_dev->card, 1,
-			bootloader_dev->sdioc_boot_sw_header->boot_ch_num,
-			sdio_al_bootloader_completed);
-
-	if (ret) {
-		sdio_al_loge(bootloader_dev->dev_log, MODULE_NAME
-			": sdio_downloader_setup failed, err=%d\n", ret);
-		goto exit_err;
-	}
-
-	sdio_al_logi(bootloader_dev->dev_log, MODULE_NAME ":In Flashless boot,"
-		" waiting for its completion\n");
-
-
-exit_err:
-	sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ":free "
-			"sdioc_boot_sw_header.\n");
-	kfree(bootloader_dev->sdioc_boot_sw_header);
-	bootloader_dev->sdioc_boot_sw_header = NULL;
-	bootloader_dev = NULL;
-
-	return ret;
-}
-
-
-/**
- *  Read SDIO-Client software header
- *
- */
-static int read_sdioc_software_header(struct sdio_al_device *sdio_al_dev,
-				      struct peer_sdioc_sw_header *header)
-{
-	int ret;
-	int i;
-	int test_version = 0;
-	int sdioc_test_version = 0;
-	struct sdio_func *func1 = NULL;
-
-	pr_debug(MODULE_NAME ":reading sdioc sw header.\n");
-
-	if (sdio_al_verify_func1(sdio_al_dev, __func__))
-		return -ENODEV;
-
-	func1 = sdio_al_dev->card->sdio_func[0];
-
-	ret = sdio_memcpy_fromio(func1, header,
-			SDIOC_SW_HEADER_ADDR, sizeof(*header));
-	if (ret) {
-		sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":fail to read "
-				"sdioc sw header.\n");
-		goto exit_err;
-	}
-
-	if (header->signature == (u32)PEER_SDIOC_SW_MAILBOX_UT_SIGNATURE) {
-		sdio_al_logi(sdio_al_dev->dev_log, MODULE_NAME ":SDIOC SW "
-				"unittest signature. 0x%x\n",
-				header->signature);
-		sdio_al->unittest_mode = true;
-		/* Verify test code compatibility with the modem */
-		sdioc_test_version = (header->version & 0xFF00) >> 8;
-		test_version = sdio_al->pdata->peer_sdioc_version_minor >> 8;
-		if (test_version != sdioc_test_version) {
-			sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
-				": HOST(0x%x) and CLIENT(0x%x) "
-				"testing VERSION don't match\n",
-				test_version,
-				sdioc_test_version);
-			msleep(500);
-			BUG();
-		}
-	}
-
-	if ((header->signature != (u32) PEER_SDIOC_SW_MAILBOX_SIGNATURE) &&
-	    (header->signature != (u32) PEER_SDIOC_SW_MAILBOX_UT_SIGNATURE)) {
-		sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":SDIOC SW "
-				"invalid signature. 0x%x\n", header->signature);
-		goto exit_err;
-	}
-	/* Upper byte has to be equal - no backward compatibility for unequal */
-	sdio_al->sdioc_major = header->version >> 16;
-	if (sdio_al->pdata->allow_sdioc_version_major_2) {
-		if ((sdio_al->sdioc_major !=
-		    sdio_al->pdata->peer_sdioc_version_major) &&
-		    (sdio_al->sdioc_major != PEER_SDIOC_OLD_VERSION_MAJOR)) {
-			sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
-				": HOST(0x%x) and CLIENT(0x%x) "
-				"SDIO_AL VERSION don't match\n",
-				((sdio_al->pdata->peer_sdioc_version_major<<16)+
-				sdio_al->pdata->peer_sdioc_version_minor),
-				header->version);
-			goto exit_err;
-		}
-	} else {
-		if (sdio_al->sdioc_major !=
-		    sdio_al->pdata->peer_sdioc_version_major) {
-			sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
-				": HOST(0x%x) and CLIENT(0x%x) "
-				"SDIO_AL VERSION don't match\n",
-				((sdio_al->pdata->peer_sdioc_version_major<<16)+
-				sdio_al->pdata->peer_sdioc_version_minor),
-				header->version);
-			goto exit_err;
-		}
-	}
-	sdio_al_dev->ch_close_supported = (header->version & 0x000F) >=
-		(sdio_al->pdata->peer_sdioc_version_minor & 0xF);
-
-	sdio_al_logi(sdio_al_dev->dev_log, MODULE_NAME ":SDIOC SW version 0x%x,"
-			" sdio_al major 0x%x minor 0x%x\n", header->version,
-			sdio_al->sdioc_major,
-			sdio_al->pdata->peer_sdioc_version_minor);
-
-	sdio_al_dev->flashless_boot_on = false;
-	for (i = 0; i < SDIO_AL_MAX_CHANNELS; i++) {
-		struct sdio_channel *ch = &sdio_al_dev->channel[i];
-
-		/* Set default values */
-		ch->read_threshold  = DEFAULT_READ_THRESHOLD;
-		ch->write_threshold = DEFAULT_WRITE_THRESHOLD;
-		ch->min_write_avail = DEFAULT_MIN_WRITE_THRESHOLD;
-		ch->is_packet_mode = true;
-		ch->peer_tx_buf_size = DEFAULT_PEER_TX_BUF_SIZE;
-		ch->poll_delay_msec = 0;
-
-		ch->num = i;
-		ch->func = NULL;
-		ch->rx_pipe_index = ch->num*2;
-		ch->tx_pipe_index = ch->num*2+1;
-
-		memset(ch->name, 0, sizeof(ch->name));
-
-		if (header->channel_names[i][0]) {
-			memcpy(ch->name, SDIO_PREFIX,
-			       strlen(SDIO_PREFIX));
-			memcpy(ch->name + strlen(SDIO_PREFIX),
-			       header->channel_names[i],
-			       PEER_CHANNEL_NAME_SIZE);
-
-			ch->state = SDIO_CHANNEL_STATE_IDLE;
-			ch->sdio_al_dev = sdio_al_dev;
-			if (sdio_al_dev->card->sdio_func[ch->num+1]) {
-				ch->func =
-				sdio_al_dev->card->sdio_func[ch->num+1];
-			} else {
-				sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
-					": NULL func for channel %s\n",
-					ch->name);
-				goto exit_err;
-			}
-		} else {
-			ch->state = SDIO_CHANNEL_STATE_INVALID;
-		}
-
-		sdio_al_logi(sdio_al_dev->dev_log, MODULE_NAME ":Channel=%s, "
-				"state=%d\n", ch->name,	ch->state);
-	}
-
-	return 0;
-
-exit_err:
-	sdio_al_get_into_err_state(sdio_al_dev);
-	memset(header, 0, sizeof(*header));
-
-	return -EIO;
-}
-
-/**
- *  Read SDIO-Client channel configuration
- *
- */
-static int read_sdioc_channel_config(struct sdio_channel *ch)
-{
-	int ret;
-	struct peer_sdioc_sw_mailbox *sw_mailbox = NULL;
-	struct peer_sdioc_channel_config *ch_config = NULL;
-	struct sdio_al_device *sdio_al_dev = ch->sdio_al_dev;
-
-	if (sdio_al_dev == NULL) {
-		sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": NULL sdio_al_dev"
-				" for channel %s\n", ch->name);
-		return -EINVAL;
-	}
-
-	if (sdio_al_dev->sdioc_sw_header->version == 0)
-		return -1;
-
-	pr_debug(MODULE_NAME ":reading sw mailbox %s channel.\n", ch->name);
-
-	sw_mailbox = kzalloc(sizeof(*sw_mailbox), GFP_KERNEL);
-	if (sw_mailbox == NULL)
-		return -ENOMEM;
-
-	ret = sdio_memcpy_fromio(ch->func, sw_mailbox,
-			SDIOC_SW_MAILBOX_ADDR, sizeof(*sw_mailbox));
-	if (ret) {
-		sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":fail to read "
-				"sw mailbox.\n");
-		goto exit_err;
-	}
-
-	ch_config = &sw_mailbox->ch_config[ch->num];
-	memcpy(&ch->ch_config, ch_config,
-		sizeof(struct peer_sdioc_channel_config));
-
-	if (!ch_config->is_ready) {
-		sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":sw mailbox "
-				"channel not ready.\n");
-		goto exit_err;
-	}
-
-	ch->read_threshold = LOW_LATENCY_THRESHOLD;
-	ch->is_low_latency_ch = ch_config->is_low_latency_ch;
-	/* Threshold on 50% of the maximum size , sdioc uses double-buffer */
-	ch->write_threshold = (ch_config->max_tx_threshold * 5) / 10;
-	ch->threshold_change_cnt = ch->ch_config.max_rx_threshold -
-			ch->read_threshold + THRESHOLD_CHANGE_EXTRA_BYTES;
-
-	if (ch->is_low_latency_ch)
-		ch->def_read_threshold = LOW_LATENCY_THRESHOLD;
-	else /* Aggregation up to 90% of the maximum size */
-		ch->def_read_threshold = (ch_config->max_rx_threshold * 9) / 10;
-
-	ch->is_packet_mode = ch_config->is_packet_mode;
-	if (!ch->is_packet_mode) {
-		ch->poll_delay_msec = DEFAULT_POLL_DELAY_NOPACKET_MSEC;
-		ch->min_write_avail = DEFAULT_MIN_WRITE_THRESHOLD_STREAMING;
-	}
-	/* The max_packet_size is set by the modem in version 3 and on */
-	if (sdio_al->sdioc_major > PEER_SDIOC_OLD_VERSION_MAJOR)
-		ch->min_write_avail = ch_config->max_packet_size;
-
-	if (ch->min_write_avail > ch->write_threshold)
-		ch->min_write_avail = ch->write_threshold;
-
-	CLOSE_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ":ch %s "
-			"read_threshold=%d, write_threshold=%d,"
-			" min_write_avail=%d, max_rx_threshold=%d,"
-			" max_tx_threshold=%d\n", ch->name, ch->read_threshold,
-			ch->write_threshold, ch->min_write_avail,
-			ch_config->max_rx_threshold,
-			ch_config->max_tx_threshold);
-
-	ch->peer_tx_buf_size = ch_config->tx_buf_size;
-
-	kfree(sw_mailbox);
-
-	return 0;
-
-exit_err:
-	sdio_al_logi(sdio_al_dev->dev_log, MODULE_NAME ":Reading SW Mailbox "
-			"error.\n");
-	kfree(sw_mailbox);
-
-	return -1;
-}
-
-
-/**
- *  Enable/Disable EOT interrupt of a pipe.
- *
- */
-static int enable_eot_interrupt(struct sdio_al_device *sdio_al_dev,
-				int pipe_index, int enable)
-{
-	int ret = 0;
-	struct sdio_func *func1;
-	u32 mask;
-	u32 pipe_mask;
-	u32 addr;
-
-	if (sdio_al_verify_func1(sdio_al_dev, __func__))
-		return -ENODEV;
-	func1 = sdio_al_dev->card->sdio_func[0];
-
-	if (pipe_index < 8) {
-		addr = PIPES_0_7_IRQ_MASK_ADDR;
-		pipe_mask = (1<<pipe_index);
-	} else {
-		addr = PIPES_8_15_IRQ_MASK_ADDR;
-		pipe_mask = (1<<(pipe_index-8));
-	}
-
-	mask = sdio_readl(func1, addr, &ret);
-	if (ret) {
-		pr_debug(MODULE_NAME ":enable_eot_interrupt fail\n");
-		goto exit_err;
-	}
-
-	if (enable)
-		mask &= (~pipe_mask); /* 0 = enable */
-	else
-		mask |= (pipe_mask);  /* 1 = disable */
-
-	sdio_writel(func1, mask, addr, &ret);
-
-exit_err:
-	return ret;
-}
-
-
-/**
- *  Enable/Disable mask interrupt of a function.
- *
- */
-static int enable_mask_irq(struct sdio_al_device *sdio_al_dev,
-			   int func_num, int enable, u8 bit_offset)
-{
-	int ret = 0;
-	struct sdio_func *func1 = NULL;
-	u32 mask = 0;
-	u32 func_mask = 0;
-	u32 addr = 0;
-	u32 offset = 0;
-
-	if (sdio_al_verify_func1(sdio_al_dev, __func__))
-		return -ENODEV;
-	func1 = sdio_al_dev->card->sdio_func[0];
-
-	if (func_num < 4) {
-		addr = FUNC_1_4_MASK_IRQ_ADDR;
-		offset = func_num * 8 + bit_offset;
-	} else {
-		addr = FUNC_5_7_MASK_IRQ_ADDR;
-		offset = (func_num - 4) * 8 + bit_offset;
-	}
-
-	func_mask = 1<<offset;
-
-	mask = sdio_readl(func1, addr, &ret);
-	if (ret) {
-		sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": "
-				"enable_mask_irq fail\n");
-		goto exit_err;
-	}
-
-	if (enable)
-		mask &= (~func_mask); /* 0 = enable */
-	else
-		mask |= (func_mask);  /* 1 = disable */
-
-	pr_debug(MODULE_NAME ":enable_mask_irq,  writing mask = 0x%x\n", mask);
-
-	sdio_writel(func1, mask, addr, &ret);
-
-exit_err:
-	return ret;
-}
-
-/**
- *  Enable/Disable Threshold interrupt of a pipe.
- *
- */
-static int enable_threshold_interrupt(struct sdio_al_device *sdio_al_dev,
-				      int pipe_index, int enable)
-{
-	int ret = 0;
-	struct sdio_func *func1;
-	u32 mask;
-	u32 pipe_mask;
-	u32 addr;
-
-	if (sdio_al_verify_func1(sdio_al_dev, __func__))
-		return -ENODEV;
-	func1 = sdio_al_dev->card->sdio_func[0];
-
-	if (pipe_index < 8) {
-		addr = PIPES_0_7_IRQ_MASK_ADDR;
-		pipe_mask = (1<<pipe_index);
-	} else {
-		addr = PIPES_8_15_IRQ_MASK_ADDR;
-		pipe_mask = (1<<(pipe_index-8));
-	}
-
-	mask = sdio_readl(func1, addr, &ret);
-	if (ret) {
-		pr_debug(MODULE_NAME ":enable_threshold_interrupt fail\n");
-		goto exit_err;
-	}
-
-	pipe_mask = pipe_mask<<8; /* Threshold bits 8..15 */
-	if (enable)
-		mask &= (~pipe_mask); /* 0 = enable */
-	else
-		mask |= (pipe_mask);  /* 1 = disable */
-
-	sdio_writel(func1, mask, addr, &ret);
-
-exit_err:
-	return ret;
-}
-
-/**
- *  Set the threshold to trigger interrupt from SDIO-Card on
- *  pipe available bytes.
- *
- */
-static int set_pipe_threshold(struct sdio_al_device *sdio_al_dev,
-			      int pipe_index, int threshold)
-{
-	int ret = 0;
-	struct sdio_func *func1;
-
-	if (sdio_al_verify_func1(sdio_al_dev, __func__))
-		return -ENODEV;
-	func1 = sdio_al_dev->card->sdio_func[0];
-
-	sdio_writel(func1, threshold,
-			PIPES_THRESHOLD_ADDR+pipe_index*4, &ret);
-	if (ret)
-		sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": "
-				"set_pipe_threshold err=%d\n", -ret);
-
-	return ret;
-}
-
-/**
- *  Enable func w/ retries
- *
- */
-static int sdio_al_enable_func_retry(struct sdio_func *func, const char *name)
-{
-	int ret, i;
-	for (i = 0; i < 200; i++) {
-		ret = sdio_enable_func(func);
-		if (ret) {
-			pr_debug(MODULE_NAME ":retry enable %s func#%d "
-					     "ret=%d\n",
-					 name, func->num, ret);
-			msleep(10);
-		} else
-			break;
-	}
-
-	return ret;
-}
-
-/**
- *  Open Channel
- *
- *  1. Init Channel Context.
- *  2. Init the Channel SDIO-Function.
- *  3. Init the Channel Pipes on Mailbox.
- */
-static int open_channel(struct sdio_channel *ch)
-{
-	int ret = 0;
-	struct sdio_al_device *sdio_al_dev = ch->sdio_al_dev;
-
-	if (sdio_al_dev == NULL) {
-		sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": NULL "
-				"sdio_al_dev for channel %s\n", ch->name);
-		return -EINVAL;
-	}
-
-	/* Init channel Context */
-	/** Func#1 is reserved for mailbox */
-	ch->func = sdio_al_dev->card->sdio_func[ch->num+1];
-	ch->rx_pipe_index = ch->num*2;
-	ch->tx_pipe_index = ch->num*2+1;
-	ch->signature = SDIO_AL_SIGNATURE;
-
-	ch->total_rx_bytes = 0;
-	ch->total_tx_bytes = 0;
-
-	ch->write_avail = 0;
-	ch->read_avail = 0;
-	ch->rx_pending_bytes = 0;
-
-	mutex_init(&ch->ch_lock);
-
-	pr_debug(MODULE_NAME ":open_channel %s func#%d\n",
-			 ch->name, ch->func->num);
-
-	INIT_LIST_HEAD(&(ch->rx_size_list_head));
-
-	/* Init SDIO Function */
-	ret = sdio_al_enable_func_retry(ch->func, ch->name);
-	if (ret) {
-		sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": "
-				"sdio_enable_func() err=%d\n", -ret);
-		goto exit_err;
-	}
-
-	/* Note: Patch Func CIS tuple issue */
-	ret = sdio_set_block_size(ch->func, SDIO_AL_BLOCK_SIZE);
-	if (ret) {
-		sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": "
-				"sdio_set_block_size()failed, err=%d\n", -ret);
-		goto exit_err;
-	}
-
-	ch->func->max_blksize = SDIO_AL_BLOCK_SIZE;
-
-	sdio_set_drvdata(ch->func, ch);
-
-	/* Get channel parameters from the peer SDIO-Client */
-	read_sdioc_channel_config(ch);
-
-	/* Set Pipes Threshold on Mailbox */
-	ret = set_pipe_threshold(sdio_al_dev,
-				 ch->rx_pipe_index, ch->read_threshold);
-	if (ret)
-		goto exit_err;
-	ret = set_pipe_threshold(sdio_al_dev,
-				 ch->tx_pipe_index, ch->write_threshold);
-	if (ret)
-		goto exit_err;
-
-	/* Set flag before interrupts are enabled to allow notify */
-	ch->state = SDIO_CHANNEL_STATE_OPEN;
-	pr_debug(MODULE_NAME ":channel %s is in OPEN state now\n", ch->name);
-
-	sdio_al_dev->poll_delay_msec = get_min_poll_time_msec(sdio_al_dev);
-
-	/* lpm mechanism lives under the assumption there is always a timer */
-	/* Check if need to start the timer */
-	if  ((sdio_al_dev->poll_delay_msec) &&
-	     (sdio_al_dev->is_timer_initialized == false)) {
-
-		init_timer(&sdio_al_dev->timer);
-		sdio_al_dev->timer.data = (unsigned long) sdio_al_dev;
-		sdio_al_dev->timer.function = sdio_al_timer_handler;
-		sdio_al_dev->timer.expires = jiffies +
-			msecs_to_jiffies(sdio_al_dev->poll_delay_msec);
-		add_timer(&sdio_al_dev->timer);
-		sdio_al_dev->is_timer_initialized = true;
-	}
-
-	/* Enable Pipes Interrupts */
-	enable_eot_interrupt(sdio_al_dev, ch->rx_pipe_index, true);
-	enable_eot_interrupt(sdio_al_dev, ch->tx_pipe_index, true);
-
-	enable_threshold_interrupt(sdio_al_dev, ch->rx_pipe_index, true);
-	enable_threshold_interrupt(sdio_al_dev, ch->tx_pipe_index, true);
-
-exit_err:
-
-	return ret;
-}
-
-/**
- *  Ask the worker to read the mailbox.
- */
-static void ask_reading_mailbox(struct sdio_al_device *sdio_al_dev)
-{
-	if (!sdio_al_dev->ask_mbox) {
-		pr_debug(MODULE_NAME ":ask_reading_mailbox for card %d\n",
-			 sdio_al_dev->host->index);
-		sdio_al_dev->ask_mbox = true;
-		wake_up(&sdio_al_dev->wait_mbox);
-	}
-}
-
-/**
- *  Start the timer
- */
-static void start_timer(struct sdio_al_device *sdio_al_dev)
-{
-	if ((sdio_al_dev->poll_delay_msec)  &&
-		(sdio_al_dev->state == CARD_INSERTED)) {
-		sdio_al_dev->timer.expires = jiffies +
-			msecs_to_jiffies(sdio_al_dev->poll_delay_msec);
-		add_timer(&sdio_al_dev->timer);
-	}
-}
-
-/**
- *  Restart(postpone) the already working timer
- */
-static void restart_timer(struct sdio_al_device *sdio_al_dev)
-{
-	if ((sdio_al_dev->poll_delay_msec) &&
-		(sdio_al_dev->state == CARD_INSERTED)) {
-		ulong expires =	jiffies +
-			msecs_to_jiffies(sdio_al_dev->poll_delay_msec);
-		mod_timer(&sdio_al_dev->timer, expires);
-	}
-}
-
-/**
- *  Stop and delete the timer
- */
-static void stop_and_del_timer(struct sdio_al_device *sdio_al_dev)
-{
-	if (sdio_al_dev->is_timer_initialized) {
-		sdio_al_dev->poll_delay_msec = 0;
-		del_timer_sync(&sdio_al_dev->timer);
-	}
-}
-
-/**
- *  Do the wakup sequence.
- *  This function should be called after claiming the host!
- *  The caller is responsible for releasing the host.
- *
- *  Wake up sequence
- *  1. Get lock
- *  2. Enable wake up function if needed
- *  3. Mark NOT OK to sleep and write it
- *  4. Restore default thresholds
- *  5. Start the mailbox and inactivity timer again
- */
-static int sdio_al_wake_up(struct sdio_al_device *sdio_al_dev,
-			   u32 not_from_int, struct sdio_channel *ch)
-{
-	int ret = 0;
-	struct sdio_func *wk_func = NULL;
-	unsigned long time_to_wait;
-	struct mmc_host *host = sdio_al_dev->host;
-
-	if (sdio_al_dev->is_err) {
-		SDIO_AL_ERR(__func__);
-		return -ENODEV;
-	}
-
-	if (!sdio_al_dev->is_ok_to_sleep) {
-		LPM_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ":card %d "
-				"already awake, no need to wake up\n",
-				sdio_al_dev->host->index);
-		return 0;
-	}
-
-	/* Wake up sequence */
-	if (not_from_int) {
-		if (ch) {
-			LPM_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ": Wake up"
-					" card %d (not by interrupt), ch %s",
-					sdio_al_dev->host->index,
-					ch->name);
-		} else {
-			LPM_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ": Wake up"
-					  " card %d (not	by interrupt)",
-					  sdio_al_dev->host->index);
-		}
-	} else {
-		LPM_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ": Wake up card "
-				"%d by interrupt",
-				sdio_al_dev->host->index);
-		sdio_al_dev->print_after_interrupt = 1;
-	}
-
-	sdio_al_vote_for_sleep(sdio_al_dev, 0);
-
-	msmsdcc_lpm_disable(host);
-	msmsdcc_set_pwrsave(host, 0);
-	/* Poll the GPIO */
-	time_to_wait = jiffies + msecs_to_jiffies(1000);
-	while (time_before(jiffies, time_to_wait)) {
-		if (sdio_al->pdata->get_mdm2ap_status())
-			break;
-		udelay(TIME_TO_WAIT_US);
-	}
-
-	pr_debug(MODULE_NAME ":GPIO mdm2ap_status=%d\n",
-		       sdio_al->pdata->get_mdm2ap_status());
-
-	/* Here get_mdm2ap_status() returning 0 is not an error condition */
-	if (sdio_al->pdata->get_mdm2ap_status() == 0)
-		LPM_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ": "
-				"get_mdm2ap_status() is 0\n");
-
-	/* Enable Wake up Function */
-	if (!sdio_al_dev->card ||
-	    !sdio_al_dev->card->sdio_func[SDIO_AL_WAKEUP_FUNC-1]) {
-		sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
-				": NULL card or wk_func\n");
-		return -ENODEV;
-	}
-	wk_func = sdio_al_dev->card->sdio_func[SDIO_AL_WAKEUP_FUNC-1];
-	ret = sdio_al_enable_func_retry(wk_func, "wakeup func");
-	if (ret) {
-		sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": "
-				"sdio_enable_func() err=%d\n", -ret);
-		goto error_exit;
-	}
-	/* Mark NOT OK_TOSLEEP */
-	sdio_al_dev->is_ok_to_sleep = 0;
-	ret = write_lpm_info(sdio_al_dev);
-	if (ret) {
-		sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": "
-				"write_lpm_info() failed, err=%d\n", -ret);
-		sdio_al_dev->is_ok_to_sleep = 1;
-		sdio_disable_func(wk_func);
-		goto error_exit;
-	}
-	sdio_disable_func(wk_func);
-
-	/* Start the timer again*/
-	restart_inactive_time(sdio_al_dev);
-	sdio_al_dev->poll_delay_msec = get_min_poll_time_msec(sdio_al_dev);
-	start_timer(sdio_al_dev);
-
-	LPM_DEBUG(sdio_al_dev->dev_log, MODULE_NAME "Finished Wake up sequence"
-			" for card %d", sdio_al_dev->host->index);
-
-	msmsdcc_set_pwrsave(host, 1);
-	pr_debug(MODULE_NAME ":Turn clock off\n");
-
-	return ret;
-error_exit:
-	sdio_al_vote_for_sleep(sdio_al_dev, 1);
-	msmsdcc_set_pwrsave(host, 1);
-	WARN_ON(ret);
-	sdio_al_get_into_err_state(sdio_al_dev);
-	return ret;
-}
-
-
-/**
- *  SDIO Function Interrupt handler.
- *
- *  Interrupt shall be triggered by SDIO-Client when:
- *  1. End-Of-Transfer (EOT) detected in packet mode.
- *  2. Bytes-available reached the threshold.
- *
- *  Reading the mailbox clears the EOT/Threshold interrupt
- *  source.
- *  The interrupt source should be cleared before this ISR
- *  returns. This ISR is called from IRQ Thread and not
- *  interrupt, so it may sleep.
- *
- */
-static void sdio_func_irq(struct sdio_func *func)
-{
-	struct sdio_al_device *sdio_al_dev = sdio_get_drvdata(func);
-
-	pr_debug(MODULE_NAME ":start %s.\n", __func__);
-
-	if (sdio_al_dev == NULL) {
-		sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": NULL device");
-		return;
-	}
-
-	if (sdio_al_dev->is_ok_to_sleep)
-		sdio_al_wake_up(sdio_al_dev, 0, NULL);
-	else
-		restart_timer(sdio_al_dev);
-
-	read_mailbox(sdio_al_dev, true);
-
-	pr_debug(MODULE_NAME ":end %s.\n", __func__);
-}
-
-/**
- *  Timer Expire Handler
- *
- */
-static void sdio_al_timer_handler(unsigned long data)
-{
-	struct sdio_al_device *sdio_al_dev = (struct sdio_al_device *)data;
-	if (sdio_al_dev == NULL) {
-		sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": NULL "
-				"sdio_al_dev for data %lu\n", data);
-		return;
-	}
-	if (sdio_al_dev->state != CARD_INSERTED) {
-		sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": sdio_al_dev "
-				"is in invalid state %d\n", sdio_al_dev->state);
-		return;
-	}
-	pr_debug(MODULE_NAME " Timer Expired\n");
-
-	ask_reading_mailbox(sdio_al_dev);
-
-	restart_timer(sdio_al_dev);
-}
-
-/**
- *  Driver Setup.
- *
- */
-static int sdio_al_setup(struct sdio_al_device *sdio_al_dev)
-{
-	int ret = 0;
-	struct mmc_card *card = sdio_al_dev->card;
-	struct sdio_func *func1 = NULL;
-	int i = 0;
-	int fn = 0;
-
-	if (sdio_al_verify_func1(sdio_al_dev, __func__))
-		return -ENODEV;
-	func1 = card->sdio_func[0];
-
-	sdio_al_logi(sdio_al_dev->dev_log, MODULE_NAME ":sdio_al_setup for "
-			"card %d\n", sdio_al_dev->host->index);
-
-	ret = sdio_al->pdata->config_mdm2ap_status(1);
-	if (ret) {
-		sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME "Could not "
-				"request GPIO\n");
-		return ret;
-	}
-
-	INIT_WORK(&sdio_al_dev->sdio_al_work.work, worker);
-	/* disable all pipes interrupts before claim irq.
-	   since all are enabled by default. */
-	for (i = 0 ; i < SDIO_AL_MAX_PIPES; i++) {
-		enable_eot_interrupt(sdio_al_dev, i, false);
-		enable_threshold_interrupt(sdio_al_dev, i, false);
-	}
-
-	/* Disable all SDIO Functions before claim irq. */
-	for (fn = 1 ; fn <= card->sdio_funcs; fn++)
-		sdio_disable_func(card->sdio_func[fn-1]);
-
-	sdio_set_drvdata(func1, sdio_al_dev);
-	sdio_al_logi(sdio_al_dev->dev_log, MODULE_NAME ":claim IRQ for card "
-			"%d\n",	sdio_al_dev->host->index);
-
-	ret = sdio_claim_irq(func1, sdio_func_irq);
-	if (ret) {
-		sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":Fail to claim"
-				" IRQ for card %d\n",
-				sdio_al_dev->host->index);
-		return ret;
-	}
-
-	sdio_al_dev->is_ready = true;
-
-	/* Start worker before interrupt might happen */
-	queue_work(sdio_al_dev->workqueue, &sdio_al_dev->sdio_al_work.work);
-
-	start_inactive_time(sdio_al_dev);
-
-	pr_debug(MODULE_NAME ":Ready.\n");
-
-	return 0;
-}
-
-/**
- *  Driver Tear-Down.
- *
- */
-static void sdio_al_tear_down(void)
-{
-	int i, j;
-	struct sdio_al_device *sdio_al_dev = NULL;
-	struct sdio_func *func1;
-
-	for (i = 0; i < MAX_NUM_OF_SDIO_DEVICES; ++i) {
-		if (sdio_al->devices[i] == NULL)
-			continue;
-		sdio_al_dev = sdio_al->devices[i];
-
-		if (sdio_al_dev->is_ready) {
-			sdio_al_dev->is_ready = false; /* Flag worker to exit */
-			sdio_al_dev->ask_mbox = false;
-			ask_reading_mailbox(sdio_al_dev); /* Wakeup worker */
-			/* allow gracefully exit of the worker thread */
-			msleep(100);
-
-			flush_workqueue(sdio_al_dev->workqueue);
-			destroy_workqueue(sdio_al_dev->workqueue);
-
-			sdio_al_vote_for_sleep(sdio_al_dev, 1);
-
-			if (!sdio_al_claim_mutex_and_verify_dev(sdio_al_dev,
-								__func__)) {
-				if (!sdio_al_dev->card ||
-				    !sdio_al_dev->card->sdio_func[0]) {
-					sdio_al_loge(sdio_al_dev->dev_log,
-						     MODULE_NAME
-							": %s: Invalid func1",
-							__func__);
-					return;
-				}
-				func1 = sdio_al_dev->card->sdio_func[0];
-				sdio_release_irq(func1);
-				sdio_disable_func(func1);
-				sdio_al_release_mutex(sdio_al_dev, __func__);
-			}
-		}
-
-		for (j = 0; j < SDIO_AL_MAX_CHANNELS; j++)
-			sdio_al_dev->channel[j].signature = 0x0;
-		sdio_al_dev->signature = 0;
-
-		kfree(sdio_al_dev->sdioc_sw_header);
-		kfree(sdio_al_dev->mailbox);
-		kfree(sdio_al_dev->rx_flush_buf);
-		kfree(sdio_al_dev);
-	}
-
-	sdio_al->pdata->config_mdm2ap_status(0);
-}
-
-/**
- *  Find channel by name.
- *
- */
-static struct sdio_channel *find_channel_by_name(const char *name)
-{
-	struct sdio_channel *ch = NULL;
-	int i, j;
-	struct sdio_al_device *sdio_al_dev = NULL;
-
-	for (j = 0; j < MAX_NUM_OF_SDIO_DEVICES; ++j) {
-		if (sdio_al->devices[j] == NULL)
-			continue;
-		sdio_al_dev = sdio_al->devices[j];
-		for (i = 0; i < SDIO_AL_MAX_CHANNELS; i++) {
-			if (sdio_al_dev->channel[i].state ==
-					SDIO_CHANNEL_STATE_INVALID)
-				continue;
-			if (strncmp(sdio_al_dev->channel[i].name, name,
-					CHANNEL_NAME_SIZE) == 0) {
-				ch = &sdio_al_dev->channel[i];
-				break;
-			}
-		}
-		if (ch != NULL)
-			break;
-	}
-
-	return ch;
-}
-
-/**
- *  Find the minimal poll time.
- *
- */
-static int get_min_poll_time_msec(struct sdio_al_device *sdio_sl_dev)
-{
-	int i;
-	int poll_delay_msec = 0x0FFFFFFF;
-
-	for (i = 0; i < SDIO_AL_MAX_CHANNELS; i++)
-		if ((sdio_sl_dev->channel[i].state ==
-					SDIO_CHANNEL_STATE_OPEN) &&
-		(sdio_sl_dev->channel[i].poll_delay_msec > 0) &&
-		(sdio_sl_dev->channel[i].poll_delay_msec < poll_delay_msec))
-			poll_delay_msec =
-				sdio_sl_dev->channel[i].poll_delay_msec;
-
-	if (poll_delay_msec == 0x0FFFFFFF)
-		poll_delay_msec = SDIO_AL_POLL_TIME_NO_STREAMING;
-
-	pr_debug(MODULE_NAME ":poll delay time is %d msec\n", poll_delay_msec);
-
-	return poll_delay_msec;
-}
-
-/**
- *  Open SDIO Channel.
- *
- *  Enable the channel.
- *  Set the channel context.
- *  Trigger reading the mailbox to check available bytes.
- *
- */
-int sdio_open(const char *name, struct sdio_channel **ret_ch, void *priv,
-		 void (*notify)(void *priv, unsigned ch_event))
-{
-	int ret = 0;
-	struct sdio_channel *ch = NULL;
-	struct sdio_al_device *sdio_al_dev = NULL;
-
-	*ret_ch = NULL; /* default */
-
-	ch = find_channel_by_name(name);
-	if (ch == NULL) {
-		sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":Can't find "
-			"channel name %s\n", name);
-		return -EINVAL;
-	}
-
-	sdio_al_dev = ch->sdio_al_dev;
-	if (sdio_al_claim_mutex_and_verify_dev(sdio_al_dev, __func__))
-		return -ENODEV;
-
-	if ((ch->state != SDIO_CHANNEL_STATE_IDLE) &&
-		(ch->state != SDIO_CHANNEL_STATE_CLOSED)) {
-		sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":Wrong ch %s "
-				"state %d\n", name, ch->state);
-		ret = -EPERM;
-		goto exit_err;
-	}
-
-	if (sdio_al_dev->is_err) {
-		SDIO_AL_ERR(__func__);
-		ret = -ENODEV;
-		goto exit_err;
-	}
-
-	ret = sdio_al_wake_up(sdio_al_dev, 1, ch);
-	if (ret)
-		goto exit_err;
-
-	ch->notify = notify;
-	ch->priv = priv;
-
-	/* Note: Set caller returned context before interrupts are enabled */
-	*ret_ch = ch;
-
-	ret = open_channel(ch);
-	if (ret) {
-		sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":sdio_open %s "
-				"err=%d\n", name, -ret);
-		goto exit_err;
-	}
-
-	CLOSE_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ":sdio_open %s "
-							"completed OK\n", name);
-	if (sdio_al_dev->lpm_chan == INVALID_SDIO_CHAN) {
-		if (sdio_al->sdioc_major == PEER_SDIOC_OLD_VERSION_MAJOR) {
-			if (!ch->is_packet_mode) {
-				sdio_al_logi(sdio_al_dev->dev_log, MODULE_NAME
-						":setting channel %s as "
-						"lpm_chan\n", name);
-				sdio_al_dev->lpm_chan = ch->num;
-			}
-		} else {
-			sdio_al_logi(sdio_al_dev->dev_log, MODULE_NAME ": "
-					"setting channel %s as lpm_chan\n",
-					name);
-			sdio_al_dev->lpm_chan = ch->num;
-		}
-	}
-
-exit_err:
-	sdio_al_release_mutex(sdio_al_dev, __func__);
-	return ret;
-}
-EXPORT_SYMBOL(sdio_open);
-
-/**
- *  Request peer operation
- *  note: sanity checks of parameters done by caller
- *        called under bus locked
- */
-static int peer_set_operation(u32 opcode,
-		struct sdio_al_device *sdio_al_dev,
-		struct sdio_channel *ch)
-{
-	int ret;
-	int offset;
-	struct sdio_func *wk_func = NULL;
-	u32 peer_operation;
-	int loop_count = 0;
-
-	if (!sdio_al_dev->card ||
-	    !sdio_al_dev->card->sdio_func[SDIO_AL_WAKEUP_FUNC-1]) {
-		sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
-				": NULL card or wk_func\n");
-		ret = -ENODEV;
-		goto exit;
-	}
-	wk_func = sdio_al_dev->card->sdio_func[SDIO_AL_WAKEUP_FUNC-1];
-
-	/* calculate offset of peer_operation field in sw mailbox struct */
-	offset = offsetof(struct peer_sdioc_sw_mailbox, ch_config) +
-		sizeof(struct peer_sdioc_channel_config) * ch->num +
-		offsetof(struct peer_sdioc_channel_config, peer_operation);
-
-	ret = sdio_al_wake_up(sdio_al_dev, 1, ch);
-	if (ret) {
-		sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":Fail to "
-				"wake up\n");
-		goto exit;
-	}
-	/* request operation from MDM peer */
-	peer_operation = PEER_OPERATION(opcode, PEER_OP_STATE_INIT);
-	ret = sdio_memcpy_toio(ch->func, SDIOC_SW_MAILBOX_ADDR+offset,
-			&peer_operation, sizeof(u32));
-	if (ret) {
-		sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":failed to "
-				"request close operation\n");
-		goto exit;
-	}
-	ret = sdio_al_enable_func_retry(wk_func, "wk_func");
-	if (ret) {
-		sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":Fail to enable"
-				" Func#%d\n", wk_func->num);
-		goto exit;
-	}
-	pr_debug(MODULE_NAME ":%s: wk_func enabled on ch %s\n",
-			__func__, ch->name);
-	/* send "start" operation to MDM */
-	peer_operation = PEER_OPERATION(opcode, PEER_OP_STATE_START);
-	ret  =  sdio_memcpy_toio(ch->func, SDIOC_SW_MAILBOX_ADDR+offset,
-			&peer_operation, sizeof(u32));
-	if (ret) {
-		sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":failed to "
-				"send start close operation\n");
-		goto exit;
-	}
-	ret = sdio_disable_func(wk_func);
-	if (ret) {
-		sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":Fail to "
-				"disable Func#%d\n", wk_func->num);
-		goto exit;
-	}
-	/* poll for peer operation ack */
-	while (peer_operation != 0) {
-		ret  =  sdio_memcpy_fromio(ch->func,
-				&peer_operation,
-				SDIOC_SW_MAILBOX_ADDR+offset,
-				sizeof(u32));
-		if (ret) {
-			sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
-					":failed to request ack on close"
-					" operation, loop_count = %d\n",
-					loop_count);
-			goto exit;
-		}
-		loop_count++;
-		if (loop_count > 10) {
-			sdio_al_logi(sdio_al_dev->dev_log, MODULE_NAME ":%s: "
-					"peer_operation=0x%x wait loop"
-					" %d on ch %s\n", __func__,
-					peer_operation, loop_count, ch->name);
-		}
-	}
-exit:
-	return ret;
-}
-
-static int channel_close(struct sdio_channel *ch, int flush_flag)
-{
-	int ret;
-	struct sdio_al_device *sdio_al_dev = NULL;
-	int flush_len;
-	ulong flush_expires;
-
-	if (!ch) {
-		sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":%s: NULL "
-				"channel\n",  __func__);
-		return -ENODEV;
-	}
-
-	if (!ch->func) {
-		sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":%s: NULL func"
-				" on channel:%d\n", __func__, ch->num);
-		return -ENODEV;
-	}
-
-	sdio_al_dev = ch->sdio_al_dev;
-	if (sdio_al_claim_mutex_and_verify_dev(sdio_al_dev, __func__))
-		return -ENODEV;
-
-	if (!sdio_al_dev->ch_close_supported) {
-		sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":%s: Not "
-			"supported by mdm, ch %s\n",
-			__func__, ch->name);
-		ret = -ENOTSUPP;
-		goto error_exit;
-	}
-
-	if (sdio_al_dev->is_err) {
-		SDIO_AL_ERR(__func__);
-		ret = -ENODEV;
-		goto error_exit;
-	}
-	if (ch->state != SDIO_CHANNEL_STATE_OPEN) {
-		sdio_al_loge(sdio_al_dev->dev_log,
-				MODULE_NAME ":%s: ch %s is not in "
-				"open state (%d)\n",
-				__func__, ch->name, ch->state);
-		ret = -ENODEV;
-		goto error_exit;
-	}
-	ch->state = SDIO_CHANNEL_STATE_CLOSING;
-	ret = peer_set_operation(PEER_OP_CODE_CLOSE, sdio_al_dev, ch);
-	if (ret) {
-		sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":%s: "
-				"peer_set_operation() failed: %d\n",
-				__func__, ret);
-		ret = -ENODEV;
-		goto error_exit;
-	}
-	/* udate poll time for opened channels */
-	if  (ch->poll_delay_msec > 0) {
-		sdio_al_dev->poll_delay_msec =
-			get_min_poll_time_msec(sdio_al_dev);
-	}
-	sdio_al_release_mutex(ch->sdio_al_dev, __func__);
-
-	flush_expires = jiffies +
-		msecs_to_jiffies(SDIO_CLOSE_FLUSH_TIMEOUT_MSEC);
-	/* flush rx packets of the channel */
-	if (flush_flag) {
-		do {
-			while (ch->read_avail > 0) {
-				flush_len = ch->read_avail;
-				ret = sdio_read_internal(ch,
-						sdio_al_dev->rx_flush_buf,
-						flush_len);
-				if (ret) {
-					sdio_al_loge(&sdio_al->gen_log,
-						MODULE_NAME ":%s sdio_read"
-						" failed: %d, ch %s\n",
-						__func__, ret,
-						ch->name);
-					return ret;
-				}
-
-				if (time_after(jiffies, flush_expires) != 0) {
-					sdio_al_loge(&sdio_al->gen_log,
-						MODULE_NAME ":%s flush rx "
-						"packets timeout: ch %s\n",
-						__func__, ch->name);
-					sdio_al_get_into_err_state(sdio_al_dev);
-					return -EBUSY;
-				}
-			}
-			msleep(100);
-			if (ch->signature != SDIO_AL_SIGNATURE) {
-					sdio_al_loge(&sdio_al->gen_log,
-						MODULE_NAME ":%s: after sleep,"
-						" invalid signature"
-						" 0x%x\n", __func__,
-						ch->signature);
-				return -ENODEV;
-			}
-			if (sdio_al_claim_mutex_and_verify_dev(ch->sdio_al_dev,
-							       __func__))
-				return -ENODEV;
-
-			ret = read_mailbox(sdio_al_dev, false);
-			if (ret) {
-				sdio_al_loge(&sdio_al->gen_log,
-						MODULE_NAME ":%s: failed to"
-						" read mailbox", __func__);
-				goto error_exit;
-			}
-			sdio_al_release_mutex(ch->sdio_al_dev, __func__);
-		} while (ch->read_avail > 0);
-	}
-	if (sdio_al_claim_mutex_and_verify_dev(ch->sdio_al_dev,
-					       __func__))
-		return -ENODEV;
-	/* disable function to be able to open the channel again */
-	ret = sdio_disable_func(ch->func);
-	if (ret) {
-		sdio_al_loge(&sdio_al->gen_log,
-			MODULE_NAME ":Fail to disable Func#%d\n",
-			ch->func->num);
-		goto error_exit;
-	}
-	ch->state = SDIO_CHANNEL_STATE_CLOSED;
-	CLOSE_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ":%s: Ch %s closed "
-				"successfully\n", __func__, ch->name);
-
-error_exit:
-	sdio_al_release_mutex(ch->sdio_al_dev, __func__);
-
-	return ret;
-}
-
-/**
- *  Close SDIO Channel.
- *
- */
-int sdio_close(struct sdio_channel *ch)
-{
-	return channel_close(ch, true);
-}
-EXPORT_SYMBOL(sdio_close);
-
-/**
- *  Get the number of available bytes to write.
- *
- */
-int sdio_write_avail(struct sdio_channel *ch)
-{
-	if (!ch) {
-		sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":%s: NULL "
-				"channel\n", __func__);
-		return -ENODEV;
-	}
-	if (ch->signature != SDIO_AL_SIGNATURE) {
-		sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":%s: "
-				"Invalid signature 0x%x\n",  __func__,
-				ch->signature);
-		return -ENODEV;
-	}
-	if (ch->state != SDIO_CHANNEL_STATE_OPEN) {
-		sdio_al_loge(ch->sdio_al_dev->dev_log, MODULE_NAME ":%s: "
-				"channel %s state is not open (%d)\n",
-				__func__, ch->name, ch->state);
-		return -ENODEV;
-	}
-	pr_debug(MODULE_NAME ":sdio_write_avail %s 0x%x\n",
-			 ch->name, ch->write_avail);
-
-	return ch->write_avail;
-}
-EXPORT_SYMBOL(sdio_write_avail);
-
-/**
- *  Get the number of available bytes to read.
- *
- */
-int sdio_read_avail(struct sdio_channel *ch)
-{
-	if (!ch) {
-		sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":%s: NULL "
-				"channel\n", __func__);
-		return -ENODEV;
-	}
-	if (ch->signature != SDIO_AL_SIGNATURE) {
-		sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":%s: "
-				"Invalid signature 0x%x\n",  __func__,
-				ch->signature);
-		return -ENODEV;
-	}
-	if (ch->state != SDIO_CHANNEL_STATE_OPEN) {
-		sdio_al_loge(ch->sdio_al_dev->dev_log, MODULE_NAME ":%s: "
-				"channel %s state is not open (%d)\n",
-				__func__, ch->name, ch->state);
-		return -ENODEV;
-	}
-	pr_debug(MODULE_NAME ":sdio_read_avail %s 0x%x\n",
-			 ch->name, ch->read_avail);
-
-	return ch->read_avail;
-}
-EXPORT_SYMBOL(sdio_read_avail);
-
-static int sdio_read_from_closed_ch(struct sdio_channel *ch, int len)
-{
-	int ret = 0;
-	struct sdio_al_device *sdio_al_dev = NULL;
-
-	if (!ch) {
-		sdio_al_loge(ch->sdio_al_dev->dev_log,
-			MODULE_NAME ":%s: NULL channel\n",  __func__);
-		return -ENODEV;
-	}
-
-	sdio_al_dev = ch->sdio_al_dev;
-	if (sdio_al_claim_mutex_and_verify_dev(sdio_al_dev, __func__))
-		return -ENODEV;
-
-	ret = sdio_memcpy_fromio(ch->func, sdio_al_dev->rx_flush_buf,
-				 PIPE_RX_FIFO_ADDR, len);
-
-	if (ret) {
-		sdio_al_loge(ch->sdio_al_dev->dev_log,
-				MODULE_NAME ":ch %s: %s err=%d, len=%d\n",
-				ch->name, __func__, -ret, len);
-		sdio_al_dev->is_err = true;
-		sdio_al_release_mutex(sdio_al_dev, __func__);
-		return ret;
-	}
-
-	restart_inactive_time(sdio_al_dev);
-
-	sdio_al_release_mutex(sdio_al_dev, __func__);
-
-	return 0;
-}
-
-/**
- *  Internal read from SDIO Channel.
- *
- *  Reading from the pipe will trigger interrupt if there are
- *  other pending packets on the SDIO-Client.
- *
- */
-static int sdio_read_internal(struct sdio_channel *ch, void *data, int len)
-{
-	int ret = 0;
-	struct sdio_al_device *sdio_al_dev = NULL;
-
-	if (!ch) {
-		sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":%s: NULL "
-				"channel\n",  __func__);
-		return -ENODEV;
-	}
-	if (!data) {
-		sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":%s: NULL data\n",
-				__func__);
-		return -ENODEV;
-	}
-	if (len == 0) {
-		sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":channel %s trying"
-				" to read 0 bytes\n", ch->name);
-		return -EINVAL;
-	}
-
-	if (ch->signature != SDIO_AL_SIGNATURE) {
-		sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":%s: Invalid "
-				"signature 0x%x\n",  __func__, ch->signature);
-		return -ENODEV;
-	}
-
-	sdio_al_dev = ch->sdio_al_dev;
-	if (sdio_al_claim_mutex_and_verify_dev(sdio_al_dev, __func__))
-		return -ENODEV;
-
-	if (sdio_al_dev->is_err) {
-		SDIO_AL_ERR(__func__);
-		ret = -ENODEV;
-		goto exit;
-	}
-
-	/* lpm policy says we can't go to sleep when we have pending rx data,
-	   so either we had rx interrupt and woken up, or we never went to
-	   sleep */
-	if (sdio_al_dev->is_ok_to_sleep) {
-		sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":%s: called "
-				"when is_ok_to_sleep is set for ch %s, len=%d,"
-				" last_any_read_avail=%d, last_read_avail=%d, "
-				"last_old_read_avail=%d", __func__, ch->name,
-				len, ch->statistics.last_any_read_avail,
-				ch->statistics.last_read_avail,
-				ch->statistics.last_old_read_avail);
-	}
-	BUG_ON(sdio_al_dev->is_ok_to_sleep);
-
-	if ((ch->state != SDIO_CHANNEL_STATE_OPEN) &&
-			(ch->state != SDIO_CHANNEL_STATE_CLOSING)) {
-		sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":%s wrong "
-				"channel %s state %d\n",
-				__func__, ch->name, ch->state);
-		ret = -EINVAL;
-		goto exit;
-	}
-
-	DATA_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ":start ch %s read %d "
-			"avail %d.\n", ch->name, len, ch->read_avail);
-
-	restart_inactive_time(sdio_al_dev);
-
-	if ((ch->is_packet_mode) && (len != ch->read_avail)) {
-		sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":sdio_read ch "
-				"%s len != read_avail\n", ch->name);
-		ret = -EINVAL;
-		goto exit;
-	}
-
-	if (len > ch->read_avail) {
-		sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":ERR ch %s: "
-				"reading more bytes (%d) than the avail(%d).\n",
-				ch->name, len, ch->read_avail);
-		ret = -ENOMEM;
-		goto exit;
-	}
-
-	ret = sdio_memcpy_fromio(ch->func, data, PIPE_RX_FIFO_ADDR, len);
-
-	if (ret) {
-		sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":ch %s: "
-				"sdio_read err=%d, len=%d, read_avail=%d, "
-				"last_read_avail=%d, last_old_read_avail=%d\n",
-				ch->name, -ret, len, ch->read_avail,
-				ch->statistics.last_read_avail,
-				ch->statistics.last_old_read_avail);
-		sdio_al_get_into_err_state(sdio_al_dev);
-		goto exit;
-	}
-
-	ch->statistics.total_read_times++;
-
-	/* Remove handled packet from the list regardless if ret is ok */
-	if (ch->is_packet_mode)
-		remove_handled_rx_packet(ch);
-	else
-		ch->read_avail -= len;
-
-	ch->total_rx_bytes += len;
-	DATA_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ":end ch %s read %d "
-			"avail %d total %d.\n", ch->name, len,
-			ch->read_avail, ch->total_rx_bytes);
-
-	if ((ch->read_avail == 0) && !(ch->is_packet_mode))
-		ask_reading_mailbox(sdio_al_dev);
-
-exit:
-	sdio_al_release_mutex(sdio_al_dev, __func__);
-
-	return ret;
-}
-
-/**
- *  Read from SDIO Channel.
- *
- *  Reading from the pipe will trigger interrupt if there are
- *  other pending packets on the SDIO-Client.
- *
- */
-int sdio_read(struct sdio_channel *ch, void *data, int len)
-{
-	if (!ch) {
-		sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":%s: NULL "
-				"channel\n", __func__);
-		return -ENODEV;
-	}
-	if (ch->signature != SDIO_AL_SIGNATURE) {
-		sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":%s: "
-			"Invalid signature 0x%x\n",  __func__, ch->signature);
-		return -ENODEV;
-	}
-	if (ch->state == SDIO_CHANNEL_STATE_OPEN) {
-		return sdio_read_internal(ch, data, len);
-	} else {
-		sdio_al_loge(ch->sdio_al_dev->dev_log, MODULE_NAME
-				":%s: Invalid channel %s state %d\n",
-				__func__, ch->name, ch->state);
-	}
-	return -ENODEV;
-}
-EXPORT_SYMBOL(sdio_read);
-
-/**
- *  Write to SDIO Channel.
- *
- */
-int sdio_write(struct sdio_channel *ch, const void *data, int len)
-{
-	int ret = 0;
-	struct sdio_al_device *sdio_al_dev = NULL;
-
-	if (!ch) {
-		sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":%s: NULL "
-				"channel\n",  __func__);
-		return -ENODEV;
-	}
-	if (!data) {
-		sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":%s: NULL data\n",
-				__func__);
-		return -ENODEV;
-	}
-	if (len == 0) {
-		sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":channel %s trying"
-				" to write 0 bytes\n", ch->name);
-		return -EINVAL;
-	}
-
-	if (ch->signature != SDIO_AL_SIGNATURE) {
-		sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":%s: Invalid "
-				"signature 0x%x\n",  __func__, ch->signature);
-		return -ENODEV;
-	}
-
-	sdio_al_dev = ch->sdio_al_dev;
-	if (sdio_al_claim_mutex_and_verify_dev(sdio_al_dev, __func__))
-		return -ENODEV;
-
-	WARN_ON(len > ch->write_avail);
-
-	if (sdio_al_dev->is_err) {
-		SDIO_AL_ERR(__func__);
-		ret = -ENODEV;
-		goto exit;
-	}
-
-	if (ch->state != SDIO_CHANNEL_STATE_OPEN) {
-		sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":writing to "
-				"closed channel %s\n", ch->name);
-		ret = -EINVAL;
-		goto exit;
-	}
-
-	if (sdio_al_dev->is_ok_to_sleep) {
-		ret = sdio_al_wake_up(sdio_al_dev, 1, ch);
-		if (ret)
-			goto exit;
-	} else {
-		restart_inactive_time(sdio_al_dev);
-	}
-
-	DATA_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ":start ch %s write %d "
-			"avail %d.\n", ch->name, len, ch->write_avail);
-
-	if (len > ch->write_avail) {
-		sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":ERR ch %s: "
-				"write more bytes (%d) than  available %d.\n",
-				ch->name, len, ch->write_avail);
-		ret = -ENOMEM;
-		goto exit;
-	}
-
-	ret = sdio_ch_write(ch, data, len);
-	if (ret) {
-		sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":sdio_write "
-				"on channel %s err=%d\n", ch->name, -ret);
-		goto exit;
-	}
-
-	ch->total_tx_bytes += len;
-	DATA_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ":end ch %s write %d "
-			"avail %d total %d.\n", ch->name, len,
-			ch->write_avail, ch->total_tx_bytes);
-
-	/* Round up to whole buffer size */
-	len = ROUND_UP(len, ch->peer_tx_buf_size);
-	/* Protect from wraparound */
-	len = min(len, (int) ch->write_avail);
-	ch->write_avail -= len;
-
-	if (ch->write_avail < ch->min_write_avail)
-		ask_reading_mailbox(sdio_al_dev);
-
-exit:
-	sdio_al_release_mutex(sdio_al_dev, __func__);
-
-	return ret;
-}
-EXPORT_SYMBOL(sdio_write);
-
-static int __devinit msm_sdio_al_probe(struct platform_device *pdev)
-{
-	if (!sdio_al) {
-		pr_err(MODULE_NAME ": %s: NULL sdio_al\n", __func__);
-		return -ENODEV;
-	}
-
-	sdio_al->pdata = pdev->dev.platform_data;
-	return 0;
-}
-
-static int __devexit msm_sdio_al_remove(struct platform_device *pdev)
-{
-	return 0;
-}
-
-static void sdio_al_close_all_channels(struct sdio_al_device *sdio_al_dev)
-{
-	int j;
-	int ret;
-	struct sdio_channel *ch = NULL;
-
-	sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ": %s", __func__);
-
-	if (!sdio_al_dev) {
-		sdio_al_loge(sdio_al_dev->dev_log,
-			MODULE_NAME ": %s: NULL device", __func__);
-		return;
-	}
-	for (j = 0; j < SDIO_AL_MAX_CHANNELS; j++) {
-		ch = &sdio_al_dev->channel[j];
-
-		if (ch->state == SDIO_CHANNEL_STATE_OPEN) {
-			sdio_al_loge(sdio_al_dev->dev_log,
-				MODULE_NAME ": %s: Call to sdio_close() for"
-				" ch %s\n", __func__, ch->name);
-			ret = channel_close(ch, false);
-			if (ret) {
-				sdio_al_loge(sdio_al_dev->dev_log,
-					MODULE_NAME ": %s: failed sdio_close()"
-					" for ch %s (%d)\n",
-					__func__, ch->name, ret);
-			}
-		} else {
-			pr_debug(MODULE_NAME ": %s: skip sdio_close() ch %s"
-					" (state=%d)\n", __func__,
-					ch->name, ch->state);
-		}
-	}
-}
-
-static void sdio_al_invalidate_sdio_clients(struct sdio_al_device *sdio_al_dev,
-					    struct platform_device **pdev_arr)
-{
-	int j;
-
-	pr_debug(MODULE_NAME ": %s: Notifying SDIO clients for card %d",
-			__func__, sdio_al_dev->host->index);
-	for (j = 0; j < SDIO_AL_MAX_CHANNELS; ++j) {
-		if (sdio_al_dev->channel[j].state ==
-			SDIO_CHANNEL_STATE_INVALID)
-			continue;
-		pdev_arr[j] = sdio_al_dev->channel[j].pdev;
-		sdio_al_dev->channel[j].signature = 0x0;
-		sdio_al_dev->channel[j].state =
-			SDIO_CHANNEL_STATE_INVALID;
-	}
-}
-
-static void sdio_al_modem_reset_operations(struct sdio_al_device
-							*sdio_al_dev)
-{
-	int ret = 0;
-	struct platform_device *pdev_arr[SDIO_AL_MAX_CHANNELS];
-	int j;
-
-	sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ": %s", __func__);
-
-	if (sdio_al_claim_mutex_and_verify_dev(sdio_al_dev, __func__))
-		return;
-
-	if (sdio_al_dev->state == CARD_REMOVED) {
-		sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ": %s: "
-			"card %d is already removed", __func__,
-			sdio_al_dev->host->index);
-		goto exit_err;
-	}
-
-	if (sdio_al_dev->state == MODEM_RESTART) {
-		sdio_al_logi(sdio_al_dev->dev_log, MODULE_NAME ": %s: "
-			"card %d was already notified for modem reset",
-			__func__, sdio_al_dev->host->index);
-		goto exit_err;
-	}
-
-	sdio_al_logi(sdio_al_dev->dev_log, MODULE_NAME ": %s: Set the "
-		"state to MODEM_RESTART for card %d",
-		__func__, sdio_al_dev->host->index);
-	sdio_al_dev->state = MODEM_RESTART;
-	sdio_al_dev->is_ready = false;
-
-	/* Stop mailbox timer */
-	stop_and_del_timer(sdio_al_dev);
-
-	if ((sdio_al_dev->is_ok_to_sleep) &&
-	    (!sdio_al_dev->is_err)) {
-		pr_debug(MODULE_NAME ": %s: wakeup modem for "
-				    "card %d", __func__,
-			sdio_al_dev->host->index);
-		ret = sdio_al_wake_up(sdio_al_dev, 1, NULL);
-	}
-
-	if (!ret && (!sdio_al_dev->is_err) && sdio_al_dev->card &&
-		sdio_al_dev->card->sdio_func[0]) {
-			sdio_al_logi(sdio_al_dev->dev_log, MODULE_NAME
-			": %s: sdio_release_irq for card %d",
-			__func__,
-			sdio_al_dev->host->index);
-			sdio_release_irq(sdio_al_dev->card->sdio_func[0]);
-	}
-
-	memset(pdev_arr, 0, sizeof(pdev_arr));
-	sdio_al_invalidate_sdio_clients(sdio_al_dev, pdev_arr);
-
-	sdio_al_release_mutex(sdio_al_dev, __func__);
-
-	sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ": %s: Notifying SDIO "
-						    "clients for card %d",
-			__func__, sdio_al_dev->host->index);
-	for (j = 0; j < SDIO_AL_MAX_CHANNELS; j++) {
-		if (!pdev_arr[j])
-			continue;
-		platform_device_unregister(pdev_arr[j]);
-	}
-	sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ": %s: Finished Notifying "
-						    "SDIO clients for card %d",
-			__func__, sdio_al_dev->host->index);
-
-	return;
-
-exit_err:
-	sdio_al_release_mutex(sdio_al_dev, __func__);
-	return;
-}
-
-#ifdef CONFIG_MSM_SUBSYSTEM_RESTART
-static void sdio_al_reset(void)
-{
-	int i;
-	struct sdio_al_device *sdio_al_dev;
-
-	sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ": %s", __func__);
-
-	for (i = 0; i < MAX_NUM_OF_SDIO_DEVICES; i++) {
-		if (sdio_al->devices[i] == NULL) {
-			pr_debug(MODULE_NAME ": %s: NULL device in index %d",
-					__func__, i);
-			continue;
-		}
-		sdio_al_dev = sdio_al->devices[i];
-		sdio_al_modem_reset_operations(sdio_al->devices[i]);
-	}
-
-	sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ": %s completed", __func__);
-}
-#endif
-
-static void msm_sdio_al_shutdown(struct platform_device *pdev)
-{
-	int i;
-	struct sdio_al_device *sdio_al_dev;
-
-	sdio_al_logi(&sdio_al->gen_log, MODULE_NAME
-			"Initiating msm_sdio_al_shutdown...");
-
-	for (i = 0; i < MAX_NUM_OF_SDIO_DEVICES; i++) {
-		if (sdio_al->devices[i] == NULL) {
-			pr_debug(MODULE_NAME ": %s: NULL device in index %d",
-					__func__, i);
-			continue;
-		}
-		sdio_al_dev = sdio_al->devices[i];
-
-		if (sdio_al_claim_mutex_and_verify_dev(sdio_al_dev, __func__))
-			return;
-
-		if (sdio_al_dev->ch_close_supported)
-			sdio_al_close_all_channels(sdio_al_dev);
-
-		sdio_al_release_mutex(sdio_al_dev, __func__);
-
-		sdio_al_modem_reset_operations(sdio_al_dev);
-	}
-	sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ": %s: "
-		"msm_sdio_al_shutdown complete.", __func__);
-}
-
-static struct platform_driver msm_sdio_al_driver = {
-	.probe          = msm_sdio_al_probe,
-	.remove         = __exit_p(msm_sdio_al_remove),
-	.shutdown	= msm_sdio_al_shutdown,
-	.driver         = {
-		.name   = "msm_sdio_al",
-	},
-};
-
-/**
- *  Initialize SDIO_AL channels.
- *
- */
-static int init_channels(struct sdio_al_device *sdio_al_dev)
-{
-	int ret = 0;
-	int i;
-
-	if (sdio_al_claim_mutex_and_verify_dev(sdio_al_dev, __func__))
-		return -ENODEV;
-
-	ret = read_sdioc_software_header(sdio_al_dev,
-					 sdio_al_dev->sdioc_sw_header);
-	if (ret)
-		goto exit;
-
-	ret = sdio_al_setup(sdio_al_dev);
-	if (ret)
-		goto exit;
-
-	for (i = 0; i < SDIO_AL_MAX_CHANNELS; i++) {
-		int ch_name_size;
-		if (sdio_al_dev->channel[i].state == SDIO_CHANNEL_STATE_INVALID)
-			continue;
-		if (sdio_al->unittest_mode) {
-			memset(sdio_al_dev->channel[i].ch_test_name, 0,
-				sizeof(sdio_al_dev->channel[i].ch_test_name));
-			ch_name_size = strnlen(sdio_al_dev->channel[i].name,
-				       CHANNEL_NAME_SIZE);
-			strncpy(sdio_al_dev->channel[i].ch_test_name,
-			       sdio_al_dev->channel[i].name,
-			       ch_name_size);
-			strncat(sdio_al_dev->channel[i].ch_test_name +
-			       ch_name_size,
-			       SDIO_TEST_POSTFIX,
-			       SDIO_TEST_POSTFIX_SIZE);
-			pr_debug(MODULE_NAME ":pdev.name = %s\n",
-				sdio_al_dev->channel[i].ch_test_name);
-			sdio_al_dev->channel[i].pdev = platform_device_alloc(
-				sdio_al_dev->channel[i].ch_test_name, -1);
-		} else {
-			pr_debug(MODULE_NAME ":pdev.name = %s\n",
-				sdio_al_dev->channel[i].name);
-			sdio_al_dev->channel[i].pdev = platform_device_alloc(
-				sdio_al_dev->channel[i].name, -1);
-		}
-		if (!sdio_al_dev->channel[i].pdev) {
-			sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
-					":NULL platform device for ch %s",
-					sdio_al_dev->channel[i].name);
-			sdio_al_dev->channel[i].state =
-				SDIO_CHANNEL_STATE_INVALID;
-			continue;
-		}
-		ret = platform_device_add(sdio_al_dev->channel[i].pdev);
-		if (ret) {
-			sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
-					":platform_device_add failed, "
-					"ret=%d\n", ret);
-			sdio_al_dev->channel[i].state =
-				SDIO_CHANNEL_STATE_INVALID;
-		}
-	}
-
-exit:
-	sdio_al_release_mutex(sdio_al_dev, __func__);
-	return ret;
-}
-
-/**
- *  Initialize SDIO_AL channels according to the client setup.
- *  This function also check if the client is in boot mode and
- *  flashless boot is required to be activated or the client is
- *  up and running.
- *
- */
-static int sdio_al_client_setup(struct sdio_al_device *sdio_al_dev)
-{
-	int ret = 0;
-	struct sdio_func *func1;
-	int signature = 0;
-
-	if (sdio_al_claim_mutex_and_verify_dev(sdio_al_dev, __func__))
-		return -ENODEV;
-
-	if (!sdio_al_dev->card || !sdio_al_dev->card->sdio_func[0]) {
-		sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":NULL card or "
-							       "func1\n");
-		sdio_al_release_mutex(sdio_al_dev, __func__);
-		return -ENODEV;
-	}
-	func1 = sdio_al_dev->card->sdio_func[0];
-
-	/* Read the header signature to determine the status of the MDM
-	 * SDIO Client
-	 */
-	signature = sdio_readl(func1, SDIOC_SW_HEADER_ADDR, &ret);
-	sdio_al_release_mutex(sdio_al_dev, __func__);
-	if (ret) {
-		sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":fail to read "
-				"signature from sw header.\n");
-		return ret;
-	}
-
-	switch (signature) {
-	case PEER_SDIOC_SW_MAILBOX_BOOT_SIGNATURE:
-		if (sdio_al_dev == sdio_al->bootloader_dev) {
-			sdio_al_logi(sdio_al_dev->dev_log, MODULE_NAME ":setup "
-					"bootloader on card %d\n",
-					sdio_al_dev->host->index);
-			return sdio_al_bootloader_setup();
-		} else {
-			sdio_al_logi(sdio_al_dev->dev_log, MODULE_NAME ":wait "
-					"for bootloader completion "
-					"on card %d\n",
-					sdio_al_dev->host->index);
-			return sdio_al_wait_for_bootloader_comp(sdio_al_dev);
-		}
-	case PEER_SDIOC_SW_MAILBOX_SIGNATURE:
-	case PEER_SDIOC_SW_MAILBOX_UT_SIGNATURE:
-		return init_channels(sdio_al_dev);
-	default:
-		sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":Invalid "
-				"signature 0x%x\n", signature);
-		return -EINVAL;
-	}
-
-	return 0;
-}
-
-static void clean_sdio_al_device_data(struct sdio_al_device *sdio_al_dev)
-{
-	sdio_al_dev->is_ready = 0;
-	sdio_al_dev->bootloader_done = 0;
-	sdio_al_dev->lpm_chan = 0;
-	sdio_al_dev->is_ok_to_sleep = 0;
-	sdio_al_dev->inactivity_time = 0;
-	sdio_al_dev->poll_delay_msec = 0;
-	sdio_al_dev->is_timer_initialized = 0;
-	sdio_al_dev->is_err = 0;
-	sdio_al_dev->is_suspended = 0;
-	sdio_al_dev->flashless_boot_on = 0;
-	sdio_al_dev->ch_close_supported = 0;
-	sdio_al_dev->print_after_interrupt = 0;
-	memset(sdio_al_dev->sdioc_sw_header, 0,
-	       sizeof(*sdio_al_dev->sdioc_sw_header));
-	memset(sdio_al_dev->mailbox, 0, sizeof(*sdio_al_dev->mailbox));
-	memset(sdio_al_dev->rx_flush_buf, 0,
-	       sizeof(*sdio_al_dev->rx_flush_buf));
-}
-
-/*
- * SDIO driver functions
- */
-static int sdio_al_sdio_probe(struct sdio_func *func,
-		const struct sdio_device_id *sdio_dev_id)
-{
-	int ret = 0;
-	struct sdio_al_device *sdio_al_dev = NULL;
-	int i;
-	struct mmc_card *card = NULL;
-
-	if (!func) {
-		sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s: NULL func\n",
-				__func__);
-		return -ENODEV;
-	}
-	card = func->card;
-
-	if (!card) {
-		sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s: NULL card\n",
-				__func__);
-		return -ENODEV;
-	}
-
-	if (!card->sdio_func[0]) {
-		sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s: NULL "
-							    "func1\n",
-				__func__);
-		return -ENODEV;
-	}
-
-	if (card->sdio_funcs < SDIO_AL_MAX_FUNCS) {
-		dev_info(&card->dev,
-			 "SDIO-functions# %d less than expected.\n",
-			 card->sdio_funcs);
-		return -ENODEV;
-	}
-
-	/* Check if there is already a device for this card */
-	for (i = 0; i < MAX_NUM_OF_SDIO_DEVICES; ++i) {
-		if (sdio_al->devices[i] == NULL)
-			continue;
-		if (sdio_al->devices[i]->host == card->host) {
-			sdio_al_dev = sdio_al->devices[i];
-			if (sdio_al_dev->state == CARD_INSERTED)
-				return 0;
-			clean_sdio_al_device_data(sdio_al_dev);
-			break;
-		}
-	}
-
-	if (!sdio_al_dev) {
-		sdio_al_dev = kzalloc(sizeof(struct sdio_al_device),
-				      GFP_KERNEL);
-		if (sdio_al_dev == NULL)
-			return -ENOMEM;
-
-		for (i = 0; i < MAX_NUM_OF_SDIO_DEVICES ; ++i)
-			if (sdio_al->devices[i] == NULL) {
-				sdio_al->devices[i] = sdio_al_dev;
-				sdio_al_dev->dev_log = &sdio_al->device_log[i];
-				spin_lock_init(&sdio_al_dev->dev_log->log_lock);
-	#ifdef CONFIG_DEBUG_FS
-				sdio_al_dbgfs_log[i].data =
-						sdio_al_dev->dev_log->buffer;
-				sdio_al_dbgfs_log[i].size =
-					SDIO_AL_DEBUG_LOG_SIZE;
-	#endif
-				break;
-			}
-		if (i == MAX_NUM_OF_SDIO_DEVICES) {
-			sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":No space "
-					"in devices array for the device\n");
-			return -ENOMEM;
-		}
-	}
-
-	dev_info(&card->dev, "SDIO Card claimed.\n");
-	sdio_al->skip_print_info = 0;
-
-	sdio_al_dev->state = CARD_INSERTED;
-
-	if (card->host->index == SDIO_BOOTLOADER_CARD_INDEX)
-		sdio_al->bootloader_dev = sdio_al_dev;
-
-	sdio_al_dev->is_ready = false;
-
-	sdio_al_dev->signature = SDIO_AL_SIGNATURE;
-
-	sdio_al_dev->is_suspended = 0;
-	sdio_al_dev->is_timer_initialized = false;
-
-	sdio_al_dev->lpm_chan = INVALID_SDIO_CHAN;
-
-	sdio_al_dev->card = card;
-	sdio_al_dev->host = card->host;
-
-	if (!sdio_al_dev->mailbox) {
-		sdio_al_dev->mailbox = kzalloc(sizeof(struct sdio_mailbox),
-					       GFP_KERNEL);
-		if (sdio_al_dev->mailbox == NULL)
-			return -ENOMEM;
-	}
-
-	if (!sdio_al_dev->sdioc_sw_header) {
-		sdio_al_dev->sdioc_sw_header
-			= kzalloc(sizeof(*sdio_al_dev->sdioc_sw_header),
-				  GFP_KERNEL);
-		if (sdio_al_dev->sdioc_sw_header == NULL)
-			return -ENOMEM;
-	}
-
-	if (!sdio_al_dev->rx_flush_buf) {
-		sdio_al_dev->rx_flush_buf = kzalloc(RX_FLUSH_BUFFER_SIZE,
-						    GFP_KERNEL);
-		if (sdio_al_dev->rx_flush_buf == NULL) {
-			sdio_al_loge(&sdio_al->gen_log,
-					MODULE_NAME ":Fail to allocate "
-					   "rx_flush_buf for card %d\n",
-			       card->host->index);
-			return -ENOMEM;
-		}
-	}
-
-	sdio_al_dev->timer.data = (unsigned long)sdio_al_dev;
-
-	wake_lock_init(&sdio_al_dev->wake_lock, WAKE_LOCK_SUSPEND, MODULE_NAME);
-	/* Don't allow sleep until all required clients register */
-	sdio_al_vote_for_sleep(sdio_al_dev, 0);
-
-	if (sdio_al_claim_mutex_and_verify_dev(sdio_al_dev, __func__))
-		return -ENODEV;
-
-	/* Init Func#1 */
-	ret = sdio_al_enable_func_retry(card->sdio_func[0], "Init Func#1");
-	if (ret) {
-		sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":Fail to "
-				"enable Func#%d\n", card->sdio_func[0]->num);
-		goto exit;
-	}
-
-	/* Patch Func CIS tuple issue */
-	ret = sdio_set_block_size(card->sdio_func[0], SDIO_AL_BLOCK_SIZE);
-	if (ret) {
-		sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":Fail to set "
-			"block size, Func#%d\n", card->sdio_func[0]->num);
-		goto exit;
-	}
-	sdio_al_dev->card->sdio_func[0]->max_blksize = SDIO_AL_BLOCK_SIZE;
-
-	sdio_al_dev->workqueue = create_singlethread_workqueue("sdio_al_wq");
-	sdio_al_dev->sdio_al_work.sdio_al_dev = sdio_al_dev;
-	init_waitqueue_head(&sdio_al_dev->wait_mbox);
-
-	ret = sdio_al_client_setup(sdio_al_dev);
-
-exit:
-	sdio_al_release_mutex(sdio_al_dev, __func__);
-	return ret;
-}
-
-static void sdio_al_sdio_remove(struct sdio_func *func)
-{
-	struct sdio_al_device *sdio_al_dev = NULL;
-	int i;
-	struct mmc_card *card = NULL;
-	struct platform_device *pdev_arr[SDIO_AL_MAX_CHANNELS];
-
-	if (!func) {
-		sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s: NULL func\n",
-				__func__);
-		return;
-	}
-	card = func->card;
-
-	if (!card) {
-		sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s: NULL card\n",
-				__func__);
-		return;
-	}
-
-	/* Find the sdio_al_device of this card */
-	for (i = 0; i < MAX_NUM_OF_SDIO_DEVICES; ++i) {
-		if (sdio_al->devices[i] == NULL)
-			continue;
-		if (sdio_al->devices[i]->card == card) {
-			sdio_al_dev = sdio_al->devices[i];
-			break;
-		}
-	}
-	if (sdio_al_dev == NULL) {
-		pr_debug(MODULE_NAME ":%s :NULL sdio_al_dev for card %d\n",
-				 __func__, card->host->index);
-		return;
-	}
-
-	if (sdio_al_claim_mutex(sdio_al_dev, __func__))
-		return;
-
-	if (sdio_al_dev->state == CARD_REMOVED) {
-		sdio_al_release_mutex(sdio_al_dev, __func__);
-		return;
-	}
-
-	if (!card->sdio_func[0]) {
-		sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s: NULL "
-						"func1\n", __func__);
-		sdio_al_release_mutex(sdio_al_dev, __func__);
-		return;
-	}
-
-	sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ":%s for card %d\n",
-			 __func__, card->host->index);
-
-	sdio_al_dev->state = CARD_REMOVED;
-
-	memset(pdev_arr, 0, sizeof(pdev_arr));
-	sdio_al_invalidate_sdio_clients(sdio_al_dev, pdev_arr);
-
-	sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ":%s: ask_reading_mailbox "
-			"for card %d\n", __func__, card->host->index);
-	sdio_al_dev->is_ready = false; /* Flag worker to exit */
-	sdio_al_dev->ask_mbox = false;
-	ask_reading_mailbox(sdio_al_dev); /* Wakeup worker */
-
-	stop_and_del_timer(sdio_al_dev);
-
-	sdio_al_release_mutex(sdio_al_dev, __func__);
-
-	sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ": %s: Notifying SDIO "
-						    "clients for card %d",
-			__func__, sdio_al_dev->host->index);
-	for (i = 0; i < SDIO_AL_MAX_CHANNELS; i++) {
-		if (!pdev_arr[i])
-			continue;
-		platform_device_unregister(pdev_arr[i]);
-	}
-	sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ": %s: Finished Notifying "
-						    "SDIO clients for card %d",
-			__func__, sdio_al_dev->host->index);
-
-	sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ":%s: vote for sleep for "
-			"card %d\n", __func__, card->host->index);
-	sdio_al_vote_for_sleep(sdio_al_dev, 1);
-
-	sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ":%s: flush_workqueue for "
-			"card %d\n", __func__, card->host->index);
-	flush_workqueue(sdio_al_dev->workqueue);
-	destroy_workqueue(sdio_al_dev->workqueue);
-	wake_lock_destroy(&sdio_al_dev->wake_lock);
-
-	sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ":%s: sdio card %d removed."
-			"\n", __func__,	card->host->index);
-}
-
-static void sdio_print_mailbox(char *prefix_str, struct sdio_mailbox *mailbox)
-{
-	int k = 0;
-	char buf[256];
-	char buf1[10];
-
-	if (!mailbox) {
-		sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": mailbox is "
-				"NULL\n");
-		return;
-	}
-
-	sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s: pipes 0_7: eot=0x%x,"
-		" thresh=0x%x, overflow=0x%x, "
-		"underflow=0x%x, mask_thresh=0x%x\n",
-		 prefix_str, mailbox->eot_pipe_0_7,
-		 mailbox->thresh_above_limit_pipe_0_7,
-		 mailbox->overflow_pipe_0_7,
-		 mailbox->underflow_pipe_0_7,
-		 mailbox->mask_thresh_above_limit_pipe_0_7);
-
-	memset(buf, 0, sizeof(buf));
-	strncat(buf, ": bytes_avail:", sizeof(buf));
-
-	for (k = 0 ; k < SDIO_AL_ACTIVE_PIPES ; ++k) {
-		snprintf(buf1, sizeof(buf1), "%d, ",
-			 mailbox->pipe_bytes_avail[k]);
-		strncat(buf, buf1, sizeof(buf));
-	}
-
-	sdio_al_loge(&sdio_al->gen_log, MODULE_NAME "%s", buf);
-}
-
-static void sdio_al_print_info(void)
-{
-	int i = 0;
-	int j = 0;
-	int ret = 0;
-	struct sdio_mailbox *mailbox = NULL;
-	struct sdio_mailbox *hw_mailbox = NULL;
-	struct peer_sdioc_channel_config *ch_config = NULL;
-	struct sdio_func *func1 = NULL;
-	struct sdio_func *lpm_func = NULL;
-	int offset = 0;
-	int is_ok_to_sleep = 0;
-	char buf[50];
-
-	if (sdio_al->skip_print_info == 1)
-		return;
-
-	sdio_al->skip_print_info = 1;
-
-	sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s - SDIO DEBUG INFO\n",
-			__func__);
-
-	if (!sdio_al) {
-		sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s - ERROR - "
-				"sdio_al is NULL\n",  __func__);
-		return;
-	}
-
-	sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": GPIO mdm2ap_status=%d\n",
-				sdio_al->pdata->get_mdm2ap_status());
-
-	for (j = 0 ; j < MAX_NUM_OF_SDIO_DEVICES ; ++j) {
-		struct sdio_al_device *sdio_al_dev = sdio_al->devices[j];
-
-		if (sdio_al_dev == NULL) {
-			continue;
-		}
-
-		if (!sdio_al_dev->host) {
-			sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": Host"
-					" is NULL\n);");
-			continue;
-		}
-
-		snprintf(buf, sizeof(buf), "Card#%d: Shadow HW MB",
-		       sdio_al_dev->host->index);
-
-		/* printing Shadowing HW Mailbox*/
-		mailbox = sdio_al_dev->mailbox;
-		sdio_print_mailbox(buf, mailbox);
-
-		sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": Card#%d: "
-			"is_ok_to_sleep=%d\n",
-			sdio_al_dev->host->index,
-			sdio_al_dev->is_ok_to_sleep);
-
-
-		sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": Card#%d: "
-				   "Shadow channels SW MB:",
-		       sdio_al_dev->host->index);
-
-		/* printing Shadowing SW Mailbox per channel*/
-		for (i = 0 ; i < SDIO_AL_MAX_CHANNELS ; ++i) {
-			struct sdio_channel *ch = &sdio_al_dev->channel[i];
-
-			if (ch == NULL) {
-				continue;
-			}
-
-			if (ch->state == SDIO_CHANNEL_STATE_INVALID)
-				continue;
-
-			ch_config = &sdio_al_dev->channel[i].ch_config;
-
-			sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
-				": Ch %s: max_rx_thres=0x%x, "
-				"max_tx_thres=0x%x, tx_buf=0x%x, "
-				"is_packet_mode=%d, "
-				"max_packet=0x%x, min_write=0x%x",
-				ch->name, ch_config->max_rx_threshold,
-				ch_config->max_tx_threshold,
-				ch_config->tx_buf_size,
-				ch_config->is_packet_mode,
-				ch_config->max_packet_size,
-				ch->min_write_avail);
-
-			sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
-				": total_rx=0x%x, total_tx=0x%x, "
-				"read_avail=0x%x, write_avail=0x%x, "
-				"rx_pending=0x%x, num_reads=0x%x, "
-				"num_notifs=0x%x", ch->total_rx_bytes,
-				ch->total_tx_bytes, ch->read_avail,
-				ch->write_avail, ch->rx_pending_bytes,
-				ch->statistics.total_read_times,
-				ch->statistics.total_notifs);
-		} /* end loop over all channels */
-
-	} /* end loop over all devices */
-
-	/* reading from client and printing is_host_ok_to_sleep per device */
-	for (j = 0 ; j < MAX_NUM_OF_SDIO_DEVICES ; ++j) {
-		struct sdio_al_device *sdio_al_dev = sdio_al->devices[j];
-
-		if (sdio_al_verify_func1(sdio_al_dev, __func__))
-			continue;
-
-		if (!sdio_al_dev->host) {
-			sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
-					": Host is NULL");
-			continue;
-		}
-
-		if (sdio_al_dev->lpm_chan == INVALID_SDIO_CHAN) {
-			sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
-				": %s - for Card#%d, is lpm_chan=="
-				"INVALID_SDIO_CHAN. continuing...",
-				__func__, sdio_al_dev->host->index);
-			continue;
-		}
-
-		offset = offsetof(struct peer_sdioc_sw_mailbox, ch_config)+
-		sizeof(struct peer_sdioc_channel_config) *
-		sdio_al_dev->lpm_chan+
-		offsetof(struct peer_sdioc_channel_config, is_host_ok_to_sleep);
-
-		lpm_func = sdio_al_dev->card->sdio_func[sdio_al_dev->
-								lpm_chan+1];
-		if (!lpm_func) {
-			sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
-					": %s - lpm_func is NULL for card#%d"
-					" continuing...\n", __func__,
-					sdio_al_dev->host->index);
-			continue;
-		}
-
-		if (sdio_al_claim_mutex_and_verify_dev(sdio_al_dev, __func__))
-			return;
-		ret  =  sdio_memcpy_fromio(lpm_func,
-					    &is_ok_to_sleep,
-					    SDIOC_SW_MAILBOX_ADDR+offset,
-					    sizeof(int));
-		sdio_al_release_mutex(sdio_al_dev, __func__);
-
-		if (ret)
-			sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
-					": %s - fail to read "
-				"is_HOST_ok_to_sleep from mailbox for card %d",
-				__func__, sdio_al_dev->host->index);
-		else
-			sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
-					": Card#%d: "
-				"is_HOST_ok_to_sleep=%d\n",
-				sdio_al_dev->host->index,
-				is_ok_to_sleep);
-	}
-
-	for (j = 0 ; j < MAX_NUM_OF_SDIO_DEVICES ; ++j) {
-		struct sdio_al_device *sdio_al_dev = sdio_al->devices[j];
-
-		if (!sdio_al_dev)
-			continue;
-
-		/* Reading HW Mailbox */
-		hw_mailbox = sdio_al_dev->mailbox;
-
-		if (sdio_al_claim_mutex_and_verify_dev(sdio_al_dev, __func__))
-			return;
-
-		if (!sdio_al_dev->card || !sdio_al_dev->card->sdio_func[0]) {
-			sdio_al_release_mutex(sdio_al_dev, __func__);
-			return;
-		}
-		func1 = sdio_al_dev->card->sdio_func[0];
-		ret = sdio_memcpy_fromio(func1, hw_mailbox,
-			HW_MAILBOX_ADDR, sizeof(*hw_mailbox));
-		sdio_al_release_mutex(sdio_al_dev, __func__);
-
-		if (ret) {
-			sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
-					": fail to read "
-			       "mailbox for card#%d. "
-			       "continuing...\n",
-			       sdio_al_dev->host->index);
-			continue;
-		}
-
-		snprintf(buf, sizeof(buf), "Card#%d: Current HW MB",
-		       sdio_al_dev->host->index);
-
-		/* Printing HW Mailbox */
-		sdio_print_mailbox(buf, hw_mailbox);
-	}
-}
-
-static struct sdio_device_id sdio_al_sdioid[] = {
-    {.class = 0, .vendor = 0x70, .device = 0x2460},
-    {.class = 0, .vendor = 0x70, .device = 0x0460},
-    {.class = 0, .vendor = 0x70, .device = 0x23F1},
-    {.class = 0, .vendor = 0x70, .device = 0x23F0},
-    {}
-};
-
-static struct sdio_driver sdio_al_sdiofn_driver = {
-    .name      = "sdio_al_sdiofn",
-    .id_table  = sdio_al_sdioid,
-    .probe     = sdio_al_sdio_probe,
-    .remove    = sdio_al_sdio_remove,
-};
-
-#ifdef CONFIG_MSM_SUBSYSTEM_RESTART
-/*
- *  Callback for notifications from restart mudule.
- *  This function handles only the BEFORE_RESTART notification.
- *  Stop all the activity on the card and notify our clients.
- */
-static int sdio_al_subsys_notifier_cb(struct notifier_block *this,
-				  unsigned long notif_type,
-				  void *data)
-{
-	if (notif_type != SUBSYS_BEFORE_SHUTDOWN) {
-		sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ": %s: got "
-				"notification %ld", __func__, notif_type);
-		return NOTIFY_DONE;
-	}
-
-	sdio_al_reset();
-	return NOTIFY_OK;
-}
-
-static struct notifier_block sdio_al_nb = {
-	.notifier_call = sdio_al_subsys_notifier_cb,
-};
-#endif
-
-/**
- *  Module Init.
- *
- *  @warn: allocate sdio_al context before registering driver.
- *
- */
-static int __init sdio_al_init(void)
-{
-	int ret = 0;
-	int i;
-
-	pr_debug(MODULE_NAME ":sdio_al_init\n");
-
-	pr_info(MODULE_NAME ":SDIO-AL SW version %s\n",
-		DRV_VERSION);
-
-	sdio_al = kzalloc(sizeof(struct sdio_al), GFP_KERNEL);
-	if (sdio_al == NULL)
-		return -ENOMEM;
-
-	for (i = 0; i < MAX_NUM_OF_SDIO_DEVICES ; ++i)
-		sdio_al->devices[i] = NULL;
-
-	sdio_al->unittest_mode = false;
-
-	sdio_al->debug.debug_lpm_on = debug_lpm_on;
-	sdio_al->debug.debug_data_on = debug_data_on;
-	sdio_al->debug.debug_close_on = debug_close_on;
-
-#ifdef CONFIG_DEBUG_FS
-	sdio_al_debugfs_init();
-#endif
-
-
-#ifdef CONFIG_MSM_SUBSYSTEM_RESTART
-	sdio_al->subsys_notif_handle = subsys_notif_register_notifier(
-		"external_modem", &sdio_al_nb);
-#endif
-
-	ret = platform_driver_register(&msm_sdio_al_driver);
-	if (ret) {
-		pr_err(MODULE_NAME ": platform_driver_register failed: %d\n",
-		       ret);
-		goto exit;
-	}
-
-	sdio_register_driver(&sdio_al_sdiofn_driver);
-
-	spin_lock_init(&sdio_al->gen_log.log_lock);
-
-exit:
-	if (ret)
-		kfree(sdio_al);
-	return ret;
-}
-
-/**
- *  Module Exit.
- *
- *  Free allocated memory.
- *  Disable SDIO-Card.
- *  Unregister driver.
- *
- */
-static void __exit sdio_al_exit(void)
-{
-	if (sdio_al == NULL)
-		return;
-
-	pr_debug(MODULE_NAME ":sdio_al_exit\n");
-
-#ifdef CONFIG_MSM_SUBSYSTEM_RESTART
-	subsys_notif_unregister_notifier(
-		sdio_al->subsys_notif_handle, &sdio_al_nb);
-#endif
-
-	sdio_al_tear_down();
-
-	sdio_unregister_driver(&sdio_al_sdiofn_driver);
-
-	kfree(sdio_al);
-
-#ifdef CONFIG_DEBUG_FS
-	sdio_al_debugfs_cleanup();
-#endif
-
-	platform_driver_unregister(&msm_sdio_al_driver);
-
-	pr_debug(MODULE_NAME ":sdio_al_exit complete\n");
-}
-
-module_init(sdio_al_init);
-module_exit(sdio_al_exit);
-
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("SDIO Abstraction Layer");
-MODULE_AUTHOR("Amir Samuelov <amirs@codeaurora.org>");
-MODULE_VERSION(DRV_VERSION);
-
diff --git a/arch/arm/mach-msm/sdio_al_dloader.c b/arch/arm/mach-msm/sdio_al_dloader.c
deleted file mode 100644
index f3effa8..0000000
--- a/arch/arm/mach-msm/sdio_al_dloader.c
+++ /dev/null
@@ -1,2574 +0,0 @@
-/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * 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.
- */
-
-/*
- * SDIO-Downloader
- *
- * To be used with Qualcomm's SDIO-Client connected to this host.
- */
-
-/* INCLUDES */
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/delay.h>
-#include <linux/wakelock.h>
-#include <linux/workqueue.h>
-#include <linux/mmc/card.h>
-#include <linux/dma-mapping.h>
-#include <mach/dma.h>
-#include <linux/mmc/sdio_func.h>
-#include "sdio_al_private.h"
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/kthread.h>
-#include <linux/version.h>
-#include <linux/errno.h>
-#include <linux/debugfs.h>
-
-/* DEFINES AND MACROS */
-#define MAX_NUM_DEVICES		1
-#define TTY_SDIO_DEV			"tty_sdio_0"
-#define TTY_SDIO_DEV_TEST		"tty_sdio_test_0"
-#define SDIOC_MAILBOX_ADDRESS		0
-#define SDIO_DL_BLOCK_SIZE		512
-#define SDIO_DL_MAIN_THREAD_NAME	"sdio_tty_main_thread"
-#define SDIOC_DL_BUFF_ADDRESS		0
-#define SDIOC_UP_BUFF_ADDRESS		0x4
-#define SDIOC_DL_BUFF_SIZE_OFFSET	0x8
-#define SDIOC_UP_BUFF_SIZE_OFFSET	0xC
-#define SDIOC_DL_WR_PTR		0x10
-#define SDIOC_DL_RD_PTR		0x14
-#define SDIOC_UL_WR_PTR		0x18
-#define SDIOC_UL_RD_PTR		0x1C
-#define SDIOC_EXIT_PTR			0x20
-#define SDIOC_OP_MODE_PTR		0x24
-#define SDIOC_PTRS_OFFSET		0x10
-#define SDIOC_PTR_REGS_SIZE		0x10
-#define SDIOC_CFG_REGS_SIZE		0x10
-#define WRITE_RETRIES			0xFFFFFFFF
-#define INPUT_SPEED			4800
-#define OUTPUT_SPEED			4800
-#define SDIOC_EXIT_CODE		0xDEADDEAD
-#define SLEEP_MS			10
-#define PRINTING_GAP			200
-#define TIMER_DURATION			10
-#define PUSH_TIMER_DURATION		5000
-#define MULTIPLE_RATIO			1
-#define MS_IN_SEC			1000
-#define BITS_IN_BYTE			8
-#define BYTES_IN_KB			1024
-#define WRITE_TILL_END_RETRIES		5
-#define SDIO_DLD_NORMAL_MODE_NAME	"SDIO DLD NORMAL MODE"
-#define SDIO_DLD_BOOT_TEST_MODE_NAME	"SDIO DLD BOOT TEST MODE"
-#define SDIO_DLD_AMSS_TEST_MODE_NAME	"SDIO DLD AMSS TEST MODE"
-#define TEST_NAME_MAX_SIZE		30
-#define PUSH_STRING
-#define SDIO_DLD_OUTGOING_BUFFER_SIZE	(48*1024*MULTIPLE_RATIO)
-
-/* FORWARD DECLARATIONS */
-static int sdio_dld_open(struct tty_struct *tty, struct file *file);
-static void sdio_dld_close(struct tty_struct *tty, struct file *file);
-static int sdio_dld_write_callback(struct tty_struct *tty,
-				   const unsigned char *buf, int count);
-static int sdio_dld_write_room(struct tty_struct *tty);
-static int sdio_dld_main_task(void *card);
-static void sdio_dld_print_info(void);
-#ifdef CONFIG_DEBUG_FS
-static int sdio_dld_debug_info_open(struct inode *inode, struct file *file);
-static ssize_t sdio_dld_debug_info_write(struct file *file,
-		const char __user *buf, size_t count, loff_t *ppos);
-#endif
-
-static void sdio_dld_tear_down(struct work_struct *work);
-DECLARE_WORK(cleanup, sdio_dld_tear_down);
-
-/* STRUCTURES AND TYPES */
-enum sdio_dld_op_mode {
-	 SDIO_DLD_NO_MODE = 0,
-	 SDIO_DLD_NORMAL_MODE = 1,
-	 SDIO_DLD_BOOT_TEST_MODE = 2,
-	 SDIO_DLD_AMSS_TEST_MODE = 3,
-	 SDIO_DLD_NUM_OF_MODES,
-};
-
-struct sdioc_reg_sequential_chunk_ptrs {
-	unsigned int dl_wr_ptr;
-	unsigned int dl_rd_ptr;
-	unsigned int up_wr_ptr;
-	unsigned int up_rd_ptr;
-};
-
-struct sdioc_reg_sequential_chunk_cfg {
-	unsigned int dl_buff_address;
-	unsigned int up_buff_address;
-	unsigned int dl_buff_size;
-	unsigned int ul_buff_size;
-};
-
-struct sdioc_reg {
-	unsigned int reg_val;
-	unsigned int reg_offset;
-};
-
-struct sdioc_reg_chunk {
-	struct sdioc_reg dl_buff_address;
-	struct sdioc_reg up_buff_address;
-	struct sdioc_reg dl_buff_size;
-	struct sdioc_reg ul_buff_size;
-	struct sdioc_reg dl_wr_ptr;
-	struct sdioc_reg dl_rd_ptr;
-	struct sdioc_reg up_wr_ptr;
-	struct sdioc_reg up_rd_ptr;
-	struct sdioc_reg good_to_exit_ptr;
-};
-
-struct sdio_data {
-	char *data;
-	int offset_read_p;
-	int offset_write_p;
-	int buffer_size;
-	int num_of_bytes_in_use;
-};
-
-struct sdio_dld_data {
-	struct sdioc_reg_chunk sdioc_reg;
-	struct sdio_data incoming_data;
-	struct sdio_data outgoing_data;
-};
-
-struct sdio_dld_wait_event {
-	wait_queue_head_t wait_event;
-	int wake_up_signal;
-};
-
-struct sdio_dld_task {
-	struct task_struct *dld_task;
-	const char *task_name;
-	struct sdio_dld_wait_event exit_wait;
-	atomic_t please_close;
-};
-
-#ifdef CONFIG_DEBUG_FS
-struct sdio_dloader_debug {
-	struct dentry *sdio_dld_debug_root;
-	struct dentry *sdio_al_dloader;
-};
-
-const struct file_operations sdio_dld_debug_info_ops = {
-	.open = sdio_dld_debug_info_open,
-	.write = sdio_dld_debug_info_write,
-};
-#endif
-
-struct sdio_downloader {
-	int sdioc_boot_func;
-	struct sdio_dld_wait_event write_callback_event;
-	struct sdio_dld_task dld_main_thread;
-	struct tty_driver *tty_drv;
-	struct tty_struct *tty_str;
-	struct sdio_dld_data sdio_dloader_data;
-	struct mmc_card *card;
-	int(*done_callback)(void);
-	struct sdio_dld_wait_event main_loop_event;
-	struct timer_list timer;
-	unsigned int poll_ms;
-	struct timer_list push_timer;
-	unsigned int push_timer_ms;
-	enum sdio_dld_op_mode op_mode;
-	char op_mode_name[TEST_NAME_MAX_SIZE];
-};
-
-struct sdio_dld_global_info {
-	int global_bytes_write_toio;
-	int global_bytes_write_tty;
-	int global_bytes_read_fromio;
-	int global_bytes_push_tty;
-	u64 start_time;
-	u64 end_time;
-	u64 delta_jiffies;
-	unsigned int time_msec;
-	unsigned int throughput;
-	int cl_dl_wr_ptr;
-	int cl_dl_rd_ptr;
-	int cl_up_wr_ptr;
-	int cl_up_rd_ptr;
-	int host_read_ptr;
-	int host_write_ptr;
-	int cl_dl_buffer_size;
-	int cl_up_buffer_size;
-	int host_outgoing_buffer_size;
-	int cl_dl_buffer_address;
-	int cl_up_buffer_address;
-};
-
-static const struct tty_operations sdio_dloader_tty_ops = {
-	.open = sdio_dld_open,
-	.close = sdio_dld_close,
-	.write = sdio_dld_write_callback,
-	.write_room = sdio_dld_write_room,
-};
-
-/* GLOBAL VARIABLES */
-struct sdio_downloader *sdio_dld;
-struct sdio_dld_global_info sdio_dld_info;
-static char outgoing_data_buffer[SDIO_DLD_OUTGOING_BUFFER_SIZE];
-
-static DEFINE_SPINLOCK(lock1);
-static unsigned long lock_flags1;
-static DEFINE_SPINLOCK(lock2);
-static unsigned long lock_flags2;
-
-static atomic_t sdio_dld_in_use = ATOMIC_INIT(0);
-static atomic_t sdio_dld_setup_done = ATOMIC_INIT(0);
-
-/*
- * sdio_op_mode sets the operation mode of the sdio_dloader -
- * it may be in NORMAL_MODE, BOOT_TEST_MODE or AMSS_TEST_MODE
- */
-static int sdio_op_mode = (int)SDIO_DLD_NORMAL_MODE;
-module_param(sdio_op_mode, int, 0);
-
-#ifdef CONFIG_DEBUG_FS
-
-struct sdio_dloader_debug sdio_dld_debug;
-
-#define ARR_SIZE 30000
-#define SDIO_DLD_DEBUGFS_INIT_VALUE	87654321
-#define SDIO_DLD_DEBUGFS_CASE_1_CODE	11111111
-#define SDIO_DLD_DEBUGFS_CASE_2_CODE	22222222
-#define SDIO_DLD_DEBUGFS_CASE_3_CODE	33333333
-#define SDIO_DLD_DEBUGFS_CASE_4_CODE	44444444
-#define SDIO_DLD_DEBUGFS_CASE_5_CODE	55555555
-#define SDIO_DLD_DEBUGFS_CASE_6_CODE	66666666
-#define SDIO_DLD_DEBUGFS_CASE_7_CODE	77777777
-#define SDIO_DLD_DEBUGFS_CASE_8_CODE	88888888
-#define SDIO_DLD_DEBUGFS_CASE_9_CODE	99999999
-#define SDIO_DLD_DEBUGFS_CASE_10_CODE	10101010
-#define SDIO_DLD_DEBUGFS_CASE_11_CODE	11001100
-#define SDIO_DLD_DEBUGFS_CASE_12_CODE	12001200
-#define SDIO_DLD_DEBUGFS_LOOP_WAIT	7
-#define SDIO_DLD_DEBUGFS_LOOP_WAKEUP	8
-#define SDIO_DLD_DEBUGFS_CB_WAIT	3
-#define SDIO_DLD_DEBUGFS_CB_WAKEUP	4
-
-static int curr_index;
-struct ptrs {
-	int h_w_ptr;
-	int h_r_ptr;
-	int c_u_w_ptr;
-	int c_u_r_ptr;
-	int code;
-	int h_has_to_send;
-	int c_has_to_receive;
-	int min_of;
-	int reserve2;
-	int tty_count;
-	int write_tty;
-	int write_toio;
-	int loop_wait_wake;
-	int cb_wait_wake;
-	int c_d_w_ptr;
-	int c_d_r_ptr;
-	int to_read;
-	int push_to_tty;
-	int global_tty_send;
-	int global_sdio_send;
-	int global_tty_received;
-	int global_sdio_received;
-	int reserve22;
-	int reserve23;
-	int reserve24;
-	int reserve25;
-	int reserve26;
-	int reserve27;
-	int reserve28;
-	int reserve29;
-	int reserve30;
-	int reserve31;
-};
-
-struct global_data {
-	int curr_i;
-	int duration_ms;
-	int global_bytes_sent;
-	int throughput_Mbs;
-	int host_outgoing_buffer_size_KB;
-	int client_up_buffer_size_KB;
-	int client_dl_buffer_size_KB;
-	int client_dl_buffer_address;
-	int client_up_buffer_address;
-	int global_bytes_received;
-	int global_bytes_pushed;
-	int reserve11;
-	int reserve12;
-	int reserve13;
-	int reserve14;
-	int reserve15;
-	int reserve16;
-	int reserve17;
-	int reserve18;
-	int reserve19;
-	int reserve20;
-	int reserve21;
-	int reserve22;
-	int reserve23;
-	int reserve24;
-	int reserve25;
-	int reserve26;
-	int reserve27;
-	int reserve28;
-	int reserve29;
-	int reserve30;
-	int reserve31;
-	struct ptrs ptr_array[ARR_SIZE];
-};
-
-static struct global_data gd;
-static struct debugfs_blob_wrapper blob;
-static struct dentry *root;
-static struct dentry *dld;
-
-struct debugfs_global {
-	int global_8k_has;
-	int global_9k_has;
-	int global_min;
-	int global_count;
-	int global_write_tty;
-	int global_write_toio;
-	int global_bytes_cb_tty;
-	int global_to_read;
-	int global_push_to_tty;
-	int global_tty_send;
-	int global_sdio_send;
-	int global_sdio_received;
-	int global_tty_push;
-};
-
-static struct debugfs_global debugfs_glob;
-
-static void update_standard_fields(int index)
-{
-
-	gd.ptr_array[index].global_tty_send =
-		sdio_dld_info.global_bytes_write_tty;
-	gd.ptr_array[index].global_sdio_send =
-		sdio_dld_info.global_bytes_write_toio;
-	gd.ptr_array[index].global_tty_received =
-		sdio_dld_info.global_bytes_push_tty;
-	gd.ptr_array[index].global_sdio_received =
-		sdio_dld_info.global_bytes_read_fromio;
-}
-
-static void update_gd(int code)
-{
-	struct sdioc_reg_chunk *reg_str =
-					&sdio_dld->sdio_dloader_data.sdioc_reg;
-	struct sdio_data *outgoing = &sdio_dld->sdio_dloader_data.outgoing_data;
-	int index = curr_index%ARR_SIZE;
-
-	gd.curr_i = curr_index;
-	gd.duration_ms = 0;
-	gd.global_bytes_sent = 0;
-	gd.throughput_Mbs = 0;
-	gd.host_outgoing_buffer_size_KB = 0;
-	gd.client_up_buffer_size_KB = 0;
-	gd.client_dl_buffer_size_KB = 0;
-	gd.client_dl_buffer_address = 0;
-	gd.client_up_buffer_address = 0;
-	gd.global_bytes_received = 0;
-	gd.global_bytes_pushed = 0;
-	gd.reserve11 = 0;
-	gd.reserve12 = 0;
-	gd.reserve13 = 0;
-	gd.reserve14 = 0;
-	gd.reserve15 = 0;
-	gd.reserve16 = 0;
-	gd.reserve17 = 0;
-	gd.reserve18 = 0;
-	gd.reserve19 = 0;
-	gd.reserve20 = 0;
-	gd.reserve21 = 0;
-	gd.reserve22 = 0;
-	gd.reserve23 = 0;
-	gd.reserve24 = 0;
-	gd.reserve25 = 0;
-	gd.reserve26 = 0;
-	gd.reserve27 = 0;
-	gd.reserve28 = 0;
-	gd.reserve29 = 0;
-	gd.reserve30 = 0;
-	gd.reserve31 = 0;
-
-	gd.ptr_array[index].h_w_ptr = SDIO_DLD_DEBUGFS_INIT_VALUE;	/*0*/
-	gd.ptr_array[index].h_r_ptr = SDIO_DLD_DEBUGFS_INIT_VALUE;	/*1*/
-	gd.ptr_array[index].c_u_w_ptr =	SDIO_DLD_DEBUGFS_INIT_VALUE;	/*2*/
-	gd.ptr_array[index].c_u_r_ptr =	SDIO_DLD_DEBUGFS_INIT_VALUE;	/*3*/
-	gd.ptr_array[index].code = SDIO_DLD_DEBUGFS_INIT_VALUE;		/*4*/
-	gd.ptr_array[index].h_has_to_send = SDIO_DLD_DEBUGFS_INIT_VALUE;/*5*/
-	gd.ptr_array[index].c_has_to_receive =
-		SDIO_DLD_DEBUGFS_INIT_VALUE;				/*6*/
-	gd.ptr_array[index].min_of = SDIO_DLD_DEBUGFS_INIT_VALUE;	/*7*/
-	gd.ptr_array[index].reserve2 = SDIO_DLD_DEBUGFS_INIT_VALUE;	/*8*/
-	gd.ptr_array[index].tty_count = SDIO_DLD_DEBUGFS_INIT_VALUE;	/*9*/
-	gd.ptr_array[index].write_tty = SDIO_DLD_DEBUGFS_INIT_VALUE;	/*A*/
-	gd.ptr_array[index].write_toio = SDIO_DLD_DEBUGFS_INIT_VALUE;	/*B*/
-	gd.ptr_array[index].loop_wait_wake =
-		SDIO_DLD_DEBUGFS_INIT_VALUE;				/*C*/
-	gd.ptr_array[index].cb_wait_wake = SDIO_DLD_DEBUGFS_INIT_VALUE;	/*D*/
-	gd.ptr_array[index].c_d_w_ptr =	SDIO_DLD_DEBUGFS_INIT_VALUE;	/*E*/
-	gd.ptr_array[index].c_d_r_ptr =	SDIO_DLD_DEBUGFS_INIT_VALUE;	/*F*/
-	gd.ptr_array[index].to_read =
-		SDIO_DLD_DEBUGFS_INIT_VALUE;			/*0x10*/
-	gd.ptr_array[index].push_to_tty =
-		SDIO_DLD_DEBUGFS_INIT_VALUE;			/*0x11*/
-	gd.ptr_array[index].global_tty_send =
-		SDIO_DLD_DEBUGFS_INIT_VALUE;			/*0x12*/
-	gd.ptr_array[index].global_sdio_send =
-		SDIO_DLD_DEBUGFS_INIT_VALUE;			/*0x13*/
-	gd.ptr_array[index].global_tty_received =
-		SDIO_DLD_DEBUGFS_INIT_VALUE;			/*0x14*/
-	gd.ptr_array[index].global_sdio_received =
-		SDIO_DLD_DEBUGFS_INIT_VALUE;			/*0x15*/
-	gd.ptr_array[index].reserve22 = SDIO_DLD_DEBUGFS_INIT_VALUE;
-	gd.ptr_array[index].reserve23 = SDIO_DLD_DEBUGFS_INIT_VALUE;
-	gd.ptr_array[index].reserve24 = SDIO_DLD_DEBUGFS_INIT_VALUE;
-	gd.ptr_array[index].reserve25 = SDIO_DLD_DEBUGFS_INIT_VALUE;
-	gd.ptr_array[index].reserve26 = SDIO_DLD_DEBUGFS_INIT_VALUE;
-	gd.ptr_array[index].reserve27 = SDIO_DLD_DEBUGFS_INIT_VALUE;
-	gd.ptr_array[index].reserve28 = SDIO_DLD_DEBUGFS_INIT_VALUE;
-	gd.ptr_array[index].reserve29 = SDIO_DLD_DEBUGFS_INIT_VALUE;
-	gd.ptr_array[index].reserve30 = SDIO_DLD_DEBUGFS_INIT_VALUE;
-	gd.ptr_array[index].reserve31 = SDIO_DLD_DEBUGFS_INIT_VALUE;
-
-	switch (code) {
-	case SDIO_DLD_DEBUGFS_CASE_1_CODE:
-		gd.ptr_array[index].code = SDIO_DLD_DEBUGFS_CASE_1_CODE;
-		gd.ptr_array[index].h_w_ptr = outgoing->offset_write_p;
-		gd.ptr_array[index].h_r_ptr = outgoing->offset_read_p;
-		gd.ptr_array[index].c_u_w_ptr =	reg_str->up_wr_ptr.reg_val;
-		gd.ptr_array[index].c_u_r_ptr =	reg_str->up_rd_ptr.reg_val;
-		gd.ptr_array[index].c_d_w_ptr =	reg_str->dl_wr_ptr.reg_val;
-		gd.ptr_array[index].c_d_r_ptr =	reg_str->dl_rd_ptr.reg_val;
-		break;
-
-	case SDIO_DLD_DEBUGFS_CASE_2_CODE:
-		gd.ptr_array[index].code = SDIO_DLD_DEBUGFS_CASE_2_CODE;
-		gd.ptr_array[index].c_u_r_ptr = reg_str->up_rd_ptr.reg_val;
-		gd.ptr_array[index].c_u_w_ptr = reg_str->up_wr_ptr.reg_val;
-		gd.ptr_array[index].h_has_to_send = debugfs_glob.global_8k_has;
-		gd.ptr_array[index].c_has_to_receive =
-			debugfs_glob.global_9k_has;
-		gd.ptr_array[index].min_of = debugfs_glob.global_min;
-		break;
-
-	case SDIO_DLD_DEBUGFS_CASE_3_CODE:
-		gd.ptr_array[index].code = SDIO_DLD_DEBUGFS_CASE_3_CODE;
-		gd.ptr_array[index].h_w_ptr = outgoing->offset_write_p;
-		gd.ptr_array[index].h_r_ptr = outgoing->offset_read_p;
-		gd.ptr_array[index].write_tty = debugfs_glob.global_write_tty;
-		break;
-
-	case SDIO_DLD_DEBUGFS_CASE_4_CODE:
-		gd.ptr_array[index].code = SDIO_DLD_DEBUGFS_CASE_4_CODE;
-		gd.ptr_array[index].h_w_ptr = outgoing->offset_write_p;
-		gd.ptr_array[index].h_r_ptr = outgoing->offset_read_p;
-		gd.ptr_array[index].c_u_r_ptr = reg_str->up_rd_ptr.reg_val;
-		gd.ptr_array[index].c_u_w_ptr = reg_str->up_wr_ptr.reg_val;
-		gd.ptr_array[index].write_toio =
-			debugfs_glob.global_write_toio;
-		break;
-
-	case SDIO_DLD_DEBUGFS_CASE_5_CODE:
-		gd.ptr_array[index].code = SDIO_DLD_DEBUGFS_CASE_5_CODE;
-		gd.ptr_array[index].tty_count = debugfs_glob.global_count;
-		break;
-
-	case SDIO_DLD_DEBUGFS_CASE_6_CODE:
-		gd.ptr_array[index].code = SDIO_DLD_DEBUGFS_CASE_6_CODE;
-		gd.ptr_array[index].loop_wait_wake = 7;
-		break;
-
-	case SDIO_DLD_DEBUGFS_CASE_7_CODE:
-		gd.ptr_array[index].code = SDIO_DLD_DEBUGFS_CASE_7_CODE;
-		gd.ptr_array[index].loop_wait_wake = 8;
-		break;
-
-	case SDIO_DLD_DEBUGFS_CASE_8_CODE:
-		gd.ptr_array[index].code = SDIO_DLD_DEBUGFS_CASE_8_CODE;
-		gd.ptr_array[index].cb_wait_wake = 3;
-		break;
-
-	case SDIO_DLD_DEBUGFS_CASE_9_CODE:
-		gd.ptr_array[index].code = SDIO_DLD_DEBUGFS_CASE_9_CODE;
-		gd.ptr_array[index].cb_wait_wake = 4;
-		break;
-
-	case SDIO_DLD_DEBUGFS_CASE_10_CODE:
-		gd.ptr_array[index].code = SDIO_DLD_DEBUGFS_CASE_10_CODE;
-		gd.ptr_array[index].cb_wait_wake =
-			debugfs_glob.global_bytes_cb_tty;
-		break;
-
-	case SDIO_DLD_DEBUGFS_CASE_11_CODE:
-		gd.ptr_array[index].code = SDIO_DLD_DEBUGFS_CASE_11_CODE;
-		gd.ptr_array[index].to_read = debugfs_glob.global_to_read;
-		break;
-
-	case SDIO_DLD_DEBUGFS_CASE_12_CODE:
-		gd.ptr_array[index].code = SDIO_DLD_DEBUGFS_CASE_12_CODE;
-		gd.ptr_array[index].push_to_tty =
-			debugfs_glob.global_push_to_tty;
-		break;
-
-	default:
-		break;
-	}
-	update_standard_fields(index);
-	curr_index++;
-}
-
-static int bootloader_debugfs_init(void)
-{
-	/* /sys/kernel/debug/bootloader there will be dld_arr file */
-	root = debugfs_create_dir("bootloader", NULL);
-	if (!root) {
-		pr_info(MODULE_NAME ": %s - creating root dir "
-			"failed\n", __func__);
-		return -ENODEV;
-	}
-
-	blob.data = &gd;
-	blob.size = sizeof(struct global_data);
-	dld = debugfs_create_blob("dld_arr", S_IRUGO, root, &blob);
-	if (!dld) {
-		debugfs_remove_recursive(root);
-		pr_err(MODULE_NAME ": %s, failed to create debugfs entry\n",
-		       __func__);
-		return -ENODEV;
-	}
-
-	return 0;
-}
-
-/*
-* for triggering the sdio_dld info use:
-* echo 1 > /sys/kernel/debug/sdio_al_dld/sdio_al_dloader_info
-*/
-static int sdio_dld_debug_init(void)
-{
-	sdio_dld_debug.sdio_dld_debug_root =
-				debugfs_create_dir("sdio_al_dld", NULL);
-	if (!sdio_dld_debug.sdio_dld_debug_root) {
-		pr_err(MODULE_NAME ": %s - Failed to create folder. "
-		       "sdio_dld_debug_root is NULL",
-		       __func__);
-		return -ENOENT;
-	}
-
-	sdio_dld_debug.sdio_al_dloader = debugfs_create_file(
-					"sdio_al_dloader_info",
-					S_IRUGO | S_IWUGO,
-					sdio_dld_debug.sdio_dld_debug_root,
-					NULL,
-					&sdio_dld_debug_info_ops);
-
-	if (!sdio_dld_debug.sdio_al_dloader) {
-		pr_err(MODULE_NAME ": %s - Failed to create a file. "
-		       "sdio_al_dloader is NULL",
-		       __func__);
-		debugfs_remove(sdio_dld_debug.sdio_dld_debug_root);
-		sdio_dld_debug.sdio_dld_debug_root = NULL;
-		return -ENOENT;
-	}
-
-	return 0;
-}
-
-static int sdio_dld_debug_info_open(struct inode *inode, struct file *file)
-{
-	file->private_data = inode->i_private;
-	return 0;
-}
-
-static ssize_t sdio_dld_debug_info_write(struct file *file,
-		const char __user *buf, size_t count, loff_t *ppos)
-{
-	sdio_dld_print_info();
-	return count;
-}
-#endif /* CONFIG_DEBUG_FS */
-
-static void sdio_dld_print_info(void)
-{
-
-	sdio_dld_info.end_time = get_jiffies_64(); /* read the current time */
-	sdio_dld_info.delta_jiffies =
-		sdio_dld_info.end_time - sdio_dld_info.start_time;
-	sdio_dld_info.time_msec = jiffies_to_msecs(sdio_dld_info.delta_jiffies);
-
-	sdio_dld_info.throughput = sdio_dld_info.global_bytes_write_toio *
-		BITS_IN_BYTE / sdio_dld_info.time_msec;
-	sdio_dld_info.throughput /= MS_IN_SEC;
-
-	pr_info(MODULE_NAME ": %s, FLASHLESS BOOT - DURATION IN MSEC = %d\n",
-		__func__,
-		sdio_dld_info.time_msec);
-
-	pr_info(MODULE_NAME ": %s, FLASHLESS BOOT - BYTES WRITTEN ON SDIO BUS "
-			    "= %d...BYTES SENT BY TTY = %d",
-		__func__,
-	       sdio_dld_info.global_bytes_write_toio,
-	       sdio_dld_info.global_bytes_write_tty);
-
-	pr_info(MODULE_NAME ": %s, FLASHLESS BOOT - BYTES RECEIVED ON SDIO BUS "
-			    "= %d...BYTES SENT TO TTY = %d",
-		__func__,
-		sdio_dld_info.global_bytes_read_fromio,
-		sdio_dld_info.global_bytes_push_tty);
-
-	pr_info(MODULE_NAME ": %s, FLASHLESS BOOT - THROUGHPUT=%d Mbit/Sec",
-		__func__, sdio_dld_info.throughput);
-
-	pr_info(MODULE_NAME ": %s, FLASHLESS BOOT - CLIENT DL_BUFFER_SIZE=%d"
-		" KB..CLIENT UL_BUFFER=%d KB\n",
-		__func__,
-		sdio_dld_info.cl_dl_buffer_size/BYTES_IN_KB,
-		sdio_dld_info.cl_up_buffer_size/BYTES_IN_KB);
-
-	pr_info(MODULE_NAME ": %s, FLASHLESS BOOT - HOST OUTGOING BUFFER_SIZE"
-			    "=%d KB",
-		__func__,
-		sdio_dld_info.host_outgoing_buffer_size/BYTES_IN_KB);
-
-	pr_info(MODULE_NAME ": %s, FLASHLESS BOOT - CLIENT DL BUFFER "
-		 "ADDRESS = 0x%x", __func__,
-		sdio_dld_info.cl_dl_buffer_address);
-
-	pr_info(MODULE_NAME ": %s, FLASHLESS BOOT - CLIENT UP BUFFER "
-		"ADDRESS = 0x%x",
-		__func__,
-		sdio_dld_info.cl_up_buffer_address);
-
-	pr_info(MODULE_NAME ": %s, FLASHLESS BOOT - CLIENT - UPLINK BUFFER - "
-		"READ POINTER = %d", __func__,
-		sdio_dld_info.cl_up_rd_ptr);
-
-	pr_info(MODULE_NAME ": %s, FLASHLESS BOOT - CLIENT - UPLINK BUFFER - "
-		"WRITE POINTER = %d", __func__,
-		sdio_dld_info.cl_up_wr_ptr);
-
-	pr_info(MODULE_NAME ": %s, FLASHLESS BOOT - CLIENT - DOWNLINK BUFFER - "
-		"READ POINTER = %d", __func__,
-		sdio_dld_info.cl_dl_rd_ptr);
-
-	pr_info(MODULE_NAME ": %s, FLASHLESS BOOT - CLIENT - DOWNLINK BUFFER - "
-		"WRITE POINTER = %d", __func__,
-		sdio_dld_info.cl_dl_wr_ptr);
-
-	pr_info(MODULE_NAME ": %s, FLASHLESS BOOT - HOST - OUTGOING BUFFER - "
-		"READ POINTER = %d", __func__,
-		sdio_dld_info.host_read_ptr);
-
-	pr_info(MODULE_NAME ": %s, FLASHLESS BOOT - HOST - OUTGOING BUFFER - "
-		"WRITE POINTER = %d", __func__,
-		sdio_dld_info.host_write_ptr);
-
-	pr_info(MODULE_NAME ": %s, FLASHLESS BOOT - END DEBUG INFO", __func__);
-}
-
-/**
-  * sdio_dld_set_op_mode
-  * sets the op_mode and the name of the op_mode. Also, in case
-  * it's invalid mode sets op_mode to SDIO_DLD_NORMAL_MODE
-  *
-  * @op_mode: the operation mode to be set
-  * @return NONE
-  */
-static void sdio_dld_set_op_mode(enum sdio_dld_op_mode op_mode)
-{
-	sdio_dld->op_mode = op_mode;
-
-	switch (op_mode) {
-	case SDIO_DLD_NORMAL_MODE:
-		memcpy(sdio_dld->op_mode_name,
-		       SDIO_DLD_NORMAL_MODE_NAME, TEST_NAME_MAX_SIZE);
-		break;
-	case SDIO_DLD_BOOT_TEST_MODE:
-		memcpy(sdio_dld->op_mode_name,
-		       SDIO_DLD_BOOT_TEST_MODE_NAME, TEST_NAME_MAX_SIZE);
-		break;
-	case SDIO_DLD_AMSS_TEST_MODE:
-		memcpy(sdio_dld->op_mode_name,
-		       SDIO_DLD_AMSS_TEST_MODE_NAME, TEST_NAME_MAX_SIZE);
-		break;
-	default:
-		sdio_dld->op_mode = SDIO_DLD_NORMAL_MODE;
-		pr_err(MODULE_NAME ": %s - Invalid Op_Mode = %d. Settings "
-		       "Op_Mode to default - NORMAL_MODE\n",
-		       __func__, op_mode);
-		memcpy(sdio_dld->op_mode_name,
-		       SDIO_DLD_NORMAL_MODE_NAME, TEST_NAME_MAX_SIZE);
-		break;
-	}
-
-	if (sdio_dld->op_mode_name != NULL) {
-		pr_info(MODULE_NAME ": %s - FLASHLESS BOOT - Op_Mode is set to "
-			"%s\n", __func__, sdio_dld->op_mode_name);
-	} else {
-		pr_info(MODULE_NAME ": %s - FLASHLESS BOOT - op_mode_name is "
-			"NULL\n", __func__);
-	}
-}
-
-/**
-  * sdio_dld_allocate_local_buffers
-  * allocates local outgoing and incoming buffers and also sets
-  * threshold for outgoing data.
-  *
-  * @return 0 on success or negative value on error.
-  */
-static int sdio_dld_allocate_local_buffers(void)
-{
-	struct sdioc_reg_chunk *reg_str = &sdio_dld->sdio_dloader_data.
-		sdioc_reg;
-	struct sdio_data *outgoing = &sdio_dld->sdio_dloader_data.outgoing_data;
-	struct sdio_data *incoming = &sdio_dld->sdio_dloader_data.incoming_data;
-
-	incoming->data =
-		kzalloc(reg_str->dl_buff_size.reg_val, GFP_KERNEL);
-
-	if (!incoming->data) {
-		pr_err(MODULE_NAME ": %s - param ""incoming->data"" is NULL. "
-		       "Couldn't allocate incoming_data local buffer\n",
-		       __func__);
-		return -ENOMEM;
-	}
-
-	incoming->buffer_size = reg_str->dl_buff_size.reg_val;
-
-	outgoing->data = outgoing_data_buffer;
-
-	outgoing->buffer_size = SDIO_DLD_OUTGOING_BUFFER_SIZE;
-
-	if (outgoing->buffer_size !=
-	    reg_str->ul_buff_size.reg_val*MULTIPLE_RATIO) {
-		pr_err(MODULE_NAME ": %s - HOST outgoing buffer size (%d bytes)"
-		       "must be a multiple of ClIENT uplink buffer size (%d "
-		       "bytes). HOST_SIZE == n*CLIENT_SIZE.(n=1,2,3...)\n",
-		       __func__,
-		       SDIO_DLD_OUTGOING_BUFFER_SIZE,
-		       reg_str->ul_buff_size.reg_val);
-		kfree(incoming->data);
-		return -EINVAL;
-	}
-
-	/* keep sdio_dld_info up to date */
-	sdio_dld_info.host_outgoing_buffer_size = outgoing->buffer_size;
-
-	return 0;
-}
-
-/**
-  * sdio_dld_dealloc_local_buffers frees incoming and outgoing
-  * buffers.
-  *
-  * @return None.
-  */
-static void sdio_dld_dealloc_local_buffers(void)
-{
-	kfree((void *)sdio_dld->sdio_dloader_data.incoming_data.data);
-}
-
-/**
-  * mailbox_to_seq_chunk_read_cfg
-  * reads 4 configuration registers of mailbox from str_func, as
-  * a sequentail chunk in memory, and updates global struct
-  * accordingly.
-  *
-  * @str_func: a pointer to func struct.
-  * @return 0 on success or negative value on error.
-  */
-static int mailbox_to_seq_chunk_read_cfg(struct sdio_func *str_func)
-{
-	struct sdioc_reg_sequential_chunk_cfg seq_chunk;
-	struct sdioc_reg_chunk *reg = &sdio_dld->sdio_dloader_data.sdioc_reg;
-	int status = 0;
-
-	if (!str_func) {
-		pr_err(MODULE_NAME ": %s - param ""str_func"" is NULL.\n",
-		       __func__);
-		return -EINVAL;
-	}
-
-	sdio_claim_host(str_func);
-
-	/* reading SDIOC_MAILBOX_SIZE bytes from SDIOC_MAILBOX_ADDRESS */
-	status = sdio_memcpy_fromio(str_func,
-				    (void *)&seq_chunk,
-				    SDIOC_MAILBOX_ADDRESS,
-				    SDIOC_CFG_REGS_SIZE);
-	if (status) {
-		pr_err(MODULE_NAME ": %s - sdio_memcpy_fromio()"
-		       " READING CFG MAILBOX failed. status=%d.\n",
-		       __func__, status);
-	}
-
-	sdio_release_host(str_func);
-
-	reg->dl_buff_address.reg_val = seq_chunk.dl_buff_address;
-	reg->up_buff_address.reg_val = seq_chunk.up_buff_address;
-	reg->dl_buff_size.reg_val = seq_chunk.dl_buff_size;
-	reg->ul_buff_size.reg_val = seq_chunk.ul_buff_size;
-
-	/* keep sdio_dld_info up to date */
-	sdio_dld_info.cl_dl_buffer_size = seq_chunk.dl_buff_size;
-	sdio_dld_info.cl_up_buffer_size = seq_chunk.ul_buff_size;
-	sdio_dld_info.cl_dl_buffer_address = seq_chunk.dl_buff_address;
-	sdio_dld_info.cl_up_buffer_address = seq_chunk.up_buff_address;
-
-	return status;
-}
-
-/**
-  * mailbox_to_seq_chunk_read_ptrs
-  * reads 4 pointers registers of mailbox from str_func, as a
-  * sequentail chunk in memory, and updates global struct
-  * accordingly.
-  *
-  * @str_func: a pointer to func struct.
-  * @return 0 on success or negative value on error.
-  */
-static int mailbox_to_seq_chunk_read_ptrs(struct sdio_func *str_func)
-{
-	struct sdioc_reg_sequential_chunk_ptrs seq_chunk;
-	struct sdioc_reg_chunk *reg = &sdio_dld->sdio_dloader_data.sdioc_reg;
-	int status = 0;
-
-	struct sdio_data *outgoing = &sdio_dld->sdio_dloader_data.outgoing_data;
-	static int counter = 1;
-	static int offset_write_p;
-	static int offset_read_p;
-	static int up_wr_ptr;
-	static int up_rd_ptr;
-	static int dl_wr_ptr;
-	static int dl_rd_ptr;
-
-	if (!str_func) {
-		pr_err(MODULE_NAME ": %s - param ""str_func"" is NULL.\n",
-		       __func__);
-		return -EINVAL;
-	}
-
-	sdio_claim_host(str_func);
-
-	/* reading SDIOC_MAILBOX_SIZE bytes from SDIOC_MAILBOX_ADDRESS */
-	status = sdio_memcpy_fromio(str_func,
-				    (void *)&seq_chunk,
-				    SDIOC_PTRS_OFFSET,
-				    SDIOC_PTR_REGS_SIZE);
-	if (status) {
-		pr_err(MODULE_NAME ": %s - sdio_memcpy_fromio()"
-		       " READING PTRS MAILBOX failed. status=%d.\n",
-		       __func__, status);
-	}
-
-	sdio_release_host(str_func);
-
-	reg->dl_rd_ptr.reg_val = seq_chunk.dl_rd_ptr;
-	reg->dl_wr_ptr.reg_val = seq_chunk.dl_wr_ptr;
-	reg->up_rd_ptr.reg_val = seq_chunk.up_rd_ptr;
-	reg->up_wr_ptr.reg_val = seq_chunk.up_wr_ptr;
-
-	/* keeping sdio_dld_info up to date */
-	sdio_dld_info.cl_dl_rd_ptr = seq_chunk.dl_rd_ptr;
-	sdio_dld_info.cl_dl_wr_ptr = seq_chunk.dl_wr_ptr;
-	sdio_dld_info.cl_up_rd_ptr = seq_chunk.up_rd_ptr;
-	sdio_dld_info.cl_up_wr_ptr = seq_chunk.up_wr_ptr;
-
-
-	/* DEBUG - if there was a change in value */
-	if ((offset_write_p != outgoing->offset_write_p) ||
-	    (offset_read_p != outgoing->offset_read_p) ||
-	    (up_wr_ptr != reg->up_wr_ptr.reg_val) ||
-	    (up_rd_ptr != reg->up_rd_ptr.reg_val) ||
-	    (dl_wr_ptr != reg->dl_wr_ptr.reg_val) ||
-	    (dl_rd_ptr != reg->dl_rd_ptr.reg_val) ||
-	    (counter % PRINTING_GAP == 0)) {
-		counter = 1;
-		pr_debug(MODULE_NAME ": %s MailBox pointers: BLOCK_SIZE=%d, "
-			 "hw=%d, hr=%d, cuw=%d, cur=%d, cdw=%d, cdr=%d\n",
-			 __func__,
-			 SDIO_DL_BLOCK_SIZE,
-			 outgoing->offset_write_p,
-			 outgoing->offset_read_p,
-			 reg->up_wr_ptr.reg_val,
-			 reg->up_rd_ptr.reg_val,
-			 reg->dl_wr_ptr.reg_val,
-			 reg->dl_rd_ptr.reg_val);
-
-#ifdef CONFIG_DEBUG_FS
-		update_gd(SDIO_DLD_DEBUGFS_CASE_1_CODE);
-#endif
-		/* update static variables */
-		offset_write_p = outgoing->offset_write_p;
-		offset_read_p =	outgoing->offset_read_p;
-		up_wr_ptr = reg->up_wr_ptr.reg_val;
-		up_rd_ptr = reg->up_rd_ptr.reg_val;
-		dl_wr_ptr = reg->dl_wr_ptr.reg_val;
-		dl_rd_ptr = reg->dl_rd_ptr.reg_val;
-	} else {
-		counter++;
-	}
-	return status;
-}
-
-/**
-  * sdio_dld_init_func
-  * enables the sdio func, and sets the func block size.
-  *
-  * @str_func: a pointer to func struct.
-  * @return 0 on success or negative value on error.
-  */
-static int sdio_dld_init_func(struct sdio_func *str_func)
-{
-	int status1 = 0;
-	int status2 = 0;
-
-	if (!str_func) {
-		pr_err(MODULE_NAME ": %s - param ""str_func"" is NULL.\n",
-		       __func__);
-		return -EINVAL;
-	}
-
-	sdio_claim_host(str_func);
-
-	status1 = sdio_enable_func(str_func);
-	if (status1) {
-		sdio_release_host(str_func);
-		pr_err(MODULE_NAME ": %s - sdio_enable_func() failed. "
-		       "status=%d\n", __func__, status1);
-		return status1;
-	}
-
-	status2 = sdio_set_block_size(str_func, SDIO_DL_BLOCK_SIZE);
-	if (status2) {
-		pr_err(MODULE_NAME ": %s - sdio_set_block_size() failed. "
-		       "status=%d\n", __func__, status2);
-		status1 = sdio_disable_func(str_func);
-		if (status1) {
-			pr_err(MODULE_NAME ": %s - sdio_disable_func() "
-		       "failed. status=%d\n", __func__, status1);
-		}
-		sdio_release_host(str_func);
-		return status2;
-	}
-
-	sdio_release_host(str_func);
-	str_func->max_blksize = SDIO_DL_BLOCK_SIZE;
-	return 0;
-}
-
-/**
-  * sdio_dld_allocate_buffers
-  * initializes the sdio func, and then reads the mailbox, in
-  * order to allocate incoming and outgoing buffers according to
-  * the size that was read from the mailbox.
-  *
-  * @str_func: a pointer to func struct.
-  * @return 0 on success or negative value on error.
-  */
-static int sdio_dld_allocate_buffers(struct sdio_func *str_func)
-{
-	int status = 0;
-
-	if (!str_func) {
-		pr_err(MODULE_NAME ": %s - param ""str_func"" is NULL.\n",
-		       __func__);
-		return -EINVAL;
-	}
-
-	status = mailbox_to_seq_chunk_read_cfg(str_func);
-	if (status) {
-		pr_err(MODULE_NAME ": %s - Failure in Function "
-		       "mailbox_to_seq_chunk_read_cfg(). status=%d\n",
-		       __func__, status);
-		return status;
-	}
-
-	status = sdio_dld_allocate_local_buffers();
-	if (status) {
-		pr_err(MODULE_NAME ": %s - Failure in Function "
-		       "sdio_dld_allocate_local_buffers(). status=%d\n",
-		       __func__, status);
-		return status;
-	}
-	return 0;
-}
-
-/**
-  * sdio_dld_create_thread
-  * creates thread and wakes it up.
-  *
-  * @return 0 on success or negative value on error.
-  */
-static int sdio_dld_create_thread(void)
-{
-	sdio_dld->dld_main_thread.task_name = SDIO_DL_MAIN_THREAD_NAME;
-
-	sdio_dld->dld_main_thread.dld_task =
-		kthread_create(sdio_dld_main_task,
-			       (void *)(sdio_dld->card),
-			       sdio_dld->dld_main_thread.task_name);
-
-	if (IS_ERR(sdio_dld->dld_main_thread.dld_task)) {
-		pr_err(MODULE_NAME ": %s - kthread_create() failed\n",
-			__func__);
-		return -ENOMEM;
-	}
-	wake_up_process(sdio_dld->dld_main_thread.dld_task);
-	return 0;
-}
-
-/**
-  * start_timer
-  * sets the timer and starts.
-  *
-  * @timer: the timer to configure and add
-  * @ms: the ms until it expires
-  * @return None.
-  */
-static void start_timer(struct timer_list *timer, unsigned int ms)
-{
-	if ((ms == 0) || (timer == NULL)) {
-		pr_err(MODULE_NAME ": %s - invalid parameter", __func__);
-	} else {
-		timer->expires = jiffies +
-			msecs_to_jiffies(ms);
-		add_timer(timer);
-	}
-}
-
-/**
-  * sdio_dld_timer_handler
-  * this is the timer handler. whenever it is invoked, it wakes
-  * up the main loop task, and the write callback, and starts
-  * the timer again.
-  *
-  * @data: a pointer to the tty device driver structure.
-  * @return None.
-  */
-
-static void sdio_dld_timer_handler(unsigned long data)
-{
-	pr_debug(MODULE_NAME " Timer Expired\n");
-	spin_lock_irqsave(&lock2, lock_flags2);
-	if (sdio_dld->main_loop_event.wake_up_signal == 0) {
-		sdio_dld->main_loop_event.wake_up_signal = 1;
-		wake_up(&sdio_dld->main_loop_event.wait_event);
-	}
-	spin_unlock_irqrestore(&lock2, lock_flags2);
-
-	sdio_dld->write_callback_event.wake_up_signal = 1;
-	wake_up(&sdio_dld->write_callback_event.wait_event);
-
-	start_timer(&sdio_dld->timer, sdio_dld->poll_ms);
-}
-
-/**
-  * sdio_dld_push_timer_handler
-  * this is a timer handler of the push_timer.
-  *
-  * @data: a pointer to the tty device driver structure.
-  * @return None.
-  */
-static void sdio_dld_push_timer_handler(unsigned long data)
-{
-	pr_err(MODULE_NAME " %s - Push Timer Expired... Trying to "
-		"push data to TTY Core for over then %d ms.\n",
-		__func__, sdio_dld->push_timer_ms);
-}
-
-/**
-  * sdio_dld_open
-  * this is the open callback of the tty driver.
-  * it initializes the sdio func, allocates the buffers, and
-  * creates the main thread.
-  *
-  * @tty: a pointer to the tty struct.
-  * @file: file descriptor.
-  * @return 0 on success or negative value on error.
-  */
-static int sdio_dld_open(struct tty_struct *tty, struct file *file)
-{
-	int status = 0;
-	int func_in_array =
-		REAL_FUNC_TO_FUNC_IN_ARRAY(sdio_dld->sdioc_boot_func);
-	struct sdio_func *str_func = sdio_dld->card->sdio_func[func_in_array];
-
-	if (atomic_read(&sdio_dld_in_use) == 1)
-		return -EBUSY;
-
-	atomic_set(&sdio_dld_in_use, 1);
-	sdio_dld->tty_str = tty;
-	sdio_dld->tty_str->low_latency = 1;
-	sdio_dld->tty_str->icanon = 0;
-	set_bit(TTY_NO_WRITE_SPLIT, &sdio_dld->tty_str->flags);
-
-	pr_info(MODULE_NAME ": %s, TTY DEVICE FOR FLASHLESS BOOT OPENED\n",
-	       __func__);
-	sdio_dld_info.start_time = get_jiffies_64(); /* read the current time */
-
-	if (!tty) {
-		pr_err(MODULE_NAME ": %s - param ""tty"" is NULL.\n",
-		       __func__);
-		return -EINVAL;
-	}
-
-	if (!str_func) {
-		pr_err(MODULE_NAME ": %s - param ""str_func"" is NULL.\n",
-		       __func__);
-		return -EINVAL;
-	}
-
-	atomic_set(&sdio_dld->dld_main_thread.please_close, 0);
-	sdio_dld->dld_main_thread.exit_wait.wake_up_signal = 0;
-
-	status = sdio_dld_allocate_buffers(str_func);
-	if (status) {
-		pr_err(MODULE_NAME ": %s, failed in "
-		       "sdio_dld_allocate_buffers(). status=%d\n",
-		       __func__, status);
-		return status;
-	}
-
-	/* init waiting event of the write callback */
-	init_waitqueue_head(&sdio_dld->write_callback_event.wait_event);
-
-	/* init waiting event of the main loop */
-	init_waitqueue_head(&sdio_dld->main_loop_event.wait_event);
-
-	/* configure and init the timer */
-	sdio_dld->poll_ms = TIMER_DURATION;
-	init_timer(&sdio_dld->timer);
-	sdio_dld->timer.data = (unsigned long) sdio_dld;
-	sdio_dld->timer.function = sdio_dld_timer_handler;
-	sdio_dld->timer.expires = jiffies +
-		msecs_to_jiffies(sdio_dld->poll_ms);
-	add_timer(&sdio_dld->timer);
-
-	sdio_dld->push_timer_ms = PUSH_TIMER_DURATION;
-	init_timer(&sdio_dld->push_timer);
-	sdio_dld->push_timer.data = (unsigned long) sdio_dld;
-	sdio_dld->push_timer.function = sdio_dld_push_timer_handler;
-
-	status = sdio_dld_create_thread();
-	if (status) {
-		del_timer_sync(&sdio_dld->timer);
-		del_timer_sync(&sdio_dld->push_timer);
-		sdio_dld_dealloc_local_buffers();
-		pr_err(MODULE_NAME ": %s, failed in sdio_dld_create_thread()."
-				   "status=%d\n", __func__, status);
-		return status;
-	}
-	return 0;
-}
-
-/**
-  * sdio_dld_close
-  * this is the close callback of the tty driver. it requests
-  * the main thread to exit, and waits for notification of it.
-  * it also de-allocates the buffers, and unregisters the tty
-  * driver and device.
-  *
-  * @tty: a pointer to the tty struct.
-  * @file: file descriptor.
-  * @return None.
-  */
-static void sdio_dld_close(struct tty_struct *tty, struct file *file)
-{
-	struct sdioc_reg_chunk *reg = &sdio_dld->sdio_dloader_data.sdioc_reg;
-
-	/* informing the SDIOC that it can exit boot phase */
-	sdio_dld->sdio_dloader_data.sdioc_reg.good_to_exit_ptr.reg_val =
-		SDIOC_EXIT_CODE;
-
-	atomic_set(&sdio_dld->dld_main_thread.please_close, 1);
-
-	pr_debug(MODULE_NAME ": %s - CLOSING - WAITING...", __func__);
-
-	wait_event(sdio_dld->dld_main_thread.exit_wait.wait_event,
-		   sdio_dld->dld_main_thread.exit_wait.wake_up_signal);
-	pr_debug(MODULE_NAME ": %s - CLOSING - WOKE UP...", __func__);
-
-#ifdef CONFIG_DEBUG_FS
-	gd.curr_i = curr_index;
-	gd.duration_ms = sdio_dld_info.time_msec;
-	gd.global_bytes_sent = sdio_dld_info.global_bytes_write_toio;
-	gd.global_bytes_received = 0;
-	gd.throughput_Mbs = sdio_dld_info.throughput;
-	gd.host_outgoing_buffer_size_KB = sdio_dld->sdio_dloader_data.
-		outgoing_data.buffer_size/BYTES_IN_KB;
-	gd.client_up_buffer_size_KB = reg->ul_buff_size.reg_val/BYTES_IN_KB;
-	gd.client_dl_buffer_size_KB = reg->dl_buff_size.reg_val/BYTES_IN_KB;
-	gd.client_dl_buffer_address = reg->dl_buff_address.reg_val;
-	gd.client_up_buffer_address = reg->up_buff_address.reg_val;
-	gd.global_bytes_received = sdio_dld_info.global_bytes_read_fromio;
-	gd.global_bytes_pushed = sdio_dld_info.global_bytes_push_tty;
-#endif
-
-	/* saving register values before deallocating sdio_dld
-	   in order to use it in sdio_dld_print_info() through shell command */
-	sdio_dld_info.cl_dl_rd_ptr = reg->dl_rd_ptr.reg_val;
-	sdio_dld_info.cl_dl_wr_ptr = reg->dl_wr_ptr.reg_val;
-	sdio_dld_info.cl_up_rd_ptr = reg->up_rd_ptr.reg_val;
-	sdio_dld_info.cl_up_wr_ptr = reg->up_wr_ptr.reg_val;
-
-	sdio_dld_info.host_read_ptr =
-		sdio_dld->sdio_dloader_data.outgoing_data.offset_read_p;
-
-	sdio_dld_info.host_write_ptr =
-		sdio_dld->sdio_dloader_data.outgoing_data.offset_write_p;
-
-	sdio_dld_info.cl_dl_buffer_size =
-		sdio_dld->sdio_dloader_data.sdioc_reg.dl_buff_size.reg_val;
-
-	sdio_dld_info.cl_up_buffer_size =
-		sdio_dld->sdio_dloader_data.sdioc_reg.ul_buff_size.reg_val;
-
-	sdio_dld_info.host_outgoing_buffer_size =
-		sdio_dld->sdio_dloader_data.outgoing_data.buffer_size;
-
-	sdio_dld_info.cl_dl_buffer_address =
-		sdio_dld->sdio_dloader_data.sdioc_reg.dl_buff_address.reg_val;
-
-	sdio_dld_info.cl_up_buffer_address =
-		sdio_dld->sdio_dloader_data.sdioc_reg.up_buff_address.reg_val;
-
-	sdio_dld_print_info();
-
-	if (sdio_dld->done_callback)
-		sdio_dld->done_callback();
-
-	schedule_work(&cleanup);
-	pr_info(MODULE_NAME ": %s - Bootloader done, returning...", __func__);
-}
-
-/**
-  * writing_size_to_buf
-  * writes from src buffer into dest buffer. if dest buffer
-  * reaches its end, rollover happens.
-  *
-  * @dest: destination buffer.
-  * @src: source buffer.
-  * @dest_wr_ptr: writing pointer in destination buffer.
-  * @dest_size: destination buffer size.
-  * @dest_rd_ptr: reading pointer in destination buffer.
-  * @size_to_write: size of bytes to write.
-  * @return -how many bytes actually written to destination
-  * buffer.
-  *
-  * ONLY destination buffer is treated as cyclic buffer.
-  */
-static int writing_size_to_buf(char *dest,
-			       const unsigned char *src,
-			       int *dest_wr_ptr,
-			       int dest_size,
-			       int dest_rd_ptr,
-			       int size_to_write)
-{
-	int actually_written = 0;
-	int size_to_add = *dest_wr_ptr;
-
-	if (!dest) {
-		pr_err(MODULE_NAME ": %s - param ""dest"" is NULL.\n",
-		       __func__);
-		return -EINVAL;
-	}
-
-	if (!src) {
-		pr_err(MODULE_NAME ": %s - param ""src"" is NULL.\n",
-		       __func__);
-		return -EINVAL;
-	}
-
-	if (!dest_wr_ptr) {
-		pr_err(MODULE_NAME ": %s - param ""dest_wr_ptr"" is NULL.\n",
-		       __func__);
-		return -EINVAL;
-	}
-
-	for (actually_written = 0 ;
-	      actually_written < size_to_write ; ++actually_written) {
-		/* checking if buffer is full */
-		if (((size_to_add + 1) % dest_size) == dest_rd_ptr) {
-			*dest_wr_ptr = size_to_add;
-			return actually_written;
-		}
-
-		dest[size_to_add] = src[actually_written];
-		size_to_add = (size_to_add+1)%dest_size;
-	}
-
-	*dest_wr_ptr = size_to_add;
-
-	return actually_written;
-}
-
-/**
-  * sdioc_bytes_till_end_of_buffer - this routine calculates how many bytes are
-  * empty/in use. if calculation requires rap around - it will ignore the rap
-  * around and will do the calculation untill the end of the buffer
-  *
-  * @write_ptr: writing pointer.
-  * @read_ptr: reading pointer.
-  * @total_size: buffer size.
-  * @free_bytes: return value-how many free bytes.
-  * @bytes_in_use: return value-how many bytes in use.
-  * @return 0 on success or negative value on error.
-  *
-  * buffer is treated as a cyclic buffer.
-  */
-static int sdioc_bytes_till_end_of_buffer(int write_ptr,
-					  int read_ptr,
-					  int total_size,
-					  int *free_bytes,
-					  int *bytes_in_use)
-{
-	if (!free_bytes) {
-		pr_err(MODULE_NAME ": %s - param ""free_bytes"" is NULL.\n",
-		       __func__);
-		return -EINVAL;
-	}
-
-	if (!bytes_in_use) {
-		pr_err(MODULE_NAME ": %s - param ""bytes_in_use"" is NULL.\n",
-		       __func__);
-		return -EINVAL;
-	}
-
-	if (write_ptr >= read_ptr) {
-		if (read_ptr == 0)
-			*free_bytes = total_size - write_ptr - 1;
-		else
-			*free_bytes = total_size - write_ptr;
-		*bytes_in_use = write_ptr - read_ptr;
-	} else {
-		*bytes_in_use = total_size - read_ptr;
-		*free_bytes = read_ptr - write_ptr - 1;
-	}
-
-	return  0;
-}
-
-/**
-  * sdioc_bytes_free_in_buffer
-  * this routine calculates how many bytes are free in a buffer
-  * and how many are in use, according to its reading and
-  * writing pointer offsets.
-  *
-  * @write_ptr: writing pointer.
-  * @read_ptr: reading pointer.
-  * @total_size: buffer size.
-  * @free_bytes: return value-how many free bytes in buffer.
-  * @bytes_in_use: return value-how many bytes in use in buffer.
-  * @return 0 on success or negative value on error.
-  *
-  * buffer is treated as a cyclic buffer.
-  */
-static int sdioc_bytes_free_in_buffer(int write_ptr,
-				      int read_ptr,
-				      int total_size,
-				      int *free_bytes,
-				      int *bytes_in_use)
-{
-	if (!free_bytes) {
-		pr_err(MODULE_NAME ": %s - param ""free_bytes"" is NULL.\n",
-		       __func__);
-		return -EINVAL;
-	}
-
-	if (!bytes_in_use) {
-		pr_err(MODULE_NAME ": %s - param ""bytes_in_use"" is NULL.\n",
-		       __func__);
-		return -EINVAL;
-	}
-
-	/* if pointers equel - buffers are empty. nothing to read/write */
-
-	if (write_ptr >= read_ptr)
-		*bytes_in_use = write_ptr - read_ptr;
-	else
-		*bytes_in_use = total_size - (read_ptr - write_ptr);
-
-	*free_bytes = total_size - *bytes_in_use - 1;
-
-	return 0;
-}
-
-/*
-* sdio_dld_write_room
-*
-* This is the write_room function of the tty driver.
-*
-* @tty: pointer to tty struct.
-* @return free bytes for write.
-*
-*/
-static int sdio_dld_write_room(struct tty_struct *tty)
-{
-	return sdio_dld->sdio_dloader_data.outgoing_data.buffer_size;
-}
-
-/**
-  * sdio_dld_write_callback
-  * this is the write callback of the tty driver.
-  *
-  * @tty: pointer to tty struct.
-  * @buf: buffer to write from.
-  * @count: number of bytes to write.
-  * @return bytes written or negative value on error.
-  *
-  * if destination buffer has not enough room for the incoming
-  * data, returns an error.
-  */
-static int sdio_dld_write_callback(struct tty_struct *tty,
-				   const unsigned char *buf, int count)
-{
-	struct sdio_data *outgoing = &sdio_dld->sdio_dloader_data.outgoing_data;
-	int dst_free_bytes = 0;
-	int dummy = 0;
-	int status = 0;
-	int bytes_written = 0;
-	int total_written = 0;
-	static int write_retry;
-	int pending_to_write = count;
-
-#ifdef CONFIG_DEBUG_FS
-	debugfs_glob.global_count = count;
-	update_gd(SDIO_DLD_DEBUGFS_CASE_5_CODE);
-#endif
-
-	pr_debug(MODULE_NAME ": %s - WRITING CALLBACK CALLED WITH %d bytes\n",
-		 __func__, count);
-
-	if (!outgoing->data) {
-		pr_err(MODULE_NAME ": %s - param ""outgoing->data"" is NULL.\n",
-		       __func__);
-		return -EINVAL;
-	}
-
-	pr_debug(MODULE_NAME ": %s - WRITE CALLBACK size to write to outgoing"
-		 " buffer %d\n", __func__, count);
-
-	/* as long as there is something to write to outgoing buffer */
-	do {
-		int bytes_to_write = 0;
-		status = sdioc_bytes_free_in_buffer(
-			outgoing->offset_write_p,
-			outgoing->offset_read_p,
-			outgoing->buffer_size,
-			&dst_free_bytes,
-			&dummy);
-
-		if (status) {
-			pr_err(MODULE_NAME ": %s - Failure in Function "
-			       "sdioc_bytes_free_in_buffer(). status=%d\n",
-			       __func__, status);
-			return status;
-		}
-
-		/*
-		 * if there is free room in outgoing buffer
-		 * lock mutex and request trigger notification from the main
-		 * task. unlock mutex, and wait for sinal
-		 */
-		if (dst_free_bytes > 0) {
-			write_retry = 0;
-			/*
-			 * if there is more data to write to outgoing buffer
-			 * than it can receive, wait for signal from main task
-			 */
-			if (pending_to_write > dst_free_bytes) {
-
-				/* sampling updated dst_free_bytes */
-				status = sdioc_bytes_free_in_buffer(
-				outgoing->offset_write_p,
-				outgoing->offset_read_p,
-				outgoing->buffer_size,
-				&dst_free_bytes,
-				&dummy);
-
-				if (status) {
-					pr_err(MODULE_NAME ": %s - Failure in "
-							   "Function "
-					       "sdioc_bytes_free_in_buffer(). "
-					       "status=%d\n", __func__, status);
-					return status;
-				}
-			}
-
-			bytes_to_write = min(pending_to_write, dst_free_bytes);
-			bytes_written =
-				writing_size_to_buf(outgoing->data,
-						    buf+total_written,
-						    &outgoing->offset_write_p,
-						    outgoing->buffer_size,
-						    outgoing->offset_read_p,
-						    bytes_to_write);
-
-			/* keeping sdio_dld_info up to date */
-			sdio_dld_info.host_write_ptr =
-				sdio_dld->sdio_dloader_data.
-					    outgoing_data.offset_write_p;
-
-#ifdef CONFIG_DEBUG_FS
-			debugfs_glob.global_write_tty = bytes_written;
-			update_gd(SDIO_DLD_DEBUGFS_CASE_3_CODE);
-#endif
-			sdio_dld_info.global_bytes_write_tty += bytes_written;
-
-			spin_lock_irqsave(&lock2, lock_flags2);
-			if (sdio_dld->main_loop_event.wake_up_signal == 0) {
-				sdio_dld->main_loop_event.wake_up_signal = 1;
-				wake_up(&sdio_dld->main_loop_event.wait_event);
-			}
-			spin_unlock_irqrestore(&lock2, lock_flags2);
-
-			/*
-			 * although outgoing buffer has enough room, writing
-			 * failed
-			 */
-			if (bytes_written != bytes_to_write) {
-				pr_err(MODULE_NAME ": %s - couldn't write "
-				       "%d bytes to " "outgoing buffer."
-				       "bytes_written=%d\n",
-				       __func__, bytes_to_write,
-				       bytes_written);
-			       return -EIO;
-			}
-
-			total_written += bytes_written;
-			pending_to_write -= bytes_written;
-			outgoing->num_of_bytes_in_use += bytes_written;
-
-			pr_debug(MODULE_NAME ": %s - WRITE CHUNK to outgoing "
-					   "buffer. pending_to_write=%d, "
-					   "outgoing_free_bytes=%d, "
-					   "bytes_written=%d\n",
-				 __func__,
-				 pending_to_write,
-				 dst_free_bytes,
-				 bytes_written);
-
-		} else {
-			write_retry++;
-
-			pr_debug(MODULE_NAME ": %s - WRITE CALLBACK - NO ROOM."
-			       " pending_to_write=%d, write_retry=%d\n",
-				 __func__,
-				 pending_to_write,
-				 write_retry);
-
-			spin_lock_irqsave(&lock1, lock_flags1);
-			sdio_dld->write_callback_event.wake_up_signal = 0;
-			spin_unlock_irqrestore(&lock1, lock_flags1);
-
-			pr_debug(MODULE_NAME ": %s - WRITE CALLBACK - "
-					     "WAITING...", __func__);
-#ifdef CONFIG_DEBUG_FS
-			update_gd(SDIO_DLD_DEBUGFS_CASE_8_CODE);
-#endif
-			wait_event(sdio_dld->write_callback_event.wait_event,
-				   sdio_dld->write_callback_event.
-				   wake_up_signal);
-#ifdef CONFIG_DEBUG_FS
-			update_gd(SDIO_DLD_DEBUGFS_CASE_9_CODE);
-#endif
-			pr_debug(MODULE_NAME ": %s - WRITE CALLBACK - "
-					     "WOKE UP...", __func__);
-		}
-	} while (pending_to_write > 0 && write_retry < WRITE_RETRIES);
-
-	if (pending_to_write > 0) {
-
-		pr_err(MODULE_NAME ": %s - WRITE CALLBACK - pending data is "
-				   "%d out of %d > 0. total written in this "
-				   "callback = %d\n",
-		       __func__, pending_to_write, count, total_written);
-	}
-
-	if (write_retry == WRITE_RETRIES) {
-		pr_err(MODULE_NAME ": %s, write_retry=%d= max\n",
-		       __func__, write_retry);
-	}
-
-#ifdef CONFIG_DEBUG_FS
-	debugfs_glob.global_bytes_cb_tty = total_written;
-	update_gd(SDIO_DLD_DEBUGFS_CASE_10_CODE);
-#endif
-
-	return total_written;
-}
-
-/**
-  * sdio_memcpy_fromio_wrapper -
-  * reads from sdioc, and updats the sdioc registers according
-  * to how many bytes were actually read.
-  *
-  * @str_func: a pointer to func struct.
-  * @client_rd_ptr: sdioc value of downlink read ptr.
-  * @client_wr_ptr: sdioc value of downlink write ptr.
-  * @buffer_to_store: buffer to store incoming data.
-  * @address_to_read: address to start reading from in sdioc.
-  * @size_to_read: size of bytes to read.
-  * @client_buffer_size: sdioc downlink buffer size.
-  * @return 0 on success or negative value on error.
-  */
-static int sdio_memcpy_fromio_wrapper(struct sdio_func *str_func,
-				      unsigned int client_rd_ptr,
-				      unsigned int client_wr_ptr,
-				      void *buffer_to_store,
-				      unsigned int address_to_read_from,
-				      int size_to_read,
-				      int client_buffer_size)
-{
-	int status = 0;
-	struct sdioc_reg_chunk *reg_str =
-		&sdio_dld->sdio_dloader_data.sdioc_reg;
-
-	if (!str_func) {
-		pr_err(MODULE_NAME ": %s - param ""str_func"" is NULL.\n",
-		       __func__);
-		return -EINVAL;
-	}
-
-	if (!buffer_to_store) {
-		pr_err(MODULE_NAME ": %s - param ""buffer_to_store"" is "
-				   "NULL.\n",
-		       __func__);
-		return -EINVAL;
-	}
-
-	if (size_to_read < 0) {
-		pr_err(MODULE_NAME ": %s - invalid size to read=%d\n",
-			__func__, size_to_read);
-		return -EINVAL;
-	}
-
-	sdio_claim_host(str_func);
-
-	pr_debug(MODULE_NAME ": %s, READING DATA - from add %d, "
-			   "size_to_read=%d\n",
-	       __func__, address_to_read_from, size_to_read);
-
-	status = sdio_memcpy_fromio(str_func,
-				    (void *)buffer_to_store,
-				    address_to_read_from,
-				    size_to_read);
-	if (status) {
-		pr_err(MODULE_NAME ": %s - sdio_memcpy_fromio()"
-		       " DATA failed. status=%d.\n",
-		       __func__, status);
-		sdio_release_host(str_func);
-		return status;
-	}
-
-	/* updating an offset according to cyclic buffer size */
-	reg_str->dl_rd_ptr.reg_val =
-		(reg_str->dl_rd_ptr.reg_val + size_to_read) %
-		client_buffer_size;
-	/* keeping sdio_dld_info up to date */
-	sdio_dld_info.cl_dl_rd_ptr = reg_str->dl_rd_ptr.reg_val;
-
-	status = sdio_memcpy_toio(str_func,
-				  reg_str->dl_rd_ptr.reg_offset,
-				  (void *)&reg_str->dl_rd_ptr.reg_val,
-				  sizeof(reg_str->dl_rd_ptr.reg_val));
-
-	if (status) {
-		pr_err(MODULE_NAME ": %s - sdio_memcpy_toio() "
-		       "UPDATE PTR failed. status=%d.\n",
-		       __func__, status);
-	}
-
-	sdio_release_host(str_func);
-	return status;
-}
-
-/**
-  * sdio_memcpy_toio_wrapper
-  * writes to sdioc, and updats the sdioc registers according
-  * to how many bytes were actually read.
-  *
-  * @str_func: a pointer to func struct.
-  * @client_wr_ptr: sdioc downlink write ptr.
-  * @h_read_ptr: host incoming read ptrs
-  * @buf_write_from: buffer to write from.
-  * @bytes_to_write: number of bytes to write.
-  * @return 0 on success or negative value on error.
-  */
-static int sdio_memcpy_toio_wrapper(struct sdio_func *str_func,
-				    unsigned int client_wr_ptr,
-				    unsigned int h_read_ptr,
-				    void *buf_write_from,
-				    int bytes_to_write)
-{
-	int status = 0;
-	struct sdioc_reg_chunk *reg_str =
-		&sdio_dld->sdio_dloader_data.sdioc_reg;
-	struct sdio_data *outgoing = &sdio_dld->sdio_dloader_data.outgoing_data;
-
-	if (!str_func) {
-		pr_err(MODULE_NAME ": %s - param ""str_func"" is NULL.\n",
-		       __func__);
-		return -EINVAL;
-	}
-
-	if (!buf_write_from) {
-		pr_err(MODULE_NAME ": %s - param ""buf_write_from"" is NULL.\n",
-		       __func__);
-		return -EINVAL;
-	}
-
-	sdio_claim_host(str_func);
-
-	pr_debug(MODULE_NAME ": %s, WRITING DATA TOIO to address 0x%x, "
-		 "bytes_to_write=%d\n",
-		 __func__,
-		reg_str->up_buff_address.reg_val + reg_str->up_wr_ptr.reg_val,
-		 bytes_to_write);
-
-	status = sdio_memcpy_toio(str_func,
-				  reg_str->up_buff_address.reg_val +
-				  reg_str->up_wr_ptr.reg_val,
-				  (void *) (outgoing->data + h_read_ptr),
-				  bytes_to_write);
-
-	if (status) {
-		pr_err(MODULE_NAME ": %s - sdio_memcpy_toio() "
-		       "DATA failed. status=%d.\n", __func__, status);
-		sdio_release_host(str_func);
-		return status;
-	}
-
-	sdio_dld_info.global_bytes_write_toio += bytes_to_write;
-	outgoing->num_of_bytes_in_use -= bytes_to_write;
-
-	/*
-	 * if writing to client succeeded, then
-	 * 1. update the client up_wr_ptr
-	 * 2. update the host outgoing rd ptr
-	 **/
-	reg_str->up_wr_ptr.reg_val =
-		((reg_str->up_wr_ptr.reg_val + bytes_to_write) %
-		 reg_str->ul_buff_size.reg_val);
-
-	/* keeping sdio_dld_info up to date */
-	sdio_dld_info.cl_up_wr_ptr = reg_str->up_wr_ptr.reg_val;
-
-	outgoing->offset_read_p =
-		((outgoing->offset_read_p + bytes_to_write) %
-		  outgoing->buffer_size);
-
-	/* keeping sdio_dld_info up to date*/
-	sdio_dld_info.host_read_ptr = outgoing->offset_read_p;
-
-#ifdef CONFIG_DEBUG_FS
-	debugfs_glob.global_write_toio = bytes_to_write;
-	update_gd(SDIO_DLD_DEBUGFS_CASE_4_CODE);
-#endif
-
-	/* updating uplink write pointer according to size that was written */
-	status = sdio_memcpy_toio(str_func,
-				  reg_str->up_wr_ptr.reg_offset,
-				  (void *)(&reg_str->up_wr_ptr.reg_val),
-				  sizeof(reg_str->up_wr_ptr.reg_val));
-	if (status) {
-		pr_err(MODULE_NAME ": %s - sdio_memcpy_toio() "
-				       "UPDATE PTR failed. status=%d.\n",
-		       __func__, status);
-	}
-
-	sdio_release_host(str_func);
-	return status;
-}
-
-/**
-  * sdio_dld_read
-  * reads from sdioc
-  *
-  * @client_rd_ptr: sdioc downlink read ptr.
-  * @client_wr_ptr: sdioc downlink write ptr.
-  * @reg_str: sdioc register shadowing struct.
-  * @str_func: a pointer to func struct.
-  * @bytes_read:how many bytes read.
-  * @return 0 on success or negative value on error.
-  */
-static int sdio_dld_read(unsigned int client_rd_ptr,
-			 unsigned int client_wr_ptr,
-			 struct sdioc_reg_chunk *reg_str,
-			 struct sdio_func *str_func,
-			 int *bytes_read)
-{
-	int status = 0;
-	struct sdio_data *incoming = &sdio_dld->sdio_dloader_data.incoming_data;
-
-	if (!reg_str) {
-		pr_err(MODULE_NAME ": %s - param ""reg_str"" is NULL.\n",
-		       __func__);
-		return -EINVAL;
-	}
-
-	if (!str_func) {
-		pr_err(MODULE_NAME ": %s - param ""str_func"" is NULL.\n",
-		       __func__);
-		return -EINVAL;
-	}
-
-	if (!bytes_read) {
-		pr_err(MODULE_NAME ": %s - param ""bytes_read"" is NULL.\n",
-		       __func__);
-		return -EINVAL;
-	}
-
-	/* there is data to read in ONE chunk */
-	if (client_wr_ptr > client_rd_ptr) {
-		status = sdio_memcpy_fromio_wrapper(
-			str_func,
-			client_rd_ptr,
-			client_wr_ptr,
-			(void *)incoming->data,
-			reg_str->dl_buff_address.reg_val + client_rd_ptr,
-			client_wr_ptr - client_rd_ptr,
-			reg_str->dl_buff_size.reg_val);
-
-		if (status) {
-			pr_err(MODULE_NAME ": %s - Failure in Function "
-			       "sdio_memcpy_fromio_wrapper(). "
-			       "SINGLE CHUNK READ. status=%d\n",
-			       __func__, status);
-			return status;
-		}
-
-		incoming->num_of_bytes_in_use += client_wr_ptr - client_rd_ptr;
-		*bytes_read = client_wr_ptr - client_rd_ptr;
-
-#ifdef CONFIG_DEBUG_FS
-			debugfs_glob.global_to_read =
-				client_wr_ptr - client_rd_ptr;
-			update_gd(SDIO_DLD_DEBUGFS_CASE_11_CODE);
-#endif
-	}
-
-	/* there is data to read in TWO chunks */
-	else {
-		int dl_buf_size = reg_str->dl_buff_size.reg_val;
-		int tail_size = dl_buf_size - client_rd_ptr;
-
-		/* reading chunk#1: from rd_ptr to the end of the buffer */
-		status = sdio_memcpy_fromio_wrapper(
-			str_func,
-			client_rd_ptr,
-			dl_buf_size,
-			(void *)incoming->data,
-			reg_str->dl_buff_address.reg_val + client_rd_ptr,
-			tail_size,
-			dl_buf_size);
-
-		if (status) {
-			pr_err(MODULE_NAME ": %s - Failure in Function "
-			       "sdio_memcpy_fromio_wrapper(). "
-			       "1 of 2 CHUNKS READ. status=%d\n",
-			       __func__, status);
-			return status;
-		}
-
-		incoming->num_of_bytes_in_use += tail_size;
-		*bytes_read = tail_size;
-
-#ifdef CONFIG_DEBUG_FS
-			debugfs_glob.global_to_read = tail_size;
-			update_gd(SDIO_DLD_DEBUGFS_CASE_11_CODE);
-#endif
-
-		/* reading chunk#2: reading from beginning buffer */
-		status = sdio_memcpy_fromio_wrapper(
-			str_func,
-			client_rd_ptr,
-			client_wr_ptr,
-			(void *)(incoming->data + tail_size),
-			reg_str->dl_buff_address.reg_val,
-			client_wr_ptr,
-			reg_str->dl_buff_size.reg_val);
-
-		if (status) {
-			pr_err(MODULE_NAME ": %s - Failure in Function "
-			       "sdio_memcpy_fromio_wrapper(). "
-			       "2 of 2 CHUNKS READ. status=%d\n",
-			       __func__, status);
-			return status;
-		}
-
-		incoming->num_of_bytes_in_use += client_wr_ptr;
-		*bytes_read += client_wr_ptr;
-
-#ifdef CONFIG_DEBUG_FS
-			debugfs_glob.global_to_read = client_wr_ptr;
-			update_gd(SDIO_DLD_DEBUGFS_CASE_11_CODE);
-#endif
-	}
-	return 0;
-}
-
-/**
-  * sdio_dld_main_task
-  * sdio downloader main task. reads mailboxf checks if there is
-  * anything to read, checks if host has anything to
-  * write.
-  *
-  * @card: a pointer to mmc_card.
-  * @return 0 on success or negative value on error.
-  */
-static int sdio_dld_main_task(void *card)
-{
-	int status = 0;
-	struct tty_struct *tty = sdio_dld->tty_str;
-	struct sdioc_reg_chunk *reg_str =
-		&sdio_dld->sdio_dloader_data.sdioc_reg;
-	int func = sdio_dld->sdioc_boot_func;
-	struct sdio_func *str_func = NULL;
-	struct sdio_data *outgoing = &sdio_dld->sdio_dloader_data.outgoing_data;
-	struct sdio_data *incoming = &sdio_dld->sdio_dloader_data.incoming_data;
-	struct sdio_dld_task *task = &sdio_dld->dld_main_thread;
-	int retries = 0;
-#ifdef PUSH_STRING
-	int bytes_pushed = 0;
-#endif
-
-	msleep(SLEEP_MS);
-
-	if (!card) {
-		pr_err(MODULE_NAME ": %s - param ""card"" is NULL.\n",
-		       __func__);
-		return -EINVAL;
-	}
-
-	if (!tty) {
-		pr_err(MODULE_NAME ": %s - param ""tty"" is NULL.\n",
-		       __func__);
-		return -EINVAL;
-	}
-
-	str_func = ((struct mmc_card *)card)->
-		sdio_func[REAL_FUNC_TO_FUNC_IN_ARRAY(func)];
-
-	if (!str_func) {
-		pr_err(MODULE_NAME ": %s - param ""str_func"" is NULL.\n",
-		       __func__);
-		return -EINVAL;
-	}
-
-	while (true) {
-		/* client pointers for both buffers */
-		int client_ul_wr_ptr = 0;
-		int client_ul_rd_ptr = 0;
-		int client_dl_wr_ptr = 0;
-		int client_dl_rd_ptr = 0;
-
-		/* host pointer for outgoing buffer */
-		int h_out_wr_ptr = 0;
-		int h_out_rd_ptr = 0;
-
-		int h_bytes_rdy_wr = 0;
-		int c_bytes_rdy_rcve = 0;
-
-		int need_to_write = 0;
-		int need_to_read = 0;
-
-		/*
-		 * forever, checking for signal to die, then read MailBox.
-		 * if nothing to read or nothing to write to client, sleep,
-		 * and again read MailBox
-		 */
-		do {
-			int dummy = 0;
-
-			/*  checking if a signal to die was sent */
-			if (atomic_read(&task->please_close) == 1) {
-
-				pr_debug(MODULE_NAME ": %s - 0x%x was written "
-					 "to 9K\n", __func__, SDIOC_EXIT_CODE);
-
-				sdio_claim_host(str_func);
-
-				/* returned value is not checked on purpose */
-				sdio_memcpy_toio(
-					str_func,
-					reg_str->good_to_exit_ptr.reg_offset,
-					(void *)&reg_str->good_to_exit_ptr.
-					reg_val,
-					sizeof(reg_str->good_to_exit_ptr.
-					       reg_val));
-
-				sdio_release_host(str_func);
-
-				task->exit_wait.wake_up_signal = 1;
-				wake_up(&task->exit_wait.wait_event);
-				return 0;
-			}
-
-			status = mailbox_to_seq_chunk_read_ptrs(str_func);
-			if (status) {
-				pr_err(MODULE_NAME ": %s - Failure in Function "
-				       "mailbox_to_seq_chunk_read_ptrs(). "
-				       "status=%d\n", __func__, status);
-				return status;
-			}
-
-			/* calculate how many bytes the host has send */
-			h_out_wr_ptr = outgoing->offset_write_p;
-			h_out_rd_ptr = outgoing->offset_read_p;
-
-			status = sdioc_bytes_till_end_of_buffer(
-				h_out_wr_ptr,
-				h_out_rd_ptr,
-				outgoing->buffer_size,
-				&dummy,
-				&h_bytes_rdy_wr);
-
-			if (status) {
-				pr_err(MODULE_NAME ": %s - Failure in Function "
-				       "sdioc_bytes_till_end_of_buffer(). "
-				       "status=%d\n", __func__, status);
-				return status;
-			}
-
-			/* is there something to read from client */
-			client_dl_wr_ptr = reg_str->dl_wr_ptr.reg_val;
-			client_dl_rd_ptr = reg_str->dl_rd_ptr.reg_val;
-
-			if (client_dl_rd_ptr != client_dl_wr_ptr)
-				need_to_read = 1;
-
-			/*
-			 *  calculate how many bytes the client can receive
-			 *  from host
-			 */
-			client_ul_wr_ptr = reg_str->up_wr_ptr.reg_val;
-			client_ul_rd_ptr = reg_str->up_rd_ptr.reg_val;
-
-			status = sdioc_bytes_till_end_of_buffer(
-				client_ul_wr_ptr,
-				client_ul_rd_ptr,
-				reg_str->ul_buff_size.reg_val,
-				&c_bytes_rdy_rcve,
-				&dummy);
-
-			if (status) {
-				pr_err(MODULE_NAME ": %s - Failure in Function "
-				       "sdioc_bytes_till_end_of_buffer(). "
-				       "status=%d\n", __func__, status);
-				return status;
-			}
-
-			/* if host has anything to write */
-			if (h_bytes_rdy_wr > 0)
-				need_to_write = 1;
-
-			if (need_to_write || need_to_read)
-				break;
-
-			spin_lock_irqsave(&lock2, lock_flags2);
-			sdio_dld->main_loop_event.wake_up_signal = 0;
-			spin_unlock_irqrestore(&lock2, lock_flags2);
-
-			pr_debug(MODULE_NAME ": %s - MAIN LOOP - WAITING...\n",
-				 __func__);
-#ifdef CONFIG_DEBUG_FS
-			update_gd(SDIO_DLD_DEBUGFS_CASE_6_CODE);
-#endif
-			wait_event(sdio_dld->main_loop_event.wait_event,
-				   sdio_dld->main_loop_event.wake_up_signal);
-#ifdef CONFIG_DEBUG_FS
-			update_gd(SDIO_DLD_DEBUGFS_CASE_7_CODE);
-#endif
-
-			pr_debug(MODULE_NAME ": %s - MAIN LOOP - WOKE UP...\n",
-				 __func__);
-
-		} while (1);
-
-		/* CHECK IF THERE IS ANYTHING TO READ IN CLIENT */
-		if (need_to_read) {
-#ifdef PUSH_STRING
-			int num_push = 0;
-			int left = 0;
-			int bytes_read;
-#else
-			int i;
-#endif
-			need_to_read = 0;
-
-			status = sdio_dld_read(client_dl_rd_ptr,
-					       client_dl_wr_ptr,
-					       reg_str,
-					       str_func,
-					       &bytes_read);
-
-			if (status) {
-				pr_err(MODULE_NAME ": %s - Failure in Function "
-				       "sdio_dld_read(). status=%d\n",
-				       __func__, status);
-				return status;
-			}
-
-			sdio_dld_info.global_bytes_read_fromio +=
-				bytes_read;
-
-			bytes_pushed = 0;
-#ifdef PUSH_STRING
-			left = incoming->num_of_bytes_in_use;
-			start_timer(&sdio_dld->push_timer,
-				    sdio_dld->push_timer_ms);
-			do {
-				num_push = tty_insert_flip_string(
-					tty,
-					incoming->data+bytes_pushed,
-					left);
-
-				bytes_pushed += num_push;
-				left -= num_push;
-				tty_flip_buffer_push(tty);
-			} while (left != 0);
-
-			del_timer(&sdio_dld->push_timer);
-
-			if (bytes_pushed != incoming->num_of_bytes_in_use) {
-				pr_err(MODULE_NAME ": %s - failed\n",
-				       __func__);
-			}
-#else
-			pr_debug(MODULE_NAME ": %s - NEED TO READ %d\n",
-			       __func__, incoming->num_of_bytes_in_use);
-
-			for (i = 0 ; i < incoming->num_of_bytes_in_use ; ++i) {
-				int err = 0;
-				err = tty_insert_flip_char(tty,
-							   incoming->data[i],
-							   TTY_NORMAL);
-				tty_flip_buffer_push(tty);
-			}
-
-			pr_debug(MODULE_NAME ": %s - JUST READ\n", __func__);
-#endif /*PUSH_STRING*/
-			sdio_dld_info.global_bytes_push_tty +=
-				incoming->num_of_bytes_in_use;
-#ifdef CONFIG_DEBUG_FS
-			debugfs_glob.global_push_to_tty = bytes_read;
-			update_gd(SDIO_DLD_DEBUGFS_CASE_12_CODE);
-#endif
-			incoming->num_of_bytes_in_use = 0;
-			tty_flip_buffer_push(tty);
-		}
-
-		/* CHECK IF THERE IS ANYTHING TO WRITE IN HOST AND HOW MUCH */
-		if (need_to_write) {
-			int dummy = 0;
-
-			do {
-				int bytes_to_write = min(c_bytes_rdy_rcve,
-							 h_bytes_rdy_wr);
-
-				/*
-				 * in case nothing to send or no room to
-				 * receive
-				 */
-				if (bytes_to_write == 0)
-					break;
-
-				if (client_ul_rd_ptr == 0 &&
-				    (client_ul_rd_ptr != client_ul_wr_ptr))
-					break;
-
-				/*
-				 * if client_rd_ptr points to start, but there
-				 * is data to read wait until WRITE_TILL_END
-				 * before writing a chunk of data, to avoid
-				 * writing until (BUF_SIZE - 1), because it will
-				 * yield an extra write of "1" bytes
-				 */
-				if (client_ul_rd_ptr == 0 &&
-				    (client_ul_rd_ptr != client_ul_wr_ptr) &&
-				    retries < WRITE_TILL_END_RETRIES) {
-					retries++;
-					break;
-				}
-				retries = 0;
-
-#ifdef CONFIG_DEBUG_FS
-				debugfs_glob.global_8k_has = h_bytes_rdy_wr;
-				debugfs_glob.global_9k_has = c_bytes_rdy_rcve;
-				debugfs_glob.global_min = bytes_to_write;
-				update_gd(SDIO_DLD_DEBUGFS_CASE_2_CODE);
-#endif
-				need_to_write = 0;
-
-				pr_debug(MODULE_NAME ": %s - NEED TO WRITE "
-					 "TOIO %d\n",
-					 __func__, bytes_to_write);
-
-				status = sdio_memcpy_toio_wrapper(
-					str_func,
-					reg_str->up_wr_ptr.reg_val,
-					outgoing->offset_read_p,
-					(void *)((char *)outgoing->data +
-						 outgoing->offset_read_p),
-					bytes_to_write);
-
-				if (status) {
-					pr_err(MODULE_NAME ": %s - Failure in "
-					       "Function "
-					       "sdio_memcpy_toio_wrapper(). "
-					       "SINGLE CHUNK WRITE. "
-					       "status=%d\n",
-					       __func__, status);
-					return status;
-				}
-
-				sdio_claim_host(str_func);
-
-				status = sdio_memcpy_fromio(
-					str_func,
-					(void *)&reg_str->up_rd_ptr.reg_val,
-					SDIOC_UL_RD_PTR,
-					sizeof(reg_str->up_rd_ptr.reg_val));
-
-				if (status) {
-					pr_err(MODULE_NAME ": %s - "
-					       "sdio_memcpy_fromio() "
-					       "failed. status=%d\n",
-					       __func__, status);
-					sdio_release_host(str_func);
-
-					return status;
-				}
-
-				sdio_release_host(str_func);
-
-				spin_lock_irqsave(&lock1, lock_flags1);
-				if (sdio_dld->write_callback_event.
-				    wake_up_signal == 0) {
-					sdio_dld->write_callback_event.
-						wake_up_signal = 1;
-					wake_up(&sdio_dld->
-						write_callback_event.
-						wait_event);
-				}
-
-				spin_unlock_irqrestore(&lock1, lock_flags1);
-				client_ul_wr_ptr = reg_str->up_wr_ptr.reg_val;
-				client_ul_rd_ptr = reg_str->up_rd_ptr.reg_val;
-
-				status = sdioc_bytes_till_end_of_buffer(
-					client_ul_wr_ptr,
-					client_ul_rd_ptr,
-					reg_str->ul_buff_size.reg_val,
-					&c_bytes_rdy_rcve,
-					&dummy);
-
-				/* calculate how many bytes host has to send */
-				h_out_wr_ptr = outgoing->offset_write_p;
-				h_out_rd_ptr = outgoing->offset_read_p;
-
-				status = sdioc_bytes_till_end_of_buffer(
-					h_out_wr_ptr,
-					h_out_rd_ptr,
-					outgoing->buffer_size,
-					&dummy,
-					&h_bytes_rdy_wr);
-
-			} while (h_out_wr_ptr != h_out_rd_ptr);
-		}
-	}
-	return 0;
-}
-
-/**
-  * sdio_dld_init_global
-  * initialization of sdio_dld global struct
-  *
-  * @card: a pointer to mmc_card.
-  * @return 0 on success or negative value on error.
-  */
-static int sdio_dld_init_global(struct mmc_card *card,
-				int(*done)(void))
-{
-	if (!card) {
-		pr_err(MODULE_NAME ": %s - param ""card"" is NULL.\n",
-		       __func__);
-		return -EINVAL;
-	}
-
-	if (!done) {
-		pr_err(MODULE_NAME ": %s - param ""done"" is NULL.\n",
-		       __func__);
-		return -EINVAL;
-	}
-
-	sdio_dld->done_callback = done;
-	sdio_dld->card = card;
-	init_waitqueue_head(&sdio_dld->dld_main_thread.exit_wait.wait_event);
-	sdio_dld->write_callback_event.wake_up_signal = 1;
-	sdio_dld->main_loop_event.wake_up_signal = 1;
-
-	sdio_dld->sdio_dloader_data.sdioc_reg.dl_buff_size.reg_offset =
-		SDIOC_DL_BUFF_SIZE_OFFSET;
-
-	sdio_dld->sdio_dloader_data.sdioc_reg.dl_rd_ptr.reg_offset =
-		SDIOC_DL_RD_PTR;
-
-	sdio_dld->sdio_dloader_data.sdioc_reg.dl_wr_ptr.reg_offset =
-		SDIOC_DL_WR_PTR;
-
-	sdio_dld->sdio_dloader_data.sdioc_reg.ul_buff_size.reg_offset =
-		SDIOC_UP_BUFF_SIZE_OFFSET;
-
-	sdio_dld->sdio_dloader_data.sdioc_reg.up_rd_ptr.reg_offset =
-		SDIOC_UL_RD_PTR;
-
-	sdio_dld->sdio_dloader_data.sdioc_reg.up_wr_ptr.reg_offset =
-		SDIOC_UL_WR_PTR;
-
-	sdio_dld->sdio_dloader_data.sdioc_reg.good_to_exit_ptr.reg_offset =
-		SDIOC_EXIT_PTR;
-
-	sdio_dld->sdio_dloader_data.sdioc_reg.dl_buff_address.reg_offset =
-		SDIOC_DL_BUFF_ADDRESS;
-
-	sdio_dld->sdio_dloader_data.sdioc_reg.up_buff_address.reg_offset =
-		SDIOC_UP_BUFF_ADDRESS;
-
-	sdio_dld_set_op_mode(SDIO_DLD_NORMAL_MODE);
-
-	return 0;
-}
-
-/**
- * sdio_downloader_setup
- * initializes the TTY driver
- *
- * @card: a pointer to mmc_card.
- * @num_of_devices: number of devices.
- * @channel_number: channel number.
- * @return 0 on success or negative value on error.
- *
- * The TTY stack needs to know in advance how many devices it should
- * plan to manage. Use this call to set up the ports that will
- * be exported through SDIO.
- */
-int sdio_downloader_setup(struct mmc_card *card,
-			  unsigned int num_of_devices,
-			  int channel_number,
-			  int(*done)(void))
-{
-	int status = 0;
-	int result = 0;
-	int func_in_array = 0;
-	struct sdio_func *str_func = NULL;
-	struct device *tty_dev;
-
-	if (atomic_read(&sdio_dld_in_use) == 1)
-		return -EBUSY;
-
-	/*
-	 * If the setup is already complete tear down the existing
-	 * one and reinitialize. This might happen during modem restarts
-	 * in boot phase.
-	 */
-	if (atomic_read(&sdio_dld_setup_done) == 1)
-		sdio_dld_tear_down(NULL);
-
-	if (num_of_devices == 0 || num_of_devices > MAX_NUM_DEVICES) {
-		pr_err(MODULE_NAME ": %s - invalid number of devices\n",
-		       __func__);
-		return -EINVAL;
-	}
-
-	if (!card) {
-		pr_err(MODULE_NAME ": %s - param ""card"" is NULL.\n",
-		       __func__);
-		return -EINVAL;
-	}
-
-	if (!done) {
-		pr_err(MODULE_NAME ": %s - param ""done"" is NULL.\n",
-		       __func__);
-		return -EINVAL;
-	}
-
-	sdio_dld = kzalloc(sizeof(struct sdio_downloader), GFP_KERNEL);
-	if (!sdio_dld) {
-		pr_err(MODULE_NAME ": %s - couldn't allocate sdio_dld data "
-		       "structure.", __func__);
-		return -ENOMEM;
-	}
-
-#ifdef CONFIG_DEBUG_FS
-	bootloader_debugfs_init();
-#endif /* CONFIG_DEBUG_FS */
-
-	status = sdio_dld_init_global(card, done);
-
-	if (status) {
-		pr_err(MODULE_NAME ": %s - Failure in Function "
-		       "sdio_dld_init_global(). status=%d\n",
-		       __func__, status);
-		kfree(sdio_dld);
-		return status;
-	}
-
-	sdio_dld->tty_drv = alloc_tty_driver(num_of_devices);
-
-	if (!sdio_dld->tty_drv) {
-		pr_err(MODULE_NAME ": %s - param ""sdio_dld->tty_drv"" is "
-				   "NULL.\n", __func__);
-		kfree(sdio_dld);
-		return -EINVAL;
-	}
-
-	sdio_dld_set_op_mode((enum sdio_dld_op_mode)sdio_op_mode);
-
-	/* according to op_mode, a different tty device is created */
-	if (sdio_dld->op_mode == SDIO_DLD_BOOT_TEST_MODE)
-		sdio_dld->tty_drv->name = TTY_SDIO_DEV_TEST;
-	else
-	    sdio_dld->tty_drv->name = TTY_SDIO_DEV;
-
-	sdio_dld->tty_drv->owner = THIS_MODULE;
-	sdio_dld->tty_drv->driver_name = "SDIO_Dloader";
-
-	/* uses dynamically assigned dev_t values */
-	sdio_dld->tty_drv->type = TTY_DRIVER_TYPE_SERIAL;
-	sdio_dld->tty_drv->subtype = SERIAL_TYPE_NORMAL;
-	sdio_dld->tty_drv->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV
-				| TTY_DRIVER_RESET_TERMIOS;
-
-	/* initializing the tty driver */
-	sdio_dld->tty_drv->init_termios = tty_std_termios;
-	sdio_dld->tty_drv->init_termios.c_cflag =
-		B4800 | CS8 | CREAD | HUPCL | CLOCAL;
-	sdio_dld->tty_drv->init_termios.c_ispeed = INPUT_SPEED;
-	sdio_dld->tty_drv->init_termios.c_ospeed = OUTPUT_SPEED;
-
-	tty_set_operations(sdio_dld->tty_drv, &sdio_dloader_tty_ops);
-
-	status = tty_register_driver(sdio_dld->tty_drv);
-	if (status) {
-		put_tty_driver(sdio_dld->tty_drv);
-		pr_err(MODULE_NAME ": %s - tty_register_driver() failed\n",
-			__func__);
-
-		sdio_dld->tty_drv = NULL;
-		kfree(sdio_dld);
-		return status;
-	}
-
-	tty_dev = tty_register_device(sdio_dld->tty_drv, 0, NULL);
-	if (IS_ERR(tty_dev)) {
-		pr_err(MODULE_NAME ": %s - tty_register_device() "
-			"failed\n", __func__);
-		tty_unregister_driver(sdio_dld->tty_drv);
-		put_tty_driver(sdio_dld->tty_drv);
-		kfree(sdio_dld);
-		return PTR_ERR(tty_dev);
-	}
-
-	sdio_dld->sdioc_boot_func = SDIOC_CHAN_TO_FUNC_NUM(channel_number);
-	func_in_array = REAL_FUNC_TO_FUNC_IN_ARRAY(sdio_dld->sdioc_boot_func);
-	str_func = sdio_dld->card->sdio_func[func_in_array];
-	status = sdio_dld_init_func(str_func);
-	if (status) {
-		pr_err(MODULE_NAME ": %s - Failure in Function "
-		       "sdio_dld_init_func(). status=%d\n",
-		       __func__, status);
-		goto exit_err;
-	}
-
-#ifdef CONFIG_DEBUG_FS
-	sdio_dld_debug_init();
-#endif
-
-	sdio_claim_host(str_func);
-
-	/*
-	 * notifing the client by writing what mode we are by writing
-	 * to a special register
-	 */
-	status = sdio_memcpy_toio(str_func,
-				  SDIOC_OP_MODE_PTR,
-				  (void *)&sdio_dld->op_mode,
-				  sizeof(sdio_dld->op_mode));
-
-	sdio_release_host(str_func);
-
-	if (status) {
-		pr_err(MODULE_NAME ": %s - sdio_memcpy_toio() "
-		       "writing to OP_MODE_REGISTER failed. "
-		       "status=%d.\n",
-		       __func__, status);
-		goto exit_err;
-	}
-
-	atomic_set(&sdio_dld_setup_done, 1);
-	return 0;
-
-exit_err:
-	tty_unregister_device(sdio_dld->tty_drv, 0);
-	result = tty_unregister_driver(sdio_dld->tty_drv);
-	if (result)
-		pr_err(MODULE_NAME ": %s - tty_unregister_driver() "
-		       "failed. result=%d\n", __func__, -result);
-	put_tty_driver(sdio_dld->tty_drv);
-	kfree(sdio_dld);
-	atomic_set(&sdio_dld_setup_done, 0);
-	return status;
-}
-
-static void sdio_dld_tear_down(struct work_struct *work)
-{
-	int status = 0;
-
-	if (atomic_read(&sdio_dld_in_use) == 1) {
-		del_timer_sync(&sdio_dld->timer);
-		del_timer_sync(&sdio_dld->push_timer);
-		sdio_dld_dealloc_local_buffers();
-	}
-
-	tty_unregister_device(sdio_dld->tty_drv, 0);
-
-	status = tty_unregister_driver(sdio_dld->tty_drv);
-	if (status) {
-		pr_err(MODULE_NAME ": %s - tty_unregister_driver() failed\n",
-		       __func__);
-	}
-
-	put_tty_driver(sdio_dld->tty_drv);
-	kfree(sdio_dld);
-	atomic_set(&sdio_dld_in_use, 0);
-	atomic_set(&sdio_dld_setup_done, 0);
-}
-
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("SDIO Downloader");
-MODULE_AUTHOR("Yaniv Gardi <ygardi@codeaurora.org>");
-MODULE_VERSION(DRV_VERSION);
-
diff --git a/arch/arm/mach-msm/sdio_al_private.h b/arch/arm/mach-msm/sdio_al_private.h
deleted file mode 100644
index 3a5ab79..0000000
--- a/arch/arm/mach-msm/sdio_al_private.h
+++ /dev/null
@@ -1,267 +0,0 @@
-/* Copyright (c) 2011, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
-
-/*
- * SDIO-Abstraction-Layer internal interface.
- */
-
-#ifndef __SDIO_AL_PRIVATE__
-#define __SDIO_AL_PRIVATE__
-
-#include <linux/mmc/card.h>
-#include <linux/platform_device.h>
-#include <mach/sdio_al.h>
-
-#define DRV_VERSION "1.30"
-#define MODULE_NAME "sdio_al"
-#define SDIOC_CHAN_TO_FUNC_NUM(x)	((x)+2)
-#define REAL_FUNC_TO_FUNC_IN_ARRAY(x)	((x)-1)
-#define SDIO_PREFIX "SDIO_"
-#define PEER_CHANNEL_NAME_SIZE		4
-#define CHANNEL_NAME_SIZE (sizeof(SDIO_PREFIX) + PEER_CHANNEL_NAME_SIZE)
-#define SDIO_TEST_POSTFIX_SIZE 5
-#define MAX_NUM_OF_SDIO_DEVICES	2
-#define TEST_CH_NAME_SIZE (CHANNEL_NAME_SIZE + SDIO_TEST_POSTFIX_SIZE)
-
-struct sdio_al_device; /* Forward Declaration */
-
-enum sdio_channel_state {
-	SDIO_CHANNEL_STATE_INVALID,	 /* before reading software header */
-	SDIO_CHANNEL_STATE_IDLE,         /* channel valid, not opened    */
-	SDIO_CHANNEL_STATE_CLOSED,       /* was closed */
-	SDIO_CHANNEL_STATE_OPEN,	 /* opened */
-	SDIO_CHANNEL_STATE_CLOSING,      /* during flush, when closing */
-};
-/**
- * Peer SDIO-Client channel configuration.
- *
- *  @is_ready - channel is ready and the data is valid.
- *
- *  @max_rx_threshold - maximum rx threshold, according to the
- *		total buffers size on the peer pipe.
- *  @max_tx_threshold - maximum tx threshold, according to the
- *		total buffers size on the peer pipe.
- *  @tx_buf_size - size of a single buffer on the peer pipe; a
- *		transfer smaller than the buffer size still
- *		make the buffer unusable for the next transfer.
- * @max_packet_size
- * @is_host_ok_to_sleep - Host marks this bit when it's okay to
- *		sleep (no pending transactions)
- */
-struct peer_sdioc_channel_config {
-	u32 is_ready;
-	u32 max_rx_threshold; /* Downlink */
-	u32 max_tx_threshold; /* Uplink */
-	u32 tx_buf_size;
-	u32 max_packet_size;
-	u32 is_host_ok_to_sleep;
-	u32 is_packet_mode;
-	u32 peer_operation;
-	u32 is_low_latency_ch;
-	u32 reserved[23];
-};
-
-
-/**
- * Peer SDIO-Client channel statsitics.
- *
- * @last_any_read_avail - the last read avail in all the
- *		 channels including this channel.
- * @last_read_avail - the last read_avail that was read from HW
- *	    mailbox.
- * @last_old_read_avail - the last read_avail channel shadow.
- * @total_notifs - the total number of read notifications sent
- *	 to this channel client
- * @total_read_times - the total number of successful sdio_read
- *	     calls for this channel
- */
-struct sdio_channel_statistics {
-	int last_any_read_avail;
-	int last_read_avail;
-	int last_old_read_avail;
-	int total_notifs;
-	int total_read_times;
-};
-
-/**
- *  SDIO Channel context.
- *
- *  @name - channel name. Used by the caller to open the
- *	  channel.
- *
- *  @read_threshold - Threshold on SDIO-Client mailbox for Rx
- *				Data available bytes. When the limit exceed
- *				the SDIO-Client generates an interrupt to the
- *				host.
- *
- *  @write_threshold - Threshold on SDIO-Client mailbox for Tx
- *				Data available bytes. When the limit exceed
- *				the SDIO-Client generates an interrupt to the
- *				host.
- *
- *  @def_read_threshold - Default theshold on SDIO-Client for Rx
- *
- *  @min_write_avail - Threshold of minimal available bytes
- *					 to write. Below that threshold the host
- *					 will initiate reading the mailbox.
- *
- *  @poll_delay_msec - Delay between polling the mailbox. When
- *				 the SDIO-Client doesn't generates EOT
- *				 interrupt for Rx Available bytes, the host
- *				 should poll the SDIO-Client mailbox.
- *
- *  @is_packet_mode - The host get interrupt when a packet is
- *				available at the SDIO-client (pipe EOT
- *				indication).
- *
- *  @num - channel number.
- *
- *  @notify - Client's callback. Should not call sdio read/write.
- *
- *  @priv - Client's private context, provided to callback.
- *
- *  @is_valid - Channel is used (we have a list of
- *		SDIO_AL_MAX_CHANNELS and not all of them are in
- *		use).
- *
- *  @is_open - Channel is open.
- *
- *  @func - SDIO Function handle.
- *
- *  @rx_pipe_index - SDIO-Client Pipe Index for Rx Data.
- *
- *  @tx_pipe_index - SDIO-Client Pipe Index for Tx Data.
- *
- *  @ch_lock - Channel lock to protect channel specific Data
- *
- *  @rx_pending_bytes - Total number of Rx pending bytes, at Rx
- *				  packet list. Maximum of 16KB-1 limited by
- *				  SDIO-Client specification.
- *
- *  @read_avail - Available bytes to read.
- *
- *  @write_avail - Available bytes to write.
- *
- *  @rx_size_list_head - The head of Rx Pending Packets List.
- *
- *  @pdev - platform device - clients to probe for the sdio-al.
- *
- *  @signature - Context Validity check.
- *
- *  @sdio_al_dev - a pointer to the sdio_al_device instance of
- *   this channel
- *
- *   @statistics - channel statistics
- *
- */
-struct sdio_channel {
-	/* Channel Configuration Parameters*/
-	char name[CHANNEL_NAME_SIZE];
-	char ch_test_name[TEST_CH_NAME_SIZE];
-	int read_threshold;
-	int write_threshold;
-	int def_read_threshold;
-	int threshold_change_cnt;
-	int min_write_avail;
-	int poll_delay_msec;
-	int is_packet_mode;
-	int is_low_latency_ch;
-
-	struct peer_sdioc_channel_config ch_config;
-
-	/* Channel Info */
-	int num;
-
-	void (*notify)(void *priv, unsigned channel_event);
-	void *priv;
-
-	int state;
-
-	struct sdio_func *func;
-
-	int rx_pipe_index;
-	int tx_pipe_index;
-
-	struct mutex ch_lock;
-
-	u32 read_avail;
-	u32 write_avail;
-
-	u32 peer_tx_buf_size;
-
-	u16 rx_pending_bytes;
-
-	struct list_head rx_size_list_head;
-
-	struct platform_device *pdev;
-
-	u32 total_rx_bytes;
-	u32 total_tx_bytes;
-
-	u32 signature;
-
-	struct sdio_al_device *sdio_al_dev;
-
-	struct sdio_channel_statistics statistics;
-};
-
-/**
- * sdio_downloader_setup
- * initializes the TTY driver
- *
- * @card: a pointer to mmc_card.
- * @num_of_devices: number of devices.
- * @channel_number: channel number.
- * @return 0 on success or negative value on error.
- *
- * The TTY stack needs to know in advance how many devices it should
- * plan to manage. Use this call to set up the ports that will
- * be exported through SDIO.
- */
-int sdio_downloader_setup(struct mmc_card *card,
-			  unsigned int num_of_devices,
-			  int func_number,
-			  int(*func)(void));
-
-/**
- * test_channel_init
- * initializes a test channel
- *
- * @name: the channel name.
- * @return 0 on success or negative value on error.
- *
- */
-int test_channel_init(char *name);
-
-/**
- * sdio_al_register_lpm_cb
- * Allow the sdio_al test to register for lpm voting
- * notifications
- *
- * @device_handle: the device handle.
- * @wakeup_callback: callback function to be called when voting.
- *
- */
-void sdio_al_register_lpm_cb(void *device_handle,
-				       int(*lpm_callback)(void *, int));
-
-/**
- * sdio_al_unregister_lpm_cb
- * Allow the sdio_al test to unregister for lpm voting
- * notifications
- *
- * @device_handle: the device handle.
- *
- */
-void sdio_al_unregister_lpm_cb(void *device_handle);
-
-#endif /* __SDIO_AL_PRIVATE__ */
diff --git a/arch/arm/mach-msm/sdio_al_test.c b/arch/arm/mach-msm/sdio_al_test.c
deleted file mode 100644
index 2c9f675..0000000
--- a/arch/arm/mach-msm/sdio_al_test.c
+++ /dev/null
@@ -1,6500 +0,0 @@
-/* Copyright (c) 2010-2011, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
-
-/*
- * SDIO-Abstraction-Layer Test Module.
- *
- */
-
-#include <linux/module.h>
-#include <linux/device.h>
-#include <linux/workqueue.h>
-#include <linux/fs.h>
-#include <linux/cdev.h>
-#include <linux/sched.h>
-#include <linux/wait.h>
-#include <linux/delay.h>
-#include <linux/slab.h>
-#include <linux/random.h>
-#include <linux/platform_device.h>
-#include <mach/sdio_smem.h>
-#include <linux/wakelock.h>
-#include <linux/uaccess.h>
-
-#include "sdio_al_private.h"
-#include <linux/debugfs.h>
-
-#include <linux/kthread.h>
-enum lpm_test_msg_type {
-	LPM_NO_MSG,	/* 0 */
-	LPM_MSG_SEND,	/* 1 */
-	LPM_MSG_REC,	/* 2 */
-	LPM_SLEEP,	/* 3 */
-	LPM_WAKEUP,	/* 4 */
-	LPM_NOTIFY	/* 5 */
-};
-
-#define LPM_NO_MSG_NAME "LPM No Event"
-#define LPM_MSG_SEND_NAME "LPM Send Msg Event"
-#define LPM_MSG_REC_NAME "LPM Receive Msg Event"
-#define LPM_SLEEP_NAME "LPM Sleep Event"
-#define LPM_WAKEUP_NAME "LPM Wakeup Event"
-
-/** Module name string */
-#define TEST_MODULE_NAME "sdio_al_test"
-
-#define TEST_SIGNATURE 0x12345678
-#define TEST_CONFIG_SIGNATURE 0xBEEFCAFE
-
-#define MAX_XFER_SIZE (16*1024)
-#define SMEM_MAX_XFER_SIZE 0xBC000
-#define A2_MIN_PACKET_SIZE 5
-#define RMNT_PACKET_SIZE (4*1024)
-#define DUN_PACKET_SIZE (2*1024)
-#define CSVT_PACKET_SIZE 1700
-
-#define TEST_DBG(x...) if (test_ctx->runtime_debug) pr_info(x)
-
-#define LPM_TEST_NUM_OF_PACKETS 100
-#define LPM_MAX_OPEN_CHAN_PER_DEV 4
-#define LPM_ARRAY_SIZE	(7*LPM_TEST_NUM_OF_PACKETS*LPM_MAX_OPEN_CHAN_PER_DEV)
-#define SDIO_LPM_TEST "sdio_lpm_test_reading_task"
-#define LPM_TEST_CONFIG_SIGNATURE 0xDEADBABE
-#define LPM_MSG_NAME_SIZE 20
-#define MAX_STR_SIZE	10
-#define MAX_AVG_RTT_TIME_USEC	2500
-#define SDIO_RMNT_RTT_PACKET_SIZE	32
-#define SDIO_CSVT_RTT_PACKET_SIZE	1900
-
-#define A2_HEADER_OVERHEAD 8
-
-enum rx_process_state {
-	RX_PROCESS_PACKET_INIT,
-	RX_PROCESS_A2_HEADER,
-	RX_PROCESS_PACKET_DATA,
-};
-
-enum sdio_test_case_type {
-	SDIO_TEST_LOOPBACK_HOST,
-	SDIO_TEST_LOOPBACK_CLIENT,
-	SDIO_TEST_LPM_HOST_WAKER,
-	SDIO_TEST_LPM_CLIENT_WAKER,
-	SDIO_TEST_LPM_RANDOM,
-	SDIO_TEST_HOST_SENDER_NO_LP,
-	SDIO_TEST_CLOSE_CHANNEL,
-	SDIO_TEST_A2_VALIDATION,
-	/* The following tests are not part of the 9k tests and should be
-	 * kept last in case new tests are added
-	 */
-	SDIO_TEST_PERF,
-	SDIO_TEST_RTT,
-	SDIO_TEST_MODEM_RESET,
-};
-
-struct lpm_task {
-	struct task_struct *lpm_task;
-	const char *task_name;
-};
-
-struct lpm_entry_type {
-	enum lpm_test_msg_type msg_type;
-	char msg_name[LPM_MSG_NAME_SIZE];
-	u32 counter;
-	u32 current_ms;
-	u32 read_avail_mask;
-	char chan_name[CHANNEL_NAME_SIZE];
-};
-
-struct lpm_msg {
-	u32 signature;
-	u32 counter;
-	u32 reserve1;
-	u32 reserve2;
-};
-
-struct test_config_msg {
-	u32 signature;
-	u32 test_case;
-	u32 test_param;
-	u32 num_packets;
-	u32 num_iterations;
-};
-
-struct test_result_msg {
-	u32 signature;
-	u32 is_successful;
-};
-
-struct test_work {
-	struct work_struct work;
-	struct test_channel *test_ch;
-};
-
-enum sdio_channels_ids {
-	SDIO_RPC,
-	SDIO_QMI,
-	SDIO_RMNT,
-	SDIO_DIAG,
-	SDIO_DUN,
-	SDIO_SMEM,
-	SDIO_CSVT,
-	SDIO_MAX_CHANNELS
-};
-
-enum sdio_test_results {
-	TEST_NO_RESULT,
-	TEST_FAILED,
-	TEST_PASSED
-};
-
-enum sdio_lpm_vote_state {
-	SDIO_NO_VOTE,
-	SDIO_VOTE_FOR_SLEEP,
-	SDIO_VOTE_AGAINST_SLEEP
-};
-
-struct sdio_test_device {
-	int open_channels_counter_to_recv;
-	int open_channels_counter_to_send;
-	struct lpm_entry_type *lpm_arr;
-	int array_size;
-	void *sdio_al_device;
-	spinlock_t lpm_array_lock;
-	unsigned long lpm_array_lock_flags;
-	u32 next_avail_entry_in_array;
-	struct lpm_task lpm_test_task;
-	u32 next_mask_id;
-	u32 read_avail_mask;
-	int modem_result_per_dev;
-	int final_result_per_dev;
-};
-
-struct test_channel {
-	struct sdio_channel *ch;
-
-	char name[CHANNEL_NAME_SIZE];
-	int ch_id;
-
-	struct sdio_test_device *test_device;
-
-	u32 *buf;
-	u32 buf_size;
-
-	struct workqueue_struct *workqueue;
-	struct test_work test_work;
-
-	u32 rx_bytes;
-	u32 tx_bytes;
-
-	wait_queue_head_t   wait_q;
-	atomic_t rx_notify_count;
-	atomic_t tx_notify_count;
-	atomic_t any_notify_count;
-	atomic_t wakeup_client;
-	atomic_t card_detected_event;
-
-	int wait_counter;
-
-	int is_used;
-	int test_type;
-	int ch_ready;
-
-	struct test_config_msg config_msg;
-
-	int test_completed;
-	int test_result;
-	struct timer_list timer;
-	int timer_interval_ms;
-
-	struct timer_list timeout_timer;
-	int timeout_ms;
-	void *sdio_al_device;
-	int is_ok_to_sleep;
-	unsigned int packet_length;
-	int random_packet_size;
-	int next_index_in_sent_msg_per_chan;
-	int channel_mask_id;
-	int modem_result_per_chan;
-	int notify_counter_per_chan;
-	int max_burst_size;        /* number of writes before close/open */
-	int card_removed;
-};
-
-struct sdio_al_test_debug {
-	u32 dun_throughput;
-	u32 rmnt_throughput;
-	struct dentry *debug_root;
-	struct dentry *debug_test_result;
-	struct dentry *debug_dun_throughput;
-	struct dentry *debug_rmnt_throughput;
-	struct dentry *rpc_sender_test;
-	struct dentry *rpc_qmi_diag_sender_test;
-	struct dentry *smem_test;
-	struct dentry *smem_rpc_test;
-	struct dentry *rmnet_a2_validation_test;
-	struct dentry *dun_a2_validation_test;
-	struct dentry *rmnet_a2_perf_test;
-	struct dentry *dun_a2_perf_test;
-	struct dentry *csvt_a2_perf_test;
-	struct dentry *rmnet_dun_a2_perf_test;
-	struct dentry *rpc_sender_rmnet_a2_perf_test;
-	struct dentry *all_channels_test;
-	struct dentry *host_sender_no_lp_diag_test;
-	struct dentry *host_sender_no_lp_diag_rpc_test;
-	struct dentry *rmnet_small_packets_test;
-	struct dentry *rmnet_rtt_test;
-	struct dentry *csvt_rtt_test;
-	struct dentry *modem_reset_rpc_test;
-	struct dentry *modem_reset_rmnet_test;
-	struct dentry *modem_reset_channels_4bit_dev_test;
-	struct dentry *modem_reset_channels_8bit_dev_test;
-	struct dentry *modem_reset_all_channels_test;
-	struct dentry *open_close_test;
-	struct dentry *open_close_dun_rmnet_test;
-	struct dentry *close_chan_lpm_test;
-	struct dentry *lpm_test_client_wakes_host_test;
-	struct dentry *lpm_test_host_wakes_client_test;
-	struct dentry *lpm_test_random_single_channel_test;
-	struct dentry *lpm_test_random_multi_channel_test;
-};
-
-struct test_context {
-	dev_t dev_num;
-	struct device *dev;
-	struct cdev *cdev;
-	int number_of_active_devices;
-	int max_number_of_devices;
-
-	struct sdio_test_device test_dev_arr[MAX_NUM_OF_SDIO_DEVICES];
-
-	struct test_channel *test_ch;
-
-	struct test_channel *test_ch_arr[SDIO_MAX_CHANNELS];
-
-	long testcase;
-
-	const char *name;
-
-	int exit_flag;
-
-	u32 signature;
-
-	int runtime_debug;
-
-	struct platform_device *smem_pdev;
-	struct sdio_smem_client *sdio_smem;
-	int smem_was_init;
-	u8 *smem_buf;
-	uint32_t smem_counter;
-
-	struct platform_device *csvt_app_pdev;
-
-	wait_queue_head_t   wait_q;
-	int test_completed;
-	int test_result;
-	struct sdio_al_test_debug debug;
-
-	struct wake_lock wake_lock;
-
-	unsigned int lpm_pseudo_random_seed;
-};
-
-/* FORWARD DECLARATIONS */
-static int set_params_loopback_9k(struct test_channel *tch);
-static int set_params_smem_test(struct test_channel *tch);
-static int set_params_a2_validation(struct test_channel *tch);
-static int set_params_a2_perf(struct test_channel *tch);
-static int set_params_8k_sender_no_lp(struct test_channel *tch);
-static int set_params_a2_small_pkts(struct test_channel *tch);
-static int set_params_rtt(struct test_channel *tch);
-static int set_params_loopback_9k_close(struct test_channel *tch);
-static int close_channel_lpm_test(int channel_num);
-static int set_params_lpm_test(struct test_channel *tch,
-				enum sdio_test_case_type test,
-				int timer_interval_ms);
-static void set_pseudo_random_seed(void);
-static int set_params_modem_reset(struct test_channel *tch);
-static int test_start(void);
-static void rx_cleanup(struct test_channel *test_ch, int *rx_packet_count);
-static void sdio_al_test_cleanup_channels(void);
-static void notify(void *priv, unsigned channel_event);
-#ifdef CONFIG_MSM_SDIO_SMEM
-static int sdio_smem_open(struct sdio_smem_client *sdio_smem);
-#endif
-
-/*
- * Seed for pseudo random time sleeping in Random LPM test.
- * If not set, current time in jiffies is used.
- */
-static unsigned int seed;
-module_param(seed, int, 0);
-static struct test_context *test_ctx;
-
-static void sdio_al_test_initial_dev_and_chan(struct test_context *test_ctx)
-{
-	int i = 0;
-
-	if (!test_ctx) {
-		pr_err(TEST_MODULE_NAME ":%s - test_ctx is NULL.\n", __func__);
-		return;
-	}
-
-	for (i = 0 ; i < MAX_NUM_OF_SDIO_DEVICES ; ++i)
-		test_ctx->test_dev_arr[i].sdio_al_device = NULL;
-
-	for (i = 0; i < SDIO_MAX_CHANNELS; i++) {
-		struct test_channel *tch = test_ctx->test_ch_arr[i];
-		if (!tch)
-			continue;
-		tch->is_used = 0;
-	}
-
-	sdio_al_test_cleanup_channels();
-}
-
-#ifdef CONFIG_DEBUG_FS
-
-static int message_repeat;
-
-static int sdio_al_test_extract_number(const char __user *buf,
-					size_t count)
-{
-	int ret = 0;
-	int number = -1;
-	char local_buf[MAX_STR_SIZE] = {0};
-	char *start = NULL;
-
-	if (count > MAX_STR_SIZE) {
-		pr_err(TEST_MODULE_NAME ": %s - MAX_STR_SIZE(%d) < count(%d). "
-		       "Please choose smaller number\n",
-		       __func__, MAX_STR_SIZE, (int)count);
-		return -EINVAL;
-	}
-
-	if (copy_from_user(local_buf, buf, count)) {
-		pr_err(TEST_MODULE_NAME ": %s - copy_from_user() failed\n",
-		       __func__);
-		return -EINVAL;
-	}
-
-	/* adding null termination to the string */
-	local_buf[count] = '\0';
-
-	/* stripping leading and trailing white spaces */
-	start = strstrip(local_buf);
-
-	ret = kstrtoint(start, 10, &number);
-
-	if (ret) {
-		pr_err(TEST_MODULE_NAME " : %s - kstrtoint() failed\n",
-		       __func__);
-		return ret;
-	}
-
-	return number;
-}
-
-static int sdio_al_test_open(struct inode *inode, struct file *file)
-{
-	file->private_data = inode->i_private;
-	message_repeat = 1;
-	return 0;
-}
-
-static void sdio_al_test_cleanup_channels(void)
-{
-	int channel_num;
-	int dummy = 0;
-
-	for (channel_num = 0 ; channel_num < SDIO_MAX_CHANNELS ;
-	      ++channel_num) {
-		if (channel_num == SDIO_SMEM)
-			continue;
-
-		 rx_cleanup(test_ctx->test_ch_arr[channel_num], &dummy);
-	}
-
-	return;
-}
-
-/* RPC SENDER TEST */
-static ssize_t rpc_sender_test_write(struct file *file,
-				      const char __user *buf,
-				      size_t count,
-				      loff_t *ppos)
-{
-	int ret = 0;
-	int i = 0;
-	int number = -1;
-
-	pr_info(TEST_MODULE_NAME "-- RPC SENDER TEST --\n");
-
-	number = sdio_al_test_extract_number(buf, count);
-
-	if (number < 0) {
-		pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() "
-		       "failed. number = %d\n", __func__, number);
-		return count;
-	}
-
-	for (i = 0 ; i < number ; ++i) {
-		pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number);
-		pr_info(TEST_MODULE_NAME " ===================");
-
-		sdio_al_test_initial_dev_and_chan(test_ctx);
-
-		set_params_loopback_9k(test_ctx->test_ch_arr[SDIO_RPC]);
-
-		ret = test_start();
-
-		if (ret)
-			break;
-	}
-
-	return count;
-}
-
-static ssize_t rpc_sender_test_read(struct file *file,
-				     char __user *buffer,
-				     size_t count,
-				     loff_t *offset)
-{
-	memset((void *)buffer, 0, count);
-
-	snprintf(buffer, count,
-		 "\nRPC_SENDER_TEST\n"
-		 "===============\n"
-		 "Description:\n"
-		 "TBD\n");
-
-	if (message_repeat == 1) {
-		message_repeat = 0;
-		return strnlen(buffer, count);
-	} else {
-		return 0;
-	}
-}
-
-const struct file_operations rpc_sender_test_ops = {
-	.open = sdio_al_test_open,
-	.write = rpc_sender_test_write,
-	.read = rpc_sender_test_read,
-};
-
-/* RPC, QMI & DIAG SENDER TEST */
-static ssize_t rpc_qmi_diag_sender_test_write(struct file *file,
-					       const char __user *buf,
-					       size_t count,
-					       loff_t *ppos)
-{
-	int ret = 0;
-	int i = 0;
-	int number = -1;
-
-	pr_info(TEST_MODULE_NAME "-- RPC, QMI AND DIAG SENDER TEST --\n");
-
-	number = sdio_al_test_extract_number(buf, count);
-
-	if (number < 0) {
-		pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() "
-		       "failed. number = %d\n", __func__, number);
-		return count;
-	}
-
-	for (i = 0 ; i < number ; ++i) {
-		pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number);
-		pr_info(TEST_MODULE_NAME " ===================");
-
-		sdio_al_test_initial_dev_and_chan(test_ctx);
-
-		set_params_loopback_9k(test_ctx->test_ch_arr[SDIO_RPC]);
-		set_params_loopback_9k(test_ctx->test_ch_arr[SDIO_QMI]);
-		set_params_loopback_9k(test_ctx->test_ch_arr[SDIO_DIAG]);
-
-		ret = test_start();
-
-		if (ret)
-			break;
-	}
-
-	return count;
-}
-
-static ssize_t rpc_qmi_diag_sender_test_read(struct file *file,
-					      char __user
-					      *buffer, size_t count,
-					      loff_t *offset)
-{
-	memset((void *)buffer, 0, count);
-
-	snprintf(buffer, count,
-		 "\nRPC_QMI_DIAG_SENDER_TEST\n"
-		 "========================\n"
-		 "Description:\n"
-		 "TBD\n");
-
-
-	if (message_repeat == 1) {
-		message_repeat = 0;
-		return strnlen(buffer, count);
-	} else {
-		return 0;
-	}
-}
-
-const struct file_operations rpc_qmi_diag_sender_test_ops = {
-	.open = sdio_al_test_open,
-	.write = rpc_qmi_diag_sender_test_write,
-	.read = rpc_qmi_diag_sender_test_read,
-};
-
-/* SMEM TEST */
-static ssize_t smem_test_write(struct file *file,
-				const char __user *buf,
-				size_t count,
-				loff_t *ppos)
-{
-	int ret = 0;
-	int i = 0;
-	int number = -1;
-
-	pr_info(TEST_MODULE_NAME "-- SMEM TEST --\n");
-
-	number = sdio_al_test_extract_number(buf, count);
-
-	if (number < 0) {
-		pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() "
-		       "failed. number = %d\n", __func__, number);
-		return count;
-	}
-
-	for (i = 0 ; i < number ; ++i) {
-		pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number);
-		pr_info(TEST_MODULE_NAME " ===================");
-
-		sdio_al_test_initial_dev_and_chan(test_ctx);
-
-		set_params_smem_test(test_ctx->test_ch_arr[SDIO_SMEM]);
-
-		ret = test_start();
-
-		if (ret)
-			break;
-	}
-
-	return count;
-}
-
-static ssize_t smem_test_read(struct file *file,
-			       char __user *buffer,
-			       size_t count,
-			       loff_t *offset)
-{
-	memset((void *)buffer, 0, count);
-
-	snprintf(buffer, count,
-		 "\nSMEM_TEST\n"
-		 "=========\n"
-		 "Description:\n"
-		 "TBD\n");
-
-	if (message_repeat == 1) {
-		message_repeat = 0;
-		return strnlen(buffer, count);
-	} else {
-		return 0;
-	}
-}
-
-const struct file_operations smem_test_ops = {
-	.open = sdio_al_test_open,
-	.write = smem_test_write,
-	.read = smem_test_read,
-};
-
-/* SMEM & RPC TEST */
-static ssize_t smem_rpc_test_write(struct file *file,
-				    const char __user *buf,
-				    size_t count,
-				    loff_t *ppos)
-{
-	int ret = 0;
-	int i = 0;
-	int number = -1;
-
-	pr_info(TEST_MODULE_NAME "-- SMEM AND RPC TEST --\n");
-
-	number = sdio_al_test_extract_number(buf, count);
-
-	if (number < 0) {
-		pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() "
-		       "failed. number = %d\n", __func__, number);
-		return count;
-	}
-
-	for (i = 0 ; i < number ; ++i) {
-		pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number);
-		pr_info(TEST_MODULE_NAME " ===================");
-
-		sdio_al_test_initial_dev_and_chan(test_ctx);
-
-		set_params_loopback_9k(test_ctx->test_ch_arr[SDIO_RPC]);
-		set_params_smem_test(test_ctx->test_ch_arr[SDIO_SMEM]);
-
-		ret = test_start();
-
-		if (ret)
-			break;
-	}
-
-	return count;
-}
-
-static ssize_t smem_rpc_test_read(struct file *file,
-				   char __user *buffer,
-				   size_t count,
-				   loff_t *offset)
-{
-	memset((void *)buffer, 0, count);
-
-	snprintf(buffer, count,
-		 "\nSMEM_RPC_TEST\n"
-		 "=============\n"
-		 "Description:\n"
-		 "TBD\n");
-
-	if (message_repeat == 1) {
-		message_repeat = 0;
-		return strnlen(buffer, count);
-	} else {
-		return 0;
-	}
-}
-
-const struct file_operations smem_rpc_test_ops = {
-	.open = sdio_al_test_open,
-	.write = smem_rpc_test_write,
-	.read = smem_rpc_test_read,
-};
-
-/* RMNET A2 VALIDATION TEST */
-static ssize_t rmnet_a2_validation_test_write(struct file *file,
-						const char __user *buf,
-						size_t count,
-						loff_t *ppos)
-{
-	int ret = 0;
-	int i = 0;
-	int number = -1;
-
-	pr_info(TEST_MODULE_NAME "-- RMNET A2 VALIDATION TEST --\n");
-
-	number = sdio_al_test_extract_number(buf, count);
-
-	if (number < 0) {
-		pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() "
-		       "failed. number = %d\n", __func__, number);
-		return count;
-	}
-
-	for (i = 0 ; i < number ; ++i) {
-		pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number);
-		pr_info(TEST_MODULE_NAME " ===================");
-
-		sdio_al_test_initial_dev_and_chan(test_ctx);
-
-		set_params_a2_validation(test_ctx->test_ch_arr[SDIO_RMNT]);
-
-		ret = test_start();
-
-		if (ret)
-			break;
-	}
-
-	return count;
-}
-
-static ssize_t rmnet_a2_validation_test_read(struct file *file,
-						char __user *buffer,
-						size_t count,
-						loff_t *offset)
-{
-	memset((void *)buffer, 0, count);
-
-	snprintf(buffer, count,
-		 "\nRMNET_A2_VALIDATION_TEST\n"
-		 "=========================\n"
-		 "Description:\n"
-		 "In this test, the HOST sends multiple packets to the\n"
-		 "CLIENT and validates the packets loop backed from A2\n"
-		 "for the RMNET channel.\n\n"
-		 "END OF DESCRIPTION\n");
-
-	if (message_repeat == 1) {
-		message_repeat = 0;
-		return strnlen(buffer, count);
-	} else {
-		return 0;
-	}
-}
-
-const struct file_operations rmnet_a2_validation_test_ops = {
-	.open = sdio_al_test_open,
-	.write = rmnet_a2_validation_test_write,
-	.read = rmnet_a2_validation_test_read,
-};
-
-/* DUN A2 VALIDATION TEST */
-static ssize_t dun_a2_validation_test_write(struct file *file,
-						const char __user *buf,
-						size_t count,
-						loff_t *ppos)
-{
-	int ret = 0;
-	int i = 0;
-	int number = -1;
-
-	pr_info(TEST_MODULE_NAME "-- DUN A2 VALIDATION TEST --\n");
-
-	number = sdio_al_test_extract_number(buf, count);
-
-	if (number < 0) {
-		pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() "
-		       "failed. number = %d\n", __func__, number);
-		return count;
-	}
-
-	for (i = 0 ; i < number ; ++i) {
-		pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number);
-		pr_info(TEST_MODULE_NAME " ===================");
-
-		sdio_al_test_initial_dev_and_chan(test_ctx);
-
-		set_params_a2_validation(test_ctx->test_ch_arr[SDIO_DUN]);
-
-		ret = test_start();
-
-		if (ret)
-			break;
-	}
-
-	return count;
-}
-
-static ssize_t dun_a2_validation_test_read(struct file *file,
-						char __user *buffer,
-						size_t count,
-						loff_t *offset)
-{
-	memset((void *)buffer, 0, count);
-
-	snprintf(buffer, count,
-		"\nDUN_A2_VALIDATION_TEST\n"
-		"=========================\n"
-		"Description:\n"
-		"In this test, the HOST sends multiple packets to the\n"
-		"CLIENT and validates the packets loop backed from A2\n"
-		"for the DUN channel.\n\n"
-		"END OF DESCRIPTION\n");
-
-	if (message_repeat == 1) {
-		message_repeat = 0;
-		return strnlen(buffer, count);
-	} else {
-		return 0;
-	}
-}
-
-const struct file_operations dun_a2_validation_test_ops = {
-	.open = sdio_al_test_open,
-	.write = dun_a2_validation_test_write,
-	.read = dun_a2_validation_test_read,
-};
-
-/* RMNET A2 PERFORMANCE TEST */
-static ssize_t rmnet_a2_perf_test_write(struct file *file,
-					 const char __user *buf,
-					 size_t count,
-					 loff_t *ppos)
-{
-	int ret = 0;
-	int i = 0;
-	int number = -1;
-
-	pr_info(TEST_MODULE_NAME "-- RMNET A2 PERFORMANCE TEST --\n");
-
-	number = sdio_al_test_extract_number(buf, count);
-
-	if (number < 0) {
-		pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() "
-		       "failed. number = %d\n", __func__, number);
-		return count;
-	}
-
-	for (i = 0 ; i < number ; ++i) {
-		pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number);
-		pr_info(TEST_MODULE_NAME " ===================");
-
-		sdio_al_test_initial_dev_and_chan(test_ctx);
-
-		set_params_a2_perf(test_ctx->test_ch_arr[SDIO_RMNT]);
-
-		ret = test_start();
-
-		if (ret)
-			break;
-	}
-
-	return count;
-}
-
-static ssize_t rmnet_a2_perf_test_read(struct file *file,
-					char __user *buffer,
-					size_t count,
-					loff_t *offset)
-{
-	memset((void *)buffer, 0, count);
-
-	snprintf(buffer, count,
-		 "\nRMNET_A2_PERFORMANCE_TEST\n"
-		 "=========================\n"
-		 "Description:\n"
-		 "TBD\n");
-
-	if (message_repeat == 1) {
-		message_repeat = 0;
-		return strnlen(buffer, count);
-	} else {
-		return 0;
-	}
-}
-
-const struct file_operations rmnet_a2_perf_test_ops = {
-	.open = sdio_al_test_open,
-	.write = rmnet_a2_perf_test_write,
-	.read = rmnet_a2_perf_test_read,
-};
-
-/* DUN A2 PERFORMANCE TEST */
-static ssize_t dun_a2_perf_test_write(struct file *file,
-				       const char __user *buf,
-				       size_t count,
-				       loff_t *ppos)
-{
-	int ret = 0;
-	int i = 0;
-	int number = -1;
-
-	pr_info(TEST_MODULE_NAME "-- DUN A2 PERFORMANCE TEST --\n");
-
-	number = sdio_al_test_extract_number(buf, count);
-
-	if (number < 0) {
-		pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() "
-		       "failed. number = %d\n", __func__, number);
-		return count;
-	}
-
-	for (i = 0 ; i < number ; ++i) {
-		pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number);
-		pr_info(TEST_MODULE_NAME " ===================");
-
-		sdio_al_test_initial_dev_and_chan(test_ctx);
-
-		set_params_a2_perf(test_ctx->test_ch_arr[SDIO_DUN]);
-
-		ret = test_start();
-
-		if (ret)
-			break;
-	}
-
-	return count;
-}
-
-static ssize_t dun_a2_perf_test_read(struct file *file,
-				      char __user *buffer,
-				      size_t count,
-				      loff_t *offset)
-{
-	memset((void *)buffer, 0, count);
-
-	snprintf(buffer, count,
-		 "\nDUN_A2_PERFORMANCE_TEST\n"
-		 "=======================\n"
-		 "Description:\n"
-		 "TBD\n");
-
-	if (message_repeat == 1) {
-		message_repeat = 0;
-		return strnlen(buffer, count);
-	} else {
-		return 0;
-	}
-}
-
-const struct file_operations dun_a2_perf_test_ops = {
-	.open = sdio_al_test_open,
-	.write = dun_a2_perf_test_write,
-	.read = dun_a2_perf_test_read,
-};
-
-/* CSVT A2 PERFORMANCE TEST */
-static ssize_t csvt_a2_perf_test_write(struct file *file,
-					const char __user *buf,
-					size_t count,
-					loff_t *ppos)
-{
-	int ret = 0;
-	int i = 0;
-	int number = -1;
-
-	pr_info(TEST_MODULE_NAME "-- CSVT A2 PERFORMANCE TEST --\n");
-
-	number = sdio_al_test_extract_number(buf, count);
-
-	if (number < 0) {
-		pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() "
-		       "failed. number = %d\n", __func__, number);
-		return count;
-	}
-
-	for (i = 0 ; i < number ; ++i) {
-		pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number);
-		pr_info(TEST_MODULE_NAME " ===================");
-
-		sdio_al_test_initial_dev_and_chan(test_ctx);
-
-		set_params_a2_perf(test_ctx->test_ch_arr[SDIO_CSVT]);
-
-		ret = test_start();
-
-		if (ret)
-			break;
-	}
-
-	return count;
-}
-
-static ssize_t csvt_a2_perf_test_read(struct file *file,
-				       char __user *buffer,
-				       size_t count,
-				       loff_t *offset)
-{
-	memset((void *)buffer, 0, count);
-
-	snprintf(buffer, count,
-		 "\nCSVT_A2_PERFORMANCE_TEST\n"
-		 "========================\n"
-		 "Description:\n"
-		 "Loopback test on the CSVT Channel, in order to check "
-		 "throughput performance.\n"
-		 "Packet size that are sent on the CSVT channel in this "
-		 "test is %d.bytes\n\n"
-		 "END OF DESCRIPTION\n", CSVT_PACKET_SIZE);
-
-	if (message_repeat == 1) {
-		message_repeat = 0;
-		return strnlen(buffer, count);
-	} else {
-		return 0;
-	}
-}
-
-const struct file_operations csvt_a2_perf_test_ops = {
-	.open = sdio_al_test_open,
-	.write = csvt_a2_perf_test_write,
-	.read = csvt_a2_perf_test_read,
-};
-
-/* RMNET DUN A2 PERFORMANCE TEST */
-static ssize_t rmnet_dun_a2_perf_test_write(struct file *file,
-					     const char __user *buf,
-					     size_t count,
-					     loff_t *ppos)
-{
-	int ret = 0;
-	int i = 0;
-	int number = -1;
-
-	pr_info(TEST_MODULE_NAME "-- RMNET AND DUN A2 PERFORMANCE TEST --\n");
-
-	number = sdio_al_test_extract_number(buf, count);
-
-	if (number < 0) {
-		pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() "
-		       "failed. number = %d\n", __func__, number);
-		return count;
-	}
-
-	for (i = 0 ; i < number ; ++i) {
-		pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number);
-		pr_info(TEST_MODULE_NAME " ===================");
-
-		sdio_al_test_initial_dev_and_chan(test_ctx);
-
-		set_params_a2_perf(test_ctx->test_ch_arr[SDIO_RMNT]);
-		set_params_a2_perf(test_ctx->test_ch_arr[SDIO_DUN]);
-
-		ret = test_start();
-
-		if (ret)
-			break;
-	}
-
-	return count;
-}
-
-static ssize_t rmnet_dun_a2_perf_test_read(struct file *file,
-					    char __user *buffer,
-					    size_t count,
-					    loff_t *offset)
-{
-	memset((void *)buffer, 0, count);
-
-	snprintf(buffer, count,
-		 "\nRMNET_DUN_A2_PERFORMANCE_TEST\n"
-		 "=============================\n"
-		 "Description:\n"
-		 "TBD\n");
-
-	if (message_repeat == 1) {
-		message_repeat = 0;
-		return strnlen(buffer, count);
-	} else {
-		return 0;
-	}
-}
-
-const struct file_operations rmnet_dun_a2_perf_test_ops = {
-	.open = sdio_al_test_open,
-	.write = rmnet_dun_a2_perf_test_write,
-	.read = rmnet_dun_a2_perf_test_read,
-};
-
-/* RPC SENDER & RMNET A2 PERFORMANCE TEST */
-static ssize_t rpc_sender_rmnet_a2_perf_test_write(struct file *file,
-						    const char __user *buf,
-						    size_t count,
-						    loff_t *ppos)
-{
-	int ret = 0;
-	int i = 0;
-	int number = -1;
-
-	pr_info(TEST_MODULE_NAME "--RPC SENDER AND RMNET A2 "
-		"PERFORMANCE --\n");
-
-	number = sdio_al_test_extract_number(buf, count);
-
-	if (number < 0) {
-		pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() "
-		       "failed. number = %d\n", __func__, number);
-		return count;
-	}
-
-	for (i = 0 ; i < number ; ++i) {
-		pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number);
-		pr_info(TEST_MODULE_NAME " ===================");
-
-		sdio_al_test_initial_dev_and_chan(test_ctx);
-
-		set_params_loopback_9k(test_ctx->test_ch_arr[SDIO_RPC]);
-		set_params_a2_perf(test_ctx->test_ch_arr[SDIO_RMNT]);
-
-		ret = test_start();
-
-		if (ret)
-			break;
-	}
-
-	return count;
-}
-
-static ssize_t rpc_sender_rmnet_a2_perf_test_read(struct file *file,
-						   char __user *buffer,
-						   size_t count,
-						   loff_t *offset)
-{
-	memset((void *)buffer, 0, count);
-
-	snprintf(buffer, count,
-		 "\nRPC_SENDER_RMNET_A2_PERFORMANCE_TEST\n"
-		 "====================================\n"
-		 "Description:\n"
-		 "TBD\n");
-
-	if (message_repeat == 1) {
-		message_repeat = 0;
-		return strnlen(buffer, count);
-	} else {
-		return 0;
-	}
-}
-
-const struct file_operations rpc_sender_rmnet_a2_perf_test_ops = {
-	.open = sdio_al_test_open,
-	.write = rpc_sender_rmnet_a2_perf_test_write,
-	.read = rpc_sender_rmnet_a2_perf_test_read,
-};
-
-/* ALL CHANNELS TEST */
-static ssize_t all_channels_test_write(struct file *file,
-					const char __user *buf,
-					size_t count,
-					loff_t *ppos)
-{
-	int ret = 0;
-	int i = 0;
-	int number = -1;
-
-	pr_info(TEST_MODULE_NAME "-- ALL THE CHANNELS TEST --\n");
-
-	number = sdio_al_test_extract_number(buf, count);
-
-	if (number < 0) {
-		pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() "
-		       "failed. number = %d\n", __func__, number);
-		return count;
-	}
-
-	for (i = 0 ; i < number ; ++i) {
-		pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number);
-		pr_info(TEST_MODULE_NAME " ===================");
-
-		sdio_al_test_initial_dev_and_chan(test_ctx);
-
-		set_params_loopback_9k(test_ctx->test_ch_arr[SDIO_RPC]);
-		set_params_loopback_9k(test_ctx->test_ch_arr[SDIO_QMI]);
-		set_params_loopback_9k(test_ctx->test_ch_arr[SDIO_DIAG]);
-		set_params_a2_perf(test_ctx->test_ch_arr[SDIO_RMNT]);
-		set_params_a2_perf(test_ctx->test_ch_arr[SDIO_DUN]);
-		set_params_smem_test(test_ctx->test_ch_arr[SDIO_SMEM]);
-		set_params_a2_perf(test_ctx->test_ch_arr[SDIO_CSVT]);
-
-		ret = test_start();
-
-		if (ret)
-			break;
-	}
-
-	return count;
-}
-
-static ssize_t all_channels_test_read(struct file *file,
-				       char __user *buffer,
-				       size_t count,
-				       loff_t *offset)
-{
-	memset((void *)buffer, 0, count);
-
-	snprintf(buffer, count,
-		 "\nALL_CHANNELS_TEST\n"
-		 "=================\n"
-		 "Description:\n"
-		 "TBD\n");
-
-	if (message_repeat == 1) {
-		message_repeat = 0;
-		return strnlen(buffer, count);
-	} else {
-		return 0;
-	}
-}
-
-const struct file_operations all_channels_test_ops = {
-	.open = sdio_al_test_open,
-	.write = all_channels_test_write,
-	.read = all_channels_test_read,
-};
-
-/* HOST SENDER NO LP DIAG TEST */
-static ssize_t host_sender_no_lp_diag_test_write(struct file *file,
-						  const char __user *buf,
-						  size_t count,
-						  loff_t *ppos)
-{
-	int ret = 0;
-	int i = 0;
-	int number = -1;
-
-	pr_info(TEST_MODULE_NAME "-- HOST SENDER NO LP FOR DIAG TEST --");
-
-	number = sdio_al_test_extract_number(buf, count);
-
-	if (number < 0) {
-		pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() "
-		       "failed. number = %d\n", __func__, number);
-		return count;
-	}
-
-	for (i = 0 ; i < number ; ++i) {
-		pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number);
-		pr_info(TEST_MODULE_NAME " ===================");
-
-		sdio_al_test_initial_dev_and_chan(test_ctx);
-
-		set_params_8k_sender_no_lp(test_ctx->test_ch_arr[SDIO_DIAG]);
-
-		ret = test_start();
-
-		if (ret)
-			break;
-	}
-
-	return count;
-}
-
-static ssize_t host_sender_no_lp_diag_test_read(struct file *file,
-						 char __user *buffer,
-						 size_t count,
-						 loff_t *offset)
-{
-	memset((void *)buffer, 0, count);
-
-	snprintf(buffer, count,
-		 "\nHOST_SENDER_NO_LP_DIAG_TEST\n"
-		 "===========================\n"
-		 "Description:\n"
-		 "TBD\n");
-
-	if (message_repeat == 1) {
-		message_repeat = 0;
-		return strnlen(buffer, count);
-	} else {
-		return 0;
-	}
-}
-
-const struct file_operations host_sender_no_lp_diag_test_ops = {
-	.open = sdio_al_test_open,
-	.write = host_sender_no_lp_diag_test_write,
-	.read = host_sender_no_lp_diag_test_read,
-};
-
-/* HOST SENDER NO LP DIAG, RPC TEST */
-static ssize_t host_sender_no_lp_diag_rpc_test_write(
-						 struct file *file,
-						 const char __user *buf,
-						 size_t count,
-						 loff_t *ppos)
-{
-	int ret = 0;
-	int i = 0;
-	int number = -1;
-
-	pr_info(TEST_MODULE_NAME "-- HOST SENDER NO LP FOR DIAG, RPC "
-		"TEST --");
-
-	number = sdio_al_test_extract_number(buf, count);
-
-	if (number < 0) {
-		pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() "
-		       "failed. number = %d\n", __func__, number);
-		return count;
-	}
-
-	for (i = 0 ; i < number ; ++i) {
-		pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number);
-		pr_info(TEST_MODULE_NAME " ===================");
-
-		sdio_al_test_initial_dev_and_chan(test_ctx);
-
-		set_params_8k_sender_no_lp(test_ctx->test_ch_arr[SDIO_DIAG]);
-		set_params_8k_sender_no_lp(test_ctx->test_ch_arr[SDIO_RPC]);
-
-		ret = test_start();
-
-		if (ret)
-			break;
-	}
-
-	return count;
-}
-
-static ssize_t host_sender_no_lp_diag_rpc_test_read(
-						 struct file *file,
-						 char __user *buffer,
-						 size_t count,
-						 loff_t *offset)
-{
-	memset((void *)buffer, 0, count);
-
-	snprintf(buffer, count,
-		 "\nHOST_SENDER_NO_LP_DIAG_RPC_TEST\n"
-		 "===================================\n"
-		 "Description:\n"
-		 "TBD\n");
-
-	if (message_repeat == 1) {
-		message_repeat = 0;
-		return strnlen(buffer, count);
-	} else {
-		return 0;
-	}
-}
-
-const struct file_operations host_sender_no_lp_diag_rpc_test_ops = {
-	.open = sdio_al_test_open,
-	.write = host_sender_no_lp_diag_rpc_test_write,
-	.read = host_sender_no_lp_diag_rpc_test_read,
-};
-
-/* RMNET SMALL PACKETS TEST */
-static ssize_t rmnet_small_packets_test_write(struct file *file,
-					       const char __user *buf,
-					       size_t count,
-					       loff_t *ppos)
-{
-	int ret = 0;
-	int i = 0;
-	int number = -1;
-
-	pr_info(TEST_MODULE_NAME "-- RMNET SMALL PACKETS (5-128) TEST --");
-
-	number = sdio_al_test_extract_number(buf, count);
-
-	if (number < 0) {
-		pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() "
-		       "failed. number = %d\n", __func__, number);
-		return count;
-	}
-
-	for (i = 0 ; i < number ; ++i) {
-		pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number);
-		pr_info(TEST_MODULE_NAME " ===================");
-
-		sdio_al_test_initial_dev_and_chan(test_ctx);
-
-		set_params_a2_small_pkts(test_ctx->test_ch_arr[SDIO_RMNT]);
-
-		ret = test_start();
-
-		if (ret)
-			break;
-	}
-
-	return count;
-}
-
-static ssize_t rmnet_small_packets_test_read(struct file *file,
-					      char __user *buffer,
-					      size_t count,
-					      loff_t *offset)
-{
-	memset((void *)buffer, 0, count);
-
-	snprintf(buffer, count,
-		 "\nRMNET_SMALL_PACKETS_TEST\n"
-		 "========================\n"
-		 "Description:\n"
-		 "TBD\n");
-
-	if (message_repeat == 1) {
-		message_repeat = 0;
-		return strnlen(buffer, count);
-	} else {
-		return 0;
-	}
-}
-
-const struct file_operations rmnet_small_packets_test_ops = {
-	.open = sdio_al_test_open,
-	.write = rmnet_small_packets_test_write,
-	.read = rmnet_small_packets_test_read,
-};
-
-/* RMNET RTT TEST */
-static ssize_t rmnet_rtt_test_write(struct file *file,
-				     const char __user *buf,
-				     size_t count,
-				     loff_t *ppos)
-{
-	int ret = 0;
-	int i = 0;
-	int number = -1;
-
-	pr_info(TEST_MODULE_NAME "-- RMNET RTT TEST --");
-
-	number = sdio_al_test_extract_number(buf, count);
-
-	if (number < 0) {
-		pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() "
-		       "failed. number = %d\n", __func__, number);
-		return count;
-	}
-
-	for (i = 0 ; i < number ; ++i) {
-		pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number);
-		pr_info(TEST_MODULE_NAME " ===================");
-
-		sdio_al_test_initial_dev_and_chan(test_ctx);
-
-		set_params_rtt(test_ctx->test_ch_arr[SDIO_RMNT]);
-
-		ret = test_start();
-
-		if (ret)
-			break;
-	}
-
-	return count;
-}
-
-static ssize_t rmnet_rtt_test_read(struct file *file,
-				    char __user *buffer,
-				    size_t count,
-				    loff_t *offset)
-{
-	memset((void *)buffer, 0, count);
-
-	snprintf(buffer, count,
-		 "\nRMNET_RTT_TEST\n"
-		 "==============\n"
-		 "Description:\n"
-		 "TBD\n");
-
-	if (message_repeat == 1) {
-		message_repeat = 0;
-		return strnlen(buffer, count);
-	} else {
-		return 0;
-	}
-}
-
-const struct file_operations rmnet_rtt_test_ops = {
-	.open = sdio_al_test_open,
-	.write = rmnet_rtt_test_write,
-	.read = rmnet_rtt_test_read,
-};
-
-/* CSVT RTT TEST */
-static ssize_t csvt_rtt_test_write(struct file *file,
-				    const char __user *buf,
-				    size_t count,
-				    loff_t *ppos)
-{
-	int ret = 0;
-	int i = 0;
-	int number = -1;
-
-	pr_info(TEST_MODULE_NAME "-- CSVT RTT TEST --");
-
-	number = sdio_al_test_extract_number(buf, count);
-
-	if (number < 0) {
-		pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() "
-		       "failed. number = %d\n", __func__, number);
-		return count;
-	}
-
-	for (i = 0 ; i < number ; ++i) {
-		pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number);
-		pr_info(TEST_MODULE_NAME " ===================");
-
-		sdio_al_test_initial_dev_and_chan(test_ctx);
-
-		set_params_rtt(test_ctx->test_ch_arr[SDIO_CSVT]);
-
-		ret = test_start();
-
-		if (ret)
-			break;
-	}
-
-	return count;
-}
-
-static ssize_t csvt_rtt_test_read(struct file *file,
-				   char __user *buffer,
-				   size_t count,
-				   loff_t *offset)
-{
-	memset((void *)buffer, 0, count);
-
-	snprintf(buffer, count,
-		 "\nCSVT_RTT_TEST\n"
-		 "==============\n"
-		 "Description:\n"
-		 "In this test the HOST send a message of %d bytes "
-		 "to the CLIENT\n\n"
-		 "END OF DESCRIPTION\n", SDIO_CSVT_RTT_PACKET_SIZE);
-
-	if (message_repeat == 1) {
-		message_repeat = 0;
-		return strnlen(buffer, count);
-	} else {
-		return 0;
-	}
-}
-
-const struct file_operations csvt_rtt_test_ops = {
-	.open = sdio_al_test_open,
-	.write = csvt_rtt_test_write,
-	.read = csvt_rtt_test_read,
-};
-
-/* MODEM RESET RPC TEST */
-static ssize_t modem_reset_rpc_test_write(struct file *file,
-					   const char __user *buf,
-					   size_t count,
-					   loff_t *ppos)
-{
-	int ret = 0;
-	int i = 0;
-	int number = -1;
-
-	pr_info(TEST_MODULE_NAME "-- MODEM RESET - RPC CHANNEL TEST --");
-
-	number = sdio_al_test_extract_number(buf, count);
-
-	if (number < 0) {
-		pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() "
-		       "failed. number = %d\n", __func__, number);
-		return count;
-	}
-
-	for (i = 0 ; i < number ; ++i) {
-		pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number);
-		pr_info(TEST_MODULE_NAME " ===================");
-
-		sdio_al_test_initial_dev_and_chan(test_ctx);
-
-		set_params_modem_reset(test_ctx->test_ch_arr[SDIO_RPC]);
-
-		ret = test_start();
-
-		if (ret)
-			break;
-	}
-
-	return count;
-}
-
-static ssize_t modem_reset_rpc_test_read(struct file *file,
-					  char __user *buffer,
-					  size_t count,
-					  loff_t *offset)
-{
-	memset((void *)buffer, 0, count);
-
-	snprintf(buffer, count,
-		 "\nMODEM_RESET_RPC_TEST\n"
-		 "====================\n"
-		 "Description:\n"
-		 "TBD\n");
-
-	if (message_repeat == 1) {
-		message_repeat = 0;
-		return strnlen(buffer, count);
-	} else {
-		return 0;
-	}
-}
-
-const struct file_operations modem_reset_rpc_test_ops = {
-	.open = sdio_al_test_open,
-	.write = modem_reset_rpc_test_write,
-	.read = modem_reset_rpc_test_read,
-};
-
-/* MODEM RESET RMNET TEST */
-static ssize_t modem_reset_rmnet_test_write(struct file *file,
-					     const char __user *buf,
-					     size_t count,
-					     loff_t *ppos)
-{
-	int ret = 0;
-	int i = 0;
-	int number = -1;
-
-	pr_info(TEST_MODULE_NAME "-- MODEM RESET - RMNT CHANNEL TEST --");
-
-	number = sdio_al_test_extract_number(buf, count);
-
-	if (number < 0) {
-		pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() "
-		       "failed. number = %d\n", __func__, number);
-		return count;
-	}
-
-	for (i = 0 ; i < number ; ++i) {
-		pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number);
-		pr_info(TEST_MODULE_NAME " ===================");
-
-		sdio_al_test_initial_dev_and_chan(test_ctx);
-
-		set_params_modem_reset(test_ctx->test_ch_arr[SDIO_RMNT]);
-
-		ret = test_start();
-
-		if (ret)
-			break;
-	}
-
-	return count;
-}
-
-static ssize_t modem_reset_rmnet_test_read(struct file *file,
-					    char __user *buffer,
-					    size_t count,
-					    loff_t *offset)
-{
-	memset((void *)buffer, 0, count);
-
-	snprintf(buffer, count,
-		 "\nMODEM_RESET_RMNET_TEST\n"
-		 "======================\n"
-		 "Description:\n"
-		 "TBD\n");
-
-	if (message_repeat == 1) {
-		message_repeat = 0;
-		return strnlen(buffer, count);
-	} else {
-		return 0;
-	}
-}
-
-const struct file_operations modem_reset_rmnet_test_ops = {
-	.open = sdio_al_test_open,
-	.write = modem_reset_rmnet_test_write,
-	.read = modem_reset_rmnet_test_read,
-};
-
-/* MODEM RESET - CHANNELS IN 4BIT DEVICE TEST */
-static ssize_t modem_reset_channels_4bit_dev_test_write(
-						struct file *file,
-						const char __user *buf,
-						size_t count,
-						loff_t *ppos)
-{
-	int ret = 0;
-	int i = 0;
-	int number = -1;
-
-	pr_info(TEST_MODULE_NAME "-- MODEM RESET - ALL CHANNELS IN "
-		"4BIT DEVICE TEST --");
-
-	number = sdio_al_test_extract_number(buf, count);
-
-	if (number < 0) {
-		pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() "
-		       "failed. number = %d\n", __func__, number);
-		return count;
-	}
-
-	for (i = 0 ; i < number ; ++i) {
-		pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number);
-		pr_info(TEST_MODULE_NAME " ===================");
-
-		sdio_al_test_initial_dev_and_chan(test_ctx);
-
-		set_params_modem_reset(test_ctx->test_ch_arr[SDIO_RPC]);
-		set_params_modem_reset(test_ctx->test_ch_arr[SDIO_QMI]);
-		set_params_modem_reset(test_ctx->test_ch_arr[SDIO_DIAG]);
-
-		ret = test_start();
-
-		if (ret)
-			break;
-	}
-
-	return count;
-}
-
-static ssize_t modem_reset_channels_4bit_dev_test_read(
-						struct file *file,
-						char __user *buffer,
-						size_t count,
-						loff_t *offset)
-{
-	memset((void *)buffer, 0, count);
-
-	snprintf(buffer, count,
-		 "\nMODEM_RESET_CHANNELS_4BIT_DEV_TEST\n"
-		 "==================================\n"
-		 "Description:\n"
-		 "TBD\n");
-
-	if (message_repeat == 1) {
-		message_repeat = 0;
-		return strnlen(buffer, count);
-	} else {
-		return 0;
-	}
-}
-
-const struct file_operations modem_reset_channels_4bit_dev_test_ops = {
-	.open = sdio_al_test_open,
-	.write = modem_reset_channels_4bit_dev_test_write,
-	.read = modem_reset_channels_4bit_dev_test_read,
-};
-
-/* MODEM RESET - CHANNELS IN 8BIT DEVICE TEST */
-static ssize_t modem_reset_channels_8bit_dev_test_write(
-						struct file *file,
-						const char __user *buf,
-						size_t count,
-						loff_t *ppos)
-{
-	int ret = 0;
-	int i = 0;
-	int number = -1;
-
-	pr_info(TEST_MODULE_NAME "-- MODEM RESET - ALL CHANNELS IN "
-		"8BIT DEVICE TEST --");
-
-	number = sdio_al_test_extract_number(buf, count);
-
-	if (number < 0) {
-		pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() "
-		       "failed. number = %d\n", __func__, number);
-		return count;
-	}
-
-	for (i = 0 ; i < number ; ++i) {
-		pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number);
-		pr_info(TEST_MODULE_NAME " ===================");
-
-		sdio_al_test_initial_dev_and_chan(test_ctx);
-
-		set_params_modem_reset(test_ctx->test_ch_arr[SDIO_RMNT]);
-		set_params_modem_reset(test_ctx->test_ch_arr[SDIO_DUN]);
-
-		ret = test_start();
-
-		if (ret)
-			break;
-	}
-
-	return count;
-}
-
-static ssize_t modem_reset_channels_8bit_dev_test_read(
-						struct file *file,
-						char __user *buffer,
-						size_t count,
-						loff_t *offset)
-{
-	memset((void *)buffer, 0, count);
-
-	snprintf(buffer, count,
-		 "\nMODEM_RESET_CHANNELS_8BIT_DEV_TEST\n"
-		 "==================================\n"
-		 "Description:\n"
-		 "TBD\n");
-
-	if (message_repeat == 1) {
-		message_repeat = 0;
-		return strnlen(buffer, count);
-	} else {
-		return 0;
-	}
-}
-
-const struct file_operations modem_reset_channels_8bit_dev_test_ops = {
-	.open = sdio_al_test_open,
-	.write = modem_reset_channels_8bit_dev_test_write,
-	.read = modem_reset_channels_8bit_dev_test_read,
-};
-
-/* MODEM RESET - ALL CHANNELS TEST */
-static ssize_t modem_reset_all_channels_test_write(struct file *file,
-						    const char __user *buf,
-						    size_t count,
-						    loff_t *ppos)
-{
-	int ret = 0;
-	int i = 0;
-	int number = -1;
-
-	pr_info(TEST_MODULE_NAME "-- MODEM RESET - ALL CHANNELS TEST --");
-
-	number = sdio_al_test_extract_number(buf, count);
-
-	if (number < 0) {
-		pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() "
-		       "failed. number = %d\n", __func__, number);
-		return count;
-	}
-
-	for (i = 0 ; i < number ; ++i) {
-		pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number);
-		pr_info(TEST_MODULE_NAME " ===================");
-
-		sdio_al_test_initial_dev_and_chan(test_ctx);
-
-		set_params_modem_reset(test_ctx->test_ch_arr[SDIO_RPC]);
-		set_params_modem_reset(test_ctx->test_ch_arr[SDIO_QMI]);
-		set_params_modem_reset(test_ctx->test_ch_arr[SDIO_DIAG]);
-		set_params_modem_reset(test_ctx->test_ch_arr[SDIO_RMNT]);
-		set_params_modem_reset(test_ctx->test_ch_arr[SDIO_DUN]);
-
-		ret = test_start();
-
-		if (ret)
-			break;
-	}
-
-	return count;
-}
-
-static ssize_t modem_reset_all_channels_test_read(struct file *file,
-						   char __user *buffer,
-						   size_t count,
-						   loff_t *offset)
-{
-	memset((void *)buffer, 0, count);
-
-	snprintf(buffer, count,
-		 "\nMODEM_RESET_ALL_CHANNELS_TEST\n"
-		 "=============================\n"
-		 "Description:\n"
-		 "TBD\n");
-
-	if (message_repeat == 1) {
-		message_repeat = 0;
-		return strnlen(buffer, count);
-	} else {
-		return 0;
-	}
-}
-
-const struct file_operations modem_reset_all_channels_test_ops = {
-	.open = sdio_al_test_open,
-	.write = modem_reset_all_channels_test_write,
-	.read = modem_reset_all_channels_test_read,
-};
-
-/* HOST SENDER WITH OPEN/CLOSE TEST */
-static ssize_t open_close_test_write(struct file *file,
-						   const char __user *buf,
-						   size_t count,
-						   loff_t *ppos)
-{
-	int ret = 0;
-	struct test_channel **ch_arr = test_ctx->test_ch_arr;
-	int i = 0;
-	int number = -1;
-
-	pr_info(TEST_MODULE_NAME "-- HOST SENDER WITH OPEN/CLOSE TEST --");
-
-	number = sdio_al_test_extract_number(buf, count);
-
-	if (number < 0) {
-		pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() "
-		       "failed. number = %d\n", __func__, number);
-		return count;
-	}
-
-	for (i = 0 ; i < number ; ++i) {
-		pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number);
-		pr_info(TEST_MODULE_NAME " ===================");
-
-		sdio_al_test_initial_dev_and_chan(test_ctx);
-
-		set_params_loopback_9k_close(ch_arr[SDIO_DIAG]);
-		set_params_loopback_9k_close(ch_arr[SDIO_RPC]);
-		set_params_loopback_9k_close(ch_arr[SDIO_SMEM]);
-		set_params_loopback_9k_close(ch_arr[SDIO_QMI]);
-		set_params_loopback_9k_close(ch_arr[SDIO_RMNT]);
-		set_params_loopback_9k_close(ch_arr[SDIO_DUN]);
-		set_params_loopback_9k_close(ch_arr[SDIO_CSVT]);
-
-		ret = test_start();
-
-		if (ret)
-			break;
-
-		pr_info(TEST_MODULE_NAME " -- correctness test for"
-				"DIAG ");
-		set_params_loopback_9k(ch_arr[SDIO_DIAG]);
-
-		ret = test_start();
-
-		if (ret)
-			break;
-	}
-
-	return count;
-}
-
-static ssize_t open_close_test_read(struct file *file,
-						  char __user *buffer,
-						  size_t count,
-						  loff_t *offset)
-{
-	memset((void *)buffer, 0, count);
-
-	snprintf(buffer, count,
-		 "\nOPEN_CLOSE_TEST\n"
-		 "============================\n"
-		 "Description:\n"
-		 "In this test the host sends 5k packets to the modem in the "
-		 "following sequence: Send a random burst of packets on "
-		 "Diag and Rmnet channels, read 0 or a random number "
-		 "of packets, close and re-open the channel. At the end of the "
-		 "test, the channel is verified by running a loopback test\n\n"
-		 "END OF DESCRIPTION\n");
-
-	if (message_repeat == 1) {
-		message_repeat = 0;
-		return strnlen(buffer, count);
-	} else {
-		return 0;
-	}
-}
-
-const struct file_operations open_close_test_ops = {
-	.open = sdio_al_test_open,
-	.write = open_close_test_write,
-	.read = open_close_test_read,
-};
-
-/* HOST SENDER WITH OPEN/CLOSE FOR DUN & RMNET TEST */
-static ssize_t open_close_dun_rmnet_test_write(struct file *file,
-						   const char __user *buf,
-						   size_t count,
-						   loff_t *ppos)
-{
-	int ret = 0;
-	struct test_channel **ch_arr = test_ctx->test_ch_arr;
-	int i = 0;
-	int number = -1;
-
-	pr_info(TEST_MODULE_NAME "-- HOST SENDER WITH OPEN/CLOSE FOR "
-		"DUN AND RMNET TEST --");
-
-	number = sdio_al_test_extract_number(buf, count);
-
-	if (number < 0) {
-		pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() "
-		       "failed. number = %d\n", __func__, number);
-		return count;
-	}
-
-	for (i = 0 ; i < number ; ++i) {
-		pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number);
-		pr_info(TEST_MODULE_NAME " ===================");
-
-		sdio_al_test_initial_dev_and_chan(test_ctx);
-
-		set_params_loopback_9k_close(ch_arr[SDIO_DUN]);
-		set_params_loopback_9k_close(ch_arr[SDIO_RMNT]);
-
-		ret = test_start();
-
-		if (ret)
-			break;
-	}
-
-	return count;
-}
-
-static ssize_t open_close_dun_rmnet_test_read(struct file *file,
-						  char __user *buffer,
-						  size_t count,
-						  loff_t *offset)
-{
-	memset((void *)buffer, 0, count);
-
-	snprintf(buffer, count,
-		 "\nOPEN_CLOSE_DUN_RMNET_TEST\n"
-		 "============================\n"
-		 "Description:\n"
-		 "In this test the host sends 5k packets to the modem in the "
-		 "following sequence: Send a random burst of packets on "
-		 "DUN and Rmnet channels, read 0 or a random number "
-		 "of packets, close and re-open the channel.\n\n"
-		 "END OF DESCRIPTION\n");
-
-	if (message_repeat == 1) {
-		message_repeat = 0;
-		return strnlen(buffer, count);
-	} else {
-		return 0;
-	}
-}
-
-const struct file_operations open_close_dun_rmnet_test_ops = {
-	.open = sdio_al_test_open,
-	.write = open_close_dun_rmnet_test_write,
-	.read = open_close_dun_rmnet_test_read,
-};
-
-/* CLOSE CHANNEL & LPM TEST HOST WAKES THE CLIENT TEST */
-static ssize_t close_chan_lpm_test_write(struct file *file,
-					  const char __user *buf,
-					  size_t count,
-					  loff_t *ppos)
-{
-	int ret = 0;
-	int i = 0;
-	int channel_num = 0;
-	int number = -1;
-
-	pr_info(TEST_MODULE_NAME "-- CLOSE CHANNEL & LPM TEST "
-		"HOST WAKES THE CLIENT TEST --\n");
-
-	number = sdio_al_test_extract_number(buf, count);
-
-	if (number < 0) {
-		pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() "
-		       "failed. number = %d\n", __func__, number);
-		return count;
-	}
-
-	for (i = 0 ; i < number ; ++i) {
-		pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number);
-		pr_info(TEST_MODULE_NAME " ===================");
-
-		sdio_al_test_initial_dev_and_chan(test_ctx);
-
-		for (channel_num = 0 ; channel_num < SDIO_MAX_CHANNELS ;
-		     channel_num++) {
-
-			ret = close_channel_lpm_test(channel_num);
-
-			if (ret)
-				break;
-
-			set_params_lpm_test(test_ctx->test_ch_arr[SDIO_RPC],
-					    SDIO_TEST_LPM_HOST_WAKER, 120);
-
-			ret = test_start();
-
-			if (ret)
-				break;
-		}
-
-		if (ret) {
-			pr_err(TEST_MODULE_NAME " -- Close channel & LPM Test "
-			       "FAILED: %d --\n", ret);
-		} else {
-			pr_err(TEST_MODULE_NAME " -- Close channel & LPM Test "
-			       "PASSED\n");
-		}
-	}
-
-	return count;
-}
-
-static ssize_t close_chan_lpm_test_read(struct file *file,
-					 char __user *buffer,
-					 size_t count,
-					 loff_t *offset)
-{
-	memset((void *)buffer, 0, count);
-
-	snprintf(buffer, count,
-		 "\nCLOSE_CHAN_LPM_TEST\n"
-		 "===================\n"
-		 "Description:\n"
-		 "TBD\n");
-
-	if (message_repeat == 1) {
-		message_repeat = 0;
-		return strnlen(buffer, count);
-	} else {
-		return 0;
-	}
-}
-
-const struct file_operations close_chan_lpm_test_ops = {
-	.open = sdio_al_test_open,
-	.write = close_chan_lpm_test_write,
-	.read = close_chan_lpm_test_read,
-};
-
-/* LPM TEST FOR DEVICE 1. CLIENT WAKES THE HOST TEST */
-static ssize_t lpm_test_client_wakes_host_test_write(struct file *file,
-						      const char __user *buf,
-						      size_t count,
-						      loff_t *ppos)
-{
-	int ret = 0;
-	int i = 0;
-	int number = -1;
-
-	pr_info(TEST_MODULE_NAME "-- LPM TEST FOR DEVICE 1. CLIENT "
-		"WAKES THE HOST TEST --\n");
-
-	number = sdio_al_test_extract_number(buf, count);
-
-	if (number < 0) {
-		pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() "
-		       "failed. number = %d\n", __func__, number);
-		return count;
-	}
-
-	for (i = 0 ; i < number ; ++i) {
-		pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number);
-		pr_info(TEST_MODULE_NAME " ===================");
-
-		sdio_al_test_initial_dev_and_chan(test_ctx);
-
-		set_params_lpm_test(test_ctx->test_ch_arr[SDIO_RPC],
-				    SDIO_TEST_LPM_CLIENT_WAKER, 90);
-
-		ret = test_start();
-
-		if (ret)
-			break;
-	}
-
-	return count;
-}
-
-static ssize_t lpm_test_client_wakes_host_test_read(struct file *file,
-						     char __user *buffer,
-						     size_t count,
-						     loff_t *offset)
-{
-	memset((void *)buffer, 0, count);
-
-	snprintf(buffer, count,
-		 "\nLPM_TEST_CLIENT_WAKES_HOST_TEST\n"
-		 "===============================\n"
-		 "Description:\n"
-		 "In this test, the HOST is going into LPM mode,\n"
-		 "and the CLIENT is responsible to send it a message\n"
-		 "in order to wake it up\n\n"
-		 "END OF DESCRIPTION\n");
-
-	if (message_repeat == 1) {
-		message_repeat = 0;
-		return strnlen(buffer, count);
-	} else {
-		return 0;
-	}
-}
-
-const struct file_operations lpm_test_client_wakes_host_test_ops = {
-	.open = sdio_al_test_open,
-	.write = lpm_test_client_wakes_host_test_write,
-	.read = lpm_test_client_wakes_host_test_read,
-};
-
-/* LPM TEST FOR DEVICE 1. HOST WAKES THE CLIENT TEST */
-static ssize_t lpm_test_host_wakes_client_test_write(struct file *file,
-						      const char __user *buf,
-						      size_t count,
-						      loff_t *ppos)
-{
-	int ret = 0;
-	int i = 0;
-	int number = -1;
-
-	pr_info(TEST_MODULE_NAME "-- LPM TEST FOR DEVICE 1. HOST "
-		"WAKES THE CLIENT TEST --\n");
-
-	number = sdio_al_test_extract_number(buf, count);
-
-	if (number < 0) {
-		pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() "
-		       "failed. number = %d\n", __func__, number);
-		return count;
-	}
-
-	for (i = 0 ; i < number ; ++i) {
-		pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number);
-		pr_info(TEST_MODULE_NAME " ===================");
-
-		sdio_al_test_initial_dev_and_chan(test_ctx);
-
-		set_params_lpm_test(test_ctx->test_ch_arr[SDIO_RPC],
-			    SDIO_TEST_LPM_HOST_WAKER, 120);
-
-		ret = test_start();
-
-		if (ret)
-			break;
-	}
-
-	return count;
-}
-
-static ssize_t lpm_test_host_wakes_client_test_read(struct file *file,
-						     char __user *buffer,
-						     size_t count,
-						     loff_t *offset)
-{
-	memset((void *)buffer, 0, count);
-
-	snprintf(buffer, count,
-		 "\nLPM_TEST_HOST_WAKES_CLIENT_TEST\n"
-		 "===============================\n"
-		 "Description:\n"
-		 "In this test, the CLIENT goes into LPM mode, and the\n"
-		 "HOST is responsible to send it a message\n"
-		 "in order to wake it up\n\n"
-		 "END OF DESCRIPTION\n");
-
-	if (message_repeat == 1) {
-		message_repeat = 0;
-		return strnlen(buffer, count);
-	} else {
-		return 0;
-	}
-}
-
-const struct file_operations lpm_test_host_wakes_client_test_ops = {
-	.open = sdio_al_test_open,
-	.write = lpm_test_host_wakes_client_test_write,
-	.read = lpm_test_host_wakes_client_test_read,
-};
-
-/* LPM TEST RANDOM, SINGLE CHANNEL TEST */
-static ssize_t lpm_test_random_single_channel_test_write(
-						struct file *file,
-						const char __user *buf,
-						size_t count,
-						loff_t *ppos)
-{
-	int ret = 0;
-	int i = 0;
-	int number = -1;
-
-	pr_info(TEST_MODULE_NAME "-- LPM TEST RANDOM SINGLE "
-		"CHANNEL TEST --\n");
-
-	number = sdio_al_test_extract_number(buf, count);
-
-	if (number < 0) {
-		pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() "
-		       "failed. number = %d\n", __func__, number);
-		return count;
-	}
-
-	for (i = 0 ; i < number ; ++i) {
-		pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number);
-		pr_info(TEST_MODULE_NAME " ===================");
-
-		sdio_al_test_initial_dev_and_chan(test_ctx);
-
-		set_pseudo_random_seed();
-		set_params_lpm_test(test_ctx->test_ch_arr[SDIO_RPC],
-				    SDIO_TEST_LPM_RANDOM, 0);
-
-		ret = test_start();
-
-		if (ret)
-			break;
-	}
-
-	return count;
-}
-
-static ssize_t lpm_test_random_single_channel_test_read(
-						struct file *file,
-						char __user *buffer,
-						size_t count,
-						loff_t *offset)
-{
-	memset((void *)buffer, 0, count);
-
-	snprintf(buffer, count,
-		 "\nLPM_TEST_RANDOM_SINGLE_CHANNEL_TEST\n"
-		 "===================================\n"
-		 "Description:\n"
-		 "In this test, the HOST and CLIENT "
-		 "send messages to each other,\n"
-		 "random in time, over RPC channel only.\n"
-		 "All events are being recorded, and later on,\n"
-		 "they are being analysed by the HOST and by the CLIENT\n,"
-		 "in order to check if the LPM mechanism worked properly,\n"
-		 "meaning:"
-		 " When all the relevant conditions are met, a device should:\n"
-		 "1. Go to sleep\n"
-		 "2. Wake up\n"
-		 "3. Stay awake\n\n"
-		 "END OF DESCRIPTION\n");
-
-	if (message_repeat == 1) {
-		message_repeat = 0;
-		return strnlen(buffer, count);
-	} else {
-		return 0;
-	}
-}
-
-const struct file_operations lpm_test_random_single_channel_test_ops = {
-	.open = sdio_al_test_open,
-	.write = lpm_test_random_single_channel_test_write,
-	.read = lpm_test_random_single_channel_test_read,
-};
-
-/* LPM TEST RANDOM, MULTI CHANNEL TEST */
-static ssize_t lpm_test_random_multi_channel_test_write(
-						struct file *file,
-						const char __user *buf,
-						size_t count,
-						loff_t *ppos)
-{
-	int ret = 0;
-	int i = 0;
-	int number = -1;
-
-	pr_info(TEST_MODULE_NAME "-- LPM TEST RANDOM MULTI CHANNEL TEST --\n");
-
-	number = sdio_al_test_extract_number(buf, count);
-
-	if (number < 0) {
-		pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() "
-		       "failed. number = %d\n", __func__, number);
-		return count;
-	}
-
-	for (i = 0 ; i < number ; ++i) {
-		pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number);
-		pr_info(TEST_MODULE_NAME " ===================");
-
-		sdio_al_test_initial_dev_and_chan(test_ctx);
-
-		set_pseudo_random_seed();
-
-		set_params_lpm_test(test_ctx->test_ch_arr[SDIO_RPC],
-				    SDIO_TEST_LPM_RANDOM, 0);
-		set_params_lpm_test(test_ctx->test_ch_arr[SDIO_DIAG],
-				    SDIO_TEST_LPM_RANDOM, 0);
-		set_params_lpm_test(test_ctx->test_ch_arr[SDIO_QMI],
-				SDIO_TEST_LPM_RANDOM, 0);
-
-		ret = test_start();
-
-		if (ret)
-			break;
-	}
-
-	return count;
-}
-
-static ssize_t lpm_test_random_multi_channel_test_read(
-				 struct file *file,
-				 char __user *buffer,
-				 size_t count,
-				 loff_t *offset)
-{
-	memset((void *)buffer, 0, count);
-
-	snprintf(buffer, count,
-		 "\nLPM_TEST_RANDOM_MULTI_CHANNEL_TEST\n"
-		 "==================================\n"
-		 "Description:\n"
-		 "In this test, the HOST and CLIENT "
-		 "send messages to each other,\n"
-		 "random in time, over RPC, QMI AND DIAG channels\n"
-		 "(i.e, on both SDIO devices).\n"
-		 "All events are being recorded, and later on,\n"
-		 "they are being analysed by the HOST and by the CLIENT,\n"
-		 "in order to check if the LPM mechanism worked properly,\n"
-		 "meaning:"
-		 " When all the relevant conditions are met, a device should:\n"
-		 "1. Go to sleep\n"
-		 "2. Wake up\n"
-		 "3. Stay awake\n\n"
-		 "END OF DESCRIPTION\n");
-
-	if (message_repeat == 1) {
-		message_repeat = 0;
-		return strnlen(buffer, count);
-	} else {
-		return 0;
-	}
-}
-
-const struct file_operations lpm_test_random_multi_channel_test_ops = {
-	.open = sdio_al_test_open,
-	.write = lpm_test_random_multi_channel_test_write,
-	.read = lpm_test_random_multi_channel_test_read,
-};
-
-static int sdio_al_test_debugfs_init(void)
-{
-	test_ctx->debug.debug_root = debugfs_create_dir("sdio_al_test",
-							       NULL);
-	if (!test_ctx->debug.debug_root)
-		return -ENOENT;
-
-	test_ctx->debug.debug_test_result = debugfs_create_u32(
-					"test_result",
-					S_IRUGO | S_IWUGO,
-					test_ctx->debug.debug_root,
-					&test_ctx->test_result);
-
-	test_ctx->debug.debug_dun_throughput = debugfs_create_u32(
-					"dun_throughput",
-					S_IRUGO | S_IWUGO,
-					test_ctx->debug.debug_root,
-					&test_ctx->debug.dun_throughput);
-
-	test_ctx->debug.debug_rmnt_throughput = debugfs_create_u32(
-					"rmnt_throughput",
-					S_IRUGO | S_IWUGO,
-					test_ctx->debug.debug_root,
-					&test_ctx->debug.rmnt_throughput);
-
-	test_ctx->debug.rpc_sender_test =
-		debugfs_create_file("10_rpc_sender_test",
-				    S_IRUGO | S_IWUGO,
-				    test_ctx->debug.debug_root,
-				    NULL,
-				    &rpc_sender_test_ops);
-
-	test_ctx->debug.rpc_qmi_diag_sender_test =
-		debugfs_create_file("20_rpc_qmi_diag_sender_test",
-				    S_IRUGO | S_IWUGO,
-				    test_ctx->debug.debug_root,
-				    NULL,
-				    &rpc_qmi_diag_sender_test_ops);
-
-	test_ctx->debug.rmnet_a2_validation_test =
-		debugfs_create_file("30_rmnet_a2_validation_test",
-				    S_IRUGO | S_IWUGO,
-				    test_ctx->debug.debug_root,
-				    NULL,
-				    &rmnet_a2_validation_test_ops);
-
-	test_ctx->debug.dun_a2_validation_test =
-		debugfs_create_file("40_dun_a2_validation_test",
-				    S_IRUGO | S_IWUGO,
-				    test_ctx->debug.debug_root,
-				    NULL,
-				    &dun_a2_validation_test_ops);
-
-	test_ctx->debug.rmnet_a2_perf_test =
-		debugfs_create_file("50_rmnet_a2_perf_test",
-				    S_IRUGO | S_IWUGO,
-				    test_ctx->debug.debug_root,
-				    NULL,
-				    &rmnet_a2_perf_test_ops);
-
-	test_ctx->debug.dun_a2_perf_test =
-		debugfs_create_file("60_dun_a2_perf_test",
-				    S_IRUGO | S_IWUGO,
-				    test_ctx->debug.debug_root,
-				    NULL,
-				    &dun_a2_perf_test_ops);
-
-	test_ctx->debug.csvt_a2_perf_test =
-		debugfs_create_file("71_csvt_a2_perf_test",
-				    S_IRUGO | S_IWUGO,
-				    test_ctx->debug.debug_root,
-				    NULL,
-				    &csvt_a2_perf_test_ops);
-
-	test_ctx->debug.rmnet_dun_a2_perf_test =
-		debugfs_create_file("70_rmnet_dun_a2_perf_test",
-				    S_IRUGO | S_IWUGO,
-				    test_ctx->debug.debug_root,
-				    NULL,
-				    &rmnet_dun_a2_perf_test_ops);
-
-	test_ctx->debug.rpc_sender_rmnet_a2_perf_test =
-		debugfs_create_file("80_rpc_sender_rmnet_a2_perf_test",
-				    S_IRUGO | S_IWUGO,
-				    test_ctx->debug.debug_root,
-				    NULL,
-				    &rpc_sender_rmnet_a2_perf_test_ops);
-
-	test_ctx->debug.smem_test =
-		debugfs_create_file("90_smem_test",
-				    S_IRUGO | S_IWUGO,
-				    test_ctx->debug.debug_root,
-				    NULL,
-				    &smem_test_ops);
-
-	test_ctx->debug.smem_rpc_test =
-		debugfs_create_file("100_smem_rpc_test",
-				    S_IRUGO | S_IWUGO,
-				    test_ctx->debug.debug_root,
-				    NULL,
-				    &smem_rpc_test_ops);
-
-	test_ctx->debug.all_channels_test =
-		debugfs_create_file("150_all_channels_test",
-				    S_IRUGO | S_IWUGO,
-				    test_ctx->debug.debug_root,
-				    NULL,
-				    &all_channels_test_ops);
-
-	test_ctx->debug.host_sender_no_lp_diag_test =
-		debugfs_create_file("160_host_sender_no_lp_diag_test",
-				    S_IRUGO | S_IWUGO,
-				    test_ctx->debug.debug_root,
-				    NULL,
-				    &host_sender_no_lp_diag_test_ops);
-
-	test_ctx->debug.host_sender_no_lp_diag_rpc_test =
-		debugfs_create_file("170_host_sender_no_lp_diag_rpc_test",
-				     S_IRUGO | S_IWUGO,
-				     test_ctx->debug.debug_root,
-				     NULL,
-				     &host_sender_no_lp_diag_rpc_test_ops);
-
-	test_ctx->debug.rmnet_small_packets_test =
-		debugfs_create_file("180_rmnet_small_packets_test",
-				     S_IRUGO | S_IWUGO,
-				     test_ctx->debug.debug_root,
-				     NULL,
-				     &rmnet_small_packets_test_ops);
-
-	test_ctx->debug.rmnet_rtt_test =
-		debugfs_create_file("190_rmnet_rtt_test",
-				     S_IRUGO | S_IWUGO,
-				     test_ctx->debug.debug_root,
-				     NULL,
-				     &rmnet_rtt_test_ops);
-
-	test_ctx->debug.csvt_rtt_test =
-		debugfs_create_file("191_csvt_rtt_test",
-				     S_IRUGO | S_IWUGO,
-				     test_ctx->debug.debug_root,
-				     NULL,
-				     &csvt_rtt_test_ops);
-
-	test_ctx->debug.modem_reset_rpc_test =
-		debugfs_create_file("220_modem_reset_rpc_test",
-				     S_IRUGO | S_IWUGO,
-				     test_ctx->debug.debug_root,
-				     NULL,
-				     &modem_reset_rpc_test_ops);
-
-	test_ctx->debug.modem_reset_rmnet_test =
-		debugfs_create_file("230_modem_reset_rmnet_test",
-				     S_IRUGO | S_IWUGO,
-				     test_ctx->debug.debug_root,
-				     NULL,
-				     &modem_reset_rmnet_test_ops);
-
-	test_ctx->debug.modem_reset_channels_4bit_dev_test =
-		debugfs_create_file("240_modem_reset_channels_4bit_dev_test",
-				     S_IRUGO | S_IWUGO,
-				     test_ctx->debug.debug_root,
-				     NULL,
-				     &modem_reset_channels_4bit_dev_test_ops);
-
-	test_ctx->debug.modem_reset_channels_8bit_dev_test =
-		debugfs_create_file("250_modem_reset_channels_8bit_dev_test",
-				     S_IRUGO | S_IWUGO,
-				     test_ctx->debug.debug_root,
-				     NULL,
-				     &modem_reset_channels_8bit_dev_test_ops);
-
-	test_ctx->debug.modem_reset_all_channels_test =
-		debugfs_create_file("260_modem_reset_all_channels_test",
-				     S_IRUGO | S_IWUGO,
-				     test_ctx->debug.debug_root,
-				     NULL,
-				     &modem_reset_all_channels_test_ops);
-
-	test_ctx->debug.open_close_test =
-		debugfs_create_file("270_open_close_test",
-				     S_IRUGO | S_IWUGO,
-				     test_ctx->debug.debug_root,
-				     NULL,
-				     &open_close_test_ops);
-
-	test_ctx->debug.open_close_dun_rmnet_test =
-		debugfs_create_file("271_open_close_dun_rmnet_test",
-				     S_IRUGO | S_IWUGO,
-				     test_ctx->debug.debug_root,
-				     NULL,
-				     &open_close_dun_rmnet_test_ops);
-
-	test_ctx->debug.close_chan_lpm_test =
-		debugfs_create_file("280_close_chan_lpm_test",
-				     S_IRUGO | S_IWUGO,
-				     test_ctx->debug.debug_root,
-				     NULL,
-				     &close_chan_lpm_test_ops);
-
-	test_ctx->debug.lpm_test_client_wakes_host_test =
-		debugfs_create_file("600_lpm_test_client_wakes_host_test",
-				     S_IRUGO | S_IWUGO,
-				     test_ctx->debug.debug_root,
-				     NULL,
-				     &lpm_test_client_wakes_host_test_ops);
-
-	test_ctx->debug.lpm_test_host_wakes_client_test =
-		debugfs_create_file("610_lpm_test_host_wakes_client_test",
-				     S_IRUGO | S_IWUGO,
-				     test_ctx->debug.debug_root,
-				     NULL,
-				     &lpm_test_host_wakes_client_test_ops);
-
-	test_ctx->debug.lpm_test_random_single_channel_test =
-		debugfs_create_file("620_lpm_test_random_single_channel_test",
-				     S_IRUGO | S_IWUGO,
-				     test_ctx->debug.debug_root,
-				     NULL,
-				     &lpm_test_random_single_channel_test_ops);
-
-	test_ctx->debug.lpm_test_random_multi_channel_test =
-		debugfs_create_file("630_lpm_test_random_multi_channel_test",
-				     S_IRUGO | S_IWUGO,
-				     test_ctx->debug.debug_root,
-				     NULL,
-				     &lpm_test_random_multi_channel_test_ops);
-
-	if ((!test_ctx->debug.debug_dun_throughput) &&
-	    (!test_ctx->debug.debug_rmnt_throughput)) {
-		debugfs_remove_recursive(test_ctx->debug.debug_root);
-		test_ctx->debug.debug_root = NULL;
-		return -ENOENT;
-	}
-	return 0;
-}
-
-static void sdio_al_test_debugfs_cleanup(void)
-{
-       debugfs_remove(test_ctx->debug.debug_dun_throughput);
-       debugfs_remove(test_ctx->debug.debug_rmnt_throughput);
-       debugfs_remove(test_ctx->debug.debug_root);
-}
-#endif
-
-static int channel_name_to_id(char *name)
-{
-	pr_info(TEST_MODULE_NAME "%s: channel name %s\n",
-		__func__, name);
-
-	if (!strncmp(name, "SDIO_RPC_TEST",
-		     strnlen("SDIO_RPC_TEST", CHANNEL_NAME_SIZE)))
-		return SDIO_RPC;
-	else if (!strncmp(name, "SDIO_QMI_TEST",
-			  strnlen("SDIO_QMI_TEST", TEST_CH_NAME_SIZE)))
-		return SDIO_QMI;
-	else if (!strncmp(name, "SDIO_RMNT_TEST",
-			  strnlen("SDIO_RMNT_TEST", TEST_CH_NAME_SIZE)))
-		return SDIO_RMNT;
-	else if (!strncmp(name, "SDIO_DIAG_TEST",
-			  strnlen("SDIO_DIAG", TEST_CH_NAME_SIZE)))
-		return SDIO_DIAG;
-	else if (!strncmp(name, "SDIO_DUN_TEST",
-			  strnlen("SDIO_DUN_TEST", TEST_CH_NAME_SIZE)))
-		return SDIO_DUN;
-	else if (!strncmp(name, "SDIO_SMEM_TEST",
-			  strnlen("SDIO_SMEM_TEST", TEST_CH_NAME_SIZE)))
-		return SDIO_SMEM;
-	else if (!strncmp(name, "SDIO_CSVT_TEST",
-			  strnlen("SDIO_CSVT_TEST", TEST_CH_NAME_SIZE)))
-		return SDIO_CSVT;
-	else
-		return SDIO_MAX_CHANNELS;
-
-	return SDIO_MAX_CHANNELS;
-}
-
-/**
- * Allocate and add SDIO_SMEM platform device
- */
-#ifdef CONFIG_MSM_SDIO_SMEM
-static int add_sdio_smem(void)
-{
-	int ret = 0;
-
-	test_ctx->smem_pdev = platform_device_alloc("SDIO_SMEM", -1);
-	ret = platform_device_add(test_ctx->smem_pdev);
-	if (ret) {
-		pr_err(TEST_MODULE_NAME ": platform_device_add failed, "
-				   "ret=%d\n", ret);
-		return ret;
-	}
-	return 0;
-}
-#endif
-
-static int open_sdio_ch(struct test_channel *tch)
-{
-	int ret = 0;
-
-	if (!tch) {
-		pr_err(TEST_MODULE_NAME ": %s NULL tch\n", __func__);
-		return -EINVAL;
-	}
-
-	if (!tch->ch_ready) {
-		TEST_DBG(TEST_MODULE_NAME ":openning channel %s\n",
-			tch->name);
-		if (tch->ch_id == SDIO_SMEM) {
-#ifdef CONFIG_MSM_SDIO_SMEM
-			if (!test_ctx->smem_pdev)
-				ret = add_sdio_smem();
-			else
-				ret = sdio_smem_open(test_ctx->sdio_smem);
-			if (ret) {
-				pr_err(TEST_MODULE_NAME
-					":openning channel %s failed\n",
-				tch->name);
-				tch->ch_ready = false;
-				return -EINVAL;
-			}
-#endif
-		} else {
-			tch->ch_ready = true;
-			ret = sdio_open(tch->name , &tch->ch, tch,
-					notify);
-			if (ret) {
-				pr_err(TEST_MODULE_NAME
-					":openning channel %s failed\n",
-				tch->name);
-				tch->ch_ready = false;
-				return -EINVAL;
-			}
-		}
-	}
-	return ret;
-}
-
-static int close_sdio_ch(struct test_channel *tch)
-{
-	int ret = 0;
-
-	if (!tch) {
-		pr_err(TEST_MODULE_NAME ": %s NULL tch\n", __func__);
-		return -EINVAL;
-	}
-
-	if (tch->ch_id == SDIO_SMEM) {
-#ifdef CONFIG_MSM_SDIO_SMEM
-		TEST_DBG(TEST_MODULE_NAME":%s closing channel %s",
-		       __func__, tch->name);
-		ret = sdio_smem_unregister_client();
-		test_ctx->smem_counter = 0;
-#endif
-	} else {
-		ret = sdio_close(tch->ch);
-	}
-
-	if (ret) {
-		pr_err(TEST_MODULE_NAME":%s close channel %s"
-				" failed\n", __func__, tch->name);
-	} else {
-		TEST_DBG(TEST_MODULE_NAME":%s close channel %s"
-				" success\n", __func__, tch->name);
-		tch->ch_ready = false;
-	}
-	return ret;
-}
-
-/**
- * Config message
- */
-
-static void send_config_msg(struct test_channel *test_ch)
-{
-	int ret = 0 ;
-	u32 write_avail = 0;
-	int size = sizeof(test_ch->config_msg);
-
-	pr_debug(TEST_MODULE_NAME "%s\n", __func__);
-
-	memcpy(test_ch->buf, (void *)&test_ch->config_msg, size);
-
-	if (test_ctx->exit_flag) {
-		pr_info(TEST_MODULE_NAME ":Exit Test.\n");
-		return;
-	}
-
-	pr_info(TEST_MODULE_NAME ":Sending the config message.\n");
-
-	/* wait for data ready event */
-	write_avail = sdio_write_avail(test_ch->ch);
-	pr_debug(TEST_MODULE_NAME ":write_avail=%d\n", write_avail);
-	if (write_avail < size) {
-		wait_event(test_ch->wait_q,
-			   atomic_read(&test_ch->tx_notify_count));
-		atomic_dec(&test_ch->tx_notify_count);
-	}
-
-	write_avail = sdio_write_avail(test_ch->ch);
-	pr_debug(TEST_MODULE_NAME ":write_avail=%d\n", write_avail);
-	if (write_avail < size) {
-		pr_info(TEST_MODULE_NAME ":not enough write avail.\n");
-		return;
-	}
-
-	ret = sdio_write(test_ch->ch, test_ch->buf, size);
-	if (ret)
-		pr_err(TEST_MODULE_NAME ":%s sdio_write err=%d.\n",
-			__func__, -ret);
-	else
-		pr_info(TEST_MODULE_NAME ":%s sent config_msg successfully.\n",
-		       __func__);
-}
-
-/**
- * Loopback Test
- */
-static void loopback_test(struct test_channel *test_ch)
-{
-	int ret = 0 ;
-	u32 read_avail = 0;
-	u32 write_avail = 0;
-
-	while (1) {
-
-		if (test_ctx->exit_flag) {
-			pr_info(TEST_MODULE_NAME ":Exit Test.\n");
-			return;
-		}
-
-		TEST_DBG(TEST_MODULE_NAME "--LOOPBACK WAIT FOR EVENT--.\n");
-		/* wait for data ready event */
-		wait_event(test_ch->wait_q,
-			   atomic_read(&test_ch->rx_notify_count));
-		atomic_dec(&test_ch->rx_notify_count);
-
-		read_avail = sdio_read_avail(test_ch->ch);
-		if (read_avail == 0)
-			continue;
-
-
-		write_avail = sdio_write_avail(test_ch->ch);
-		if (write_avail < read_avail) {
-			pr_info(TEST_MODULE_NAME
-				":not enough write avail.\n");
-			continue;
-		}
-
-		ret = sdio_read(test_ch->ch, test_ch->buf, read_avail);
-		if (ret) {
-			pr_info(TEST_MODULE_NAME
-			       ":worker, sdio_read err=%d.\n", -ret);
-			continue;
-		}
-		test_ch->rx_bytes += read_avail;
-
-		TEST_DBG(TEST_MODULE_NAME ":worker total rx bytes = 0x%x.\n",
-			 test_ch->rx_bytes);
-
-
-		ret = sdio_write(test_ch->ch,
-				 test_ch->buf, read_avail);
-		if (ret) {
-			pr_info(TEST_MODULE_NAME
-				":loopback sdio_write err=%d.\n",
-				-ret);
-			continue;
-		}
-		test_ch->tx_bytes += read_avail;
-
-		TEST_DBG(TEST_MODULE_NAME
-			 ":loopback total tx bytes = 0x%x.\n",
-			 test_ch->tx_bytes);
-	} /* end of while */
-}
-
-/**
- * Check if all tests completed
- */
-static void check_test_completion(void)
-{
-	int i;
-
-	for (i = 0; i < SDIO_MAX_CHANNELS; i++) {
-		struct test_channel *tch = test_ctx->test_ch_arr[i];
-
-		if ((!tch) || (!tch->is_used) || (!tch->ch_ready))
-			continue;
-		if (!tch->test_completed) {
-			pr_info(TEST_MODULE_NAME ": %s - Channel %s test is "
-				"not completed", __func__, tch->name);
-			return;
-		}
-	}
-	pr_info(TEST_MODULE_NAME ": %s - Test is completed", __func__);
-	test_ctx->test_completed = 1;
-	wake_up(&test_ctx->wait_q);
-}
-
-static int pseudo_random_seed(unsigned int *seed_number)
-{
-	if (!seed_number)
-		return 0;
-
-	*seed_number = (unsigned int)(((unsigned long)*seed_number *
-				(unsigned long)1103515367) + 35757);
-	return (int)((*seed_number / (64*1024)) % 500);
-}
-
-/* this function must be locked before accessing it */
-static void lpm_test_update_entry(struct test_channel *tch,
-				  enum lpm_test_msg_type msg_type,
-				   char *msg_name,
-				  int counter)
-{
-	u32 index = 0;
-	static int print_full = 1;
-	struct sdio_test_device *test_device;
-
-	if (!tch) {
-		pr_err(TEST_MODULE_NAME ": %s - NULL test channel\n", __func__);
-		return;
-	}
-
-	test_device = tch->test_device;
-
-	if (!test_device) {
-		pr_err(TEST_MODULE_NAME ": %s - NULL test device\n", __func__);
-		return;
-	}
-
-	if (!test_device->lpm_arr) {
-		pr_err(TEST_MODULE_NAME ": %s - NULL lpm_arr\n", __func__);
-		return;
-	}
-
-	if (test_device->next_avail_entry_in_array >=
-					test_device->array_size) {
-		pr_err(TEST_MODULE_NAME ": %s - lpm array is full",
-			__func__);
-
-		if (print_full) {
-			print_hex_dump(KERN_INFO, TEST_MODULE_NAME ": lpm_arr:",
-				0, 32, 2,
-				(void *)test_device->lpm_arr,
-				sizeof(test_device->lpm_arr), false);
-			print_full = 0;
-		}
-		return;
-	}
-
-	index = test_device->next_avail_entry_in_array;
-	if ((msg_type == LPM_MSG_SEND) || (msg_type == LPM_MSG_REC))
-		test_device->lpm_arr[index].counter = counter;
-	else
-		test_device->lpm_arr[index].counter = 0;
-
-	test_device->lpm_arr[index].msg_type = msg_type;
-	memcpy(test_device->lpm_arr[index].msg_name, msg_name,
-	       LPM_MSG_NAME_SIZE);
-	test_device->lpm_arr[index].current_ms =
-		jiffies_to_msecs(get_jiffies_64());
-
-	test_device->lpm_arr[index].read_avail_mask =
-		test_device->read_avail_mask;
-
-	if ((msg_type == LPM_SLEEP) || (msg_type == LPM_WAKEUP))
-		memcpy(test_device->lpm_arr[index].chan_name, "DEVICE  ",
-		       CHANNEL_NAME_SIZE);
-	else
-		memcpy(test_device->lpm_arr[index].chan_name, tch->name,
-		       CHANNEL_NAME_SIZE);
-
-	test_device->next_avail_entry_in_array++;
-}
-
-static int wait_for_result_msg(struct test_channel *test_ch)
-{
-	u32 read_avail = 0;
-	int ret = 0;
-
-	pr_info(TEST_MODULE_NAME ": %s - START, channel %s\n",
-		__func__, test_ch->name);
-
-	while (1) {
-		read_avail = sdio_read_avail(test_ch->ch);
-
-		if (read_avail == 0) {
-			pr_info(TEST_MODULE_NAME
-				": read_avail is 0 for chan %s\n",
-				test_ch->name);
-			wait_event(test_ch->wait_q,
-				   atomic_read(&test_ch->rx_notify_count));
-			atomic_dec(&test_ch->rx_notify_count);
-			continue;
-		}
-
-		memset(test_ch->buf, 0x00, test_ch->buf_size);
-
-		ret = sdio_read(test_ch->ch, test_ch->buf, read_avail);
-		if (ret) {
-			pr_info(TEST_MODULE_NAME ":  sdio_read for chan"
-				"%s failed, err=%d.\n",
-				test_ch->name, -ret);
-			goto exit_err;
-		}
-
-		if (test_ch->buf[0] != TEST_CONFIG_SIGNATURE) {
-			pr_info(TEST_MODULE_NAME ": Not a test_result "
-				"signature. expected 0x%x. received 0x%x "
-				"for chan %s\n",
-				TEST_CONFIG_SIGNATURE,
-				test_ch->buf[0],
-				test_ch->name);
-			continue;
-		} else {
-			pr_info(TEST_MODULE_NAME ": Signature is "
-				"TEST_CONFIG_SIGNATURE as expected for"
-				"channel %s\n", test_ch->name);
-			break;
-		}
-	}
-
-	return test_ch->buf[1];
-
-exit_err:
-	return 0;
-}
-
-static void print_random_lpm_test_array(struct sdio_test_device *test_dev)
-{
-	int i;
-
-	if (!test_dev) {
-		pr_err(TEST_MODULE_NAME ": %s - NULL test device\n", __func__);
-		return;
-	}
-
-	for (i = 0 ; i < test_dev->next_avail_entry_in_array ; ++i) {
-		if (i == 0)
-			pr_err(TEST_MODULE_NAME ": index %4d, chan=%2s, "
-			       "code=%1d=%4s, msg#%1d, ms from before=-1, "
-			       "read_mask=0x%d, ms=%2u",
-			       i,
-			       test_dev->lpm_arr[i].chan_name,
-			       test_dev->lpm_arr[i].msg_type,
-			       test_dev->lpm_arr[i].msg_name,
-			       test_dev->lpm_arr[i].counter,
-			       test_dev->lpm_arr[i].read_avail_mask,
-			       test_dev->lpm_arr[i].current_ms);
-		else
-			pr_err(TEST_MODULE_NAME ": index "
-			       "%4d, %2s, code=%1d=%4s, msg#%1d, ms from "
-			       "before=%2u, read_mask=0x%d, ms=%2u",
-			       i,
-			       test_dev->lpm_arr[i].chan_name,
-			       test_dev->lpm_arr[i].msg_type,
-			       test_dev->lpm_arr[i].msg_name,
-			       test_dev->lpm_arr[i].counter,
-			       test_dev->lpm_arr[i].current_ms -
-			       test_dev->lpm_arr[i-1].current_ms,
-			       test_dev->lpm_arr[i].read_avail_mask,
-			       test_dev->lpm_arr[i].current_ms);
-
-		udelay(1000);
-	}
-}
-
-static int check_random_lpm_test_array(struct sdio_test_device *test_dev)
-{
-	int i = 0, j = 0;
-	unsigned int delta_ms = 0;
-	int arr_ind = 0;
-	int ret = 0;
-	int notify_counter = 0;
-	int sleep_counter = 0;
-	int wakeup_counter = 0;
-	int lpm_activity_counter = 0;
-
-	if (!test_dev) {
-		pr_err(TEST_MODULE_NAME ": %s - NULL test device\n", __func__);
-		return -ENODEV;
-	}
-
-	for (i = 0; i < test_dev->next_avail_entry_in_array; i++) {
-		notify_counter = 0;
-		sleep_counter = 0;
-		wakeup_counter = 0;
-
-		if ((test_dev->lpm_arr[i].msg_type == LPM_MSG_SEND) ||
-		     (test_dev->lpm_arr[i].msg_type == LPM_MSG_REC)) {
-			/* find the next message in the array */
-			arr_ind = test_dev->next_avail_entry_in_array;
-			for (j = i+1; j < arr_ind; j++) {
-				if ((test_dev->lpm_arr[j].msg_type ==
-				     LPM_MSG_SEND) ||
-				    (test_dev->lpm_arr[j].msg_type ==
-				     LPM_MSG_REC) ||
-				    (test_dev->lpm_arr[j].msg_type ==
-				     LPM_NOTIFY))
-					break;
-				if (test_dev->lpm_arr[j].msg_type ==
-				    LPM_SLEEP)
-					sleep_counter++;
-				if (test_dev->lpm_arr[j].msg_type ==
-				    LPM_WAKEUP)
-					wakeup_counter++;
-			}
-			if (j == arr_ind) {
-				ret = 0;
-				break;
-			}
-
-			delta_ms = test_dev->lpm_arr[j].current_ms -
-				test_dev->lpm_arr[i].current_ms;
-			if (delta_ms < 30) {
-				if ((sleep_counter == 0)
-				    && (wakeup_counter == 0)) {
-					continue;
-				} else {
-					pr_err(TEST_MODULE_NAME "%s: lpm "
-						"activity while delta is less "
-						"than 30, i=%d, j=%d, "
-						"sleep_counter=%d, "
-						"wakeup_counter=%d",
-					       __func__, i, j,
-					       sleep_counter, wakeup_counter);
-					ret = -ENODEV;
-					break;
-				}
-			} else {
-				if ((delta_ms > 90) &&
-				    (test_dev->lpm_arr[i].
-						read_avail_mask == 0)) {
-					if (j != i+3) {
-						pr_err(TEST_MODULE_NAME
-						       "%s: unexpected "
-						       "lpm activity "
-						       "while delta is "
-						       "bigger than "
-						       "90, i=%d, "
-						       "j=%d, "
-						       "notify_counter"
-						       "=%d",
-						       __func__, i, j,
-						       notify_counter);
-						ret = -ENODEV;
-						break;
-					}
-					lpm_activity_counter++;
-				}
-			}
-		}
-	}
-
-	pr_info(TEST_MODULE_NAME ": %s - lpm_activity_counter=%d",
-		__func__, lpm_activity_counter);
-
-	return ret;
-}
-
-static int lpm_test_main_task(void *ptr)
-{
-	u32 read_avail = 0;
-	int last_msg_index = 0;
-	struct test_channel *test_ch = (struct test_channel *)ptr;
-	struct sdio_test_device *test_dev;
-	struct lpm_msg lpm_msg;
-	int ret = 0;
-	int host_result = 0;
-
-	if (!test_ch) {
-		pr_err(TEST_MODULE_NAME ": %s - NULL channel\n", __func__);
-		return -ENODEV;
-	}
-
-	pr_err(TEST_MODULE_NAME ": %s - STARTED. channel %s\n",
-	       __func__, test_ch->name);
-
-	test_dev = test_ch->test_device;
-
-	if (!test_dev) {
-		pr_err(TEST_MODULE_NAME ": %s - NULL Test Device\n", __func__);
-		return -ENODEV;
-	}
-
-	while (last_msg_index < test_ch->config_msg.num_packets - 1) {
-
-		TEST_DBG(TEST_MODULE_NAME ": %s - "
-			"IN LOOP last_msg_index=%d\n",
-		       __func__, last_msg_index);
-
-		read_avail = sdio_read_avail(test_ch->ch);
-		if (read_avail == 0) {
-			TEST_DBG(TEST_MODULE_NAME
-					":read_avail 0 for chan %s, "
-					"wait for event\n",
-					test_ch->name);
-			wait_event(test_ch->wait_q,
-				   atomic_read(&test_ch->rx_notify_count));
-			atomic_dec(&test_ch->rx_notify_count);
-
-			read_avail = sdio_read_avail(test_ch->ch);
-			if (read_avail == 0) {
-				pr_err(TEST_MODULE_NAME
-					":read_avail size %d for chan %s not as"
-					" expected\n",
-					read_avail, test_ch->name);
-				continue;
-			}
-		}
-
-		memset(test_ch->buf, 0x00, sizeof(test_ch->buf));
-
-		ret = sdio_read(test_ch->ch, test_ch->buf, read_avail);
-		if (ret) {
-			pr_info(TEST_MODULE_NAME ":sdio_read for chan %s"
-				" err=%d.\n", test_ch->name, -ret);
-			goto exit_err;
-		}
-
-		memcpy((void *)&lpm_msg, test_ch->buf, sizeof(lpm_msg));
-
-		/*
-		 * when reading from channel, we want to turn off the bit
-		 * mask that implies that there is pending data on that channel
-		 */
-		if (test_ch->test_device != NULL) {
-			spin_lock_irqsave(&test_dev->lpm_array_lock,
-					  test_dev->lpm_array_lock_flags);
-
-			test_ch->notify_counter_per_chan--;
-
-			/*
-			 * if the channel has no pending data, turn off the
-			 * pending data bit mask of the channel
-			 */
-			if (test_ch->notify_counter_per_chan == 0) {
-				test_ch->test_device->read_avail_mask =
-					test_ch->test_device->read_avail_mask &
-					~test_ch->channel_mask_id;
-			}
-
-			last_msg_index = lpm_msg.counter;
-			lpm_test_update_entry(test_ch,
-					      LPM_MSG_REC,
-					      "RECEIVE",
-					      last_msg_index);
-
-			spin_unlock_irqrestore(&test_dev->lpm_array_lock,
-					       test_dev->lpm_array_lock_flags);
-		}
-	}
-
-	pr_info(TEST_MODULE_NAME ":%s: Finished to recieve all (%d) "
-		"packets from the modem %s. Waiting for result_msg",
-		__func__, test_ch->config_msg.num_packets, test_ch->name);
-
-	/* Wait for the resault message from the modem */
-	test_ch->modem_result_per_chan = wait_for_result_msg(test_ch);
-
-	/*
-	 * the DEVICE modem result is a failure if one of the channels on
-	 * that device, got modem_result = 0. this is why we bitwise "AND" each
-	 * time another channel completes its task
-	 */
-	test_dev->modem_result_per_dev &= test_ch->modem_result_per_chan;
-
-	/*
-	 * when reading from channel, we want to turn off the bit
-	 * mask that implies that there is pending data on that channel
-	 */
-	spin_lock_irqsave(&test_dev->lpm_array_lock,
-					  test_dev->lpm_array_lock_flags);
-
-	test_dev->open_channels_counter_to_recv--;
-
-	/* turning off the read_avail bit of the channel */
-	test_ch->test_device->read_avail_mask =
-		test_ch->test_device->read_avail_mask &
-		~test_ch->channel_mask_id;
-
-	spin_unlock_irqrestore(&test_dev->lpm_array_lock,
-					       test_dev->lpm_array_lock_flags);
-
-	/* Wait for all the packets to be sent to the modem */
-	while (1) {
-		spin_lock_irqsave(&test_dev->lpm_array_lock,
-				  test_dev->lpm_array_lock_flags);
-
-		if (test_ch->next_index_in_sent_msg_per_chan >=
-		    test_ch->config_msg.num_packets - 1) {
-
-			spin_unlock_irqrestore(&test_dev->lpm_array_lock,
-					       test_dev->lpm_array_lock_flags);
-			break;
-		} else {
-			pr_info(TEST_MODULE_NAME ":%s: Didn't finished to send "
-				"all packets, "
-				"next_index_in_sent_msg_per_chan = %d ",
-				__func__,
-				test_ch->next_index_in_sent_msg_per_chan);
-		}
-		spin_unlock_irqrestore(&test_dev->lpm_array_lock,
-				       test_dev->lpm_array_lock_flags);
-		msleep(60);
-	}
-
-	/*
-	 * if device has still open channels to test, then the test on the
-	 * device is still running but the test on current channel is completed
-	 */
-	if (test_dev->open_channels_counter_to_recv != 0 ||
-	    test_dev->open_channels_counter_to_send != 0) {
-		test_ch->test_completed = 1;
-		return 0;
-	} else {
-		test_ctx->number_of_active_devices--;
-		sdio_al_unregister_lpm_cb(test_ch->sdio_al_device);
-
-		if (test_ch->test_type == SDIO_TEST_LPM_RANDOM)
-			host_result = check_random_lpm_test_array(test_dev);
-
-		if (host_result ||
-		    !test_dev->modem_result_per_dev ||
-		    test_ctx->runtime_debug)
-			print_random_lpm_test_array(test_dev);
-
-		pr_info(TEST_MODULE_NAME ": %s - host_result=%d.(0 for "
-			"SUCCESS) device_modem_result=%d (1 for SUCCESS)",
-			__func__, host_result, test_dev->modem_result_per_dev);
-
-		test_ch->test_completed = 1;
-		if (test_dev->modem_result_per_dev && !host_result) {
-			pr_info(TEST_MODULE_NAME ": %s - Random LPM "
-				"TEST_PASSED for device %d of %d\n",
-				__func__,
-				(test_ctx->max_number_of_devices-
-				test_ctx->number_of_active_devices),
-				test_ctx->max_number_of_devices);
-			test_dev->final_result_per_dev = 1; /* PASSED */
-		} else {
-			pr_info(TEST_MODULE_NAME ": %s - Random LPM "
-				"TEST_FAILED for device %d of %d\n",
-				__func__,
-				(test_ctx->max_number_of_devices-
-				test_ctx->number_of_active_devices),
-				test_ctx->max_number_of_devices);
-			test_dev->final_result_per_dev = 0; /* FAILED */
-		}
-
-		check_test_completion();
-
-		kfree(test_ch->test_device->lpm_arr);
-
-		return 0;
-	}
-
-exit_err:
-	pr_info(TEST_MODULE_NAME ": TEST FAIL for chan %s.\n",
-		test_ch->name);
-	test_ch->test_completed = 1;
-	test_dev->open_channels_counter_to_recv--;
-	test_dev->next_avail_entry_in_array = 0;
-	test_ch->next_index_in_sent_msg_per_chan = 0;
-	test_ch->test_result = TEST_FAILED;
-	check_test_completion();
-	return -ENODEV;
-}
-
-static int lpm_test_create_read_thread(struct test_channel *test_ch)
-{
-	struct sdio_test_device *test_dev;
-
-	pr_info(TEST_MODULE_NAME ": %s - STARTED channel %s\n",
-		__func__, test_ch->name);
-
-	if (!test_ch) {
-		pr_err(TEST_MODULE_NAME ": %s - NULL test channel\n", __func__);
-		return -ENODEV;
-	}
-
-	test_dev = test_ch->test_device;
-
-	if (!test_dev) {
-		pr_err(TEST_MODULE_NAME ": %s - NULL test device\n", __func__);
-		return -ENODEV;
-	}
-
-	test_dev->lpm_test_task.task_name = SDIO_LPM_TEST;
-
-	test_dev->lpm_test_task.lpm_task =
-		kthread_create(lpm_test_main_task,
-			       (void *)(test_ch),
-			       test_dev->lpm_test_task.task_name);
-
-	if (IS_ERR(test_dev->lpm_test_task.lpm_task)) {
-		pr_err(TEST_MODULE_NAME ": %s - kthread_create() failed\n",
-			__func__);
-		return -ENOMEM;
-	}
-
-	wake_up_process(test_dev->lpm_test_task.lpm_task);
-
-	return 0;
-}
-
-static void lpm_continuous_rand_test(struct test_channel *test_ch)
-{
-	unsigned int local_ms = 0;
-	int ret = 0;
-	unsigned int write_avail = 0;
-	struct sdio_test_device *test_dev;
-
-	pr_info(MODULE_NAME ": %s - STARTED\n", __func__);
-
-	if (!test_ch) {
-		pr_err(TEST_MODULE_NAME ": %s - NULL channel\n", __func__);
-		return;
-	}
-
-	test_dev = test_ch->test_device;
-
-	if (!test_dev) {
-		pr_err(TEST_MODULE_NAME ": %s - NULL Test Device\n", __func__);
-		return;
-	}
-
-	ret = lpm_test_create_read_thread(test_ch);
-	if (ret != 0) {
-		pr_err(TEST_MODULE_NAME ": %s - failed to create lpm reading "
-		       "thread", __func__);
-	}
-
-	while (1) {
-
-		struct lpm_msg msg;
-		u32 ret = 0;
-
-		/* sleeping period is dependent on number of open channels */
-		test_ch->config_msg.test_param =
-				test_ctx->lpm_pseudo_random_seed;
-
-		local_ms = test_dev->open_channels_counter_to_send *
-			test_ctx->lpm_pseudo_random_seed;
-		TEST_DBG(TEST_MODULE_NAME ":%s: SLEEPING for %d ms",
-		       __func__, local_ms);
-		msleep(local_ms);
-
-		msg.counter = test_ch->next_index_in_sent_msg_per_chan;
-		msg.signature = LPM_TEST_CONFIG_SIGNATURE;
-		msg.reserve1 = 0;
-		msg.reserve2 = 0;
-
-		/* wait for data ready event */
-		write_avail = sdio_write_avail(test_ch->ch);
-		pr_debug(TEST_MODULE_NAME ": %s: write_avail=%d\n",
-		       __func__, write_avail);
-		if (write_avail < sizeof(msg)) {
-			wait_event(test_ch->wait_q,
-				   atomic_read(&test_ch->tx_notify_count));
-			atomic_dec(&test_ch->tx_notify_count);
-		}
-
-		write_avail = sdio_write_avail(test_ch->ch);
-		if (write_avail < sizeof(msg)) {
-			pr_info(TEST_MODULE_NAME ": %s: not enough write "
-				"avail.\n", __func__);
-			break;
-		}
-
-		ret = sdio_write(test_ch->ch, (u32 *)&msg, sizeof(msg));
-		if (ret)
-			pr_err(TEST_MODULE_NAME ":%s: sdio_write err=%d.\n",
-				__func__, -ret);
-
-		TEST_DBG(TEST_MODULE_NAME ": %s: for chan %s, write, "
-			 "msg # %d\n",
-			 __func__,
-			 test_ch->name,
-			 test_ch->next_index_in_sent_msg_per_chan);
-
-		if (test_ch->test_type == SDIO_TEST_LPM_RANDOM) {
-			spin_lock_irqsave(&test_dev->lpm_array_lock,
-					  test_dev->lpm_array_lock_flags);
-			lpm_test_update_entry(test_ch, LPM_MSG_SEND,
-					      "SEND  ",
-					      test_ch->
-					      next_index_in_sent_msg_per_chan);
-
-			test_ch->next_index_in_sent_msg_per_chan++;
-
-			if (test_ch->next_index_in_sent_msg_per_chan ==
-			    test_ch->config_msg.num_packets) {
-				spin_unlock_irqrestore(
-				    &test_dev->lpm_array_lock,
-				    test_dev->lpm_array_lock_flags);
-				break;
-			}
-
-			spin_unlock_irqrestore(&test_dev->lpm_array_lock,
-					       test_dev->lpm_array_lock_flags);
-		}
-	}
-
-	spin_lock_irqsave(&test_dev->lpm_array_lock,
-				  test_dev->lpm_array_lock_flags);
-	test_dev->open_channels_counter_to_send--;
-	spin_unlock_irqrestore(&test_dev->lpm_array_lock,
-				       test_dev->lpm_array_lock_flags);
-
-	pr_info(TEST_MODULE_NAME ": %s: - Finished to send all (%d) "
-		"packets to the modem on channel %s",
-		__func__, test_ch->config_msg.num_packets, test_ch->name);
-
-	return;
-}
-
-static void lpm_test(struct test_channel *test_ch)
-{
-	pr_info(TEST_MODULE_NAME ": %s - START channel %s\n", __func__,
-		test_ch->name);
-
-	if (!test_ch) {
-		pr_err(TEST_MODULE_NAME ": %s - NULL test channel\n", __func__);
-		return;
-	}
-
-	test_ch->modem_result_per_chan = wait_for_result_msg(test_ch);
-	pr_debug(TEST_MODULE_NAME ": %s - delete the timeout timer\n",
-	       __func__);
-	del_timer_sync(&test_ch->timeout_timer);
-
-	if (test_ch->modem_result_per_chan == 0) {
-		pr_err(TEST_MODULE_NAME ": LPM TEST - Client didn't sleep. "
-		       "Result Msg - is_successful=%d\n", test_ch->buf[1]);
-		goto exit_err;
-	} else {
-		pr_info(TEST_MODULE_NAME ": %s -"
-			"LPM 9K WAS SLEEPING - PASS\n", __func__);
-		if (test_ch->test_result == TEST_PASSED) {
-			pr_info(TEST_MODULE_NAME ": LPM TEST_PASSED\n");
-			test_ch->test_completed = 1;
-			check_test_completion();
-		} else {
-			pr_err(TEST_MODULE_NAME ": LPM TEST - Host didn't "
-			       "sleep. Client slept\n");
-			goto exit_err;
-		}
-	}
-
-	return;
-
-exit_err:
-	pr_info(TEST_MODULE_NAME ": TEST FAIL for chan %s.\n",
-		test_ch->name);
-	test_ch->test_completed = 1;
-	test_ch->test_result = TEST_FAILED;
-	check_test_completion();
-	return;
-}
-
-
-/**
- * LPM Test while the host wakes up the modem
- */
-static void lpm_test_host_waker(struct test_channel *test_ch)
-{
-	pr_info(TEST_MODULE_NAME ": %s - START\n", __func__);
-	wait_event(test_ch->wait_q, atomic_read(&test_ch->wakeup_client));
-	atomic_set(&test_ch->wakeup_client, 0);
-
-	pr_info(TEST_MODULE_NAME ": %s - Sending the config_msg to wakeup "
-		" the client\n", __func__);
-	send_config_msg(test_ch);
-
-	lpm_test(test_ch);
-}
-
-/**
-  * Writes number of packets into test channel
-  * @test_ch: test channel control struct
-  * @burst_size: number of packets to send
-  */
-static int write_packet_burst(struct test_channel *test_ch,
-		int burst_size)
-{
-	int ret = 0;
-	int packet_count = 0;
-	unsigned int random_num = 0;
-	int size = test_ch->packet_length; /* first packet size */
-	u32 write_avail = 0;
-
-	while (packet_count < burst_size) {
-		/* wait for data ready event */
-		write_avail = sdio_write_avail(test_ch->ch);
-		TEST_DBG(TEST_MODULE_NAME ":%s write_avail=%d,size=%d on chan"
-				" %s\n", __func__,
-				write_avail, size, test_ch->name);
-		if (write_avail < size) {
-			TEST_DBG(TEST_MODULE_NAME ":%s wait for event on"
-					" chan %s\n", __func__, test_ch->name);
-			wait_event(test_ch->wait_q,
-					atomic_read(&test_ch->tx_notify_count));
-			atomic_dec(&test_ch->tx_notify_count);
-		}
-		write_avail = sdio_write_avail(test_ch->ch);
-		if (write_avail < size) {
-			pr_info(TEST_MODULE_NAME ":%s not enough write"
-					" avail %d, need %d on chan %s\n",
-					__func__, write_avail, size,
-					test_ch->name);
-			continue;
-		}
-		ret = sdio_write(test_ch->ch, test_ch->buf, size);
-		if (ret) {
-			pr_err(TEST_MODULE_NAME ":%s sdio_write "
-					"failed (%d) on chan %s\n", __func__,
-					ret, test_ch->name);
-			break;
-		}
-		udelay(1000); /*low bus usage while running number of channels*/
-		TEST_DBG(TEST_MODULE_NAME ":%s() successfully write %d bytes"
-				", packet_count=%d on chan %s\n", __func__,
-				size, packet_count, test_ch->name);
-		test_ch->tx_bytes += size;
-		packet_count++;
-		/* get next packet size */
-		random_num = get_random_int();
-		size = (random_num % test_ch->packet_length) + 1;
-	}
-	return ret;
-}
-
-/**
-  * Reads packet from test channel and checks that packet number
-  * encoded into the packet is equal to packet_counter
-  * This function is applicable for packet mode channels only
-  *
-  * @test_ch: test channel
-  * @size: expected packet size
-  * @packet_counter: number to validate readed packet
-  */
-static int read_data_from_packet_ch(struct test_channel *test_ch,
-				unsigned int size,
-				int packet_counter)
-{
-	u32 read_avail = 0;
-	int ret = 0;
-
-	if (!test_ch || !test_ch->ch) {
-		pr_err(TEST_MODULE_NAME
-				":%s: NULL channel\n", __func__);
-		return -EINVAL;
-	}
-
-	if (!test_ch->ch->is_packet_mode) {
-		pr_err(TEST_MODULE_NAME
-				":%s:not packet mode ch %s\n",
-				__func__, test_ch->name);
-		return -EINVAL;
-	}
-	read_avail = sdio_read_avail(test_ch->ch);
-	/* wait for read data ready event */
-	if (read_avail < size) {
-		TEST_DBG(TEST_MODULE_NAME ":%s() wait for rx data on "
-				"chan %s\n", __func__, test_ch->name);
-		wait_event(test_ch->wait_q,
-				atomic_read(&test_ch->rx_notify_count));
-		atomic_dec(&test_ch->rx_notify_count);
-	}
-	read_avail = sdio_read_avail(test_ch->ch);
-	TEST_DBG(TEST_MODULE_NAME ":%s read_avail=%d bytes on chan %s\n",
-			__func__, read_avail, test_ch->name);
-
-	if (read_avail != size) {
-		pr_err(TEST_MODULE_NAME
-				":read_avail size %d for chan %s not as "
-				"expected size %d\n",
-				read_avail, test_ch->name, size);
-		return -EINVAL;
-	}
-
-	ret = sdio_read(test_ch->ch, test_ch->buf, read_avail);
-	if (ret) {
-		pr_err(TEST_MODULE_NAME ":%s() sdio_read for chan %s (%d)\n",
-				__func__, test_ch->name, -ret);
-		return ret;
-	}
-	if ((test_ch->buf[0] != packet_counter) && (size != 1)) {
-		pr_err(TEST_MODULE_NAME ":Read WRONG DATA"
-				" for chan %s, size=%d\n",
-				test_ch->name, size);
-		return -EINVAL;
-	}
-	return 0;
-}
-
-
-/**
-  * Reads packet from test channel and checks that packet number
-  * encoded into the packet is equal to packet_counter
-  * This function is applicable for streaming mode channels only
-  *
-  * @test_ch: test channel
-  * @size: expected packet size
-  * @packet_counter: number to validate readed packet
-  */
-static int read_data_from_stream_ch(struct test_channel *test_ch,
-				unsigned int size,
-				int packet_counter)
-{
-	u32 read_avail = 0;
-	int ret = 0;
-
-	if (!test_ch || !test_ch->ch) {
-		pr_err(TEST_MODULE_NAME
-				":%s: NULL channel\n", __func__);
-		return -EINVAL;
-	}
-
-	if (test_ch->ch->is_packet_mode) {
-		pr_err(TEST_MODULE_NAME
-				":%s:not streaming mode ch %s\n",
-				__func__, test_ch->name);
-		return -EINVAL;
-	}
-	read_avail = sdio_read_avail(test_ch->ch);
-	/* wait for read data ready event */
-	if (read_avail < size) {
-		TEST_DBG(TEST_MODULE_NAME ":%s() wait for rx data on "
-				"chan %s\n", __func__, test_ch->name);
-		wait_event(test_ch->wait_q,
-				atomic_read(&test_ch->rx_notify_count));
-		atomic_dec(&test_ch->rx_notify_count);
-	}
-	read_avail = sdio_read_avail(test_ch->ch);
-	TEST_DBG(TEST_MODULE_NAME ":%s read_avail=%d bytes on chan %s\n",
-			__func__, read_avail, test_ch->name);
-
-	if (read_avail < size) {
-		pr_err(TEST_MODULE_NAME
-				":read_avail size %d for chan %s not as "
-				"expected size %d\n",
-				read_avail, test_ch->name, size);
-		return -EINVAL;
-	}
-
-	ret = sdio_read(test_ch->ch, test_ch->buf, size + A2_HEADER_OVERHEAD);
-	if (ret) {
-		pr_err(TEST_MODULE_NAME ":%s() sdio_read for chan %s (%d)\n",
-				__func__, test_ch->name, -ret);
-		return ret;
-	}
-	if ((test_ch->buf[A2_HEADER_OVERHEAD/4] != packet_counter) &&
-	    (size != 1)) {
-		pr_err(TEST_MODULE_NAME ":Read WRONG DATA"
-				" for chan %s, size=%d, packet_counter=%d\n",
-				test_ch->name, size, packet_counter);
-		print_hex_dump(KERN_INFO, TEST_MODULE_NAME ": rmnet:",
-				0, 32, 2,
-				(void *)test_ch->buf,
-				size + A2_HEADER_OVERHEAD, false);
-		return -EINVAL;
-	}
-	return 0;
-}
-
-/**
- *   Test close channel feature for SDIO_SMEM channel:
- *   close && re-open the SDIO_SMEM channel.
- */
-#ifdef CONFIG_MSM_SDIO_SMEM
-static void open_close_smem_test(struct test_channel *test_ch)
-{
-	int i = 0;
-	int ret = 0;
-
-	pr_info(TEST_MODULE_NAME ":%s\n", __func__);
-
-	for (i = 0; i < 100 ; ++i) {
-		ret = close_sdio_ch(test_ch);
-		if (ret) {
-			pr_err(TEST_MODULE_NAME ":%s close_sdio_ch for ch %s"
-						" failed\n",
-						__func__, test_ch->name);
-			goto exit_err;
-		}
-		ret = open_sdio_ch(test_ch);
-		if (ret) {
-			pr_err(TEST_MODULE_NAME ":%s open_sdio_ch for ch %s "
-						" failed\n",
-						__func__, test_ch->name);
-			goto exit_err;
-		}
-	}
-
-	pr_info(TEST_MODULE_NAME ":%s TEST PASS for chan %s.\n", __func__,
-			test_ch->name);
-	test_ch->test_completed = 1;
-	test_ch->test_result = TEST_PASSED;
-	check_test_completion();
-	return;
-exit_err:
-	pr_info(TEST_MODULE_NAME ":%s TEST FAIL for chan %s.\n", __func__,
-			test_ch->name);
-	test_ch->test_completed = 1;
-	test_ch->test_result = TEST_FAILED;
-	check_test_completion();
-	return;
-}
-#endif
-
-/**
- *   Test close channel feature:
- *   1. write random packet number into channel
- *   2. read some data from channel (do this only for second half of
- *   requested packets to send).
- *   3. close && re-open then repeat 1.
- *
- *   Total packets to send: test_ch->config_msg.num_packets.
- *   Burst size is random in [1..test_ch->max_burst_size] range
- *   Packet size is random in [1..test_ch->packet_length]
- */
-static void open_close_test(struct test_channel *test_ch)
-{
-	int ret = 0;
-	u32 read_avail = 0;
-	int total_packet_count = 0;
-	int size = 0;
-	u16 *buf16 = NULL;
-	int i;
-	int max_packet_count = 0;
-	unsigned int random_num = 0;
-	int curr_burst_size = 0;
-
-	if (!test_ch || !test_ch->ch) {
-		pr_err(TEST_MODULE_NAME ":%s NULL channel\n",
-				__func__);
-		return;
-	}
-
-	curr_burst_size = test_ch->max_burst_size;
-	size = test_ch->packet_length;
-	buf16 = (u16 *) test_ch->buf;
-
-	/* the test sends configured number of packets in
-	   2 portions: first without reading between write bursts,
-	   second with it */
-	max_packet_count = test_ch->config_msg.num_packets / 2;
-
-	pr_info(TEST_MODULE_NAME ":%s channel %s, total packets:%d,"
-			" max packet size %d, max burst size:%d\n",
-			__func__, test_ch->name,
-			test_ch->config_msg.num_packets, test_ch->packet_length,
-			test_ch->max_burst_size);
-	for (i = 0 ; i < size / 2 ; i++)
-		buf16[i] = (u16) (i & 0xFFFF);
-
-	for (i = 0; i < 2 ; i++) {
-		total_packet_count = 0;
-		while (total_packet_count < max_packet_count) {
-			if (test_ctx->exit_flag) {
-				pr_info(TEST_MODULE_NAME ":%s exit test\n",
-						__func__);
-				return;
-			}
-			test_ch->buf[0] = total_packet_count;
-			random_num = get_random_int();
-			curr_burst_size = (random_num %
-					test_ch->max_burst_size) + 1;
-
-			/* limit burst size to send
-			 * no more than configured packets */
-			if (curr_burst_size + total_packet_count >
-					max_packet_count) {
-				curr_burst_size = max_packet_count -
-					total_packet_count;
-			}
-			TEST_DBG(TEST_MODULE_NAME ":%s Current burst size:%d"
-					" on chan %s\n", __func__,
-					curr_burst_size, test_ch->name);
-			ret = write_packet_burst(test_ch, curr_burst_size);
-			if (ret) {
-				pr_err(TEST_MODULE_NAME ":%s write burst failed (%d), ch %s\n",
-						__func__, ret, test_ch->name);
-				goto exit_err;
-			}
-			if (i > 0) {
-				/* read from channel */
-				if (test_ch->ch->is_packet_mode)
-					ret = read_data_from_packet_ch(test_ch,
-							size,
-							total_packet_count);
-				else
-					ret = read_data_from_stream_ch(test_ch,
-							size,
-							total_packet_count);
-				if (ret) {
-					pr_err(TEST_MODULE_NAME ":%s read"
-							" failed:%d, chan %s\n",
-							__func__, ret,
-							test_ch->name);
-					goto exit_err;
-				}
-			}
-			TEST_DBG(TEST_MODULE_NAME ":%s before close, ch %s\n",
-					__func__, test_ch->name);
-			ret = close_sdio_ch(test_ch);
-			if (ret) {
-				pr_err(TEST_MODULE_NAME":%s close channel %s"
-						" failed (%d)\n",
-						__func__, test_ch->name, ret);
-				goto exit_err;
-			} else {
-				TEST_DBG(TEST_MODULE_NAME":%s close channel %s"
-						" success\n", __func__,
-						test_ch->name);
-				total_packet_count += curr_burst_size;
-				atomic_set(&test_ch->rx_notify_count, 0);
-				atomic_set(&test_ch->tx_notify_count, 0);
-				atomic_set(&test_ch->any_notify_count, 0);
-			}
-			TEST_DBG(TEST_MODULE_NAME ":%s before open, ch %s\n",
-					__func__, test_ch->name);
-			ret = open_sdio_ch(test_ch);
-			if (ret) {
-				pr_err(TEST_MODULE_NAME":%s open channel %s"
-						" failed (%d)\n",
-						__func__, test_ch->name, ret);
-				goto exit_err;
-			} else {
-				read_avail = sdio_read_avail(test_ch->ch);
-				if (read_avail > 0) {
-					pr_err(TEST_MODULE_NAME": after open"
-						" ch %s read_availis not zero"
-						" (%d bytes)\n",
-						test_ch->name, read_avail);
-					goto exit_err;
-				}
-			}
-			TEST_DBG(TEST_MODULE_NAME ":%s total tx = %d,"
-					" packet# = %d, size = %d for ch %s\n",
-					__func__, test_ch->tx_bytes,
-					total_packet_count, size,
-					test_ch->name);
-		} /* end of while */
-	}
-	pr_info(TEST_MODULE_NAME ":%s Test end: total rx bytes = 0x%x,"
-			" total tx bytes = 0x%x for chan %s\n", __func__,
-			test_ch->rx_bytes, test_ch->tx_bytes, test_ch->name);
-	pr_info(TEST_MODULE_NAME ":%s TEST PASS for chan %s.\n", __func__,
-			test_ch->name);
-	test_ch->test_completed = 1;
-	test_ch->test_result = TEST_PASSED;
-	check_test_completion();
-	return;
-exit_err:
-	pr_info(TEST_MODULE_NAME ":%s TEST FAIL for chan %s.\n", __func__,
-			test_ch->name);
-	test_ch->test_completed = 1;
-	test_ch->test_result = TEST_FAILED;
-	check_test_completion();
-	return;
-}
-
-/**
- * sender Test
- */
-static void sender_test(struct test_channel *test_ch)
-{
-	int ret = 0 ;
-	u32 read_avail = 0;
-	u32 write_avail = 0;
-	int packet_count = 0;
-	int size = 512;
-	u16 *buf16 = (u16 *) test_ch->buf;
-	int i;
-	int max_packet_count = 10000;
-	int random_num = 0;
-
-	max_packet_count = test_ch->config_msg.num_packets;
-
-	for (i = 0 ; i < size / 2 ; i++)
-		buf16[i] = (u16) (i & 0xFFFF);
-
-
-	pr_info(TEST_MODULE_NAME
-		 ":SENDER TEST START for chan %s\n", test_ch->name);
-
-	while (packet_count < max_packet_count) {
-
-		if (test_ctx->exit_flag) {
-			pr_info(TEST_MODULE_NAME ":Exit Test.\n");
-			return;
-		}
-
-		random_num = get_random_int();
-		size = (random_num % test_ch->packet_length) + 1;
-
-		TEST_DBG(TEST_MODULE_NAME "SENDER WAIT FOR EVENT for chan %s\n",
-			test_ch->name);
-
-		/* wait for data ready event */
-		write_avail = sdio_write_avail(test_ch->ch);
-		TEST_DBG(TEST_MODULE_NAME ":write_avail=%d\n", write_avail);
-		if (write_avail < size) {
-			wait_event(test_ch->wait_q,
-				   atomic_read(&test_ch->tx_notify_count));
-			atomic_dec(&test_ch->tx_notify_count);
-		}
-
-		write_avail = sdio_write_avail(test_ch->ch);
-		TEST_DBG(TEST_MODULE_NAME ":write_avail=%d\n", write_avail);
-		if (write_avail < size) {
-			pr_info(TEST_MODULE_NAME ":not enough write avail.\n");
-			continue;
-		}
-
-		test_ch->buf[0] = packet_count;
-
-		ret = sdio_write(test_ch->ch, test_ch->buf, size);
-		if (ret) {
-			pr_info(TEST_MODULE_NAME ":sender sdio_write err=%d.\n",
-				-ret);
-			goto exit_err;
-		}
-
-		/* wait for read data ready event */
-		TEST_DBG(TEST_MODULE_NAME ":sender wait for rx data for "
-					  "chan %s\n",
-			 test_ch->name);
-		read_avail = sdio_read_avail(test_ch->ch);
-		wait_event(test_ch->wait_q,
-			   atomic_read(&test_ch->rx_notify_count));
-		atomic_dec(&test_ch->rx_notify_count);
-
-		read_avail = sdio_read_avail(test_ch->ch);
-
-		if (read_avail != size) {
-			pr_info(TEST_MODULE_NAME
-				":read_avail size %d for chan %s not as "
-				"expected size %d.\n",
-				read_avail, test_ch->name, size);
-			goto exit_err;
-		}
-
-		memset(test_ch->buf, 0x00, size);
-
-		ret = sdio_read(test_ch->ch, test_ch->buf, size);
-		if (ret) {
-			pr_info(TEST_MODULE_NAME ":sender sdio_read for chan %s"
-						 " err=%d.\n",
-				test_ch->name, -ret);
-			goto exit_err;
-		}
-
-
-		if ((test_ch->buf[0] != packet_count) && (size != 1)) {
-			pr_info(TEST_MODULE_NAME ":sender sdio_read WRONG DATA"
-						 " for chan %s, size=%d\n",
-				test_ch->name, size);
-			goto exit_err;
-		}
-
-		test_ch->tx_bytes += size;
-		test_ch->rx_bytes += size;
-		packet_count++;
-
-		TEST_DBG(TEST_MODULE_NAME
-			 ":sender total rx bytes = 0x%x , packet#=%d, size=%d"
-			 " for chan %s\n",
-			 test_ch->rx_bytes, packet_count, size, test_ch->name);
-		TEST_DBG(TEST_MODULE_NAME
-			 ":sender total tx bytes = 0x%x , packet#=%d, size=%d"
-			 " for chan %s\n",
-			 test_ch->tx_bytes, packet_count, size, test_ch->name);
-
-	} /* end of while */
-
-	pr_info(TEST_MODULE_NAME
-		 ":SENDER TEST END: total rx bytes = 0x%x, "
-		 " total tx bytes = 0x%x for chan %s\n",
-		 test_ch->rx_bytes, test_ch->tx_bytes, test_ch->name);
-
-	pr_info(TEST_MODULE_NAME ": TEST PASS for chan %s.\n",
-		test_ch->name);
-	test_ch->test_completed = 1;
-	test_ch->test_result = TEST_PASSED;
-	check_test_completion();
-	return;
-
-exit_err:
-	pr_info(TEST_MODULE_NAME ": TEST FAIL for chan %s.\n",
-		test_ch->name);
-	test_ch->test_completed = 1;
-	test_ch->test_result = TEST_FAILED;
-	check_test_completion();
-	return;
-}
-
-/**
- * A2 Perf Test
- */
-static void a2_performance_test(struct test_channel *test_ch)
-{
-	int ret = 0 ;
-	u32 read_avail = 0;
-	u32 write_avail = 0;
-	int tx_packet_count = 0;
-	int rx_packet_count = 0;
-	int size = 0;
-	u16 *buf16 = (u16 *) test_ch->buf;
-	int i;
-	int total_bytes = 0;
-	int max_packets = 10000;
-	u32 packet_size = test_ch->buf_size;
-	int rand_size = 0;
-
-	u64 start_jiffy, end_jiffy, delta_jiffies;
-	unsigned int time_msec = 0;
-	u32 throughput = 0;
-
-	max_packets = test_ch->config_msg.num_packets;
-	packet_size = test_ch->packet_length;
-
-	for (i = 0; i < packet_size / 2; i++)
-		buf16[i] = (u16) (i & 0xFFFF);
-
-	pr_info(TEST_MODULE_NAME ": A2 PERFORMANCE TEST START for chan %s\n",
-		test_ch->name);
-
-	start_jiffy = get_jiffies_64(); /* read the current time */
-
-	while (tx_packet_count < max_packets) {
-
-		if (test_ctx->exit_flag) {
-			pr_info(TEST_MODULE_NAME ":Exit Test.\n");
-			return;
-		}
-
-		if (test_ch->random_packet_size) {
-			rand_size = get_random_int();
-			packet_size = (rand_size % test_ch->packet_length) + 1;
-			if (packet_size < A2_MIN_PACKET_SIZE)
-				packet_size = A2_MIN_PACKET_SIZE;
-		}
-
-		/* wait for data ready event */
-		/* use a func to avoid compiler optimizations */
-		write_avail = sdio_write_avail(test_ch->ch);
-		read_avail = sdio_read_avail(test_ch->ch);
-		TEST_DBG(TEST_MODULE_NAME ":channel %s, write_avail=%d, "
-					 "read_avail=%d for chan %s\n",
-			test_ch->name, write_avail, read_avail,
-			test_ch->name);
-		if ((write_avail == 0) && (read_avail == 0)) {
-			wait_event(test_ch->wait_q,
-				   atomic_read(&test_ch->any_notify_count));
-			atomic_set(&test_ch->any_notify_count, 0);
-		}
-
-		write_avail = sdio_write_avail(test_ch->ch);
-		TEST_DBG(TEST_MODULE_NAME ":channel %s, write_avail=%d\n",
-			 test_ch->name, write_avail);
-		if (write_avail > 0) {
-			size = min(packet_size, write_avail) ;
-			TEST_DBG(TEST_MODULE_NAME ":tx size = %d for chan %s\n",
-				 size, test_ch->name);
-			test_ch->buf[0] = tx_packet_count;
-			test_ch->buf[(size/4)-1] = tx_packet_count;
-
-			ret = sdio_write(test_ch->ch, test_ch->buf, size);
-			if (ret) {
-				pr_info(TEST_MODULE_NAME ":sdio_write err=%d"
-							 " for chan %s\n",
-					-ret, test_ch->name);
-				goto exit_err;
-			}
-			tx_packet_count++;
-			test_ch->tx_bytes += size;
-		}
-
-		read_avail = sdio_read_avail(test_ch->ch);
-		TEST_DBG(TEST_MODULE_NAME ":channel %s, read_avail=%d\n",
-			 test_ch->name, read_avail);
-		if (read_avail > 0) {
-			size = min(packet_size, read_avail);
-			pr_debug(TEST_MODULE_NAME ":rx size = %d.\n", size);
-			ret = sdio_read(test_ch->ch, test_ch->buf, size);
-			if (ret) {
-				pr_info(TEST_MODULE_NAME ": sdio_read size %d "
-							 " err=%d"
-							 " for chan %s\n",
-					size, -ret, test_ch->name);
-				goto exit_err;
-			}
-			rx_packet_count++;
-			test_ch->rx_bytes += size;
-		}
-
-		TEST_DBG(TEST_MODULE_NAME
-			 ":total rx bytes = %d , rx_packet#=%d"
-			 " for chan %s\n",
-			 test_ch->rx_bytes, rx_packet_count, test_ch->name);
-		TEST_DBG(TEST_MODULE_NAME
-			 ":total tx bytes = %d , tx_packet#=%d"
-			 " for chan %s\n",
-			 test_ch->tx_bytes, tx_packet_count, test_ch->name);
-
-	} /* while (tx_packet_count < max_packets ) */
-
-	end_jiffy = get_jiffies_64(); /* read the current time */
-
-	delta_jiffies = end_jiffy - start_jiffy;
-	time_msec = jiffies_to_msecs(delta_jiffies);
-
-	pr_info(TEST_MODULE_NAME ":total rx bytes = 0x%x , rx_packet#=%d for"
-				 " chan %s.\n",
-		test_ch->rx_bytes, rx_packet_count, test_ch->name);
-	pr_info(TEST_MODULE_NAME ":total tx bytes = 0x%x , tx_packet#=%d"
-				 " for chan %s.\n",
-		test_ch->tx_bytes, tx_packet_count, test_ch->name);
-
-	total_bytes = (test_ch->tx_bytes + test_ch->rx_bytes);
-	pr_err(TEST_MODULE_NAME ":total bytes = %d, time msec = %d"
-				" for chan %s\n",
-		   total_bytes , (int) time_msec, test_ch->name);
-
-	if (!test_ch->random_packet_size) {
-		if (time_msec) {
-			throughput = (total_bytes / time_msec) * 8 / 1000;
-			pr_err(TEST_MODULE_NAME ": %s - Performance = "
-			       "%d Mbit/sec for chan %s\n",
-			       __func__, throughput, test_ch->name);
-		} else {
-			pr_err(TEST_MODULE_NAME ": %s - time_msec = 0 Couldn't "
-			       "calculate performence for chan %s\n",
-			   __func__, test_ch->name);
-		}
-
-	}
-
-#ifdef CONFIG_DEBUG_FS
-	switch (test_ch->ch_id) {
-	case SDIO_DUN:
-		test_ctx->debug.dun_throughput = throughput;
-		break;
-	case SDIO_RMNT:
-		test_ctx->debug.rmnt_throughput = throughput;
-		break;
-	default:
-		pr_err(TEST_MODULE_NAME "No debugfs for this channel "
-					"throughput");
-	}
-#endif
-
-	pr_err(TEST_MODULE_NAME ": A2 PERFORMANCE TEST END for chan %s.\n",
-	       test_ch->name);
-
-	pr_err(TEST_MODULE_NAME ": TEST PASS for chan %s\n", test_ch->name);
-	test_ch->test_completed = 1;
-	test_ch->test_result = TEST_PASSED;
-	check_test_completion();
-	return;
-
-exit_err:
-	pr_err(TEST_MODULE_NAME ": TEST FAIL for chan %s\n", test_ch->name);
-	test_ch->test_completed = 1;
-	test_ch->test_result = TEST_FAILED;
-	check_test_completion();
-	return;
-}
-
-/**
- * rx_cleanup
- * This function reads all the messages sent by the modem until
- * the read_avail is 0 after 1 second of sleep.
- * The function returns the number of packets that was received.
- */
-static void rx_cleanup(struct test_channel *test_ch, int *rx_packet_count)
-{
-	int read_avail = 0;
-	int ret = 0;
-	int counter = 0;
-
-	if (!test_ch || !test_ch->ch) {
-		pr_err(TEST_MODULE_NAME ":%s NULL channel\n",
-				__func__);
-		return;
-	}
-
-	read_avail = sdio_read_avail(test_ch->ch);
-	TEST_DBG(TEST_MODULE_NAME ":channel %s, read_avail=%d\n",
-		 test_ch->name, read_avail);
-
-	/* If no pending messages, wait to see if the modem sends data */
-	if (read_avail == 0) {
-		msleep(1000);
-		read_avail = sdio_read_avail(test_ch->ch);
-	}
-
-	while ((read_avail > 0) && (counter < 10)) {
-		TEST_DBG(TEST_MODULE_NAME ": read_avail=%d for ch %s\n",
-			 read_avail, test_ch->name);
-
-		ret = sdio_read(test_ch->ch, test_ch->buf, read_avail);
-		if (ret) {
-			pr_info(TEST_MODULE_NAME ": sdio_read size %d "
-						 " err=%d for chan %s\n",
-				read_avail, -ret, test_ch->name);
-			break;
-		}
-		(*rx_packet_count)++;
-		test_ch->rx_bytes += read_avail;
-		read_avail = sdio_read_avail(test_ch->ch);
-		if (read_avail == 0) {
-			msleep(1000);
-			counter++;
-			read_avail = sdio_read_avail(test_ch->ch);
-		}
-	}
-	pr_info(TEST_MODULE_NAME ": finished cleanup for ch %s, "
-				 "rx_packet_count=%d, total rx bytes=%d\n",
-			 test_ch->name, *rx_packet_count, test_ch->rx_bytes);
-}
-
-
-/**
- * A2 RTT Test
- * This function sends a packet and calculate the RTT time of
- * this packet.
- * The test also calculte Min, Max and Average RTT
- */
-static void a2_rtt_test(struct test_channel *test_ch)
-{
-	int ret = 0 ;
-	u32 read_avail = 0;
-	u32 write_avail = 0;
-	int tx_packet_count = 0;
-	int rx_packet_count = 0;
-	u16 *buf16 = NULL;
-	int i;
-	int max_packets = 0;
-	u32 packet_size = 0;
-	s64 start_time, end_time;
-	int delta_usec = 0;
-	int time_average = 0;
-	int min_delta_usec = 0xFFFF;
-	int max_delta_usec = 0;
-	int total_time = 0;
-	int expected_read_size = 0;
-	int delay_ms = 0;
-	int slow_rtt_counter = 0;
-	int read_avail_so_far = 0;
-
-	if (test_ch) {
-		/*
-		 * Cleanup the pending RX data (such as loopback of the
-		 * config msg)
-		 */
-		rx_cleanup(test_ch, &rx_packet_count);
-		rx_packet_count = 0;
-	} else {
-		return;
-	}
-
-	max_packets = test_ch->config_msg.num_packets;
-	packet_size = test_ch->packet_length;
-	buf16 = (u16 *) test_ch->buf;
-
-	for (i = 0; i < packet_size / 2; i++)
-		buf16[i] = (u16) (i & 0xFFFF);
-
-	pr_info(TEST_MODULE_NAME ": A2 RTT TEST START for chan %s\n",
-		test_ch->name);
-
-	switch (test_ch->ch_id) {
-	case SDIO_RMNT:
-		delay_ms = 100;
-		break;
-	case SDIO_CSVT:
-		delay_ms = 0;
-		break;
-	default:
-		pr_err(TEST_MODULE_NAME ": %s - ch_id invalid.\n",
-		       __func__);
-		return;
-	}
-
-	while (tx_packet_count < max_packets) {
-		if (test_ctx->exit_flag) {
-			pr_info(TEST_MODULE_NAME ":Exit Test.\n");
-			return;
-		}
-		start_time = 0;
-		end_time = 0;
-		read_avail_so_far = 0;
-
-		if (delay_ms)
-			msleep(delay_ms);
-
-		/* wait for data ready event */
-		write_avail = sdio_write_avail(test_ch->ch);
-		TEST_DBG(TEST_MODULE_NAME ":ch %s: write_avail=%d\n",
-			test_ch->name, write_avail);
-		if (write_avail == 0) {
-			wait_event(test_ch->wait_q,
-				   atomic_read(&test_ch->tx_notify_count));
-			atomic_dec(&test_ch->tx_notify_count);
-		}
-
-		write_avail = sdio_write_avail(test_ch->ch);
-		TEST_DBG(TEST_MODULE_NAME ":channel %s, write_avail=%d\n",
-			 test_ch->name, write_avail);
-		if (write_avail > 0) {
-			TEST_DBG(TEST_MODULE_NAME ":tx size = %d for chan %s\n",
-				 packet_size, test_ch->name);
-			test_ch->buf[0] = tx_packet_count;
-
-			start_time = ktime_to_us(ktime_get());
-			ret = sdio_write(test_ch->ch, test_ch->buf,
-					 packet_size);
-			if (ret) {
-				pr_err(TEST_MODULE_NAME ":sdio_write err=%d"
-							 " for chan %s\n",
-					-ret, test_ch->name);
-				goto exit_err;
-			}
-			tx_packet_count++;
-			test_ch->tx_bytes += packet_size;
-		} else {
-				pr_err(TEST_MODULE_NAME ": Invalid write_avail"
-							 " %d for chan %s\n",
-					write_avail, test_ch->name);
-				goto exit_err;
-		}
-
-		expected_read_size = packet_size + A2_HEADER_OVERHEAD;
-
-		while (read_avail_so_far < expected_read_size) {
-
-			read_avail = sdio_read_avail(test_ch->ch);
-
-			if (!read_avail) {
-				wait_event(test_ch->wait_q,
-					   atomic_read(&test_ch->
-						       rx_notify_count));
-
-				atomic_dec(&test_ch->rx_notify_count);
-				continue;
-			}
-
-			read_avail_so_far += read_avail;
-
-			if (read_avail_so_far > expected_read_size) {
-				pr_err(TEST_MODULE_NAME ": %s - Invalid "
-				       "read_avail(%d)  read_avail_so_far(%d) "
-				       "can't be larger than "
-				       "expected_read_size(%d).",
-				       __func__,
-				       read_avail,
-				       read_avail_so_far,
-				       expected_read_size);
-				goto exit_err;
-			}
-
-			/*
-			 * must read entire pending bytes, so later, we will
-			 * get a notification when more data arrives
-			 */
-			ret = sdio_read(test_ch->ch, test_ch->buf,
-					read_avail);
-
-			if (ret) {
-				pr_info(TEST_MODULE_NAME ": sdio_read size %d "
-					" err=%d for chan %s\n",
-					read_avail, -ret,
-					test_ch->name);
-				goto exit_err;
-			}
-		}
-
-		end_time = ktime_to_us(ktime_get());
-		rx_packet_count++;
-		test_ch->rx_bytes += expected_read_size;
-
-		delta_usec = (int)(end_time - start_time);
-		total_time += delta_usec;
-		if (delta_usec < min_delta_usec)
-				min_delta_usec = delta_usec;
-		if (delta_usec > max_delta_usec)
-				max_delta_usec = delta_usec;
-
-		/* checking the RTT per channel criteria */
-		if (delta_usec > MAX_AVG_RTT_TIME_USEC) {
-			pr_err(TEST_MODULE_NAME ": %s - "
-			       "msg # %d - rtt time (%d usec) is "
-			       "longer than %d usec\n",
-			       __func__,
-			       tx_packet_count,
-			       delta_usec,
-			       MAX_AVG_RTT_TIME_USEC);
-			slow_rtt_counter++;
-		}
-
-		TEST_DBG(TEST_MODULE_NAME
-			 ":RTT time=%d for packet #%d for chan %s\n",
-			 delta_usec, tx_packet_count, test_ch->name);
-	} /* while (tx_packet_count < max_packets ) */
-
-	pr_info(TEST_MODULE_NAME ": %s - tx_packet_count = %d\n",
-		__func__, tx_packet_count);
-
-	pr_info(TEST_MODULE_NAME ": %s - total rx bytes = 0x%x, "
-		"rx_packet# = %d for chan %s.\n",
-		__func__, test_ch->rx_bytes, rx_packet_count, test_ch->name);
-
-	pr_info(TEST_MODULE_NAME ": %s - total tx bytes = 0x%x, "
-		"tx_packet# = %d for chan %s.\n",
-		__func__, test_ch->tx_bytes, tx_packet_count, test_ch->name);
-
-	pr_info(TEST_MODULE_NAME ": %s - slow_rtt_counter = %d for "
-		"chan %s.\n",
-		__func__, slow_rtt_counter, test_ch->name);
-
-	if (tx_packet_count) {
-		time_average = total_time / tx_packet_count;
-		pr_info(TEST_MODULE_NAME ":Average RTT time = %d for chan %s\n",
-		   time_average, test_ch->name);
-	} else {
-		pr_err(TEST_MODULE_NAME ": %s - tx_packet_count=0. couldn't "
-		       "calculate average rtt time", __func__);
-	}
-
-	pr_info(TEST_MODULE_NAME ":MIN RTT time = %d for chan %s\n",
-		   min_delta_usec, test_ch->name);
-	pr_info(TEST_MODULE_NAME ":MAX RTT time = %d for chan %s\n",
-		   max_delta_usec, test_ch->name);
-
-	pr_info(TEST_MODULE_NAME ": A2 RTT TEST END for chan %s.\n",
-	       test_ch->name);
-
-	if (ret)
-		goto exit_err;
-
-	if (time_average == 0 || time_average > MAX_AVG_RTT_TIME_USEC) {
-		pr_err(TEST_MODULE_NAME ": %s - average_time = %d. Invalid "
-		       "value",
-		       __func__, time_average);
-		goto exit_err;
-
-	}
-
-	pr_info(TEST_MODULE_NAME ": TEST PASS for chan %s\n", test_ch->name);
-	test_ch->test_completed = 1;
-	test_ch->test_result = TEST_PASSED;
-	check_test_completion();
-	return;
-
-exit_err:
-	pr_err(TEST_MODULE_NAME ": TEST FAIL for chan %s\n", test_ch->name);
-	test_ch->test_completed = 1;
-	test_ch->test_result = TEST_FAILED;
-	check_test_completion();
-	return;
-}
-
-/**
- * Process Rx Data - Helper for A2 Validation Test
- * @test_ch(in/out) : Test channel that contains Rx data buffer to process.
- *
- * @rx_unprocessed_bytes(in) : Number of bytes to process in the buffer.
- *
- * @rx_process_packet_state(in/out) :
- * Current processing state (used to identify what to process
- * next in a partial packet)
- *
- * @rx_packet_size(in/out) :
- * Number of bytes remaining in the packet to be processed.
- *
- * @rx_packet_count(in/out) :
- * Number of packets processed.
- */
-static int process_rx_data(struct test_channel *test_ch,
-			   u32 rx_unprocessed_bytes,
-			   int *rx_process_packet_state,
-			   u16 *rx_packet_size,
-			   int *rx_packet_count)
-{
-	u8 *buf = (u8 *)test_ch->buf;
-	int eop = 0;
-	int i = 0;
-	int ret = 0;
-	u32 *ptr = 0;
-	u16 size = 0;
-
-	/* process rx data */
-	while (rx_unprocessed_bytes) {
-		TEST_DBG(TEST_MODULE_NAME ": unprocessed bytes : %u\n",
-			rx_unprocessed_bytes);
-
-		switch (*rx_process_packet_state) {
-		case RX_PROCESS_PACKET_INIT:
-			/* process the A2 header */
-			TEST_DBG(TEST_MODULE_NAME ": "
-				"RX_PROCESS_PACKET_INIT\n");
-			*rx_process_packet_state = RX_PROCESS_PACKET_INIT;
-			if (rx_unprocessed_bytes < 4)
-				break;
-
-			i += 4;
-			rx_unprocessed_bytes -= 4;
-
-		case RX_PROCESS_A2_HEADER:
-			/* process the rest of A2 header */
-			TEST_DBG(TEST_MODULE_NAME ": RX_PROCESS_A2_HEADER\n");
-			*rx_process_packet_state = RX_PROCESS_A2_HEADER;
-			if (rx_unprocessed_bytes < 4)
-				break;
-
-			ptr = (u32 *)&buf[i];
-			/*
-			 * upper 2 bytes of the last 4 bytes of A2 header
-			 * contains the size of the packet
-			 */
-			*rx_packet_size = *ptr >> 0x10;
-
-			i += 4;
-			rx_unprocessed_bytes -= 4;
-
-		case RX_PROCESS_PACKET_DATA:
-			/* process the2_2_ packet data */
-			TEST_DBG(TEST_MODULE_NAME ": RX_PROCESS_PACKET_DATA "
-				 "- packet size - %u\n", *rx_packet_size);
-			*rx_process_packet_state = RX_PROCESS_PACKET_DATA;
-
-			size = *rx_packet_size;
-			if (*rx_packet_size <= rx_unprocessed_bytes) {
-				eop = *rx_packet_size;
-				*rx_packet_size = 0;
-			} else {
-				eop = rx_unprocessed_bytes;
-				*rx_packet_size = *rx_packet_size -
-						  rx_unprocessed_bytes;
-			}
-
-			/* no more bytes available to process */
-			if (!eop)
-				break;
-			/*
-			 * end of packet is starting from
-			 * the current position
-			 */
-			eop = eop + i;
-			TEST_DBG(TEST_MODULE_NAME ": size - %u, "
-				 "packet size - %u eop - %d\n",
-				 size, *rx_packet_size, eop);
-
-			/* validate the data */
-			for (; i < eop; i++) {
-				if (buf[i] != (test_ch->rx_bytes % 256)) {
-					pr_err(TEST_MODULE_NAME ": "
-					       "Corrupt data. buf:%u, "
-					       "data:%u\n", buf[i],
-					       test_ch->rx_bytes % 256);
-					ret = -EINVAL;
-					goto err;
-				}
-				rx_unprocessed_bytes--;
-				test_ch->rx_bytes++;
-			}
-
-			/* have more data to be processed */
-			if (*rx_packet_size)
-				break;
-
-			/*
-			 * A2 sends data in 4 byte alignment,
-			 * skip the padding
-			 */
-			if (size % 4) {
-				i += 4 - (size % 4);
-				rx_unprocessed_bytes -= 4 - (size % 4);
-			}
-			*rx_packet_count = *rx_packet_count + 1;
-
-			/* re init the state to process new packet */
-			*rx_process_packet_state = RX_PROCESS_PACKET_INIT;
-			break;
-		default:
-			pr_err(TEST_MODULE_NAME ": Invalid case: %d\n",
-			       *rx_process_packet_state);
-			ret = -EINVAL;
-			goto err;
-		}
-		TEST_DBG(TEST_MODULE_NAME ": Continue processing "
-			"if more data is available\n");
-	}
-
-err:
-	return ret;
-}
-
-/**
- * A2 Validation Test
- * Send packets and validate the returned packets.
- * Transmit one packet at a time, while process multiple rx
- * packets in a single transaction.
- * A transaction is of size min(random number, write_avail).
- * A packet consists of a min of 1 byte to channel supported max.
- */
-static void a2_validation_test(struct test_channel *test_ch)
-{
-	int ret = 0 ;
-	u32 read_avail = 0;
-	u32 write_avail = 0;
-	int tx_packet_count = 0;
-	int rx_packet_count = 0;
-	int initial_rx_packet_count = 0;
-	u32 size = 0;
-	u8 *buf8 = (u8 *)test_ch->buf;
-	int i = 0;
-	int max_packets = test_ch->config_msg.num_packets;
-	u16 tx_packet_size = 0;
-	u16 rx_packet_size = 0;
-	u32 random_num = 0;
-	int rx_process_packet_state = RX_PROCESS_PACKET_INIT;
-
-	pr_info(TEST_MODULE_NAME ": A2 VALIDATION TEST START for chan %s\n",
-		test_ch->name);
-
-	/* Wait for the initial rx messages before starting the test. */
-	rx_cleanup(test_ch, &initial_rx_packet_count);
-
-	test_ch->tx_bytes = 0;
-	test_ch->rx_bytes = 0;
-
-	/* Continue till we have transmitted and received all packets */
-	while ((tx_packet_count < max_packets) ||
-	       (rx_packet_count < max_packets)) {
-
-		if (test_ctx->exit_flag) {
-			pr_info(TEST_MODULE_NAME ":Exit Test.\n");
-			return;
-		}
-
-		random_num = get_random_int();
-		size = (random_num % test_ch->packet_length) + 1;
-		TEST_DBG(TEST_MODULE_NAME ": Random tx packet size =%u", size);
-
-		/*
-		 * wait for data ready event
-		 * use a func to avoid compiler optimizations
-		 */
-		write_avail = sdio_write_avail(test_ch->ch);
-		read_avail = sdio_read_avail(test_ch->ch);
-		TEST_DBG(TEST_MODULE_NAME ": write_avail=%d, "
-			"read_avail=%d for chan %s\n",
-			write_avail, read_avail, test_ch->name);
-
-		if ((write_avail == 0) && (read_avail == 0)) {
-			wait_event(test_ch->wait_q,
-				   atomic_read(&test_ch->any_notify_count));
-			atomic_set(&test_ch->any_notify_count, 0);
-		}
-
-		/* Transmit data */
-		write_avail = sdio_write_avail(test_ch->ch);
-		if ((tx_packet_count < max_packets) && (write_avail > 0)) {
-			tx_packet_size = min(size, write_avail) ;
-			TEST_DBG(TEST_MODULE_NAME ": tx size = %u, "
-				"write_avail = %u tx_packet# = %d\n",
-				tx_packet_size, write_avail,
-				tx_packet_count);
-			memset(test_ch->buf, 0, test_ch->buf_size);
-			/* populate the buffer */
-			for (i = 0; i < tx_packet_size; i++) {
-				buf8[i] = test_ch->tx_bytes % 256;
-				test_ch->tx_bytes++;
-			}
-
-			ret = sdio_write(test_ch->ch, test_ch->buf,
-					  tx_packet_size);
-			if (ret) {
-				pr_err(TEST_MODULE_NAME ":sdio_write err=%d"
-					" for chan %s\n",
-					-ret, test_ch->name);
-				goto exit_err;
-			}
-			tx_packet_count++;
-		}
-
-		/* Receive data */
-		read_avail = sdio_read_avail(test_ch->ch);
-		if (read_avail > 0) {
-			TEST_DBG(TEST_MODULE_NAME ": rx size = %u, "
-				"rx_packet#=%d.\n",
-				read_avail, rx_packet_count);
-			memset(test_ch->buf, 0, test_ch->buf_size);
-
-			ret = sdio_read(test_ch->ch, test_ch->buf,
-					read_avail);
-			if (ret) {
-				pr_err(TEST_MODULE_NAME ": sdio_read "
-					"size %d err=%d for chan %s\n",
-					size, -ret, test_ch->name);
-				goto exit_err;
-			}
-
-			/* Process data */
-			ret = process_rx_data(test_ch, read_avail,
-					      &rx_process_packet_state,
-					      &rx_packet_size,
-					      &rx_packet_count);
-
-			if (ret != 0)
-				goto exit_err;
-		}
-		TEST_DBG(TEST_MODULE_NAME ": Continue loop ...\n");
-	}
-
-	if (test_ch->tx_bytes != test_ch->rx_bytes) {
-		pr_err(TEST_MODULE_NAME ": Total number of bytes "
-			"transmitted (%u) does not match the total "
-			"number of bytes received (%u).", test_ch->tx_bytes,
-			test_ch->rx_bytes);
-		goto exit_err;
-	}
-
-	pr_info(TEST_MODULE_NAME ": A2 VALIDATION TEST END for chan %s.\n",
-		test_ch->name);
-
-	pr_info(TEST_MODULE_NAME ": TEST PASS for chan %s\n", test_ch->name);
-	test_ch->test_completed = 1;
-	test_ch->test_result = TEST_PASSED;
-	check_test_completion();
-	return;
-
-exit_err:
-	pr_info(TEST_MODULE_NAME ": TEST FAIL for chan %s\n", test_ch->name);
-	test_ch->test_completed = 1;
-	test_ch->test_result = TEST_FAILED;
-	check_test_completion();
-	return;
-}
-
-/**
- * sender No loopback Test
- */
-static void sender_no_loopback_test(struct test_channel *test_ch)
-{
-	int ret = 0 ;
-	u32 write_avail = 0;
-	int packet_count = 0;
-	int size = 512;
-	u16 *buf16 = (u16 *) test_ch->buf;
-	int i;
-	int max_packet_count = 10000;
-	unsigned int random_num = 0;
-
-	max_packet_count = test_ch->config_msg.num_packets;
-
-	for (i = 0 ; i < size / 2 ; i++)
-		buf16[i] = (u16) (i & 0xFFFF);
-
-	pr_info(TEST_MODULE_NAME
-		 ":SENDER NO LP TEST START for chan %s\n", test_ch->name);
-
-	while (packet_count < max_packet_count) {
-
-		if (test_ctx->exit_flag) {
-			pr_info(TEST_MODULE_NAME ":Exit Test.\n");
-			return;
-		}
-
-		random_num = get_random_int();
-		size = (random_num % test_ch->packet_length) + 1;
-
-		TEST_DBG(TEST_MODULE_NAME ":SENDER WAIT FOR EVENT "
-					  "for chan %s\n",
-			test_ch->name);
-
-		/* wait for data ready event */
-		write_avail = sdio_write_avail(test_ch->ch);
-		TEST_DBG(TEST_MODULE_NAME ":write_avail=%d\n", write_avail);
-		if (write_avail < size) {
-			wait_event(test_ch->wait_q,
-				   atomic_read(&test_ch->tx_notify_count));
-			atomic_dec(&test_ch->tx_notify_count);
-		}
-
-		write_avail = sdio_write_avail(test_ch->ch);
-		TEST_DBG(TEST_MODULE_NAME ":write_avail=%d\n", write_avail);
-		if (write_avail < size) {
-			pr_info(TEST_MODULE_NAME ":not enough write avail.\n");
-			continue;
-		}
-
-		test_ch->buf[0] = packet_count;
-
-		ret = sdio_write(test_ch->ch, test_ch->buf, size);
-		if (ret) {
-			pr_info(TEST_MODULE_NAME ":sender sdio_write err=%d.\n",
-				-ret);
-			goto exit_err;
-		}
-
-		test_ch->tx_bytes += size;
-		packet_count++;
-
-		TEST_DBG(TEST_MODULE_NAME
-			 ":sender total tx bytes = 0x%x , packet#=%d, size=%d"
-			 " for chan %s\n",
-			 test_ch->tx_bytes, packet_count, size, test_ch->name);
-
-	} /* end of while */
-
-	pr_info(TEST_MODULE_NAME
-		 ":SENDER TEST END: total tx bytes = 0x%x, "
-		 " for chan %s\n",
-		 test_ch->tx_bytes, test_ch->name);
-
-	test_ch->modem_result_per_chan = wait_for_result_msg(test_ch);
-
-	if (test_ch->modem_result_per_chan) {
-		pr_info(TEST_MODULE_NAME ": TEST PASS for chan %s.\n",
-			test_ch->name);
-		test_ch->test_result = TEST_PASSED;
-	} else {
-		pr_info(TEST_MODULE_NAME ": TEST FAILURE for chan %s.\n",
-			test_ch->name);
-		test_ch->test_result = TEST_FAILED;
-	}
-	test_ch->test_completed = 1;
-	check_test_completion();
-	return;
-
-exit_err:
-	pr_info(TEST_MODULE_NAME ": TEST FAIL for chan %s.\n",
-		test_ch->name);
-	test_ch->test_completed = 1;
-	test_ch->test_result = TEST_FAILED;
-	check_test_completion();
-	return;
-}
-
-
-/**
- * Modem reset Test
- * The test verifies that it finished sending all the packets
- * while there might be modem reset in the middle
- */
-static void modem_reset_test(struct test_channel *test_ch)
-{
-	int ret = 0 ;
-	u32 read_avail = 0;
-	u32 write_avail = 0;
-	int tx_packet_count = 0;
-	int rx_packet_count = 0;
-	int size = 0;
-	u16 *buf16 = (u16 *) test_ch->buf;
-	int i;
-	int max_packets = 10000;
-	u32 packet_size = test_ch->buf_size;
-	int is_err = 0;
-
-	max_packets = test_ch->config_msg.num_packets;
-	packet_size = test_ch->packet_length;
-
-	for (i = 0; i < packet_size / 2; i++)
-		buf16[i] = (u16) (i & 0xFFFF);
-
-	pr_info(TEST_MODULE_NAME ": Modem Reset TEST START for chan %s\n",
-		test_ch->name);
-
-	while (tx_packet_count < max_packets) {
-
-		if (test_ctx->exit_flag) {
-			pr_info(TEST_MODULE_NAME ":Exit Test.\n");
-			return;
-		}
-
-		if (test_ch->card_removed) {
-			pr_info(TEST_MODULE_NAME ": card removal was detected "
-				"for chan %s, tx_total=0x%x\n",
-				test_ch->name, test_ch->tx_bytes);
-			wait_event(test_ch->wait_q,
-				   atomic_read(&test_ch->card_detected_event));
-			atomic_set(&test_ch->card_detected_event, 0);
-			pr_info(TEST_MODULE_NAME ": card_detected_event "
-					"for chan %s\n", test_ch->name);
-			if (test_ch->card_removed)
-				continue;
-			is_err = 0;
-			/* Need to wait for the modem to be ready */
-			msleep(5000);
-			pr_info(TEST_MODULE_NAME ": sending the config message "
-					"for chan %s\n", test_ch->name);
-			send_config_msg(test_ch);
-		}
-
-		/* wait for data ready event */
-		/* use a func to avoid compiler optimizations */
-		write_avail = sdio_write_avail(test_ch->ch);
-		read_avail = sdio_read_avail(test_ch->ch);
-		TEST_DBG(TEST_MODULE_NAME ":channel %s, write_avail=%d, "
-					 "read_avail=%d for chan %s\n",
-			test_ch->name, write_avail, read_avail,
-			test_ch->name);
-		if ((write_avail == 0) && (read_avail == 0)) {
-			wait_event(test_ch->wait_q,
-				   atomic_read(&test_ch->any_notify_count));
-			atomic_set(&test_ch->any_notify_count, 0);
-		}
-		if (atomic_read(&test_ch->card_detected_event)) {
-			atomic_set(&test_ch->card_detected_event, 0);
-			pr_info(TEST_MODULE_NAME ": card_detected_event "
-				"for chan %s, tx_total=0x%x\n",
-				test_ch->name,  test_ch->tx_bytes);
-			if (test_ch->card_removed)
-				continue;
-			/* Need to wait for the modem to be ready */
-			msleep(5000);
-			is_err = 0;
-			pr_info(TEST_MODULE_NAME ": sending the config message "
-					"for chan %s\n", test_ch->name);
-			send_config_msg(test_ch);
-		}
-
-		write_avail = sdio_write_avail(test_ch->ch);
-		TEST_DBG(TEST_MODULE_NAME ":channel %s, write_avail=%d\n",
-			 test_ch->name, write_avail);
-		if (write_avail > 0) {
-			size = min(packet_size, write_avail) ;
-			pr_debug(TEST_MODULE_NAME ":tx size = %d for chan %s\n",
-				 size, test_ch->name);
-			test_ch->buf[0] = tx_packet_count;
-			test_ch->buf[(size/4)-1] = tx_packet_count;
-
-			TEST_DBG(TEST_MODULE_NAME ":channel %s, sdio_write, "
-				"size=%d\n", test_ch->name, size);
-			if (is_err) {
-				msleep(100);
-				continue;
-			}
-			ret = sdio_write(test_ch->ch, test_ch->buf, size);
-			if (ret) {
-				pr_info(TEST_MODULE_NAME ":sdio_write err=%d"
-							 " for chan %s\n",
-					-ret, test_ch->name);
-				is_err = 1;
-				msleep(20);
-				continue;
-			}
-			tx_packet_count++;
-			test_ch->tx_bytes += size;
-			test_ch->config_msg.num_packets--;
-		}
-
-		read_avail = sdio_read_avail(test_ch->ch);
-		TEST_DBG(TEST_MODULE_NAME ":channel %s, read_avail=%d\n",
-			 test_ch->name, read_avail);
-		if (read_avail > 0) {
-			size = min(packet_size, read_avail);
-			pr_debug(TEST_MODULE_NAME ":rx size = %d.\n", size);
-			TEST_DBG(TEST_MODULE_NAME ":channel %s, sdio_read, "
-				"size=%d\n", test_ch->name, size);
-			if (is_err) {
-				msleep(100);
-				continue;
-			}
-			ret = sdio_read(test_ch->ch, test_ch->buf, size);
-			if (ret) {
-				pr_info(TEST_MODULE_NAME ": sdio_read size %d "
-							 " err=%d"
-							 " for chan %s\n",
-					size, -ret, test_ch->name);
-				is_err = 1;
-				msleep(20);
-				continue;
-			}
-			rx_packet_count++;
-			test_ch->rx_bytes += size;
-		}
-
-		TEST_DBG(TEST_MODULE_NAME
-			 ":total rx bytes = %d , rx_packet#=%d"
-			 " for chan %s\n",
-			 test_ch->rx_bytes, rx_packet_count, test_ch->name);
-		TEST_DBG(TEST_MODULE_NAME
-			 ":total tx bytes = %d , tx_packet#=%d"
-			 " for chan %s\n",
-			 test_ch->tx_bytes, tx_packet_count, test_ch->name);
-
-		udelay(500);
-
-	} /* while (tx_packet_count < max_packets ) */
-
-	pr_info(TEST_MODULE_NAME ":total rx bytes = 0x%x , rx_packet#=%d for"
-				 " chan %s.\n",
-		test_ch->rx_bytes, rx_packet_count, test_ch->name);
-	pr_info(TEST_MODULE_NAME ":total tx bytes = 0x%x , tx_packet#=%d"
-				 " for chan %s.\n",
-		test_ch->tx_bytes, tx_packet_count, test_ch->name);
-
-	pr_err(TEST_MODULE_NAME ": Modem Reset TEST END for chan %s.\n",
-	       test_ch->name);
-
-	pr_err(TEST_MODULE_NAME ": TEST PASS for chan %s\n", test_ch->name);
-	test_ch->test_completed = 1;
-	test_ch->test_result = TEST_PASSED;
-	check_test_completion();
-	return;
-}
-
-/**
- * Worker thread to handle the tests types
- */
-static void worker(struct work_struct *work)
-{
-	struct test_channel *test_ch = NULL;
-	struct test_work *test_work = container_of(work,
-						 struct	test_work,
-						 work);
-	int test_type = 0;
-
-	test_ch = test_work->test_ch;
-
-	if (test_ch == NULL) {
-		pr_err(TEST_MODULE_NAME ":NULL test_ch\n");
-		return;
-	}
-
-	test_type = test_ch->test_type;
-
-	switch (test_type) {
-	case SDIO_TEST_LOOPBACK_HOST:
-		loopback_test(test_ch);
-		break;
-	case SDIO_TEST_LOOPBACK_CLIENT:
-		sender_test(test_ch);
-		break;
-	case SDIO_TEST_PERF:
-		a2_performance_test(test_ch);
-		break;
-	case SDIO_TEST_LPM_CLIENT_WAKER:
-		lpm_test(test_ch);
-		break;
-	case SDIO_TEST_LPM_HOST_WAKER:
-		lpm_test_host_waker(test_ch);
-		break;
-	case SDIO_TEST_HOST_SENDER_NO_LP:
-		sender_no_loopback_test(test_ch);
-		break;
-	case SDIO_TEST_LPM_RANDOM:
-		lpm_continuous_rand_test(test_ch);
-		break;
-	case SDIO_TEST_RTT:
-		a2_rtt_test(test_ch);
-		break;
-	case SDIO_TEST_CLOSE_CHANNEL:
-		if (test_ch->ch_id != SDIO_SMEM)
-			open_close_test(test_ch);
-		break;
-	case SDIO_TEST_MODEM_RESET:
-		modem_reset_test(test_ch);
-		break;
-	case SDIO_TEST_A2_VALIDATION:
-		a2_validation_test(test_ch);
-		break;
-	default:
-		pr_err(TEST_MODULE_NAME ":Bad Test type = %d.\n",
-			(int) test_type);
-	}
-}
-
-
-/**
- * Notification Callback
- *
- * Notify the worker
- *
- */
-static void notify(void *priv, unsigned channel_event)
-{
-	struct test_channel *test_ch = (struct test_channel *) priv;
-
-	pr_debug(TEST_MODULE_NAME ": %s - notify event=%d.\n",
-		 __func__, channel_event);
-
-	if (test_ch->ch == NULL) {
-		pr_info(TEST_MODULE_NAME ": %s - notify before ch ready.\n",
-			__func__);
-		return;
-	}
-
-	switch (channel_event) {
-	case SDIO_EVENT_DATA_READ_AVAIL:
-		atomic_inc(&test_ch->rx_notify_count);
-		atomic_set(&test_ch->any_notify_count, 1);
-		TEST_DBG(TEST_MODULE_NAME ": %s - SDIO_EVENT_DATA_READ_AVAIL, "
-			 "any_notify_count=%d, rx_notify_count=%d\n",
-			 __func__,
-			 atomic_read(&test_ch->any_notify_count),
-			 atomic_read(&test_ch->rx_notify_count));
-		/*
-		 * when there is pending data on a channel we would like to
-		 * turn on the bit mask that implies that there is pending
-		 * data for that channel on that deivce
-		 */
-		if (test_ch->test_device != NULL &&
-		    test_ch->test_type == SDIO_TEST_LPM_RANDOM) {
-			spin_lock_irqsave(&test_ch->test_device->lpm_array_lock,
-					  test_ch->test_device->
-						  lpm_array_lock_flags);
-			test_ch->test_device->read_avail_mask |=
-				test_ch->channel_mask_id;
-			test_ch->notify_counter_per_chan++;
-
-			lpm_test_update_entry(test_ch, LPM_NOTIFY, "NOTIFY", 0);
-			spin_unlock_irqrestore(&test_ch->test_device->
-					       lpm_array_lock,
-					       test_ch->test_device->
-						  lpm_array_lock_flags);
-		}
-		break;
-
-	case SDIO_EVENT_DATA_WRITE_AVAIL:
-		atomic_inc(&test_ch->tx_notify_count);
-		atomic_set(&test_ch->any_notify_count, 1);
-		TEST_DBG(TEST_MODULE_NAME ": %s - SDIO_EVENT_DATA_WRITE_AVAIL, "
-			 "any_notify_count=%d, tx_notify_count=%d\n",
-			 __func__,
-			 atomic_read(&test_ch->any_notify_count),
-			 atomic_read(&test_ch->tx_notify_count));
-		break;
-
-	default:
-		BUG();
-	}
-	wake_up(&test_ch->wait_q);
-
-}
-
-#ifdef CONFIG_MSM_SDIO_SMEM
-static int sdio_smem_test_cb(int event)
-{
-	struct test_channel *tch = test_ctx->test_ch_arr[SDIO_SMEM];
-	int i;
-	int *smem_buf = (int *)test_ctx->smem_buf;
-	uint32_t val = 0;
-	int ret = 0;
-
-	pr_debug(TEST_MODULE_NAME ":%s: Received event %d\n", __func__, event);
-
-	if (!tch) {
-		pr_err(TEST_MODULE_NAME ": %s NULL tch\n", __func__);
-		return -EINVAL;
-	}
-
-	switch (event) {
-	case SDIO_SMEM_EVENT_READ_DONE:
-		tch->rx_bytes += SMEM_MAX_XFER_SIZE;
-		for (i = 0; i < SMEM_MAX_XFER_SIZE;) {
-			val = (int)*smem_buf;
-			if ((val != test_ctx->smem_counter) && tch->is_used) {
-				pr_err(TEST_MODULE_NAME ":%s: Invalid value %d "
-				"expected %d in smem arr",
-				__func__, val, test_ctx->smem_counter);
-				pr_err(TEST_MODULE_NAME ":SMEM test FAILED\n");
-				tch->test_completed = 1;
-				tch->test_result = TEST_FAILED;
-				check_test_completion();
-				ret = -EINVAL;
-				goto exit;
-			}
-			i += 4;
-			smem_buf++;
-			test_ctx->smem_counter++;
-		}
-		if (tch->rx_bytes >= 40000000) {
-			if ((!tch->test_completed) && tch->is_used) {
-				pr_info(TEST_MODULE_NAME ":SMEM test PASSED\n");
-				tch->test_completed = 1;
-				tch->test_result = TEST_PASSED;
-				check_test_completion();
-			}
-		}
-		break;
-	case SDIO_SMEM_EVENT_READ_ERR:
-		if (tch->is_used) {
-			pr_err(TEST_MODULE_NAME ":Read overflow, "
-						"SMEM test FAILED\n");
-			tch->test_completed = 1;
-			tch->test_result = TEST_FAILED;
-			ret = -EIO;
-		}
-		break;
-	default:
-		if (tch->is_used) {
-			pr_err(TEST_MODULE_NAME ":Unhandled event %d\n", event);
-			ret = -EINVAL;
-		}
-		break;
-	}
-exit:
-	return ret;
-}
-
-static int sdio_smem_open(struct sdio_smem_client *sdio_smem)
-{
-	int ret = 0;
-
-	if (!sdio_smem) {
-		pr_info(TEST_MODULE_NAME "%s: NULL sdio_smem_client\n",
-			__func__);
-		return -EINVAL;
-	}
-
-	if (test_ctx->test_ch_arr[SDIO_SMEM]->ch_ready) {
-		pr_info(TEST_MODULE_NAME "%s: SDIO_SMEM channel is already opened\n",
-			__func__);
-		return 0;
-	}
-
-	test_ctx->test_ch_arr[SDIO_SMEM]->ch_ready = 1;
-	sdio_smem->buf = test_ctx->smem_buf;
-	sdio_smem->size = SMEM_MAX_XFER_SIZE;
-	sdio_smem->cb_func = sdio_smem_test_cb;
-	ret = sdio_smem_register_client();
-	if (ret)
-		pr_info(TEST_MODULE_NAME "%s: Error (%d) registering sdio_smem "
-					 "test client\n",
-			__func__, ret);
-
-	return ret;
-}
-
-static int sdio_smem_test_probe(struct platform_device *pdev)
-{
-	test_ctx->sdio_smem = container_of(pdev, struct sdio_smem_client,
-					   plat_dev);
-
-	return sdio_smem_open(test_ctx->sdio_smem);
-}
-
-static struct platform_driver sdio_smem_client_drv = {
-	.probe		= sdio_smem_test_probe,
-	.driver		= {
-		.name	= "SDIO_SMEM_CLIENT",
-		.owner	= THIS_MODULE,
-	},
-};
-#endif
-
-static void sdio_test_lpm_timeout_handler(unsigned long data)
-{
-	struct test_channel *tch = (struct test_channel *)data;
-
-	pr_info(TEST_MODULE_NAME ": %s - LPM TEST TIMEOUT Expired after "
-			    "%d ms\n", __func__, tch->timeout_ms);
-	tch->test_completed = 1;
-	pr_info(TEST_MODULE_NAME ": %s - tch->test_result = TEST_FAILED\n",
-		__func__);
-	tch->test_completed = 1;
-	tch->test_result = TEST_FAILED;
-	check_test_completion();
-	return;
-}
-
-static void sdio_test_lpm_timer_handler(unsigned long data)
-{
-	struct test_channel *tch = (struct test_channel *)data;
-
-	pr_info(TEST_MODULE_NAME ": %s - LPM TEST Timer Expired after "
-			    "%d ms\n", __func__, tch->timer_interval_ms);
-
-	if (!tch) {
-		pr_err(TEST_MODULE_NAME ": %s - LPM TEST FAILED. "
-		       "tch is NULL\n", __func__);
-		return;
-	}
-
-	if (!tch->ch) {
-		pr_err(TEST_MODULE_NAME ": %s - LPM TEST FAILED. tch->ch "
-		       "is NULL\n", __func__);
-		tch->test_result = TEST_FAILED;
-		return;
-	}
-
-	/* Verfiy that we voted for sleep */
-	if (tch->is_ok_to_sleep) {
-		tch->test_result = TEST_PASSED;
-		pr_info(TEST_MODULE_NAME ": %s - 8K voted for sleep\n",
-			__func__);
-	} else {
-		tch->test_result = TEST_FAILED;
-		pr_info(TEST_MODULE_NAME ": %s - 8K voted against sleep\n",
-			__func__);
-
-	}
-
-	sdio_al_unregister_lpm_cb(tch->sdio_al_device);
-
-	if (tch->test_type == SDIO_TEST_LPM_HOST_WAKER) {
-		atomic_set(&tch->wakeup_client, 1);
-		wake_up(&tch->wait_q);
-	}
-}
-
-int sdio_test_wakeup_callback(void *device_handle, int is_vote_for_sleep)
-{
-	int i = 0;
-
-	TEST_DBG(TEST_MODULE_NAME ": %s is_vote_for_sleep=%d!!!",
-		__func__, is_vote_for_sleep);
-
-	for (i = 0; i < SDIO_MAX_CHANNELS; i++) {
-		struct test_channel *tch = test_ctx->test_ch_arr[i];
-
-		if ((!tch) || (!tch->is_used) || (!tch->ch_ready))
-			continue;
-		if (tch->sdio_al_device == device_handle) {
-			tch->is_ok_to_sleep = is_vote_for_sleep;
-
-			if (tch->test_type == SDIO_TEST_LPM_RANDOM) {
-				spin_lock_irqsave(&tch->test_device->
-						  lpm_array_lock,
-						  tch->test_device->
-						  lpm_array_lock_flags);
-				if (is_vote_for_sleep == 1)
-					lpm_test_update_entry(tch,
-							      LPM_SLEEP,
-							      "SLEEP ", 0);
-				else
-					lpm_test_update_entry(tch,
-							      LPM_WAKEUP,
-							      "WAKEUP", 0);
-
-				spin_unlock_irqrestore(&tch->test_device->
-						       lpm_array_lock,
-						       tch->test_device->
-						       lpm_array_lock_flags);
-				break;
-			}
-		}
-	}
-
-	return 0;
-}
-
-static int sdio_test_find_dev(struct test_channel *tch)
-{
-	int j;
-	int null_index = -1;
-
-	for (j = 0 ; j < MAX_NUM_OF_SDIO_DEVICES; ++j) {
-
-		struct sdio_test_device *test_dev =
-		&test_ctx->test_dev_arr[j];
-
-		if (test_dev->sdio_al_device == NULL) {
-			if (null_index == -1)
-				null_index = j;
-			continue;
-		}
-
-		if (test_dev->sdio_al_device ==
-		    tch->ch->sdio_al_dev) {
-			test_dev->open_channels_counter_to_recv++;
-			test_dev->open_channels_counter_to_send++;
-			tch->test_device = test_dev;
-			/* setting mask id for pending data for
-			   this channel */
-			tch->channel_mask_id = test_dev->next_mask_id;
-			test_dev->next_mask_id *= 2;
-			pr_info(TEST_MODULE_NAME ": %s - channel %s "
-				"got read_mask_id = 0x%x. device "
-				"next_mask_id=0x%x",
-				__func__, tch->name, tch->channel_mask_id,
-				test_dev->next_mask_id);
-			break;
-		}
-	}
-
-	/*
-	 * happens ones a new device is "discovered" while testing. i.e
-	 * if testing a few channels, a new deivce will be "discovered" once
-	 * the first channel of a device is being tested
-	 */
-	if (j == MAX_NUM_OF_SDIO_DEVICES) {
-
-		struct sdio_test_device *test_dev =
-			&test_ctx->
-			test_dev_arr[null_index];
-		test_dev->sdio_al_device =
-			tch->ch->sdio_al_dev;
-
-		test_ctx->number_of_active_devices++;
-		test_ctx->max_number_of_devices++;
-		test_dev->open_channels_counter_to_recv++;
-		test_dev->open_channels_counter_to_send++;
-		test_dev->next_avail_entry_in_array = 0;
-		tch->test_device = test_dev;
-		tch->test_device->array_size =
-			LPM_ARRAY_SIZE;
-		test_dev->modem_result_per_dev = 1;
-		tch->modem_result_per_chan = 0;
-		test_dev->next_avail_entry_in_array = 0;
-
-		spin_lock_init(&test_dev->
-			       lpm_array_lock);
-
-		if (tch->test_type == SDIO_TEST_LPM_RANDOM) {
-			pr_err(MODULE_NAME ": %s - "
-			       "Allocating Msg Array for "
-			       "Maximum open channels for device (%d) "
-			       "Channels. Array has %d entries",
-			       __func__,
-			       LPM_MAX_OPEN_CHAN_PER_DEV,
-			       test_dev->array_size);
-
-			test_dev->lpm_arr =
-				kzalloc(sizeof(
-				struct lpm_entry_type) *
-					tch->
-					test_device->array_size,
-				GFP_KERNEL);
-
-			if (!test_dev->lpm_arr) {
-				pr_err(MODULE_NAME ": %s - "
-					"lpm_arr is NULL",
-					__func__);
-				return -ENOMEM;
-			}
-		}
-
-		/*
-		 * in new device, initialize next_mask_id, and setting
-		 * mask_id to the channel
-		 */
-		test_dev->next_mask_id = 0x1;
-		tch->channel_mask_id = test_dev->next_mask_id;
-		test_dev->next_mask_id *= 2;
-		pr_info(TEST_MODULE_NAME ": %s - channel %s got "
-			"read_mask_id = 0x%x. device next_mask_id=0x%x",
-			__func__,
-			tch->name,
-			tch->channel_mask_id,
-			test_dev->next_mask_id);
-	}
-
-	return 0;
-}
-
-static void check_test_result(void)
-{
-	int result = 1;
-	int i = 0;
-
-	test_ctx->max_number_of_devices = 0;
-
-	pr_info(TEST_MODULE_NAME ": %s - Woke Up\n", __func__);
-
-	for (i = 0; i < SDIO_MAX_CHANNELS; i++) {
-		struct test_channel *tch = test_ctx->test_ch_arr[i];
-
-		if ((!tch) || (!tch->is_used) || (!tch->ch_ready))
-			continue;
-
-		if (tch->test_type == SDIO_TEST_LPM_RANDOM)
-			result &= tch->test_device->final_result_per_dev;
-		else
-			if (tch->test_result == TEST_FAILED) {
-				pr_info(TEST_MODULE_NAME ": %s - "
-					"Test FAILED\n", __func__);
-				test_ctx->test_result = TEST_FAILED;
-				pr_err(TEST_MODULE_NAME ": %s - "
-				       "test_result %d",
-				       __func__, test_ctx->test_result);
-				return;
-			}
-	}
-
-	if (result == 0) {
-		pr_info(TEST_MODULE_NAME ": %s - Test FAILED\n", __func__);
-		test_ctx->test_result = TEST_FAILED;
-		pr_err(TEST_MODULE_NAME ": %s - "
-		       "test_result %d",
-		       __func__, test_ctx->test_result);
-		return;
-	}
-
-	pr_info(TEST_MODULE_NAME ": %s - Test PASSED", __func__);
-	test_ctx->test_result = TEST_PASSED;
-	pr_err(TEST_MODULE_NAME ": %s - "
-	       "test_result %d",
-	       __func__, test_ctx->test_result);
-	return;
-}
-
-/**
- * Test Main
- */
-static int test_start(void)
-{
-	int ret = -ENOMEM;
-	int i;
-
-	pr_debug(TEST_MODULE_NAME ":Starting Test ....\n");
-
-	test_ctx->test_completed = 0;
-	test_ctx->test_result = TEST_NO_RESULT;
-	test_ctx->debug.dun_throughput = 0;
-	test_ctx->debug.rmnt_throughput = 0;
-	test_ctx->number_of_active_devices = 0;
-
-	pr_err(TEST_MODULE_NAME ": %s - test_result %d",
-	       __func__, test_ctx->test_result);
-
-	memset(test_ctx->test_dev_arr, 0,
-		sizeof(struct sdio_test_device)*MAX_NUM_OF_SDIO_DEVICES);
-
-	/* Open The Channels */
-	for (i = 0; i < SDIO_MAX_CHANNELS; i++) {
-		struct test_channel *tch = test_ctx->test_ch_arr[i];
-
-		if ((!tch) || (!tch->is_used))
-			continue;
-
-		tch->rx_bytes = 0;
-		tch->tx_bytes = 0;
-
-		atomic_set(&tch->tx_notify_count, 0);
-		atomic_set(&tch->rx_notify_count, 0);
-		atomic_set(&tch->any_notify_count, 0);
-		atomic_set(&tch->wakeup_client, 0);
-
-		/* in case there are values left from previous tests */
-		tch->notify_counter_per_chan = 0;
-		tch->next_index_in_sent_msg_per_chan = 0;
-
-		memset(tch->buf, 0x00, tch->buf_size);
-		tch->test_result = TEST_NO_RESULT;
-
-		tch->test_completed = 0;
-
-		ret = open_sdio_ch(tch);
-		if (ret)
-			continue;
-
-		if (tch->ch_id != SDIO_SMEM) {
-			ret = sdio_test_find_dev(tch);
-
-			if (ret) {
-				pr_err(TEST_MODULE_NAME ": %s - "
-				       "sdio_test_find_dev() returned with "
-				       "error", __func__);
-				return -ENODEV;
-			}
-
-			tch->sdio_al_device = tch->ch->sdio_al_dev;
-		}
-
-		if ((tch->test_type == SDIO_TEST_LPM_HOST_WAKER) ||
-		    (tch->test_type == SDIO_TEST_LPM_CLIENT_WAKER) ||
-		    (tch->test_type == SDIO_TEST_LPM_RANDOM))
-			sdio_al_register_lpm_cb(tch->sdio_al_device,
-					 sdio_test_wakeup_callback);
-	}
-
-	/*
-	 * make some space between opening the channels and sending the
-	 * config messages
-	 */
-	msleep(100);
-
-	/*
-	 * try to delay send_config_msg of all channels to after the point
-	 * when we open them all
-	 */
-	for (i = 0; i < SDIO_MAX_CHANNELS; i++) {
-		struct test_channel *tch = test_ctx->test_ch_arr[i];
-
-		if ((!tch) || (!tch->is_used))
-			continue;
-
-		if ((tch->ch_ready) && (tch->ch_id != SDIO_SMEM))
-			send_config_msg(tch);
-
-		if ((tch->test_type == SDIO_TEST_LPM_HOST_WAKER) ||
-		    (tch->test_type == SDIO_TEST_LPM_CLIENT_WAKER) ||
-		    (tch->test_type == SDIO_TEST_LPM_RANDOM)) {
-			if (tch->timer_interval_ms > 0) {
-				pr_info(TEST_MODULE_NAME ": %s - init timer, "
-					"ms=%d\n",
-					__func__, tch->timer_interval_ms);
-				init_timer(&tch->timer);
-				tch->timer.data = (unsigned long)tch;
-				tch->timer.function =
-					sdio_test_lpm_timer_handler;
-				tch->timer.expires = jiffies +
-				    msecs_to_jiffies(tch->timer_interval_ms);
-				add_timer(&tch->timer);
-			}
-		}
-	}
-
-	pr_debug(TEST_MODULE_NAME ":queue_work..\n");
-	for (i = 0; i < SDIO_MAX_CHANNELS; i++) {
-		struct test_channel *tch = test_ctx->test_ch_arr[i];
-
-		if ((!tch) || (!tch->is_used) || (!tch->ch_ready))
-			continue;
-
-		if (tch->ch_id == SDIO_SMEM) {
-#ifdef CONFIG_MSM_SDIO_SMEM
-			if (tch->test_type == SDIO_TEST_CLOSE_CHANNEL)
-				open_close_smem_test(tch);
-#endif
-		} else {
-			queue_work(tch->workqueue, &tch->test_work.work);
-		}
-
-	}
-
-	pr_info(TEST_MODULE_NAME ": %s - Waiting for the test completion\n",
-		__func__);
-
-	wait_event(test_ctx->wait_q, test_ctx->test_completed);
-	check_test_result();
-
-	/*
-	 * Close the channels and zero the is_used flag so that if the modem
-	 * will be reset after the test completion we won't re-open
-	 * the channels
-	 */
-	for (i = 0; i < SDIO_MAX_CHANNELS; i++) {
-		struct test_channel *tch = test_ctx->test_ch_arr[i];
-
-		if ((!tch) || (!tch->is_used))
-			continue;
-		if (!tch->ch_ready) {
-			tch->is_used = 0;
-			continue;
-		}
-
-		close_sdio_ch(tch);
-		tch->is_used = 0;
-	}
-
-	if (test_ctx->test_result == TEST_PASSED)
-		return 0;
-	else
-		return -EINVAL;
-}
-
-static int set_params_loopback_9k(struct test_channel *tch)
-{
-	if (!tch) {
-		pr_err(TEST_MODULE_NAME ":NULL channel\n");
-		return -EINVAL;
-	}
-	tch->is_used = 1;
-	tch->test_type = SDIO_TEST_LOOPBACK_CLIENT;
-	tch->config_msg.signature = TEST_CONFIG_SIGNATURE;
-	tch->config_msg.test_case = SDIO_TEST_LOOPBACK_CLIENT;
-	tch->config_msg.num_packets = 10000;
-	tch->config_msg.num_iterations = 1;
-
-	tch->packet_length = 512;
-	if (tch->ch_id == SDIO_RPC)
-		tch->packet_length = 128;
-	tch->timer_interval_ms = 0;
-
-	return 0;
-}
-static int set_params_loopback_9k_close(struct test_channel *tch)
-{
-	if (!tch) {
-		pr_err(TEST_MODULE_NAME ":NULL channel\n");
-		return -EINVAL;
-	}
-	tch->is_used = 1;
-	tch->test_type = SDIO_TEST_CLOSE_CHANNEL;
-	tch->config_msg.signature = TEST_CONFIG_SIGNATURE;
-	tch->config_msg.test_case = SDIO_TEST_LOOPBACK_CLIENT;
-	tch->config_msg.num_packets = 5000;
-	tch->config_msg.num_iterations = 1;
-	tch->max_burst_size = 10;
-	switch (tch->ch_id) {
-	case SDIO_DUN:
-	case SDIO_RPC:
-		tch->packet_length = 128; /* max is 2K*/
-		break;
-	case SDIO_DIAG:
-	case SDIO_RMNT:
-	default:
-		tch->packet_length = 512; /* max is 4k */
-	}
-	tch->timer_interval_ms = 0;
-	return 0;
-}
-static int set_params_a2_perf(struct test_channel *tch)
-{
-	if (!tch) {
-		pr_err(TEST_MODULE_NAME ":NULL channel\n");
-		return -EINVAL;
-	}
-	tch->is_used = 1;
-	tch->test_type = SDIO_TEST_PERF;
-	tch->config_msg.signature = TEST_CONFIG_SIGNATURE;
-	tch->config_msg.test_case = SDIO_TEST_LOOPBACK_CLIENT;
-
-	switch (tch->ch_id) {
-	case SDIO_DIAG:
-		tch->packet_length = 512;
-		break;
-	case SDIO_DUN:
-		tch->packet_length = DUN_PACKET_SIZE;
-		break;
-	case SDIO_CSVT:
-		tch->packet_length = CSVT_PACKET_SIZE;
-		break;
-	default:
-		tch->packet_length = MAX_XFER_SIZE;
-		break;
-	}
-
-	pr_info(TEST_MODULE_NAME ": %s: packet_length=%d", __func__,
-			tch->packet_length);
-
-	tch->config_msg.num_packets = 10000;
-	tch->config_msg.num_iterations = 1;
-	tch->random_packet_size = 0;
-
-	tch->timer_interval_ms = 0;
-
-	return 0;
-}
-
-static int set_params_rtt(struct test_channel *tch)
-{
-	if (!tch) {
-		pr_err(TEST_MODULE_NAME ":NULL channel\n");
-		return -EINVAL;
-	}
-	tch->is_used = 1;
-	tch->test_type = SDIO_TEST_RTT;
-	tch->config_msg.signature = TEST_CONFIG_SIGNATURE;
-	tch->config_msg.test_case = SDIO_TEST_LOOPBACK_CLIENT;
-
-	switch (tch->ch_id) {
-	case SDIO_RMNT:
-		tch->packet_length = SDIO_RMNT_RTT_PACKET_SIZE;
-		break;
-	case SDIO_CSVT:
-		tch->packet_length = SDIO_CSVT_RTT_PACKET_SIZE;
-		break;
-	default:
-		pr_err(TEST_MODULE_NAME ": %s - ch_id invalid.\n", __func__);
-		return -EINVAL;
-	}
-
-	pr_info(TEST_MODULE_NAME ": %s: packet_length=%d", __func__,
-			tch->packet_length);
-
-	tch->config_msg.num_packets = 200;
-	tch->config_msg.num_iterations = 1;
-	tch->random_packet_size = 0;
-
-	tch->timer_interval_ms = 0;
-
-	return 0;
-}
-
-static int set_params_a2_small_pkts(struct test_channel *tch)
-{
-	if (!tch) {
-		pr_err(TEST_MODULE_NAME ":NULL channel\n");
-		return -EINVAL;
-	}
-	tch->is_used = 1;
-	tch->test_type = SDIO_TEST_PERF;
-	tch->config_msg.signature = TEST_CONFIG_SIGNATURE;
-	tch->config_msg.test_case = SDIO_TEST_LOOPBACK_CLIENT;
-	tch->packet_length = 128;
-
-	tch->config_msg.num_packets = 1000000;
-	tch->config_msg.num_iterations = 1;
-	tch->random_packet_size = 1;
-
-	tch->timer_interval_ms = 0;
-
-	return 0;
-}
-
-static int set_params_modem_reset(struct test_channel *tch)
-{
-	if (!tch) {
-		pr_err(TEST_MODULE_NAME ":NULL channel\n");
-		return -EINVAL;
-	}
-	tch->is_used = 1;
-	tch->test_type = SDIO_TEST_MODEM_RESET;
-	tch->config_msg.signature = TEST_CONFIG_SIGNATURE;
-	tch->config_msg.test_case = SDIO_TEST_LOOPBACK_CLIENT;
-	tch->packet_length = 512;
-	if (tch->ch_id == SDIO_RPC)
-		tch->packet_length = 128;
-	else if ((tch->ch_id == SDIO_RMNT) || (tch->ch_id == SDIO_DUN))
-		tch->packet_length = MAX_XFER_SIZE;
-
-	tch->config_msg.num_packets = 50000;
-	tch->config_msg.num_iterations = 1;
-
-	tch->timer_interval_ms = 0;
-
-	return 0;
-}
-
-static int set_params_a2_validation(struct test_channel *tch)
-{
-	if (!tch) {
-		pr_err(TEST_MODULE_NAME ":NULL channel\n");
-		return -EINVAL;
-	}
-	tch->is_used = 1;
-	tch->test_type = SDIO_TEST_A2_VALIDATION;
-	tch->config_msg.signature = TEST_CONFIG_SIGNATURE;
-	tch->config_msg.test_case = SDIO_TEST_LOOPBACK_CLIENT;
-
-	if (tch->ch_id == SDIO_RMNT)
-		tch->packet_length = RMNT_PACKET_SIZE;
-	else if (tch->ch_id == SDIO_DUN)
-		tch->packet_length = DUN_PACKET_SIZE;
-	else
-		tch->packet_length = MAX_XFER_SIZE;
-
-	tch->config_msg.num_packets = 10000;
-	tch->config_msg.num_iterations = 1;
-	tch->timer_interval_ms = 0;
-
-	return 0;
-}
-
-static int set_params_smem_test(struct test_channel *tch)
-{
-	if (!tch) {
-		pr_err(TEST_MODULE_NAME ":NULL channel\n");
-		return -EINVAL;
-	}
-	tch->is_used = 1;
-	tch->timer_interval_ms = 0;
-
-	return 0;
-}
-
-static int set_params_lpm_test(struct test_channel *tch,
-				enum sdio_test_case_type test,
-				int timer_interval_ms)
-{
-	static int first_time = 1;
-	if (!tch) {
-		pr_err(TEST_MODULE_NAME ": %s - NULL channel\n", __func__);
-		return -EINVAL;
-	}
-
-	tch->is_used = 1;
-	tch->test_type = test;
-	tch->config_msg.signature = TEST_CONFIG_SIGNATURE;
-	tch->config_msg.test_case = test;
-	tch->config_msg.num_packets = LPM_TEST_NUM_OF_PACKETS;
-	tch->config_msg.num_iterations = 1;
-	tch->timer_interval_ms = timer_interval_ms;
-	tch->timeout_ms = 10000;
-
-	tch->packet_length = 0;
-	if (test != SDIO_TEST_LPM_RANDOM) {
-		init_timer(&tch->timeout_timer);
-		tch->timeout_timer.data = (unsigned long)tch;
-		tch->timeout_timer.function = sdio_test_lpm_timeout_handler;
-		tch->timeout_timer.expires = jiffies +
-			msecs_to_jiffies(tch->timeout_ms);
-		add_timer(&tch->timeout_timer);
-		pr_info(TEST_MODULE_NAME ": %s - Initiated LPM TIMEOUT TIMER."
-			"set to %d ms\n",
-			__func__, tch->timeout_ms);
-	}
-
-	if (first_time) {
-		pr_info(TEST_MODULE_NAME ": %s - wake_lock_init() called\n",
-		__func__);
-		wake_lock_init(&test_ctx->wake_lock,
-			       WAKE_LOCK_SUSPEND, TEST_MODULE_NAME);
-		first_time = 0;
-	}
-
-	pr_info(TEST_MODULE_NAME ": %s - wake_lock() for the TEST is "
-		"called channel %s. to prevent real sleeping\n",
-		__func__, tch->name);
-	wake_lock(&test_ctx->wake_lock);
-
-	return 0;
-}
-
-static int set_params_8k_sender_no_lp(struct test_channel *tch)
-{
-	if (!tch) {
-		pr_err(TEST_MODULE_NAME ":NULL channel\n");
-		return -EINVAL;
-	}
-	tch->is_used = 1;
-	tch->test_type = SDIO_TEST_HOST_SENDER_NO_LP;
-	tch->config_msg.signature = TEST_CONFIG_SIGNATURE;
-	tch->config_msg.test_case = SDIO_TEST_HOST_SENDER_NO_LP;
-	tch->config_msg.num_packets = 1000;
-	tch->config_msg.num_iterations = 1;
-
-	tch->packet_length = 512;
-	if (tch->ch_id == SDIO_RPC)
-		tch->packet_length = 128;
-	tch->timer_interval_ms = 0;
-
-	return 0;
-}
-
-static void set_pseudo_random_seed(void)
-{
-	/* Set the seed accoring to the kernel command parameters if any or
-	   get a random value */
-	if (seed != 0) {
-		test_ctx->lpm_pseudo_random_seed = seed;
-	} else {
-		test_ctx->lpm_pseudo_random_seed =
-			(unsigned int)(get_jiffies_64() & 0xFFFF);
-		test_ctx->lpm_pseudo_random_seed =
-			pseudo_random_seed(&test_ctx->lpm_pseudo_random_seed);
-	}
-
-	pr_info(TEST_MODULE_NAME ":%s: seed is %u",
-		   __func__, test_ctx->lpm_pseudo_random_seed);
-}
-
-/*
-   for each channel
-   1. open channel
-   2. close channel
-*/
-static int close_channel_lpm_test(int channel_num)
-{
-	int ret = 0;
-	struct test_channel *tch = NULL;
-	tch = test_ctx->test_ch_arr[channel_num];
-
-	if (!tch) {
-		pr_info(TEST_MODULE_NAME ":%s ch#%d is NULL\n",
-			__func__, channel_num);
-		return 0;
-	}
-
-	ret = open_sdio_ch(tch);
-	if (ret) {
-		pr_err(TEST_MODULE_NAME":%s open channel %s"
-			" failed\n", __func__, tch->name);
-		return ret;
-	} else {
-		pr_info(TEST_MODULE_NAME":%s open channel %s"
-			" success\n", __func__, tch->name);
-	}
-	ret = close_sdio_ch(tch);
-	if (ret) {
-		pr_err(TEST_MODULE_NAME":%s close channel %s"
-				" failed\n", __func__, tch->name);
-		return ret;
-	} else {
-		pr_info(TEST_MODULE_NAME":%s close channel %s"
-				" success\n", __func__, tch->name);
-	}
-
-	tch->is_used = 0;
-
-	return ret;
-}
-
-/**
- * Write File.
- *
- * @note Trigger the test from user space by:
- * echo 1 > /dev/sdio_al_test
- *
- */
-ssize_t test_write(struct file *filp, const char __user *buf, size_t size,
-		   loff_t *f_pos)
-{
-	sdio_al_test_initial_dev_and_chan(test_ctx);
-
-	if (strict_strtol(buf, 10, &test_ctx->testcase))
-		return -EINVAL;
-
-	switch (test_ctx->testcase) {
-	case 98:
-		pr_info(TEST_MODULE_NAME " set runtime debug on");
-		test_ctx->runtime_debug = 1;
-		return size;
-	case 99:
-		pr_info(TEST_MODULE_NAME " set runtime debug off");
-		test_ctx->runtime_debug = 0;
-		return size;
-	default:
-		pr_info(TEST_MODULE_NAME ":Bad Test number = %d.\n",
-			(int)test_ctx->testcase);
-		return size;
-	}
-
-	return size;
-}
-
-/**
- * Test Channel Init.
- */
-int test_channel_init(char *name)
-{
-	struct test_channel *test_ch;
-	int ch_id = 0;
-	int ret;
-
-	pr_debug(TEST_MODULE_NAME ":%s.\n", __func__);
-	pr_info(TEST_MODULE_NAME ": init test channel %s.\n", name);
-
-	ch_id = channel_name_to_id(name);
-	pr_debug(TEST_MODULE_NAME ":id = %d.\n", ch_id);
-	if (test_ctx->test_ch_arr[ch_id] == NULL) {
-		test_ch = kzalloc(sizeof(*test_ch), GFP_KERNEL);
-		if (test_ch == NULL) {
-			pr_err(TEST_MODULE_NAME ":kzalloc err for allocating "
-						"test_ch %s.\n",
-			       name);
-			return -ENOMEM;
-		}
-		test_ctx->test_ch_arr[ch_id] = test_ch;
-
-		test_ch->ch_id = ch_id;
-
-		strncpy(test_ch->name, name,
-		       strnlen(name, TEST_CH_NAME_SIZE)-SDIO_TEST_POSTFIX_SIZE);
-
-		test_ch->buf_size = MAX_XFER_SIZE;
-
-		test_ch->buf = kzalloc(test_ch->buf_size, GFP_KERNEL);
-		if (test_ch->buf == NULL) {
-			kfree(test_ch);
-			test_ctx->test_ch = NULL;
-			return -ENOMEM;
-		}
-
-		if (test_ch->ch_id == SDIO_SMEM) {
-			test_ctx->smem_buf = kzalloc(SMEM_MAX_XFER_SIZE,
-						     GFP_KERNEL);
-			if (test_ctx->smem_buf == NULL) {
-				pr_err(TEST_MODULE_NAME ":%s: Unable to "
-							"allocate smem buf\n",
-				       __func__);
-				kfree(test_ch);
-				test_ctx->test_ch = NULL;
-				return -ENOMEM;
-			}
-
-#ifdef CONFIG_MSM_SDIO_SMEM
-			ret = platform_driver_register(&sdio_smem_client_drv);
-			if (ret) {
-				pr_err(TEST_MODULE_NAME ":%s: Unable to "
-							"register sdio smem "
-							"test client\n",
-				       __func__);
-				return ret;
-			}
-#endif
-		} else {
-			test_ch->workqueue =
-				create_singlethread_workqueue(test_ch->name);
-			test_ch->test_work.test_ch = test_ch;
-			INIT_WORK(&test_ch->test_work.work, worker);
-
-			init_waitqueue_head(&test_ch->wait_q);
-		}
-	} else {
-		test_ch = test_ctx->test_ch_arr[ch_id];
-		pr_info(TEST_MODULE_NAME ":%s: ch %s was detected again\n",
-			__func__, test_ch->name);
-		test_ch->card_removed = 0;
-		if ((test_ch->is_used) &&
-		    (test_ch->test_type == SDIO_TEST_MODEM_RESET)) {
-			if (test_ch->ch_id == SDIO_SMEM) {
-#ifdef CONFIG_MSM_SDIO_SMEM
-				ret = add_sdio_smem();
-				if (ret) {
-					test_ch->ch_ready = false;
-					return 0;
-				}
-#endif
-			} else {
-				ret = open_sdio_ch(test_ch);
-				if (ret) {
-					pr_info(TEST_MODULE_NAME
-						":%s: open channel %s failed\n",
-					__func__, test_ch->name);
-					return 0;
-				}
-				ret = sdio_test_find_dev(test_ch);
-
-				if (ret) {
-					pr_err(TEST_MODULE_NAME ": %s - "
-					       "sdio_test_find_dev() returned "
-					       "with error", __func__);
-					return -ENODEV;
-				}
-
-				test_ch->sdio_al_device =
-					test_ch->ch->sdio_al_dev;
-			}
-			atomic_set(&test_ch->card_detected_event, 1);
-			wake_up(&test_ch->wait_q);
-		}
-	}
-
-	return 0;
-}
-
-static int sdio_test_channel_probe(struct platform_device *pdev)
-{
-	if (!pdev)
-		return -EIO;
-	return test_channel_init((char *)pdev->name);
-}
-
-static int sdio_test_channel_remove(struct platform_device *pdev)
-{
-	int ch_id;
-
-	if (!pdev)
-		return -EIO;
-
-	ch_id = channel_name_to_id((char *)pdev->name);
-	if (test_ctx->test_ch_arr[ch_id] == NULL)
-		return 0;
-
-	pr_info(TEST_MODULE_NAME "%s: remove ch %s\n",
-		__func__, test_ctx->test_ch_arr[ch_id]->name);
-
-	if ((ch_id == SDIO_SMEM) && (test_ctx->smem_pdev)) {
-		platform_device_unregister(test_ctx->smem_pdev);
-		test_ctx->smem_pdev = NULL;
-	}
-
-	test_ctx->test_ch_arr[ch_id]->ch_ready = 0;
-	test_ctx->test_ch_arr[ch_id]->card_removed = 1;
-
-	return 0;
-
-}
-
-static int sdio_test_channel_csvt_probe(struct platform_device *pdev)
-{
-	int ret = 0;
-
-	if (!pdev)
-		return -ENODEV;
-
-	test_ctx->csvt_app_pdev = platform_device_alloc("SDIO_CSVT_TEST_APP",
-							-1);
-	ret = platform_device_add(test_ctx->csvt_app_pdev);
-		if (ret) {
-			pr_err(MODULE_NAME ":platform_device_add failed, "
-					   "ret=%d\n", ret);
-			return ret;
-		}
-
-	return sdio_test_channel_probe(pdev);
-}
-
-static int sdio_test_channel_csvt_remove(struct platform_device *pdev)
-{
-	if (!pdev)
-		return -ENODEV;
-
-	platform_device_unregister(test_ctx->csvt_app_pdev);
-
-	return sdio_test_channel_remove(pdev);
-}
-
-static struct platform_driver sdio_rpc_drv = {
-	.probe		= sdio_test_channel_probe,
-	.remove		= sdio_test_channel_remove,
-	.driver		= {
-		.name	= "SDIO_RPC_TEST",
-		.owner	= THIS_MODULE,
-	},
-};
-
-static struct platform_driver sdio_qmi_drv = {
-	.probe		= sdio_test_channel_probe,
-	.remove		= sdio_test_channel_remove,
-	.driver		= {
-		.name	= "SDIO_QMI_TEST",
-		.owner	= THIS_MODULE,
-	},
-};
-
-static struct platform_driver sdio_diag_drv = {
-	.probe		= sdio_test_channel_probe,
-	.remove		= sdio_test_channel_remove,
-	.driver		= {
-		.name	= "SDIO_DIAG_TEST",
-		.owner	= THIS_MODULE,
-	},
-};
-
-static struct platform_driver sdio_smem_drv = {
-	.probe		= sdio_test_channel_probe,
-	.remove		= sdio_test_channel_remove,
-	.driver		= {
-		.name	= "SDIO_SMEM_TEST",
-		.owner	= THIS_MODULE,
-	},
-};
-
-static struct platform_driver sdio_rmnt_drv = {
-	.probe		= sdio_test_channel_probe,
-	.remove		= sdio_test_channel_remove,
-	.driver		= {
-		.name	= "SDIO_RMNT_TEST",
-		.owner	= THIS_MODULE,
-	},
-};
-
-static struct platform_driver sdio_dun_drv = {
-	.probe		= sdio_test_channel_probe,
-	.remove		= sdio_test_channel_remove,
-	.driver		= {
-		.name	= "SDIO_DUN_TEST",
-		.owner	= THIS_MODULE,
-	},
-};
-
-static struct platform_driver sdio_csvt_drv = {
-	.probe		= sdio_test_channel_csvt_probe,
-	.remove		= sdio_test_channel_csvt_remove,
-	.driver		= {
-		.name	= "SDIO_CSVT_TEST",
-		.owner	= THIS_MODULE,
-	},
-};
-
-static struct class *test_class;
-
-const struct file_operations test_fops = {
-	.owner = THIS_MODULE,
-	.write = test_write,
-};
-
-/**
- * Module Init.
- */
-static int __init test_init(void)
-{
-	int ret;
-
-	pr_debug(TEST_MODULE_NAME ":test_init.\n");
-
-	test_ctx = kzalloc(sizeof(struct test_context), GFP_KERNEL);
-
-	if (test_ctx == NULL) {
-		pr_err(TEST_MODULE_NAME ":kzalloc err.\n");
-		return -ENOMEM;
-	}
-	test_ctx->test_ch = NULL;
-	test_ctx->signature = TEST_SIGNATURE;
-
-	test_ctx->name = "UNKNOWN";
-
-	init_waitqueue_head(&test_ctx->wait_q);
-
-#ifdef CONFIG_DEBUG_FS
-	sdio_al_test_debugfs_init();
-#endif
-
-	test_class = class_create(THIS_MODULE, TEST_MODULE_NAME);
-
-	ret = alloc_chrdev_region(&test_ctx->dev_num, 0, 1, TEST_MODULE_NAME);
-	if (ret) {
-		pr_err(TEST_MODULE_NAME "alloc_chrdev_region err.\n");
-		return -ENODEV;
-	}
-
-	test_ctx->dev = device_create(test_class, NULL, test_ctx->dev_num,
-				      test_ctx, TEST_MODULE_NAME);
-	if (IS_ERR(test_ctx->dev)) {
-		pr_err(TEST_MODULE_NAME ":device_create err.\n");
-		return -ENODEV;
-	}
-
-	test_ctx->cdev = cdev_alloc();
-	if (test_ctx->cdev == NULL) {
-		pr_err(TEST_MODULE_NAME ":cdev_alloc err.\n");
-		return -ENODEV;
-	}
-	cdev_init(test_ctx->cdev, &test_fops);
-	test_ctx->cdev->owner = THIS_MODULE;
-
-	ret = cdev_add(test_ctx->cdev, test_ctx->dev_num, 1);
-	if (ret)
-		pr_err(TEST_MODULE_NAME ":cdev_add err=%d\n", -ret);
-	else
-		pr_debug(TEST_MODULE_NAME ":SDIO-AL-Test init OK..\n");
-
-	platform_driver_register(&sdio_rpc_drv);
-	platform_driver_register(&sdio_qmi_drv);
-	platform_driver_register(&sdio_diag_drv);
-	platform_driver_register(&sdio_smem_drv);
-	platform_driver_register(&sdio_rmnt_drv);
-	platform_driver_register(&sdio_dun_drv);
-	platform_driver_register(&sdio_csvt_drv);
-
-	return ret;
-}
-
-/**
- * Module Exit.
- */
-static void __exit test_exit(void)
-{
-	int i;
-
-	pr_debug(TEST_MODULE_NAME ":test_exit.\n");
-
-	test_ctx->exit_flag = true;
-
-	msleep(100); /* allow gracefully exit of the worker thread */
-
-	cdev_del(test_ctx->cdev);
-	device_destroy(test_class, test_ctx->dev_num);
-	unregister_chrdev_region(test_ctx->dev_num, 1);
-
-	platform_driver_unregister(&sdio_rpc_drv);
-	platform_driver_unregister(&sdio_qmi_drv);
-	platform_driver_unregister(&sdio_diag_drv);
-	platform_driver_unregister(&sdio_smem_drv);
-	platform_driver_unregister(&sdio_rmnt_drv);
-	platform_driver_unregister(&sdio_dun_drv);
-	platform_driver_unregister(&sdio_csvt_drv);
-
-	for (i = 0; i < SDIO_MAX_CHANNELS; i++) {
-		struct test_channel *tch = test_ctx->test_ch_arr[i];
-		if (!tch)
-			continue;
-		kfree(tch->buf);
-		kfree(tch);
-	}
-
-#ifdef CONFIG_DEBUG_FS
-	sdio_al_test_debugfs_cleanup();
-#endif
-
-	kfree(test_ctx);
-
-	pr_debug(TEST_MODULE_NAME ":test_exit complete.\n");
-}
-
-module_init(test_init);
-module_exit(test_exit);
-
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("SDIO_AL Test");
-MODULE_AUTHOR("Amir Samuelov <amirs@codeaurora.org>");
-
-
diff --git a/arch/arm/mach-msm/sdio_cmux.c b/arch/arm/mach-msm/sdio_cmux.c
deleted file mode 100644
index 48ca6b7..0000000
--- a/arch/arm/mach-msm/sdio_cmux.c
+++ /dev/null
@@ -1,901 +0,0 @@
-/* Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * 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 DEBUG
-
-#include <linux/module.h>
-#include <linux/fs.h>
-#include <linux/device.h>
-#include <linux/delay.h>
-#include <linux/sched.h>
-#include <linux/spinlock.h>
-#include <linux/mutex.h>
-#include <linux/uaccess.h>
-#include <linux/workqueue.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
-#include <linux/termios.h>
-#include <linux/debugfs.h>
-#include <linux/moduleparam.h>
-
-#include <mach/sdio_al.h>
-#include <mach/sdio_cmux.h>
-
-#include "modem_notifier.h"
-
-#define MAX_WRITE_RETRY 5
-#define MAGIC_NO_V1 0x33FC
-
-static int msm_sdio_cmux_debug_mask;
-module_param_named(debug_mask, msm_sdio_cmux_debug_mask,
-		   int, S_IRUGO | S_IWUSR | S_IWGRP);
-
-enum cmd_type {
-	DATA = 0,
-	OPEN,
-	CLOSE,
-	STATUS,
-	NUM_CMDS
-};
-
-#define DSR_POS 0x1
-#define CTS_POS 0x2
-#define RI_POS 0x4
-#define CD_POS 0x8
-
-struct sdio_cmux_ch {
-	int lc_id;
-
-	struct mutex lc_lock;
-	wait_queue_head_t open_wait_queue;
-	int is_remote_open;
-	int is_local_open;
-	int is_channel_reset;
-
-	char local_status;
-	char remote_status;
-
-	struct mutex tx_lock;
-	struct list_head tx_list;
-
-	void *priv;
-	struct mutex rx_cb_lock;
-	void (*receive_cb)(void *, int, void *);
-	void (*write_done)(void *, int, void *);
-	void (*status_callback)(int, void *);
-} logical_ch[SDIO_CMUX_NUM_CHANNELS];
-
-struct sdio_cmux_hdr {
-	uint16_t magic_no;
-	uint8_t status;         /* This field is reserved for commands other
-				 * than STATUS */
-	uint8_t cmd;
-	uint8_t pad_bytes;
-	uint8_t lc_id;
-	uint16_t pkt_len;
-};
-
-struct sdio_cmux_pkt {
-	struct sdio_cmux_hdr *hdr;
-	void *data;
-};
-
-struct sdio_cmux_list_elem {
-	struct list_head list;
-	struct sdio_cmux_pkt cmux_pkt;
-};
-
-#define logical_ch_is_local_open(x)                        \
-	(logical_ch[(x)].is_local_open)
-
-#define logical_ch_is_remote_open(x)                       \
-	(logical_ch[(x)].is_remote_open)
-
-static void sdio_cdemux_fn(struct work_struct *work);
-static DECLARE_WORK(sdio_cdemux_work, sdio_cdemux_fn);
-static struct workqueue_struct *sdio_cdemux_wq;
-
-static DEFINE_MUTEX(write_lock);
-static uint32_t bytes_to_write;
-static DEFINE_MUTEX(temp_rx_lock);
-static LIST_HEAD(temp_rx_list);
-
-static void sdio_cmux_fn(struct work_struct *work);
-static DECLARE_WORK(sdio_cmux_work, sdio_cmux_fn);
-static struct workqueue_struct *sdio_cmux_wq;
-
-static struct sdio_channel *sdio_qmi_chl;
-static uint32_t sdio_cmux_inited;
-
-static uint32_t abort_tx;
-static DEFINE_MUTEX(modem_reset_lock);
-
-static DEFINE_MUTEX(probe_lock);
-
-enum {
-	MSM_SDIO_CMUX_DEBUG = 1U << 0,
-	MSM_SDIO_CMUX_DUMP_BUFFER = 1U << 1,
-};
-
-static struct platform_device sdio_ctl_dev = {
-	.name		= "SDIO_CTL",
-	.id		= -1,
-};
-
-#if defined(DEBUG)
-#define D_DUMP_BUFFER(prestr, cnt, buf) \
-do { \
-	if (msm_sdio_cmux_debug_mask & MSM_SDIO_CMUX_DUMP_BUFFER) { \
-		int i; \
-		pr_debug("%s", prestr); \
-		for (i = 0; i < cnt; i++) \
-			pr_info("%.2x", buf[i]); \
-		pr_debug("\n"); \
-	} \
-} while (0)
-
-#define D(x...) \
-do { \
-	if (msm_sdio_cmux_debug_mask & MSM_SDIO_CMUX_DEBUG) \
-		pr_debug(x); \
-} while (0)
-
-#else
-#define D_DUMP_BUFFER(prestr, cnt, buf) do {} while (0)
-#define D(x...) do {} while (0)
-#endif
-
-static int sdio_cmux_ch_alloc(int id)
-{
-	if (id < 0 || id >= SDIO_CMUX_NUM_CHANNELS) {
-		pr_err("%s: Invalid lc_id - %d\n", __func__, id);
-		return -EINVAL;
-	}
-
-	logical_ch[id].lc_id = id;
-	mutex_init(&logical_ch[id].lc_lock);
-	init_waitqueue_head(&logical_ch[id].open_wait_queue);
-	logical_ch[id].is_remote_open = 0;
-	logical_ch[id].is_local_open = 0;
-	logical_ch[id].is_channel_reset = 0;
-
-	INIT_LIST_HEAD(&logical_ch[id].tx_list);
-	mutex_init(&logical_ch[id].tx_lock);
-
-	logical_ch[id].priv = NULL;
-	mutex_init(&logical_ch[id].rx_cb_lock);
-	logical_ch[id].receive_cb = NULL;
-	logical_ch[id].write_done = NULL;
-	return 0;
-}
-
-static int sdio_cmux_ch_clear_and_signal(int id)
-{
-	struct sdio_cmux_list_elem *list_elem;
-
-	if (id < 0 || id >= SDIO_CMUX_NUM_CHANNELS) {
-		pr_err("%s: Invalid lc_id - %d\n", __func__, id);
-		return -EINVAL;
-	}
-
-	mutex_lock(&logical_ch[id].lc_lock);
-	logical_ch[id].is_remote_open = 0;
-	mutex_lock(&logical_ch[id].tx_lock);
-	while (!list_empty(&logical_ch[id].tx_list)) {
-		list_elem = list_first_entry(&logical_ch[id].tx_list,
-					     struct sdio_cmux_list_elem,
-					     list);
-		list_del(&list_elem->list);
-		kfree(list_elem->cmux_pkt.hdr);
-		kfree(list_elem);
-	}
-	mutex_unlock(&logical_ch[id].tx_lock);
-	mutex_lock(&logical_ch[id].rx_cb_lock);
-	if (logical_ch[id].receive_cb)
-		logical_ch[id].receive_cb(NULL, 0, logical_ch[id].priv);
-	mutex_unlock(&logical_ch[id].rx_cb_lock);
-	if (logical_ch[id].write_done)
-		logical_ch[id].write_done(NULL, 0, logical_ch[id].priv);
-	mutex_unlock(&logical_ch[id].lc_lock);
-	wake_up(&logical_ch[id].open_wait_queue);
-	return 0;
-}
-
-static int sdio_cmux_write_cmd(const int id, enum cmd_type type)
-{
-	int write_size = 0;
-	void *write_data = NULL;
-	struct sdio_cmux_list_elem *list_elem;
-
-	if (id < 0 || id >= SDIO_CMUX_NUM_CHANNELS) {
-		pr_err("%s: Invalid lc_id - %d\n", __func__, id);
-		return -EINVAL;
-	}
-
-	if (type < 0 || type > NUM_CMDS) {
-		pr_err("%s: Invalid cmd - %d\n", __func__, type);
-		return -EINVAL;
-	}
-
-	write_size = sizeof(struct sdio_cmux_hdr);
-	list_elem = kmalloc(sizeof(struct sdio_cmux_list_elem), GFP_KERNEL);
-	if (!list_elem) {
-		pr_err("%s: list_elem alloc failed\n", __func__);
-		return -ENOMEM;
-	}
-
-	write_data = kmalloc(write_size, GFP_KERNEL);
-	if (!write_data) {
-		pr_err("%s: write_data alloc failed\n", __func__);
-		kfree(list_elem);
-		return -ENOMEM;
-	}
-
-	list_elem->cmux_pkt.hdr = (struct sdio_cmux_hdr *)write_data;
-	list_elem->cmux_pkt.data = NULL;
-
-	list_elem->cmux_pkt.hdr->lc_id = (uint8_t)id;
-	list_elem->cmux_pkt.hdr->pkt_len = (uint16_t)0;
-	list_elem->cmux_pkt.hdr->cmd = (uint8_t)type;
-	list_elem->cmux_pkt.hdr->status = (uint8_t)0;
-	if (type == STATUS)
-		list_elem->cmux_pkt.hdr->status = logical_ch[id].local_status;
-	list_elem->cmux_pkt.hdr->pad_bytes = (uint8_t)0;
-	list_elem->cmux_pkt.hdr->magic_no = (uint16_t)MAGIC_NO_V1;
-
-	mutex_lock(&logical_ch[id].tx_lock);
-	list_add_tail(&list_elem->list, &logical_ch[id].tx_list);
-	mutex_unlock(&logical_ch[id].tx_lock);
-
-	mutex_lock(&write_lock);
-	bytes_to_write += write_size;
-	mutex_unlock(&write_lock);
-	queue_work(sdio_cmux_wq, &sdio_cmux_work);
-
-	return 0;
-}
-
-int sdio_cmux_open(const int id,
-		   void (*receive_cb)(void *, int, void *),
-		   void (*write_done)(void *, int, void *),
-		   void (*status_callback)(int, void *),
-		   void *priv)
-{
-	int r;
-	struct sdio_cmux_list_elem *list_elem, *list_elem_tmp;
-
-	if (!sdio_cmux_inited)
-		return -ENODEV;
-	if (id < 0 || id >= SDIO_CMUX_NUM_CHANNELS) {
-		pr_err("%s: Invalid id - %d\n", __func__, id);
-		return -EINVAL;
-	}
-
-	r = wait_event_timeout(logical_ch[id].open_wait_queue,
-				logical_ch[id].is_remote_open, (1 * HZ));
-	if (r < 0) {
-		pr_err("ERROR %s: wait_event_timeout() failed for"
-		       " ch%d with rc %d\n", __func__, id, r);
-		return r;
-	}
-	if (r == 0) {
-		pr_err("ERROR %s: Wait Timed Out for ch%d\n", __func__, id);
-		return -ETIMEDOUT;
-	}
-
-	mutex_lock(&logical_ch[id].lc_lock);
-	if (!logical_ch[id].is_remote_open) {
-		pr_err("%s: Remote ch%d not opened\n", __func__, id);
-		mutex_unlock(&logical_ch[id].lc_lock);
-		return -EINVAL;
-	}
-	if (logical_ch[id].is_local_open) {
-		mutex_unlock(&logical_ch[id].lc_lock);
-		return 0;
-	}
-	logical_ch[id].is_local_open = 1;
-	logical_ch[id].priv = priv;
-	logical_ch[id].write_done = write_done;
-	logical_ch[id].status_callback = status_callback;
-	mutex_lock(&logical_ch[id].rx_cb_lock);
-	logical_ch[id].receive_cb = receive_cb;
-	if (logical_ch[id].receive_cb) {
-		mutex_lock(&temp_rx_lock);
-		list_for_each_entry_safe(list_elem, list_elem_tmp,
-					 &temp_rx_list, list) {
-			if ((int)list_elem->cmux_pkt.hdr->lc_id == id) {
-				logical_ch[id].receive_cb(
-					list_elem->cmux_pkt.data,
-					(int)list_elem->cmux_pkt.hdr->pkt_len,
-					logical_ch[id].priv);
-				list_del(&list_elem->list);
-				kfree(list_elem->cmux_pkt.hdr);
-				kfree(list_elem);
-			}
-		}
-		mutex_unlock(&temp_rx_lock);
-	}
-	mutex_unlock(&logical_ch[id].rx_cb_lock);
-	mutex_unlock(&logical_ch[id].lc_lock);
-	sdio_cmux_write_cmd(id, OPEN);
-	return 0;
-}
-EXPORT_SYMBOL(sdio_cmux_open);
-
-int sdio_cmux_close(int id)
-{
-	struct sdio_cmux_ch *ch;
-
-	if (!sdio_cmux_inited)
-		return -ENODEV;
-	if (id < 0 || id >= SDIO_CMUX_NUM_CHANNELS) {
-		pr_err("%s: Invalid channel close\n", __func__);
-		return -EINVAL;
-	}
-
-	ch = &logical_ch[id];
-	mutex_lock(&ch->lc_lock);
-	mutex_lock(&logical_ch[id].rx_cb_lock);
-	ch->receive_cb = NULL;
-	mutex_unlock(&logical_ch[id].rx_cb_lock);
-	mutex_lock(&ch->tx_lock);
-	ch->write_done = NULL;
-	mutex_unlock(&ch->tx_lock);
-	ch->is_local_open = 0;
-	ch->priv = NULL;
-	mutex_unlock(&ch->lc_lock);
-	sdio_cmux_write_cmd(ch->lc_id, CLOSE);
-	return 0;
-}
-EXPORT_SYMBOL(sdio_cmux_close);
-
-int sdio_cmux_write_avail(int id)
-{
-	int write_avail;
-
-	mutex_lock(&logical_ch[id].lc_lock);
-	if (logical_ch[id].is_channel_reset) {
-		mutex_unlock(&logical_ch[id].lc_lock);
-		return -ENETRESET;
-	}
-	mutex_unlock(&logical_ch[id].lc_lock);
-	write_avail = sdio_write_avail(sdio_qmi_chl);
-	return write_avail - bytes_to_write;
-}
-EXPORT_SYMBOL(sdio_cmux_write_avail);
-
-int sdio_cmux_write(int id, void *data, int len)
-{
-	struct sdio_cmux_list_elem *list_elem;
-	uint32_t write_size;
-	void *write_data = NULL;
-	struct sdio_cmux_ch *ch;
-	int ret;
-
-	if (!sdio_cmux_inited)
-		return -ENODEV;
-	if (id < 0 || id >= SDIO_CMUX_NUM_CHANNELS) {
-		pr_err("%s: Invalid channel id %d\n", __func__, id);
-		return -ENODEV;
-	}
-
-	ch = &logical_ch[id];
-	if (len <= 0) {
-		pr_err("%s: Invalid len %d bytes to write\n",
-			__func__, len);
-		return -EINVAL;
-	}
-
-	write_size = sizeof(struct sdio_cmux_hdr) + len;
-	list_elem = kmalloc(sizeof(struct sdio_cmux_list_elem), GFP_KERNEL);
-	if (!list_elem) {
-		pr_err("%s: list_elem alloc failed\n", __func__);
-		return -ENOMEM;
-	}
-
-	write_data = kmalloc(write_size, GFP_KERNEL);
-	if (!write_data) {
-		pr_err("%s: write_data alloc failed\n", __func__);
-		kfree(list_elem);
-		return -ENOMEM;
-	}
-
-	list_elem->cmux_pkt.hdr = (struct sdio_cmux_hdr *)write_data;
-	list_elem->cmux_pkt.data = (void *)((char *)write_data +
-						sizeof(struct sdio_cmux_hdr));
-	memcpy(list_elem->cmux_pkt.data, data, len);
-
-	list_elem->cmux_pkt.hdr->lc_id = (uint8_t)ch->lc_id;
-	list_elem->cmux_pkt.hdr->pkt_len = (uint16_t)len;
-	list_elem->cmux_pkt.hdr->cmd = (uint8_t)DATA;
-	list_elem->cmux_pkt.hdr->status = (uint8_t)0;
-	list_elem->cmux_pkt.hdr->pad_bytes = (uint8_t)0;
-	list_elem->cmux_pkt.hdr->magic_no = (uint16_t)MAGIC_NO_V1;
-
-	mutex_lock(&ch->lc_lock);
-	if (!ch->is_remote_open || !ch->is_local_open) {
-		pr_err("%s: Local ch%d sending data before sending/receiving"
-		       " OPEN command\n", __func__, ch->lc_id);
-		if (ch->is_channel_reset)
-			ret = -ENETRESET;
-		else
-			ret = -ENODEV;
-		mutex_unlock(&ch->lc_lock);
-		kfree(write_data);
-		kfree(list_elem);
-		return ret;
-	}
-	mutex_lock(&ch->tx_lock);
-	list_add_tail(&list_elem->list, &ch->tx_list);
-	mutex_unlock(&ch->tx_lock);
-	mutex_unlock(&ch->lc_lock);
-
-	mutex_lock(&write_lock);
-	bytes_to_write += write_size;
-	mutex_unlock(&write_lock);
-	queue_work(sdio_cmux_wq, &sdio_cmux_work);
-
-	return len;
-}
-EXPORT_SYMBOL(sdio_cmux_write);
-
-int is_remote_open(int id)
-{
-	if (id < 0 || id >= SDIO_CMUX_NUM_CHANNELS)
-		return -ENODEV;
-
-	return logical_ch_is_remote_open(id);
-}
-EXPORT_SYMBOL(is_remote_open);
-
-int sdio_cmux_is_channel_reset(int id)
-{
-	int ret;
-	if (id < 0 || id >= SDIO_CMUX_NUM_CHANNELS)
-		return -ENODEV;
-
-	mutex_lock(&logical_ch[id].lc_lock);
-	ret = logical_ch[id].is_channel_reset;
-	mutex_unlock(&logical_ch[id].lc_lock);
-	return ret;
-}
-EXPORT_SYMBOL(sdio_cmux_is_channel_reset);
-
-int sdio_cmux_tiocmget(int id)
-{
-	int ret =  (logical_ch[id].remote_status & DSR_POS ? TIOCM_DSR : 0) |
-		(logical_ch[id].remote_status & CTS_POS ? TIOCM_CTS : 0) |
-		(logical_ch[id].remote_status & CD_POS ? TIOCM_CD : 0) |
-		(logical_ch[id].remote_status & RI_POS ? TIOCM_RI : 0) |
-		(logical_ch[id].local_status & CTS_POS ? TIOCM_RTS : 0) |
-		(logical_ch[id].local_status & DSR_POS ? TIOCM_DTR : 0);
-	return ret;
-}
-EXPORT_SYMBOL(sdio_cmux_tiocmget);
-
-int sdio_cmux_tiocmset(int id, unsigned int set, unsigned int clear)
-{
-	if (set & TIOCM_DTR)
-		logical_ch[id].local_status |= DSR_POS;
-
-	if (set & TIOCM_RTS)
-		logical_ch[id].local_status |= CTS_POS;
-
-	if (clear & TIOCM_DTR)
-		logical_ch[id].local_status &= ~DSR_POS;
-
-	if (clear & TIOCM_RTS)
-		logical_ch[id].local_status &= ~CTS_POS;
-
-	sdio_cmux_write_cmd(id, STATUS);
-	return 0;
-}
-EXPORT_SYMBOL(sdio_cmux_tiocmset);
-
-static int copy_packet(void *pkt, int size)
-{
-	struct sdio_cmux_list_elem *list_elem = NULL;
-	void *temp_pkt = NULL;
-
-	list_elem = kmalloc(sizeof(struct sdio_cmux_list_elem), GFP_KERNEL);
-	if (!list_elem) {
-		pr_err("%s: list_elem alloc failed\n", __func__);
-		return -ENOMEM;
-	}
-	temp_pkt = kmalloc(size, GFP_KERNEL);
-	if (!temp_pkt) {
-		pr_err("%s: temp_pkt alloc failed\n", __func__);
-		kfree(list_elem);
-		return -ENOMEM;
-	}
-
-	memcpy(temp_pkt, pkt, size);
-	list_elem->cmux_pkt.hdr = temp_pkt;
-	list_elem->cmux_pkt.data = (void *)((char *)temp_pkt +
-					    sizeof(struct sdio_cmux_hdr));
-	mutex_lock(&temp_rx_lock);
-	list_add_tail(&list_elem->list, &temp_rx_list);
-	mutex_unlock(&temp_rx_lock);
-	return 0;
-}
-
-static int process_cmux_pkt(void *pkt, int size)
-{
-	struct sdio_cmux_hdr *mux_hdr;
-	uint32_t id, data_size;
-	void *data;
-	char *dump_buf = (char *)pkt;
-
-	D_DUMP_BUFFER("process_cmux_pkt:", size, dump_buf);
-	mux_hdr = (struct sdio_cmux_hdr *)pkt;
-	switch (mux_hdr->cmd) {
-	case OPEN:
-		id = (uint32_t)(mux_hdr->lc_id);
-		D("%s: Received OPEN command for ch%d\n", __func__, id);
-		mutex_lock(&logical_ch[id].lc_lock);
-		logical_ch[id].is_remote_open = 1;
-		if (logical_ch[id].is_channel_reset) {
-			sdio_cmux_write_cmd(id, OPEN);
-			logical_ch[id].is_channel_reset = 0;
-		}
-		mutex_unlock(&logical_ch[id].lc_lock);
-		wake_up(&logical_ch[id].open_wait_queue);
-		break;
-
-	case CLOSE:
-		id = (uint32_t)(mux_hdr->lc_id);
-		D("%s: Received CLOSE command for ch%d\n", __func__, id);
-		sdio_cmux_ch_clear_and_signal(id);
-		break;
-
-	case DATA:
-		id = (uint32_t)(mux_hdr->lc_id);
-		D("%s: Received DATA for ch%d\n", __func__, id);
-		/*Channel is not locally open & if single packet received
-		  then drop it*/
-		mutex_lock(&logical_ch[id].lc_lock);
-		if (!logical_ch[id].is_remote_open) {
-			mutex_unlock(&logical_ch[id].lc_lock);
-			pr_err("%s: Remote Ch%d sent data before sending/"
-			       "receiving OPEN command\n", __func__, id);
-			return -ENODEV;
-		}
-
-		data = (void *)((char *)pkt + sizeof(struct sdio_cmux_hdr));
-		data_size = (int)(((struct sdio_cmux_hdr *)pkt)->pkt_len);
-		mutex_unlock(&logical_ch[id].lc_lock);
-		/*
-		 * The lc_lock is released before the call to receive_cb
-		 * to avoid a dead lock where in the receive_cb would call a
-		 * function that tries to acquire a rx_lock which is already
-		 * acquired by a Thread that is waiting on lc_lock.
-		 */
-		mutex_lock(&logical_ch[id].rx_cb_lock);
-		if (logical_ch[id].receive_cb)
-			logical_ch[id].receive_cb(data, data_size,
-						logical_ch[id].priv);
-		else
-			copy_packet(pkt, size);
-		mutex_unlock(&logical_ch[id].rx_cb_lock);
-		break;
-
-	case STATUS:
-		id = (uint32_t)(mux_hdr->lc_id);
-		D("%s: Received STATUS command for ch%d\n", __func__, id);
-		if (logical_ch[id].remote_status != mux_hdr->status) {
-			mutex_lock(&logical_ch[id].lc_lock);
-			logical_ch[id].remote_status = mux_hdr->status;
-			mutex_unlock(&logical_ch[id].lc_lock);
-			if (logical_ch[id].status_callback)
-				logical_ch[id].status_callback(
-							sdio_cmux_tiocmget(id),
-							logical_ch[id].priv);
-		}
-		break;
-	}
-	return 0;
-}
-
-static void parse_cmux_data(void *data, int size)
-{
-	int data_parsed = 0, pkt_size;
-	char *temp_ptr;
-
-	D("Entered %s\n", __func__);
-	temp_ptr = (char *)data;
-	while (data_parsed < size) {
-		pkt_size = sizeof(struct sdio_cmux_hdr) +
-			   (int)(((struct sdio_cmux_hdr *)temp_ptr)->pkt_len);
-		D("Parsed %d bytes, Current Pkt Size %d bytes,"
-		  " Total size %d bytes\n", data_parsed, pkt_size, size);
-		process_cmux_pkt((void *)temp_ptr, pkt_size);
-		data_parsed += pkt_size;
-		temp_ptr += pkt_size;
-	}
-
-	kfree(data);
-}
-
-static void sdio_cdemux_fn(struct work_struct *work)
-{
-	int r = 0, read_avail = 0;
-	void *cmux_data;
-
-	while (1) {
-		read_avail = sdio_read_avail(sdio_qmi_chl);
-		if (read_avail < 0) {
-			pr_err("%s: sdio_read_avail failed with rc %d\n",
-				__func__, read_avail);
-			return;
-		}
-
-		if (read_avail == 0) {
-			D("%s: Nothing to read\n", __func__);
-			return;
-		}
-
-		D("%s: kmalloc %d bytes\n", __func__, read_avail);
-		cmux_data = kmalloc(read_avail, GFP_KERNEL);
-		if (!cmux_data) {
-			pr_err("%s: kmalloc Failed\n", __func__);
-			return;
-		}
-
-		D("%s: sdio_read %d bytes\n", __func__, read_avail);
-		r = sdio_read(sdio_qmi_chl, cmux_data, read_avail);
-		if (r < 0) {
-			pr_err("%s: sdio_read failed with rc %d\n",
-				__func__, r);
-			kfree(cmux_data);
-			return;
-		}
-
-		parse_cmux_data(cmux_data, read_avail);
-	}
-	return;
-}
-
-static void sdio_cmux_fn(struct work_struct *work)
-{
-	int i, r = 0;
-	void *write_data;
-	uint32_t write_size, write_avail, write_retry = 0;
-	int bytes_written;
-	struct sdio_cmux_list_elem *list_elem = NULL;
-	struct sdio_cmux_ch *ch;
-
-	for (i = 0; i < SDIO_CMUX_NUM_CHANNELS; ++i) {
-		ch = &logical_ch[i];
-		bytes_written = 0;
-		mutex_lock(&ch->tx_lock);
-		while (!list_empty(&ch->tx_list)) {
-			list_elem = list_first_entry(&ch->tx_list,
-					     struct sdio_cmux_list_elem,
-					     list);
-			list_del(&list_elem->list);
-			mutex_unlock(&ch->tx_lock);
-
-			write_data = (void *)list_elem->cmux_pkt.hdr;
-			write_size = sizeof(struct sdio_cmux_hdr) +
-				(uint32_t)list_elem->cmux_pkt.hdr->pkt_len;
-
-			mutex_lock(&modem_reset_lock);
-			while (!(abort_tx) &&
-				((write_avail = sdio_write_avail(sdio_qmi_chl))
-						< write_size)) {
-				mutex_unlock(&modem_reset_lock);
-				pr_err("%s: sdio_write_avail %d bytes, "
-				       "write size %d bytes. Waiting...\n",
-					__func__, write_avail, write_size);
-				msleep(250);
-				mutex_lock(&modem_reset_lock);
-			}
-			while (!(abort_tx) &&
-				((r = sdio_write(sdio_qmi_chl,
-						write_data, write_size)) < 0)
-				&& (r != -ENODEV)
-				&& (write_retry++ < MAX_WRITE_RETRY)) {
-				mutex_unlock(&modem_reset_lock);
-				pr_err("%s: sdio_write failed with rc %d."
-				       "Retrying...", __func__, r);
-				msleep(250);
-				mutex_lock(&modem_reset_lock);
-			}
-			if (!r && !abort_tx) {
-				D("%s: sdio_write_completed %dbytes\n",
-				  __func__, write_size);
-				bytes_written += write_size;
-			} else if (r == -ENODEV) {
-				pr_err("%s: aborting_tx because sdio_write"
-				       " returned %d\n", __func__, r);
-				r = 0;
-				abort_tx = 1;
-			}
-			mutex_unlock(&modem_reset_lock);
-			kfree(list_elem->cmux_pkt.hdr);
-			kfree(list_elem);
-			mutex_lock(&write_lock);
-			bytes_to_write -= write_size;
-			mutex_unlock(&write_lock);
-			mutex_lock(&ch->tx_lock);
-		}
-		if (ch->write_done)
-			ch->write_done(NULL, bytes_written, ch->priv);
-		mutex_unlock(&ch->tx_lock);
-	}
-	return;
-}
-
-static void sdio_qmi_chl_notify(void *priv, unsigned event)
-{
-	if (event == SDIO_EVENT_DATA_READ_AVAIL) {
-		D("%s: Received SDIO_EVENT_DATA_READ_AVAIL\n", __func__);
-		queue_work(sdio_cdemux_wq, &sdio_cdemux_work);
-	}
-}
-
-#ifdef CONFIG_DEBUG_FS
-
-static int debug_tbl(char *buf, int max)
-{
-	int i = 0;
-	int j;
-
-	for (j = 0; j < SDIO_CMUX_NUM_CHANNELS; ++j) {
-		i += scnprintf(buf + i, max - i,
-			"ch%02d  local open=%s  remote open=%s\n",
-			j, logical_ch_is_local_open(j) ? "Y" : "N",
-			logical_ch_is_remote_open(j) ? "Y" : "N");
-	}
-
-	return i;
-}
-
-#define DEBUG_BUFMAX 4096
-static char debug_buffer[DEBUG_BUFMAX];
-
-static ssize_t debug_read(struct file *file, char __user *buf,
-				size_t count, loff_t *ppos)
-{
-	int (*fill)(char *buf, int max) = file->private_data;
-	int bsize = fill(debug_buffer, DEBUG_BUFMAX);
-	return simple_read_from_buffer(buf, count, ppos, debug_buffer, bsize);
-}
-
-static int debug_open(struct inode *inode, struct file *file)
-{
-	file->private_data = inode->i_private;
-	return 0;
-}
-
-
-static const struct file_operations debug_ops = {
-	.read = debug_read,
-	.open = debug_open,
-};
-
-static void debug_create(const char *name, mode_t mode,
-				struct dentry *dent,
-				int (*fill)(char *buf, int max))
-{
-	debugfs_create_file(name, mode, dent, fill, &debug_ops);
-}
-
-#endif
-
-static int sdio_cmux_probe(struct platform_device *pdev)
-{
-	int i, r;
-
-	mutex_lock(&probe_lock);
-	D("%s Begins\n", __func__);
-	if (sdio_cmux_inited) {
-		mutex_lock(&modem_reset_lock);
-		r =  sdio_open("SDIO_QMI", &sdio_qmi_chl, NULL,
-				sdio_qmi_chl_notify);
-		if (r < 0) {
-			mutex_unlock(&modem_reset_lock);
-			pr_err("%s: sdio_open() failed\n", __func__);
-			goto error0;
-		}
-		abort_tx = 0;
-		mutex_unlock(&modem_reset_lock);
-		mutex_unlock(&probe_lock);
-		return 0;
-	}
-
-	for (i = 0; i < SDIO_CMUX_NUM_CHANNELS; ++i)
-		sdio_cmux_ch_alloc(i);
-	INIT_LIST_HEAD(&temp_rx_list);
-
-	sdio_cmux_wq = create_singlethread_workqueue("sdio_cmux");
-	if (IS_ERR(sdio_cmux_wq)) {
-		pr_err("%s: create_singlethread_workqueue() ENOMEM\n",
-			__func__);
-		r = -ENOMEM;
-		goto error0;
-	}
-
-	sdio_cdemux_wq = create_singlethread_workqueue("sdio_cdemux");
-	if (IS_ERR(sdio_cdemux_wq)) {
-		pr_err("%s: create_singlethread_workqueue() ENOMEM\n",
-			__func__);
-		r = -ENOMEM;
-		goto error1;
-	}
-
-	r = sdio_open("SDIO_QMI", &sdio_qmi_chl, NULL, sdio_qmi_chl_notify);
-	if (r < 0) {
-		pr_err("%s: sdio_open() failed\n", __func__);
-		goto error2;
-	}
-
-	platform_device_register(&sdio_ctl_dev);
-	sdio_cmux_inited = 1;
-	D("SDIO Control MUX Driver Initialized.\n");
-	mutex_unlock(&probe_lock);
-	return 0;
-
-error2:
-	destroy_workqueue(sdio_cdemux_wq);
-error1:
-	destroy_workqueue(sdio_cmux_wq);
-error0:
-	mutex_unlock(&probe_lock);
-	return r;
-}
-
-static int sdio_cmux_remove(struct platform_device *pdev)
-{
-	int i;
-
-	mutex_lock(&modem_reset_lock);
-	abort_tx = 1;
-
-	for (i = 0; i < SDIO_CMUX_NUM_CHANNELS; ++i) {
-		mutex_lock(&logical_ch[i].lc_lock);
-		logical_ch[i].is_channel_reset = 1;
-		mutex_unlock(&logical_ch[i].lc_lock);
-		sdio_cmux_ch_clear_and_signal(i);
-	}
-	sdio_qmi_chl = NULL;
-	mutex_unlock(&modem_reset_lock);
-
-	return 0;
-}
-
-static struct platform_driver sdio_cmux_driver = {
-	.probe          = sdio_cmux_probe,
-	.remove         = sdio_cmux_remove,
-	.driver         = {
-			.name   = "SDIO_QMI",
-			.owner  = THIS_MODULE,
-	},
-};
-
-static int __init sdio_cmux_init(void)
-{
-#ifdef CONFIG_DEBUG_FS
-	struct dentry *dent;
-
-	dent = debugfs_create_dir("sdio_cmux", 0);
-	if (!IS_ERR(dent))
-		debug_create("tbl", 0444, dent, debug_tbl);
-#endif
-
-	msm_sdio_cmux_debug_mask = 0;
-	return platform_driver_register(&sdio_cmux_driver);
-}
-
-module_init(sdio_cmux_init);
-MODULE_DESCRIPTION("MSM SDIO Control MUX");
-MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/sdio_ctl.c b/arch/arm/mach-msm/sdio_ctl.c
deleted file mode 100644
index cacdce9..0000000
--- a/arch/arm/mach-msm/sdio_ctl.c
+++ /dev/null
@@ -1,575 +0,0 @@
-/* Copyright (c) 2010-2012, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
-
-/*
- * SDIO Control Driver -- Provides a binary SDIO muxed control port
- *                       interface.
- */
-
-#include <linux/cdev.h>
-#include <linux/module.h>
-#include <linux/fs.h>
-#include <linux/device.h>
-#include <linux/delay.h>
-#include <linux/sched.h>
-#include <linux/spinlock.h>
-#include <linux/mutex.h>
-#include <linux/uaccess.h>
-#include <linux/workqueue.h>
-#include <linux/poll.h>
-#include <asm/ioctls.h>
-#include <linux/platform_device.h>
-#include <mach/msm_smd.h>
-#include <mach/sdio_al.h>
-#include <mach/sdio_cmux.h>
-#include "modem_notifier.h"
-#include <linux/slab.h>
-
-#define MAX_WRITE_RETRY 5
-#define MAGIC_NO_V1 0x33FC
-#define NUM_SDIO_CTL_PORTS 10
-#define DEVICE_NAME "sdioctl"
-#define MAX_BUF_SIZE 2048
-#define DEBUG
-
-static int msm_sdio_ctl_debug_mask;
-module_param_named(debug_mask, msm_sdio_ctl_debug_mask,
-		   int, S_IRUGO | S_IWUSR | S_IWGRP);
-
-struct sdio_ctl_dev {
-	int id;
-	char name[9];
-	struct cdev cdev;
-	struct device *devicep;
-	struct mutex dev_lock;
-	int ref_count;
-
-	struct mutex rx_lock;
-	uint32_t read_avail;
-	struct list_head rx_list;
-
-	wait_queue_head_t read_wait_queue;
-	wait_queue_head_t write_wait_queue;
-} *sdio_ctl_devp[NUM_SDIO_CTL_PORTS];
-
-struct sdio_ctl_pkt {
-	int data_size;
-	void *data;
-};
-
-struct sdio_ctl_list_elem {
-	struct list_head list;
-	struct sdio_ctl_pkt ctl_pkt;
-};
-
-struct class *sdio_ctl_classp;
-static dev_t sdio_ctl_number;
-static uint32_t sdio_ctl_inited;
-
-enum {
-	MSM_SDIO_CTL_DEBUG = 1U << 0,
-	MSM_SDIO_CTL_DUMP_BUFFER = 1U << 1,
-};
-
-#if defined(DEBUG)
-#define D_DUMP_BUFFER(prestr, cnt, buf) \
-do { \
-	if (msm_sdio_ctl_debug_mask & MSM_SDIO_CTL_DUMP_BUFFER) { \
-		int i; \
-		pr_info("%s", prestr); \
-		for (i = 0; i < cnt; i++) \
-			pr_info("%.2x", buf[i]); \
-		pr_info("\n"); \
-	} \
-} while (0)
-
-#define D(x...) \
-do { \
-	if (msm_sdio_ctl_debug_mask & MSM_SDIO_CTL_DEBUG) \
-		pr_info(x); \
-} while (0)
-
-#else
-#define D_DUMP_BUFFER(prestr, cnt, buf) do {} while (0)
-#define D(x...) do {} while (0)
-#endif
-
-static uint32_t cmux_ch_id[] = {
-	SDIO_CMUX_DATA_CTL_0,
-	SDIO_CMUX_DATA_CTL_1,
-	SDIO_CMUX_DATA_CTL_2,
-	SDIO_CMUX_DATA_CTL_3,
-	SDIO_CMUX_DATA_CTL_4,
-	SDIO_CMUX_DATA_CTL_5,
-	SDIO_CMUX_DATA_CTL_6,
-	SDIO_CMUX_DATA_CTL_7,
-	SDIO_CMUX_USB_CTL_0,
-	SDIO_CMUX_CSVT_CTL_0
-};
-
-static int get_ctl_dev_index(int id)
-{
-	int dev_index;
-	for (dev_index = 0; dev_index < NUM_SDIO_CTL_PORTS; dev_index++) {
-		if (cmux_ch_id[dev_index] == id)
-			return dev_index;
-	}
-	return -ENODEV;
-}
-
-static void sdio_ctl_receive_cb(void *data, int size, void *priv)
-{
-	struct sdio_ctl_list_elem *list_elem = NULL;
-	int id = ((struct sdio_ctl_dev *)(priv))->id;
-	int dev_index;
-
-	if (id < 0 || id > cmux_ch_id[NUM_SDIO_CTL_PORTS - 1])
-		return;
-	dev_index = get_ctl_dev_index(id);
-	if (dev_index < 0) {
-		pr_err("%s: Ch%d is not exported to user-space\n",
-			__func__, id);
-		return;
-	}
-
-	if (!data || size <= 0) {
-		wake_up(&sdio_ctl_devp[dev_index]->read_wait_queue);
-		return;
-	}
-
-	list_elem = kmalloc(sizeof(struct sdio_ctl_list_elem), GFP_KERNEL);
-	if (!list_elem) {
-		pr_err("%s: list_elem alloc failed\n", __func__);
-		return;
-	}
-
-	list_elem->ctl_pkt.data = kmalloc(size, GFP_KERNEL);
-	if (!list_elem->ctl_pkt.data) {
-		pr_err("%s: list_elem->data alloc failed\n", __func__);
-		kfree(list_elem);
-		return;
-	}
-	memcpy(list_elem->ctl_pkt.data, data, size);
-	list_elem->ctl_pkt.data_size = size;
-	mutex_lock(&sdio_ctl_devp[dev_index]->rx_lock);
-	list_add_tail(&list_elem->list, &sdio_ctl_devp[dev_index]->rx_list);
-	sdio_ctl_devp[dev_index]->read_avail += size;
-	mutex_unlock(&sdio_ctl_devp[dev_index]->rx_lock);
-	wake_up(&sdio_ctl_devp[dev_index]->read_wait_queue);
-}
-
-static void sdio_ctl_write_done(void *data, int size, void *priv)
-{
-	int id = ((struct sdio_ctl_dev *)(priv))->id;
-	int dev_index;
-	if (id < 0 || id > cmux_ch_id[NUM_SDIO_CTL_PORTS - 1])
-		return;
-
-	dev_index = get_ctl_dev_index(id);
-	if (dev_index < 0) {
-		pr_err("%s: Ch%d is not exported to user-space\n",
-			__func__, id);
-		return;
-	}
-	wake_up(&sdio_ctl_devp[dev_index]->write_wait_queue);
-}
-
-static long sdio_ctl_ioctl(struct file *file, unsigned int cmd,
-					      unsigned long arg)
-{
-	int ret;
-	struct sdio_ctl_dev *sdio_ctl_devp;
-
-	sdio_ctl_devp = file->private_data;
-	if (!sdio_ctl_devp)
-		return -ENODEV;
-
-	switch (cmd) {
-	case TIOCMGET:
-		ret = sdio_cmux_tiocmget(sdio_ctl_devp->id);
-		break;
-	case TIOCMSET:
-		ret = sdio_cmux_tiocmset(sdio_ctl_devp->id, arg, ~arg);
-		break;
-	default:
-		ret = -EINVAL;
-	}
-
-	return ret;
-}
-
-static unsigned int sdio_ctl_poll(struct file *file, poll_table *wait)
-{
-	struct sdio_ctl_dev *sdio_ctl_devp;
-	unsigned int mask = 0;
-
-	sdio_ctl_devp = file->private_data;
-	if (!sdio_ctl_devp) {
-		pr_err("%s: on a NULL device\n", __func__);
-		return POLLERR;
-	}
-
-	poll_wait(file, &sdio_ctl_devp->read_wait_queue, wait);
-	mutex_lock(&sdio_ctl_devp->rx_lock);
-	if (sdio_cmux_is_channel_reset(sdio_ctl_devp->id)) {
-		mutex_unlock(&sdio_ctl_devp->rx_lock);
-		pr_err("%s notifying reset for sdio_ctl_dev id:%d\n",
-			__func__, sdio_ctl_devp->id);
-		return POLLERR;
-	}
-
-	if (sdio_ctl_devp->read_avail > 0)
-		mask |= POLLIN | POLLRDNORM;
-
-	mutex_unlock(&sdio_ctl_devp->rx_lock);
-
-	return mask;
-}
-
-ssize_t sdio_ctl_read(struct file *file,
-		      char __user *buf,
-		      size_t count,
-		      loff_t *ppos)
-{
-	int r = 0, id, bytes_to_read;
-	struct sdio_ctl_dev *sdio_ctl_devp;
-	struct sdio_ctl_list_elem *list_elem = NULL;
-
-	sdio_ctl_devp = file->private_data;
-
-	if (!sdio_ctl_devp)
-		return -ENODEV;
-
-	D("%s: read from ch%d\n", __func__, sdio_ctl_devp->id);
-
-	id = sdio_ctl_devp->id;
-	mutex_lock(&sdio_ctl_devp->rx_lock);
-	while (sdio_ctl_devp->read_avail <= 0) {
-		mutex_unlock(&sdio_ctl_devp->rx_lock);
-		r = wait_event_interruptible(sdio_ctl_devp->read_wait_queue,
-					     sdio_ctl_devp->read_avail > 0 ||
-					     !is_remote_open(id));
-		if (sdio_cmux_is_channel_reset(id))
-			return -ENETRESET;
-
-		if (!is_remote_open(id))
-			return -ENODEV;
-
-		if (r < 0) {
-			/* qualify error message */
-			/* we get this anytime a signal comes in */
-			if (r != -ERESTARTSYS)
-				pr_err("ERROR:%s: wait_event_interruptible "
-				       "ret %i\n", __func__, r);
-			return r;
-		}
-		mutex_lock(&sdio_ctl_devp->rx_lock);
-	}
-
-	if (list_empty(&sdio_ctl_devp->rx_list)) {
-		mutex_unlock(&sdio_ctl_devp->rx_lock);
-		D("%s: Nothing in ch%d's rx_list\n", __func__,
-		  sdio_ctl_devp->id);
-		return -EAGAIN;
-	}
-
-	list_elem = list_first_entry(&sdio_ctl_devp->rx_list,
-				     struct sdio_ctl_list_elem, list);
-	bytes_to_read = (uint32_t)(list_elem->ctl_pkt.data_size);
-	if (bytes_to_read > count) {
-		mutex_unlock(&sdio_ctl_devp->rx_lock);
-		pr_err("%s: Packet size %d > buf size %d\n", __func__,
-			bytes_to_read, count);
-		return -ENOMEM;
-	}
-
-	if (copy_to_user(buf, list_elem->ctl_pkt.data, bytes_to_read)) {
-		mutex_unlock(&sdio_ctl_devp->rx_lock);
-		pr_err("%s: copy_to_user failed for ch%d\n", __func__,
-			sdio_ctl_devp->id);
-		return -EFAULT;
-	}
-	sdio_ctl_devp->read_avail -= bytes_to_read;
-	list_del(&list_elem->list);
-	kfree(list_elem->ctl_pkt.data);
-	kfree(list_elem);
-	mutex_unlock(&sdio_ctl_devp->rx_lock);
-	D("%s: Returning %d bytes to ch%d\n", __func__,
-			bytes_to_read, sdio_ctl_devp->id);
-	return bytes_to_read;
-}
-
-
-ssize_t sdio_ctl_write(struct file *file,
-		       const char __user *buf,
-		       size_t count,
-		       loff_t *ppos)
-{
-	int r = 0, id;
-	char *temp_buf;
-	struct sdio_ctl_dev *sdio_ctl_devp;
-
-	if (count <= 0)
-		return -EINVAL;
-
-	sdio_ctl_devp = file->private_data;
-	if (!sdio_ctl_devp)
-		return -ENODEV;
-
-	D("%s: writing %i bytes on ch%d\n",
-	  __func__, count, sdio_ctl_devp->id);
-	id = sdio_ctl_devp->id;
-	mutex_lock(&sdio_ctl_devp->dev_lock);
-	while (sdio_cmux_write_avail(id) < count) {
-		mutex_unlock(&sdio_ctl_devp->dev_lock);
-		r = wait_event_interruptible(sdio_ctl_devp->write_wait_queue,
-					     sdio_cmux_write_avail(id) >= count
-					     || !is_remote_open(id));
-
-		if (sdio_cmux_is_channel_reset(id))
-			return -ENETRESET;
-
-		if (!is_remote_open(id))
-			return -ENODEV;
-
-		if (r < 0) {
-			/* qualify error message */
-			/* we get this anytime a signal comes in */
-			if (r != -ERESTARTSYS)
-				pr_err("ERROR:%s: wait_event_interruptible "
-				       "ret %i\n", __func__, r);
-			return r;
-		}
-		mutex_lock(&sdio_ctl_devp->dev_lock);
-	}
-
-	temp_buf = kmalloc(count, GFP_KERNEL);
-	if (!temp_buf) {
-		mutex_unlock(&sdio_ctl_devp->dev_lock);
-		pr_err("%s: temp_buf alloc failed\n", __func__);
-		return -ENOMEM;
-	}
-
-	if (copy_from_user(temp_buf, buf, count)) {
-		mutex_unlock(&sdio_ctl_devp->dev_lock);
-		pr_err("%s: copy_from_user failed\n", __func__);
-		kfree(temp_buf);
-		return -EFAULT;
-	}
-
-	r = sdio_cmux_write(id, (void *)temp_buf, count);
-	kfree(temp_buf);
-	mutex_unlock(&sdio_ctl_devp->dev_lock);
-	return r;
-}
-
-
-int sdio_ctl_open(struct inode *inode, struct file *file)
-{
-	int r = 0;
-	struct sdio_ctl_dev *sdio_ctl_devp;
-
-	if (!sdio_ctl_inited)
-		return -EIO;
-
-	sdio_ctl_devp = container_of(inode->i_cdev, struct sdio_ctl_dev, cdev);
-
-	if (!sdio_ctl_devp)
-		return -ENODEV;
-
-	D("%s called on sdioctl%d device\n", __func__, sdio_ctl_devp->id);
-	r = sdio_cmux_open(sdio_ctl_devp->id, sdio_ctl_receive_cb,
-			   sdio_ctl_write_done, NULL,
-			   sdio_ctl_devp);
-	if (r < 0) {
-		pr_err("ERROR %s: sdio_cmux_open failed with rc %d\n",
-			__func__, r);
-		return r;
-	}
-
-	mutex_lock(&sdio_ctl_devp->dev_lock);
-	sdio_ctl_devp->ref_count++;
-	mutex_unlock(&sdio_ctl_devp->dev_lock);
-
-	file->private_data = sdio_ctl_devp;
-	return 0;
-}
-
-int sdio_ctl_release(struct inode *inode, struct file *file)
-{
-	struct sdio_ctl_dev *sdio_ctl_devp;
-	struct sdio_ctl_list_elem *list_elem = NULL;
-
-	sdio_ctl_devp = file->private_data;
-	if (!sdio_ctl_devp)
-		return -EINVAL;
-
-	D("%s called on sdioctl%d device\n", __func__, sdio_ctl_devp->id);
-
-	mutex_lock(&sdio_ctl_devp->dev_lock);
-	if (sdio_ctl_devp->ref_count > 0) {
-		sdio_ctl_devp->ref_count--;
-		if (!sdio_ctl_devp->ref_count) {
-			mutex_lock(&sdio_ctl_devp->rx_lock);
-			while (!list_empty(&sdio_ctl_devp->rx_list)) {
-				list_elem = list_first_entry(
-						&sdio_ctl_devp->rx_list,
-						struct sdio_ctl_list_elem,
-						list);
-				list_del(&list_elem->list);
-				kfree(list_elem->ctl_pkt.data);
-				kfree(list_elem);
-			}
-			sdio_ctl_devp->read_avail = 0;
-			mutex_unlock(&sdio_ctl_devp->rx_lock);
-			sdio_cmux_close(sdio_ctl_devp->id);
-		}
-	}
-	mutex_unlock(&sdio_ctl_devp->dev_lock);
-
-	file->private_data = NULL;
-	return 0;
-}
-
-static const struct file_operations sdio_ctl_fops = {
-	.owner = THIS_MODULE,
-	.open = sdio_ctl_open,
-	.release = sdio_ctl_release,
-	.read = sdio_ctl_read,
-	.write = sdio_ctl_write,
-	.poll = sdio_ctl_poll,
-	.unlocked_ioctl = sdio_ctl_ioctl,
-};
-
-static int sdio_ctl_probe(struct platform_device *pdev)
-{
-	int i;
-	int r;
-
-	pr_info("%s Begins\n", __func__);
-	for (i = 0; i < NUM_SDIO_CTL_PORTS; ++i) {
-		sdio_ctl_devp[i] = kzalloc(sizeof(struct sdio_ctl_dev),
-					GFP_KERNEL);
-		if (IS_ERR(sdio_ctl_devp[i])) {
-			pr_err("ERROR:%s kmalloc() ENOMEM\n", __func__);
-			r = -ENOMEM;
-			goto error0;
-		}
-
-		sdio_ctl_devp[i]->id = cmux_ch_id[i];
-		sdio_ctl_devp[i]->ref_count = 0;
-
-		mutex_init(&sdio_ctl_devp[i]->dev_lock);
-		init_waitqueue_head(&sdio_ctl_devp[i]->read_wait_queue);
-		init_waitqueue_head(&sdio_ctl_devp[i]->write_wait_queue);
-		mutex_init(&sdio_ctl_devp[i]->rx_lock);
-		INIT_LIST_HEAD(&sdio_ctl_devp[i]->rx_list);
-		sdio_ctl_devp[i]->read_avail = 0;
-	}
-
-	r = alloc_chrdev_region(&sdio_ctl_number, 0, NUM_SDIO_CTL_PORTS,
-				DEVICE_NAME);
-	if (IS_ERR_VALUE(r)) {
-		pr_err("ERROR:%s: alloc_chrdev_region() ret %i.\n",
-		       __func__, r);
-		goto error0;
-	}
-
-	sdio_ctl_classp = class_create(THIS_MODULE, DEVICE_NAME);
-	if (IS_ERR(sdio_ctl_classp)) {
-		pr_err("ERROR:%s: class_create() ENOMEM\n", __func__);
-		r = -ENOMEM;
-		goto error1;
-	}
-
-	for (i = 0; i < NUM_SDIO_CTL_PORTS; ++i) {
-		cdev_init(&sdio_ctl_devp[i]->cdev, &sdio_ctl_fops);
-		sdio_ctl_devp[i]->cdev.owner = THIS_MODULE;
-
-		r = cdev_add(&sdio_ctl_devp[i]->cdev, (sdio_ctl_number + i),
-			     1);
-
-		if (IS_ERR_VALUE(r)) {
-			pr_err("%s: cdev_add() ret %i\n", __func__, r);
-			kfree(sdio_ctl_devp[i]);
-			goto error2;
-		}
-
-		sdio_ctl_devp[i]->devicep =
-				device_create(sdio_ctl_classp, NULL,
-				      (sdio_ctl_number + i), NULL,
-				      DEVICE_NAME "%d", cmux_ch_id[i]);
-
-		if (IS_ERR(sdio_ctl_devp[i]->devicep)) {
-			pr_err("%s: device_create() ENOMEM\n", __func__);
-			r = -ENOMEM;
-			cdev_del(&sdio_ctl_devp[i]->cdev);
-			kfree(sdio_ctl_devp[i]);
-			goto error2;
-		}
-	}
-
-	sdio_ctl_inited = 1;
-	D("SDIO Control Port Driver Initialized.\n");
-	return 0;
-
-error2:
-	while (--i >= 0) {
-		cdev_del(&sdio_ctl_devp[i]->cdev);
-		device_destroy(sdio_ctl_classp,
-			       MKDEV(MAJOR(sdio_ctl_number), i));
-	}
-
-	class_destroy(sdio_ctl_classp);
-	i = NUM_SDIO_CTL_PORTS;
-error1:
-	unregister_chrdev_region(MAJOR(sdio_ctl_number), NUM_SDIO_CTL_PORTS);
-error0:
-	while (--i >= 0)
-		kfree(sdio_ctl_devp[i]);
-	return r;
-}
-
-static int sdio_ctl_remove(struct platform_device *pdev)
-{
-	int i;
-
-	for (i = 0; i < NUM_SDIO_CTL_PORTS; ++i) {
-		cdev_del(&sdio_ctl_devp[i]->cdev);
-		kfree(sdio_ctl_devp[i]);
-		device_destroy(sdio_ctl_classp,
-			       MKDEV(MAJOR(sdio_ctl_number), i));
-	}
-	class_destroy(sdio_ctl_classp);
-	unregister_chrdev_region(MAJOR(sdio_ctl_number), NUM_SDIO_CTL_PORTS);
-
-	return 0;
-}
-
-static struct platform_driver sdio_ctl_driver = {
-	.probe		= sdio_ctl_probe,
-	.remove		= sdio_ctl_remove,
-	.driver		= {
-			.name	= "SDIO_CTL",
-			.owner	= THIS_MODULE,
-	},
-};
-
-static int __init sdio_ctl_init(void)
-{
-	msm_sdio_ctl_debug_mask = 0;
-	return platform_driver_register(&sdio_ctl_driver);
-}
-
-module_init(sdio_ctl_init);
-MODULE_DESCRIPTION("MSM SDIO Control Port");
-MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/sdio_dmux.c b/arch/arm/mach-msm/sdio_dmux.c
deleted file mode 100644
index c6d665d..0000000
--- a/arch/arm/mach-msm/sdio_dmux.c
+++ /dev/null
@@ -1,925 +0,0 @@
-/* Copyright (c) 2010-2011, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- */
-
-/*
- *  SDIO DMUX module.
- */
-
-#define DEBUG
-
-#include <linux/delay.h>
-#include <linux/module.h>
-#include <linux/netdevice.h>
-#include <linux/platform_device.h>
-#include <linux/sched.h>
-#include <linux/skbuff.h>
-#include <linux/wakelock.h>
-#include <linux/debugfs.h>
-#include <linux/smp.h>
-#include <linux/cpumask.h>
-
-#include <mach/sdio_al.h>
-#include <mach/sdio_dmux.h>
-
-#define SDIO_CH_LOCAL_OPEN       0x1
-#define SDIO_CH_REMOTE_OPEN      0x2
-#define SDIO_CH_IN_RESET         0x4
-
-#define SDIO_MUX_HDR_MAGIC_NO    0x33fc
-
-#define SDIO_MUX_HDR_CMD_DATA    0
-#define SDIO_MUX_HDR_CMD_OPEN    1
-#define SDIO_MUX_HDR_CMD_CLOSE   2
-
-#define LOW_WATERMARK            2
-#define HIGH_WATERMARK           4
-
-static int msm_sdio_dmux_debug_enable;
-module_param_named(debug_enable, msm_sdio_dmux_debug_enable,
-		   int, S_IRUGO | S_IWUSR | S_IWGRP);
-
-#if defined(DEBUG)
-static uint32_t sdio_dmux_read_cnt;
-static uint32_t sdio_dmux_write_cnt;
-static uint32_t sdio_dmux_write_cpy_cnt;
-static uint32_t sdio_dmux_write_cpy_bytes;
-
-#define DBG(x...) do {		                 \
-		if (msm_sdio_dmux_debug_enable)  \
-			pr_debug(x);	         \
-	} while (0)
-
-#define DBG_INC_READ_CNT(x) do {	                               \
-		sdio_dmux_read_cnt += (x);                             \
-		if (msm_sdio_dmux_debug_enable)                        \
-			pr_debug("%s: total read bytes %u\n",          \
-				 __func__, sdio_dmux_read_cnt);        \
-	} while (0)
-
-#define DBG_INC_WRITE_CNT(x)  do {	                               \
-		sdio_dmux_write_cnt += (x);                            \
-		if (msm_sdio_dmux_debug_enable)                        \
-			pr_debug("%s: total written bytes %u\n",       \
-				 __func__, sdio_dmux_write_cnt);       \
-	} while (0)
-
-#define DBG_INC_WRITE_CPY(x)  do {	                                     \
-		sdio_dmux_write_cpy_bytes += (x);                            \
-		sdio_dmux_write_cpy_cnt++;                                   \
-		if (msm_sdio_dmux_debug_enable)                              \
-			pr_debug("%s: total write copy cnt %u, bytes %u\n",  \
-				 __func__, sdio_dmux_write_cpy_cnt,          \
-				 sdio_dmux_write_cpy_bytes);                 \
-	} while (0)
-#else
-#define DBG(x...) do { } while (0)
-#define DBG_INC_READ_CNT(x...) do { } while (0)
-#define DBG_INC_WRITE_CNT(x...) do { } while (0)
-#define DBG_INC_WRITE_CPY(x...) do { } while (0)
-#endif
-
-struct sdio_ch_info {
-	uint32_t status;
-	void (*receive_cb)(void *, struct sk_buff *);
-	void (*write_done)(void *, struct sk_buff *);
-	void *priv;
-	spinlock_t lock;
-	int num_tx_pkts;
-	int use_wm;
-};
-
-static struct sk_buff_head sdio_mux_write_pool;
-static spinlock_t sdio_mux_write_lock;
-
-static struct sdio_channel *sdio_mux_ch;
-static struct sdio_ch_info sdio_ch[SDIO_DMUX_NUM_CHANNELS];
-struct wake_lock sdio_mux_ch_wakelock;
-static int sdio_mux_initialized;
-static int fatal_error;
-
-struct sdio_mux_hdr {
-	uint16_t magic_num;
-	uint8_t reserved;
-	uint8_t cmd;
-	uint8_t pad_len;
-	uint8_t ch_id;
-	uint16_t pkt_len;
-};
-
-struct sdio_partial_pkt_info {
-	uint32_t valid;
-	struct sk_buff *skb;
-	struct sdio_mux_hdr *hdr;
-};
-
-static void sdio_mux_read_data(struct work_struct *work);
-static void sdio_mux_write_data(struct work_struct *work);
-static void sdio_mux_send_open_cmd(uint32_t id);
-
-static DEFINE_MUTEX(sdio_mux_lock);
-static DECLARE_WORK(work_sdio_mux_read, sdio_mux_read_data);
-static DECLARE_WORK(work_sdio_mux_write, sdio_mux_write_data);
-static DECLARE_DELAYED_WORK(delayed_work_sdio_mux_write, sdio_mux_write_data);
-
-static struct workqueue_struct *sdio_mux_workqueue;
-static struct sdio_partial_pkt_info sdio_partial_pkt;
-
-#define sdio_ch_is_open(x)						\
-	(sdio_ch[(x)].status == (SDIO_CH_LOCAL_OPEN | SDIO_CH_REMOTE_OPEN))
-
-#define sdio_ch_is_local_open(x)			\
-	(sdio_ch[(x)].status & SDIO_CH_LOCAL_OPEN)
-
-#define sdio_ch_is_remote_open(x)			\
-	(sdio_ch[(x)].status & SDIO_CH_REMOTE_OPEN)
-
-#define sdio_ch_is_in_reset(x)			\
-	(sdio_ch[(x)].status & SDIO_CH_IN_RESET)
-
-static inline void skb_set_data(struct sk_buff *skb,
-				unsigned char *data,
-				unsigned int len)
-{
-	/* panic if tail > end */
-	skb->data = data;
-	skb->tail = skb->data + len;
-	skb->len  = len;
-	skb->truesize = len + sizeof(struct sk_buff);
-}
-
-static void sdio_mux_save_partial_pkt(struct sdio_mux_hdr *hdr,
-				      struct sk_buff *skb_mux)
-{
-	struct sk_buff *skb;
-
-	/* i think we can avoid cloning here */
-	skb =  skb_clone(skb_mux, GFP_KERNEL);
-	if (!skb) {
-		pr_err("%s: cannot clone skb\n", __func__);
-		return;
-	}
-
-	/* protect? */
-	skb_set_data(skb, (unsigned char *)hdr,
-		     skb->tail - (unsigned char *)hdr);
-	sdio_partial_pkt.skb = skb;
-	sdio_partial_pkt.valid = 1;
-	DBG("%s: head %p data %p tail %p end %p len %d\n", __func__,
-	    skb->head, skb->data, skb->tail, skb->end, skb->len);
-	return;
-}
-
-static void *handle_sdio_mux_data(struct sdio_mux_hdr *hdr,
-				  struct sk_buff *skb_mux)
-{
-	struct sk_buff *skb;
-	void *rp = (void *)hdr;
-	unsigned long flags;
-
-	/* protect? */
-	rp += sizeof(*hdr);
-	if (rp < (void *)skb_mux->tail)
-		rp += (hdr->pkt_len + hdr->pad_len);
-
-	if (rp > (void *)skb_mux->tail) {
-		/* partial packet */
-		sdio_mux_save_partial_pkt(hdr, skb_mux);
-		goto packet_done;
-	}
-
-	DBG("%s: hdr %p next %p tail %p pkt_size %d\n",
-	    __func__, hdr, rp, skb_mux->tail, hdr->pkt_len + hdr->pad_len);
-
-	skb =  skb_clone(skb_mux, GFP_KERNEL);
-	if (!skb) {
-		pr_err("%s: cannot clone skb\n", __func__);
-		goto packet_done;
-	}
-
-	skb_set_data(skb, (unsigned char *)(hdr + 1), hdr->pkt_len);
-	DBG("%s: head %p data %p tail %p end %p len %d\n",
-	    __func__, skb->head, skb->data, skb->tail, skb->end, skb->len);
-
-	/* probably we should check channel status */
-	/* discard packet early if local side not open */
-	spin_lock_irqsave(&sdio_ch[hdr->ch_id].lock, flags);
-	if (sdio_ch[hdr->ch_id].receive_cb)
-		sdio_ch[hdr->ch_id].receive_cb(sdio_ch[hdr->ch_id].priv, skb);
-	else
-		dev_kfree_skb_any(skb);
-	spin_unlock_irqrestore(&sdio_ch[hdr->ch_id].lock, flags);
-
-packet_done:
-	return rp;
-}
-
-static void *handle_sdio_mux_command(struct sdio_mux_hdr *hdr,
-				     struct sk_buff *skb_mux)
-{
-	void *rp;
-	unsigned long flags;
-	int send_open = 0;
-
-	DBG("%s: cmd %d ch %d\n", __func__, hdr->cmd, hdr->ch_id);
-	switch (hdr->cmd) {
-	case SDIO_MUX_HDR_CMD_DATA:
-		rp = handle_sdio_mux_data(hdr, skb_mux);
-		break;
-	case SDIO_MUX_HDR_CMD_OPEN:
-		spin_lock_irqsave(&sdio_ch[hdr->ch_id].lock, flags);
-		sdio_ch[hdr->ch_id].status |= SDIO_CH_REMOTE_OPEN;
-		sdio_ch[hdr->ch_id].num_tx_pkts = 0;
-
-		if (sdio_ch_is_in_reset(hdr->ch_id)) {
-			DBG("%s: in reset - sending open cmd\n", __func__);
-			sdio_ch[hdr->ch_id].status &= ~SDIO_CH_IN_RESET;
-			send_open = 1;
-		}
-
-		/* notify client so it can update its status */
-		if (sdio_ch[hdr->ch_id].receive_cb)
-			sdio_ch[hdr->ch_id].receive_cb(
-					sdio_ch[hdr->ch_id].priv, NULL);
-
-		if (sdio_ch[hdr->ch_id].write_done)
-			sdio_ch[hdr->ch_id].write_done(
-					sdio_ch[hdr->ch_id].priv, NULL);
-		spin_unlock_irqrestore(&sdio_ch[hdr->ch_id].lock, flags);
-		rp = hdr + 1;
-		if (send_open)
-			sdio_mux_send_open_cmd(hdr->ch_id);
-
-		break;
-	case SDIO_MUX_HDR_CMD_CLOSE:
-		/* probably should drop pending write */
-		spin_lock_irqsave(&sdio_ch[hdr->ch_id].lock, flags);
-		sdio_ch[hdr->ch_id].status &= ~SDIO_CH_REMOTE_OPEN;
-		spin_unlock_irqrestore(&sdio_ch[hdr->ch_id].lock, flags);
-		rp = hdr + 1;
-		break;
-	default:
-		rp = hdr + 1;
-	}
-
-	return rp;
-}
-
-static void *handle_sdio_partial_pkt(struct sk_buff *skb_mux)
-{
-	struct sk_buff *p_skb;
-	struct sdio_mux_hdr *p_hdr;
-	void *ptr, *rp = skb_mux->data;
-
-	/* protoect? */
-	if (sdio_partial_pkt.valid) {
-		p_skb = sdio_partial_pkt.skb;
-
-		ptr = skb_push(skb_mux, p_skb->len);
-		memcpy(ptr, p_skb->data, p_skb->len);
-		sdio_partial_pkt.skb = NULL;
-		sdio_partial_pkt.valid = 0;
-		dev_kfree_skb_any(p_skb);
-
-		DBG("%s: head %p data %p tail %p end %p len %d\n", __func__,
-		    skb_mux->head, skb_mux->data, skb_mux->tail,
-		    skb_mux->end, skb_mux->len);
-
-		p_hdr = (struct sdio_mux_hdr *)skb_mux->data;
-		rp = handle_sdio_mux_command(p_hdr, skb_mux);
-	}
-	return rp;
-}
-
-static void sdio_mux_read_data(struct work_struct *work)
-{
-	struct sk_buff *skb_mux;
-	void *ptr = 0;
-	int sz, rc, len = 0;
-	struct sdio_mux_hdr *hdr;
-	static int workqueue_pinned;
-
-	if (!workqueue_pinned) {
-		struct cpumask cpus;
-
-		cpumask_clear(&cpus);
-		cpumask_set_cpu(0, &cpus);
-
-		if (sched_setaffinity(current->pid, &cpus))
-			pr_err("%s: sdio_dmux set CPU affinity failed\n",
-					__func__);
-		workqueue_pinned = 1;
-	}
-
-	DBG("%s: reading\n", __func__);
-	/* should probably have a separate read lock */
-	mutex_lock(&sdio_mux_lock);
-	sz = sdio_read_avail(sdio_mux_ch);
-	DBG("%s: read avail %d\n", __func__, sz);
-	if (sz <= 0) {
-		if (sz)
-			pr_err("%s: read avail failed %d\n", __func__, sz);
-		mutex_unlock(&sdio_mux_lock);
-		return;
-	}
-
-	/* net_ip_aling is probably not required */
-	if (sdio_partial_pkt.valid)
-		len = sdio_partial_pkt.skb->len;
-
-	/* If allocation fails attempt to get a smaller chunk of mem */
-	do {
-		skb_mux = __dev_alloc_skb(sz + NET_IP_ALIGN + len, GFP_KERNEL);
-		if (skb_mux)
-			break;
-
-		pr_err("%s: cannot allocate skb of size:%d + "
-			"%d (NET_SKB_PAD)\n", __func__,
-			sz + NET_IP_ALIGN + len, NET_SKB_PAD);
-		/* the skb structure adds NET_SKB_PAD bytes to the memory
-		 * request, which may push the actual request above PAGE_SIZE
-		 * in that case, we need to iterate one more time to make sure
-		 * we get the memory request under PAGE_SIZE
-		 */
-		if (sz + NET_IP_ALIGN + len + NET_SKB_PAD <= PAGE_SIZE) {
-			pr_err("%s: allocation failed\n", __func__);
-			mutex_unlock(&sdio_mux_lock);
-			return;
-		}
-		sz /= 2;
-	} while (1);
-
-	skb_reserve(skb_mux, NET_IP_ALIGN + len);
-	ptr = skb_put(skb_mux, sz);
-
-	/* half second wakelock is fine? */
-	wake_lock_timeout(&sdio_mux_ch_wakelock, HZ / 2);
-	rc = sdio_read(sdio_mux_ch, ptr, sz);
-	DBG("%s: read %d\n", __func__, rc);
-	if (rc) {
-		pr_err("%s: sdio read failed %d\n", __func__, rc);
-		dev_kfree_skb_any(skb_mux);
-		mutex_unlock(&sdio_mux_lock);
-		queue_work(sdio_mux_workqueue, &work_sdio_mux_read);
-		return;
-	}
-	mutex_unlock(&sdio_mux_lock);
-
-	DBG_INC_READ_CNT(sz);
-	DBG("%s: head %p data %p tail %p end %p len %d\n", __func__,
-	    skb_mux->head, skb_mux->data, skb_mux->tail,
-	    skb_mux->end, skb_mux->len);
-
-	/* move to a separate function */
-	/* probably do skb_pull instead of pointer adjustment */
-	hdr = handle_sdio_partial_pkt(skb_mux);
-	while ((void *)hdr < (void *)skb_mux->tail) {
-
-		if (((void *)hdr + sizeof(*hdr)) > (void *)skb_mux->tail) {
-			/* handle partial header */
-			sdio_mux_save_partial_pkt(hdr, skb_mux);
-			break;
-		}
-
-		if (hdr->magic_num != SDIO_MUX_HDR_MAGIC_NO) {
-			pr_err("%s: packet error\n", __func__);
-			break;
-		}
-
-		hdr = handle_sdio_mux_command(hdr, skb_mux);
-	}
-	dev_kfree_skb_any(skb_mux);
-
-	DBG("%s: read done\n", __func__);
-	queue_work(sdio_mux_workqueue, &work_sdio_mux_read);
-}
-
-static int sdio_mux_write(struct sk_buff *skb)
-{
-	int rc, sz;
-
-	mutex_lock(&sdio_mux_lock);
-	sz = sdio_write_avail(sdio_mux_ch);
-	DBG("%s: avail %d len %d\n", __func__, sz, skb->len);
-	if (skb->len <= sz) {
-		rc = sdio_write(sdio_mux_ch, skb->data, skb->len);
-		DBG("%s: write returned %d\n", __func__, rc);
-		if (rc == 0)
-			DBG_INC_WRITE_CNT(skb->len);
-	} else
-		rc = -ENOMEM;
-
-	mutex_unlock(&sdio_mux_lock);
-	return rc;
-}
-
-static int sdio_mux_write_cmd(void *data, uint32_t len)
-{
-	int avail, rc;
-	for (;;) {
-		mutex_lock(&sdio_mux_lock);
-		avail = sdio_write_avail(sdio_mux_ch);
-		DBG("%s: avail %d len %d\n", __func__, avail, len);
-		if (avail >= len) {
-			rc = sdio_write(sdio_mux_ch, data, len);
-			DBG("%s: write returned %d\n", __func__, rc);
-			if (!rc) {
-				DBG_INC_WRITE_CNT(len);
-				break;
-			}
-		}
-		mutex_unlock(&sdio_mux_lock);
-		msleep(250);
-	}
-	mutex_unlock(&sdio_mux_lock);
-	return 0;
-}
-
-static void sdio_mux_send_open_cmd(uint32_t id)
-{
-	struct sdio_mux_hdr hdr = {
-		.magic_num = SDIO_MUX_HDR_MAGIC_NO,
-		.cmd = SDIO_MUX_HDR_CMD_OPEN,
-		.reserved = 0,
-		.ch_id = id,
-		.pkt_len = 0,
-		.pad_len = 0
-	};
-
-	sdio_mux_write_cmd((void *)&hdr, sizeof(hdr));
-}
-
-static void sdio_mux_write_data(struct work_struct *work)
-{
-	int rc, reschedule = 0;
-	int notify = 0;
-	struct sk_buff *skb;
-	unsigned long flags;
-	int avail;
-	int ch_id;
-
-	spin_lock_irqsave(&sdio_mux_write_lock, flags);
-	while ((skb = __skb_dequeue(&sdio_mux_write_pool))) {
-		ch_id = ((struct sdio_mux_hdr *)skb->data)->ch_id;
-
-		avail = sdio_write_avail(sdio_mux_ch);
-		if (avail < skb->len) {
-			/* we may have to wait for write avail
-			 * notification from sdio al
-			 */
-			DBG("%s: sdio_write_avail(%d) < skb->len(%d)\n",
-					__func__, avail, skb->len);
-
-			reschedule = 1;
-			break;
-		}
-		spin_unlock_irqrestore(&sdio_mux_write_lock, flags);
-		rc = sdio_mux_write(skb);
-		spin_lock_irqsave(&sdio_mux_write_lock, flags);
-		if (rc == 0) {
-
-			spin_lock(&sdio_ch[ch_id].lock);
-			sdio_ch[ch_id].num_tx_pkts--;
-			spin_unlock(&sdio_ch[ch_id].lock);
-
-			if (sdio_ch[ch_id].write_done)
-				sdio_ch[ch_id].write_done(
-						sdio_ch[ch_id].priv, skb);
-			else
-				dev_kfree_skb_any(skb);
-		} else if (rc == -EAGAIN || rc == -ENOMEM) {
-			/* recoverable error - retry again later */
-			reschedule = 1;
-			break;
-		} else if (rc == -ENODEV) {
-			/*
-			 * sdio_al suffered some kind of fatal error
-			 * prevent future writes and clean up pending ones
-			 */
-			fatal_error = 1;
-			do {
-				ch_id = ((struct sdio_mux_hdr *)
-						skb->data)->ch_id;
-				spin_lock(&sdio_ch[ch_id].lock);
-				sdio_ch[ch_id].num_tx_pkts--;
-				spin_unlock(&sdio_ch[ch_id].lock);
-				dev_kfree_skb_any(skb);
-			} while ((skb = __skb_dequeue(&sdio_mux_write_pool)));
-			spin_unlock_irqrestore(&sdio_mux_write_lock, flags);
-			return;
-		} else {
-			/* unknown error condition - drop the
-			 * skb and reschedule for the
-			 * other skb's
-			 */
-			pr_err("%s: sdio_mux_write error %d"
-				   " for ch %d, skb=%p\n",
-				__func__, rc, ch_id, skb);
-			notify = 1;
-			break;
-		}
-	}
-
-	if (reschedule) {
-		if (sdio_ch_is_in_reset(ch_id)) {
-			notify = 1;
-		} else {
-			__skb_queue_head(&sdio_mux_write_pool, skb);
-			queue_delayed_work(sdio_mux_workqueue,
-					&delayed_work_sdio_mux_write,
-					msecs_to_jiffies(250)
-					);
-		}
-	}
-
-	if (notify) {
-		spin_lock(&sdio_ch[ch_id].lock);
-		sdio_ch[ch_id].num_tx_pkts--;
-		spin_unlock(&sdio_ch[ch_id].lock);
-
-		if (sdio_ch[ch_id].write_done)
-			sdio_ch[ch_id].write_done(
-				sdio_ch[ch_id].priv, skb);
-		else
-			dev_kfree_skb_any(skb);
-	}
-	spin_unlock_irqrestore(&sdio_mux_write_lock, flags);
-}
-
-int msm_sdio_is_channel_in_reset(uint32_t id)
-{
-	int rc = 0;
-
-	if (id >= SDIO_DMUX_NUM_CHANNELS)
-		return -EINVAL;
-
-	if (sdio_ch_is_in_reset(id))
-		rc = 1;
-
-	return rc;
-}
-
-int msm_sdio_dmux_write(uint32_t id, struct sk_buff *skb)
-{
-	int rc = 0;
-	struct sdio_mux_hdr *hdr;
-	unsigned long flags;
-	struct sk_buff *new_skb;
-
-	if (id >= SDIO_DMUX_NUM_CHANNELS)
-		return -EINVAL;
-	if (!skb)
-		return -EINVAL;
-	if (!sdio_mux_initialized)
-		return -ENODEV;
-	if (fatal_error)
-		return -ENODEV;
-
-	DBG("%s: writing to ch %d len %d\n", __func__, id, skb->len);
-	spin_lock_irqsave(&sdio_ch[id].lock, flags);
-	if (sdio_ch_is_in_reset(id)) {
-		spin_unlock_irqrestore(&sdio_ch[id].lock, flags);
-		pr_err("%s: port is in reset: %d\n", __func__,
-				sdio_ch[id].status);
-		return -ENETRESET;
-	}
-	if (!sdio_ch_is_local_open(id)) {
-		spin_unlock_irqrestore(&sdio_ch[id].lock, flags);
-		pr_err("%s: port not open: %d\n", __func__, sdio_ch[id].status);
-		return -ENODEV;
-	}
-	if (sdio_ch[id].use_wm &&
-			(sdio_ch[id].num_tx_pkts >= HIGH_WATERMARK)) {
-		spin_unlock_irqrestore(&sdio_ch[id].lock, flags);
-		pr_err("%s: watermark exceeded: %d\n", __func__, id);
-		return -EAGAIN;
-	}
-	spin_unlock_irqrestore(&sdio_ch[id].lock, flags);
-
-	spin_lock_irqsave(&sdio_mux_write_lock, flags);
-	/* if skb do not have any tailroom for padding,
-	   copy the skb into a new expanded skb */
-	if ((skb->len & 0x3) && (skb_tailroom(skb) < (4 - (skb->len & 0x3)))) {
-		/* revisit, probably dev_alloc_skb and memcpy is effecient */
-		new_skb = skb_copy_expand(skb, skb_headroom(skb),
-					  4 - (skb->len & 0x3), GFP_ATOMIC);
-		if (new_skb == NULL) {
-			pr_err("%s: cannot allocate skb\n", __func__);
-			rc = -ENOMEM;
-			goto write_done;
-		}
-		dev_kfree_skb_any(skb);
-		skb = new_skb;
-		DBG_INC_WRITE_CPY(skb->len);
-	}
-
-	hdr = (struct sdio_mux_hdr *)skb_push(skb, sizeof(struct sdio_mux_hdr));
-
-	/* caller should allocate for hdr and padding
-	   hdr is fine, padding is tricky */
-	hdr->magic_num = SDIO_MUX_HDR_MAGIC_NO;
-	hdr->cmd = SDIO_MUX_HDR_CMD_DATA;
-	hdr->reserved = 0;
-	hdr->ch_id = id;
-	hdr->pkt_len = skb->len - sizeof(struct sdio_mux_hdr);
-	if (skb->len & 0x3)
-		skb_put(skb, 4 - (skb->len & 0x3));
-
-	hdr->pad_len = skb->len - (sizeof(struct sdio_mux_hdr) + hdr->pkt_len);
-
-	DBG("%s: data %p, tail %p skb len %d pkt len %d pad len %d\n",
-	    __func__, skb->data, skb->tail, skb->len,
-	    hdr->pkt_len, hdr->pad_len);
-	__skb_queue_tail(&sdio_mux_write_pool, skb);
-
-	spin_lock(&sdio_ch[id].lock);
-	sdio_ch[id].num_tx_pkts++;
-	spin_unlock(&sdio_ch[id].lock);
-
-	queue_work(sdio_mux_workqueue, &work_sdio_mux_write);
-
-write_done:
-	spin_unlock_irqrestore(&sdio_mux_write_lock, flags);
-	return rc;
-}
-
-int msm_sdio_dmux_open(uint32_t id, void *priv,
-			void (*receive_cb)(void *, struct sk_buff *),
-			void (*write_done)(void *, struct sk_buff *))
-{
-	unsigned long flags;
-
-	DBG("%s: opening ch %d\n", __func__, id);
-	if (!sdio_mux_initialized)
-		return -ENODEV;
-	if (id >= SDIO_DMUX_NUM_CHANNELS)
-		return -EINVAL;
-
-	spin_lock_irqsave(&sdio_ch[id].lock, flags);
-	if (sdio_ch_is_local_open(id)) {
-		pr_info("%s: Already opened %d\n", __func__, id);
-		spin_unlock_irqrestore(&sdio_ch[id].lock, flags);
-		goto open_done;
-	}
-
-	sdio_ch[id].receive_cb = receive_cb;
-	sdio_ch[id].write_done = write_done;
-	sdio_ch[id].priv = priv;
-	sdio_ch[id].status |= SDIO_CH_LOCAL_OPEN;
-	sdio_ch[id].num_tx_pkts = 0;
-	sdio_ch[id].use_wm = 0;
-	spin_unlock_irqrestore(&sdio_ch[id].lock, flags);
-
-	sdio_mux_send_open_cmd(id);
-
-open_done:
-	pr_info("%s: opened ch %d\n", __func__, id);
-	return 0;
-}
-
-int msm_sdio_dmux_close(uint32_t id)
-{
-	struct sdio_mux_hdr hdr;
-	unsigned long flags;
-
-	if (id >= SDIO_DMUX_NUM_CHANNELS)
-		return -EINVAL;
-	DBG("%s: closing ch %d\n", __func__, id);
-	if (!sdio_mux_initialized)
-		return -ENODEV;
-	spin_lock_irqsave(&sdio_ch[id].lock, flags);
-
-	sdio_ch[id].receive_cb = NULL;
-	sdio_ch[id].priv = NULL;
-	sdio_ch[id].status &= ~SDIO_CH_LOCAL_OPEN;
-	sdio_ch[id].status &= ~SDIO_CH_IN_RESET;
-	spin_unlock_irqrestore(&sdio_ch[id].lock, flags);
-
-	hdr.magic_num = SDIO_MUX_HDR_MAGIC_NO;
-	hdr.cmd = SDIO_MUX_HDR_CMD_CLOSE;
-	hdr.reserved = 0;
-	hdr.ch_id = id;
-	hdr.pkt_len = 0;
-	hdr.pad_len = 0;
-
-	sdio_mux_write_cmd((void *)&hdr, sizeof(hdr));
-
-	pr_info("%s: closed ch %d\n", __func__, id);
-	return 0;
-}
-
-static void sdio_mux_notify(void *_dev, unsigned event)
-{
-	DBG("%s: event %d notified\n", __func__, event);
-
-	/* write avail may not be enouogh for a packet, but should be fine */
-	if ((event == SDIO_EVENT_DATA_WRITE_AVAIL) &&
-	    sdio_write_avail(sdio_mux_ch))
-		queue_work(sdio_mux_workqueue, &work_sdio_mux_write);
-
-	if ((event == SDIO_EVENT_DATA_READ_AVAIL) &&
-	    sdio_read_avail(sdio_mux_ch))
-		queue_work(sdio_mux_workqueue, &work_sdio_mux_read);
-}
-
-int msm_sdio_dmux_is_ch_full(uint32_t id)
-{
-	unsigned long flags;
-	int ret;
-
-	if (id >= SDIO_DMUX_NUM_CHANNELS)
-		return -EINVAL;
-
-	spin_lock_irqsave(&sdio_ch[id].lock, flags);
-	sdio_ch[id].use_wm = 1;
-	ret = sdio_ch[id].num_tx_pkts >= HIGH_WATERMARK;
-	DBG("%s: ch %d num tx pkts=%d, HWM=%d\n", __func__,
-			id, sdio_ch[id].num_tx_pkts, ret);
-	if (!sdio_ch_is_local_open(id)) {
-		ret = -ENODEV;
-		pr_err("%s: port not open: %d\n", __func__, sdio_ch[id].status);
-	}
-	spin_unlock_irqrestore(&sdio_ch[id].lock, flags);
-
-	return ret;
-}
-
-int msm_sdio_dmux_is_ch_low(uint32_t id)
-{
-	int ret;
-
-	if (id >= SDIO_DMUX_NUM_CHANNELS)
-		return -EINVAL;
-
-	sdio_ch[id].use_wm = 1;
-	ret = sdio_ch[id].num_tx_pkts <= LOW_WATERMARK;
-	DBG("%s: ch %d num tx pkts=%d, LWM=%d\n", __func__,
-			id, sdio_ch[id].num_tx_pkts, ret);
-	if (!sdio_ch_is_local_open(id)) {
-		ret = -ENODEV;
-		pr_err("%s: port not open: %d\n", __func__, sdio_ch[id].status);
-	}
-
-	return ret;
-}
-
-#ifdef CONFIG_DEBUG_FS
-
-static int debug_tbl(char *buf, int max)
-{
-	int i = 0;
-	int j;
-
-	for (j = 0; j < SDIO_DMUX_NUM_CHANNELS; ++j) {
-		i += scnprintf(buf + i, max - i,
-			"ch%02d  local open=%s  remote open=%s\n",
-			j, sdio_ch_is_local_open(j) ? "Y" : "N",
-			sdio_ch_is_remote_open(j) ? "Y" : "N");
-	}
-
-	return i;
-}
-
-#define DEBUG_BUFMAX 4096
-static char debug_buffer[DEBUG_BUFMAX];
-
-static ssize_t debug_read(struct file *file, char __user *buf,
-				size_t count, loff_t *ppos)
-{
-	int (*fill)(char *buf, int max) = file->private_data;
-	int bsize = fill(debug_buffer, DEBUG_BUFMAX);
-	return simple_read_from_buffer(buf, count, ppos, debug_buffer, bsize);
-}
-
-static int debug_open(struct inode *inode, struct file *file)
-{
-	file->private_data = inode->i_private;
-	return 0;
-}
-
-
-static const struct file_operations debug_ops = {
-	.read = debug_read,
-	.open = debug_open,
-};
-
-static void debug_create(const char *name, mode_t mode,
-				struct dentry *dent,
-				int (*fill)(char *buf, int max))
-{
-	debugfs_create_file(name, mode, dent, fill, &debug_ops);
-}
-
-#endif
-
-static int sdio_dmux_probe(struct platform_device *pdev)
-{
-	int rc;
-
-	DBG("%s probe called\n", __func__);
-
-	if (!sdio_mux_initialized) {
-		sdio_mux_workqueue = create_singlethread_workqueue("sdio_dmux");
-		if (!sdio_mux_workqueue)
-			return -ENOMEM;
-
-		skb_queue_head_init(&sdio_mux_write_pool);
-		spin_lock_init(&sdio_mux_write_lock);
-
-		for (rc = 0; rc < SDIO_DMUX_NUM_CHANNELS; ++rc)
-			spin_lock_init(&sdio_ch[rc].lock);
-
-
-		wake_lock_init(&sdio_mux_ch_wakelock, WAKE_LOCK_SUSPEND,
-				   "sdio_dmux");
-	}
-
-	rc = sdio_open("SDIO_RMNT", &sdio_mux_ch, NULL, sdio_mux_notify);
-	if (rc < 0) {
-		pr_err("%s: sido open failed %d\n", __func__, rc);
-		wake_lock_destroy(&sdio_mux_ch_wakelock);
-		destroy_workqueue(sdio_mux_workqueue);
-		sdio_mux_initialized = 0;
-		return rc;
-	}
-
-	fatal_error = 0;
-	sdio_mux_initialized = 1;
-	return 0;
-}
-
-static int sdio_dmux_remove(struct platform_device *pdev)
-{
-	int i;
-	unsigned long ch_lock_flags;
-	unsigned long write_lock_flags;
-	struct sk_buff *skb;
-
-	DBG("%s remove called\n", __func__);
-	if (!sdio_mux_initialized)
-		return 0;
-
-	/* set reset state for any open channels */
-	for (i = 0; i < SDIO_DMUX_NUM_CHANNELS; ++i) {
-		spin_lock_irqsave(&sdio_ch[i].lock, ch_lock_flags);
-		if (sdio_ch_is_open(i)) {
-			sdio_ch[i].status |= SDIO_CH_IN_RESET;
-			sdio_ch[i].status &= ~SDIO_CH_REMOTE_OPEN;
-
-			/* notify client so it can update its status */
-			if (sdio_ch[i].receive_cb)
-				sdio_ch[i].receive_cb(
-						sdio_ch[i].priv, NULL);
-		}
-		spin_unlock_irqrestore(&sdio_ch[i].lock, ch_lock_flags);
-	}
-
-	/* cancel any pending writes */
-	spin_lock_irqsave(&sdio_mux_write_lock, write_lock_flags);
-	while ((skb = __skb_dequeue(&sdio_mux_write_pool))) {
-		i = ((struct sdio_mux_hdr *)skb->data)->ch_id;
-		if (sdio_ch[i].write_done)
-			sdio_ch[i].write_done(
-					sdio_ch[i].priv, skb);
-		else
-			dev_kfree_skb_any(skb);
-	}
-	spin_unlock_irqrestore(&sdio_mux_write_lock,
-			write_lock_flags);
-
-	return 0;
-}
-
-static struct platform_driver sdio_dmux_driver = {
-	.probe		= sdio_dmux_probe,
-	.remove   = sdio_dmux_remove,
-	.driver		= {
-		.name	= "SDIO_RMNT",
-		.owner	= THIS_MODULE,
-	},
-};
-
-static int __init sdio_dmux_init(void)
-{
-#ifdef CONFIG_DEBUG_FS
-	struct dentry *dent;
-
-	dent = debugfs_create_dir("sdio_dmux", 0);
-	if (!IS_ERR(dent))
-		debug_create("tbl", 0444, dent, debug_tbl);
-#endif
-	return platform_driver_register(&sdio_dmux_driver);
-}
-
-module_init(sdio_dmux_init);
-MODULE_DESCRIPTION("MSM SDIO DMUX");
-MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/sdio_smem.c b/arch/arm/mach-msm/sdio_smem.c
deleted file mode 100644
index edc0d23..0000000
--- a/arch/arm/mach-msm/sdio_smem.c
+++ /dev/null
@@ -1,175 +0,0 @@
-/* Copyright (c) 2010-2011, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
-
-#define pr_fmt(fmt) "%s: " fmt, __func__
-
-#include <linux/sched.h>
-#include <linux/wait.h>
-#include <linux/workqueue.h>
-#include <linux/module.h>
-#include <mach/sdio_al.h>
-#include <mach/sdio_smem.h>
-
-static void sdio_smem_read(struct work_struct *work);
-
-static struct sdio_channel *channel;
-static struct workqueue_struct *workq;
-static DECLARE_WORK(work_read, sdio_smem_read);
-static DECLARE_WAIT_QUEUE_HEAD(waitq);
-static int bytes_avail;
-static int sdio_ch_opened;
-
-static void sdio_smem_release(struct device *dev)
-{
-	pr_debug("sdio smem released\n");
-}
-
-static struct sdio_smem_client client;
-
-static void sdio_smem_read(struct work_struct *work)
-{
-	int err;
-	int read_avail;
-	char *data = client.buf;
-
-	if (!sdio_ch_opened)
-		return;
-
-	read_avail = sdio_read_avail(channel);
-	if (read_avail > bytes_avail ||
-		read_avail < 0) {
-		pr_err("Error: read_avail=%d bytes_avail=%d\n",
-			read_avail, bytes_avail);
-		goto read_err;
-	}
-
-	if (read_avail == 0)
-		return;
-
-	err = sdio_read(channel,
-			&data[client.size - bytes_avail],
-			read_avail);
-	if (err) {
-		pr_err("sdio_read error (%d)", err);
-		goto read_err;
-	}
-
-	bytes_avail -= read_avail;
-	pr_debug("read %d bytes (bytes_avail = %d)\n",
-			read_avail, bytes_avail);
-
-	if (!bytes_avail) {
-		bytes_avail = client.size;
-		err = client.cb_func(SDIO_SMEM_EVENT_READ_DONE);
-	}
-	if (err)
-		pr_err("error (%d) on callback\n", err);
-
-	return;
-
-read_err:
-	if (sdio_ch_opened)
-		client.cb_func(SDIO_SMEM_EVENT_READ_ERR);
-	return;
-}
-
-static void sdio_smem_notify(void *priv, unsigned event)
-{
-	pr_debug("%d event received\n", event);
-
-	if (event == SDIO_EVENT_DATA_READ_AVAIL ||
-	    event == SDIO_EVENT_DATA_WRITE_AVAIL)
-		queue_work(workq, &work_read);
-}
-
-int sdio_smem_register_client(void)
-{
-	int err = 0;
-
-	if (!client.buf || !client.size || !client.cb_func)
-		return -EINVAL;
-
-	pr_debug("buf = %p\n", client.buf);
-	pr_debug("size = 0x%x\n", client.size);
-
-	bytes_avail = client.size;
-	workq = create_singlethread_workqueue("sdio_smem");
-	if (!workq)
-		return -ENOMEM;
-
-	sdio_ch_opened = 1;
-	err = sdio_open("SDIO_SMEM", &channel, NULL, sdio_smem_notify);
-	if (err) {
-		sdio_ch_opened = 0;
-		pr_err("sdio_open error (%d)\n", err);
-		destroy_workqueue(workq);
-		return err;
-	}
-	pr_debug("SDIO SMEM channel opened\n");
-	return err;
-}
-
-int sdio_smem_unregister_client(void)
-{
-	int err = 0;
-
-	sdio_ch_opened = 0;
-	err = sdio_close(channel);
-	if (err) {
-		pr_err("sdio_close error (%d)\n", err);
-		return err;
-	}
-	pr_debug("SDIO SMEM channel closed\n");
-	flush_workqueue(workq);
-	destroy_workqueue(workq);
-	bytes_avail = 0;
-	client.buf = NULL;
-	client.cb_func = NULL;
-	client.size = 0;
-
-	return 0;
-}
-
-static int sdio_smem_probe(struct platform_device *pdev)
-{
-	client.plat_dev.name = "SDIO_SMEM_CLIENT";
-	client.plat_dev.id = -1;
-	client.plat_dev.dev.release = sdio_smem_release;
-
-	return platform_device_register(&client.plat_dev);
-}
-
-static int sdio_smem_remove(struct platform_device *pdev)
-{
-	platform_device_unregister(&client.plat_dev);
-	memset(&client, 0, sizeof(client));
-	sdio_ch_opened = 0;
-	return 0;
-}
-static struct platform_driver sdio_smem_drv = {
-	.probe		= sdio_smem_probe,
-	.remove		= sdio_smem_remove,
-	.driver		= {
-		.name	= "SDIO_SMEM",
-		.owner	= THIS_MODULE,
-	},
-};
-
-static int __init sdio_smem_init(void)
-{
-	return platform_driver_register(&sdio_smem_drv);
-};
-
-module_init(sdio_smem_init);
-
-MODULE_DESCRIPTION("SDIO SMEM");
-MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/sdio_tty.c b/arch/arm/mach-msm/sdio_tty.c
deleted file mode 100644
index c4b7673..0000000
--- a/arch/arm/mach-msm/sdio_tty.c
+++ /dev/null
@@ -1,824 +0,0 @@
-/* Copyright (c) 2011, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
-
-#include <linux/slab.h>
-#include <linux/sched.h>
-#include <linux/wait.h>
-#include <linux/workqueue.h>
-#include <linux/platform_device.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/module.h>
-#include <linux/debugfs.h>
-#include <mach/sdio_al.h>
-
-#define INPUT_SPEED			4800
-#define OUTPUT_SPEED			4800
-#define SDIO_TTY_MODULE_NAME		"sdio_tty"
-#define SDIO_TTY_MAX_PACKET_SIZE	4096
-#define MAX_SDIO_TTY_DRV		1
-#define MAX_SDIO_TTY_DEVS		2
-#define MAX_SDIO_TTY_DEV_NAME_SIZE	25
-
-/* Configurations per channel device */
-/* CSVT */
-#define SDIO_TTY_CSVT_DEV		"sdio_tty_csvt_0"
-#define SDIO_TTY_CSVT_TEST_DEV		"sdio_tty_csvt_test_0"
-#define SDIO_TTY_CH_CSVT		"SDIO_CSVT"
-
-enum sdio_tty_state {
-	TTY_INITIAL = 0,
-	TTY_REGISTERED = 1,
-	TTY_OPENED = 2,
-	TTY_CLOSED = 3,
-};
-
-enum sdio_tty_devices {
-	SDIO_CSVT,
-	SDIO_CSVT_TEST_APP,
-};
-
-static const struct platform_device_id sdio_tty_id_table[] = {
-	{ "SDIO_CSVT",		SDIO_CSVT },
-	{ "SDIO_CSVT_TEST_APP",	SDIO_CSVT_TEST_APP },
-	{ },
-};
-MODULE_DEVICE_TABLE(platform, sdio_tty_id_table);
-
-struct sdio_tty {
-	struct sdio_channel *ch;
-	char *sdio_ch_name;
-	char tty_dev_name[MAX_SDIO_TTY_DEV_NAME_SIZE];
-	int device_id;
-	struct workqueue_struct *workq;
-	struct work_struct work_read;
-	wait_queue_head_t   waitq;
-	struct tty_driver *tty_drv;
-	struct tty_struct *tty_str;
-	int debug_msg_on;
-	char *read_buf;
-	enum sdio_tty_state sdio_tty_state;
-	int is_sdio_open;
-	int tty_open_count;
-	int total_rx;
-	int total_tx;
-};
-
-static struct sdio_tty *sdio_tty[MAX_SDIO_TTY_DEVS];
-
-#ifdef CONFIG_DEBUG_FS
-struct dentry *sdio_tty_debug_root;
-struct dentry *sdio_tty_debug_info;
-#endif
-
-#define DEBUG_MSG(sdio_tty_drv, x...) if (sdio_tty_drv->debug_msg_on) pr_info(x)
-
-/*
- * Enable sdio_tty debug messages
- * By default the sdio_tty debug messages are turned off
- */
-static int csvt_debug_msg_on;
-module_param(csvt_debug_msg_on, int, 0);
-
-static void sdio_tty_read(struct work_struct *work)
-{
-	int ret = 0;
-	int read_avail = 0;
-	int left = 0;
-	int total_push = 0;
-	int num_push = 0;
-	struct sdio_tty *sdio_tty_drv = NULL;
-
-	sdio_tty_drv = container_of(work, struct sdio_tty, work_read);
-
-	if (!sdio_tty_drv) {
-		pr_err(SDIO_TTY_MODULE_NAME ": %s: NULL sdio_tty", __func__);
-		return ;
-	}
-
-	if (sdio_tty_drv->sdio_tty_state != TTY_OPENED) {
-		pr_err(SDIO_TTY_MODULE_NAME ": %s: sdio_tty_state = %d",
-			__func__, sdio_tty_drv->sdio_tty_state);
-		return;
-	}
-
-	if (!sdio_tty_drv->read_buf) {
-		pr_err(SDIO_TTY_MODULE_NAME ": %s: NULL read_buf for dev %s",
-			__func__, sdio_tty_drv->tty_dev_name);
-		return;
-	}
-
-	/* Read the data from the SDIO channel as long as there is available
-	   data */
-	while (1) {
-		if (test_bit(TTY_THROTTLED, &sdio_tty_drv->tty_str->flags)) {
-			DEBUG_MSG(sdio_tty_drv, SDIO_TTY_MODULE_NAME
-					": %s: TTY_THROTTLED bit is set for "
-					"dev %s, exit", __func__,
-					sdio_tty_drv->tty_dev_name);
-			return;
-		}
-
-		total_push = 0;
-		read_avail = sdio_read_avail(sdio_tty_drv->ch);
-
-		DEBUG_MSG(sdio_tty_drv, SDIO_TTY_MODULE_NAME
-				": %s: read_avail is %d for dev %s", __func__,
-				read_avail, sdio_tty_drv->tty_dev_name);
-
-		if (read_avail == 0) {
-			DEBUG_MSG(sdio_tty_drv, SDIO_TTY_MODULE_NAME
-					": %s: read_avail is 0 for dev %s",
-					__func__, sdio_tty_drv->tty_dev_name);
-			return;
-		}
-
-		if (read_avail > SDIO_TTY_MAX_PACKET_SIZE) {
-			pr_err(SDIO_TTY_MODULE_NAME ": %s: read_avail(%d) is "
-				"bigger than SDIO_TTY_MAX_PACKET_SIZE(%d) "
-				"for dev %s", __func__, read_avail,
-				SDIO_TTY_MAX_PACKET_SIZE,
-				sdio_tty_drv->tty_dev_name);
-			return;
-		}
-
-		ret = sdio_read(sdio_tty_drv->ch,
-				sdio_tty_drv->read_buf,
-				read_avail);
-		if (ret < 0) {
-			pr_err(SDIO_TTY_MODULE_NAME ": %s: sdio_read error(%d) "
-				"for dev %s", __func__, ret,
-				sdio_tty_drv->tty_dev_name);
-			return;
-		}
-
-		left = read_avail;
-		do {
-			num_push = tty_insert_flip_string(
-				sdio_tty_drv->tty_str,
-				sdio_tty_drv->read_buf+total_push,
-				left);
-			total_push += num_push;
-			left -= num_push;
-			tty_flip_buffer_push(sdio_tty_drv->tty_str);
-		} while (left != 0);
-
-		if (total_push != read_avail) {
-			pr_err(SDIO_TTY_MODULE_NAME ": %s: failed, total_push"
-				"(%d) != read_avail(%d) for dev %s\n",
-				__func__, total_push, read_avail,
-				sdio_tty_drv->tty_dev_name);
-		}
-
-		tty_flip_buffer_push(sdio_tty_drv->tty_str);
-		sdio_tty_drv->total_rx += read_avail;
-
-		DEBUG_MSG(sdio_tty_drv, SDIO_TTY_MODULE_NAME ": %s: Rx: %d, "
-				"Total Rx = %d bytes for dev %s", __func__,
-				read_avail, sdio_tty_drv->total_rx,
-				sdio_tty_drv->tty_dev_name);
-	}
-}
-
-/**
-  * sdio_tty_write_room
-  *
-  * This is the write_room function of the tty driver.
-  *
-  * @tty: pointer to tty struct.
-  * @return free bytes for write.
-  *
-  */
-static int sdio_tty_write_room(struct tty_struct *tty)
-{
-	int write_avail = 0;
-	struct sdio_tty *sdio_tty_drv = NULL;
-
-	if (!tty) {
-		pr_err(SDIO_TTY_MODULE_NAME ": %s: NULL tty", __func__);
-		return -ENODEV;
-	}
-	sdio_tty_drv = tty->driver_data;
-	if (!sdio_tty_drv) {
-		pr_err(SDIO_TTY_MODULE_NAME ": %s: NULL sdio_tty_drv",
-			__func__);
-		return -ENODEV;
-	}
-
-	if (sdio_tty_drv->sdio_tty_state != TTY_OPENED) {
-		pr_err(SDIO_TTY_MODULE_NAME ": %s: sdio_tty_state = %d",
-			__func__, sdio_tty_drv->sdio_tty_state);
-		return -EPERM;
-	}
-
-	write_avail = sdio_write_avail(sdio_tty_drv->ch);
-	DEBUG_MSG(sdio_tty_drv, SDIO_TTY_MODULE_NAME ": %s: write_avail=%d "
-			"for dev %s", __func__, write_avail,
-			sdio_tty_drv->tty_dev_name);
-
-	return write_avail;
-}
-
-/**
-  * sdio_tty_write_callback
-  * this is the write callback of the tty driver.
-  *
-  * @tty: pointer to tty struct.
-  * @buf: buffer to write from.
-  * @count: number of bytes to write.
-  * @return bytes written or negative value on error.
-  *
-  * if destination buffer has not enough room for the incoming
-  * data, writes the possible amount of bytes .
-  */
-static int sdio_tty_write_callback(struct tty_struct *tty,
-				   const unsigned char *buf, int count)
-{
-	int write_avail = 0;
-	int len = count;
-	int ret = 0;
-	struct sdio_tty *sdio_tty_drv = NULL;
-
-	if (!tty) {
-		pr_err(SDIO_TTY_MODULE_NAME ": %s: NULL tty", __func__);
-		return -ENODEV;
-	}
-	sdio_tty_drv = tty->driver_data;
-	if (!sdio_tty_drv) {
-		pr_err(SDIO_TTY_MODULE_NAME ": %s: NULL sdio_tty_drv",
-			__func__);
-		return -ENODEV;
-	}
-
-	if (sdio_tty_drv->sdio_tty_state != TTY_OPENED) {
-		pr_err(SDIO_TTY_MODULE_NAME ": %s: sdio_tty_state = %d",
-			__func__, sdio_tty_drv->sdio_tty_state);
-		return -EPERM;
-	}
-
-	DEBUG_MSG(sdio_tty_drv, SDIO_TTY_MODULE_NAME ": %s: Write Callback "
-			"called with %d bytes for dev %s\n", __func__, count,
-			sdio_tty_drv->tty_dev_name);
-	write_avail = sdio_write_avail(sdio_tty_drv->ch);
-	if (write_avail == 0) {
-		DEBUG_MSG(sdio_tty_drv, SDIO_TTY_MODULE_NAME ": %s: "
-				"write_avail is 0 for dev %s\n",
-				__func__, sdio_tty_drv->tty_dev_name);
-		return 0;
-	}
-	if (write_avail > SDIO_TTY_MAX_PACKET_SIZE) {
-		DEBUG_MSG(sdio_tty_drv, SDIO_TTY_MODULE_NAME ": %s: "
-				"write_avail(%d) is bigger than max packet "
-				"size(%d) for dev %s, setting to "
-				"max_packet_size\n", __func__, write_avail,
-				SDIO_TTY_MAX_PACKET_SIZE,
-				sdio_tty_drv->tty_dev_name);
-		write_avail = SDIO_TTY_MAX_PACKET_SIZE;
-	}
-	if (write_avail < count) {
-		DEBUG_MSG(sdio_tty_drv, SDIO_TTY_MODULE_NAME ": %s: "
-				"write_avail(%d) is smaller than required(%d) "
-				"for dev %s, writing only %d bytes\n",
-				__func__, write_avail, count,
-				sdio_tty_drv->tty_dev_name, write_avail);
-		len = write_avail;
-	}
-	ret = sdio_write(sdio_tty_drv->ch, buf, len);
-	if (ret) {
-		pr_err(SDIO_TTY_MODULE_NAME ": %s: sdio_write failed for "
-			"dev %s, ret=%d\n", __func__,
-			sdio_tty_drv->tty_dev_name, ret);
-		return 0;
-	}
-
-	sdio_tty_drv->total_tx += len;
-
-	DEBUG_MSG(sdio_tty_drv, SDIO_TTY_MODULE_NAME ": %s: Tx: %d, "
-			"Total Tx = %d for dev %s", __func__, len,
-			sdio_tty_drv->total_tx, sdio_tty_drv->tty_dev_name);
-	return len;
-}
-
-static void sdio_tty_notify(void *priv, unsigned event)
-{
-	struct sdio_tty *sdio_tty_drv = priv;
-
-	if (!sdio_tty_drv) {
-		pr_err(SDIO_TTY_MODULE_NAME ": %s: NULL sdio_tty_drv",
-			__func__);
-	}
-
-	if (sdio_tty_drv->sdio_tty_state != TTY_OPENED) {
-		pr_err(SDIO_TTY_MODULE_NAME ": %s: sdio_tty_state = %d",
-			__func__, sdio_tty_drv->sdio_tty_state);
-		return;
-	}
-
-	DEBUG_MSG(sdio_tty_drv, SDIO_TTY_MODULE_NAME ": %s: event %d "
-			"received for dev %s\n", __func__, event,
-			sdio_tty_drv->tty_dev_name);
-
-	if (event == SDIO_EVENT_DATA_READ_AVAIL)
-		queue_work(sdio_tty_drv->workq, &sdio_tty_drv->work_read);
-}
-
-/**
-  * sdio_tty_open
-  * This is the open callback of the tty driver. it opens
-  * the sdio channel, and creates the workqueue.
-  *
-  * @tty: a pointer to the tty struct.
-  * @file: file descriptor.
-  * @return 0 on success or negative value on error.
-  */
-static int sdio_tty_open(struct tty_struct *tty, struct file *file)
-{
-	int ret = 0;
-	int i = 0;
-	struct sdio_tty *sdio_tty_drv = NULL;
-
-	if (!tty) {
-		pr_err(SDIO_TTY_MODULE_NAME ": %s: NULL tty", __func__);
-		return -ENODEV;
-	}
-
-	for (i = 0; i < MAX_SDIO_TTY_DEVS; i++) {
-		if (sdio_tty[i] == NULL)
-			continue;
-		if (!strncmp(sdio_tty[i]->tty_dev_name, tty->name,
-				MAX_SDIO_TTY_DEV_NAME_SIZE)) {
-			sdio_tty_drv = sdio_tty[i];
-			break;
-		}
-	}
-
-	if (!sdio_tty_drv) {
-		pr_err(SDIO_TTY_MODULE_NAME ": %s: NULL sdio_tty_drv",
-		       __func__);
-		return -ENODEV;
-	}
-
-	sdio_tty_drv->tty_open_count++;
-	if (sdio_tty_drv->sdio_tty_state == TTY_OPENED) {
-		pr_err(SDIO_TTY_MODULE_NAME ": %s: tty dev(%s) is already open",
-			__func__, sdio_tty_drv->tty_dev_name);
-		return -EBUSY;
-	}
-
-	tty->driver_data = sdio_tty_drv;
-
-	sdio_tty_drv->tty_str = tty;
-	sdio_tty_drv->tty_str->low_latency = 1;
-	sdio_tty_drv->tty_str->icanon = 0;
-	set_bit(TTY_NO_WRITE_SPLIT, &sdio_tty_drv->tty_str->flags);
-
-	sdio_tty_drv->read_buf = kzalloc(SDIO_TTY_MAX_PACKET_SIZE, GFP_KERNEL);
-	if (sdio_tty_drv->read_buf == NULL) {
-		pr_err(SDIO_TTY_MODULE_NAME ": %s: failed to allocate read_buf "
-			"for dev %s", __func__, sdio_tty_drv->tty_dev_name);
-		return -ENOMEM;
-	}
-
-	sdio_tty_drv->workq = create_singlethread_workqueue("sdio_tty_read");
-	if (!sdio_tty_drv->workq) {
-		pr_err(SDIO_TTY_MODULE_NAME ": %s: failed to create workq "
-			"for dev %s", __func__, sdio_tty_drv->tty_dev_name);
-		return -ENOMEM;
-	}
-
-	if (!sdio_tty_drv->is_sdio_open) {
-		ret = sdio_open(sdio_tty_drv->sdio_ch_name, &sdio_tty_drv->ch,
-				sdio_tty_drv, sdio_tty_notify);
-		if (ret < 0) {
-			pr_err(SDIO_TTY_MODULE_NAME ": %s: sdio_open err=%d "
-				"for dev %s\n", __func__, ret,
-				sdio_tty_drv->tty_dev_name);
-			destroy_workqueue(sdio_tty_drv->workq);
-			return ret;
-		}
-
-		pr_info(SDIO_TTY_MODULE_NAME ": %s: SDIO_TTY channel(%s) "
-			"opened\n", __func__, sdio_tty_drv->sdio_ch_name);
-
-		sdio_tty_drv->is_sdio_open = 1;
-	} else {
-		/* If SDIO channel is already open try to read the data
-		 * from the modem
-		 */
-		queue_work(sdio_tty_drv->workq, &sdio_tty_drv->work_read);
-
-	}
-
-	sdio_tty_drv->sdio_tty_state = TTY_OPENED;
-
-	pr_info(SDIO_TTY_MODULE_NAME ": %s: TTY device(%s) opened\n",
-		__func__, sdio_tty_drv->tty_dev_name);
-
-	return ret;
-}
-
-/**
-  * sdio_tty_close
-  * This is the close callback of the tty driver. it requests
-  * the main thread to exit, and waits for notification of it.
-  * it also de-allocates the buffers, and unregisters the tty
-  * driver and device.
-  *
-  * @tty: a pointer to the tty struct.
-  * @file: file descriptor.
-  * @return None.
-  */
-static void sdio_tty_close(struct tty_struct *tty, struct file *file)
-{
-	struct sdio_tty *sdio_tty_drv = NULL;
-
-	if (!tty) {
-		pr_err(SDIO_TTY_MODULE_NAME ": %s: NULL tty", __func__);
-		return;
-	}
-	sdio_tty_drv = tty->driver_data;
-	if (!sdio_tty_drv) {
-		pr_err(SDIO_TTY_MODULE_NAME ": %s: NULL sdio_tty_drv",
-		       __func__);
-		return;
-	}
-	if (sdio_tty_drv->sdio_tty_state != TTY_OPENED) {
-		pr_err(SDIO_TTY_MODULE_NAME ": %s: trying to close a "
-			"TTY device that was not opened\n", __func__);
-		return;
-	}
-	if (--sdio_tty_drv->tty_open_count != 0)
-		return;
-
-	flush_workqueue(sdio_tty_drv->workq);
-	destroy_workqueue(sdio_tty_drv->workq);
-
-	kfree(sdio_tty_drv->read_buf);
-	sdio_tty_drv->read_buf = NULL;
-
-	sdio_tty_drv->sdio_tty_state = TTY_CLOSED;
-
-	pr_info(SDIO_TTY_MODULE_NAME ": %s: SDIO_TTY device(%s) closed\n",
-		__func__, sdio_tty_drv->tty_dev_name);
-}
-
-static void sdio_tty_unthrottle(struct tty_struct *tty)
-{
-	struct sdio_tty *sdio_tty_drv = NULL;
-
-	if (!tty) {
-		pr_err(SDIO_TTY_MODULE_NAME ": %s: NULL tty", __func__);
-		return;
-	}
-	sdio_tty_drv = tty->driver_data;
-	if (!sdio_tty_drv) {
-		pr_err(SDIO_TTY_MODULE_NAME ": %s: NULL sdio_tty_drv",
-		       __func__);
-		return;
-	}
-
-	if (sdio_tty_drv->sdio_tty_state != TTY_OPENED) {
-		pr_err(SDIO_TTY_MODULE_NAME ": %s: sdio_tty_state = %d",
-		       __func__, sdio_tty_drv->sdio_tty_state);
-		return;
-	}
-
-	queue_work(sdio_tty_drv->workq, &sdio_tty_drv->work_read);
-	return;
-}
-
-static const struct tty_operations sdio_tty_ops = {
-	.open = sdio_tty_open,
-	.close = sdio_tty_close,
-	.write = sdio_tty_write_callback,
-	.write_room = sdio_tty_write_room,
-	.unthrottle = sdio_tty_unthrottle,
-};
-
-int sdio_tty_init_tty(char *tty_name, char *sdio_ch_name,
-			enum sdio_tty_devices device_id, int debug_msg_on)
-{
-	int ret = 0;
-	int i = 0;
-	struct device *tty_dev = NULL;
-	struct sdio_tty *sdio_tty_drv = NULL;
-
-	sdio_tty_drv = kzalloc(sizeof(struct sdio_tty), GFP_KERNEL);
-	if (sdio_tty_drv == NULL) {
-		pr_err(SDIO_TTY_MODULE_NAME ": %s: failed to allocate sdio_tty "
-			"for dev %s", __func__, tty_name);
-		return -ENOMEM;
-	}
-
-	for (i = 0; i < MAX_SDIO_TTY_DEVS; i++) {
-		if (sdio_tty[i] == NULL) {
-			sdio_tty[i] = sdio_tty_drv;
-			break;
-		}
-	}
-
-	if (i == MAX_SDIO_TTY_DEVS) {
-		pr_err(SDIO_TTY_MODULE_NAME ": %s: tty dev(%s) creation failed,"
-			" max limit(%d) reached.", __func__, tty_name,
-			MAX_SDIO_TTY_DEVS);
-		kfree(sdio_tty_drv);
-		return -ENODEV;
-	}
-
-	snprintf(sdio_tty_drv->tty_dev_name, MAX_SDIO_TTY_DEV_NAME_SIZE,
-			"%s%d", tty_name, 0);
-	sdio_tty_drv->sdio_ch_name = sdio_ch_name;
-	sdio_tty_drv->device_id = device_id;
-	pr_info(SDIO_TTY_MODULE_NAME ": %s: dev=%s, id=%d, channel=%s\n",
-		__func__, sdio_tty_drv->tty_dev_name, sdio_tty_drv->device_id,
-		sdio_tty_drv->sdio_ch_name);
-
-	INIT_WORK(&sdio_tty_drv->work_read, sdio_tty_read);
-
-	sdio_tty_drv->tty_drv = alloc_tty_driver(MAX_SDIO_TTY_DRV);
-
-	if (!sdio_tty_drv->tty_drv) {
-		pr_err(SDIO_TTY_MODULE_NAME ": %s - tty_drv is NULL for dev %s",
-			__func__, sdio_tty_drv->tty_dev_name);
-		kfree(sdio_tty_drv);
-		return -ENODEV;
-	}
-
-	sdio_tty_drv->tty_drv->name = tty_name;
-	sdio_tty_drv->tty_drv->owner = THIS_MODULE;
-	sdio_tty_drv->tty_drv->driver_name = "SDIO_tty";
-	/* uses dynamically assigned dev_t values */
-	sdio_tty_drv->tty_drv->type = TTY_DRIVER_TYPE_SERIAL;
-	sdio_tty_drv->tty_drv->subtype = SERIAL_TYPE_NORMAL;
-	sdio_tty_drv->tty_drv->flags = TTY_DRIVER_REAL_RAW
-		| TTY_DRIVER_DYNAMIC_DEV
-		| TTY_DRIVER_RESET_TERMIOS;
-
-	/* initializing the tty driver */
-	sdio_tty_drv->tty_drv->init_termios = tty_std_termios;
-	sdio_tty_drv->tty_drv->init_termios.c_cflag =
-		B4800 | CS8 | CREAD | HUPCL | CLOCAL;
-	sdio_tty_drv->tty_drv->init_termios.c_ispeed = INPUT_SPEED;
-	sdio_tty_drv->tty_drv->init_termios.c_ospeed = OUTPUT_SPEED;
-
-	tty_set_operations(sdio_tty_drv->tty_drv, &sdio_tty_ops);
-
-	ret = tty_register_driver(sdio_tty_drv->tty_drv);
-	if (ret) {
-		put_tty_driver(sdio_tty_drv->tty_drv);
-		pr_err(SDIO_TTY_MODULE_NAME ": %s: tty_register_driver() "
-			"failed for dev %s\n", __func__,
-			sdio_tty_drv->tty_dev_name);
-
-		sdio_tty_drv->tty_drv = NULL;
-		kfree(sdio_tty_drv);
-		return -ENODEV;
-	}
-
-	tty_dev = tty_register_device(sdio_tty_drv->tty_drv, 0, NULL);
-	if (IS_ERR(tty_dev)) {
-		pr_err(SDIO_TTY_MODULE_NAME ": %s: tty_register_device() "
-			"failed for dev %s\n", __func__,
-			sdio_tty_drv->tty_dev_name);
-		tty_unregister_driver(sdio_tty_drv->tty_drv);
-		put_tty_driver(sdio_tty_drv->tty_drv);
-		kfree(sdio_tty_drv);
-		return -ENODEV;
-	}
-
-	sdio_tty_drv->sdio_tty_state = TTY_REGISTERED;
-	if (debug_msg_on) {
-		pr_info(SDIO_TTY_MODULE_NAME ": %s: turn on debug msg for %s",
-			__func__, sdio_tty_drv->tty_dev_name);
-		sdio_tty_drv->debug_msg_on = debug_msg_on;
-	}
-	return 0;
-}
-
-int sdio_tty_uninit_tty(void *sdio_tty_handle)
-{
-	int ret = 0;
-	int i = 0;
-	struct sdio_tty *sdio_tty_drv = sdio_tty_handle;
-
-	if (!sdio_tty_drv) {
-		pr_err(SDIO_TTY_MODULE_NAME ": %s: NULL sdio_tty_drv",
-		       __func__);
-		return -ENODEV;
-	}
-	if (sdio_tty_drv->sdio_tty_state == TTY_OPENED) {
-		flush_workqueue(sdio_tty_drv->workq);
-		destroy_workqueue(sdio_tty_drv->workq);
-
-		kfree(sdio_tty_drv->read_buf);
-		sdio_tty_drv->read_buf = NULL;
-	}
-
-	if (sdio_tty_drv->sdio_tty_state != TTY_INITIAL) {
-		tty_unregister_device(sdio_tty_drv->tty_drv, 0);
-
-		ret = tty_unregister_driver(sdio_tty_drv->tty_drv);
-		if (ret) {
-			pr_err(SDIO_TTY_MODULE_NAME ": %s: "
-				"tty_unregister_driver() failed for dev %s\n",
-				__func__, sdio_tty_drv->tty_dev_name);
-		}
-		put_tty_driver(sdio_tty_drv->tty_drv);
-		sdio_tty_drv->sdio_tty_state = TTY_INITIAL;
-		sdio_tty_drv->tty_drv = NULL;
-	}
-
-	for (i = 0; i < MAX_SDIO_TTY_DEVS; i++) {
-		if (sdio_tty[i] == NULL)
-			continue;
-		if (sdio_tty[i]->device_id == sdio_tty_drv->device_id) {
-			sdio_tty[i] = NULL;
-			break;
-		}
-	}
-
-	DEBUG_MSG(sdio_tty_drv, SDIO_TTY_MODULE_NAME ": %s: Freeing sdio_tty "
-			"structure, dev=%s", __func__,
-			sdio_tty_drv->tty_dev_name);
-	kfree(sdio_tty_drv);
-
-	return 0;
-}
-
-static int sdio_tty_probe(struct platform_device *pdev)
-{
-	const struct platform_device_id *id = platform_get_device_id(pdev);
-	enum sdio_tty_devices device_id = id->driver_data;
-	char *device_name = NULL;
-	char *channel_name = NULL;
-	int debug_msg_on = 0;
-	int ret = 0;
-
-	pr_debug(SDIO_TTY_MODULE_NAME ": %s for %s", __func__, pdev->name);
-
-	switch (device_id) {
-	case SDIO_CSVT:
-		device_name = SDIO_TTY_CSVT_DEV;
-		channel_name = SDIO_TTY_CH_CSVT;
-		debug_msg_on = csvt_debug_msg_on;
-		break;
-	case SDIO_CSVT_TEST_APP:
-		device_name = SDIO_TTY_CSVT_TEST_DEV;
-		channel_name = SDIO_TTY_CH_CSVT;
-		debug_msg_on = csvt_debug_msg_on;
-		break;
-	default:
-		pr_err(SDIO_TTY_MODULE_NAME ": %s Invalid device:%s, id:%d",
-			__func__, pdev->name, device_id);
-		ret = -ENODEV;
-		break;
-	}
-
-	if (device_name) {
-		ret = sdio_tty_init_tty(device_name, channel_name,
-					device_id, debug_msg_on);
-		if (ret) {
-			pr_err(SDIO_TTY_MODULE_NAME ": %s: sdio_tty_init_tty "
-				"failed for dev:%s", __func__, device_name);
-		}
-	}
-	return ret;
-}
-
-static int sdio_tty_remove(struct platform_device *pdev)
-{
-	const struct platform_device_id *id = platform_get_device_id(pdev);
-	enum sdio_tty_devices device_id = id->driver_data;
-	struct sdio_tty *sdio_tty_drv = NULL;
-	int i = 0;
-	int ret = 0;
-
-	pr_debug(SDIO_TTY_MODULE_NAME ": %s for %s", __func__, pdev->name);
-
-	for (i = 0; i < MAX_SDIO_TTY_DEVS; i++) {
-		if (sdio_tty[i] == NULL)
-			continue;
-		if (sdio_tty[i]->device_id == device_id) {
-			sdio_tty_drv = sdio_tty[i];
-			break;
-		}
-	}
-
-	if (!sdio_tty_drv) {
-		pr_err(SDIO_TTY_MODULE_NAME ": %s: NULL sdio_tty_drv",
-		       __func__);
-		return -ENODEV;
-	}
-
-	ret = sdio_tty_uninit_tty(sdio_tty_drv);
-	if (ret) {
-		pr_err(SDIO_TTY_MODULE_NAME ": %s: sdio_tty_uninit_tty "
-			"failed for %s", __func__, pdev->name);
-	}
-	return ret;
-}
-
-static struct platform_driver sdio_tty_pdrv = {
-	.probe		= sdio_tty_probe,
-	.remove		= sdio_tty_remove,
-	.id_table	= sdio_tty_id_table,
-	.driver		= {
-		.name	= "SDIO_TTY",
-		.owner	= THIS_MODULE,
-	},
-};
-
-#ifdef CONFIG_DEBUG_FS
-void sdio_tty_print_info(void)
-{
-	int i = 0;
-
-	for (i = 0; i < MAX_SDIO_TTY_DEVS; i++) {
-		if (sdio_tty[i] == NULL)
-			continue;
-		pr_info(SDIO_TTY_MODULE_NAME ": %s: Total Rx=%d, Tx = %d "
-			"for dev %s", __func__, sdio_tty[i]->total_rx,
-			sdio_tty[i]->total_tx, sdio_tty[i]->tty_dev_name);
-	}
-}
-
-static int tty_debug_info_open(struct inode *inode, struct file *file)
-{
-	file->private_data = inode->i_private;
-	return 0;
-}
-
-static ssize_t tty_debug_info_write(struct file *file,
-		const char __user *buf, size_t count, loff_t *ppos)
-{
-	sdio_tty_print_info();
-	return count;
-}
-
-const struct file_operations tty_debug_info_ops = {
-	.open = tty_debug_info_open,
-	.write = tty_debug_info_write,
-};
-#endif
-
-/*
- *  Module Init.
- *
- *  Register SDIO TTY driver.
- *
- */
-static int __init sdio_tty_init(void)
-{
-	int ret = 0;
-
-	ret = platform_driver_register(&sdio_tty_pdrv);
-	if (ret) {
-		pr_err(SDIO_TTY_MODULE_NAME ": %s: platform_driver_register "
-					    "failed", __func__);
-	}
-#ifdef CONFIG_DEBUG_FS
-	else {
-		sdio_tty_debug_root = debugfs_create_dir("sdio_tty", NULL);
-		if (sdio_tty_debug_root) {
-			sdio_tty_debug_info = debugfs_create_file(
-							"sdio_tty_debug",
-							S_IRUGO | S_IWUGO,
-							sdio_tty_debug_root,
-							NULL,
-							&tty_debug_info_ops);
-		}
-	}
-#endif
-	return ret;
-};
-
-/*
- *  Module Exit.
- *
- *  Unregister SDIO TTY driver.
- *
- */
-static void __exit sdio_tty_exit(void)
-{
-#ifdef CONFIG_DEBUG_FS
-	debugfs_remove(sdio_tty_debug_info);
-	debugfs_remove(sdio_tty_debug_root);
-#endif
-	platform_driver_unregister(&sdio_tty_pdrv);
-}
-
-module_init(sdio_tty_init);
-module_exit(sdio_tty_exit);
-
-MODULE_DESCRIPTION("SDIO TTY");
-MODULE_LICENSE("GPL v2");
-MODULE_AUTHOR("Maya Erez <merez@codeaurora.org>");
diff --git a/arch/arm/mach-msm/smd.c b/arch/arm/mach-msm/smd.c
index 09b3113..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;
 	}
 }
 
@@ -2285,7 +2299,7 @@
 				edge_to_pids[ch->type].subsys_name);
 		irq_chip->irq_mask(irq_data);
 		if (cpumask)
-			irq_chip->irq_set_affinity(irq_data, cpumask, true);
+			irq_set_affinity(int_cfg->irq_id, cpumask);
 	} else {
 		SMD_POWER_INFO("SMD Unmasking interrupts from %s\n",
 				edge_to_pids[ch->type].subsys_name);
diff --git a/arch/arm/mach-msm/smd_tty.c b/arch/arm/mach-msm/smd_tty.c
index 428d5b0..e1c5162 100644
--- a/arch/arm/mach-msm/smd_tty.c
+++ b/arch/arm/mach-msm/smd_tty.c
@@ -28,6 +28,7 @@
 #include <linux/tty.h>
 #include <linux/tty_driver.h>
 #include <linux/tty_flip.h>
+#include <linux/suspend.h>
 
 #include <mach/msm_smd.h>
 #include <mach/subsystem_restart.h>
@@ -40,6 +41,7 @@
 #define MAX_SMD_TTYS 37
 #define MAX_TTY_BUF_SIZE 2048
 #define TTY_PUSH_WS_DELAY 500
+#define TTY_PUSH_WS_POST_SUSPEND_DELAY 100
 #define MAX_RA_WAKE_LOCK_NAME_LEN 32
 #define SMD_TTY_PROBE_WAIT_TIMEOUT 3000
 #define SMD_TTY_LOG_PAGES 2
@@ -63,6 +65,10 @@
 static struct delayed_work smd_tty_probe_work;
 static int smd_tty_probe_done;
 
+static bool smd_tty_in_suspend;
+static bool smd_tty_read_in_suspend;
+static struct wakeup_source read_in_suspend_ws;
+
 /**
  * struct smd_tty_info - context for an individual SMD TTY device
  *
@@ -297,6 +303,9 @@
 		 */
 		__pm_wakeup_event(&info->pending_ws, TTY_PUSH_WS_DELAY);
 
+		 if (smd_tty_in_suspend)
+			smd_tty_read_in_suspend = true;
+
 		tty_flip_buffer_push(tty);
 	}
 
@@ -551,7 +560,7 @@
 
 static void smd_tty_close(struct tty_struct *tty, struct file *f)
 {
-	struct smd_tty_info *info = tty->driver_data;
+	struct smd_tty_info *info = smd_tty + tty->index;
 
 	tty_port_close(&info->port, tty, f);
 }
@@ -696,6 +705,32 @@
 	return -ENODEV;
 }
 
+static int smd_tty_pm_notifier(struct notifier_block *nb,
+				unsigned long event, void *unused)
+{
+	switch (event) {
+	case PM_SUSPEND_PREPARE:
+		smd_tty_read_in_suspend = false;
+		smd_tty_in_suspend = true;
+	break;
+
+	case PM_POST_SUSPEND:
+		smd_tty_in_suspend = false;
+		if (smd_tty_read_in_suspend) {
+			smd_tty_read_in_suspend = false;
+			__pm_wakeup_event(&read_in_suspend_ws,
+				TTY_PUSH_WS_POST_SUSPEND_DELAY);
+		}
+	break;
+	}
+	return NOTIFY_DONE;
+}
+
+static struct notifier_block smd_tty_pm_nb = {
+	.notifier_call = smd_tty_pm_notifier,
+	.priority = 0,
+};
+
 /**
  * smd_tty_log_init()- Init function for IPC logging
  *
@@ -836,6 +871,11 @@
 		}
 	}
 	INIT_DELAYED_WORK(&loopback_work, loopback_probe_worker);
+
+	ret = register_pm_notifier(&smd_tty_pm_nb);
+	if (ret)
+		pr_err("%s: power state notif error %d\n", __func__, ret);
+
 	return 0;
 
 out:
@@ -918,6 +958,10 @@
 	}
 	INIT_DELAYED_WORK(&loopback_work, loopback_probe_worker);
 
+	ret = register_pm_notifier(&smd_tty_pm_nb);
+	if (ret)
+		pr_err("%s: power state notif error %d\n", __func__, ret);
+
 	return 0;
 
 error:
@@ -1002,6 +1046,7 @@
 	schedule_delayed_work(&smd_tty_probe_work,
 				msecs_to_jiffies(SMD_TTY_PROBE_WAIT_TIMEOUT));
 
+	wakeup_source_init(&read_in_suspend_ws, "SMDTTY_READ_IN_SUSPEND");
 	return 0;
 }
 
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/smp2p.c b/arch/arm/mach-msm/smp2p.c
index df241f8..5574eae 100644
--- a/arch/arm/mach-msm/smp2p.c
+++ b/arch/arm/mach-msm/smp2p.c
@@ -940,7 +940,7 @@
 
 	if (size < sizeof(struct smp2p_smem)) {
 		SMP2P_ERR(
-			"%s pid %d item size too small; expected: %d actual: %d\n",
+			"%s pid %d item size too small; expected: %zu actual: %d\n",
 			__func__, remote_pid,
 			sizeof(struct smp2p_smem), size);
 		smem_item = NULL;
diff --git a/arch/arm/mach-msm/smp2p_private.h b/arch/arm/mach-msm/smp2p_private.h
index 8e0d7a3..7174950 100644
--- a/arch/arm/mach-msm/smp2p_private.h
+++ b/arch/arm/mach-msm/smp2p_private.h
@@ -1,6 +1,6 @@
 /* arch/arm/mach-msm/smp2p_private.h
  *
- * 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
@@ -44,10 +44,10 @@
 #define SMP2P_GET_BITS(hdr_val, mask, bit) \
 	(((hdr_val) & (mask)) >> (bit))
 #define SMP2P_SET_BITS(hdr_val, mask, bit, new_value) \
-	do {\
+	{\
 		hdr_val = (hdr_val & ~(mask)) \
 		| (((new_value) << (bit)) & (mask)); \
-	} while (0)
+	}
 
 #define SMP2P_GET_LOCAL_PID(hdr) \
 	SMP2P_GET_BITS(hdr, SMP2P_LOCAL_PID_MASK, SMP2P_LOCAL_PID_BIT)
diff --git a/arch/arm/mach-msm/socinfo.c b/arch/arm/mach-msm/socinfo.c
index e7cec58..795749b 100644
--- a/arch/arm/mach-msm/socinfo.c
+++ b/arch/arm/mach-msm/socinfo.c
@@ -21,10 +21,12 @@
 #include <linux/sys_soc.h>
 #include <linux/slab.h>
 #include <linux/stat.h>
+#include <linux/string.h>
 #include <linux/sysdev.h>
 #include <linux/types.h>
 
 #include <asm/mach-types.h>
+#include <asm/system_misc.h>
 
 #include <mach/socinfo.h>
 #include <mach/msm_smem.h>
@@ -174,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;
@@ -183,246 +193,250 @@
 	struct socinfo_v6 v6;
 	struct socinfo_v7 v7;
 	struct socinfo_v8 v8;
+	struct socinfo_v9 v9;
 } *socinfo;
 
-static enum msm_cpu cpu_of_id[] = {
+static struct msm_soc_info cpu_of_id[] = {
 
 	/* 7x01 IDs */
-	[1]  = MSM_CPU_7X01,
-	[16] = MSM_CPU_7X01,
-	[17] = MSM_CPU_7X01,
-	[18] = MSM_CPU_7X01,
-	[19] = MSM_CPU_7X01,
-	[23] = MSM_CPU_7X01,
-	[25] = MSM_CPU_7X01,
-	[26] = MSM_CPU_7X01,
-	[32] = MSM_CPU_7X01,
-	[33] = MSM_CPU_7X01,
-	[34] = MSM_CPU_7X01,
-	[35] = MSM_CPU_7X01,
+	[0]  = {MSM_CPU_UNKNOWN, "Unknown CPU"},
+	[1]  = {MSM_CPU_7X01, "MSM7X01"},
+	[16] = {MSM_CPU_7X01, "MSM7X01"},
+	[17] = {MSM_CPU_7X01, "MSM7X01"},
+	[18] = {MSM_CPU_7X01, "MSM7X01"},
+	[19] = {MSM_CPU_7X01, "MSM7X01"},
+	[23] = {MSM_CPU_7X01, "MSM7X01"},
+	[25] = {MSM_CPU_7X01, "MSM7X01"},
+	[26] = {MSM_CPU_7X01, "MSM7X01"},
+	[32] = {MSM_CPU_7X01, "MSM7X01"},
+	[33] = {MSM_CPU_7X01, "MSM7X01"},
+	[34] = {MSM_CPU_7X01, "MSM7X01"},
+	[35] = {MSM_CPU_7X01, "MSM7X01"},
 
 	/* 7x25 IDs */
-	[20] = MSM_CPU_7X25,
-	[21] = MSM_CPU_7X25, /* 7225 */
-	[24] = MSM_CPU_7X25, /* 7525 */
-	[27] = MSM_CPU_7X25, /* 7625 */
-	[39] = MSM_CPU_7X25,
-	[40] = MSM_CPU_7X25,
-	[41] = MSM_CPU_7X25,
-	[42] = MSM_CPU_7X25,
-	[62] = MSM_CPU_7X25, /* 7625-1 */
-	[63] = MSM_CPU_7X25, /* 7225-1 */
-	[66] = MSM_CPU_7X25, /* 7225-2 */
+	[20] = {MSM_CPU_7X25, "MSM7X25"},
+	[21] = {MSM_CPU_7X25, "MSM7X25"},
+	[24] = {MSM_CPU_7X25, "MSM7X25"},
+	[27] = {MSM_CPU_7X25, "MSM7X25"},
+	[39] = {MSM_CPU_7X25, "MSM7X25"},
+	[40] = {MSM_CPU_7X25, "MSM7X25"},
+	[41] = {MSM_CPU_7X25, "MSM7X25"},
+	[42] = {MSM_CPU_7X25, "MSM7X25"},
+	[62] = {MSM_CPU_7X25, "MSM7X25"},
+	[63] = {MSM_CPU_7X25, "MSM7X25"},
+	[66] = {MSM_CPU_7X25, "MSM7X25"},
 
 
 	/* 7x27 IDs */
-	[43] = MSM_CPU_7X27,
-	[44] = MSM_CPU_7X27,
-	[61] = MSM_CPU_7X27,
-	[67] = MSM_CPU_7X27, /* 7227-1 */
-	[68] = MSM_CPU_7X27, /* 7627-1 */
-	[69] = MSM_CPU_7X27, /* 7627-2 */
+	[43] = {MSM_CPU_7X27, "MSM7X27"},
+	[44] = {MSM_CPU_7X27, "MSM7X27"},
+	[61] = {MSM_CPU_7X27, "MSM7X27"},
+	[67] = {MSM_CPU_7X27, "MSM7X27"},
+	[68] = {MSM_CPU_7X27, "MSM7X27"},
+	[69] = {MSM_CPU_7X27, "MSM7X27"},
 
 
 	/* 8x50 IDs */
-	[30] = MSM_CPU_8X50,
-	[36] = MSM_CPU_8X50,
-	[37] = MSM_CPU_8X50,
-	[38] = MSM_CPU_8X50,
+	[30] = {MSM_CPU_8X50, "MSM8X50"},
+	[36] = {MSM_CPU_8X50, "MSM8X50"},
+	[37] = {MSM_CPU_8X50, "MSM8X50"},
+	[38] = {MSM_CPU_8X50, "MSM8X50"},
 
 	/* 7x30 IDs */
-	[59] = MSM_CPU_7X30,
-	[60] = MSM_CPU_7X30,
+	[59] = {MSM_CPU_7X30, "MSM7X30"},
+	[60] = {MSM_CPU_7X30, "MSM7X30"},
 
 	/* 8x55 IDs */
-	[74] = MSM_CPU_8X55,
-	[75] = MSM_CPU_8X55,
-	[85] = MSM_CPU_8X55,
+	[74] = {MSM_CPU_8X55, "MSM8X55"},
+	[75] = {MSM_CPU_8X55, "MSM8X55"},
+	[85] = {MSM_CPU_8X55, "MSM8X55"},
 
 	/* 8x60 IDs */
-	[70] = MSM_CPU_8X60,
-	[71] = MSM_CPU_8X60,
-	[86] = MSM_CPU_8X60,
+	[70] = {MSM_CPU_8X60, "MSM8X60"},
+	[71] = {MSM_CPU_8X60, "MSM8X60"},
+	[86] = {MSM_CPU_8X60, "MSM8X60"},
 
 	/* 8960 IDs */
-	[87] = MSM_CPU_8960,
+	[87] = {MSM_CPU_8960, "MSM8960"},
 
 	/* 7x25A IDs */
-	[88] = MSM_CPU_7X25A,
-	[89] = MSM_CPU_7X25A,
-	[96] = MSM_CPU_7X25A,
+	[88] = {MSM_CPU_7X25A, "MSM7X25A"},
+	[89] = {MSM_CPU_7X25A, "MSM7X25A"},
+	[96] = {MSM_CPU_7X25A, "MSM7X25A"},
 
 	/* 7x27A IDs */
-	[90] = MSM_CPU_7X27A,
-	[91] = MSM_CPU_7X27A,
-	[92] = MSM_CPU_7X27A,
-	[97] = MSM_CPU_7X27A,
+	[90] = {MSM_CPU_7X27A, "MSM7X27A"},
+	[91] = {MSM_CPU_7X27A, "MSM7X27A"},
+	[92] = {MSM_CPU_7X27A, "MSM7X27A"},
+	[97] = {MSM_CPU_7X27A, "MSM7X27A"},
 
 	/* FSM9xxx ID */
-	[94] = FSM_CPU_9XXX,
-	[95] = FSM_CPU_9XXX,
+	[94] = {FSM_CPU_9XXX, "FSM9XXX"},
+	[95] = {FSM_CPU_9XXX, "FSM9XXX"},
 
 	/*  7x25AA ID */
-	[98] = MSM_CPU_7X25AA,
-	[99] = MSM_CPU_7X25AA,
-	[100] = MSM_CPU_7X25AA,
+	[98] = {MSM_CPU_7X25AA, "MSM7X25AA"},
+	[99] = {MSM_CPU_7X25AA, "MSM7X25AA"},
+	[100] = {MSM_CPU_7X25AA, "MSM7X25AA"},
 
 	/*  7x27AA ID */
-	[101] = MSM_CPU_7X27AA,
-	[102] = MSM_CPU_7X27AA,
-	[103] = MSM_CPU_7X27AA,
-	[136] = MSM_CPU_7X27AA,
+	[101] = {MSM_CPU_7X27AA, "MSM7X27AA"},
+	[102] = {MSM_CPU_7X27AA, "MSM7X27AA"},
+	[103] = {MSM_CPU_7X27AA, "MSM7X27AA"},
+	[136] = {MSM_CPU_7X27AA, "MSM7X27AA"},
 
 	/* 9x15 ID */
-	[104] = MSM_CPU_9615,
-	[105] = MSM_CPU_9615,
-	[106] = MSM_CPU_9615,
-	[107] = MSM_CPU_9615,
-	[171] = MSM_CPU_9615,
+	[104] = {MSM_CPU_9615, "MSM9615"},
+	[105] = {MSM_CPU_9615, "MSM9615"},
+	[106] = {MSM_CPU_9615, "MSM9615"},
+	[107] = {MSM_CPU_9615, "MSM9615"},
+	[171] = {MSM_CPU_9615, "MSM9615"},
 
 	/* 8064 IDs */
-	[109] = MSM_CPU_8064,
+	[109] = {MSM_CPU_8064, "APQ8064"},
 
 	/* 8930 IDs */
-	[116] = MSM_CPU_8930,
-	[117] = MSM_CPU_8930,
-	[118] = MSM_CPU_8930,
-	[119] = MSM_CPU_8930,
-	[179] = MSM_CPU_8930,
+	[116] = {MSM_CPU_8930, "MSM8930"},
+	[117] = {MSM_CPU_8930, "MSM8930"},
+	[118] = {MSM_CPU_8930, "MSM8930"},
+	[119] = {MSM_CPU_8930, "MSM8930"},
+	[179] = {MSM_CPU_8930, "MSM8930"},
 
 	/* 8627 IDs */
-	[120] = MSM_CPU_8627,
-	[121] = MSM_CPU_8627,
+	[120] = {MSM_CPU_8627, "MSM8627"},
+	[121] = {MSM_CPU_8627, "MSM8627"},
 
 	/* 8660A ID */
-	[122] = MSM_CPU_8960,
+	[122] = {MSM_CPU_8960, "MSM8960"},
 
 	/* 8260A ID */
-	[123] = MSM_CPU_8960,
+	[123] = {MSM_CPU_8960, "MSM8960"},
 
 	/* 8060A ID */
-	[124] = MSM_CPU_8960,
+	[124] = {MSM_CPU_8960, "MSM8960"},
 
 	/* 8974 IDs */
-	[126] = MSM_CPU_8974,
-	[184] = MSM_CPU_8974,
-	[185] = MSM_CPU_8974,
-	[186] = MSM_CPU_8974,
+	[126] = {MSM_CPU_8974, "MSM8974"},
+	[184] = {MSM_CPU_8974, "MSM8974"},
+	[185] = {MSM_CPU_8974, "MSM8974"},
+	[186] = {MSM_CPU_8974, "MSM8974"},
 
 	/* 8974AA IDs */
-	[208] = MSM_CPU_8974PRO_AA,
-	[211] = MSM_CPU_8974PRO_AA,
-	[214] = MSM_CPU_8974PRO_AA,
-	[217] = MSM_CPU_8974PRO_AA,
+	[208] = {MSM_CPU_8974PRO_AA, "MSM8974PRO-AA"},
+	[211] = {MSM_CPU_8974PRO_AA, "MSM8974PRO-AA"},
+	[214] = {MSM_CPU_8974PRO_AA, "MSM8974PRO-AA"},
+	[217] = {MSM_CPU_8974PRO_AA, "MSM8974PRO-AA"},
 
 	/* 8974AB IDs */
-	[209] = MSM_CPU_8974PRO_AB,
-	[212] = MSM_CPU_8974PRO_AB,
-	[215] = MSM_CPU_8974PRO_AB,
-	[218] = MSM_CPU_8974PRO_AB,
+	[209] = {MSM_CPU_8974PRO_AB, "MSM8974PRO-AB"},
+	[212] = {MSM_CPU_8974PRO_AB, "MSM8974PRO-AB"},
+	[215] = {MSM_CPU_8974PRO_AB, "MSM8974PRO-AB"},
+	[218] = {MSM_CPU_8974PRO_AB, "MSM8974PRO-AB"},
 
 	/* 8974AC IDs */
-	[194] = MSM_CPU_8974PRO_AC,
-	[210] = MSM_CPU_8974PRO_AC,
-	[213] = MSM_CPU_8974PRO_AC,
-	[216] = MSM_CPU_8974PRO_AC,
+	[194] = {MSM_CPU_8974PRO_AC, "MSM8974PRO-AC"},
+	[210] = {MSM_CPU_8974PRO_AC, "MSM8974PRO-AC"},
+	[213] = {MSM_CPU_8974PRO_AC, "MSM8974PRO-AC"},
+	[216] = {MSM_CPU_8974PRO_AC, "MSM8974PRO-AC"},
 
 	/* 8625 IDs */
-	[127] = MSM_CPU_8625,
-	[128] = MSM_CPU_8625,
-	[129] = MSM_CPU_8625,
-	[137] = MSM_CPU_8625,
-	[167] = MSM_CPU_8625,
+	[127] = {MSM_CPU_8625, "MSM8625"},
+	[128] = {MSM_CPU_8625, "MSM8625"},
+	[129] = {MSM_CPU_8625, "MSM8625"},
+	[137] = {MSM_CPU_8625, "MSM8625"},
+	[167] = {MSM_CPU_8625, "MSM8625"},
 
 	/* 8064 MPQ ID */
-	[130] = MSM_CPU_8064,
+	[130] = {MSM_CPU_8064, "APQ8064"},
 
 	/* 7x25AB IDs */
-	[131] = MSM_CPU_7X25AB,
-	[132] = MSM_CPU_7X25AB,
-	[133] = MSM_CPU_7X25AB,
-	[135] = MSM_CPU_7X25AB,
+	[131] = {MSM_CPU_7X25AB, "MSM7X25AB"},
+	[132] = {MSM_CPU_7X25AB, "MSM7X25AB"},
+	[133] = {MSM_CPU_7X25AB, "MSM7X25AB"},
+	[135] = {MSM_CPU_7X25AB, "MSM7X25AB"},
 
 	/* 9625 IDs */
-	[134] = MSM_CPU_9625,
-	[148] = MSM_CPU_9625,
-	[149] = MSM_CPU_9625,
-	[150] = MSM_CPU_9625,
-	[151] = MSM_CPU_9625,
-	[152] = MSM_CPU_9625,
-	[173] = MSM_CPU_9625,
-	[174] = MSM_CPU_9625,
-	[175] = MSM_CPU_9625,
+	[134] = {MSM_CPU_9625, "MSM9625"},
+	[148] = {MSM_CPU_9625, "MSM9625"},
+	[149] = {MSM_CPU_9625, "MSM9625"},
+	[150] = {MSM_CPU_9625, "MSM9625"},
+	[151] = {MSM_CPU_9625, "MSM9625"},
+	[152] = {MSM_CPU_9625, "MSM9625"},
+	[173] = {MSM_CPU_9625, "MSM9625"},
+	[174] = {MSM_CPU_9625, "MSM9625"},
+	[175] = {MSM_CPU_9625, "MSM9625"},
 
 	/* 8960AB IDs */
-	[138] = MSM_CPU_8960AB,
-	[139] = MSM_CPU_8960AB,
-	[140] = MSM_CPU_8960AB,
-	[141] = MSM_CPU_8960AB,
+	[138] = {MSM_CPU_8960AB, "MSM8960AB"},
+	[139] = {MSM_CPU_8960AB, "MSM8960AB"},
+	[140] = {MSM_CPU_8960AB, "MSM8960AB"},
+	[141] = {MSM_CPU_8960AB, "MSM8960AB"},
 
 	/* 8930AA IDs */
-	[142] = MSM_CPU_8930AA,
-	[143] = MSM_CPU_8930AA,
-	[144] = MSM_CPU_8930AA,
-	[160] = MSM_CPU_8930AA,
-	[180] = MSM_CPU_8930AA,
+	[142] = {MSM_CPU_8930AA, "MSM8930AA"},
+	[143] = {MSM_CPU_8930AA, "MSM8930AA"},
+	[144] = {MSM_CPU_8930AA, "MSM8930AA"},
+	[160] = {MSM_CPU_8930AA, "MSM8930AA"},
+	[180] = {MSM_CPU_8930AA, "MSM8930AA"},
 
 	/* 8226 IDs */
-	[145] = MSM_CPU_8226,
-	[158] = MSM_CPU_8226,
-	[159] = MSM_CPU_8226,
-	[198] = MSM_CPU_8226,
-	[199] = MSM_CPU_8226,
-	[200] = MSM_CPU_8226,
-	[205] = MSM_CPU_8226,
-	[219] = MSM_CPU_8226,
-	[220] = MSM_CPU_8226,
-	[221] = MSM_CPU_8226,
-	[222] = MSM_CPU_8226,
-	[223] = MSM_CPU_8226,
-	[224] = MSM_CPU_8226,
+	[145] = {MSM_CPU_8226, "MSM8626"},
+	[158] = {MSM_CPU_8226, "MSM8226"},
+	[159] = {MSM_CPU_8226, "MSM8526"},
+	[198] = {MSM_CPU_8226, "MSM8126"},
+	[199] = {MSM_CPU_8226, "APQ8026"},
+	[200] = {MSM_CPU_8226, "MSM8926"},
+	[205] = {MSM_CPU_8226, "MSM8326"},
+	[219] = {MSM_CPU_8226, "APQ8028"},
+	[220] = {MSM_CPU_8226, "MSM8128"},
+	[221] = {MSM_CPU_8226, "MSM8228"},
+	[222] = {MSM_CPU_8226, "MSM8528"},
+	[223] = {MSM_CPU_8226, "MSM8628"},
+	[224] = {MSM_CPU_8226, "MSM8928"},
 
 	/* 8092 IDs */
-	[146] = MSM_CPU_8092,
+	[146] = {MSM_CPU_8092, "MSM8092"},
 
 	/* 8610 IDs */
-	[147] = MSM_CPU_8610,
-	[161] = MSM_CPU_8610,
-	[162] = MSM_CPU_8610,
-	[163] = MSM_CPU_8610,
-	[164] = MSM_CPU_8610,
-	[165] = MSM_CPU_8610,
-	[166] = MSM_CPU_8610,
+	[147] = {MSM_CPU_8610, "MSM8610"},
+	[161] = {MSM_CPU_8610, "MSM8110"},
+	[162] = {MSM_CPU_8610, "MSM8210"},
+	[163] = {MSM_CPU_8610, "MSM8810"},
+	[164] = {MSM_CPU_8610, "MSM8212"},
+	[165] = {MSM_CPU_8610, "MSM8612"},
+	[166] = {MSM_CPU_8610, "MSM8112"},
+	[225] = {MSM_CPU_8610, "MSM8510"},
+	[226] = {MSM_CPU_8610, "MSM8512"},
 
 	/* 8064AB IDs */
-	[153] = MSM_CPU_8064AB,
+	[153] = {MSM_CPU_8064AB, "APQ8064AB"},
 
 	/* 8930AB IDs */
-	[154] = MSM_CPU_8930AB,
-	[155] = MSM_CPU_8930AB,
-	[156] = MSM_CPU_8930AB,
-	[157] = MSM_CPU_8930AB,
-	[181] = MSM_CPU_8930AB,
+	[154] = {MSM_CPU_8930AB, "MSM8930AB"},
+	[155] = {MSM_CPU_8930AB, "MSM8930AB"},
+	[156] = {MSM_CPU_8930AB, "MSM8930AB"},
+	[157] = {MSM_CPU_8930AB, "MSM8930AB"},
+	[181] = {MSM_CPU_8930AB, "MSM8930AB"},
 
 	/* 8625Q IDs */
-	[168] = MSM_CPU_8625Q,
-	[169] = MSM_CPU_8625Q,
-	[170] = MSM_CPU_8625Q,
+	[168] = {MSM_CPU_8625Q, "MSM8225Q"},
+	[169] = {MSM_CPU_8625Q, "MSM8625Q"},
+	[170] = {MSM_CPU_8625Q, "MSM8125Q"},
 
 	/* 8064AA IDs */
-	[172] = MSM_CPU_8064AA,
+	[172] = {MSM_CPU_8064AA, "APQ8064AA"},
 
 	/* 8084 IDs */
-	[178] = MSM_CPU_8084,
+	[178] = {MSM_CPU_8084, "APQ8084"},
 
 	/* krypton IDs */
-	[187] = MSM_CPU_KRYPTON,
+	[187] = {MSM_CPU_KRYPTON, "MSMKRYPTON"},
 
 	/* FSM9900 ID */
-	[188] = FSM_CPU_9900,
+	[188] = {FSM_CPU_9900, "FSM9900"},
 
 	/* Samarium IDs */
-	[195] = MSM_CPU_SAMARIUM,
+	[195] = {MSM_CPU_SAMARIUM, "MSMSAMARIUM"},
 
 	/* Uninitialized IDs are not known to run Linux.
 	   MSM_CPU_UNKNOWN is set to 0 to ensure these IDs are
@@ -453,6 +467,25 @@
 	return (socinfo) ? socinfo->v1.build_id : NULL;
 }
 
+static char *msm_read_hardware_id(void)
+{
+	static char msm_soc_str[128] = "Qualcomm ";
+	static bool string_generated = false;
+
+	if (string_generated)
+		return msm_soc_str;
+	if (!socinfo)
+		goto err_path;
+	if (!cpu_of_id[socinfo->v1.id].soc_id_string)
+		goto err_path;
+
+	string_generated = true;
+	return strncat(msm_soc_str, cpu_of_id[socinfo->v1.id].soc_id_string,
+			sizeof(msm_soc_str) - strlen(msm_soc_str));
+err_path:
+	return "UNKNOWN SOC TYPE";
+}
+
 uint32_t socinfo_get_raw_id(void)
 {
 	return socinfo ?
@@ -498,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 ?
@@ -676,6 +717,8 @@
 			char *buf)
 {
 	uint32_t hw_subtype;
+	WARN_ONCE(1, "Deprecated, use platform_subtype_id instead\n");
+
 	if (!socinfo) {
 		pr_err("%s: No socinfo found!\n", __func__);
 		return 0;
@@ -705,6 +748,18 @@
 }
 
 static ssize_t
+socinfo_show_platform_subtype_id(struct sys_device *dev,
+			struct sysdev_attribute *attr,
+			char *buf)
+{
+	uint32_t hw_subtype;
+
+	hw_subtype = socinfo_get_platform_subtype();
+	return snprintf(buf, PAGE_SIZE, "%u\n",
+		hw_subtype);
+}
+
+static ssize_t
 socinfo_show_pmic_model(struct sys_device *dev,
 			struct sysdev_attribute *attr,
 			char *buf)
@@ -827,6 +882,26 @@
 }
 
 static ssize_t
+msm_get_platform_subtype_id(struct device *dev,
+			struct device_attribute *attr,
+			char *buf)
+{
+	uint32_t hw_subtype;
+	hw_subtype = socinfo_get_platform_subtype();
+	return snprintf(buf, PAGE_SIZE, "%u\n",
+		hw_subtype);
+}
+
+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)
@@ -972,6 +1047,8 @@
 static struct sysdev_attribute socinfo_v6_files[] = {
 	_SYSDEV_ATTR(platform_subtype, 0444,
 			socinfo_show_platform_subtype, NULL),
+	_SYSDEV_ATTR(platform_subtype_id, 0444,
+			socinfo_show_platform_subtype_id, NULL),
 };
 
 static struct sysdev_attribute socinfo_v7_files[] = {
@@ -1057,6 +1134,17 @@
 	__ATTR(platform_subtype, S_IRUGO,
 			msm_get_platform_subtype, NULL);
 
+/* Platform Subtype String is being deprecated. Use Platform
+ * Subtype ID instead.
+ */
+static struct device_attribute msm_soc_attr_platform_subtype_id =
+	__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);
@@ -1141,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,
@@ -1150,6 +1241,8 @@
 	case 6:
 		device_create_file(msm_soc_device,
 					&msm_soc_attr_platform_subtype);
+		device_create_file(msm_soc_device,
+					&msm_soc_attr_platform_subtype_id);
 	case 5:
 		device_create_file(msm_soc_device,
 					&msm_soc_attr_accessory_chip);
@@ -1354,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;
@@ -1362,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,
@@ -1399,14 +1512,16 @@
 	}
 
 	WARN(!socinfo_get_id(), "Unknown SOC ID!\n");
-	WARN(socinfo_get_id() >= ARRAY_SIZE(cpu_of_id),
-		"New IDs added! ID => CPU mapping might need an update.\n");
 
-	if (socinfo->v1.id < ARRAY_SIZE(cpu_of_id))
-		cur_cpu = cpu_of_id[socinfo->v1.id];
+	if (socinfo_get_id() >= ARRAY_SIZE(cpu_of_id))
+		BUG_ON("New IDs added! ID => CPU mapping might need an update.\n");
+
+	else
+		cur_cpu = cpu_of_id[socinfo->v1.id].generic_soc_type;
 
 	boot_stats_init();
 	socinfo_print();
+	arch_read_hardware_id = msm_read_hardware_id;
 
 	return 0;
 }
diff --git a/arch/arm/mach-msm/subsystem_restart.c b/arch/arm/mach-msm/subsystem_restart.c
index 01e0985..bc4eb76 100644
--- a/arch/arm/mach-msm/subsystem_restart.c
+++ b/arch/arm/mach-msm/subsystem_restart.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
@@ -466,13 +466,20 @@
 
 	pr_info("[%p]: Powering up %s\n", current, name);
 	init_completion(&dev->err_ready);
-	if (dev->desc->powerup(dev->desc) < 0)
+
+	if (dev->desc->powerup(dev->desc) < 0) {
+		notify_each_subsys_device(&dev, 1, SUBSYS_POWERUP_FAILURE,
+								NULL);
 		panic("[%p]: Powerup error: %s!", current, name);
+	}
 
 	ret = wait_for_err_ready(dev);
-	if (ret)
+	if (ret) {
+		notify_each_subsys_device(&dev, 1, SUBSYS_POWERUP_FAILURE,
+								NULL);
 		panic("[%p]: Timed out waiting for error ready: %s!",
 			current, name);
+	}
 	subsys_set_state(dev, SUBSYS_ONLINE);
 }
 
@@ -500,8 +507,11 @@
 
 	init_completion(&subsys->err_ready);
 	ret = subsys->desc->start(subsys->desc);
-	if (ret)
+	if (ret){
+		notify_each_subsys_device(&subsys, 1, SUBSYS_POWERUP_FAILURE,
+									NULL);
 		return ret;
+	}
 
 	if (subsys->desc->is_not_loadable) {
 		subsys_set_state(subsys, SUBSYS_ONLINE);
@@ -509,12 +519,14 @@
 	}
 
 	ret = wait_for_err_ready(subsys);
-	if (ret)
+	if (ret) {
 		/* pil-boot succeeded but we need to shutdown
 		 * the device because error ready timed out.
 		 */
+		notify_each_subsys_device(&subsys, 1, SUBSYS_POWERUP_FAILURE,
+									NULL);
 		subsys->desc->stop(subsys->desc);
-	else
+	} else
 		subsys_set_state(subsys, SUBSYS_ONLINE);
 
 	return ret;
diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c
index 4ff4b3e..935bb9a 100644
--- a/arch/arm/mm/dma-mapping.c
+++ b/arch/arm/mm/dma-mapping.c
@@ -308,7 +308,7 @@
 static int __init atomic_pool_init(void)
 {
 	struct dma_pool *pool = &atomic_pool;
-	pgprot_t prot = pgprot_dmacoherent(pgprot_kernel);
+	pgprot_t prot = pgprot_dmacoherent(PAGE_KERNEL);
 	unsigned long nr_pages = pool->size >> PAGE_SHIFT;
 	unsigned long *bitmap;
 	struct page *page;
@@ -550,7 +550,7 @@
 				   void *cpu_addr, size_t size)
 {
 	if (!PageHighMem(page))
-		__dma_remap(page, size, pgprot_kernel, false);
+		__dma_remap(page, size, PAGE_KERNEL, false);
 	else
 		__dma_free_remap(cpu_addr, size, true);
 	dma_release_from_contiguous(dev, page, size >> PAGE_SHIFT);
@@ -657,7 +657,7 @@
 void *arm_dma_alloc(struct device *dev, size_t size, dma_addr_t *handle,
 		    gfp_t gfp, struct dma_attrs *attrs)
 {
-	pgprot_t prot = __get_dma_pgprot(attrs, pgprot_kernel);
+	pgprot_t prot = __get_dma_pgprot(attrs, PAGE_KERNEL);
 	void *memory;
 	bool no_kernel_mapping = dma_get_attr(DMA_ATTR_NO_KERNEL_MAPPING,
 					attrs);
@@ -1151,7 +1151,7 @@
 static void *arm_iommu_alloc_attrs(struct device *dev, size_t size,
 	    dma_addr_t *handle, gfp_t gfp, struct dma_attrs *attrs)
 {
-	pgprot_t prot = __get_dma_pgprot(attrs, pgprot_kernel);
+	pgprot_t prot = __get_dma_pgprot(attrs, PAGE_KERNEL);
 	struct page **pages;
 	void *addr = NULL;
 
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 a1a2e51..3d52735 100644
--- a/arch/arm/mm/mmu.c
+++ b/arch/arm/mm/mmu.c
@@ -307,7 +307,8 @@
 		.domain    = DOMAIN_KERNEL,
 	},
 	[MT_MEMORY_DMA_READY] = {
-		.prot_pte  = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY,
+		.prot_pte  = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY |
+				L_PTE_XN,
 		.prot_l1   = PMD_TYPE_TABLE,
 		.domain    = DOMAIN_KERNEL,
 	},
@@ -343,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); \
@@ -1500,10 +1503,106 @@
 		vm->flags = VM_LOWMEM | VM_ARM_STATIC_MAPPING;
 		vm->flags |= VM_ARM_MTYPE(type);
 		vm->caller = map_lowmem;
-		vm_area_add_early(vm++);
+		vm_area_add_early(vm);
+		mark_vmalloc_reserved_area(vm->addr, vm->size);
+		vm++;
 	}
 }
 
+#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.
@@ -1518,6 +1617,7 @@
 	prepare_page_table();
 	map_lowmem();
 	dma_contiguous_remap();
+	remap_pages();
 	devicemaps_init(mdesc);
 	kmap_init();
 
diff --git a/block/blk-core.c b/block/blk-core.c
index 123f79a..7afd6cf 100644
--- a/block/blk-core.c
+++ b/block/blk-core.c
@@ -314,7 +314,8 @@
 	if (!q->notified_urgent &&
 		q->elevator->type->ops.elevator_is_urgent_fn &&
 		q->urgent_request_fn &&
-		q->elevator->type->ops.elevator_is_urgent_fn(q)) {
+		q->elevator->type->ops.elevator_is_urgent_fn(q) &&
+		list_empty(&q->flush_data_in_flight)) {
 		q->notified_urgent = true;
 		q->urgent_request_fn(q);
 	} else
@@ -1220,8 +1221,9 @@
 
 	elv_completed_request(q, req);
 
-	/* this is a bio leak */
-	WARN_ON(req->bio != NULL);
+	/* this is a bio leak if the bio is not tagged with BIO_DONTFREE */
+	WARN_ON(req->bio && !bio_flagged(req->bio, BIO_DONTFREE));
+
 
 	/*
 	 * Request may not have originated from ll_rw_blk. if not,
@@ -2273,6 +2275,15 @@
 	blk_account_io_completion(req, nr_bytes);
 
 	total_bytes = bio_nbytes = 0;
+
+	/*
+	 * Check for this if flagged, Req based dm needs to perform
+	 * post processing, hence dont end bios or request.DM
+	 * layer takes care.
+	 */
+	if (bio_flagged(req->bio, BIO_DONTFREE))
+		return false;
+
 	while ((bio = req->bio) != NULL) {
 		int nbytes;
 
diff --git a/drivers/base/dma-contiguous.c b/drivers/base/dma-contiguous.c
index 885721f..2adcbbc 100644
--- a/drivers/base/dma-contiguous.c
+++ b/drivers/base/dma-contiguous.c
@@ -47,6 +47,7 @@
 	unsigned long	base_pfn;
 	unsigned long	count;
 	unsigned long	*bitmap;
+	struct mutex lock;
 };
 
 static DEFINE_MUTEX(cma_mutex);
@@ -191,6 +192,7 @@
 	ret = cma_activate_area(base_pfn, count);
 	if (ret)
 		goto error;
+	mutex_init(&cma->lock);
 
 	pr_debug("%s: returned %p\n", __func__, (void *)cma);
 	return cma;
@@ -212,6 +214,7 @@
 	unsigned long len;
 	__be32 *prop;
 	char *name;
+	phys_addr_t limit = MEMBLOCK_ALLOC_ANYWHERE;
 
 	if (!of_get_flat_dt_prop(node, "linux,contiguous-region", NULL))
 		return 0;
@@ -225,9 +228,13 @@
 
 	name = of_get_flat_dt_prop(node, "label", NULL);
 
-	pr_info("Found %s, memory base %lx, size %ld MiB\n", uname,
-		(unsigned long)base, (unsigned long)size / SZ_1M);
-	dma_contiguous_reserve_area(size, &base, MEMBLOCK_ALLOC_ANYWHERE, name);
+	prop = of_get_flat_dt_prop(node, "linux,memory-limit", NULL);
+	if (prop)
+		limit = be32_to_cpu(prop[0]);
+
+	pr_info("Found %s, memory base %lx, size %ld MiB, limit %pa\n", uname,
+		(unsigned long)base, (unsigned long)size / SZ_1M, &limit);
+	dma_contiguous_reserve_area(size, &base, limit, name);
 
 	return 0;
 }
@@ -454,6 +461,13 @@
 	return cma->base_pfn << PAGE_SHIFT;
 }
 
+static void clear_cma_bitmap(struct cma *cma, unsigned long pfn, int count)
+{
+	mutex_lock(&cma->lock);
+	bitmap_clear(cma->bitmap, pfn - cma->base_pfn, count);
+	mutex_unlock(&cma->lock);
+}
+
 /**
  * dma_alloc_from_contiguous() - allocate pages from contiguous area
  * @dev:   Pointer to device for which the allocation is performed.
@@ -488,23 +502,36 @@
 
 	mask = (1 << align) - 1;
 
-	mutex_lock(&cma_mutex);
 
 	for (;;) {
+		mutex_lock(&cma->lock);
 		pageno = bitmap_find_next_zero_area(cma->bitmap, cma->count,
 						    start, count, mask);
-		if (pageno >= cma->count)
+		if (pageno >= cma->count) {
+			mutex_unlock(&cma->lock);
 			break;
+		}
+		bitmap_set(cma->bitmap, pageno, count);
+		/*
+		 * It's safe to drop the lock here. We've marked this region for
+		 * our exclusive use. If the migration fails we will take the
+		 * lock again and unmark it.
+		 */
+		mutex_unlock(&cma->lock);
 
 		pfn = cma->base_pfn + pageno;
+		mutex_lock(&cma_mutex);
 		ret = alloc_contig_range(pfn, pfn + count, MIGRATE_CMA);
+		mutex_unlock(&cma_mutex);
 		if (ret == 0) {
-			bitmap_set(cma->bitmap, pageno, count);
 			page = pfn_to_page(pfn);
 			break;
 		} else if (ret != -EBUSY) {
+			pfn = 0;
+			clear_cma_bitmap(cma, pfn, count);
 			break;
 		}
+		clear_cma_bitmap(cma, pfn, count);
 		tries++;
 		trace_dma_alloc_contiguous_retry(tries);
 
@@ -514,7 +541,6 @@
 		start = pageno + mask + 1;
 	}
 
-	mutex_unlock(&cma_mutex);
 	pr_debug("%s(): returned %p\n", __func__, page);
 	return page;
 }
@@ -547,10 +573,8 @@
 
 	VM_BUG_ON(pfn + count > cma->base_pfn + cma->count);
 
-	mutex_lock(&cma_mutex);
-	bitmap_clear(cma->bitmap, pfn - cma->base_pfn, count);
 	free_contig_range(pfn, count);
-	mutex_unlock(&cma_mutex);
+	clear_cma_bitmap(cma, pfn, count);
 
 	return true;
 }
diff --git a/drivers/bluetooth/bluetooth-power.c b/drivers/bluetooth/bluetooth-power.c
index 13c9080..9ccee05 100644
--- a/drivers/bluetooth/bluetooth-power.c
+++ b/drivers/bluetooth/bluetooth-power.c
@@ -30,7 +30,7 @@
 #define BT_PWR_DBG(fmt, arg...)  pr_debug("%s: " fmt "\n" , __func__ , ## arg)
 #define BT_PWR_INFO(fmt, arg...) pr_info("%s: " fmt "\n" , __func__ , ## arg)
 #define BT_PWR_ERR(fmt, arg...)  pr_err("%s: " fmt "\n" , __func__ , ## arg)
-
+#define BT_VDD_PA_CURRENT        60000
 
 static struct of_device_id bt_power_match_table[] = {
 	{	.compatible = "qca,ar3002" },
@@ -213,6 +213,9 @@
 				BT_PWR_ERR("bt_power vddpa config failed");
 				goto vdd_pa_fail;
 			}
+			regulator_set_optimum_mode(
+				bt_power_pdata->bt_vdd_pa->reg,
+				BT_VDD_PA_CURRENT);
 		}
 		if (bt_power_pdata->bt_chip_pwd) {
 			rc = bt_configure_vreg(bt_power_pdata->bt_chip_pwd);
diff --git a/drivers/bluetooth/hci_ath.c b/drivers/bluetooth/hci_ath.c
index 0383d8f..8272528 100644
--- a/drivers/bluetooth/hci_ath.c
+++ b/drivers/bluetooth/hci_ath.c
@@ -5,7 +5,7 @@
  *  power management protocol extension to H4 to support AR300x Bluetooth Chip.
  *
  *  Copyright (c) 2009-2010 Atheros Communications Inc.
- *  Copyright (c) 2012-2013 The Linux Foundation. All rights reserved.
+ *  Copyright (c) 2012-2014 The Linux Foundation. All rights reserved.
  *
  *  Acknowledgements:
  *  This file is based on hci_h4.c, which was written
diff --git a/drivers/char/adsprpc.c b/drivers/char/adsprpc.c
index cc8cf47..009ab57 100644
--- a/drivers/char/adsprpc.c
+++ b/drivers/char/adsprpc.c
@@ -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
@@ -564,10 +564,7 @@
 		rpra[i].buf.len = pra[i].buf.len;
 		if (!rpra[i].buf.len)
 			continue;
-		if (list[i].num) {
-			rpra[i].buf.pv = pra[i].buf.pv;
-			continue;
-		} else if (me->smmu.enabled && fds && (fds[i] >= 0)) {
+		if (me->smmu.enabled && fds && (fds[i] >= 0)) {
 			len = buf_page_size(pra[i].buf.len);
 			handles[i] = ion_import_dma_buf(me->iclient, fds[i]);
 			VERIFY(err, 0 == IS_ERR_OR_NULL(handles[i]));
@@ -583,6 +580,9 @@
 			pages[list[i].pgidx].addr = iova;
 			pages[list[i].pgidx].size = len;
 			continue;
+		} else if (list[i].num) {
+			rpra[i].buf.pv = pra[i].buf.pv;
+			continue;
 		}
 		if (rlen < pra[i].buf.len) {
 			struct fastrpc_buf *b;
diff --git a/drivers/char/diag/diag_dci.c b/drivers/char/diag/diag_dci.c
index 2dbb2f5..0edfdad 100644
--- a/drivers/char/diag/diag_dci.c
+++ b/drivers/char/diag/diag_dci.c
@@ -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
@@ -216,7 +216,11 @@
 	if (recv_pkt_cmd_code != DCI_PKT_RSP_CODE)
 		cmd_code_len = 4; /* delayed response */
 	write_len = (int)(*(uint16_t *)(buf+2)) - cmd_code_len;
-
+	if (write_len <= 0) {
+		pr_err("diag: Invalid length in %s, write_len: %d",
+					__func__, write_len);
+		return;
+	}
 	pr_debug("diag: len = %d\n", write_len);
 	tag = (int *)(buf + (4 + cmd_code_len)); /* Retrieve the Tag field */
 	req_entry = diag_dci_get_request_entry(*tag);
@@ -278,7 +282,7 @@
 {
 	uint16_t event_id, event_id_packet, length, temp_len;
 	uint8_t *event_mask_ptr, byte_mask, payload_len, payload_len_field;
-	uint8_t timestamp[8], bit_index, timestamp_len;
+	uint8_t timestamp[8] = {0}, bit_index, timestamp_len;
 	uint8_t event_data[MAX_EVENT_SIZE];
 	unsigned int byte_index, total_event_len, i;
 	struct diag_dci_client_tbl *entry;
@@ -383,17 +387,23 @@
 
 void extract_dci_log(unsigned char *buf)
 {
-	uint16_t log_code, item_num;
+	uint16_t log_code, item_num, log_length;
 	uint8_t equip_id, *log_mask_ptr, byte_mask;
 	unsigned int i, byte_index, byte_offset = 0;
 	struct diag_dci_client_tbl *entry;
 
+	log_length = *(uint16_t *)(buf + 2);
 	log_code = *(uint16_t *)(buf + 6);
 	equip_id = LOG_GET_EQUIP_ID(log_code);
 	item_num = LOG_GET_ITEM_NUM(log_code);
 	byte_index = item_num/8 + 2;
 	byte_mask = 0x01 << (item_num % 8);
 
+	if (log_length > USHRT_MAX - 4) {
+		pr_err("diag: Integer overflow in %s, log_len:%d",
+				__func__, log_length);
+		return;
+	}
 	byte_offset = (equip_id * 514) + byte_index;
 	if (byte_offset >=  DCI_LOG_MASK_SIZE) {
 		pr_err("diag: Invalid byte_offset %d in dci log\n",
@@ -430,8 +440,8 @@
 				*(int *)(entry->dci_data+entry->data_len) =
 								DCI_LOG_TYPE;
 				memcpy(entry->dci_data + entry->data_len + 4,
-					    buf + 4, *(uint16_t *)(buf + 2));
-				entry->data_len += 4 + *(uint16_t *)(buf + 2);
+					    buf + 4, log_length);
+				entry->data_len += 4 + log_length;
 			}
 			mutex_unlock(&entry->data_mutex);
 			mutex_unlock(&dci_health_mutex);
@@ -487,9 +497,9 @@
 	}
 	mutex_unlock(&dci_log_mask_mutex);
 
-	ret = diag_send_dci_log_mask(driver->smd_cntl[index].ch);
+	ret = diag_send_dci_log_mask(&driver->smd_cntl[index]);
 
-	ret = diag_send_dci_event_mask(driver->smd_cntl[index].ch);
+	ret = diag_send_dci_event_mask(&driver->smd_cntl[index]);
 
 	smd_info->notify_context = 0;
 }
@@ -562,8 +572,10 @@
 					&driver->smd_dci[i];
 		if (entry.client_id == smd_info->peripheral) {
 			if (smd_info->ch) {
+				mutex_lock(&smd_info->smd_ch_mutex);
 				smd_write(smd_info->ch,
 					driver->apps_dci_buf, len + 10);
+				mutex_unlock(&smd_info->smd_ch_mutex);
 				status = DIAG_DCI_NO_ERROR;
 			}
 			break;
@@ -757,7 +769,7 @@
 			ret = DIAG_DCI_NO_ERROR;
 		}
 		/* send updated mask to peripherals */
-		ret = diag_send_dci_log_mask(driver->smd_cntl[MODEM_DATA].ch);
+		ret = diag_send_dci_log_mask(&driver->smd_cntl[MODEM_DATA]);
 	} else if (*(int *)temp == DCI_EVENT_TYPE) {
 		/* Minimum length of a event mask config is 12 + 4 bytes for
 		  atleast one event id to be set or reset. */
@@ -828,13 +840,29 @@
 			ret = DIAG_DCI_NO_ERROR;
 		}
 		/* send updated mask to peripherals */
-		ret = diag_send_dci_event_mask(driver->smd_cntl[MODEM_DATA].ch);
+		ret = diag_send_dci_event_mask(&driver->smd_cntl[MODEM_DATA]);
 	} else {
 		pr_alert("diag: Incorrect DCI transaction\n");
 	}
 	return ret;
 }
 
+int diag_dci_find_client_index_health(int client_id)
+{
+	int i, ret = DCI_CLIENT_INDEX_INVALID;
+
+	for (i = 0; i < MAX_DCI_CLIENTS; i++) {
+		if (driver->dci_client_tbl[i].client != NULL) {
+			if (driver->dci_client_tbl[i].client_id ==
+					client_id) {
+				ret = i;
+				break;
+			}
+		}
+	}
+	return ret;
+}
+
 int diag_dci_find_client_index(int client_id)
 {
 	int i, ret = DCI_CLIENT_INDEX_INVALID;
@@ -940,7 +968,7 @@
 }
 
 
-int diag_send_dci_event_mask(smd_channel_t *ch)
+int diag_send_dci_event_mask(struct diag_smd_info *smd_info)
 {
 	void *buf = driver->buf_event_mask_update;
 	int header_size = sizeof(struct diag_ctrl_event_mask);
@@ -963,10 +991,12 @@
 	}
 	memcpy(buf, driver->event_mask, header_size);
 	memcpy(buf+header_size, dci_cumulative_event_mask, DCI_EVENT_MASK_SIZE);
-	if (ch) {
+	if (smd_info && smd_info->ch) {
 		while (retry_count < 3) {
-			wr_size = smd_write(ch, buf,
+			mutex_lock(&smd_info->smd_ch_mutex);
+			wr_size = smd_write(smd_info->ch, buf,
 					 header_size + DCI_EVENT_MASK_SIZE);
+			mutex_unlock(&smd_info->smd_ch_mutex);
 			if (wr_size == -ENOMEM) {
 				retry_count++;
 				for (timer = 0; timer < 5; timer++)
@@ -1106,7 +1136,7 @@
 	mutex_unlock(&dci_log_mask_mutex);
 }
 
-int diag_send_dci_log_mask(smd_channel_t *ch)
+int diag_send_dci_log_mask(struct diag_smd_info *smd_info)
 {
 	void *buf = driver->buf_log_mask_update;
 	int header_size = sizeof(struct diag_ctrl_log_mask);
@@ -1114,7 +1144,7 @@
 	int i, wr_size = -ENOMEM, retry_count = 0, timer;
 	int ret = DIAG_DCI_NO_ERROR;
 
-	if (!ch) {
+	if (!smd_info || !smd_info->ch) {
 		pr_err("diag: ch not valid for dci log mask update\n");
 		return DIAG_DCI_SEND_DATA_FAIL;
 	}
@@ -1132,9 +1162,12 @@
 		memcpy(buf, driver->log_mask, header_size);
 		memcpy(buf+header_size, log_mask_ptr+2, 512);
 		/* if dirty byte is set and channel is valid */
-		if (ch && *(log_mask_ptr+1)) {
+		if (smd_info->ch && *(log_mask_ptr+1)) {
 			while (retry_count < 3) {
-				wr_size = smd_write(ch, buf, header_size + 512);
+				mutex_lock(&smd_info->smd_ch_mutex);
+				wr_size = smd_write(smd_info->ch, buf,
+							header_size + 512);
+				mutex_unlock(&smd_info->smd_ch_mutex);
 				if (wr_size == -ENOMEM) {
 					retry_count++;
 					for (timer = 0; timer < 5; timer++)
@@ -1406,7 +1439,7 @@
 		}
 	}
 	mutex_unlock(&dci_log_mask_mutex);
-	err = diag_send_dci_log_mask(driver->smd_cntl[MODEM_DATA].ch);
+	err = diag_send_dci_log_mask(&driver->smd_cntl[MODEM_DATA]);
 	return err;
 }
 
@@ -1432,7 +1465,7 @@
 			*(update_ptr + j) |= *(event_mask_ptr + j);
 	}
 	mutex_unlock(&dci_event_mask_mutex);
-	err = diag_send_dci_event_mask(driver->smd_cntl[MODEM_DATA].ch);
+	err = diag_send_dci_event_mask(&driver->smd_cntl[MODEM_DATA]);
 	return err;
 }
 
diff --git a/drivers/char/diag/diag_dci.h b/drivers/char/diag/diag_dci.h
index c9be39a..870b0f3 100644
--- a/drivers/char/diag/diag_dci.h
+++ b/drivers/char/diag/diag_dci.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
@@ -56,6 +56,7 @@
 } __packed;
 
 struct diag_dci_client_tbl {
+	uint32_t client_id;
 	struct task_struct *client;
 	uint16_t list; /* bit mask */
 	int signal_type;
@@ -74,6 +75,7 @@
 
 /* This is used for DCI health stats */
 struct diag_dci_health_stats {
+	int client_id;
 	int dropped_logs;
 	int dropped_events;
 	int received_logs;
@@ -119,20 +121,22 @@
 								int recd_bytes);
 int diag_process_dci_transaction(unsigned char *buf, int len);
 void extract_dci_pkt_rsp(struct diag_smd_info *smd_info, unsigned char *buf);
+
+int diag_dci_find_client_index_health(int client_id);
 int diag_dci_find_client_index(int client_id);
 /* DCI Log streaming functions */
 void create_dci_log_mask_tbl(unsigned char *tbl_buf);
 void update_dci_cumulative_log_mask(int offset, unsigned int byte_index,
 						uint8_t byte_mask);
 void clear_client_dci_cumulative_log_mask(int client_index);
-int diag_send_dci_log_mask(smd_channel_t *ch);
+int diag_send_dci_log_mask(struct diag_smd_info *smd_info);
 void extract_dci_log(unsigned char *buf);
 int diag_dci_clear_log_mask(void);
 int diag_dci_query_log_mask(uint16_t log_code);
 /* DCI event streaming functions */
 void update_dci_cumulative_event_mask(int offset, uint8_t byte_mask);
 void clear_client_dci_cumulative_event_mask(int client_index);
-int diag_send_dci_event_mask(smd_channel_t *ch);
+int diag_send_dci_event_mask(struct diag_smd_info *smd_info);
 void extract_dci_events(unsigned char *buf);
 void create_dci_event_mask_tbl(unsigned char *tbl_buf);
 int diag_dci_clear_event_mask(void);
diff --git a/drivers/char/diag/diag_debugfs.c b/drivers/char/diag/diag_debugfs.c
index beaf75d..3a1c96b 100644
--- a/drivers/char/diag/diag_debugfs.c
+++ b/drivers/char/diag/diag_debugfs.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
@@ -33,14 +33,14 @@
 {
 	char *buf;
 	int ret;
-
+	unsigned int buf_size;
 	buf = kzalloc(sizeof(char) * DEBUG_BUF_SIZE, GFP_KERNEL);
 	if (!buf) {
 		pr_err("diag: %s, Error allocating memory\n", __func__);
 		return -ENOMEM;
 	}
-
-	ret = scnprintf(buf, DEBUG_BUF_SIZE,
+	buf_size = ksize(buf);
+	ret = scnprintf(buf, buf_size,
 		"modem ch: 0x%x\n"
 		"lpass ch: 0x%x\n"
 		"riva ch: 0x%x\n"
@@ -181,7 +181,7 @@
 		driver->real_time_mode);
 
 #ifdef CONFIG_DIAG_OVER_USB
-	ret += scnprintf(buf+ret, DEBUG_BUF_SIZE,
+	ret += scnprintf(buf+ret, buf_size-ret,
 		"usb_connected: %d\n",
 		driver->usb_connected);
 #endif
@@ -195,9 +195,11 @@
 				char __user *ubuf, size_t count, loff_t *ppos)
 {
 	char *buf = NULL;
-	int bytes_remaining, bytes_written = 0, bytes_in_buf = 0, i = 0;
+	unsigned int bytes_remaining, bytes_written = 0;
+	unsigned int bytes_in_buf = 0, i = 0;
 	struct diag_dci_data_info *temp_data = dci_data_smd;
-	int buf_size = (DEBUG_BUF_SIZE < count) ? DEBUG_BUF_SIZE : count;
+	unsigned int buf_size;
+	buf_size = (DEBUG_BUF_SIZE < count) ? DEBUG_BUF_SIZE : count;
 
 	if (diag_dbgfs_dci_finished) {
 		diag_dbgfs_dci_finished = 0;
@@ -210,6 +212,7 @@
 		return -ENOMEM;
 	}
 
+	buf_size = ksize(buf);
 	bytes_remaining = buf_size;
 
 	if (diag_dbgfs_dci_data_index == 0) {
@@ -286,6 +289,7 @@
 {
 	char *buf;
 	int ret;
+	unsigned int buf_size;
 
 	buf = kzalloc(sizeof(char) * DEBUG_BUF_SIZE, GFP_KERNEL);
 	if (!buf) {
@@ -293,7 +297,8 @@
 		return -ENOMEM;
 	}
 
-	ret = scnprintf(buf, DEBUG_BUF_SIZE,
+	buf_size = ksize(buf);
+	ret = scnprintf(buf, buf_size,
 		"Pending status for work_stucts:\n"
 		"diag_drain_work: %d\n"
 		"Modem data diag_read_smd_work: %d\n"
@@ -341,7 +346,7 @@
 						diag_notify_update_smd_work)));
 
 #ifdef CONFIG_DIAG_OVER_USB
-	ret += scnprintf(buf+ret, DEBUG_BUF_SIZE,
+	ret += scnprintf(buf+ret, buf_size-ret,
 		"diag_proc_hdlc_work: %d\n"
 		"diag_read_work: %d\n",
 		work_pending(&(driver->diag_proc_hdlc_work)),
@@ -359,10 +364,11 @@
 	char *buf;
 	int ret = 0;
 	int i;
-	int bytes_remaining;
-	int bytes_in_buffer = 0;
-	int bytes_written;
-	int buf_size = (DEBUG_BUF_SIZE < count) ? DEBUG_BUF_SIZE : count;
+	unsigned int bytes_remaining;
+	unsigned int bytes_in_buffer = 0;
+	unsigned int bytes_written;
+	unsigned int buf_size;
+	buf_size = (DEBUG_BUF_SIZE < count) ? DEBUG_BUF_SIZE : count;
 
 	if (diag_dbgfs_table_index >= diag_max_reg) {
 		/* Done. Reset to prepare for future requests */
@@ -375,7 +381,7 @@
 		pr_err("diag: %s, Error allocating memory\n", __func__);
 		return -ENOMEM;
 	}
-
+	buf_size = ksize(buf);
 	bytes_remaining = buf_size;
 
 	if (diag_dbgfs_table_index == 0) {
@@ -384,6 +390,7 @@
 			"WCNSS: %d, APPS: %d\n",
 			MODEM_DATA, LPASS_DATA, WCNSS_DATA, APPS_DATA);
 		bytes_in_buffer += bytes_written;
+		bytes_remaining -= bytes_written;
 	}
 
 	for (i = diag_dbgfs_table_index; i < diag_max_reg; i++) {
@@ -427,14 +434,15 @@
 {
 	char *buf = NULL;
 	int ret = 0, i = 0;
-
+	unsigned int buf_size;
 	buf = kzalloc(sizeof(char) * DEBUG_BUF_SIZE, GFP_KERNEL);
 	if (ZERO_OR_NULL_PTR(buf)) {
 		pr_err("diag: %s, Error allocating memory\n", __func__);
 		return -ENOMEM;
 	}
+	buf_size = ksize(buf);
 
-	ret = scnprintf(buf, DEBUG_BUF_SIZE,
+	ret = scnprintf(buf, buf_size,
 		"POOL_TYPE_COPY: [0x%p : 0x%p] count = %d\n"
 		"POOL_TYPE_HDLC: [0x%p : 0x%p] count = %d\n"
 		"POOL_TYPE_USER: [0x%p : 0x%p] count = %d\n"
@@ -455,7 +463,7 @@
 	for (i = 0; i < MAX_HSIC_CH; i++) {
 		if (!diag_hsic[i].hsic_inited)
 			continue;
-		ret += scnprintf(buf+ret, DEBUG_BUF_SIZE-ret,
+		ret += scnprintf(buf+ret, buf_size-ret,
 				"POOL_TYPE_HSIC_%d: [0x%p : 0x%p] count = %d\n",
 				i+1,
 				diag_hsic[i].diag_hsic_pool,
@@ -466,7 +474,7 @@
 	for (i = 0; i < MAX_HSIC_CH; i++) {
 		if (!diag_hsic[i].hsic_inited)
 			continue;
-		ret += scnprintf(buf+ret, DEBUG_BUF_SIZE-ret,
+		ret += scnprintf(buf+ret, buf_size-ret,
 				"POOL_TYPE_HSIC_%d_WRITE: [0x%p : 0x%p] count = %d\n",
 				i+1,
 				diag_hsic[i].diag_hsic_write_pool,
@@ -485,6 +493,7 @@
 {
 	char *buf = NULL;
 	int ret = 0;
+	unsigned int buf_size;
 
 	buf = kzalloc(sizeof(char) * DEBUG_BUF_SIZE, GFP_KERNEL);
 	if (ZERO_OR_NULL_PTR(buf)) {
@@ -492,7 +501,8 @@
 		return -ENOMEM;
 	}
 
-	ret = scnprintf(buf, DEBUG_BUF_SIZE,
+	buf_size = ksize(buf);
+	ret = scnprintf(buf, buf_size,
 		"POOL_TYPE_COPY: [0x%p : 0x%p] count = %d\n"
 		"POOL_TYPE_HDLC: [0x%p : 0x%p] count = %d\n"
 		"POOL_TYPE_USER: [0x%p : 0x%p] count = %d\n"
@@ -524,13 +534,15 @@
 	char *buf;
 	int ret;
 	int i;
-	int bytes_remaining;
-	int bytes_in_buffer = 0;
-	int bytes_written;
-	int buf_size = (DEBUG_BUF_SIZE < count) ? DEBUG_BUF_SIZE : count;
+	unsigned int bytes_remaining;
+	unsigned int bytes_in_buffer = 0;
+	unsigned int bytes_written;
+	unsigned int buf_size;
 	int bytes_hsic_inited = 45;
 	int bytes_hsic_not_inited = 410;
 
+	buf_size = (DEBUG_BUF_SIZE < count) ? DEBUG_BUF_SIZE : count;
+
 	if (diag_dbgfs_finished) {
 		diag_dbgfs_finished = 0;
 		return 0;
@@ -542,6 +554,7 @@
 		return -ENOMEM;
 	}
 
+	buf_size = ksize(buf);
 	bytes_remaining = buf_size;
 
 	/* Only one smux for now */
@@ -583,8 +596,8 @@
 			"in_busy_hsic_write: %d\n"
 			"count_hsic_pool: %d\n"
 			"count_hsic_write_pool: %d\n"
-			"diag_hsic_pool: %x\n"
-			"diag_hsic_write_pool: %x\n"
+			"diag_hsic_pool: %p\n"
+			"diag_hsic_write_pool: %p\n"
 			"HSIC write_len: %d\n"
 			"num_hsic_buf_tbl_entries: %d\n"
 			"HSIC usb_connected: %d\n"
@@ -601,8 +614,8 @@
 			diag_hsic[i].in_busy_hsic_write,
 			diag_hsic[i].count_hsic_pool,
 			diag_hsic[i].count_hsic_write_pool,
-			(unsigned int)diag_hsic[i].diag_hsic_pool,
-			(unsigned int)diag_hsic[i].diag_hsic_write_pool,
+			diag_hsic[i].diag_hsic_pool,
+			diag_hsic[i].diag_hsic_write_pool,
 			diag_bridge[i].write_len,
 			diag_hsic[i].num_hsic_buf_tbl_entries,
 			diag_bridge[i].usb_connected,
diff --git a/drivers/char/diag/diag_masks.c b/drivers/char/diag/diag_masks.c
index c28b3bd..8b00ece 100644
--- a/drivers/char/diag/diag_masks.c
+++ b/drivers/char/diag/diag_masks.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2008-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
@@ -327,10 +327,10 @@
 	}
 
 	diag_send_feature_mask_update(smd_info);
-	diag_send_msg_mask_update(smd_info->ch, ALL_SSID, ALL_SSID,
+	diag_send_msg_mask_update(smd_info, ALL_SSID, ALL_SSID,
 						smd_info->peripheral);
-	diag_send_log_mask_update(smd_info->ch, ALL_EQUIP_ID);
-	diag_send_event_mask_update(smd_info->ch, diag_event_num_bytes);
+	diag_send_log_mask_update(smd_info, ALL_EQUIP_ID);
+	diag_send_event_mask_update(smd_info, diag_event_num_bytes);
 
 	if (smd_info->notify_context == SMD_EVENT_OPEN)
 		diag_send_diag_mode_update_by_smd(smd_info,
@@ -339,7 +339,7 @@
 	smd_info->notify_context = 0;
 }
 
-void diag_send_log_mask_update(smd_channel_t *ch, int equip_id)
+void diag_send_log_mask_update(struct diag_smd_info *smd_info, int equip_id)
 {
 	void *buf = driver->buf_log_mask_update;
 	struct diag_log_mask_t *log_item = NULL;
@@ -348,6 +348,12 @@
 	int wr_size = -ENOMEM, retry_count = 0;
 	int i, header_size, send_once = 0;
 
+	if (!smd_info) {
+		pr_err("diag: In %s, null smd info pointer\n",
+			__func__);
+		return;
+	}
+
 	header_size = sizeof(struct diag_ctrl_log_mask);
 	log_item = (struct diag_log_mask_t *)driver->log_masks;
 	mutex_lock(&driver->diag_cntl_mutex);
@@ -390,10 +396,12 @@
 			       log_mask_size);
 		}
 
-		if (ch) {
+		if (smd_info->ch) {
 			while (retry_count < 3) {
-				wr_size = smd_write(ch, buf,
+				mutex_lock(&smd_info->smd_ch_mutex);
+				wr_size = smd_write(smd_info->ch, buf,
 						header_size + log_mask_size);
+				mutex_unlock(&smd_info->smd_ch_mutex);
 				if (wr_size == -ENOMEM) {
 					retry_count++;
 					usleep_range(10000, 10100);
@@ -415,12 +423,18 @@
 	mutex_unlock(&driver->diag_cntl_mutex);
 }
 
-void diag_send_event_mask_update(smd_channel_t *ch, int num_bytes)
+void diag_send_event_mask_update(struct diag_smd_info *smd_info, int num_bytes)
 {
 	void *buf = driver->buf_event_mask_update;
 	int header_size = sizeof(struct diag_ctrl_event_mask);
 	int wr_size = -ENOMEM, retry_count = 0;
 
+	if (!smd_info) {
+		pr_err("diag: In %s, null smd info pointer\n",
+			__func__);
+		return;
+	}
+
 	mutex_lock(&driver->diag_cntl_mutex);
 	if (num_bytes == 0) {
 		pr_debug("diag: event mask not set yet, so no update\n");
@@ -459,9 +473,12 @@
 		return;
 	}
 	memcpy(buf, driver->event_mask, header_size);
-	if (ch) {
+	if (smd_info->ch) {
 		while (retry_count < 3) {
-			wr_size = smd_write(ch, buf, header_size + num_bytes);
+			mutex_lock(&smd_info->smd_ch_mutex);
+			wr_size = smd_write(smd_info->ch, buf,
+						header_size + num_bytes);
+			mutex_unlock(&smd_info->smd_ch_mutex);
 			if (wr_size == -ENOMEM) {
 				retry_count++;
 				usleep_range(10000, 10100);
@@ -476,14 +493,20 @@
 	mutex_unlock(&driver->diag_cntl_mutex);
 }
 
-void diag_send_msg_mask_update(smd_channel_t *ch, int updated_ssid_first,
-						int updated_ssid_last, int proc)
+void diag_send_msg_mask_update(struct diag_smd_info *smd_info,
+				int updated_ssid_first, int updated_ssid_last,
+				int proc)
 {
 	void *buf = driver->buf_msg_mask_update;
 	int first, last, actual_last, size = -ENOMEM, retry_count = 0;
 	int header_size = sizeof(struct diag_ctrl_msg_mask);
 	uint8_t *ptr = driver->msg_masks;
 
+	if (!smd_info) {
+		pr_err("diag: In %s, null smd info pointer\n",
+				__func__);
+		return;
+	}
 	mutex_lock(&driver->diag_cntl_mutex);
 	while (*(uint32_t *)(ptr + 4)) {
 		first = *(uint32_t *)ptr;
@@ -543,10 +566,12 @@
 		driver->msg_mask->ssid_first = first;
 		driver->msg_mask->ssid_last = actual_last;
 		memcpy(buf, driver->msg_mask, header_size);
-		if (ch) {
+		if (smd_info->ch) {
 			while (retry_count < 3) {
-				size = smd_write(ch, buf, header_size +
-				 4*(driver->msg_mask->msg_mask_size));
+				mutex_lock(&smd_info->smd_ch_mutex);
+				size = smd_write(smd_info->ch, buf, header_size
+					+ 4*(driver->msg_mask->msg_mask_size));
+				mutex_unlock(&smd_info->smd_ch_mutex);
 				if (size == -ENOMEM) {
 					retry_count++;
 					usleep_range(10000, 10100);
@@ -606,7 +631,9 @@
 	total_len = header_size + FEATURE_MASK_LEN_BYTES;
 
 	while (retry_count < 3) {
+		mutex_lock(&smd_info->smd_ch_mutex);
 		wr_size = smd_write(smd_info->ch, buf, total_len);
+		mutex_unlock(&smd_info->smd_ch_mutex);
 		if (wr_size == -ENOMEM) {
 			retry_count++;
 			/*
@@ -661,7 +688,7 @@
 			for (i = 0; i < NUM_SMD_CONTROL_CHANNELS; i++) {
 				if (driver->smd_cntl[i].ch)
 					diag_send_log_mask_update(
-						driver->smd_cntl[i].ch,
+						&driver->smd_cntl[i],
 						*(int *)buf);
 			}
 			encode_rsp_and_send(12 + payload_length - 1);
@@ -703,7 +730,7 @@
 			for (i = 0; i < NUM_SMD_CONTROL_CHANNELS; i++) {
 				if (driver->smd_cntl[i].ch)
 					diag_send_log_mask_update(
-						driver->smd_cntl[i].ch,
+						&driver->smd_cntl[i],
 						ALL_EQUIP_ID);
 
 			}
@@ -774,7 +801,7 @@
 			for (i = 0; i < NUM_SMD_CONTROL_CHANNELS; i++) {
 				if (driver->smd_cntl[i].ch)
 					diag_send_msg_mask_update(
-						driver->smd_cntl[i].ch,
+						&driver->smd_cntl[i],
 						ssid_first, ssid_last,
 						driver->smd_cntl[i].peripheral);
 
@@ -799,7 +826,7 @@
 			for (i = 0; i < NUM_SMD_CONTROL_CHANNELS; i++) {
 				if (driver->smd_cntl[i].ch)
 					diag_send_msg_mask_update(
-						driver->smd_cntl[i].ch,
+						&driver->smd_cntl[i],
 						ALL_SSID, ALL_SSID,
 						driver->smd_cntl[i].peripheral);
 
@@ -825,7 +852,7 @@
 			for (i = 0; i < NUM_SMD_CONTROL_CHANNELS; i++) {
 				if (driver->smd_cntl[i].ch)
 					diag_send_event_mask_update(
-						driver->smd_cntl[i].ch,
+						&driver->smd_cntl[i],
 						diag_event_num_bytes);
 			}
 			encode_rsp_and_send(6 + EVENT_LAST_ID/8);
@@ -843,7 +870,7 @@
 			for (i = 0; i < NUM_SMD_CONTROL_CHANNELS; i++) {
 				if (driver->smd_cntl[i].ch)
 					diag_send_event_mask_update(
-						driver->smd_cntl[i].ch,
+						&driver->smd_cntl[i],
 						diag_event_num_bytes);
 			}
 			encode_rsp_and_send(2);
diff --git a/drivers/char/diag/diag_masks.h b/drivers/char/diag/diag_masks.h
index 856d4fc..3ec087d 100644
--- a/drivers/char/diag/diag_masks.h
+++ b/drivers/char/diag/diag_masks.h
@@ -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
@@ -21,10 +21,10 @@
 	uint8_t ptr[MAX_ITEMS_PER_EQUIP_ID];
 } __packed;
 
-void diag_send_event_mask_update(smd_channel_t *, int num_bytes);
-void diag_send_msg_mask_update(smd_channel_t *, int ssid_first,
+void diag_send_event_mask_update(struct diag_smd_info *smd_info, int num_bytes);
+void diag_send_msg_mask_update(struct diag_smd_info *smd_info, int ssid_first,
 					 int ssid_last, int proc);
-void diag_send_log_mask_update(smd_channel_t *, int);
+void diag_send_log_mask_update(struct diag_smd_info *smd_info, int);
 void diag_mask_update_fn(struct work_struct *work);
 void diag_send_feature_mask_update(struct diag_smd_info *smd_info);
 int diag_process_apps_masks(unsigned char *buf, int len);
diff --git a/drivers/char/diag/diagchar.h b/drivers/char/diag/diagchar.h
index 606953d..95d90b3 100644
--- a/drivers/char/diag/diagchar.h
+++ b/drivers/char/diag/diagchar.h
@@ -107,6 +107,10 @@
 #define DIAG_STM_WCNSS	0x04
 #define DIAG_STM_APPS	0x08
 
+#define DIAG_DIAG_STM		0x214
+
+#define BAD_PARAM_RESPONSE_MESSAGE 20
+
 /*
  * The status bit masks when received in a signal handler are to be
  * used in conjunction with the peripheral list bit mask to determine the
@@ -237,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;
@@ -379,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 6ead0ad..93e932a 100644
--- a/drivers/char/diag/diagchar_core.c
+++ b/drivers/char/diag/diagchar_core.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2008-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
@@ -51,6 +51,7 @@
 MODULE_LICENSE("GPL v2");
 MODULE_VERSION("1.0");
 
+#define MIN_SIZ_ALLOW 4
 #define INIT	1
 #define EXIT	-1
 struct diagchar_dev *driver;
@@ -341,6 +342,9 @@
 		else if (subsys_id == 0x32 && cmd_code_hi >= 0x03  &&
 			 cmd_code_lo <= 0x03)
 			return 1;
+		else if (subsys_id == 0x57 && cmd_code_hi >= 0x0E &&
+			 cmd_code_lo <= 0x0E)
+			return 1;
 	}
 	return 0;
 }
@@ -475,8 +479,8 @@
 
 		for (i = 0; i < diag_hsic[index].poolsize_hsic_write; i++) {
 			if (hsic_buf_tbl[i].length > 0) {
-				pr_debug("diag: HSIC copy to user, i: %d, buf: %x, len: %d\n",
-					i, (unsigned int)hsic_buf_tbl[i].buf,
+				pr_debug("diag: HSIC copy to user, i: %d, buf: %p, len: %d\n",
+					i, hsic_buf_tbl[i].buf,
 					hsic_buf_tbl[i].length);
 				num_data++;
 
@@ -939,6 +943,8 @@
 		for (i = 0; i < MAX_DCI_CLIENTS; i++) {
 			if (driver->dci_client_tbl[i].client == NULL) {
 				driver->dci_client_tbl[i].client = current;
+				driver->dci_client_tbl[i].client_id =
+							driver->dci_client_id;
 				driver->dci_client_tbl[i].list =
 							 dci_params->list;
 				driver->dci_client_tbl[i].signal_type =
@@ -978,7 +984,7 @@
 			clear_client_dci_cumulative_log_mask(i);
 			/* send updated log mask to peripherals */
 			result =
-			diag_send_dci_log_mask(driver->smd_cntl[MODEM_DATA].ch);
+			diag_send_dci_log_mask(&driver->smd_cntl[MODEM_DATA]);
 			if (result != DIAG_DCI_NO_ERROR) {
 				mutex_unlock(&driver->dci_mutex);
 				return result;
@@ -988,7 +994,7 @@
 			/* send updated event mask to peripherals */
 			result =
 			diag_send_dci_event_mask(
-				driver->smd_cntl[MODEM_DATA].ch);
+				&driver->smd_cntl[MODEM_DATA]);
 			if (result != DIAG_DCI_NO_ERROR) {
 				mutex_unlock(&driver->dci_mutex);
 				return result;
@@ -1039,7 +1045,7 @@
 				 sizeof(struct diag_dci_health_stats)))
 			return -EFAULT;
 		mutex_lock(&dci_health_mutex);
-		i = diag_dci_find_client_index(current->tgid);
+		i = diag_dci_find_client_index_health(stats.client_id);
 		if (i != DCI_CLIENT_INDEX_INVALID) {
 			dci_params = &(driver->dci_client_tbl[i]);
 			stats.dropped_logs = dci_params->dropped_logs;
@@ -1117,7 +1123,7 @@
 	case DIAG_IOCTL_VOTE_REAL_TIME:
 		if (copy_from_user(&rt_vote, (void *)ioarg, sizeof(struct
 							real_time_vote_t)))
-			result = -EFAULT;
+			return -EFAULT;
 		driver->real_time_update_busy++;
 		if (rt_vote.proc == DIAG_PROC_DCI) {
 			diag_dci_set_real_time(current->tgid,
@@ -1165,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)
@@ -1194,10 +1201,9 @@
 		for (i = 0; i < driver->buf_tbl_size; i++) {
 			if (driver->buf_tbl[i].length > 0) {
 #ifdef DIAG_DEBUG
-				pr_debug("diag: WRITING the buf address "
-				       "and length is %x , %d\n", (unsigned int)
-					(driver->buf_tbl[i].buf),
-					driver->buf_tbl[i].length);
+				pr_debug("diag: WRITING the buf address and length is %p , %d\n",
+					 driver->buf_tbl[i].buf,
+					 driver->buf_tbl[i].length);
 #endif
 				num_data++;
 				/* Copy the length of data being passed */
@@ -1218,10 +1224,9 @@
 				ret += driver->buf_tbl[i].length;
 drop:
 #ifdef DIAG_DEBUG
-				pr_debug("diag: DEQUEUE buf address and"
-				       " length is %x,%d\n", (unsigned int)
-				       (driver->buf_tbl[i].buf), driver->
-				       buf_tbl[i].length);
+				pr_debug("diag: DEQUEUE buf address and length is %p, %d\n",
+					 driver->buf_tbl[i].buf,
+					 driver->buf_tbl[i].length);
 #endif
 				diagmem_free(driver, (unsigned char *)
 				(driver->buf_tbl[i].buf), POOL_TYPE_HDLC);
@@ -1246,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++;
@@ -1261,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) {
@@ -1452,6 +1463,10 @@
 	index = 0;
 	/* Get the packet type F3/log/event/Pkt response */
 	err = copy_from_user((&pkt_type), buf, 4);
+	if (err) {
+		pr_alert("diag: copy failed for pkt_type\n");
+		return -EAGAIN;
+	}
 	/* First 4 bytes indicate the type of payload - ignore these */
 	if (count < 4) {
 		pr_err("diag: Client sending short data\n");
@@ -1494,7 +1509,7 @@
 	}
 	if (pkt_type == CALLBACK_DATA_TYPE) {
 		if (payload_size > driver->itemsize) {
-			pr_err("diag: Dropping packet, packet payload size crosses 4KB limit. Current payload size %d\n",
+			pr_err("diag: Dropping packet, invalid packet size. Current payload size %d\n",
 				payload_size);
 			driver->dropped_count++;
 			return -EBADMSG;
@@ -1525,6 +1540,11 @@
 			return ret;
 		}
 		/* The packet is for the remote processor */
+		if (payload_size <= MIN_SIZ_ALLOW) {
+				pr_err("diag: Integer underflow in %s, payload size: %d",
+							__func__, payload_size);
+		return -EBADMSG;
+		}
 		token_offset = 4;
 		payload_size -= 4;
 		buf += 4;
@@ -1628,6 +1648,11 @@
 			diag_get_remote(*(int *)driver->user_space_data_buf);
 
 		if (remote_proc) {
+			if (payload_size <= MIN_SIZ_ALLOW) {
+				pr_err("diag: Integer underflow in %s, payload size: %d",
+							__func__, payload_size);
+				return -EBADMSG;
+			}
 			token_offset = 4;
 			payload_size -= 4;
 			buf += 4;
diff --git a/drivers/char/diag/diagchar_hdlc.c b/drivers/char/diag/diagchar_hdlc.c
index 3e38a3c..6f527a5 100644
--- a/drivers/char/diag/diagchar_hdlc.c
+++ b/drivers/char/diag/diagchar_hdlc.c
@@ -177,8 +177,8 @@
 	int msg_start;
 
 	if (hdlc && hdlc->src_ptr && hdlc->dest_ptr &&
-	    (hdlc->src_size - hdlc->src_idx > 0) &&
-	    (hdlc->dest_size - hdlc->dest_idx > 0)) {
+	    (hdlc->src_size > hdlc->src_idx) &&
+	    (hdlc->dest_size > hdlc->dest_idx)) {
 
 		msg_start = (hdlc->src_idx == 0) ? 1 : 0;
 
diff --git a/drivers/char/diag/diagfwd.c b/drivers/char/diag/diagfwd.c
index 395bea0..f7e720f 100644
--- a/drivers/char/diag/diagfwd.c
+++ b/drivers/char/diag/diagfwd.c
@@ -56,6 +56,8 @@
 #define STM_RSP_SMD_COMPLY_INDEX	9
 #define STM_RSP_NUM_BYTES		10
 
+#define STM_COMMAND_VALID 1
+
 #define SMD_DRAIN_BUF_SIZE 4096
 
 int diag_debug_buf_idx;
@@ -71,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",
@@ -83,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);
@@ -90,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);
 	}
 }
 
@@ -460,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
@@ -487,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 */
@@ -524,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;
@@ -531,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);
 			}
 		}
 	}
@@ -812,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;
@@ -825,10 +873,9 @@
 					driver->buf_tbl[i].length =
 								 driver->used;
 #ifdef DIAG_DEBUG
-					pr_debug("diag: ENQUEUE buf ptr"
-						   " and length is %x , %d\n",
-						   (unsigned int)(driver->buf_
-				tbl[i].buf), driver->buf_tbl[i].length);
+					pr_debug("diag: ENQUEUE buf ptr and length is %p , %d\n",
+						 driver->buf_tbl[i].buf,
+						 driver->buf_tbl[i].length);
 #endif
 					break;
 				}
@@ -860,9 +907,9 @@
 			if (foundIndex == -1)
 				err = -1;
 			else
-				pr_debug("diag: ENQUEUE HSIC buf ptr and length is %x , %d, ch %d\n",
-					(unsigned int)buf,
-					 diag_bridge[index].write_len, index);
+				pr_debug("diag: ENQUEUE HSIC buf ptr and length is %p , %d, ch %d\n",
+					 buf, diag_bridge[index].write_len,
+					 index);
 		}
 #endif
 		for (i = 0; i < driver->num_clients; i++)
@@ -918,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) {
@@ -940,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) {
@@ -1137,20 +1184,44 @@
 	}
 }
 
-int diag_process_stm_cmd(unsigned char *buf)
+int diag_process_stm_cmd(unsigned char *buf, unsigned char *dest_buf)
 {
-	uint8_t version = *(buf+STM_CMD_VERSION_OFFSET);
-	uint8_t mask = *(buf+STM_CMD_MASK_OFFSET);
-	uint8_t cmd = *(buf+STM_CMD_DATA_OFFSET);
+	uint8_t version, mask, cmd;
 	uint8_t rsp_supported = 0;
 	uint8_t rsp_smd_comply = 0;
-	int valid_command = 1;
 	int i;
 
-	/* Check if command is valid */
-	if ((version != 1) || (mask == 0) || (0 != (mask >> 4)) ||
-			(cmd != ENABLE_STM && cmd != DISABLE_STM)) {
-		valid_command = 0;
+	if (!buf || !dest_buf) {
+		pr_err("diag: Invalid pointers buf: %p, dest_buf %p in %s\n",
+		       buf, dest_buf, __func__);
+		return -EIO;
+	}
+
+	version = *(buf + STM_CMD_VERSION_OFFSET);
+	mask = *(buf + STM_CMD_MASK_OFFSET);
+	cmd = *(buf + STM_CMD_DATA_OFFSET);
+
+	/*
+	 * Check if command is valid. If the command is asking for
+	 * status, then the processor mask field is to be ignored.
+	 */
+	if ((version != 1) || (cmd > STATUS_STM) ||
+		((cmd != STATUS_STM) && ((mask == 0) || (0 != (mask >> 4))))) {
+		/* Command is invalid. Send bad param message response */
+		dest_buf[0] = BAD_PARAM_RESPONSE_MESSAGE;
+		for (i = 0; i < STM_CMD_NUM_BYTES; i++)
+			dest_buf[i+1] = *(buf + i);
+		return STM_CMD_NUM_BYTES+1;
+	} else if (cmd == STATUS_STM) {
+		/*
+		 * Only the status is being queried, so fill in whether diag
+		 * over stm is supported or not
+		 */
+		for (i = 0; i < NUM_SMD_CONTROL_CHANNELS; i++)
+			if (driver->peripheral_supports_stm[i])
+				rsp_supported |= 1 << i;
+
+		rsp_supported |= DIAG_STM_APPS;
 	} else {
 		if (mask & DIAG_STM_MODEM)
 			diag_process_stm_mask(cmd, DIAG_STM_MODEM, MODEM_DATA,
@@ -1170,15 +1241,13 @@
 	}
 
 	for (i = 0; i < STM_CMD_NUM_BYTES; i++)
-		driver->apps_rsp_buf[i] = *(buf+i);
+		dest_buf[i] = *(buf + i);
 
-	driver->apps_rsp_buf[STM_RSP_VALID_INDEX] = valid_command;
-	driver->apps_rsp_buf[STM_RSP_SUPPORTED_INDEX] = rsp_supported;
-	driver->apps_rsp_buf[STM_RSP_SMD_COMPLY_INDEX] = rsp_smd_comply;
+	dest_buf[STM_RSP_VALID_INDEX] = STM_COMMAND_VALID;
+	dest_buf[STM_RSP_SUPPORTED_INDEX] = rsp_supported;
+	dest_buf[STM_RSP_SMD_COMPLY_INDEX] = rsp_smd_comply;
 
-	encode_rsp_and_send(STM_RSP_NUM_BYTES-1);
-
-	return 0;
+	return STM_RSP_NUM_BYTES;
 }
 
 int diag_apps_responds()
@@ -1274,8 +1343,13 @@
 		encode_rsp_and_send(7);
 		return 0;
 	} else if ((*buf == 0x4b) && (*(buf+1) == 0x12) &&
-		(*(uint16_t *)(buf+2) == 0x020E)) {
-		return diag_process_stm_cmd(buf);
+		(*(uint16_t *)(buf+2) == DIAG_DIAG_STM)) {
+		len = diag_process_stm_cmd(buf, driver->apps_rsp_buf);
+		if (len > 0) {
+			encode_rsp_and_send(len - 1);
+			return 0;
+		}
+		return len;
 	}
 	/* Check for Apps Only & get event mask request */
 	else if (diag_apps_responds() && *buf == 0x81) {
@@ -1789,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,
@@ -1801,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,
@@ -1840,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);
 	}
@@ -1861,27 +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;
-	usb_diag_free_req(driver->legacy_ch);
 	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);
 			}
 		}
 	}
@@ -1901,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;
@@ -1913,6 +2009,7 @@
 			break;
 		}
 	}
+	spin_unlock_irqrestore(&data->in_busy_lock, flags);
 
 	if (found_it) {
 		if (data[i].type == SMD_DATA_TYPE)
@@ -2026,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:
@@ -2044,7 +2141,6 @@
 		break;
 	}
 }
-
 #endif /* DIAG OVER USB */
 
 void diag_smd_notify(void *ctxt, unsigned event)
@@ -2256,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:
@@ -2569,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);
@@ -2616,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)
@@ -2626,8 +2726,6 @@
 		diag_smd_destructor(&driver->smd_data[i]);
 
 #ifdef CONFIG_DIAG_OVER_USB
-	if (driver->usb_connected)
-		usb_diag_free_req(driver->legacy_ch);
 	usb_diag_close(driver->legacy_ch);
 #endif
 	platform_driver_unregister(&msm_smd_ch1_driver);
@@ -2655,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/char/diag/diagfwd_bridge.c b/drivers/char/diag/diagfwd_bridge.c
index 143959b..142d15a 100644
--- a/drivers/char/diag/diagfwd_bridge.c
+++ b/drivers/char/diag/diagfwd_bridge.c
@@ -133,7 +133,6 @@
 			/* If the usb cable is being disconnected */
 			if (process_cable) {
 				diag_bridge[i].usb_connected = 0;
-				usb_diag_free_req(diag_bridge[i].ch);
 			}
 
 			if (i == SMUX) {
@@ -383,8 +382,6 @@
 	for (i = 0; i < MAX_BRIDGES; i++) {
 		if (diag_bridge[i].enabled) {
 #ifdef CONFIG_DIAG_OVER_USB
-			if (diag_bridge[i].usb_connected)
-				usb_diag_free_req(diag_bridge[i].ch);
 			usb_diag_close(diag_bridge[i].ch);
 #endif
 			kfree(diag_bridge[i].usb_buf_out);
diff --git a/drivers/char/diag/diagfwd_cntl.c b/drivers/char/diag/diagfwd_cntl.c
index d3c311d..a75f7f69 100644
--- a/drivers/char/diag/diagfwd_cntl.c
+++ b/drivers/char/diag/diagfwd_cntl.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
@@ -349,10 +349,19 @@
 	int wr_size = -ENOMEM, retry_count = 0, timer;
 	struct diag_smd_info *data = NULL;
 
-	/* For now only allow the modem to receive the message */
-	if (!smd_info || smd_info->type != SMD_CNTL_TYPE ||
-		(smd_info->peripheral != MODEM_DATA))
+	if (!smd_info || smd_info->type != SMD_CNTL_TYPE) {
+		pr_err("diag: In %s, invalid channel info, smd_info: %p type: %d\n",
+					__func__, smd_info,
+					((smd_info) ? smd_info->type : -1));
 		return;
+	}
+
+	if (smd_info->peripheral < MODEM_DATA ||
+					smd_info->peripheral > WCNSS_DATA) {
+		pr_err("diag: In %s, invalid peripheral %d\n", __func__,
+							smd_info->peripheral);
+		return;
+	}
 
 	data = &driver->smd_data[smd_info->peripheral];
 	if (!data)
@@ -380,7 +389,9 @@
 
 	if (smd_info->ch) {
 		while (retry_count < 3) {
+			mutex_lock(&smd_info->smd_ch_mutex);
 			wr_size = smd_write(smd_info->ch, buf, msg_size);
+			mutex_unlock(&smd_info->smd_ch_mutex);
 			if (wr_size == -ENOMEM) {
 				/*
 				 * The smd channel is full. Delay while
@@ -433,7 +444,9 @@
 		stm_msg.version = 1;
 		stm_msg.control_data = stm_control_data;
 		while (retry_count < 3) {
+			mutex_lock(&smd_info->smd_ch_mutex);
 			wr_size = smd_write(smd_info->ch, &stm_msg, msg_size);
+			mutex_unlock(&smd_info->smd_ch_mutex);
 			if (wr_size == -ENOMEM) {
 				/*
 				 * The smd channel is full. Delay while
diff --git a/drivers/char/diag/diagfwd_cntl.h b/drivers/char/diag/diagfwd_cntl.h
index d79195c..7f5ea03 100644
--- a/drivers/char/diag/diagfwd_cntl.h
+++ b/drivers/char/diag/diagfwd_cntl.h
@@ -54,8 +54,9 @@
 #define ENABLE_SEPARATE_CMDRSP	1
 #define DISABLE_SEPARATE_CMDRSP	0
 
-#define ENABLE_STM	1
 #define DISABLE_STM	0
+#define ENABLE_STM	1
+#define STATUS_STM	2
 
 #define UPDATE_PERIPHERAL_STM_STATE	1
 #define CLEAR_PERIPHERAL_STM_STATE	2
diff --git a/drivers/char/diag/diagfwd_sdio.c b/drivers/char/diag/diagfwd_sdio.c
index 7d4e0d5..ef56a1b 100644
--- a/drivers/char/diag/diagfwd_sdio.c
+++ b/drivers/char/diag/diagfwd_sdio.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011, 2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -131,7 +131,6 @@
 
 int diagfwd_disconnect_sdio(void)
 {
-	usb_diag_free_req(driver->mdm_ch);
 	if (driver->sdio_ch && (driver->logging_mode == USB_MODE)) {
 		driver->in_busy_sdio = 1;
 		diag_sdio_close();
@@ -280,10 +279,6 @@
 
 void diagfwd_sdio_exit(void)
 {
-#ifdef CONFIG_DIAG_OVER_USB
-	if (driver->usb_connected)
-		usb_diag_free_req(driver->mdm_ch);
-#endif
 	platform_driver_unregister(&msm_sdio_ch_driver);
 #ifdef CONFIG_DIAG_OVER_USB
 	usb_diag_close(driver->mdm_ch);
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/coresight/coresight-tmc.c b/drivers/coresight/coresight-tmc.c
index f35ba53..0c7c9e0 100644
--- a/drivers/coresight/coresight-tmc.c
+++ b/drivers/coresight/coresight-tmc.c
@@ -177,6 +177,7 @@
 	bool			byte_cntr_read_active;
 	wait_queue_head_t	wq;
 	char			*byte_cntr_node;
+	uint32_t		mem_size;
 };
 
 static void tmc_wait_for_flush(struct tmc_drvdata *drvdata)
@@ -1310,6 +1311,32 @@
 static DEVICE_ATTR(byte_cntr_value, S_IRUGO | S_IWUSR,
 		   tmc_etr_show_byte_cntr_value, tmc_etr_store_byte_cntr_value);
 
+static ssize_t tmc_etr_show_mem_size(struct device *dev,
+				     struct device_attribute *attr,
+				     char *buf)
+{
+	struct tmc_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	unsigned long val = drvdata->mem_size;
+
+	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+}
+
+static ssize_t tmc_etr_store_mem_size(struct device *dev,
+				      struct device_attribute *attr,
+				      const char *buf, size_t size)
+{
+	struct tmc_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	unsigned long val;
+
+	if (sscanf(buf, "%lx", &val) != 1)
+		return -EINVAL;
+
+	drvdata->mem_size = val;
+	return size;
+}
+static DEVICE_ATTR(mem_size, S_IRUGO | S_IWUSR,
+		   tmc_etr_show_mem_size, tmc_etr_store_mem_size);
+
 static struct attribute *tmc_attrs[] = {
 	&dev_attr_trigger_cntr.attr,
 	NULL,
@@ -1322,6 +1349,7 @@
 static struct attribute *tmc_etr_attrs[] = {
 	&dev_attr_out_mode.attr,
 	&dev_attr_byte_cntr_value.attr,
+	&dev_attr_mem_size.attr,
 	NULL,
 };
 
diff --git a/drivers/cpufreq/cpu-boost.c b/drivers/cpufreq/cpu-boost.c
index 8cd5ef9..b4aec53 100644
--- a/drivers/cpufreq/cpu-boost.c
+++ b/drivers/cpufreq/cpu-boost.c
@@ -1,5 +1,5 @@
 /*
- * 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
@@ -17,6 +17,7 @@
 #include <linux/init.h>
 #include <linux/notifier.h>
 #include <linux/cpufreq.h>
+#include <linux/cpu.h>
 #include <linux/sched.h>
 #include <linux/jiffies.h>
 #include <linux/kthread.h>
@@ -62,6 +63,12 @@
  * The CPUFREQ_ADJUST notifier is used to override the current policy min to
  * make sure policy min >= boost_min. The cpufreq framework then does the job
  * of enforcing the new policy.
+ *
+ * The sync kthread needs to run on the CPU in question to avoid deadlocks in
+ * the wake up code. Achieve this by binding the thread to the respective
+ * CPU. But a CPU going offline unbinds threads from that CPU. So, set it up
+ * again each time the CPU comes back up. We can use CPUFREQ_START to figure
+ * out a CPU is coming online instead of registering for hotplug notifiers.
  */
 static int boost_adjust_notify(struct notifier_block *nb, unsigned long val, void *data)
 {
@@ -72,22 +79,27 @@
 	unsigned int ib_min = s->input_boost_min;
 	unsigned int min;
 
-	if (val != CPUFREQ_ADJUST)
-		return NOTIFY_OK;
+	switch (val) {
+	case CPUFREQ_ADJUST:
+		if (!b_min && !ib_min)
+			break;
 
-	if (!b_min && !ib_min)
-		return NOTIFY_OK;
+		min = max(b_min, ib_min);
 
-	min = max(b_min, ib_min);
+		pr_debug("CPU%u policy min before boost: %u kHz\n",
+			 cpu, policy->min);
+		pr_debug("CPU%u boost min: %u kHz\n", cpu, min);
 
-	pr_debug("CPU%u policy min before boost: %u kHz\n",
-		 cpu, policy->min);
-	pr_debug("CPU%u boost min: %u kHz\n", cpu, min);
+		cpufreq_verify_within_limits(policy, min, UINT_MAX);
 
-	cpufreq_verify_within_limits(policy, min, UINT_MAX);
+		pr_debug("CPU%u policy min after boost: %u kHz\n",
+			 cpu, policy->min);
+		break;
 
-	pr_debug("CPU%u policy min after boost: %u kHz\n",
-		 cpu, policy->min);
+	case CPUFREQ_START:
+		set_cpus_allowed(s->thread, *cpumask_of(cpu));
+		break;
+	}
 
 	return NOTIFY_OK;
 }
@@ -165,9 +177,15 @@
 			s->boost_min = src_policy.cur;
 		}
 		/* Force policy re-evaluation to trigger adjust notifier. */
-		cpufreq_update_policy(dest_cpu);
-		queue_delayed_work_on(s->cpu, cpu_boost_wq,
-			&s->boost_rem, msecs_to_jiffies(boost_ms));
+		get_online_cpus();
+		if (cpu_online(dest_cpu)) {
+			cpufreq_update_policy(dest_cpu);
+			queue_delayed_work_on(dest_cpu, cpu_boost_wq,
+				&s->boost_rem, msecs_to_jiffies(boost_ms));
+		} else {
+			s->boost_min = 0;
+		}
+		put_online_cpus();
 	}
 
 	return 0;
@@ -202,6 +220,7 @@
 	struct cpu_sync *i_sync_info;
 	struct cpufreq_policy policy;
 
+	get_online_cpus();
 	for_each_online_cpu(i) {
 
 		i_sync_info = &per_cpu(sync_info, i);
@@ -218,6 +237,7 @@
 			&i_sync_info->input_boost_rem,
 			msecs_to_jiffies(input_boost_ms));
 	}
+	put_online_cpus();
 }
 
 static void cpuboost_input_event(struct input_handle *handle,
@@ -315,8 +335,6 @@
 	int cpu, ret;
 	struct cpu_sync *s;
 
-	cpufreq_register_notifier(&boost_adjust_nb, CPUFREQ_POLICY_NOTIFIER);
-
 	cpu_boost_wq = alloc_workqueue("cpuboost_wq", WQ_HIGHPRI, 0);
 	if (!cpu_boost_wq)
 		return -EFAULT;
@@ -332,11 +350,13 @@
 		INIT_DELAYED_WORK(&s->input_boost_rem, do_input_boost_rem);
 		s->thread = kthread_run(boost_mig_sync_thread, (void *)cpu,
 					"boost_sync/%d", cpu);
+		set_cpus_allowed(s->thread, *cpumask_of(cpu));
 	}
+	cpufreq_register_notifier(&boost_adjust_nb, CPUFREQ_POLICY_NOTIFIER);
 	atomic_notifier_chain_register(&migration_notifier_head,
 					&boost_migration_nb);
-
 	ret = input_register_handler(&cpuboost_input_handler);
+
 	return 0;
 }
 late_initcall(cpu_boost_init);
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index 975a42f..4605685 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -1726,7 +1726,8 @@
 	memcpy(&policy->cpuinfo, &data->cpuinfo,
 				sizeof(struct cpufreq_cpuinfo));
 
-	if (policy->min > data->max || policy->max < data->min) {
+	if (policy->min > data->user_policy.max
+		|| policy->max < data->user_policy.min) {
 		ret = -EINVAL;
 		goto error_out;
 	}
diff --git a/drivers/cpufreq/cpufreq_interactive.c b/drivers/cpufreq/cpufreq_interactive.c
index 22448a1..3a964a5 100644
--- a/drivers/cpufreq/cpufreq_interactive.c
+++ b/drivers/cpufreq/cpufreq_interactive.c
@@ -124,11 +124,14 @@
 static bool io_is_busy;
 
 /*
- * If the max load among the other CPUs is higher than sync_freq_load_threshold
- * then do not let the frequency to drop below sync_freq
+ * If the max load among other CPUs is higher than up_threshold_any_cpu_load
+ * and if the highest frequency among the other CPUs is higher than
+ * up_threshold_any_cpu_freq then do not let the frequency to drop below
+ * sync_freq
  */
-static unsigned int sync_freq_load_threshold;
+static unsigned int up_threshold_any_cpu_load;
 static unsigned int sync_freq;
+static unsigned int up_threshold_any_cpu_freq;
 
 static int cpufreq_governor_interactive(struct cpufreq_policy *policy,
 		unsigned int event);
@@ -393,8 +396,9 @@
 	unsigned long flags;
 	bool boosted;
 	unsigned long mod_min_sample_time;
-	int i, max_load_other_cpu;
-	unsigned int max_freq_other_cpu;
+	int i, max_load;
+	unsigned int max_freq;
+	struct cpufreq_interactive_cpuinfo *picpu;
 
 	if (!down_read_trylock(&pcpu->enable_sem))
 		return;
@@ -416,20 +420,6 @@
 	pcpu->prev_load = cpu_load;
 	boosted = boost_val || now < boostpulse_endtime;
 
-	max_load_other_cpu = 0;
-	max_freq_other_cpu = 0;
-	for_each_online_cpu(i) {
-		struct cpufreq_interactive_cpuinfo *picpu =
-						&per_cpu(cpuinfo, i);
-		if (i == data)
-			continue;
-		if (max_load_other_cpu < picpu->prev_load)
-			max_load_other_cpu = picpu->prev_load;
-
-		if (picpu->policy->cur > max_freq_other_cpu)
-			max_freq_other_cpu = picpu->policy->cur;
-	}
-
 	if (cpu_load >= go_hispeed_load || boosted) {
 		if (pcpu->target_freq < hispeed_freq) {
 			new_freq = hispeed_freq;
@@ -441,10 +431,27 @@
 		}
 	} else {
 		new_freq = choose_freq(pcpu, loadadjfreq);
-		if (sync_freq && (max_freq_other_cpu > sync_freq) &&
-			(max_load_other_cpu > sync_freq_load_threshold) &&
-				(new_freq < sync_freq))
-			new_freq = sync_freq;
+
+		if (sync_freq && new_freq < sync_freq) {
+
+			max_load = 0;
+			max_freq = 0;
+
+			for_each_online_cpu(i) {
+				picpu = &per_cpu(cpuinfo, i);
+
+				if (i == data || picpu->prev_load <
+						up_threshold_any_cpu_load)
+					continue;
+
+				max_load = max(max_load, picpu->prev_load);
+				max_freq = max(max_freq, picpu->target_freq);
+			}
+
+			if (max_freq > up_threshold_any_cpu_freq &&
+				max_load >= up_threshold_any_cpu_load)
+				new_freq = sync_freq;
+		}
 	}
 
 	if (pcpu->target_freq >= hispeed_freq &&
@@ -470,11 +477,10 @@
 	 * Do not scale below floor_freq unless we have been at or above the
 	 * floor frequency for the minimum sample time since last validated.
 	 */
-	if (pcpu->policy->cur == pcpu->policy->max) {
+	if (sampling_down_factor && pcpu->policy->cur == pcpu->policy->max)
 		mod_min_sample_time = sampling_down_factor;
-	} else {
+	else
 		mod_min_sample_time = min_sample_time;
-	}
 
 	if (new_freq < pcpu->floor_freq) {
 		if (now - pcpu->floor_validate_time < mod_min_sample_time) {
@@ -1121,13 +1127,13 @@
 static struct global_attr sync_freq_attr = __ATTR(sync_freq, 0644,
 		show_sync_freq, store_sync_freq);
 
-static ssize_t show_sync_freq_load_threshold(struct kobject *kobj,
+static ssize_t show_up_threshold_any_cpu_load(struct kobject *kobj,
 			struct attribute *attr, char *buf)
 {
-	return sprintf(buf, "%u\n", sync_freq_load_threshold);
+	return snprintf(buf, PAGE_SIZE, "%u\n", up_threshold_any_cpu_load);
 }
 
-static ssize_t store_sync_freq_load_threshold(struct kobject *kobj,
+static ssize_t store_up_threshold_any_cpu_load(struct kobject *kobj,
 			struct attribute *attr, const char *buf, size_t count)
 {
 	int ret;
@@ -1136,14 +1142,38 @@
 	ret = kstrtoul(buf, 0, &val);
 	if (ret < 0)
 		return ret;
-	sync_freq_load_threshold = val;
+	up_threshold_any_cpu_load = val;
 	return count;
 }
 
-static struct global_attr sync_freq_load_threshold_attr =
-		__ATTR(sync_freq_load_threshold, 0644,
-		show_sync_freq_load_threshold, store_sync_freq_load_threshold);
+static struct global_attr up_threshold_any_cpu_load_attr =
+		__ATTR(up_threshold_any_cpu_load, 0644,
+		show_up_threshold_any_cpu_load,
+				store_up_threshold_any_cpu_load);
 
+static ssize_t show_up_threshold_any_cpu_freq(struct kobject *kobj,
+			struct attribute *attr, char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "%u\n", up_threshold_any_cpu_freq);
+}
+
+static ssize_t store_up_threshold_any_cpu_freq(struct kobject *kobj,
+			struct attribute *attr, const char *buf, size_t count)
+{
+	int ret;
+	unsigned long val;
+
+	ret = kstrtoul(buf, 0, &val);
+	if (ret < 0)
+		return ret;
+	up_threshold_any_cpu_freq = val;
+	return count;
+}
+
+static struct global_attr up_threshold_any_cpu_freq_attr =
+		__ATTR(up_threshold_any_cpu_freq, 0644,
+		show_up_threshold_any_cpu_freq,
+				store_up_threshold_any_cpu_freq);
 
 static struct attribute *interactive_attributes[] = {
 	&target_loads_attr.attr,
@@ -1159,7 +1189,8 @@
 	&io_is_busy_attr.attr,
 	&sampling_down_factor_attr.attr,
 	&sync_freq_attr.attr,
-	&sync_freq_load_threshold_attr.attr,
+	&up_threshold_any_cpu_load_attr.attr,
+	&up_threshold_any_cpu_freq_attr.attr,
 	NULL,
 };
 
@@ -1219,6 +1250,8 @@
 			pcpu->hispeed_validate_time =
 				pcpu->floor_validate_time;
 			down_write(&pcpu->enable_sem);
+			del_timer_sync(&pcpu->cpu_timer);
+			del_timer_sync(&pcpu->cpu_slack_timer);
 			cpufreq_interactive_timer_start(j);
 			pcpu->governor_enabled = 1;
 			up_write(&pcpu->enable_sem);
@@ -1252,6 +1285,7 @@
 			pcpu = &per_cpu(cpuinfo, j);
 			down_write(&pcpu->enable_sem);
 			pcpu->governor_enabled = 0;
+			pcpu->target_freq = 0;
 			del_timer_sync(&pcpu->cpu_timer);
 			del_timer_sync(&pcpu->cpu_slack_timer);
 			up_write(&pcpu->enable_sem);
diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c
index 8f7d39c..7f8b4cd 100644
--- a/drivers/cpufreq/cpufreq_ondemand.c
+++ b/drivers/cpufreq/cpufreq_ondemand.c
@@ -978,14 +978,8 @@
 			dbs_info->sample_type = DBS_SUB_SAMPLE;
 			delay = dbs_info->freq_hi_jiffies;
 		} else {
-			/* We want all CPUs to do sampling nearly on
-			 * same jiffy
-			 */
 			delay = usecs_to_jiffies(dbs_tuners_ins.sampling_rate
 				* dbs_info->rate_mult);
-
-			if (num_online_cpus() > 1)
-				delay -= jiffies % delay;
 		}
 	} else {
 		__cpufreq_driver_target(dbs_info->cur_policy,
diff --git a/drivers/crypto/msm/ota_crypto.c b/drivers/crypto/msm/ota_crypto.c
index 5051a3a..6ecf5b2 100644
--- a/drivers/crypto/msm/ota_crypto.c
+++ b/drivers/crypto/msm/ota_crypto.c
@@ -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
@@ -674,50 +674,50 @@
 	struct ota_qce_dev *p;
 
 	pstat = &_qcota_stat;
-	len = snprintf(_debug_read_buf, DEBUG_MAX_RW_BUF - 1,
+	len = scnprintf(_debug_read_buf, DEBUG_MAX_RW_BUF - 1,
 			"\nQualcomm OTA crypto accelerator Statistics:\n");
 
-	len += snprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
+	len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
 			"   F8 request             : %d\n",
 					pstat->f8_req);
-	len += snprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
+	len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
 			"   F8 operation success   : %d\n",
 					pstat->f8_op_success);
-	len += snprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
+	len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
 			"   F8 operation fail      : %d\n",
 					pstat->f8_op_fail);
 
-	len += snprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
+	len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
 			"   F8 MP request          : %d\n",
 					pstat->f8_mp_req);
-	len += snprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
+	len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
 			"   F8 MP operation success: %d\n",
 					pstat->f8_mp_op_success);
-	len += snprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
+	len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
 			"   F8 MP operation fail   : %d\n",
 					pstat->f8_mp_op_fail);
 
-	len += snprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
+	len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
 			"   F9 request             : %d\n",
 					pstat->f9_req);
-	len += snprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
+	len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
 			"   F9 operation success   : %d\n",
 					pstat->f9_op_success);
-	len += snprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
+	len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
 			"   F9 operation fail      : %d\n",
 					pstat->f9_op_fail);
 
 	spin_lock_irqsave(&podev->lock, flags);
 
 	list_for_each_entry(p, &podev->qce_dev, qlist) {
-		len += snprintf(
+		len += scnprintf(
 			_debug_read_buf + len,
 			DEBUG_MAX_RW_BUF - len - 1,
 			"   Engine %d Req          : %d\n",
 			p->unit,
 			p->totalReq
 		);
-		len += snprintf(
+		len += scnprintf(
 			_debug_read_buf + len,
 			DEBUG_MAX_RW_BUF - len - 1,
 			"   Engine %d Req Error    : %d\n",
diff --git a/drivers/crypto/msm/qce.c b/drivers/crypto/msm/qce.c
index 8037187..d11a831 100644
--- a/drivers/crypto/msm/qce.c
+++ b/drivers/crypto/msm/qce.c
@@ -1,6 +1,6 @@
 /* Qualcomm Crypto Engine driver.
  *
- * 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
@@ -422,7 +422,7 @@
 {
 	unsigned n;
 
-	n = len  / sizeof(uint32_t) ;
+	n = len  / sizeof(uint32_t);
 	for (; n > 0; n--) {
 		*iv =  ((*b << 24)      & 0xff000000) |
 				(((*(b+1)) << 16) & 0xff0000)   |
@@ -436,12 +436,12 @@
 	if (n == 3) {
 		*iv = ((*b << 24) & 0xff000000) |
 				(((*(b+1)) << 16) & 0xff0000)   |
-				(((*(b+2)) << 8) & 0xff00)     ;
+				(((*(b+2)) << 8) & 0xff00);
 	} else if (n == 2) {
 		*iv = ((*b << 24) & 0xff000000) |
-				(((*(b+1)) << 16) & 0xff0000)   ;
+				(((*(b+1)) << 16) & 0xff0000);
 	} else if (n == 1) {
-		*iv = ((*b << 24) & 0xff000000) ;
+		*iv = ((*b << 24) & 0xff000000);
 	}
 }
 
@@ -1819,7 +1819,7 @@
 	}
 };
 
-static int _ce_f9_setup(struct qce_device *pce_dev, struct qce_f9_req * req)
+static int _ce_f9_setup(struct qce_device *pce_dev, struct qce_f9_req *req)
 {
 	uint32_t cfg;
 	uint32_t ikey[OTA_KEY_SIZE/sizeof(uint32_t)];
@@ -1846,7 +1846,7 @@
 	if (req->algorithm == QCE_OTA_ALGO_KASUMI)
 		cfg |= (CRYPTO_AUTH_SIZE_UIA1 << CRYPTO_AUTH_SIZE);
 	else
-		cfg |= (CRYPTO_AUTH_SIZE_UIA2 << CRYPTO_AUTH_SIZE) ;
+		cfg |= (CRYPTO_AUTH_SIZE_UIA2 << CRYPTO_AUTH_SIZE);
 
 	if (req->direction == QCE_OTA_DIR_DOWNLINK)
 		cfg |= 1 << CRYPTO_F9_DIRECTION;
@@ -1885,7 +1885,7 @@
 	if (req->algorithm == QCE_OTA_ALGO_KASUMI)
 		cfg |= (CRYPTO_ENCR_KEY_SZ_UEA1 << CRYPTO_ENCR_KEY_SZ);
 	else
-		cfg |= (CRYPTO_ENCR_KEY_SZ_UEA2 << CRYPTO_ENCR_KEY_SZ) ;
+		cfg |= (CRYPTO_ENCR_KEY_SZ_UEA2 << CRYPTO_ENCR_KEY_SZ);
 	if (key_stream_mode)
 		cfg |= 1 << CRYPTO_F8_KEYSTREAM_ENABLE;
 	if (req->direction == QCE_OTA_DIR_DOWNLINK)
@@ -1932,6 +1932,9 @@
 	return 0;
 };
 
+struct qce_pm_table qce_pm_table = {NULL, NULL};
+EXPORT_SYMBOL(qce_pm_table);
+
 int qce_aead_req(void *handle, struct qce_req *q_req)
 {
 	struct qce_device *pce_dev = (struct qce_device *) handle;
@@ -2555,7 +2558,7 @@
 	rc = _ce_f8_setup(pce_dev, req, false, num_pkt, cipher_start,
 			cipher_size);
 	if (rc)
-		goto bad ;
+		goto bad;
 
 	/* setup for callback, and issue command to adm */
 	pce_dev->areq = cookie;
diff --git a/drivers/crypto/msm/qce.h b/drivers/crypto/msm/qce.h
index afd5141..6ba5063 100644
--- a/drivers/crypto/msm/qce.h
+++ b/drivers/crypto/msm/qce.h
@@ -1,6 +1,6 @@
 /* Qualcomm Crypto Engine driver API
  *
- * 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
@@ -116,6 +116,14 @@
 	bool bam;
 	bool is_shared;
 	bool hw_key;
+	bool use_sw_aes_cbc_ecb_ctr_algo;
+	bool use_sw_aead_algo;
+	bool use_sw_aes_xts_algo;
+	bool use_sw_ahash_algo;
+	bool use_sw_hmac_algo;
+	bool use_sw_aes_ccm_algo;
+	bool clk_mgmt_sus_res;
+	unsigned int ce_device;
 };
 
 /* Sha operation parameters */
@@ -158,6 +166,13 @@
 	unsigned int  flags;
 };
 
+struct qce_pm_table {
+	int (*suspend)(void *handle);
+	int (*resume)(void *handle);
+};
+
+extern struct qce_pm_table qce_pm_table;
+
 void *qce_open(struct platform_device *pdev, int *rc);
 int qce_close(void *handle);
 int qce_aead_req(void *handle, struct qce_req *req);
diff --git a/drivers/crypto/msm/qce50.c b/drivers/crypto/msm/qce50.c
index a4154c1..ad7dd31 100644
--- a/drivers/crypto/msm/qce50.c
+++ b/drivers/crypto/msm/qce50.c
@@ -1,6 +1,6 @@
 /* Qualcomm Crypto Engine driver.
  *
- * 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
@@ -38,6 +38,7 @@
 #include "qce.h"
 #include "qce50.h"
 #include "qcryptohw_50.h"
+#include "qce_ota.h"
 
 #define CRYPTO_CONFIG_RESET 0xE001F
 #define QCE_MAX_NUM_DSCR    0x500
@@ -72,6 +73,7 @@
 	int is_shared;			/* CE HW is shared */
 	bool support_cmd_dscr;
 	bool support_hw_key;
+	bool support_clk_mgmt_sus_res;
 
 	void __iomem *iobase;	    /* Virtual io base of CE HW  */
 	unsigned int phy_iobase;    /* Physical io base of CE HW    */
@@ -96,6 +98,17 @@
 	enum qce_cipher_mode_enum mode;
 	struct qce_ce_cfg_reg_setting reg;
 	struct ce_sps_data ce_sps;
+	uint32_t engines_avail;
+	dma_addr_t phy_ota_src;
+	dma_addr_t phy_ota_dst;
+	unsigned int ota_size;
+
+	bool use_sw_aes_cbc_ecb_ctr_algo;
+	bool use_sw_aead_algo;
+	bool use_sw_aes_xts_algo;
+	bool use_sw_ahash_algo;
+	bool use_sw_hmac_algo;
+	bool use_sw_aes_ccm_algo;
 };
 
 /* Standard initialization vector for SHA-1, source: FIPS 180-2 */
@@ -114,7 +127,7 @@
 {
 	unsigned n;
 
-	n = len  / sizeof(uint32_t) ;
+	n = len  / sizeof(uint32_t);
 	for (; n > 0; n--) {
 		*iv =  ((*b << 24)      & 0xff000000) |
 				(((*(b+1)) << 16) & 0xff0000)   |
@@ -128,12 +141,12 @@
 	if (n == 3) {
 		*iv = ((*b << 24) & 0xff000000) |
 				(((*(b+1)) << 16) & 0xff0000)   |
-				(((*(b+2)) << 8) & 0xff00)     ;
+				(((*(b+2)) << 8) & 0xff00);
 	} else if (n == 2) {
 		*iv = ((*b << 24) & 0xff000000) |
-				(((*(b+1)) << 16) & 0xff0000)   ;
+				(((*(b+1)) << 16) & 0xff0000);
 	} else if (n == 1) {
-		*iv = ((*b << 24) & 0xff000000) ;
+		*iv = ((*b << 24) & 0xff000000);
 	}
 }
 
@@ -202,22 +215,28 @@
 	};
 	pce_dev->ce_sps.minor_version = min_rev;
 
+	pce_dev->engines_avail = readl_relaxed(pce_dev->iobase +
+					CRYPTO_ENGINES_AVAIL);
 	dev_info(pce_dev->pdev, "Qualcomm Crypto %d.%d.%d device found @0x%x\n",
 			maj_rev, min_rev, step_rev, pce_dev->phy_iobase);
 
 	pce_dev->ce_sps.ce_burst_size = MAX_CE_BAM_BURST_SIZE;
 
 	dev_info(pce_dev->pdev,
+			"CE device = 0x%x\n, "
 			"IO base, CE = 0x%x\n, "
 			"Consumer (IN) PIPE %d,    "
 			"Producer (OUT) PIPE %d\n"
 			"IO base BAM = 0x%x\n"
-			"BAM IRQ %d\n",
+			"BAM IRQ %d\n"
+			"Engines Availability = 0x%x\n",
+			(uint32_t) pce_dev->ce_sps.ce_device,
 			(uint32_t) pce_dev->iobase,
 			pce_dev->ce_sps.dest_pipe_index,
 			pce_dev->ce_sps.src_pipe_index,
 			(uint32_t)pce_dev->ce_sps.bam_iobase,
-			pce_dev->ce_sps.bam_irq);
+			pce_dev->ce_sps.bam_irq,
+			pce_dev->engines_avail);
 	return 0;
 };
 
@@ -268,31 +287,38 @@
 			0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
 	bool sha1 = false;
 	struct sps_command_element *pce = NULL;
+	bool use_hw_key = false;
+	bool use_pipe_key = false;
+	uint32_t authk_size_in_word = sreq->authklen/sizeof(uint32_t);
+	uint32_t auth_cfg;
 
 	if ((sreq->alg == QCE_HASH_SHA1_HMAC) ||
 			(sreq->alg == QCE_HASH_SHA256_HMAC) ||
 			(sreq->alg ==  QCE_HASH_AES_CMAC)) {
-		uint32_t authk_size_in_word = sreq->authklen/sizeof(uint32_t);
 
-		_byte_stream_to_net_words(mackey32, sreq->authkey,
-						sreq->authklen);
 
-		/* check for null key. If null, use hw key*/
-		for (i = 0; i < authk_size_in_word; i++) {
-			if (mackey32[i] != 0)
-				break;
-		}
-
+		/* no more check for null key. use flag */
+		if ((sreq->flags & QCRYPTO_CTX_USE_HW_KEY)
+						== QCRYPTO_CTX_USE_HW_KEY)
+			use_hw_key = true;
+		else if ((sreq->flags & QCRYPTO_CTX_USE_PIPE_KEY) ==
+						QCRYPTO_CTX_USE_PIPE_KEY)
+			use_pipe_key = true;
 		pce = cmdlistinfo->go_proc;
-		if (i == authk_size_in_word) {
+		if (use_hw_key == true) {
 			pce->addr = (uint32_t)(CRYPTO_GOPROC_QC_KEY_REG +
 							pce_dev->phy_iobase);
 		} else {
 			pce->addr = (uint32_t)(CRYPTO_GOPROC_REG +
 							pce_dev->phy_iobase);
 			pce = cmdlistinfo->auth_key;
-			for (i = 0; i < authk_size_in_word; i++, pce++)
-				pce->data = mackey32[i];
+			if (use_pipe_key == false) {
+				_byte_stream_to_net_words(mackey32,
+						sreq->authkey,
+						sreq->authklen);
+				for (i = 0; i < authk_size_in_word; i++, pce++)
+					pce->data = mackey32[i];
+			}
 		}
 	}
 
@@ -347,14 +373,19 @@
 
 	/* Set/reset  last bit in CFG register  */
 	pce = cmdlistinfo->auth_seg_cfg;
+	auth_cfg = pce->data & ~(1 << CRYPTO_LAST |
+				1 << CRYPTO_FIRST |
+				1 << CRYPTO_USE_PIPE_KEY_AUTH |
+				1 << CRYPTO_USE_HW_KEY_AUTH);
 	if (sreq->last_blk)
-		pce->data |= 1 << CRYPTO_LAST;
-	else
-		pce->data &= ~(1 << CRYPTO_LAST);
+		auth_cfg |= 1 << CRYPTO_LAST;
 	if (sreq->first_blk)
-		pce->data |= 1 << CRYPTO_FIRST;
-	else
-		pce->data &= ~(1 << CRYPTO_FIRST);
+		auth_cfg |= 1 << CRYPTO_FIRST;
+	if (use_hw_key)
+		auth_cfg |= 1 << CRYPTO_USE_HW_KEY_AUTH;
+	if (use_pipe_key)
+		auth_cfg |= 1 << CRYPTO_USE_PIPE_KEY_AUTH;
+	pce->data = auth_cfg;
 go_proc:
 	/* write auth seg size */
 	pce = cmdlistinfo->auth_seg_size;
@@ -443,7 +474,7 @@
 		uint32_t totallen_in, uint32_t coffset,
 		struct qce_cmdlist_info *cmdlistinfo)
 {
-	int32_t authk_size_in_word = q_req->authklen/sizeof(uint32_t);
+	int32_t authk_size_in_word = SHA_HMAC_KEY_SIZE/sizeof(uint32_t);
 	int i;
 	uint32_t mackey32[SHA_HMAC_KEY_SIZE/sizeof(uint32_t)] = {0};
 	struct sps_command_element *pce;
@@ -804,12 +835,20 @@
 			}
 			/* write xts du size */
 			pce = cmdlistinfo->encr_xts_du_size;
-			if (!(creq->flags & QCRYPTO_CTX_XTS_MASK))
-				pce->data = creq->cryptlen;
-			else
+			switch (creq->flags & QCRYPTO_CTX_XTS_MASK) {
+			case QCRYPTO_CTX_XTS_DU_SIZE_512B:
 				pce->data = min((unsigned int)QCE_SECTOR_SIZE,
 						creq->cryptlen);
-
+				break;
+			case QCRYPTO_CTX_XTS_DU_SIZE_1KB:
+				pce->data =
+					min((unsigned int)QCE_SECTOR_SIZE * 2,
+					creq->cryptlen);
+				break;
+			default:
+				pce->data = creq->cryptlen;
+				break;
+			}
 		}
 		if (creq->mode !=  QCE_MODE_ECB) {
 			if (creq->mode ==  QCE_MODE_XTS)
@@ -889,15 +928,141 @@
 	return 0;
 };
 
+static int _ce_f9_setup(struct qce_device *pce_dev, struct qce_f9_req *req,
+		struct qce_cmdlist_info *cmdlistinfo)
+{
+	uint32_t ikey32[OTA_KEY_SIZE/sizeof(uint32_t)];
+	uint32_t key_size_in_word = OTA_KEY_SIZE/sizeof(uint32_t);
+	uint32_t cfg;
+	struct sps_command_element *pce;
+	int i;
+
+	switch (req->algorithm) {
+	case QCE_OTA_ALGO_KASUMI:
+		cfg = pce_dev->reg.auth_cfg_kasumi;
+		break;
+	case QCE_OTA_ALGO_SNOW3G:
+	default:
+		cfg = pce_dev->reg.auth_cfg_snow3g;
+		break;
+	};
+
+	/* write key in CRYPTO_AUTH_IV0-3_REG */
+	_byte_stream_to_net_words(ikey32, &req->ikey[0], OTA_KEY_SIZE);
+	pce = cmdlistinfo->auth_iv;
+	for (i = 0; i < key_size_in_word; i++, pce++)
+		pce->data = ikey32[i];
+
+	/* write last bits  in CRYPTO_AUTH_IV4_REG  */
+	pce->data = req->last_bits;
+
+	/* write fresh to CRYPTO_AUTH_BYTECNT0_REG */
+	pce = cmdlistinfo->auth_bytecount;
+	pce->data = req->fresh;
+
+	/* write count-i  to CRYPTO_AUTH_BYTECNT1_REG */
+	pce++;
+	pce->data = req->count_i;
+
+	/* write auth seg cfg */
+	pce = cmdlistinfo->auth_seg_cfg;
+	if (req->direction == QCE_OTA_DIR_DOWNLINK)
+		cfg |= BIT(CRYPTO_F9_DIRECTION);
+	pce->data = cfg;
+
+	/* write auth seg size */
+	pce = cmdlistinfo->auth_seg_size;
+	pce->data = req->msize;
+
+	/* write auth seg start*/
+	pce = cmdlistinfo->auth_seg_start;
+	pce->data = 0;
+
+	/* write seg size  */
+	pce = cmdlistinfo->seg_size;
+	pce->data = req->msize;
+
+
+	/* write go */
+	pce = cmdlistinfo->go_proc;
+	pce->addr = (uint32_t)(CRYPTO_GOPROC_REG + pce_dev->phy_iobase);
+	return 0;
+}
+
+static int _ce_f8_setup(struct qce_device *pce_dev, struct qce_f8_req *req,
+		bool key_stream_mode, uint16_t npkts, uint16_t cipher_offset,
+		uint16_t cipher_size,
+		struct qce_cmdlist_info *cmdlistinfo)
+{
+	uint32_t ckey32[OTA_KEY_SIZE/sizeof(uint32_t)];
+	uint32_t key_size_in_word = OTA_KEY_SIZE/sizeof(uint32_t);
+	uint32_t cfg;
+	struct sps_command_element *pce;
+	int i;
+
+	switch (req->algorithm) {
+	case QCE_OTA_ALGO_KASUMI:
+		cfg = pce_dev->reg.encr_cfg_kasumi;
+		break;
+	case QCE_OTA_ALGO_SNOW3G:
+	default:
+		cfg = pce_dev->reg.encr_cfg_snow3g;
+		break;
+	};
+	/* write key */
+	_byte_stream_to_net_words(ckey32, &req->ckey[0], OTA_KEY_SIZE);
+	pce = cmdlistinfo->encr_key;
+	for (i = 0; i < key_size_in_word; i++, pce++)
+		pce->data = ckey32[i];
+
+	/* write encr seg cfg */
+	pce = cmdlistinfo->encr_seg_cfg;
+	if (key_stream_mode)
+		cfg |= BIT(CRYPTO_F8_KEYSTREAM_ENABLE);
+	if (req->direction == QCE_OTA_DIR_DOWNLINK)
+		cfg |= BIT(CRYPTO_F8_DIRECTION);
+	pce->data = cfg;
+
+	/* write encr seg start */
+	pce = cmdlistinfo->encr_seg_start;
+	pce->data = (cipher_offset & 0xffff);
+
+	/* write encr seg size  */
+	pce = cmdlistinfo->encr_seg_size;
+	pce->data = cipher_size;
+
+	/* write seg size  */
+	pce = cmdlistinfo->seg_size;
+	pce->data = req->data_len;
+
+	/* write cntr0_iv0 for countC */
+	pce = cmdlistinfo->encr_cntr_iv;
+	pce->data = req->count_c;
+	/* write cntr1_iv1 for nPkts, and bearer */
+	pce++;
+	if (npkts == 1)
+		npkts = 0;
+	pce->data = req->bearer << CRYPTO_CNTR1_IV1_REG_F8_BEARER |
+				npkts << CRYPTO_CNTR1_IV1_REG_F8_PKT_CNT;
+
+	/* write go */
+	pce = cmdlistinfo->go_proc;
+	pce->addr = (uint32_t)(CRYPTO_GOPROC_REG + pce_dev->phy_iobase);
+
+	return 0;
+}
+
 static int _ce_setup_hash_direct(struct qce_device *pce_dev,
 				struct qce_sha_req *sreq)
 {
 	uint32_t auth32[SHA256_DIGEST_SIZE / sizeof(uint32_t)];
 	uint32_t diglen;
 	bool use_hw_key = false;
+	bool use_pipe_key = false;
 	int i;
 	uint32_t mackey32[SHA_HMAC_KEY_SIZE/sizeof(uint32_t)] = {
 			0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+	uint32_t authk_size_in_word = sreq->authklen/sizeof(uint32_t);
 	bool sha1 = false;
 	uint32_t auth_cfg = 0;
 
@@ -944,25 +1109,25 @@
 	if ((sreq->alg == QCE_HASH_SHA1_HMAC) ||
 			(sreq->alg == QCE_HASH_SHA256_HMAC) ||
 			(sreq->alg ==  QCE_HASH_AES_CMAC)) {
-		uint32_t authk_size_in_word = sreq->authklen/sizeof(uint32_t);
 
 		_byte_stream_to_net_words(mackey32, sreq->authkey,
 						sreq->authklen);
 
-		/* check for null key. If null, use hw key*/
-		for (i = 0; i < authk_size_in_word; i++) {
-			if (mackey32[i] != 0)
-				break;
-		}
+		/* no more check for null key. use flag to check*/
 
-		if (i == authk_size_in_word)
+		if ((sreq->flags & QCRYPTO_CTX_USE_HW_KEY) ==
+					QCRYPTO_CTX_USE_HW_KEY) {
 			use_hw_key = true;
-		else
-			/* Clear auth_ivn, auth_keyn registers  */
+		} else if ((sreq->flags & QCRYPTO_CTX_USE_PIPE_KEY) ==
+						QCRYPTO_CTX_USE_PIPE_KEY) {
+			use_pipe_key = true;
+		} else {
+			/* setup key */
 			for (i = 0; i < authk_size_in_word; i++)
 				writel_relaxed(mackey32[i], (pce_dev->iobase +
 					(CRYPTO_AUTH_KEY0_REG +
 							i*sizeof(uint32_t))));
+		}
 	}
 
 	if (sreq->alg ==  QCE_HASH_AES_CMAC)
@@ -1036,6 +1201,10 @@
 		auth_cfg |= 1 << CRYPTO_FIRST;
 	else
 		auth_cfg &= ~(1 << CRYPTO_FIRST);
+	if (use_hw_key)
+		auth_cfg |= 1 << CRYPTO_USE_HW_KEY_AUTH;
+	if (use_pipe_key)
+		auth_cfg |= 1 << CRYPTO_USE_PIPE_KEY_AUTH;
 go_proc:
 	 /* write seg_cfg */
 	writel_relaxed(auth_cfg, pce_dev->iobase + CRYPTO_AUTH_SEG_CFG_REG);
@@ -1071,7 +1240,7 @@
 static int _ce_setup_aead_direct(struct qce_device *pce_dev,
 		struct qce_req *q_req, uint32_t totallen_in, uint32_t coffset)
 {
-	int32_t authk_size_in_word = q_req->authklen/sizeof(uint32_t);
+	int32_t authk_size_in_word = SHA_HMAC_KEY_SIZE/sizeof(uint32_t);
 	int i;
 	uint32_t mackey32[SHA_HMAC_KEY_SIZE/sizeof(uint32_t)] = {0};
 	uint32_t a_cfg;
@@ -1454,15 +1623,25 @@
 						(i * sizeof(uint32_t)));
 			}
 			/* write xts du size */
-			if (use_pipe_key == true)
-				writel_relaxed(min((uint32_t)QCE_SECTOR_SIZE,
-						creq->cryptlen),
-						pce_dev->iobase +
-						CRYPTO_ENCR_XTS_DU_SIZE_REG);
-			else
-				writel_relaxed(creq->cryptlen ,
-						pce_dev->iobase +
-						CRYPTO_ENCR_XTS_DU_SIZE_REG);
+			switch (creq->flags & QCRYPTO_CTX_XTS_MASK) {
+			case QCRYPTO_CTX_XTS_DU_SIZE_512B:
+				writel_relaxed(
+					min((uint32_t)QCE_SECTOR_SIZE,
+					creq->cryptlen), pce_dev->iobase +
+					CRYPTO_ENCR_XTS_DU_SIZE_REG);
+				break;
+			case QCRYPTO_CTX_XTS_DU_SIZE_1KB:
+				writel_relaxed(
+					min((uint32_t)(QCE_SECTOR_SIZE * 2),
+					creq->cryptlen), pce_dev->iobase +
+					CRYPTO_ENCR_XTS_DU_SIZE_REG);
+				break;
+			default:
+				writel_relaxed(creq->cryptlen,
+					pce_dev->iobase +
+					CRYPTO_ENCR_XTS_DU_SIZE_REG);
+				break;
+			}
 		}
 		if (creq->mode !=  QCE_MODE_ECB) {
 			if (creq->mode ==  QCE_MODE_XTS)
@@ -1556,6 +1735,168 @@
 	return 0;
 };
 
+static int _ce_f9_setup_direct(struct qce_device *pce_dev,
+				 struct qce_f9_req *req)
+{
+	uint32_t ikey32[OTA_KEY_SIZE/sizeof(uint32_t)];
+	uint32_t key_size_in_word = OTA_KEY_SIZE/sizeof(uint32_t);
+	uint32_t auth_cfg;
+	int i;
+
+	switch (req->algorithm) {
+	case QCE_OTA_ALGO_KASUMI:
+		auth_cfg = pce_dev->reg.auth_cfg_kasumi;
+		break;
+	case QCE_OTA_ALGO_SNOW3G:
+	default:
+		auth_cfg = pce_dev->reg.auth_cfg_snow3g;
+		break;
+	};
+
+	/* clear status */
+	writel_relaxed(0, pce_dev->iobase + CRYPTO_STATUS_REG);
+
+	/* set big endian configuration */
+	writel_relaxed(pce_dev->reg.crypto_cfg_be, (pce_dev->iobase +
+							CRYPTO_CONFIG_REG));
+	/*
+	 * Ensure previous instructions (setting the CONFIG register)
+	 * was completed before issuing starting to set other config register
+	 * This is to ensure the configurations are done in correct endian-ness
+	 * as set in the CONFIG registers
+	 */
+	mb();
+
+	/* write enc_seg_cfg */
+	writel_relaxed(0, pce_dev->iobase + CRYPTO_ENCR_SEG_CFG_REG);
+
+	/* write ecn_seg_size */
+	writel_relaxed(0, pce_dev->iobase + CRYPTO_ENCR_SEG_SIZE_REG);
+
+	/* write key in CRYPTO_AUTH_IV0-3_REG */
+	_byte_stream_to_net_words(ikey32, &req->ikey[0], OTA_KEY_SIZE);
+	for (i = 0; i < key_size_in_word; i++)
+		writel_relaxed(ikey32[i], (pce_dev->iobase +
+			(CRYPTO_AUTH_IV0_REG + i*sizeof(uint32_t))));
+
+	/* write last bits  in CRYPTO_AUTH_IV4_REG  */
+	writel_relaxed(req->last_bits, (pce_dev->iobase +
+					CRYPTO_AUTH_IV4_REG));
+
+	/* write fresh to CRYPTO_AUTH_BYTECNT0_REG */
+	writel_relaxed(req->fresh, (pce_dev->iobase +
+					 CRYPTO_AUTH_BYTECNT0_REG));
+
+	/* write count-i  to CRYPTO_AUTH_BYTECNT1_REG */
+	writel_relaxed(req->count_i, (pce_dev->iobase +
+					 CRYPTO_AUTH_BYTECNT1_REG));
+
+	/* write auth seg cfg */
+	if (req->direction == QCE_OTA_DIR_DOWNLINK)
+		auth_cfg |= BIT(CRYPTO_F9_DIRECTION);
+	writel_relaxed(auth_cfg, pce_dev->iobase + CRYPTO_AUTH_SEG_CFG_REG);
+
+	/* write auth seg size */
+	writel_relaxed(req->msize, pce_dev->iobase + CRYPTO_AUTH_SEG_SIZE_REG);
+
+	/* write auth seg start*/
+	writel_relaxed(0, pce_dev->iobase + CRYPTO_AUTH_SEG_START_REG);
+
+	/* write seg size  */
+	writel_relaxed(req->msize, pce_dev->iobase + CRYPTO_SEG_SIZE_REG);
+
+	/* set little endian configuration before go*/
+	writel_relaxed(pce_dev->reg.crypto_cfg_le, (pce_dev->iobase +
+							CRYPTO_CONFIG_REG));
+	/* write go */
+	writel_relaxed(((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP)),
+				pce_dev->iobase +  CRYPTO_GOPROC_REG);
+	/*
+	 * Ensure previous instructions (setting the GO register)
+	 * was completed before issuing a DMA transfer request
+	 */
+	mb();
+	return 0;
+}
+
+static int _ce_f8_setup_direct(struct qce_device *pce_dev,
+		struct qce_f8_req *req, bool key_stream_mode,
+		uint16_t npkts, uint16_t cipher_offset, uint16_t cipher_size)
+{
+	int i = 0;
+	uint32_t encr_cfg = 0;
+	uint32_t ckey32[OTA_KEY_SIZE/sizeof(uint32_t)];
+	uint32_t key_size_in_word = OTA_KEY_SIZE/sizeof(uint32_t);
+
+	switch (req->algorithm) {
+	case QCE_OTA_ALGO_KASUMI:
+		encr_cfg = pce_dev->reg.encr_cfg_kasumi;
+		break;
+	case QCE_OTA_ALGO_SNOW3G:
+	default:
+		encr_cfg = pce_dev->reg.encr_cfg_snow3g;
+		break;
+	};
+	/* clear status */
+	writel_relaxed(0, pce_dev->iobase + CRYPTO_STATUS_REG);
+	/* set big endian configuration */
+	writel_relaxed(pce_dev->reg.crypto_cfg_be, (pce_dev->iobase +
+							CRYPTO_CONFIG_REG));
+	/* write auth seg configuration */
+	writel_relaxed(0, pce_dev->iobase + CRYPTO_AUTH_SEG_CFG_REG);
+	/* write auth seg size */
+	writel_relaxed(0, pce_dev->iobase + CRYPTO_AUTH_SEG_SIZE_REG);
+
+	/* write key */
+	_byte_stream_to_net_words(ckey32, &req->ckey[0], OTA_KEY_SIZE);
+
+	for (i = 0; i < key_size_in_word; i++)
+		writel_relaxed(ckey32[i], (pce_dev->iobase +
+			(CRYPTO_ENCR_KEY0_REG + i*sizeof(uint32_t))));
+	/* write encr seg cfg */
+	if (key_stream_mode)
+		encr_cfg |= BIT(CRYPTO_F8_KEYSTREAM_ENABLE);
+	if (req->direction == QCE_OTA_DIR_DOWNLINK)
+		encr_cfg |= BIT(CRYPTO_F8_DIRECTION);
+	writel_relaxed(encr_cfg, pce_dev->iobase +
+		CRYPTO_ENCR_SEG_CFG_REG);
+
+	/* write encr seg start */
+	writel_relaxed((cipher_offset & 0xffff), pce_dev->iobase +
+		CRYPTO_ENCR_SEG_START_REG);
+	/* write encr seg size  */
+	writel_relaxed(cipher_size, pce_dev->iobase +
+		CRYPTO_ENCR_SEG_SIZE_REG);
+
+	/* write seg size  */
+	writel_relaxed(req->data_len, pce_dev->iobase +
+		CRYPTO_SEG_SIZE_REG);
+
+	/* write cntr0_iv0 for countC */
+	writel_relaxed(req->count_c, pce_dev->iobase +
+		CRYPTO_CNTR0_IV0_REG);
+	/* write cntr1_iv1 for nPkts, and bearer */
+	if (npkts == 1)
+		npkts = 0;
+	writel_relaxed(req->bearer << CRYPTO_CNTR1_IV1_REG_F8_BEARER |
+				npkts << CRYPTO_CNTR1_IV1_REG_F8_PKT_CNT,
+			pce_dev->iobase + CRYPTO_CNTR1_IV1_REG);
+
+	/* set little endian configuration before go*/
+	writel_relaxed(pce_dev->reg.crypto_cfg_le, (pce_dev->iobase +
+							CRYPTO_CONFIG_REG));
+	/* write go */
+	writel_relaxed(((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP)),
+				pce_dev->iobase +  CRYPTO_GOPROC_REG);
+	/*
+	 * Ensure previous instructions (setting the GO register)
+	 * was completed before issuing a DMA transfer request
+	 */
+	mb();
+	return 0;
+}
+
+
 static int _qce_unlock_other_pipes(struct qce_device *pce_dev)
 {
 	int rc = 0;
@@ -1705,6 +2046,48 @@
 	return 0;
 };
 
+static int _f9_complete(struct qce_device *pce_dev)
+{
+	uint32_t mac_i;
+	uint32_t status;
+	int32_t result_status;
+
+	dma_unmap_single(pce_dev->pdev, pce_dev->phy_ota_src,
+				pce_dev->ota_size, DMA_TO_DEVICE);
+	_byte_stream_to_net_words(&mac_i,
+		(char *)(&pce_dev->ce_sps.result->auth_iv[0]),
+		CRYPTO_REG_SIZE);
+	/* read status before unlock */
+	status = readl_relaxed(pce_dev->iobase + CRYPTO_STATUS_REG);
+	if (_qce_unlock_other_pipes(pce_dev)) {
+		pce_dev->qce_cb(pce_dev->areq, NULL, NULL, -ENXIO);
+		return -ENXIO;
+	}
+	if (status & ((1 << CRYPTO_SW_ERR) | (1 << CRYPTO_AXI_ERR)
+				| (1 <<  CRYPTO_HSD_ERR))) {
+		pr_err("f9 operation error. Status %x\n", status);
+		result_status = -ENXIO;
+	} else if (pce_dev->ce_sps.consumer_status |
+				pce_dev->ce_sps.producer_status)  {
+		pr_err("f9 sps operation error. sps status %x %x\n",
+				pce_dev->ce_sps.consumer_status,
+				pce_dev->ce_sps.producer_status);
+		result_status = -ENXIO;
+	} else if ((status & (1 << CRYPTO_OPERATION_DONE)) == 0) {
+		pr_err("f9 operation not done? Status %x, sps status %x %x\n",
+			status,
+			pce_dev->ce_sps.consumer_status,
+			pce_dev->ce_sps.producer_status);
+		result_status = -ENXIO;
+	} else {
+		result_status = 0;
+	}
+	pce_dev->qce_cb(pce_dev->areq, (void *) mac_i, NULL,
+				result_status);
+
+	return 0;
+}
+
 static int _ablk_cipher_complete(struct qce_device *pce_dev)
 {
 	struct ablkcipher_request *areq;
@@ -1811,6 +2194,47 @@
 	return 0;
 };
 
+static int _f8_complete(struct qce_device *pce_dev)
+{
+	uint32_t status;
+	int32_t result_status;
+
+	if (pce_dev->phy_ota_dst != 0)
+		dma_unmap_single(pce_dev->pdev, pce_dev->phy_ota_dst,
+				pce_dev->ota_size, DMA_FROM_DEVICE);
+	if (pce_dev->phy_ota_src != 0)
+		dma_unmap_single(pce_dev->pdev, pce_dev->phy_ota_src,
+				pce_dev->ota_size, (pce_dev->phy_ota_dst) ?
+				DMA_TO_DEVICE : DMA_BIDIRECTIONAL);
+	/* read status before unlock */
+	status = readl_relaxed(pce_dev->iobase + CRYPTO_STATUS_REG);
+	if (_qce_unlock_other_pipes(pce_dev)) {
+		pce_dev->qce_cb(pce_dev->areq, NULL, NULL, -ENXIO);
+		return -ENXIO;
+	}
+	if (status & ((1 << CRYPTO_SW_ERR) | (1 << CRYPTO_AXI_ERR)
+				| (1 <<  CRYPTO_HSD_ERR))) {
+		pr_err("f8 operation error. Status %x\n", status);
+		result_status = -ENXIO;
+	} else if (pce_dev->ce_sps.consumer_status |
+				pce_dev->ce_sps.producer_status)  {
+		pr_err("f8 sps operation error. sps status %x %x\n",
+				pce_dev->ce_sps.consumer_status,
+				pce_dev->ce_sps.producer_status);
+		result_status = -ENXIO;
+	} else if ((status & (1 << CRYPTO_OPERATION_DONE)) == 0) {
+		pr_err("f8 operation not done? Status %x, sps status %x %x\n",
+			status,
+			pce_dev->ce_sps.consumer_status,
+			pce_dev->ce_sps.producer_status);
+		result_status = -ENXIO;
+	} else {
+		result_status = 0;
+	}
+	pce_dev->qce_cb(pce_dev->areq, NULL, NULL, result_status);
+	return 0;
+}
+
 #ifdef QCE_DEBUG
 static void _qce_dump_descr_fifos(struct qce_device *pce_dev)
 {
@@ -1903,8 +2327,11 @@
 
 static void _qce_set_flag(struct sps_transfer *sps_bam_pipe, uint32_t flag)
 {
-	struct sps_iovec *iovec = sps_bam_pipe->iovec +
-					(sps_bam_pipe->iovec_count - 1);
+	struct sps_iovec *iovec;
+
+	if (sps_bam_pipe->iovec_count == 0)
+		return;
+	iovec  = sps_bam_pipe->iovec + (sps_bam_pipe->iovec_count - 1);
 	iovec->flags |= flag;
 }
 
@@ -1913,16 +2340,26 @@
 {
 	struct sps_iovec *iovec = sps_bam_pipe->iovec +
 					sps_bam_pipe->iovec_count;
-	if (sps_bam_pipe->iovec_count == QCE_MAX_NUM_DSCR) {
-		pr_err("Num of descrptor %d exceed max (%d)",
-			sps_bam_pipe->iovec_count, (uint32_t)QCE_MAX_NUM_DSCR);
-		return -ENOMEM;
-	}
-	if (len) {
-		iovec->size = len;
+	uint32_t data_cnt;
+
+	while (len > 0) {
+		if (sps_bam_pipe->iovec_count == QCE_MAX_NUM_DSCR) {
+			pr_err("Num of descrptor %d exceed max (%d)",
+				sps_bam_pipe->iovec_count,
+				(uint32_t)QCE_MAX_NUM_DSCR);
+			return -ENOMEM;
+		}
+		if (len > SPS_MAX_PKT_SIZE)
+			data_cnt = SPS_MAX_PKT_SIZE;
+		else
+			data_cnt = len;
+		iovec->size = data_cnt;
 		iovec->addr = addr;
 		iovec->flags = 0;
 		sps_bam_pipe->iovec_count++;
+		iovec++;
+		addr += data_cnt;
+		len -= data_cnt;
 	}
 	return 0;
 }
@@ -1988,13 +2425,15 @@
 	int rc = 0;
 
 	_qce_dump_descr_fifos(pce_dev);
-	rc = sps_transfer(pce_dev->ce_sps.consumer.pipe,
+	if (pce_dev->ce_sps.in_transfer.iovec_count) {
+		rc = sps_transfer(pce_dev->ce_sps.consumer.pipe,
 					  &pce_dev->ce_sps.in_transfer);
-	if (rc) {
-		pr_err("sps_xfr() fail (consumer pipe=0x%x) rc = %d,",
+		if (rc) {
+			pr_err("sps_xfr() fail (consumer pipe=0x%x) rc = %d,",
 				(u32)pce_dev->ce_sps.consumer.pipe, rc);
-		_qce_dump_descr_fifos_fail(pce_dev);
-		return rc;
+			_qce_dump_descr_fifos_fail(pce_dev);
+			return rc;
+		}
 	}
 	rc = sps_transfer(pce_dev->ce_sps.producer.pipe,
 					  &pce_dev->ce_sps.out_transfer);
@@ -2195,8 +2634,8 @@
 	list_del(&pbam->qlist);
 	kfree(pbam);
 
-	pce_dev->pbam = NULL;
 ret:
+	pce_dev->pbam = NULL;
 	mutex_unlock(&bam_register_lock);
 }
 
@@ -2206,7 +2645,7 @@
 	struct sps_bam_props bam = {0};
 	struct bam_registration_info *pbam = NULL;
 	struct bam_registration_info *p;
-	uint32_t bam_cfg = 0 ;
+	uint32_t bam_cfg = 0;
 
 
 	mutex_lock(&bam_register_lock);
@@ -2255,6 +2694,10 @@
 					CRYPTO_BAM_CNFG_BITS_REG);
 	pbam->support_cmd_dscr =  (bam_cfg & CRYPTO_BAM_CD_ENABLE_MASK) ?
 					true : false;
+	if (pbam->support_cmd_dscr == false) {
+		pr_info("qce50 don't support command descriptor. bam_cfg%x\n",
+								 bam_cfg);
+	}
 	pce_dev->support_cmd_dscr = pbam->support_cmd_dscr;
 
 	bam.phys_addr = pce_dev->ce_sps.bam_mem;
@@ -2282,6 +2725,7 @@
 		bam.manage = SPS_BAM_MGR_DEVICE_REMOTE;
 	else
 		bam.manage = SPS_BAM_MGR_LOCAL;
+
 	bam.ee = 1;
 
 	pr_debug("bam physical base=0x%x\n", (u32)bam.phys_addr);
@@ -2419,6 +2863,55 @@
 	_sha_complete(pce_dev);
 };
 
+static void _f9_sps_producer_callback(struct sps_event_notify *notify)
+{
+	struct qce_device *pce_dev = (struct qce_device *)
+		((struct sps_event_notify *)notify)->user;
+
+	pce_dev->ce_sps.notify = *notify;
+	pr_debug("sps ev_id=%d, addr=0x%x, size=0x%x, flags=0x%x\n",
+			notify->event_id,
+			notify->data.transfer.iovec.addr,
+			notify->data.transfer.iovec.size,
+			notify->data.transfer.iovec.flags);
+	/* done */
+	_f9_complete(pce_dev);
+}
+
+static void _f8_sps_producer_callback(struct sps_event_notify *notify)
+{
+	struct qce_device *pce_dev = (struct qce_device *)
+		((struct sps_event_notify *)notify)->user;
+
+	pce_dev->ce_sps.notify = *notify;
+	pr_debug("sps ev_id=%d, addr=0x%x, size=0x%x, flags=0x%x\n",
+			notify->event_id,
+			notify->data.transfer.iovec.addr,
+			notify->data.transfer.iovec.size,
+			notify->data.transfer.iovec.flags);
+
+	if (pce_dev->ce_sps.producer_state == QCE_PIPE_STATE_COMP) {
+		pce_dev->ce_sps.producer_state = QCE_PIPE_STATE_IDLE;
+		/* done */
+		_f8_complete(pce_dev);
+	} else {
+		int rc = 0;
+		pce_dev->ce_sps.producer_state = QCE_PIPE_STATE_COMP;
+		pce_dev->ce_sps.out_transfer.iovec_count = 0;
+		_qce_sps_add_data(GET_PHYS_ADDR(pce_dev->ce_sps.result_dump),
+					CRYPTO_RESULT_DUMP_SIZE,
+					  &pce_dev->ce_sps.out_transfer);
+		_qce_set_flag(&pce_dev->ce_sps.out_transfer,
+				SPS_IOVEC_FLAG_EOT|SPS_IOVEC_FLAG_INT);
+		rc = sps_transfer(pce_dev->ce_sps.producer.pipe,
+					  &pce_dev->ce_sps.out_transfer);
+		if (rc) {
+			pr_err("sps_xfr() fail (producer pipe=0x%x) rc = %d,",
+				(u32)pce_dev->ce_sps.producer.pipe, rc);
+		}
+	}
+}
+
 static void _ablk_cipher_sps_producer_callback(struct sps_event_notify *notify)
 {
 	struct qce_device *pce_dev = (struct qce_device *)
@@ -2462,7 +2955,7 @@
 	(*cmd_ptr)->mask = 0xFFFFFFFF;
 	if (populate != NULL)
 		*populate = *cmd_ptr;
-	(*cmd_ptr)++ ;
+	(*cmd_ptr)++;
 }
 
 static int _setup_cipher_aes_cmdlistptrs(struct qce_device *pdev,
@@ -3251,6 +3744,172 @@
 	return 0;
 }
 
+static int _setup_f8_cmdlistptrs(struct qce_device *pdev,
+	unsigned char **pvaddr, enum qce_ota_algo_enum alg)
+{
+	struct sps_command_element *ce_vaddr;
+	uint32_t ce_vaddr_start;
+	struct qce_cmdlistptr_ops *cmdlistptr = &pdev->ce_sps.cmdlistptr;
+	struct qce_cmdlist_info *pcl_info = NULL;
+	int i = 0;
+	uint32_t encr_cfg = 0;
+	uint32_t key_reg = 4;
+
+	*pvaddr = (unsigned char *) ALIGN(((unsigned int)(*pvaddr)),
+					pdev->ce_sps.ce_burst_size);
+	ce_vaddr = (struct sps_command_element *)(*pvaddr);
+	ce_vaddr_start = (uint32_t)(*pvaddr);
+
+	/*
+	 * Designate chunks of the allocated memory to various
+	 * command list pointers related to f8 cipher algorithm defined
+	 * in ce_cmdlistptrs_ops structure.
+	 */
+
+	switch (alg) {
+	case QCE_OTA_ALGO_KASUMI:
+		cmdlistptr->f8_kasumi.cmdlist = (uint32_t)ce_vaddr;
+		pcl_info = &(cmdlistptr->f8_kasumi);
+		encr_cfg = pdev->reg.encr_cfg_kasumi;
+		break;
+
+	case QCE_OTA_ALGO_SNOW3G:
+	default:
+		cmdlistptr->f8_snow3g.cmdlist = (uint32_t)ce_vaddr;
+		pcl_info = &(cmdlistptr->f8_snow3g);
+		encr_cfg = pdev->reg.encr_cfg_snow3g;
+		break;
+	}
+	/* clear status register */
+	qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_STATUS_REG,
+							0, NULL);
+	/* set config to big endian */
+	qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_CONFIG_REG,
+			pdev->reg.crypto_cfg_be, &pcl_info->crypto_cfg);
+
+	qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_SEG_SIZE_REG, 0,
+						&pcl_info->seg_size);
+
+	qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_ENCR_SEG_CFG_REG, encr_cfg,
+						&pcl_info->encr_seg_cfg);
+	qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_ENCR_SEG_SIZE_REG, 0,
+						&pcl_info->encr_seg_size);
+	qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_ENCR_SEG_START_REG, 0,
+						&pcl_info->encr_seg_start);
+
+	qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_AUTH_SEG_CFG_REG, 0,
+						&pcl_info->auth_seg_cfg);
+
+	qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_AUTH_SEG_SIZE_REG,
+						0, &pcl_info->auth_seg_size);
+	qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_AUTH_SEG_START_REG,
+						0, &pcl_info->auth_seg_start);
+
+	qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_ENCR_KEY0_REG, 0,
+						 &pcl_info->encr_key);
+	for (i = 1; i < key_reg; i++)
+		qce_add_cmd_element(pdev, &ce_vaddr,
+				(CRYPTO_ENCR_KEY0_REG + i * sizeof(uint32_t)),
+				0, NULL);
+
+	qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_CNTR0_IV0_REG, 0,
+						&pcl_info->encr_cntr_iv);
+	qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_CNTR1_IV1_REG, 0,
+								NULL);
+	qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_CONFIG_REG,
+					pdev->reg.crypto_cfg_le, NULL);
+
+	qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_GOPROC_REG,
+			((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP)),
+			&pcl_info->go_proc);
+
+	pcl_info->size = (uint32_t)ce_vaddr - (uint32_t)ce_vaddr_start;
+	*pvaddr = (unsigned char *) ce_vaddr;
+
+	return 0;
+}
+
+static int _setup_f9_cmdlistptrs(struct qce_device *pdev,
+	unsigned char **pvaddr, enum qce_ota_algo_enum alg)
+{
+	struct sps_command_element *ce_vaddr;
+	uint32_t ce_vaddr_start;
+	struct qce_cmdlistptr_ops *cmdlistptr = &pdev->ce_sps.cmdlistptr;
+	struct qce_cmdlist_info *pcl_info = NULL;
+	int i = 0;
+	uint32_t auth_cfg = 0;
+	uint32_t iv_reg = 0;
+
+	*pvaddr = (unsigned char *) ALIGN(((unsigned int)(*pvaddr)),
+					pdev->ce_sps.ce_burst_size);
+	ce_vaddr_start = (uint32_t)(*pvaddr);
+	ce_vaddr = (struct sps_command_element *)(*pvaddr);
+
+	/*
+	 * Designate chunks of the allocated memory to various
+	 * command list pointers related to authentication operations
+	 * defined in ce_cmdlistptrs_ops structure.
+	 */
+	switch (alg) {
+	case QCE_OTA_ALGO_KASUMI:
+		cmdlistptr->f9_kasumi.cmdlist = (uint32_t)ce_vaddr;
+		pcl_info = &(cmdlistptr->f9_kasumi);
+		auth_cfg = pdev->reg.auth_cfg_kasumi;
+		break;
+
+	case QCE_OTA_ALGO_SNOW3G:
+	default:
+		cmdlistptr->f9_snow3g.cmdlist = (uint32_t)ce_vaddr;
+		pcl_info = &(cmdlistptr->f9_snow3g);
+		auth_cfg = pdev->reg.auth_cfg_snow3g;
+	};
+
+	/* clear status register */
+	qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_STATUS_REG,
+							0, NULL);
+	/* set config to big endian */
+	qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_CONFIG_REG,
+			pdev->reg.crypto_cfg_be, &pcl_info->crypto_cfg);
+
+	iv_reg = 5;
+
+	qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_SEG_SIZE_REG, 0,
+						&pcl_info->seg_size);
+
+	qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_ENCR_SEG_CFG_REG, 0,
+						&pcl_info->encr_seg_cfg);
+
+	qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_AUTH_SEG_CFG_REG,
+					auth_cfg, &pcl_info->auth_seg_cfg);
+	qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_AUTH_SEG_SIZE_REG, 0,
+						&pcl_info->auth_seg_size);
+	qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_AUTH_SEG_START_REG, 0,
+						&pcl_info->auth_seg_start);
+
+	qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_AUTH_IV0_REG, 0,
+							&pcl_info->auth_iv);
+	for (i = 1; i < iv_reg; i++) {
+		qce_add_cmd_element(pdev, &ce_vaddr,
+				(CRYPTO_AUTH_IV0_REG + i*sizeof(uint32_t)),
+				0, NULL);
+	}
+	qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_AUTH_BYTECNT0_REG,
+					0, &pcl_info->auth_bytecount);
+	qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_AUTH_BYTECNT1_REG, 0, NULL);
+
+	qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_CONFIG_REG,
+					pdev->reg.crypto_cfg_le, NULL);
+
+	qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_GOPROC_REG,
+			((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP)),
+			&pcl_info->go_proc);
+
+	pcl_info->size = (uint32_t)ce_vaddr - (uint32_t)ce_vaddr_start;
+	*pvaddr = (unsigned char *) ce_vaddr;
+
+	return 0;
+}
+
 static int _setup_unlock_pipe_cmdlistptrs(struct qce_device *pdev,
 		unsigned char **pvaddr)
 {
@@ -3334,6 +3993,10 @@
 
 	_setup_aead_ccm_cmdlistptrs(pdev, pvaddr, true);
 	_setup_aead_ccm_cmdlistptrs(pdev, pvaddr, false);
+	_setup_f8_cmdlistptrs(pdev, pvaddr, QCE_OTA_ALGO_KASUMI);
+	_setup_f8_cmdlistptrs(pdev, pvaddr, QCE_OTA_ALGO_SNOW3G);
+	_setup_f9_cmdlistptrs(pdev, pvaddr, QCE_OTA_ALGO_KASUMI);
+	_setup_f9_cmdlistptrs(pdev, pvaddr, QCE_OTA_ALGO_SNOW3G);
 	_setup_unlock_pipe_cmdlistptrs(pdev, pvaddr);
 
 	return 0;
@@ -3461,6 +4124,13 @@
 		(CRYPTO_ENCR_ALG_DES << CRYPTO_ENCR_ALG) |
 		(CRYPTO_ENCR_MODE_CBC << CRYPTO_ENCR_MODE);
 
+	/* Initialize encr_cfg register for kasumi/snow3g  alg */
+	pce_dev->reg.encr_cfg_kasumi =
+		(CRYPTO_ENCR_ALG_KASUMI << CRYPTO_ENCR_ALG);
+
+	pce_dev->reg.encr_cfg_snow3g =
+		(CRYPTO_ENCR_ALG_SNOW_3G << CRYPTO_ENCR_ALG);
+
 	/* Initialize auth_cfg register for CMAC alg */
 	pce_dev->reg.auth_cfg_cmac_128 =
 		(1 << CRYPTO_LAST) | (1 << CRYPTO_FIRST) |
@@ -3531,6 +4201,13 @@
 		((MAX_NONCE/sizeof(uint32_t)) << CRYPTO_AUTH_NONCE_NUM_WORDS);
 	pce_dev->reg.auth_cfg_aes_ccm_256 &= ~(1 << CRYPTO_USE_HW_KEY_AUTH);
 
+	/* Initialize auth_cfg register for kasumi/snow3g */
+	pce_dev->reg.auth_cfg_kasumi =
+			(CRYPTO_AUTH_ALG_KASUMI << CRYPTO_AUTH_ALG) |
+				BIT(CRYPTO_FIRST) | BIT(CRYPTO_LAST);
+	pce_dev->reg.auth_cfg_snow3g =
+			(CRYPTO_AUTH_ALG_SNOW3G << CRYPTO_AUTH_ALG) |
+				BIT(CRYPTO_FIRST) | BIT(CRYPTO_LAST);
 	return 0;
 }
 
@@ -3728,6 +4405,65 @@
 	return rc;
 }
 
+static int _qce_suspend(void *handle)
+{
+	struct qce_device *pce_dev = (struct qce_device *)handle;
+	struct sps_pipe *sps_pipe_info;
+
+	if (handle == NULL)
+		return -ENODEV;
+
+	qce_enable_clk(pce_dev);
+
+	sps_pipe_info = pce_dev->ce_sps.consumer.pipe;
+	sps_disconnect(sps_pipe_info);
+
+	sps_pipe_info = pce_dev->ce_sps.producer.pipe;
+	sps_disconnect(sps_pipe_info);
+
+	qce_disable_clk(pce_dev);
+	return 0;
+}
+
+static int _qce_resume(void *handle)
+{
+	struct qce_device *pce_dev = (struct qce_device *)handle;
+	struct sps_pipe *sps_pipe_info;
+	struct sps_connect *sps_connect_info;
+	int rc;
+
+	if (handle == NULL)
+		return -ENODEV;
+
+	qce_enable_clk(pce_dev);
+
+	sps_pipe_info = pce_dev->ce_sps.consumer.pipe;
+	sps_connect_info = &pce_dev->ce_sps.consumer.connect;
+	memset(sps_connect_info->desc.base, 0x00, sps_connect_info->desc.size);
+	rc = sps_connect(sps_pipe_info, sps_connect_info);
+	if (rc) {
+		pr_err("sps_connect() fail pipe_handle=0x%x, rc = %d\n",
+			(u32)sps_pipe_info, rc);
+		return rc;
+	}
+	sps_pipe_info = pce_dev->ce_sps.producer.pipe;
+	sps_connect_info = &pce_dev->ce_sps.producer.connect;
+	memset(sps_connect_info->desc.base, 0x00, sps_connect_info->desc.size);
+	rc = sps_connect(sps_pipe_info, sps_connect_info);
+	if (rc)
+		pr_err("sps_connect() fail pipe_handle=0x%x, rc = %d\n",
+			(u32)sps_pipe_info, rc);
+
+	pce_dev->ce_sps.out_transfer.user = pce_dev->ce_sps.producer.pipe;
+	pce_dev->ce_sps.in_transfer.user = pce_dev->ce_sps.consumer.pipe;
+
+	qce_disable_clk(pce_dev);
+	return rc;
+}
+
+struct qce_pm_table qce_pm_table  = {_qce_suspend, _qce_resume};
+EXPORT_SYMBOL(qce_pm_table);
+
 int qce_aead_req(void *handle, struct qce_req *q_req)
 {
 	struct qce_device *pce_dev;
@@ -4105,6 +4841,302 @@
 }
 EXPORT_SYMBOL(qce_process_sha_req);
 
+int qce_f8_req(void *handle, struct qce_f8_req *req,
+			void *cookie, qce_comp_func_ptr_t qce_cb)
+{
+	struct qce_device *pce_dev = (struct qce_device *) handle;
+	bool key_stream_mode;
+	dma_addr_t dst;
+	int rc;
+	struct qce_cmdlist_info *cmdlistinfo;
+
+	switch (req->algorithm) {
+	case QCE_OTA_ALGO_KASUMI:
+		cmdlistinfo = &pce_dev->ce_sps.cmdlistptr.f8_kasumi;
+		break;
+	case QCE_OTA_ALGO_SNOW3G:
+		cmdlistinfo = &pce_dev->ce_sps.cmdlistptr.f8_snow3g;
+		break;
+	default:
+		return -EINVAL;
+	};
+
+	key_stream_mode = (req->data_in == NULL);
+
+	if ((key_stream_mode && (req->data_len & 0xf)) ||
+				(req->bearer >= QCE_OTA_MAX_BEARER))
+		return -EINVAL;
+
+	/* F8 cipher input       */
+	if (key_stream_mode)
+		pce_dev->phy_ota_src = 0;
+	else {
+		pce_dev->phy_ota_src = dma_map_single(pce_dev->pdev,
+					req->data_in, req->data_len,
+					(req->data_in == req->data_out) ?
+					DMA_BIDIRECTIONAL : DMA_TO_DEVICE);
+	}
+
+	/* F8 cipher output     */
+	if (req->data_in != req->data_out) {
+		dst = dma_map_single(pce_dev->pdev, req->data_out,
+				req->data_len, DMA_FROM_DEVICE);
+		pce_dev->phy_ota_dst = dst;
+	} else {
+		/* in place ciphering */
+		dst = pce_dev->phy_ota_src;
+		pce_dev->phy_ota_dst = 0;
+	}
+	pce_dev->ota_size = req->data_len;
+
+
+	/* set up crypto device */
+	if (pce_dev->support_cmd_dscr)
+		rc = _ce_f8_setup(pce_dev, req, key_stream_mode, 1, 0,
+				 req->data_len, cmdlistinfo);
+	else
+		rc = _ce_f8_setup_direct(pce_dev, req, key_stream_mode, 1, 0,
+				 req->data_len);
+	if (rc < 0)
+		goto bad;
+
+	/* setup for callback, and issue command to sps */
+	pce_dev->areq = cookie;
+	pce_dev->qce_cb = qce_cb;
+
+	/* Register producer callback event for DESC_DONE event. */
+	pce_dev->ce_sps.producer.event.callback =
+				_f8_sps_producer_callback;
+	pce_dev->ce_sps.producer.event.options = SPS_O_DESC_DONE;
+	rc = sps_register_event(pce_dev->ce_sps.producer.pipe,
+					&pce_dev->ce_sps.producer.event);
+	if (rc) {
+		pr_err("Producer callback registration failed rc = %d\n", rc);
+		goto bad;
+	}
+	_qce_sps_iovec_count_init(pce_dev);
+
+	if (pce_dev->support_cmd_dscr)
+		_qce_sps_add_cmd(pce_dev, SPS_IOVEC_FLAG_LOCK, cmdlistinfo,
+					&pce_dev->ce_sps.in_transfer);
+
+	if (!key_stream_mode) {
+		_qce_sps_add_data((uint32_t)pce_dev->phy_ota_src, req->data_len,
+					&pce_dev->ce_sps.in_transfer);
+		_qce_set_flag(&pce_dev->ce_sps.in_transfer,
+				SPS_IOVEC_FLAG_EOT|SPS_IOVEC_FLAG_NWD);
+	}
+
+	_qce_sps_add_data((uint32_t)dst, req->data_len,
+					&pce_dev->ce_sps.out_transfer);
+
+	if (req->data_len > SPS_MAX_PKT_SIZE) {
+		_qce_set_flag(&pce_dev->ce_sps.out_transfer,
+							SPS_IOVEC_FLAG_INT);
+		pce_dev->ce_sps.producer_state = QCE_PIPE_STATE_IDLE;
+	} else {
+		pce_dev->ce_sps.producer_state = QCE_PIPE_STATE_COMP;
+		_qce_sps_add_data(GET_PHYS_ADDR(pce_dev->ce_sps.result_dump),
+					CRYPTO_RESULT_DUMP_SIZE,
+					  &pce_dev->ce_sps.out_transfer);
+		_qce_set_flag(&pce_dev->ce_sps.out_transfer,
+							SPS_IOVEC_FLAG_INT);
+	}
+	rc = _qce_sps_transfer(pce_dev);
+	if (rc)
+		goto bad;
+	return 0;
+bad:
+	if (pce_dev->phy_ota_dst != 0)
+		dma_unmap_single(pce_dev->pdev, pce_dev->phy_ota_dst,
+				req->data_len, DMA_FROM_DEVICE);
+	if (pce_dev->phy_ota_src != 0)
+		dma_unmap_single(pce_dev->pdev, pce_dev->phy_ota_src,
+				req->data_len,
+				(req->data_in == req->data_out) ?
+					DMA_BIDIRECTIONAL : DMA_TO_DEVICE);
+	return rc;
+}
+EXPORT_SYMBOL(qce_f8_req);
+
+int qce_f8_multi_pkt_req(void *handle, struct qce_f8_multi_pkt_req *mreq,
+			void *cookie, qce_comp_func_ptr_t qce_cb)
+{
+	struct qce_device *pce_dev = (struct qce_device *) handle;
+	uint16_t num_pkt = mreq->num_pkt;
+	uint16_t cipher_start = mreq->cipher_start;
+	uint16_t cipher_size = mreq->cipher_size;
+	struct qce_f8_req *req = &mreq->qce_f8_req;
+	uint32_t total;
+	dma_addr_t dst = 0;
+	int rc = 0;
+	struct qce_cmdlist_info *cmdlistinfo;
+
+	switch (req->algorithm) {
+	case QCE_OTA_ALGO_KASUMI:
+		cmdlistinfo = &pce_dev->ce_sps.cmdlistptr.f8_kasumi;
+		break;
+	case QCE_OTA_ALGO_SNOW3G:
+		cmdlistinfo = &pce_dev->ce_sps.cmdlistptr.f8_snow3g;
+		break;
+	default:
+		return -EINVAL;
+	};
+
+	total = num_pkt *  req->data_len;
+
+	/* F8 cipher input       */
+	pce_dev->phy_ota_src = dma_map_single(pce_dev->pdev,
+				req->data_in, total,
+				(req->data_in == req->data_out) ?
+				DMA_BIDIRECTIONAL : DMA_TO_DEVICE);
+
+	/* F8 cipher output      */
+	if (req->data_in != req->data_out) {
+		dst = dma_map_single(pce_dev->pdev, req->data_out, total,
+						DMA_FROM_DEVICE);
+		pce_dev->phy_ota_dst = dst;
+	} else {
+		/* in place ciphering */
+		dst = pce_dev->phy_ota_src;
+		pce_dev->phy_ota_dst = 0;
+	}
+
+	pce_dev->ota_size = total;
+
+	/* set up crypto device */
+	if (pce_dev->support_cmd_dscr)
+		rc = _ce_f8_setup(pce_dev, req, false, num_pkt, cipher_start,
+			cipher_size, cmdlistinfo);
+	else
+		rc = _ce_f8_setup_direct(pce_dev, req, false, num_pkt,
+			cipher_start, cipher_size);
+	if (rc)
+		goto bad;
+
+	/* setup for callback, and issue command to sps */
+	pce_dev->areq = cookie;
+	pce_dev->qce_cb = qce_cb;
+
+	/* Register producer callback event for DESC_DONE event. */
+	pce_dev->ce_sps.producer.event.callback =
+				_f8_sps_producer_callback;
+	pce_dev->ce_sps.producer.event.options = SPS_O_DESC_DONE;
+	rc = sps_register_event(pce_dev->ce_sps.producer.pipe,
+					&pce_dev->ce_sps.producer.event);
+	if (rc) {
+		pr_err("Producer callback registration failed rc = %d\n", rc);
+		goto bad;
+	}
+	_qce_sps_iovec_count_init(pce_dev);
+
+	if (pce_dev->support_cmd_dscr)
+		_qce_sps_add_cmd(pce_dev, SPS_IOVEC_FLAG_LOCK, cmdlistinfo,
+					&pce_dev->ce_sps.in_transfer);
+
+	_qce_sps_add_data((uint32_t)pce_dev->phy_ota_src, total,
+					&pce_dev->ce_sps.in_transfer);
+	_qce_set_flag(&pce_dev->ce_sps.in_transfer,
+				SPS_IOVEC_FLAG_EOT|SPS_IOVEC_FLAG_NWD);
+
+	_qce_sps_add_data((uint32_t)dst, total,
+					&pce_dev->ce_sps.out_transfer);
+
+	if (total > SPS_MAX_PKT_SIZE) {
+		_qce_set_flag(&pce_dev->ce_sps.out_transfer,
+							SPS_IOVEC_FLAG_INT);
+		pce_dev->ce_sps.producer_state = QCE_PIPE_STATE_IDLE;
+	} else {
+		pce_dev->ce_sps.producer_state = QCE_PIPE_STATE_COMP;
+		_qce_sps_add_data(GET_PHYS_ADDR(pce_dev->ce_sps.result_dump),
+					CRYPTO_RESULT_DUMP_SIZE,
+					  &pce_dev->ce_sps.out_transfer);
+		_qce_set_flag(&pce_dev->ce_sps.out_transfer,
+							SPS_IOVEC_FLAG_INT);
+	}
+	rc = _qce_sps_transfer(pce_dev);
+
+	if (rc == 0)
+		return 0;
+bad:
+	if (pce_dev->phy_ota_dst)
+		dma_unmap_single(pce_dev->pdev, pce_dev->phy_ota_dst, total,
+				DMA_FROM_DEVICE);
+	dma_unmap_single(pce_dev->pdev, pce_dev->phy_ota_src, total,
+				(req->data_in == req->data_out) ?
+				DMA_BIDIRECTIONAL : DMA_TO_DEVICE);
+	return rc;
+}
+EXPORT_SYMBOL(qce_f8_multi_pkt_req);
+
+int qce_f9_req(void *handle, struct qce_f9_req *req, void *cookie,
+			qce_comp_func_ptr_t qce_cb)
+{
+	struct qce_device *pce_dev = (struct qce_device *) handle;
+	int rc;
+	struct qce_cmdlist_info *cmdlistinfo;
+
+	switch (req->algorithm) {
+	case QCE_OTA_ALGO_KASUMI:
+		cmdlistinfo = &pce_dev->ce_sps.cmdlistptr.f9_kasumi;
+		break;
+	case QCE_OTA_ALGO_SNOW3G:
+		cmdlistinfo = &pce_dev->ce_sps.cmdlistptr.f9_snow3g;
+		break;
+	default:
+		return -EINVAL;
+	};
+
+	pce_dev->phy_ota_src = dma_map_single(pce_dev->pdev, req->message,
+			req->msize, DMA_TO_DEVICE);
+
+	pce_dev->ota_size = req->msize;
+
+	if (pce_dev->support_cmd_dscr)
+		rc = _ce_f9_setup(pce_dev, req, cmdlistinfo);
+	else
+		rc = _ce_f9_setup_direct(pce_dev, req);
+	if (rc < 0)
+		goto bad;
+
+	/* setup for callback, and issue command to sps */
+	pce_dev->areq = cookie;
+	pce_dev->qce_cb = qce_cb;
+
+	/* Register producer callback event for DESC_DONE event. */
+	pce_dev->ce_sps.producer.event.callback = _f9_sps_producer_callback;
+	pce_dev->ce_sps.producer.event.options = SPS_O_DESC_DONE;
+	rc = sps_register_event(pce_dev->ce_sps.producer.pipe,
+					&pce_dev->ce_sps.producer.event);
+	if (rc) {
+		pr_err("Producer callback registration failed rc = %d\n", rc);
+		goto bad;
+	}
+
+	_qce_sps_iovec_count_init(pce_dev);
+	if (pce_dev->support_cmd_dscr)
+		_qce_sps_add_cmd(pce_dev, SPS_IOVEC_FLAG_LOCK, cmdlistinfo,
+					&pce_dev->ce_sps.in_transfer);
+	_qce_sps_add_data((uint32_t)pce_dev->phy_ota_src, req->msize,
+					&pce_dev->ce_sps.in_transfer);
+	_qce_set_flag(&pce_dev->ce_sps.in_transfer,
+				SPS_IOVEC_FLAG_EOT|SPS_IOVEC_FLAG_NWD);
+
+	_qce_sps_add_data(GET_PHYS_ADDR(pce_dev->ce_sps.result_dump),
+					CRYPTO_RESULT_DUMP_SIZE,
+					  &pce_dev->ce_sps.out_transfer);
+	_qce_set_flag(&pce_dev->ce_sps.out_transfer, SPS_IOVEC_FLAG_INT);
+	rc = _qce_sps_transfer(pce_dev);
+	if (rc)
+		goto bad;
+	return 0;
+bad:
+	dma_unmap_single(pce_dev->pdev, pce_dev->phy_ota_src,
+				req->msize, DMA_TO_DEVICE);
+	return rc;
+}
+EXPORT_SYMBOL(qce_f9_req);
+
 static int __qce_get_device_tree_data(struct platform_device *pdev,
 		struct qce_device *pce_dev)
 {
@@ -4115,6 +5147,28 @@
 				"qcom,ce-hw-shared");
 	pce_dev->support_hw_key = of_property_read_bool((&pdev->dev)->of_node,
 				"qcom,ce-hw-key");
+
+	pce_dev->use_sw_aes_cbc_ecb_ctr_algo =
+				of_property_read_bool((&pdev->dev)->of_node,
+				"qcom,use-sw-aes-cbc-ecb-ctr-algo");
+	pce_dev->use_sw_aead_algo =
+				of_property_read_bool((&pdev->dev)->of_node,
+				"qcom,use-sw-aead-algo");
+	pce_dev->use_sw_aes_xts_algo =
+				of_property_read_bool((&pdev->dev)->of_node,
+				"qcom,use-sw-aes-xts-algo");
+	pce_dev->use_sw_ahash_algo =
+				of_property_read_bool((&pdev->dev)->of_node,
+				"qcom,use-sw-ahash-algo");
+	pce_dev->use_sw_hmac_algo =
+				of_property_read_bool((&pdev->dev)->of_node,
+				"qcom,use-sw-hmac-algo");
+	pce_dev->use_sw_aes_ccm_algo =
+				of_property_read_bool((&pdev->dev)->of_node,
+				"qcom,use-sw-aes-ccm-algo");
+	pce_dev->support_clk_mgmt_sus_res = of_property_read_bool(
+		(&pdev->dev)->of_node, "qcom,clk-mgmt-sus-res");
+
 	if (of_property_read_u32((&pdev->dev)->of_node,
 				"qcom,bam-pipe-pair",
 				&pce_dev->ce_sps.pipe_pair_index)) {
@@ -4123,6 +5177,15 @@
 	} else {
 		pr_warn("bam_pipe_pair=0x%x", pce_dev->ce_sps.pipe_pair_index);
 	}
+	if (of_property_read_u32((&pdev->dev)->of_node,
+				"qcom,ce-device",
+				&pce_dev->ce_sps.ce_device)) {
+		pr_err("Fail to get CE device information.\n");
+		return -EINVAL;
+	} else {
+		pr_warn("ce-device =0x%x", pce_dev->ce_sps.ce_device);
+	}
+
 	pce_dev->ce_sps.dest_pipe_index	= 2 * pce_dev->ce_sps.pipe_pair_index;
 	pce_dev->ce_sps.src_pipe_index	= pce_dev->ce_sps.dest_pipe_index + 1;
 
@@ -4339,7 +5402,7 @@
 		goto err_pce_dev;
 	}
 
-	pce_dev->memsize = 9 * PAGE_SIZE;
+	pce_dev->memsize = 10 * PAGE_SIZE;
 	pce_dev->coh_vmem = dma_alloc_coherent(pce_dev->pdev,
 			pce_dev->memsize, &pce_dev->coh_pmem, GFP_KERNEL);
 	if (pce_dev->coh_vmem == NULL) {
@@ -4354,7 +5417,7 @@
 
 	*rc = qce_enable_clk(pce_dev);
 	if (*rc)
-		goto err;
+		goto err_enable_clk;
 
 	if (_probe_ce_engine(pce_dev)) {
 		*rc = -ENXIO;
@@ -4363,12 +5426,17 @@
 	*rc = 0;
 
 	qce_init_ce_cfg_val(pce_dev);
-	qce_sps_init(pce_dev);
+	*rc  = qce_sps_init(pce_dev);
+	if (*rc)
+		goto err;
 	qce_setup_ce_sps_data(pce_dev);
 	qce_disable_clk(pce_dev);
 
 	return pce_dev;
 err:
+	qce_disable_clk(pce_dev);
+
+err_enable_clk:
 	__qce_deinit_clk(pce_dev);
 
 err_mem:
@@ -4410,6 +5478,11 @@
 }
 EXPORT_SYMBOL(qce_close);
 
+#define OTA_SUPPORT_MASK (1 << CRYPTO_ENCR_SNOW3G_SEL |\
+				1 << CRYPTO_ENCR_KASUMI_SEL |\
+				1 << CRYPTO_AUTH_SNOW3G_SEL |\
+				1 << CRYPTO_AUTH_KASUMI_SEL)
+
 int qce_hw_support(void *handle, struct ce_hw_support *ce_support)
 {
 	struct qce_device *pce_dev = (struct qce_device *)handle;
@@ -4424,18 +5497,37 @@
 	ce_support->cmac  = true;
 	ce_support->aes_key_192 = false;
 	ce_support->aes_xts = true;
-	ce_support->ota = false;
+	if ((pce_dev->engines_avail & OTA_SUPPORT_MASK) == OTA_SUPPORT_MASK)
+		ce_support->ota = true;
+	else
+		ce_support->ota = false;
 	ce_support->bam = true;
 	ce_support->is_shared = (pce_dev->is_shared == 1) ? true : false;
 	ce_support->hw_key = pce_dev->support_hw_key;
 	ce_support->aes_ccm = true;
+	ce_support->clk_mgmt_sus_res = pce_dev->support_clk_mgmt_sus_res;
 	if (pce_dev->ce_sps.minor_version)
 		ce_support->aligned_only = false;
 	else
 		ce_support->aligned_only = true;
+
+	ce_support->use_sw_aes_cbc_ecb_ctr_algo =
+				pce_dev->use_sw_aes_cbc_ecb_ctr_algo;
+	ce_support->use_sw_aead_algo =
+				pce_dev->use_sw_aead_algo;
+	ce_support->use_sw_aes_xts_algo =
+				pce_dev->use_sw_aes_xts_algo;
+	ce_support->use_sw_ahash_algo =
+				pce_dev->use_sw_ahash_algo;
+	ce_support->use_sw_hmac_algo =
+				pce_dev->use_sw_hmac_algo;
+	ce_support->use_sw_aes_ccm_algo =
+				pce_dev->use_sw_aes_ccm_algo;
+	ce_support->ce_device = pce_dev->ce_sps.ce_device;
 	return 0;
 }
 EXPORT_SYMBOL(qce_hw_support);
 
+
 MODULE_LICENSE("GPL v2");
 MODULE_DESCRIPTION("Crypto Engine driver");
diff --git a/drivers/crypto/msm/qce50.h b/drivers/crypto/msm/qce50.h
index adab5d4..78bfdee 100644
--- a/drivers/crypto/msm/qce50.h
+++ b/drivers/crypto/msm/qce50.h
@@ -113,6 +113,10 @@
 	struct qce_cmdlist_info aead_hmac_sha1_ecb_3des;
 	struct qce_cmdlist_info aead_aes_128_ccm;
 	struct qce_cmdlist_info aead_aes_256_ccm;
+	struct qce_cmdlist_info f8_kasumi;
+	struct qce_cmdlist_info f8_snow3g;
+	struct qce_cmdlist_info f9_kasumi;
+	struct qce_cmdlist_info f9_snow3g;
 	struct qce_cmdlist_info unlock_all_pipes;
 };
 
@@ -140,6 +144,8 @@
 
 	uint32_t encr_cfg_3des_cbc;
 	uint32_t encr_cfg_3des_ecb;
+	uint32_t encr_cfg_kasumi;
+	uint32_t encr_cfg_snow3g;
 
 	uint32_t auth_cfg_cmac_128;
 	uint32_t auth_cfg_cmac_256;
@@ -154,7 +160,8 @@
 	uint32_t auth_cfg_aes_ccm_256;
 	uint32_t auth_cfg_aead_sha1_hmac;
 	uint32_t auth_cfg_aead_sha256_hmac;
-
+	uint32_t auth_cfg_kasumi;
+	uint32_t auth_cfg_snow3g;
 };
 
 /* DM data structure with buffers, commandlists & commmand pointer lists */
@@ -169,6 +176,7 @@
 	struct sps_event_notify		notify;
 	struct scatterlist		*src;
 	struct scatterlist		*dst;
+	uint32_t			ce_device;
 	unsigned int			pipe_pair_index;
 	unsigned int			src_pipe_index;
 	unsigned int			dest_pipe_index;
diff --git a/drivers/crypto/msm/qcrypto.c b/drivers/crypto/msm/qcrypto.c
index 6606706..c247189 100644
--- a/drivers/crypto/msm/qcrypto.c
+++ b/drivers/crypto/msm/qcrypto.c
@@ -1,6 +1,6 @@
 /* Qualcomm Crypto driver
  *
- * 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
@@ -24,6 +24,10 @@
 #include <linux/interrupt.h>
 #include <linux/spinlock.h>
 #include <linux/debugfs.h>
+#include <linux/workqueue.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/cache.h>
 
 #include <crypto/ctr.h>
 #include <crypto/des.h>
@@ -35,6 +39,7 @@
 #include <crypto/authenc.h>
 #include <crypto/scatterwalk.h>
 #include <crypto/internal/hash.h>
+#include <crypto/internal/aead.h>
 
 #include <mach/scm.h>
 #include <linux/platform_data/qcom_crypto_device.h>
@@ -51,38 +56,86 @@
  */
 #define MAX_ALIGN_SIZE  0x40
 
+#define QCRYPTO_HIGH_BANDWIDTH_TIMEOUT 1000
+
+enum qcrypto_bus_state {
+	BUS_NO_BANDWIDTH = 0,
+	BUS_HAS_BANDWIDTH,
+	BUS_BANDWIDTH_RELEASING,
+	BUS_BANDWIDTH_ALLOCATING,
+	BUS_SUSPENDED,
+};
+
 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_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 assigned
+					 * waiting to be executed
+					 */
+	u64 total_req;
+	u64 err_req;
+	u32 unit;
+	u32 ce_device;
+	unsigned int signature;
+
+	enum qcrypto_bus_state bw_state;
+	bool   high_bw_req;
+	struct timer_list bw_reaper_timer;
+	struct work_struct bw_reaper_ws;
+	struct work_struct bw_allocate_ws;
+
+	/* engine execution sequence number */
+	u32    active_seq;
+	/* last QCRYPTO_HIGH_BANDWIDTH_TIMEOUT active_seq */
+	u32    last_active_seq;
+
+	bool   check_flag;
+};
 
 struct crypto_priv {
 	/* CE features supported by target device*/
@@ -91,34 +144,31 @@
 	/* CE features/algorithms supported by HW engine*/
 	struct ce_hw_support ce_support;
 
-	uint32_t  bus_scale_handle;
-	/* the lock protects queue and req*/
+	/* the lock protects crypto queue and req */
 	spinlock_t lock;
 
-	/* qce handle */
-	void *qce;
-
 	/* list of  registered algorithms */
 	struct list_head alg_list;
 
-	/* platform device */
-	struct platform_device *pdev;
-
 	/* current active request */
 	struct crypto_async_request *req;
-	int res;
-
-	/* request queue */
-	struct crypto_queue queue;
 
 	uint32_t ce_lock_count;
-	uint32_t high_bw_req_count;
-
 	struct work_struct unlock_ce_ws;
+	struct list_head engine_list; /* list of  qcrypto engines */
+	int32_t total_units;   /* total units of engines */
+	struct mutex engine_lock;
 
-	struct tasklet_struct done_tasklet;
+	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(
+					struct crypto_priv *cp);
 
 /*-------------------------------------------------------------------------
 * Resource Locking Service
@@ -129,8 +179,6 @@
 #define NUM_RETRY				1000
 #define CE_BUSY				        55
 
-static DEFINE_MUTEX(qcrypto_sent_bw_req);
-
 static int qcrypto_scm_cmd(int resource, int cmd, int *response)
 {
 #ifdef CONFIG_MSM_SCM
@@ -151,6 +199,29 @@
 #endif
 }
 
+static struct crypto_engine *_qrypto_find_pengine_device(struct crypto_priv *cp,
+			 unsigned int device)
+{
+	struct crypto_engine *entry = NULL;
+	unsigned long flags;
+
+	spin_lock_irqsave(&cp->lock, flags);
+	list_for_each_entry(entry, &cp->engine_list, elist) {
+		if (entry->ce_device == device)
+			break;
+	}
+	spin_unlock_irqrestore(&cp->lock, flags);
+
+	if (((entry != NULL) && (entry->ce_device != device)) ||
+		(entry == NULL)) {
+		pr_err("Device node for CE device %d NOT FOUND!!\n",
+				device);
+		return NULL;
+	}
+
+	return entry;
+}
+
 static void qcrypto_unlock_ce(struct work_struct *work)
 {
 	int response = 0;
@@ -212,7 +283,14 @@
 /* max of AES_BLOCK_SIZE, DES3_EDE_BLOCK_SIZE */
 #define QCRYPTO_MAX_IV_LENGTH	16
 
+#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];
 
@@ -222,12 +300,20 @@
 	unsigned int authsize;
 	unsigned int auth_key_len;
 
-	struct crypto_priv *cp;
-	unsigned int flags;
+	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;
 	int  aead;
 	struct scatterlist asg;		/* Formatted associated data sg  */
@@ -250,6 +336,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,
@@ -265,31 +353,22 @@
 };
 
 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		byte_count[4];
-	uint8_t			digest[SHA_MAX_DIGEST_SIZE];
 	uint32_t		diglen;
-	uint8_t			*tmp_tbuf;
-	uint8_t			*trailing_buf;
-	uint8_t			*in_buf;
 	uint32_t		authkey_in_len;
-	uint32_t		trailing_buf_len;
-	uint8_t			first_blk;
-	uint8_t			last_blk;
 	uint8_t			authkey[SHA_MAX_BLOCK_SIZE];
 	struct ahash_request *ahash_req;
 	struct completion ahash_req_complete;
-	struct scatterlist *sg;
-	struct scatterlist tmp_sg;
-	struct crypto_priv *cp;
-	unsigned int flags;
 };
 
 struct qcrypto_sha_req_ctx {
-	union {
-		struct sha1_state sha1_state_ctx;
-		struct sha256_state sha256_state_ctx;
-	};
+	struct qcrypto_resp_ctx rsp_entry;/* rsp entry. */
+	struct crypto_engine *pengine;  /* engine assigned to this request */
+
 	struct scatterlist *src;
 	uint32_t nbytes;
 
@@ -297,6 +376,20 @@
 	struct scatterlist dsg;		/* Data sg */
 	unsigned char *data;		/* Incoming data pointer*/
 	unsigned char *data2;		/* Updated data pointer*/
+
+	uint32_t byte_count[4];
+	u64 count;
+	uint8_t	first_blk;
+	uint8_t	last_blk;
+	uint8_t	 trailing_buf[SHA_MAX_BLOCK_SIZE];
+	uint32_t trailing_buf_len;
+
+	/* dma buffer, Internal use */
+	uint8_t	staging_dmabuf
+		[SHA_MAX_BLOCK_SIZE+SHA_MAX_DIGEST_SIZE+MAX_ALIGN_SIZE];
+
+	uint8_t	digest[SHA_MAX_DIGEST_SIZE];
+	struct scatterlist sg[2];
 };
 
 static void _byte_stream_to_words(uint32_t *iv, unsigned char *b,
@@ -304,7 +397,7 @@
 {
 	unsigned n;
 
-	n = len  / sizeof(uint32_t) ;
+	n = len  / sizeof(uint32_t);
 	for (; n > 0; n--) {
 		*iv =  ((*b << 24)      & 0xff000000) |
 				(((*(b+1)) << 16) & 0xff0000)   |
@@ -318,12 +411,12 @@
 	if (n == 3) {
 		*iv = ((*b << 24) & 0xff000000) |
 				(((*(b+1)) << 16) & 0xff0000)   |
-				(((*(b+2)) << 8) & 0xff00)     ;
+				(((*(b+2)) << 8) & 0xff00);
 	} else if (n == 2) {
 		*iv = ((*b << 24) & 0xff000000) |
-				(((*(b+1)) << 16) & 0xff0000)   ;
+				(((*(b+1)) << 16) & 0xff0000);
 	} else if (n == 1) {
-		*iv = ((*b << 24) & 0xff000000) ;
+		*iv = ((*b << 24) & 0xff000000);
 	}
 }
 
@@ -352,58 +445,157 @@
 	}
 }
 
-static void qcrypto_ce_high_bw_req(struct crypto_priv *cp, bool high_bw_req)
+static void qcrypto_ce_set_bus(struct crypto_engine *pengine,
+				 bool high_bw_req)
 {
 	int ret = 0;
 
-	mutex_lock(&qcrypto_sent_bw_req);
 	if (high_bw_req) {
-		if (cp->high_bw_req_count == 0) {
-			ret = qce_enable_clk(cp->qce);
-			if (ret) {
-				pr_err("%s Unable enable clk\n", __func__);
-				mutex_unlock(&qcrypto_sent_bw_req);
-				return;
-			}
-			ret = msm_bus_scale_client_update_request(
-					cp->bus_scale_handle, 1);
-			if (ret) {
-				pr_err("%s Unable to set to high bandwidth\n",
-							__func__);
-				qce_disable_clk(cp->qce);
-				mutex_unlock(&qcrypto_sent_bw_req);
-				return;
-			}
+		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;
 		}
-		cp->high_bw_req_count++;
+		ret = msm_bus_scale_client_update_request(
+				pengine->bus_scale_handle, 1);
+		if (ret) {
+			pr_err("%s Unable to set to high bandwidth\n",
+						__func__);
+			qce_disable_clk(pengine->qce);
+			goto clk_err;
+		}
+
+
 	} else {
-		if (cp->high_bw_req_count == 1) {
-			ret = msm_bus_scale_client_update_request(
-					cp->bus_scale_handle, 0);
-			if (ret) {
-				pr_err("%s Unable to set to low bandwidth\n",
-							__func__);
-				mutex_unlock(&qcrypto_sent_bw_req);
-				return;
-			}
-			ret = qce_disable_clk(cp->qce);
-			if (ret) {
-				pr_err("%s Unable disable clk\n", __func__);
-				ret = msm_bus_scale_client_update_request(
-					cp->bus_scale_handle, 1);
-				if (ret)
-					pr_err("%s Unable to set to high bandwidth\n",
-							__func__);
-				mutex_unlock(&qcrypto_sent_bw_req);
-				return;
-			}
+
+		ret = msm_bus_scale_client_update_request(
+				pengine->bus_scale_handle, 0);
+		if (ret) {
+			pr_err("%s Unable to set to low bandwidth\n",
+						__func__);
+			goto clk_err;
 		}
-		cp->high_bw_req_count--;
+		ret = qce_disable_clk(pengine->qce);
+		if (ret) {
+			pr_err("%s Unable disable clk\n", __func__);
+			ret = msm_bus_scale_client_update_request(
+				pengine->bus_scale_handle, 1);
+			if (ret)
+				pr_err("%s Unable to set to high bandwidth\n",
+						__func__);
+			goto clk_err;
+		}
+		pm_relax(&pengine->pdev->dev);
 	}
-	mutex_unlock(&qcrypto_sent_bw_req);
+	return;
+clk_err:
+	pm_relax(&pengine->pdev->dev);
+	return;
+
 }
 
-static int _start_qcrypto_process(struct crypto_priv *cp);
+static void qcrypto_bw_reaper_timer_callback(unsigned long data)
+{
+	struct crypto_engine *pengine = (struct crypto_engine *)data;
+
+	schedule_work(&pengine->bw_reaper_ws);
+
+	return;
+}
+
+static void qcrypto_bw_set_timeout(struct crypto_engine *pengine)
+{
+	pengine->bw_reaper_timer.data =
+			(unsigned long)(pengine);
+	pengine->bw_reaper_timer.expires = jiffies +
+			msecs_to_jiffies(QCRYPTO_HIGH_BANDWIDTH_TIMEOUT);
+	add_timer(&(pengine->bw_reaper_timer));
+}
+
+static void qcrypto_ce_bw_allocate_req(struct crypto_engine *pengine)
+{
+	schedule_work(&pengine->bw_allocate_ws);
+}
+
+static int _start_qcrypto_process(struct crypto_priv *cp,
+					struct crypto_engine *pengine);
+
+static void qcrypto_bw_allocate_work(struct work_struct *work)
+{
+	struct  crypto_engine *pengine = container_of(work,
+				struct crypto_engine, bw_allocate_ws);
+	unsigned long flags;
+	struct crypto_priv *cp = pengine->pcp;
+
+	spin_lock_irqsave(&cp->lock, flags);
+	pengine->bw_state = BUS_BANDWIDTH_ALLOCATING;
+	spin_unlock_irqrestore(&cp->lock, flags);
+
+	qcrypto_ce_set_bus(pengine, true);
+
+	spin_lock_irqsave(&cp->lock, flags);
+	pengine->bw_state = BUS_HAS_BANDWIDTH;
+	pengine->high_bw_req = false;
+	pengine->active_seq++;
+	pengine->check_flag = true;
+	spin_unlock_irqrestore(&cp->lock, flags);
+	_start_qcrypto_process(cp, pengine);
+};
+
+static void qcrypto_bw_reaper_work(struct work_struct *work)
+{
+	struct  crypto_engine *pengine = container_of(work,
+				struct crypto_engine, bw_reaper_ws);
+	struct crypto_priv *cp = pengine->pcp;
+	unsigned long flags;
+	u32    active_seq;
+	bool restart = false;
+
+	spin_lock_irqsave(&cp->lock, flags);
+	active_seq = pengine->active_seq;
+	if (pengine->bw_state == BUS_HAS_BANDWIDTH &&
+		(active_seq == pengine->last_active_seq)) {
+
+		/* check if engine is stuck */
+		if (pengine->req) {
+			if (pengine->check_flag)
+				dev_err(&pengine->pdev->dev,
+				"The engine appears to be stuck seq %d req %p.\n",
+				active_seq, pengine->req);
+			pengine->check_flag = false;
+			goto ret;
+		}
+		if (cp->platform_support.bus_scale_table == NULL)
+			goto ret;
+		pengine->bw_state = BUS_BANDWIDTH_RELEASING;
+		spin_unlock_irqrestore(&cp->lock, flags);
+
+		qcrypto_ce_set_bus(pengine, false);
+
+		spin_lock_irqsave(&cp->lock, flags);
+
+		if (pengine->high_bw_req == true) {
+			/* we got request while we are disabling clock */
+			pengine->bw_state = BUS_BANDWIDTH_ALLOCATING;
+			spin_unlock_irqrestore(&cp->lock, flags);
+
+			qcrypto_ce_set_bus(pengine, true);
+
+			spin_lock_irqsave(&cp->lock, flags);
+			pengine->bw_state = BUS_HAS_BANDWIDTH;
+			pengine->high_bw_req = false;
+			restart = true;
+		} else
+			pengine->bw_state = BUS_NO_BANDWIDTH;
+	}
+ret:
+	pengine->last_active_seq = active_seq;
+	spin_unlock_irqrestore(&cp->lock, flags);
+	if (restart)
+		_start_qcrypto_process(cp, pengine);
+	qcrypto_bw_set_timeout(pengine);
+}
 
 static int qcrypto_count_sg(struct scatterlist *sg, int nbytes)
 {
@@ -499,9 +691,13 @@
 
 	/* random first IV */
 	get_random_bytes(ctx->iv, QCRYPTO_MAX_IV_LENGTH);
-	if (ctx->cp->platform_support.bus_scale_table != NULL)
-		qcrypto_ce_high_bw_req(ctx->cp, true);
-
+	if (_qcrypto_init_assign) {
+		ctx->pengine = _qcrypto_static_assign_engine(ctx->cp);
+		if (ctx->pengine == NULL)
+			return -ENODEV;
+	} else
+		ctx->pengine = NULL;
+	INIT_LIST_HEAD(&ctx->rsp_queue);
 	return 0;
 };
 
@@ -517,30 +713,15 @@
 	crypto_ahash_set_reqsize(ahash, sizeof(struct qcrypto_sha_req_ctx));
 	/* update context with ptr to cp */
 	sha_ctx->cp = q_alg->cp;
-	sha_ctx->sg = NULL;
 	sha_ctx->flags = 0;
-
-	sha_ctx->tmp_tbuf = kzalloc(SHA_MAX_BLOCK_SIZE +
-					SHA_MAX_DIGEST_SIZE, GFP_KERNEL);
-	if (sha_ctx->tmp_tbuf == NULL) {
-		pr_err("qcrypto Can't Allocate mem: sha_ctx->tmp_tbuf, error %ld\n",
-			PTR_ERR(sha_ctx->tmp_tbuf));
-		return -ENOMEM;
-	}
-
-	sha_ctx->trailing_buf = kzalloc(SHA_MAX_BLOCK_SIZE, GFP_KERNEL);
-	if (sha_ctx->trailing_buf == NULL) {
-		kfree(sha_ctx->tmp_tbuf);
-		sha_ctx->tmp_tbuf = NULL;
-		pr_err("qcrypto Can't Allocate mem: sha_ctx->trailing_buf, error %ld\n",
-			PTR_ERR(sha_ctx->trailing_buf));
-		return -ENOMEM;
-	}
-
 	sha_ctx->ahash_req = NULL;
-	if (sha_ctx->cp->platform_support.bus_scale_table != NULL)
-		qcrypto_ce_high_bw_req(sha_ctx->cp, 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;
+	INIT_LIST_HEAD(&sha_ctx->rsp_queue);
 	return 0;
 };
 
@@ -548,20 +729,12 @@
 {
 	struct qcrypto_sha_ctx *sha_ctx = crypto_tfm_ctx(tfm);
 
-	kfree(sha_ctx->tmp_tbuf);
-	sha_ctx->tmp_tbuf = NULL;
-	kfree(sha_ctx->trailing_buf);
-	sha_ctx->trailing_buf = NULL;
-	if (sha_ctx->sg != NULL) {
-		kfree(sha_ctx->sg);
-		sha_ctx->sg = NULL;
-	}
+	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->cp->platform_support.bus_scale_table != NULL)
-		qcrypto_ce_high_bw_req(sha_ctx->cp, false);
 };
 
 
@@ -610,134 +783,175 @@
 {
 	struct qcrypto_cipher_ctx *ctx = crypto_tfm_ctx(tfm);
 
-	if (ctx->cp->platform_support.bus_scale_table != NULL)
-		qcrypto_ce_high_bw_req(ctx->cp, false);
+	if (!list_empty(&ctx->rsp_queue))
+		pr_err("_qcrypto__cra_ablkcipher_exit: requests still outstanding");
 };
 
 static void _qcrypto_cra_aead_exit(struct crypto_tfm *tfm)
 {
 	struct qcrypto_cipher_ctx *ctx = crypto_tfm_ctx(tfm);
 
-	if (ctx->cp->platform_support.bus_scale_table != NULL)
-		qcrypto_ce_high_bw_req(ctx->cp, false);
+	if (!list_empty(&ctx->rsp_queue))
+		pr_err("_qcrypto__cra_aead_exit: requests still outstanding");
 };
 
 static int _disp_stats(int id)
 {
 	struct crypto_stat *pstat;
 	int len = 0;
+	unsigned long flags;
+	struct crypto_priv *cp = &qcrypto_dev;
+	struct crypto_engine *pe;
 
 	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 operation success       : %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     : %llu\n",
+					pstat->aead_rfc4309_ccm_aes_dec);
+	len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
+			"   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 %4d Req                     : %llu\n",
+			pe->unit,
+			pe->total_req
+		);
+		len += snprintf(
+			_debug_read_buf + len,
+			DEBUG_MAX_RW_BUF - len - 1,
+			"   Engine %4d Req Error               : %llu\n",
+			pe->unit,
+			pe->err_req
+		);
+	}
+	spin_unlock_irqrestore(&cp->lock, flags);
 	return len;
 }
 
-static int _qcrypto_remove(struct platform_device *pdev)
+static void _qcrypto_remove_engine(struct crypto_engine *pengine)
 {
 	struct crypto_priv *cp;
 	struct qcrypto_alg *q_alg;
 	struct qcrypto_alg *n;
+	unsigned long flags;
 
-	cp = platform_get_drvdata(pdev);
+	cp = pengine->pcp;
 
-	if (!cp)
-		return 0;
+	spin_lock_irqsave(&cp->lock, flags);
+	list_del(&pengine->elist);
+	if (cp->next_engine == pengine)
+		cp->next_engine = NULL;
+	spin_unlock_irqrestore(&cp->lock, flags);
 
-	if (cp->platform_support.bus_scale_table != NULL)
-		msm_bus_scale_unregister_client(cp->bus_scale_handle);
+	cp->total_units--;
+
+	tasklet_kill(&pengine->done_tasklet);
+	cancel_work_sync(&pengine->bw_reaper_ws);
+	cancel_work_sync(&pengine->bw_allocate_ws);
+	del_timer_sync(&pengine->bw_reaper_timer);
+
+	if (pengine->bus_scale_handle != 0)
+		msm_bus_scale_unregister_client(pengine->bus_scale_handle);
+	pengine->bus_scale_handle = 0;
+
+	if (cp->total_units)
+		return;
 
 	list_for_each_entry_safe(q_alg, n, &cp->alg_list, entry) {
 		if (q_alg->alg_type == QCRYPTO_ALG_CIPHER)
@@ -747,14 +961,26 @@
 		list_del(&q_alg->entry);
 		kfree(q_alg);
 	}
+}
 
-	if (cp->qce)
-		qce_close(cp->qce);
-	tasklet_kill(&cp->done_tasklet);
-	kfree(cp);
+static int _qcrypto_remove(struct platform_device *pdev)
+{
+	struct crypto_engine *pengine;
+	struct crypto_priv *cp;
+
+	pengine = platform_get_drvdata(pdev);
+
+	if (!pengine)
+		return 0;
+	cp = pengine->pcp;
+	mutex_lock(&cp->engine_lock);
+	_qcrypto_remove_engine(pengine);
+	mutex_unlock(&cp->engine_lock);
+	if (pengine->qce)
+		qce_close(pengine->qce);
+	kfree(pengine);
 	return 0;
-};
-
+}
 
 static int _qcrypto_check_aes_keylen(struct crypto_ablkcipher *cipher,
 		struct crypto_priv *cp, unsigned int len)
@@ -891,56 +1117,72 @@
 	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_priv *cp = (struct crypto_priv *)data;
+	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 = cp->req;
-	cp->req = NULL;
+	areq = pengine->req;
+
+	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)
-		areq->complete(areq, cp->res);
-	_start_qcrypto_process(cp);
-};
-
-static void _update_sha1_ctx(struct ahash_request  *req)
-{
-	struct qcrypto_sha_req_ctx *rctx = ahash_request_ctx(req);
-	struct sha1_state *sha_state_ctx = &rctx->sha1_state_ctx;
-	struct qcrypto_sha_ctx *sha_ctx = crypto_tfm_ctx(req->base.tfm);
-
-	if (sha_ctx->last_blk == 1)
-		memset(sha_state_ctx, 0x00, sizeof(struct sha1_state));
-	else {
-		memset(sha_state_ctx->buffer, 0x00, SHA1_BLOCK_SIZE);
-		memcpy(sha_state_ctx->buffer, sha_ctx->trailing_buf,
-						sha_ctx->trailing_buf_len);
-		_byte_stream_to_words(sha_state_ctx->state , sha_ctx->digest,
-					SHA1_DIGEST_SIZE);
-	}
-	return;
-}
-
-static void _update_sha256_ctx(struct ahash_request  *req)
-{
-	struct qcrypto_sha_req_ctx *rctx = ahash_request_ctx(req);
-	struct sha256_state *sha_state_ctx = &rctx->sha256_state_ctx;
-	struct qcrypto_sha_ctx *sha_ctx = crypto_tfm_ctx(req->base.tfm);
-
-	if (sha_ctx->last_blk == 1)
-		memset(sha_state_ctx, 0x00, sizeof(struct sha256_state));
-	else {
-		memset(sha_state_ctx->buf, 0x00, SHA256_BLOCK_SIZE);
-		memcpy(sha_state_ctx->buf, sha_ctx->trailing_buf,
-						sha_ctx->trailing_buf_len);
-		_byte_stream_to_words(sha_state_ctx->state, sha_ctx->digest,
-					SHA256_DIGEST_SIZE);
-	}
-	return;
+		_qcrypto_tfm_complete(cp, type, tfm_ctx);
 }
 
 static void _qce_ahash_complete(void *cookie, unsigned char *digest,
@@ -954,44 +1196,36 @@
 	struct crypto_stat *pstat;
 	uint32_t diglen = crypto_ahash_digestsize(ahash);
 	uint32_t *auth32 = (uint32_t *)authdata;
+	struct crypto_engine *pengine;
 
 	pstat = &_qcrypto_stat;
 
+	pengine = rctx->pengine;
 #ifdef QCRYPTO_DEBUG
-	dev_info(&cp->pdev->dev, "_qce_ahash_complete: %p ret %d\n",
+	dev_info(&pengine->pdev->dev, "_qce_ahash_complete: %p ret %d\n",
 				areq, ret);
 #endif
 	if (digest) {
-		memcpy(sha_ctx->digest, digest, diglen);
+		memcpy(rctx->digest, digest, diglen);
 		memcpy(areq->result, digest, diglen);
 	}
 	if (authdata) {
-		sha_ctx->byte_count[0] = auth32[0];
-		sha_ctx->byte_count[1] = auth32[1];
-		sha_ctx->byte_count[2] = auth32[2];
-		sha_ctx->byte_count[3] = auth32[3];
+		rctx->byte_count[0] = auth32[0];
+		rctx->byte_count[1] = auth32[1];
+		rctx->byte_count[2] = auth32[2];
+		rctx->byte_count[3] = auth32[3];
 	}
 	areq->src = rctx->src;
 	areq->nbytes = rctx->nbytes;
 
-	if (sha_ctx->sg != NULL) {
-		kfree(sha_ctx->sg);
-		sha_ctx->sg = NULL;
-	}
-
-	if (sha_ctx->alg == QCE_HASH_SHA1)
-		_update_sha1_ctx(areq);
-	if (sha_ctx->alg == QCE_HASH_SHA256)
-		_update_sha256_ctx(areq);
-
-	sha_ctx->last_blk = 0;
-	sha_ctx->first_blk = 0;
+	rctx->last_blk = 0;
+	rctx->first_blk = 0;
 
 	if (ret) {
-		cp->res = -ENXIO;
+		pengine->res = -ENXIO;
 		pstat->sha_op_fail++;
 	} else {
-		cp->res = 0;
+		pengine->res = 0;
 		pstat->sha_op_success++;
 	}
 	if (cp->ce_support.aligned_only)  {
@@ -1001,7 +1235,7 @@
 
 	if (cp->platform_support.ce_shared)
 		schedule_work(&cp->unlock_ce_ws);
-	tasklet_schedule(&cp->done_tasklet);
+	tasklet_schedule(&pengine->done_tasklet);
 };
 
 static void _qce_ablk_cipher_complete(void *cookie, unsigned char *icb,
@@ -1012,21 +1246,24 @@
 	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;
-
+	rctx = ablkcipher_request_ctx(areq);
+	pengine = rctx->pengine;
 #ifdef QCRYPTO_DEBUG
-	dev_info(&cp->pdev->dev, "_qce_ablk_cipher_complete: %p ret %d\n",
+	dev_info(&pengine->pdev->dev, "_qce_ablk_cipher_complete: %p ret %d\n",
 				areq, ret);
 #endif
 	if (iv)
 		memcpy(ctx->iv, iv, crypto_ablkcipher_ivsize(ablk));
 
 	if (ret) {
-		cp->res = -ENXIO;
+		pengine->res = -ENXIO;
 		pstat->ablk_cipher_op_fail++;
 	} else {
-		cp->res = 0;
+		pengine->res = 0;
 		pstat->ablk_cipher_op_success++;
 	}
 
@@ -1050,7 +1287,7 @@
 
 	if (cp->platform_support.ce_shared)
 		schedule_work(&cp->unlock_ce_ws);
-	tasklet_schedule(&cp->done_tasklet);
+	tasklet_schedule(&pengine->done_tasklet);
 };
 
 
@@ -1063,10 +1300,11 @@
 	struct crypto_priv *cp = ctx->cp;
 	struct qcrypto_cipher_req_ctx *rctx;
 	struct crypto_stat *pstat;
+	struct crypto_engine *pengine;
 
 	pstat = &_qcrypto_stat;
-
 	rctx = aead_request_ctx(areq);
+	pengine = rctx->pengine;
 
 	if (rctx->mode == QCE_MODE_CCM) {
 		if (cp->ce_support.aligned_only)  {
@@ -1162,11 +1400,11 @@
 	else
 		pstat->aead_op_success++;
 
-	cp->res = ret;
+	pengine->res = ret;
 
 	if (cp->platform_support.ce_shared)
 		schedule_work(&cp->unlock_ce_ws);
-	tasklet_schedule(&cp->done_tasklet);
+	tasklet_schedule(&pengine->done_tasklet);
 }
 
 static int aead_ccm_set_msg_len(u8 *block, unsigned int msglen, int csize)
@@ -1215,6 +1453,12 @@
 	uint32_t bytes = 0;
 	uint32_t num_sg = 0;
 
+	if (alen == 0) {
+		qreq->assoc = NULL;
+		qreq->assoclen = 0;
+		return 0;
+	}
+
 	qreq->assoc = kzalloc((alen + 0x64), GFP_ATOMIC);
 	if (!qreq->assoc) {
 		pr_err("qcrypto Memory allocation of adata FAIL, error %ld\n",
@@ -1251,7 +1495,7 @@
 	return 0;
 }
 
-static int _qcrypto_process_ablkcipher(struct crypto_priv *cp,
+static int _qcrypto_process_ablkcipher(struct crypto_engine *pengine,
 				struct crypto_async_request *async_req)
 {
 	struct qce_req qreq;
@@ -1264,8 +1508,9 @@
 	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 (cp->ce_support.aligned_only) {
+	if (pengine->pcp->ce_support.aligned_only) {
 		uint32_t bytes = 0;
 		uint32_t num_sg = 0;
 
@@ -1306,35 +1551,38 @@
 	qreq.flags = cipher_ctx->flags;
 
 	if ((cipher_ctx->enc_key_len == 0) &&
-			(cp->platform_support.hw_key_support == 0))
+			(pengine->pcp->platform_support.hw_key_support == 0))
 		ret = -EINVAL;
 	else
-		ret =  qce_ablk_cipher_req(cp->qce, &qreq);
+		ret =  qce_ablk_cipher_req(pengine->qce, &qreq);
 
 	return ret;
 }
 
-static int _qcrypto_process_ahash(struct crypto_priv *cp,
+static int _qcrypto_process_ahash(struct crypto_engine *pengine,
 				struct crypto_async_request *async_req)
 {
 	struct ahash_request *req;
 	struct qce_sha_req sreq;
+	struct qcrypto_sha_req_ctx *rctx;
 	struct qcrypto_sha_ctx *sha_ctx;
 	int ret = 0;
 
 	req = container_of(async_req,
 				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 =  &sha_ctx->digest[0];
+	sreq.digest =  &rctx->digest[0];
 	sreq.src = req->src;
-	sreq.auth_data[0] = sha_ctx->byte_count[0];
-	sreq.auth_data[1] = sha_ctx->byte_count[1];
-	sreq.auth_data[2] = sha_ctx->byte_count[2];
-	sreq.auth_data[3] = sha_ctx->byte_count[3];
-	sreq.first_blk = sha_ctx->first_blk;
-	sreq.last_blk = sha_ctx->last_blk;
+	sreq.auth_data[0] = rctx->byte_count[0];
+	sreq.auth_data[1] = rctx->byte_count[1];
+	sreq.auth_data[2] = rctx->byte_count[2];
+	sreq.auth_data[3] = rctx->byte_count[3];
+	sreq.first_blk = rctx->first_blk;
+	sreq.last_blk = rctx->last_blk;
 	sreq.size = req->nbytes;
 	sreq.areq = req;
 	sreq.flags = sha_ctx->flags;
@@ -1363,12 +1611,12 @@
 		ret = -1;
 		break;
 	};
-	ret =  qce_process_sha_req(cp->qce, &sreq);
+	ret =  qce_process_sha_req(pengine->qce, &sreq);
 
 	return ret;
 }
 
-static int _qcrypto_process_aead(struct crypto_priv *cp,
+static int _qcrypto_process_aead(struct  crypto_engine *pengine,
 				struct crypto_async_request *async_req)
 {
 	struct qce_req qreq;
@@ -1380,6 +1628,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;
@@ -1396,7 +1645,10 @@
 	qreq.authkey = cipher_ctx->auth_key;
 	qreq.authklen = cipher_ctx->auth_key_len;
 	qreq.authsize = crypto_aead_authsize(aead);
-	qreq.ivsize =  crypto_aead_ivsize(aead);
+	if (qreq.mode == QCE_MODE_CCM)
+		qreq.ivsize =  AES_BLOCK_SIZE;
+	else
+		qreq.ivsize =  crypto_aead_ivsize(aead);
 	qreq.flags = cipher_ctx->flags;
 
 	if (qreq.mode == QCE_MODE_CCM) {
@@ -1417,7 +1669,7 @@
 		if (ret)
 			return ret;
 
-		if (cp->ce_support.aligned_only) {
+		if (pengine->pcp->ce_support.aligned_only) {
 			uint32_t bytes = 0;
 			uint32_t num_sg = 0;
 
@@ -1443,8 +1695,9 @@
 				kzfree(qreq.assoc);
 				return -ENOMEM;
 			}
-
-			memcpy((char *)rctx->data, qreq.assoc, qreq.assoclen);
+			if (qreq.assoclen)
+				memcpy((char *)rctx->data, qreq.assoc,
+						 qreq.assoclen);
 
 			num_sg = qcrypto_count_sg(req->src, req->cryptlen);
 			bytes = qcrypto_sg_copy_to_buffer(req->src, num_sg,
@@ -1487,7 +1740,7 @@
 		sg_mark_end(req->assoc);
 	} else {
 		/* for aead operations, other than aes(ccm) */
-		if (cp->ce_support.aligned_only) {
+		if (pengine->pcp->ce_support.aligned_only) {
 			uint32_t bytes = 0;
 			uint32_t num_sg = 0;
 
@@ -1558,53 +1811,147 @@
 			req->dst = &rctx->dsg;
 		}
 	}
-	ret =  qce_aead_req(cp->qce, &qreq);
+	ret =  qce_aead_req(pengine->qce, &qreq);
 
 	return ret;
 }
+#define list_next_entry(pos, member) \
+		list_entry(pos->member.next, typeof(*pos), member)
+static struct crypto_engine *_qcrypto_static_assign_engine(
+					struct crypto_priv *cp)
+{
+	struct crypto_engine *pengine;
+	unsigned long flags;
 
-static int _start_qcrypto_process(struct crypto_priv *cp)
+	spin_lock_irqsave(&cp->lock, flags);
+	if (cp->next_engine)
+		pengine = cp->next_engine;
+	else
+		pengine = list_first_entry(&cp->engine_list,
+				struct crypto_engine, elist);
+
+	if (list_is_last(&pengine->elist, &cp->engine_list))
+		cp->next_engine = list_first_entry(
+			&cp->engine_list, struct crypto_engine, elist);
+	else
+		cp->next_engine = list_next_entry(pengine, elist);
+	spin_unlock_irqrestore(&cp->lock, flags);
+	return pengine;
+}
+
+static int _start_qcrypto_process(struct crypto_priv *cp,
+				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 (cp->req == NULL) {
-		backlog = crypto_get_backlog(&cp->queue);
-		async_req = crypto_dequeue_request(&cp->queue);
-		cp->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_ABLKCIPHER:
-		ret = _qcrypto_process_ablkcipher(cp, async_req);
-		break;
 	case CRYPTO_ALG_TYPE_AHASH:
-		ret = _qcrypto_process_ahash(cp, async_req);
+		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:
-		ret = _qcrypto_process_aead(cp, async_req);
+	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;
+	pengine->active_seq++;
+	pengine->check_flag = true;
+
+	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);
+		break;
+	case CRYPTO_ALG_TYPE_AHASH:
+		ret = _qcrypto_process_ahash(pengine, async_req);
+		break;
+	case CRYPTO_ALG_TYPE_AEAD:
+		ret = _qcrypto_process_aead(pengine, async_req);
 		break;
 	default:
 		ret = -EINVAL;
 	};
-
+	pengine->total_req++;
 	if (ret) {
+		arsp->res = ret;
+		pengine->err_req++;
 		spin_lock_irqsave(&cp->lock, flags);
-		cp->req = NULL;
+		pengine->req = NULL;
+		pengine->arsp = NULL;
 		spin_unlock_irqrestore(&cp->lock, flags);
 
 		if (type == CRYPTO_ALG_TYPE_ABLKCIPHER)
@@ -1615,13 +1962,25 @@
 			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,
 				struct crypto_async_request *req)
 {
 	int ret;
@@ -1634,10 +1993,40 @@
 	}
 
 	spin_lock_irqsave(&cp->lock, flags);
-	ret = crypto_enqueue_request(&cp->queue, req);
-	spin_unlock_irqrestore(&cp->lock, flags);
-	_start_qcrypto_process(cp);
 
+	if (pengine) {
+		ret = crypto_enqueue_request(&pengine->req_queue, req);
+	} else {
+		ret = crypto_enqueue_request(&cp->req_queue, req);
+		pengine = _avail_eng(cp);
+	}
+	if (pengine) {
+		switch (pengine->bw_state) {
+		case BUS_NO_BANDWIDTH:
+			if (pengine->high_bw_req == false) {
+				qcrypto_ce_bw_allocate_req(pengine);
+				pengine->high_bw_req = true;
+			}
+			pengine = NULL;
+			break;
+		case BUS_HAS_BANDWIDTH:
+			break;
+		case BUS_BANDWIDTH_RELEASING:
+			pengine->high_bw_req = true;
+			pengine = NULL;
+			break;
+		case BUS_BANDWIDTH_ALLOCATING:
+			pengine = NULL;
+			break;
+		case BUS_SUSPENDED:
+		default:
+			pengine = NULL;
+			break;
+		}
+	}
+	spin_unlock_irqrestore(&cp->lock, flags);
+	if (pengine)
+		_start_qcrypto_process(cp, pengine);
 	return ret;
 }
 
@@ -1653,7 +2042,7 @@
 	BUG_ON(crypto_tfm_alg_type(req->base.tfm) !=
 					CRYPTO_ALG_TYPE_ABLKCIPHER);
 #ifdef QCRYPTO_DEBUG
-	dev_info(&cp->pdev->dev, "_qcrypto_enc_aes_ecb: %p\n", req);
+	dev_info(&ctx->pengine->pdev->dev, "_qcrypto_enc_aes_ecb: %p\n", req);
 #endif
 	rctx = ablkcipher_request_ctx(req);
 	rctx->aead = 0;
@@ -1662,7 +2051,7 @@
 	rctx->mode = QCE_MODE_ECB;
 
 	pstat->ablk_cipher_aes_enc++;
-	return _qcrypto_queue_req(cp, &req->base);
+	return _qcrypto_queue_req(cp, ctx->pengine, &req->base);
 };
 
 static int _qcrypto_enc_aes_cbc(struct ablkcipher_request *req)
@@ -1677,7 +2066,7 @@
 	BUG_ON(crypto_tfm_alg_type(req->base.tfm) !=
 					CRYPTO_ALG_TYPE_ABLKCIPHER);
 #ifdef QCRYPTO_DEBUG
-	dev_info(&cp->pdev->dev, "_qcrypto_enc_aes_cbc: %p\n", req);
+	dev_info(&ctx->pengine->pdev->dev, "_qcrypto_enc_aes_cbc: %p\n", req);
 #endif
 	rctx = ablkcipher_request_ctx(req);
 	rctx->aead = 0;
@@ -1686,7 +2075,7 @@
 	rctx->mode = QCE_MODE_CBC;
 
 	pstat->ablk_cipher_aes_enc++;
-	return _qcrypto_queue_req(cp, &req->base);
+	return _qcrypto_queue_req(cp, ctx->pengine, &req->base);
 };
 
 static int _qcrypto_enc_aes_ctr(struct ablkcipher_request *req)
@@ -1701,7 +2090,7 @@
 	BUG_ON(crypto_tfm_alg_type(req->base.tfm) !=
 				CRYPTO_ALG_TYPE_ABLKCIPHER);
 #ifdef QCRYPTO_DEBUG
-	dev_info(&cp->pdev->dev, "_qcrypto_enc_aes_ctr: %p\n", req);
+	dev_info(&ctx->pengine->pdev->dev, "_qcrypto_enc_aes_ctr: %p\n", req);
 #endif
 	rctx = ablkcipher_request_ctx(req);
 	rctx->aead = 0;
@@ -1710,7 +2099,7 @@
 	rctx->mode = QCE_MODE_CTR;
 
 	pstat->ablk_cipher_aes_enc++;
-	return _qcrypto_queue_req(cp, &req->base);
+	return _qcrypto_queue_req(cp, ctx->pengine, &req->base);
 };
 
 static int _qcrypto_enc_aes_xts(struct ablkcipher_request *req)
@@ -1731,7 +2120,7 @@
 	rctx->mode = QCE_MODE_XTS;
 
 	pstat->ablk_cipher_aes_enc++;
-	return _qcrypto_queue_req(cp, &req->base);
+	return _qcrypto_queue_req(cp, ctx->pengine, &req->base);
 };
 
 static int _qcrypto_aead_encrypt_aes_ccm(struct aead_request *req)
@@ -1757,7 +2146,30 @@
 	rctx->iv = req->iv;
 
 	pstat->aead_ccm_aes_enc++;
-	return _qcrypto_queue_req(cp, &req->base);
+	return _qcrypto_queue_req(cp, ctx->pengine, &req->base);
+}
+
+static int _qcrypto_aead_rfc4309_enc_aes_ccm(struct aead_request *req)
+{
+	struct qcrypto_cipher_req_ctx *rctx;
+	struct qcrypto_cipher_ctx *ctx = crypto_tfm_ctx(req->base.tfm);
+	struct crypto_priv *cp = ctx->cp;
+	struct crypto_stat *pstat;
+
+	pstat = &_qcrypto_stat;
+
+	rctx = aead_request_ctx(req);
+	rctx->aead = 1;
+	rctx->alg = CIPHER_ALG_AES;
+	rctx->dir = QCE_ENCRYPT;
+	rctx->mode = QCE_MODE_CCM;
+	memset(rctx->rfc4309_iv, 0, sizeof(rctx->rfc4309_iv));
+	rctx->rfc4309_iv[0] = 3; /* L -1 */
+	memcpy(&rctx->rfc4309_iv[1], ctx->ccm4309_nonce, 3);
+	memcpy(&rctx->rfc4309_iv[4], req->iv, 8);
+	rctx->iv = rctx->rfc4309_iv;
+	pstat->aead_rfc4309_ccm_aes_enc++;
+	return _qcrypto_queue_req(cp, ctx->pengine, &req->base);
 }
 
 static int _qcrypto_enc_des_ecb(struct ablkcipher_request *req)
@@ -1778,7 +2190,7 @@
 	rctx->mode = QCE_MODE_ECB;
 
 	pstat->ablk_cipher_des_enc++;
-	return _qcrypto_queue_req(cp, &req->base);
+	return _qcrypto_queue_req(cp, ctx->pengine, &req->base);
 };
 
 static int _qcrypto_enc_des_cbc(struct ablkcipher_request *req)
@@ -1799,7 +2211,7 @@
 	rctx->mode = QCE_MODE_CBC;
 
 	pstat->ablk_cipher_des_enc++;
-	return _qcrypto_queue_req(cp, &req->base);
+	return _qcrypto_queue_req(cp, ctx->pengine, &req->base);
 };
 
 static int _qcrypto_enc_3des_ecb(struct ablkcipher_request *req)
@@ -1820,7 +2232,7 @@
 	rctx->mode = QCE_MODE_ECB;
 
 	pstat->ablk_cipher_3des_enc++;
-	return _qcrypto_queue_req(cp, &req->base);
+	return _qcrypto_queue_req(cp, ctx->pengine, &req->base);
 };
 
 static int _qcrypto_enc_3des_cbc(struct ablkcipher_request *req)
@@ -1841,7 +2253,7 @@
 	rctx->mode = QCE_MODE_CBC;
 
 	pstat->ablk_cipher_3des_enc++;
-	return _qcrypto_queue_req(cp, &req->base);
+	return _qcrypto_queue_req(cp, ctx->pengine, &req->base);
 };
 
 static int _qcrypto_dec_aes_ecb(struct ablkcipher_request *req)
@@ -1856,7 +2268,7 @@
 	BUG_ON(crypto_tfm_alg_type(req->base.tfm) !=
 				CRYPTO_ALG_TYPE_ABLKCIPHER);
 #ifdef QCRYPTO_DEBUG
-	dev_info(&cp->pdev->dev, "_qcrypto_dec_aes_ecb: %p\n", req);
+	dev_info(&ctx->pengine->pdev->dev, "_qcrypto_dec_aes_ecb: %p\n", req);
 #endif
 	rctx = ablkcipher_request_ctx(req);
 	rctx->aead = 0;
@@ -1865,7 +2277,7 @@
 	rctx->mode = QCE_MODE_ECB;
 
 	pstat->ablk_cipher_aes_dec++;
-	return _qcrypto_queue_req(cp, &req->base);
+	return _qcrypto_queue_req(cp, ctx->pengine, &req->base);
 };
 
 static int _qcrypto_dec_aes_cbc(struct ablkcipher_request *req)
@@ -1880,7 +2292,7 @@
 	BUG_ON(crypto_tfm_alg_type(req->base.tfm) !=
 				CRYPTO_ALG_TYPE_ABLKCIPHER);
 #ifdef QCRYPTO_DEBUG
-	dev_info(&cp->pdev->dev, "_qcrypto_dec_aes_cbc: %p\n", req);
+	dev_info(&ctx->pengine->pdev->dev, "_qcrypto_dec_aes_cbc: %p\n", req);
 #endif
 
 	rctx = ablkcipher_request_ctx(req);
@@ -1890,7 +2302,7 @@
 	rctx->mode = QCE_MODE_CBC;
 
 	pstat->ablk_cipher_aes_dec++;
-	return _qcrypto_queue_req(cp, &req->base);
+	return _qcrypto_queue_req(cp, ctx->pengine, &req->base);
 };
 
 static int _qcrypto_dec_aes_ctr(struct ablkcipher_request *req)
@@ -1905,7 +2317,7 @@
 	BUG_ON(crypto_tfm_alg_type(req->base.tfm) !=
 					CRYPTO_ALG_TYPE_ABLKCIPHER);
 #ifdef QCRYPTO_DEBUG
-	dev_info(&cp->pdev->dev, "_qcrypto_dec_aes_ctr: %p\n", req);
+	dev_info(&ctx->pengine->pdev->dev, "_qcrypto_dec_aes_ctr: %p\n", req);
 #endif
 	rctx = ablkcipher_request_ctx(req);
 	rctx->aead = 0;
@@ -1916,7 +2328,7 @@
 	rctx->dir = QCE_ENCRYPT;
 
 	pstat->ablk_cipher_aes_dec++;
-	return _qcrypto_queue_req(cp, &req->base);
+	return _qcrypto_queue_req(cp, ctx->pengine, &req->base);
 };
 
 static int _qcrypto_dec_des_ecb(struct ablkcipher_request *req)
@@ -1937,7 +2349,7 @@
 	rctx->mode = QCE_MODE_ECB;
 
 	pstat->ablk_cipher_des_dec++;
-	return _qcrypto_queue_req(cp, &req->base);
+	return _qcrypto_queue_req(cp, ctx->pengine, &req->base);
 };
 
 static int _qcrypto_dec_des_cbc(struct ablkcipher_request *req)
@@ -1958,7 +2370,7 @@
 	rctx->mode = QCE_MODE_CBC;
 
 	pstat->ablk_cipher_des_dec++;
-	return _qcrypto_queue_req(cp, &req->base);
+	return _qcrypto_queue_req(cp, ctx->pengine, &req->base);
 };
 
 static int _qcrypto_dec_3des_ecb(struct ablkcipher_request *req)
@@ -1979,7 +2391,7 @@
 	rctx->mode = QCE_MODE_ECB;
 
 	pstat->ablk_cipher_3des_dec++;
-	return _qcrypto_queue_req(cp, &req->base);
+	return _qcrypto_queue_req(cp, ctx->pengine, &req->base);
 };
 
 static int _qcrypto_dec_3des_cbc(struct ablkcipher_request *req)
@@ -2000,7 +2412,7 @@
 	rctx->mode = QCE_MODE_CBC;
 
 	pstat->ablk_cipher_3des_dec++;
-	return _qcrypto_queue_req(cp, &req->base);
+	return _qcrypto_queue_req(cp, ctx->pengine, &req->base);
 };
 
 static int _qcrypto_dec_aes_xts(struct ablkcipher_request *req)
@@ -2021,7 +2433,7 @@
 	rctx->dir = QCE_DECRYPT;
 
 	pstat->ablk_cipher_aes_dec++;
-	return _qcrypto_queue_req(cp, &req->base);
+	return _qcrypto_queue_req(cp, ctx->pengine, &req->base);
 };
 
 
@@ -2048,9 +2460,30 @@
 	rctx->iv = req->iv;
 
 	pstat->aead_ccm_aes_dec++;
-	return _qcrypto_queue_req(cp, &req->base);
+	return _qcrypto_queue_req(cp, ctx->pengine, &req->base);
 }
 
+static int _qcrypto_aead_rfc4309_dec_aes_ccm(struct aead_request *req)
+{
+	struct qcrypto_cipher_req_ctx *rctx;
+	struct qcrypto_cipher_ctx *ctx = crypto_tfm_ctx(req->base.tfm);
+	struct crypto_priv *cp = ctx->cp;
+	struct crypto_stat *pstat;
+
+	pstat = &_qcrypto_stat;
+	rctx = aead_request_ctx(req);
+	rctx->aead = 1;
+	rctx->alg = CIPHER_ALG_AES;
+	rctx->dir = QCE_DECRYPT;
+	rctx->mode = QCE_MODE_CCM;
+	memset(rctx->rfc4309_iv, 0, sizeof(rctx->rfc4309_iv));
+	rctx->rfc4309_iv[0] = 3; /* L -1 */
+	memcpy(&rctx->rfc4309_iv[1], ctx->ccm4309_nonce, 3);
+	memcpy(&rctx->rfc4309_iv[4], req->iv, 8);
+	rctx->iv = rctx->rfc4309_iv;
+	pstat->aead_rfc4309_ccm_aes_dec++;
+	return _qcrypto_queue_req(cp, ctx->pengine, &req->base);
+}
 static int _qcrypto_aead_setauthsize(struct crypto_aead *authenc,
 				unsigned int authsize)
 {
@@ -2081,6 +2514,24 @@
 	return 0;
 }
 
+static int _qcrypto_aead_rfc4309_ccm_setauthsize(struct crypto_aead *authenc,
+				  unsigned int authsize)
+{
+	struct qcrypto_cipher_ctx *ctx = crypto_aead_ctx(authenc);
+
+	switch (authsize) {
+	case 8:
+	case 12:
+	case 16:
+		break;
+	default:
+		return -EINVAL;
+	}
+	ctx->authsize = authsize;
+	return 0;
+}
+
+
 static int _qcrypto_aead_setkey(struct crypto_aead *tfm, const u8 *key,
 			unsigned int keylen)
 {
@@ -2146,6 +2597,21 @@
 	return 0;
 }
 
+static int _qcrypto_aead_rfc4309_ccm_setkey(struct crypto_aead *aead,
+				 const u8 *key, unsigned int key_len)
+{
+	struct crypto_tfm *tfm = crypto_aead_tfm(aead);
+	struct qcrypto_cipher_ctx *ctx = crypto_tfm_ctx(tfm);
+	int ret;
+
+	if (key_len < QCRYPTO_CCM4309_NONCE_LEN)
+		return -EINVAL;
+	key_len -= QCRYPTO_CCM4309_NONCE_LEN;
+	memcpy(ctx->ccm4309_nonce, key + key_len,  QCRYPTO_CCM4309_NONCE_LEN);
+	ret = _qcrypto_aead_ccm_setkey(aead, key, key_len);
+	return ret;
+};
+
 static int _qcrypto_aead_encrypt_aes_cbc(struct aead_request *req)
 {
 	struct qcrypto_cipher_req_ctx *rctx;
@@ -2156,7 +2622,8 @@
 	pstat = &_qcrypto_stat;
 
 #ifdef QCRYPTO_DEBUG
-	dev_info(&cp->pdev->dev, "_qcrypto_aead_encrypt_aes_cbc: %p\n", req);
+	dev_info(&ctx->pengine->pdev->dev,
+			 "_qcrypto_aead_encrypt_aes_cbc: %p\n", req);
 #endif
 
 	rctx = aead_request_ctx(req);
@@ -2167,7 +2634,7 @@
 	rctx->iv = req->iv;
 
 	pstat->aead_sha1_aes_enc++;
-	return _qcrypto_queue_req(cp, &req->base);
+	return _qcrypto_queue_req(cp, ctx->pengine, &req->base);
 }
 
 static int _qcrypto_aead_decrypt_aes_cbc(struct aead_request *req)
@@ -2180,7 +2647,8 @@
 	pstat = &_qcrypto_stat;
 
 #ifdef QCRYPTO_DEBUG
-	dev_info(&cp->pdev->dev, "_qcrypto_aead_decrypt_aes_cbc: %p\n", req);
+	dev_info(&ctx->pengine->pdev->dev,
+			 "_qcrypto_aead_decrypt_aes_cbc: %p\n", req);
 #endif
 	rctx = aead_request_ctx(req);
 	rctx->aead = 1;
@@ -2190,7 +2658,7 @@
 	rctx->iv = req->iv;
 
 	pstat->aead_sha1_aes_dec++;
-	return _qcrypto_queue_req(cp, &req->base);
+	return _qcrypto_queue_req(cp, ctx->pengine, &req->base);
 }
 
 static int _qcrypto_aead_givencrypt_aes_cbc(struct aead_givcrypt_request *req)
@@ -2215,7 +2683,7 @@
 	 /* avoid consecutive packets going out with same IV */
 	*(__be64 *)req->giv ^= cpu_to_be64(req->seq);
 	pstat->aead_sha1_aes_enc++;
-	return _qcrypto_queue_req(cp, &areq->base);
+	return _qcrypto_queue_req(cp, ctx->pengine, &areq->base);
 }
 
 #ifdef QCRYPTO_AEAD_AES_CTR
@@ -2236,7 +2704,7 @@
 	rctx->iv = req->iv;
 
 	pstat->aead_sha1_aes_enc++;
-	return _qcrypto_queue_req(cp, &req->base);
+	return _qcrypto_queue_req(cp, ctx->pengine, &req->base);
 }
 
 static int _qcrypto_aead_decrypt_aes_ctr(struct aead_request *req)
@@ -2259,7 +2727,7 @@
 	rctx->iv = req->iv;
 
 	pstat->aead_sha1_aes_dec++;
-	return _qcrypto_queue_req(cp, &req->base);
+	return _qcrypto_queue_req(cp, ctx->pengine, &req->base);
 }
 
 static int _qcrypto_aead_givencrypt_aes_ctr(struct aead_givcrypt_request *req)
@@ -2284,7 +2752,7 @@
 	 /* avoid consecutive packets going out with same IV */
 	*(__be64 *)req->giv ^= cpu_to_be64(req->seq);
 	pstat->aead_sha1_aes_enc++;
-	return _qcrypto_queue_req(cp, &areq->base);
+	return _qcrypto_queue_req(cp, ctx->pengine, &areq->base);
 };
 #endif /* QCRYPTO_AEAD_AES_CTR */
 
@@ -2305,7 +2773,7 @@
 	rctx->iv = req->iv;
 
 	pstat->aead_sha1_des_enc++;
-	return _qcrypto_queue_req(cp, &req->base);
+	return _qcrypto_queue_req(cp, ctx->pengine, &req->base);
 }
 
 static int _qcrypto_aead_decrypt_des_cbc(struct aead_request *req)
@@ -2325,7 +2793,7 @@
 	rctx->iv = req->iv;
 
 	pstat->aead_sha1_des_dec++;
-	return _qcrypto_queue_req(cp, &req->base);
+	return _qcrypto_queue_req(cp, ctx->pengine, &req->base);
 }
 
 static int _qcrypto_aead_givencrypt_des_cbc(struct aead_givcrypt_request *req)
@@ -2350,7 +2818,7 @@
 	 /* avoid consecutive packets going out with same IV */
 	*(__be64 *)req->giv ^= cpu_to_be64(req->seq);
 	pstat->aead_sha1_des_enc++;
-	return _qcrypto_queue_req(cp, &areq->base);
+	return _qcrypto_queue_req(cp, ctx->pengine, &areq->base);
 }
 
 static int _qcrypto_aead_encrypt_3des_cbc(struct aead_request *req)
@@ -2370,7 +2838,7 @@
 	rctx->iv = req->iv;
 
 	pstat->aead_sha1_3des_enc++;
-	return _qcrypto_queue_req(cp, &req->base);
+	return _qcrypto_queue_req(cp, ctx->pengine, &req->base);
 }
 
 static int _qcrypto_aead_decrypt_3des_cbc(struct aead_request *req)
@@ -2390,7 +2858,7 @@
 	rctx->iv = req->iv;
 
 	pstat->aead_sha1_3des_dec++;
-	return _qcrypto_queue_req(cp, &req->base);
+	return _qcrypto_queue_req(cp, ctx->pengine, &req->base);
 }
 
 static int _qcrypto_aead_givencrypt_3des_cbc(struct aead_givcrypt_request *req)
@@ -2415,18 +2883,21 @@
 	 /* avoid consecutive packets going out with same IV */
 	*(__be64 *)req->giv ^= cpu_to_be64(req->seq);
 	pstat->aead_sha1_3des_enc++;
-	return _qcrypto_queue_req(cp, &areq->base);
+	return _qcrypto_queue_req(cp, ctx->pengine, &areq->base);
 }
 
-static int _sha_init(struct qcrypto_sha_ctx *ctx)
+static int _sha_init(struct ahash_request *req)
 {
-	ctx->first_blk = 1;
-	ctx->last_blk = 0;
-	ctx->byte_count[0] = 0;
-	ctx->byte_count[1] = 0;
-	ctx->byte_count[2] = 0;
-	ctx->byte_count[3] = 0;
-	ctx->trailing_buf_len = 0;
+	struct qcrypto_sha_req_ctx *rctx = ahash_request_ctx(req);
+
+	rctx->first_blk = 1;
+	rctx->last_blk = 0;
+	rctx->byte_count[0] = 0;
+	rctx->byte_count[1] = 0;
+	rctx->byte_count[2] = 0;
+	rctx->byte_count[3] = 0;
+	rctx->trailing_buf_len = 0;
+	rctx->count = 0;
 
 	return 0;
 };
@@ -2435,18 +2906,17 @@
 {
 	struct qcrypto_sha_ctx *sha_ctx = crypto_tfm_ctx(req->base.tfm);
 	struct crypto_stat *pstat;
+	struct qcrypto_sha_req_ctx *rctx = ahash_request_ctx(req);
 
 	pstat = &_qcrypto_stat;
 
-	_sha_init(sha_ctx);
+	_sha_init(req);
 	sha_ctx->alg = QCE_HASH_SHA1;
 
-	memset(&sha_ctx->trailing_buf[0], 0x00, SHA1_BLOCK_SIZE);
-	memcpy(&sha_ctx->digest[0], &_std_init_vector_sha1_uint8[0],
+	memset(&rctx->trailing_buf[0], 0x00, SHA1_BLOCK_SIZE);
+	memcpy(&rctx->digest[0], &_std_init_vector_sha1_uint8[0],
 						SHA1_DIGEST_SIZE);
 	sha_ctx->diglen = SHA1_DIGEST_SIZE;
-	_update_sha1_ctx(req);
-
 	pstat->sha1_digest++;
 	return 0;
 };
@@ -2455,18 +2925,17 @@
 {
 	struct qcrypto_sha_ctx *sha_ctx = crypto_tfm_ctx(req->base.tfm);
 	struct crypto_stat *pstat;
+	struct qcrypto_sha_req_ctx *rctx = ahash_request_ctx(req);
 
 	pstat = &_qcrypto_stat;
 
-	_sha_init(sha_ctx);
+	_sha_init(req);
 	sha_ctx->alg = QCE_HASH_SHA256;
 
-	memset(&sha_ctx->trailing_buf[0], 0x00, SHA256_BLOCK_SIZE);
-	memcpy(&sha_ctx->digest[0], &_std_init_vector_sha256_uint8[0],
+	memset(&rctx->trailing_buf[0], 0x00, SHA256_BLOCK_SIZE);
+	memcpy(&rctx->digest[0], &_std_init_vector_sha256_uint8[0],
 						SHA256_DIGEST_SIZE);
 	sha_ctx->diglen = SHA256_DIGEST_SIZE;
-	_update_sha256_ctx(req);
-
 	pstat->sha256_digest++;
 	return 0;
 };
@@ -2475,82 +2944,126 @@
 static int _sha1_export(struct ahash_request  *req, void *out)
 {
 	struct qcrypto_sha_req_ctx *rctx = ahash_request_ctx(req);
-	struct sha1_state *sha_state_ctx = &rctx->sha1_state_ctx;
 	struct sha1_state *out_ctx = (struct sha1_state *)out;
 
-	out_ctx->count = sha_state_ctx->count;
-	memcpy(out_ctx->state, sha_state_ctx->state, sizeof(out_ctx->state));
-	memcpy(out_ctx->buffer, sha_state_ctx->buffer, SHA1_BLOCK_SIZE);
+	out_ctx->count = rctx->count;
+	_byte_stream_to_words(out_ctx->state, rctx->digest, SHA1_DIGEST_SIZE);
+	memcpy(out_ctx->buffer, rctx->trailing_buf, SHA1_BLOCK_SIZE);
 
 	return 0;
 };
 
+static int _sha1_hmac_export(struct ahash_request  *req, void *out)
+{
+	return _sha1_export(req, out);
+}
+
+/* crypto hw padding constant for hmac first operation */
+#define HMAC_PADDING 64
+
+static int __sha1_import_common(struct ahash_request  *req, const void *in,
+				bool hmac)
+{
+	struct qcrypto_sha_ctx *sha_ctx = crypto_tfm_ctx(req->base.tfm);
+	struct qcrypto_sha_req_ctx *rctx = ahash_request_ctx(req);
+	struct sha1_state *in_ctx = (struct sha1_state *)in;
+	u64 hw_count = in_ctx->count;
+
+	rctx->count = in_ctx->count;
+	memcpy(rctx->trailing_buf, in_ctx->buffer, SHA1_BLOCK_SIZE);
+	if (in_ctx->count <= SHA1_BLOCK_SIZE) {
+		rctx->first_blk = 1;
+	} else {
+		rctx->first_blk = 0;
+		/*
+		 * For hmac, there is a hardware padding done
+		 * when first is set. So the byte_count will be
+		 * incremened by 64 after the operstion of first
+		 */
+		if (hmac)
+			hw_count += HMAC_PADDING;
+	}
+	rctx->byte_count[0] =  (uint32_t)(hw_count & 0xFFFFFFC0);
+	rctx->byte_count[1] =  (uint32_t)(hw_count >> 32);
+	_words_to_byte_stream(in_ctx->state, rctx->digest, sha_ctx->diglen);
+
+	rctx->trailing_buf_len = (uint32_t)(in_ctx->count &
+						(SHA1_BLOCK_SIZE-1));
+	return 0;
+}
+
 static int _sha1_import(struct ahash_request  *req, const void *in)
 {
-	struct qcrypto_sha_ctx *sha_ctx = crypto_tfm_ctx(req->base.tfm);
-	struct qcrypto_sha_req_ctx *rctx = ahash_request_ctx(req);
-	struct sha1_state *sha_state_ctx = &rctx->sha1_state_ctx;
-	struct sha1_state *in_ctx = (struct sha1_state *)in;
-
-	sha_state_ctx->count = in_ctx->count;
-	memcpy(sha_state_ctx->state, in_ctx->state, sizeof(in_ctx->state));
-	memcpy(sha_state_ctx->buffer, in_ctx->buffer, SHA1_BLOCK_SIZE);
-	memcpy(sha_ctx->trailing_buf, in_ctx->buffer, SHA1_BLOCK_SIZE);
-
-	sha_ctx->byte_count[0] =  (uint32_t)(in_ctx->count & 0xFFFFFFC0);
-	sha_ctx->byte_count[1] =  (uint32_t)(in_ctx->count >> 32);
-	_words_to_byte_stream(in_ctx->state, sha_ctx->digest, sha_ctx->diglen);
-
-	sha_ctx->trailing_buf_len = (uint32_t)(in_ctx->count &
-						(SHA1_BLOCK_SIZE-1));
-
-	if (!(in_ctx->count))
-		sha_ctx->first_blk = 1;
-	else
-		sha_ctx->first_blk = 0;
-
-	return 0;
+	return __sha1_import_common(req, in, false);
 }
+
+static int _sha1_hmac_import(struct ahash_request  *req, const void *in)
+{
+	return __sha1_import_common(req, in, true);
+}
+
 static int _sha256_export(struct ahash_request  *req, void *out)
 {
 	struct qcrypto_sha_req_ctx *rctx = ahash_request_ctx(req);
-	struct sha256_state *sha_state_ctx = &rctx->sha256_state_ctx;
 	struct sha256_state *out_ctx = (struct sha256_state *)out;
 
-	out_ctx->count = sha_state_ctx->count;
-	memcpy(out_ctx->state, sha_state_ctx->state, sizeof(out_ctx->state));
-	memcpy(out_ctx->buf, sha_state_ctx->buf, SHA256_BLOCK_SIZE);
+	out_ctx->count = rctx->count;
+	_byte_stream_to_words(out_ctx->state, rctx->digest, SHA256_DIGEST_SIZE);
+	memcpy(out_ctx->buf, rctx->trailing_buf, SHA256_BLOCK_SIZE);
 
 	return 0;
 };
 
-static int _sha256_import(struct ahash_request  *req, const void *in)
+static int _sha256_hmac_export(struct ahash_request  *req, void *out)
+{
+	return _sha256_export(req, out);
+}
+
+static int __sha256_import_common(struct ahash_request  *req, const void *in,
+			bool hmac)
 {
 	struct qcrypto_sha_ctx *sha_ctx = crypto_tfm_ctx(req->base.tfm);
 	struct qcrypto_sha_req_ctx *rctx = ahash_request_ctx(req);
-	struct sha256_state *sha_state_ctx = &rctx->sha256_state_ctx;
 	struct sha256_state *in_ctx = (struct sha256_state *)in;
+	u64 hw_count = in_ctx->count;
 
-	sha_state_ctx->count = in_ctx->count;
-	memcpy(sha_state_ctx->state, in_ctx->state, sizeof(in_ctx->state));
-	memcpy(sha_state_ctx->buf, in_ctx->buf, SHA256_BLOCK_SIZE);
-	memcpy(sha_ctx->trailing_buf, in_ctx->buf, SHA256_BLOCK_SIZE);
+	rctx->count = in_ctx->count;
+	memcpy(rctx->trailing_buf, in_ctx->buf, SHA256_BLOCK_SIZE);
 
-	sha_ctx->byte_count[0] =  (uint32_t)(in_ctx->count & 0xFFFFFFC0);
-	sha_ctx->byte_count[1] =  (uint32_t)(in_ctx->count >> 32);
-	_words_to_byte_stream(in_ctx->state, sha_ctx->digest, sha_ctx->diglen);
+	if (in_ctx->count <= SHA256_BLOCK_SIZE) {
+		rctx->first_blk = 1;
+	} else {
+		rctx->first_blk = 0;
+		/*
+		 * for hmac, there is a hardware padding done
+		 * when first is set. So the byte_count will be
+		 * incremened by 64 after the operstion of first
+		 */
+		if (hmac)
+			hw_count += HMAC_PADDING;
+	}
 
-	sha_ctx->trailing_buf_len = (uint32_t)(in_ctx->count &
+	rctx->byte_count[0] =  (uint32_t)(hw_count & 0xFFFFFFC0);
+	rctx->byte_count[1] =  (uint32_t)(hw_count >> 32);
+	_words_to_byte_stream(in_ctx->state, rctx->digest, sha_ctx->diglen);
+
+	rctx->trailing_buf_len = (uint32_t)(in_ctx->count &
 						(SHA256_BLOCK_SIZE-1));
 
-	if (!(in_ctx->count))
-		sha_ctx->first_blk = 1;
-	else
-		sha_ctx->first_blk = 0;
 
 	return 0;
 }
 
+static int _sha256_import(struct ahash_request  *req, const void *in)
+{
+	return __sha256_import_common(req, in, false);
+}
+
+static int _sha256_hmac_import(struct ahash_request  *req, const void *in)
+{
+	return __sha256_import_common(req, in, true);
+}
+
 static int _copy_source(struct ahash_request  *req)
 {
 	struct qcrypto_sha_req_ctx *srctx = NULL;
@@ -2593,23 +3106,19 @@
 	uint32_t nbytes;
 	uint32_t offset = 0;
 	uint32_t bytes = 0;
-
+	uint8_t  *staging;
 	int ret = 0;
 
 	/* check for trailing buffer from previous updates and append it */
-	total = req->nbytes + sha_ctx->trailing_buf_len;
+	total = req->nbytes + rctx->trailing_buf_len;
 	len = req->nbytes;
 
 	if (total <= sha_block_size) {
-		k_src = &sha_ctx->trailing_buf[sha_ctx->trailing_buf_len];
+		k_src = &rctx->trailing_buf[rctx->trailing_buf_len];
 		num_sg = qcrypto_count_sg(req->src, len);
 		bytes = qcrypto_sg_copy_to_buffer(req->src, num_sg, k_src, len);
 
-		sha_ctx->trailing_buf_len = total;
-		if (sha_ctx->alg == QCE_HASH_SHA1)
-			_update_sha1_ctx(req);
-		if (sha_ctx->alg == QCE_HASH_SHA256)
-			_update_sha256_ctx(req);
+		rctx->trailing_buf_len = total;
 		return 0;
 	}
 
@@ -2617,9 +3126,10 @@
 	rctx->src = req->src;
 	rctx->nbytes = req->nbytes;
 
-	memcpy(sha_ctx->tmp_tbuf, sha_ctx->trailing_buf,
-					sha_ctx->trailing_buf_len);
-	k_src = &sha_ctx->trailing_buf[0];
+	staging = (uint8_t *) ALIGN(((unsigned int)rctx->staging_dmabuf),
+							L1_CACHE_BYTES);
+	memcpy(staging, rctx->trailing_buf, rctx->trailing_buf_len);
+	k_src = &rctx->trailing_buf[0];
 	/*  get new trailing buffer */
 	sha_pad_len = ALIGN(total, sha_block_size) - total;
 	trailing_buf_len =  sha_block_size - sha_pad_len;
@@ -2632,7 +3142,7 @@
 	nbytes = total - trailing_buf_len;
 	num_sg = qcrypto_count_sg(req->src, req->nbytes);
 
-	len = sha_ctx->trailing_buf_len;
+	len = rctx->trailing_buf_len;
 	sg_last = req->src;
 
 	while (len < nbytes) {
@@ -2641,56 +3151,41 @@
 		len += sg_last->length;
 		sg_last = scatterwalk_sg_next(sg_last);
 	}
-	if (sha_ctx->trailing_buf_len) {
+	if (rctx->trailing_buf_len) {
 		if (cp->ce_support.aligned_only)  {
-			sha_ctx->sg = kzalloc(sizeof(struct scatterlist),
-								GFP_ATOMIC);
-			if (sha_ctx->sg == NULL) {
-				pr_err("MemAlloc fail sha_ctx->sg, error %ld\n",
-						PTR_ERR(sha_ctx->sg));
-				return -ENOMEM;
-			}
 			rctx->data2 = kzalloc((req->nbytes + 64), GFP_ATOMIC);
 			if (rctx->data2 == NULL) {
 				pr_err("Mem Alloc fail srctx->data2, err %ld\n",
 							PTR_ERR(rctx->data2));
-				kfree(sha_ctx->sg);
 				return -ENOMEM;
 			}
-			memcpy(rctx->data2, sha_ctx->tmp_tbuf,
-						sha_ctx->trailing_buf_len);
-			memcpy((rctx->data2 + sha_ctx->trailing_buf_len),
+			memcpy(rctx->data2, staging,
+						rctx->trailing_buf_len);
+			memcpy((rctx->data2 + rctx->trailing_buf_len),
 					rctx->data, req->src->length);
 			kfree(rctx->data);
 			rctx->data = rctx->data2;
-			sg_set_buf(&sha_ctx->sg[0], rctx->data,
-					(sha_ctx->trailing_buf_len +
+			sg_set_buf(&rctx->sg[0], rctx->data,
+					(rctx->trailing_buf_len +
 							req->src->length));
-			req->src = sha_ctx->sg;
-			sg_mark_end(&sha_ctx->sg[0]);
+			req->src = rctx->sg;
+			sg_mark_end(&rctx->sg[0]);
 		} else {
 			sg_mark_end(sg_last);
-			sha_ctx->sg = kzalloc(2 * (sizeof(struct scatterlist)),
-								GFP_ATOMIC);
-			if (sha_ctx->sg == NULL) {
-				pr_err("MEMalloc fail sha_ctx->sg, error %ld\n",
-							PTR_ERR(sha_ctx->sg));
-				return -ENOMEM;
-			}
-
-			sg_set_buf(&sha_ctx->sg[0], sha_ctx->tmp_tbuf,
-						sha_ctx->trailing_buf_len);
-			sg_mark_end(&sha_ctx->sg[1]);
-			sg_chain(sha_ctx->sg, 2, req->src);
-			req->src = sha_ctx->sg;
+			memset(rctx->sg, 0, sizeof(rctx->sg));
+			sg_set_buf(&rctx->sg[0], staging,
+						rctx->trailing_buf_len);
+			sg_mark_end(&rctx->sg[1]);
+			sg_chain(rctx->sg, 2, req->src);
+			req->src = rctx->sg;
 		}
 	} else
 		sg_mark_end(sg_last);
 
 	req->nbytes = nbytes;
-	sha_ctx->trailing_buf_len = trailing_buf_len;
+	rctx->trailing_buf_len = trailing_buf_len;
 
-	ret =  _qcrypto_queue_req(cp, &req->base);
+	ret =  _qcrypto_queue_req(cp, sha_ctx->pengine, &req->base);
 
 	return ret;
 };
@@ -2698,7 +3193,6 @@
 static int _sha1_update(struct ahash_request  *req)
 {
 	struct qcrypto_sha_req_ctx *rctx = ahash_request_ctx(req);
-	struct sha1_state *sha_state_ctx = &rctx->sha1_state_ctx;
 	struct qcrypto_sha_ctx *sha_ctx = crypto_tfm_ctx(req->base.tfm);
 	struct crypto_priv *cp = sha_ctx->cp;
 
@@ -2706,14 +3200,13 @@
 		if (_copy_source(req))
 			return -ENOMEM;
 	}
-	sha_state_ctx->count += req->nbytes;
+	rctx->count += req->nbytes;
 	return _sha_update(req, SHA1_BLOCK_SIZE);
 }
 
 static int _sha256_update(struct ahash_request  *req)
 {
 	struct qcrypto_sha_req_ctx *rctx = ahash_request_ctx(req);
-	struct sha256_state *sha_state_ctx = &rctx->sha256_state_ctx;
 	struct qcrypto_sha_ctx *sha_ctx = crypto_tfm_ctx(req->base.tfm);
 	struct crypto_priv *cp = sha_ctx->cp;
 
@@ -2722,7 +3215,7 @@
 			return -ENOMEM;
 	}
 
-	sha_state_ctx->count += req->nbytes;
+	rctx->count += req->nbytes;
 	return _sha_update(req, SHA256_BLOCK_SIZE);
 }
 
@@ -2732,26 +3225,29 @@
 	struct crypto_priv *cp = sha_ctx->cp;
 	struct qcrypto_sha_req_ctx *rctx = ahash_request_ctx(req);
 	int ret = 0;
+	uint8_t  *staging;
 
 	if (cp->ce_support.aligned_only) {
 		if (_copy_source(req))
 			return -ENOMEM;
 	}
 
-	sha_ctx->last_blk = 1;
+	rctx->last_blk = 1;
 
 	/* save the original req structure fields*/
 	rctx->src = req->src;
 	rctx->nbytes = req->nbytes;
 
-	sg_set_buf(&sha_ctx->tmp_sg, sha_ctx->trailing_buf,
-					sha_ctx->trailing_buf_len);
-	sg_mark_end(&sha_ctx->tmp_sg);
+	staging = (uint8_t *) ALIGN(((unsigned int)rctx->staging_dmabuf),
+							L1_CACHE_BYTES);
+	memcpy(staging, rctx->trailing_buf, rctx->trailing_buf_len);
+	sg_set_buf(&rctx->sg[0], staging, rctx->trailing_buf_len);
+	sg_mark_end(&rctx->sg[0]);
 
-	req->src = &sha_ctx->tmp_sg;
-	req->nbytes = sha_ctx->trailing_buf_len;
+	req->src = &rctx->sg[0];
+	req->nbytes = rctx->trailing_buf_len;
 
-	ret =  _qcrypto_queue_req(cp, &req->base);
+	ret =  _qcrypto_queue_req(cp, sha_ctx->pengine, &req->base);
 
 	return ret;
 };
@@ -2781,9 +3277,9 @@
 	/* save the original req structure fields*/
 	rctx->src = req->src;
 	rctx->nbytes = req->nbytes;
-	sha_ctx->first_blk = 1;
-	sha_ctx->last_blk = 1;
-	ret =  _qcrypto_queue_req(cp, &req->base);
+	rctx->first_blk = 1;
+	rctx->last_blk = 1;
+	ret =  _qcrypto_queue_req(cp, sha_ctx->pengine, &req->base);
 
 	return ret;
 }
@@ -2814,32 +3310,49 @@
 		unsigned int len)
 {
 	struct qcrypto_sha_ctx *sha_ctx = crypto_tfm_ctx(&tfm->base);
+	uint8_t	*in_buf;
 	int ret = 0;
+	struct scatterlist sg;
+	struct ahash_request *ahash_req;
+	struct completion ahash_req_complete;
 
-	sha_ctx->in_buf = kzalloc(len + 64, GFP_KERNEL);
-	if (sha_ctx->in_buf == NULL) {
-		pr_err("qcrypto Can't Allocate mem: sha_ctx->in_buf, error %ld\n",
-		PTR_ERR(sha_ctx->in_buf));
+	ahash_req = ahash_request_alloc(tfm, GFP_KERNEL);
+	if (ahash_req == NULL)
+		return -ENOMEM;
+	init_completion(&ahash_req_complete);
+	ahash_request_set_callback(ahash_req,
+				CRYPTO_TFM_REQ_MAY_BACKLOG,
+				_crypto_sha_hmac_ahash_req_complete,
+				&ahash_req_complete);
+	crypto_ahash_clear_flags(tfm, ~0);
+
+	in_buf = kzalloc(len + 64, GFP_KERNEL);
+	if (in_buf == NULL) {
+		pr_err("qcrypto Can't Allocate mem: in_buf, error %ld\n",
+			PTR_ERR(in_buf));
+		ahash_request_free(ahash_req);
 		return -ENOMEM;
 	}
-	memcpy(sha_ctx->in_buf, key, len);
-	sg_set_buf(&sha_ctx->tmp_sg, sha_ctx->in_buf, len);
-	sg_mark_end(&sha_ctx->tmp_sg);
+	memcpy(in_buf, key, len);
+	sg_set_buf(&sg, in_buf, len);
+	sg_mark_end(&sg);
 
-	ahash_request_set_crypt(sha_ctx->ahash_req, &sha_ctx->tmp_sg,
+	ahash_request_set_crypt(ahash_req, &sg,
 				&sha_ctx->authkey[0], len);
 
-	ret = _sha_digest(sha_ctx->ahash_req);
+	if (sha_ctx->alg == QCE_HASH_SHA1)
+		ret = _sha1_digest(ahash_req);
+	else
+		ret = _sha256_digest(ahash_req);
 	if (ret == -EINPROGRESS || ret == -EBUSY) {
 		ret =
 			wait_for_completion_interruptible(
-						&sha_ctx->ahash_req_complete);
+						&ahash_req_complete);
 		INIT_COMPLETION(sha_ctx->ahash_req_complete);
 	}
 
-	sha_ctx->authkey_in_len = len;
-	kfree(sha_ctx->in_buf);
-	sha_ctx->in_buf = NULL;
+	kfree(in_buf);
+	ahash_request_free(ahash_req);
 
 	return ret;
 }
@@ -2848,16 +3361,15 @@
 							unsigned int len)
 {
 	struct qcrypto_sha_ctx *sha_ctx = crypto_tfm_ctx(&tfm->base);
-
-	if (len <= SHA1_BLOCK_SIZE)
+	memset(&sha_ctx->authkey[0], 0, SHA1_BLOCK_SIZE);
+	if (len <= SHA1_BLOCK_SIZE) {
 		memcpy(&sha_ctx->authkey[0], key, len);
-	else {
-		_sha_init(sha_ctx);
+		sha_ctx->authkey_in_len = len;
+	} else {
 		sha_ctx->alg = QCE_HASH_SHA1;
-		memcpy(&sha_ctx->digest[0], &_std_init_vector_sha1_uint8[0],
-						SHA1_DIGEST_SIZE);
 		sha_ctx->diglen = SHA1_DIGEST_SIZE;
 		_sha_hmac_setkey(tfm, key, len);
+		sha_ctx->authkey_in_len = SHA1_BLOCK_SIZE;
 	}
 	return 0;
 }
@@ -2867,15 +3379,15 @@
 {
 	struct qcrypto_sha_ctx *sha_ctx = crypto_tfm_ctx(&tfm->base);
 
-	if (len <= SHA256_BLOCK_SIZE)
+	memset(&sha_ctx->authkey[0], 0, SHA256_BLOCK_SIZE);
+	if (len <= SHA256_BLOCK_SIZE) {
 		memcpy(&sha_ctx->authkey[0], key, len);
-	else {
-		_sha_init(sha_ctx);
+		sha_ctx->authkey_in_len = len;
+	} else {
 		sha_ctx->alg = QCE_HASH_SHA256;
-		memcpy(&sha_ctx->digest[0], &_std_init_vector_sha256_uint8[0],
-						SHA256_DIGEST_SIZE);
 		sha_ctx->diglen = SHA256_DIGEST_SIZE;
 		_sha_hmac_setkey(tfm, key, len);
+		sha_ctx->authkey_in_len = SHA256_BLOCK_SIZE;
 	}
 
 	return 0;
@@ -2885,11 +3397,12 @@
 						uint32_t sha_block_size)
 {
 	struct qcrypto_sha_ctx *sha_ctx = crypto_tfm_ctx(req->base.tfm);
+	struct qcrypto_sha_req_ctx *rctx = ahash_request_ctx(req);
 	int i;
 
 	for (i = 0; i < sha_block_size; i++)
-		sha_ctx->trailing_buf[i] = sha_ctx->authkey[i] ^ 0x36;
-	sha_ctx->trailing_buf_len = sha_block_size;
+		rctx->trailing_buf[i] = sha_ctx->authkey[i] ^ 0x36;
+	rctx->trailing_buf_len = sha_block_size;
 
 	return 0;
 }
@@ -2900,16 +3413,16 @@
 	struct crypto_priv *cp = sha_ctx->cp;
 	struct crypto_stat *pstat;
 	int ret = 0;
+	struct qcrypto_sha_req_ctx *rctx = ahash_request_ctx(req);
 
 	pstat = &_qcrypto_stat;
 	pstat->sha1_hmac_digest++;
 
-	_sha_init(sha_ctx);
-	memset(&sha_ctx->trailing_buf[0], 0x00, SHA1_BLOCK_SIZE);
-	memcpy(&sha_ctx->digest[0], &_std_init_vector_sha1_uint8[0],
+	_sha_init(req);
+	memset(&rctx->trailing_buf[0], 0x00, SHA1_BLOCK_SIZE);
+	memcpy(&rctx->digest[0], &_std_init_vector_sha1_uint8[0],
 						SHA1_DIGEST_SIZE);
 	sha_ctx->diglen = SHA1_DIGEST_SIZE;
-	_update_sha1_ctx(req);
 
 	if (cp->ce_support.sha_hmac)
 			sha_ctx->alg = QCE_HASH_SHA1_HMAC;
@@ -2927,16 +3440,17 @@
 	struct crypto_priv *cp = sha_ctx->cp;
 	struct crypto_stat *pstat;
 	int ret = 0;
+	struct qcrypto_sha_req_ctx *rctx = ahash_request_ctx(req);
 
 	pstat = &_qcrypto_stat;
 	pstat->sha256_hmac_digest++;
 
-	_sha_init(sha_ctx);
-	memset(&sha_ctx->trailing_buf[0], 0x00, SHA256_BLOCK_SIZE);
-	memcpy(&sha_ctx->digest[0], &_std_init_vector_sha256_uint8[0],
+	_sha_init(req);
+
+	memset(&rctx->trailing_buf[0], 0x00, SHA256_BLOCK_SIZE);
+	memcpy(&rctx->digest[0], &_std_init_vector_sha256_uint8[0],
 						SHA256_DIGEST_SIZE);
 	sha_ctx->diglen = SHA256_DIGEST_SIZE;
-	_update_sha256_ctx(req);
 
 	if (cp->ce_support.sha_hmac)
 		sha_ctx->alg = QCE_HASH_SHA256_HMAC;
@@ -2965,36 +3479,39 @@
 	struct qcrypto_sha_req_ctx *rctx = ahash_request_ctx(req);
 	struct crypto_priv *cp = sha_ctx->cp;
 	int i;
+	uint8_t  *staging;
+	uint8_t *p;
 
+	staging = (uint8_t *) ALIGN(((unsigned int)rctx->staging_dmabuf),
+							L1_CACHE_BYTES);
+	p = staging;
 	for (i = 0; i < sha_block_size; i++)
-		sha_ctx->tmp_tbuf[i] = sha_ctx->authkey[i] ^ 0x5c;
+		*p++ = sha_ctx->authkey[i] ^ 0x5c;
+	memcpy(p, &rctx->digest[0], sha_digest_size);
+	sg_set_buf(&rctx->sg[0], staging, sha_block_size +
+							sha_digest_size);
+	sg_mark_end(&rctx->sg[0]);
 
 	/* save the original req structure fields*/
 	rctx->src = req->src;
 	rctx->nbytes = req->nbytes;
 
-	memcpy(&sha_ctx->tmp_tbuf[sha_block_size], &sha_ctx->digest[0],
-						 sha_digest_size);
-
-	sg_set_buf(&sha_ctx->tmp_sg, sha_ctx->tmp_tbuf, sha_block_size +
-							sha_digest_size);
-	sg_mark_end(&sha_ctx->tmp_sg);
-	req->src = &sha_ctx->tmp_sg;
+	req->src = &rctx->sg[0];
 	req->nbytes = sha_block_size + sha_digest_size;
 
-	_sha_init(sha_ctx);
+	_sha_init(req);
 	if (sha_ctx->alg == QCE_HASH_SHA1) {
-		memcpy(&sha_ctx->digest[0], &_std_init_vector_sha1_uint8[0],
+		memcpy(&rctx->digest[0], &_std_init_vector_sha1_uint8[0],
 							SHA1_DIGEST_SIZE);
 		sha_ctx->diglen = SHA1_DIGEST_SIZE;
 	} else {
-		memcpy(&sha_ctx->digest[0], &_std_init_vector_sha256_uint8[0],
+		memcpy(&rctx->digest[0], &_std_init_vector_sha256_uint8[0],
 							SHA256_DIGEST_SIZE);
 		sha_ctx->diglen = SHA256_DIGEST_SIZE;
 	}
 
-	sha_ctx->last_blk = 1;
-	return  _qcrypto_queue_req(cp, &req->base);
+	rctx->last_blk = 1;
+	return  _qcrypto_queue_req(cp, sha_ctx->pengine, &req->base);
 }
 
 static int _sha_hmac_inner_hash(struct ahash_request *req,
@@ -3004,17 +3521,19 @@
 	struct ahash_request *areq = sha_ctx->ahash_req;
 	struct crypto_priv *cp = sha_ctx->cp;
 	int ret = 0;
+	struct qcrypto_sha_req_ctx *rctx = ahash_request_ctx(req);
+	uint8_t  *staging;
 
-	sha_ctx->last_blk = 1;
+	staging = (uint8_t *) ALIGN(((unsigned int)rctx->staging_dmabuf),
+							L1_CACHE_BYTES);
+	memcpy(staging, rctx->trailing_buf, rctx->trailing_buf_len);
+	sg_set_buf(&rctx->sg[0], staging, rctx->trailing_buf_len);
+	sg_mark_end(&rctx->sg[0]);
 
-	sg_set_buf(&sha_ctx->tmp_sg, sha_ctx->trailing_buf,
-					sha_ctx->trailing_buf_len);
-	sg_mark_end(&sha_ctx->tmp_sg);
-
-	ahash_request_set_crypt(areq, &sha_ctx->tmp_sg, &sha_ctx->digest[0],
-						sha_ctx->trailing_buf_len);
-	sha_ctx->last_blk = 1;
-	ret =  _qcrypto_queue_req(cp, &areq->base);
+	ahash_request_set_crypt(areq, &rctx->sg[0], &rctx->digest[0],
+						rctx->trailing_buf_len);
+	rctx->last_blk = 1;
+	ret =  _qcrypto_queue_req(cp, sha_ctx->pengine, &areq->base);
 
 	if (ret == -EINPROGRESS || ret == -EBUSY) {
 		ret =
@@ -3067,12 +3586,13 @@
 {
 	struct qcrypto_sha_ctx *sha_ctx = crypto_tfm_ctx(req->base.tfm);
 	struct crypto_stat *pstat;
+	struct qcrypto_sha_req_ctx *rctx = ahash_request_ctx(req);
 
 	pstat = &_qcrypto_stat;
 	pstat->sha1_hmac_digest++;
 
-	_sha_init(sha_ctx);
-	memcpy(&sha_ctx->digest[0], &_std_init_vector_sha1_uint8[0],
+	_sha_init(req);
+	memcpy(&rctx->digest[0], &_std_init_vector_sha1_uint8[0],
 							SHA1_DIGEST_SIZE);
 	sha_ctx->diglen = SHA1_DIGEST_SIZE;
 	sha_ctx->alg = QCE_HASH_SHA1_HMAC;
@@ -3084,12 +3604,13 @@
 {
 	struct qcrypto_sha_ctx *sha_ctx = crypto_tfm_ctx(req->base.tfm);
 	struct crypto_stat *pstat;
+	struct qcrypto_sha_req_ctx *rctx = ahash_request_ctx(req);
 
 	pstat = &_qcrypto_stat;
 	pstat->sha256_hmac_digest++;
 
-	_sha_init(sha_ctx);
-	memcpy(&sha_ctx->digest[0], &_std_init_vector_sha256_uint8[0],
+	_sha_init(req);
+	memcpy(&rctx->digest[0], &_std_init_vector_sha256_uint8[0],
 						SHA256_DIGEST_SIZE);
 	sha_ctx->diglen = SHA256_DIGEST_SIZE;
 	sha_ctx->alg = QCE_HASH_SHA256_HMAC;
@@ -3097,6 +3618,62 @@
 	return _sha_digest(req);
 }
 
+static int _qcrypto_prefix_alg_cra_name(char cra_name[], unsigned int size)
+{
+	char new_cra_name[CRYPTO_MAX_ALG_NAME] = "qcom-";
+	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);
+	return 0;
+}
+
+
+int qcrypto_cipher_set_device(struct ablkcipher_request *req, unsigned int dev)
+{
+	struct qcrypto_cipher_ctx *ctx = crypto_tfm_ctx(req->base.tfm);
+	struct crypto_priv *cp = ctx->cp;
+	struct crypto_engine *pengine = NULL;
+
+	pengine = _qrypto_find_pengine_device(cp, dev);
+	if (pengine == NULL)
+		return -ENODEV;
+	ctx->pengine = pengine;
+
+	return 0;
+};
+EXPORT_SYMBOL(qcrypto_cipher_set_device);
+
+int qcrypto_aead_set_device(struct aead_request *req, unsigned int dev)
+{
+	struct qcrypto_cipher_ctx *ctx = crypto_tfm_ctx(req->base.tfm);
+	struct crypto_priv *cp = ctx->cp;
+	struct crypto_engine *pengine = NULL;
+
+	pengine = _qrypto_find_pengine_device(cp, dev);
+	if (pengine == NULL)
+		return -ENODEV;
+	ctx->pengine = pengine;
+
+	return 0;
+};
+EXPORT_SYMBOL(qcrypto_aead_set_device);
+
+int qcrypto_ahash_set_device(struct ahash_request *req, unsigned int dev)
+{
+	struct qcrypto_sha_ctx *ctx = crypto_tfm_ctx(req->base.tfm);
+	struct crypto_priv *cp = ctx->cp;
+	struct crypto_engine *pengine = NULL;
+
+	pengine = _qrypto_find_pengine_device(cp, dev);
+	if (pengine == NULL)
+		return -ENODEV;
+	ctx->pengine = pengine;
+
+	return 0;
+};
+EXPORT_SYMBOL(qcrypto_ahash_set_device);
+
 int qcrypto_cipher_set_flag(struct ablkcipher_request *req, unsigned int flags)
 {
 	struct qcrypto_cipher_ctx *ctx = crypto_tfm_ctx(req->base.tfm);
@@ -3252,8 +3829,8 @@
 		.init		=	_sha1_hmac_init,
 		.update		=	_sha1_hmac_update,
 		.final		=	_sha1_hmac_final,
-		.export		=	_sha1_export,
-		.import		=	_sha1_import,
+		.export		=	_sha1_hmac_export,
+		.import		=	_sha1_hmac_import,
 		.digest		=	_sha1_hmac_digest,
 		.setkey		=	_sha1_hmac_setkey,
 		.halg		= {
@@ -3280,8 +3857,8 @@
 		.init		=	_sha256_hmac_init,
 		.update		=	_sha256_hmac_update,
 		.final		=	_sha256_hmac_final,
-		.export		=	_sha256_export,
-		.import		=	_sha256_import,
+		.export		=	_sha256_hmac_export,
+		.import		=	_sha256_hmac_import,
 		.digest		=	_sha256_hmac_digest,
 		.setkey		=	_sha256_hmac_setkey,
 		.halg		= {
@@ -3612,7 +4189,7 @@
 	.cra_u		= {
 		.aead = {
 			.ivsize         = AES_BLOCK_SIZE,
-			.maxauthsize    = SHA1_DIGEST_SIZE,
+			.maxauthsize    = AES_BLOCK_SIZE,
 			.setkey = _qcrypto_aead_ccm_setkey,
 			.setauthsize = _qcrypto_aead_ccm_setauthsize,
 			.encrypt = _qcrypto_aead_encrypt_aes_ccm,
@@ -3622,43 +4199,92 @@
 	}
 };
 
+static struct crypto_alg _qcrypto_aead_rfc4309_ccm_algo = {
+	.cra_name	= "rfc4309(ccm(aes))",
+	.cra_driver_name = "qcrypto-rfc4309-aes-ccm",
+	.cra_priority	= 300,
+	.cra_flags	= CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_ASYNC,
+	.cra_blocksize  = 1,
+	.cra_ctxsize	= sizeof(struct qcrypto_cipher_ctx),
+	.cra_alignmask	= 0,
+	.cra_type	= &crypto_nivaead_type,
+	.cra_module	= THIS_MODULE,
+	.cra_init	= _qcrypto_cra_aead_init,
+	.cra_exit	= _qcrypto_cra_aead_exit,
+	.cra_u		= {
+		.aead = {
+			.ivsize         = 8,
+			.maxauthsize    = 16,
+			.setkey = _qcrypto_aead_rfc4309_ccm_setkey,
+			.setauthsize = _qcrypto_aead_rfc4309_ccm_setauthsize,
+			.encrypt = _qcrypto_aead_rfc4309_enc_aes_ccm,
+			.decrypt = _qcrypto_aead_rfc4309_dec_aes_ccm,
+			.geniv = "seqiv",
+		}
+	}
+};
+
 
 static int  _qcrypto_probe(struct platform_device *pdev)
 {
 	int rc = 0;
 	void *handle;
-	struct crypto_priv *cp;
+	struct crypto_priv *cp = &qcrypto_dev;
 	int i;
 	struct msm_ce_hw_support *platform_support;
+	struct crypto_engine *pengine;
+	unsigned long flags;
 
-	cp = kzalloc(sizeof(*cp), GFP_KERNEL);
-	if (!cp) {
+	pengine = kzalloc(sizeof(*pengine), GFP_KERNEL);
+	if (!pengine) {
 		pr_err("qcrypto Memory allocation of q_alg FAIL, error %ld\n",
-				PTR_ERR(cp));
+				PTR_ERR(pengine));
 		return -ENOMEM;
 	}
 
 	/* open qce */
 	handle = qce_open(pdev, &rc);
 	if (handle == NULL) {
-		kfree(cp);
+		kfree(pengine);
 		platform_set_drvdata(pdev, NULL);
 		return rc;
 	}
 
-	INIT_LIST_HEAD(&cp->alg_list);
-	platform_set_drvdata(pdev, cp);
-	spin_lock_init(&cp->lock);
-	tasklet_init(&cp->done_tasklet, req_done, (unsigned long)cp);
-	crypto_init_queue(&cp->queue, 50);
-	cp->qce = handle;
-	cp->pdev = pdev;
-	qce_hw_support(cp->qce, &cp->ce_support);
+	platform_set_drvdata(pdev, pengine);
+	pengine->qce = handle;
+	pengine->pcp = cp;
+	pengine->pdev = pdev;
+	pengine->req = NULL;
+	pengine->signature = 0xdeadbeef;
+
+	init_timer(&(pengine->bw_reaper_timer));
+	INIT_WORK(&pengine->bw_reaper_ws, qcrypto_bw_reaper_work);
+	pengine->bw_reaper_timer.function =
+			qcrypto_bw_reaper_timer_callback;
+	INIT_WORK(&pengine->bw_allocate_ws, qcrypto_bw_allocate_work);
+	pengine->high_bw_req = false;
+	pengine->active_seq = 0;
+	pengine->last_active_seq = 0;
+	pengine->check_flag = false;
+	qcrypto_bw_set_timeout(pengine);
+
+	tasklet_init(&pengine->done_tasklet, req_done, (unsigned long)pengine);
+	crypto_init_queue(&pengine->req_queue, MSM_QCRYPTO_REQ_QUEUE_LENGTH);
+
+	mutex_lock(&cp->engine_lock);
+	cp->total_units++;
+	pengine->unit = cp->total_units;
+
+	spin_lock_irqsave(&cp->lock, flags);
+	list_add_tail(&pengine->elist, &cp->engine_list);
+	cp->next_engine = pengine;
+	spin_unlock_irqrestore(&cp->lock, flags);
+
+	qce_hw_support(pengine->qce, &cp->ce_support);
 	if (cp->ce_support.bam)	 {
 		cp->platform_support.ce_shared = cp->ce_support.is_shared;
 		cp->platform_support.shared_ce_resource = 0;
 		cp->platform_support.hw_key_support = cp->ce_support.hw_key;
-		cp->platform_support.bus_scale_table =	NULL;
 		cp->platform_support.sha_hmac = 1;
 
 		cp->platform_support.bus_scale_table =
@@ -3666,6 +4292,9 @@
 					msm_bus_cl_get_pdata(pdev);
 		if (!cp->platform_support.bus_scale_table)
 			pr_warn("bus_scale_table is NULL\n");
+
+		pengine->ce_device = cp->ce_support.ce_device;
+
 	} else {
 		platform_support =
 			(struct msm_ce_hw_support *)pdev->dev.platform_data;
@@ -3678,24 +4307,28 @@
 				platform_support->bus_scale_table;
 		cp->platform_support.sha_hmac = platform_support->sha_hmac;
 	}
-	cp->high_bw_req_count = 0;
-	cp->ce_lock_count = 0;
 
-
-	if (cp->platform_support.ce_shared)
-		INIT_WORK(&cp->unlock_ce_ws, qcrypto_unlock_ce);
+	pengine->bus_scale_handle = 0;
 
 	if (cp->platform_support.bus_scale_table != NULL) {
-		cp->bus_scale_handle =
+		pengine->bus_scale_handle =
 			msm_bus_scale_register_client(
 				(struct msm_bus_scale_pdata *)
 					cp->platform_support.bus_scale_table);
-		if (!cp->bus_scale_handle) {
-			printk(KERN_ERR "%s not able to get bus scale\n",
+		if (!pengine->bus_scale_handle) {
+			pr_err("%s not able to get bus scale\n",
 				__func__);
 			rc =  -ENOMEM;
 			goto err;
 		}
+		pengine->bw_state = BUS_NO_BANDWIDTH;
+	} else {
+		pengine->bw_state = BUS_HAS_BANDWIDTH;
+	}
+
+	if (cp->total_units != 1) {
+		mutex_unlock(&cp->engine_lock);
+		return 0;
 	}
 
 	/* register crypto cipher algorithms the device supports */
@@ -3708,6 +4341,18 @@
 			rc = PTR_ERR(q_alg);
 			goto err;
 		}
+		if (cp->ce_support.use_sw_aes_cbc_ecb_ctr_algo) {
+			rc = _qcrypto_prefix_alg_cra_name(
+					q_alg->cipher_alg.cra_name,
+					strlen(q_alg->cipher_alg.cra_name));
+			if (rc) {
+				dev_err(&pdev->dev,
+					"The algorithm name %s is too long.\n",
+					q_alg->cipher_alg.cra_name);
+				kfree(q_alg);
+				goto err;
+			}
+		}
 		rc = crypto_register_alg(&q_alg->cipher_alg);
 		if (rc) {
 			dev_err(&pdev->dev, "%s alg registration failed\n",
@@ -3730,6 +4375,18 @@
 			rc = PTR_ERR(q_alg);
 			goto err;
 		}
+		if (cp->ce_support.use_sw_aes_xts_algo) {
+			rc = _qcrypto_prefix_alg_cra_name(
+					q_alg->cipher_alg.cra_name,
+					strlen(q_alg->cipher_alg.cra_name));
+			if (rc) {
+				dev_err(&pdev->dev,
+					"The algorithm name %s is too long.\n",
+					q_alg->cipher_alg.cra_name);
+				kfree(q_alg);
+				goto err;
+			}
+		}
 		rc = crypto_register_alg(&q_alg->cipher_alg);
 		if (rc) {
 			dev_err(&pdev->dev, "%s alg registration failed\n",
@@ -3755,7 +4412,18 @@
 			rc = PTR_ERR(q_alg);
 			goto err;
 		}
-
+		if (cp->ce_support.use_sw_ahash_algo) {
+			rc = _qcrypto_prefix_alg_cra_name(
+				q_alg->sha_alg.halg.base.cra_name,
+				strlen(q_alg->sha_alg.halg.base.cra_name));
+			if (rc) {
+				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;
+			}
+		}
 		rc = crypto_register_ahash(&q_alg->sha_alg);
 		if (rc) {
 			dev_err(&pdev->dev, "%s alg registration failed\n",
@@ -3781,7 +4449,18 @@
 				rc = PTR_ERR(q_alg);
 				goto err;
 			}
-
+			if (cp->ce_support.use_sw_aead_algo) {
+				rc = _qcrypto_prefix_alg_cra_name(
+					q_alg->cipher_alg.cra_name,
+					strlen(q_alg->cipher_alg.cra_name));
+				if (rc) {
+					dev_err(&pdev->dev,
+						"The algorithm name %s is too long.\n",
+						q_alg->cipher_alg.cra_name);
+					kfree(q_alg);
+					goto err;
+				}
+			}
 			rc = crypto_register_alg(&q_alg->cipher_alg);
 			if (rc) {
 				dev_err(&pdev->dev,
@@ -3808,7 +4487,19 @@
 				rc = PTR_ERR(q_alg);
 				goto err;
 			}
-
+			if (cp->ce_support.use_sw_hmac_algo) {
+				rc = _qcrypto_prefix_alg_cra_name(
+					q_alg->sha_alg.halg.base.cra_name,
+					strlen(
+					q_alg->sha_alg.halg.base.cra_name));
+				if (rc) {
+					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;
+				}
+			}
 			rc = crypto_register_ahash(&q_alg->sha_alg);
 			if (rc) {
 				dev_err(&pdev->dev,
@@ -3834,6 +4525,48 @@
 			rc = PTR_ERR(q_alg);
 			goto err;
 		}
+		if (cp->ce_support.use_sw_aes_ccm_algo) {
+			rc = _qcrypto_prefix_alg_cra_name(
+					q_alg->cipher_alg.cra_name,
+					strlen(q_alg->cipher_alg.cra_name));
+			if (rc) {
+				dev_err(&pdev->dev,
+						"The algorithm name %s is too long.\n",
+						q_alg->cipher_alg.cra_name);
+				kfree(q_alg);
+				goto err;
+			}
+		}
+		rc = crypto_register_alg(&q_alg->cipher_alg);
+		if (rc) {
+			dev_err(&pdev->dev, "%s alg registration failed\n",
+					q_alg->cipher_alg.cra_driver_name);
+			kfree(q_alg);
+		} else {
+			list_add_tail(&q_alg->entry, &cp->alg_list);
+			dev_info(&pdev->dev, "%s\n",
+					q_alg->cipher_alg.cra_driver_name);
+		}
+
+		q_alg = _qcrypto_cipher_alg_alloc(cp,
+					&_qcrypto_aead_rfc4309_ccm_algo);
+		if (IS_ERR(q_alg)) {
+			rc = PTR_ERR(q_alg);
+			goto err;
+		}
+
+		if (cp->ce_support.use_sw_aes_ccm_algo) {
+			rc = _qcrypto_prefix_alg_cra_name(
+					q_alg->cipher_alg.cra_name,
+					strlen(q_alg->cipher_alg.cra_name));
+			if (rc) {
+				dev_err(&pdev->dev,
+						"The algorithm name %s is too long.\n",
+						q_alg->cipher_alg.cra_name);
+				kfree(q_alg);
+				goto err;
+			}
+		}
 		rc = crypto_register_alg(&q_alg->cipher_alg);
 		if (rc) {
 			dev_err(&pdev->dev, "%s alg registration failed\n",
@@ -3846,12 +4579,101 @@
 		}
 	}
 
+	mutex_unlock(&cp->engine_lock);
 	return 0;
 err:
-	_qcrypto_remove(pdev);
+	_qcrypto_remove_engine(pengine);
+	mutex_unlock(&cp->engine_lock);
+	if (pengine->qce)
+		qce_close(pengine->qce);
+	kfree(pengine);
 	return rc;
 };
 
+static int  _qcrypto_suspend(struct platform_device *pdev, pm_message_t state)
+{
+	int ret = 0;
+	struct crypto_engine *pengine;
+	struct crypto_priv *cp;
+	unsigned long flags;
+
+	pengine = platform_get_drvdata(pdev);
+	if (!pengine)
+		return -EINVAL;
+
+	/*
+	 * Check if this platform supports clock management in suspend/resume
+	 * If not, just simply return 0.
+	 */
+	cp = pengine->pcp;
+	if (!cp->ce_support.clk_mgmt_sus_res)
+		return 0;
+	spin_lock_irqsave(&cp->lock, flags);
+	switch (pengine->bw_state) {
+	case BUS_NO_BANDWIDTH:
+		if (pengine->high_bw_req == false)
+			pengine->bw_state = BUS_SUSPENDED;
+		else
+			ret = -EBUSY;
+		break;
+	case BUS_HAS_BANDWIDTH:
+	case BUS_BANDWIDTH_RELEASING:
+	case BUS_BANDWIDTH_ALLOCATING:
+	case BUS_SUSPENDED:
+	default:
+			ret = -EBUSY;
+			break;
+	}
+
+	spin_unlock_irqrestore(&cp->lock, flags);
+	if (ret)
+		return ret;
+	else {
+		if (qce_pm_table.suspend)
+			qce_pm_table.suspend(pengine->qce);
+		return 0;
+	}
+}
+
+static int  _qcrypto_resume(struct platform_device *pdev)
+{
+	struct crypto_engine *pengine;
+	struct crypto_priv *cp;
+	unsigned long flags;
+	bool restart = false;
+
+	pengine = platform_get_drvdata(pdev);
+
+	if (!pengine)
+		return -EINVAL;
+
+	cp = pengine->pcp;
+	if (!cp->ce_support.clk_mgmt_sus_res)
+		return 0;
+
+	spin_lock_irqsave(&cp->lock, flags);
+	if (pengine->bw_state == BUS_SUSPENDED) {
+		pengine->bw_state = BUS_BANDWIDTH_ALLOCATING;
+		spin_unlock_irqrestore(&cp->lock, flags);
+
+		if (qce_pm_table.resume)
+			qce_pm_table.resume(pengine->qce);
+
+		qcrypto_ce_set_bus(pengine, true);
+
+		spin_lock_irqsave(&cp->lock, flags);
+		pengine->bw_state = BUS_HAS_BANDWIDTH;
+		pengine->high_bw_req = false;
+		restart = true;
+		pengine->active_seq++;
+		pengine->check_flag = true;
+	}
+	spin_unlock_irqrestore(&cp->lock, flags);
+	if (restart)
+		_start_qcrypto_process(cp, pengine);
+
+	return 0;
+}
 
 static struct of_device_id qcrypto_match[] = {
 	{	.compatible = "qcom,qcrypto",
@@ -3862,6 +4684,8 @@
 static struct platform_driver _qualcomm_crypto = {
 	.probe          = _qcrypto_probe,
 	.remove         = _qcrypto_remove,
+	.suspend        = _qcrypto_suspend,
+	.resume         = _qcrypto_resume,
 	.driver         = {
 		.owner  = THIS_MODULE,
 		.name   = "qcrypto",
@@ -3895,10 +4719,19 @@
 static ssize_t _debug_stats_write(struct file *file, const char __user *buf,
 			size_t count, loff_t *ppos)
 {
+	unsigned long flags;
+	struct crypto_priv *cp = &qcrypto_dev;
+	struct crypto_engine *pe;
 
 	memset((char *)&_qcrypto_stat, 0, sizeof(struct crypto_stat));
+	spin_lock_irqsave(&cp->lock, flags);
+	list_for_each_entry(pe, &cp->engine_list, elist) {
+		pe->total_req = 0;
+		pe->err_req = 0;
+	}
+	spin_unlock_irqrestore(&cp->lock, flags);
 	return count;
-};
+}
 
 static const struct file_operations _debug_stats_ops = {
 	.open =         _debug_stats_open,
@@ -3938,11 +4771,21 @@
 static int __init _qcrypto_init(void)
 {
 	int rc;
+	struct crypto_priv *pcp = &qcrypto_dev;
 
 	rc = _qcrypto_debug_init();
 	if (rc)
 		return rc;
-
+	INIT_LIST_HEAD(&pcp->alg_list);
+	INIT_LIST_HEAD(&pcp->engine_list);
+	INIT_WORK(&pcp->unlock_ce_ws, qcrypto_unlock_ce);
+	spin_lock_init(&pcp->lock);
+	mutex_init(&pcp->engine_lock);
+	pcp->total_units = 0;
+	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/Kconfig b/drivers/devfreq/Kconfig
index 17bbe19..ca7953d 100644
--- a/drivers/devfreq/Kconfig
+++ b/drivers/devfreq/Kconfig
@@ -71,6 +71,25 @@
 	  Sets the frequency using a "on-demand" algorithm.
 	  This governor is unlikely to be useful for other devices.
 
+config DEVFREQ_GOV_MSM_CPUFREQ
+	bool "MSM CPUfreq"
+	depends on CPU_FREQ_MSM
+	help
+	  MSM CPUfreq based governor for CPU bandwidth voting.  Sets the CPU
+	  to DDR BW vote based on the current CPU frequency.  This governor
+	  is unlikely to be useful for non-MSM devices.
+
+config DEVFREQ_GOV_MSM_CPUBW_HWMON
+	tristate "HW monitor based governor for CPUBW"
+	depends on ARCH_MSM_KRAIT
+	help
+	  HW monitor based governor for CPU to DDR bandwidth voting. This
+	  goveror currently supports only Krait L2 PM counters.  Sets the CPU
+	  BW vote by using L2 PM counters to monitor the Krait's use of DDR.
+	  Since this governor uses some of the PM counters it can conflict
+	  with existing profiling tools.  This governor is unlikely to be
+	  useful for other devices.
+
 comment "DEVFREQ Drivers"
 
 config ARM_EXYNOS4_BUS_DEVFREQ
diff --git a/drivers/devfreq/Makefile b/drivers/devfreq/Makefile
index 29b48ff..e06ed9f 100644
--- a/drivers/devfreq/Makefile
+++ b/drivers/devfreq/Makefile
@@ -4,6 +4,8 @@
 obj-$(CONFIG_DEVFREQ_GOV_POWERSAVE)	+= governor_powersave.o
 obj-$(CONFIG_DEVFREQ_GOV_USERSPACE)	+= governor_userspace.o
 obj-$(CONFIG_DEVFREQ_GOV_MSM_ADRENO_TZ)	+= governor_msm_adreno_tz.o
+obj-$(CONFIG_DEVFREQ_GOV_MSM_CPUFREQ)	+= governor_msm_cpufreq.o
+obj-$(CONFIG_DEVFREQ_GOV_MSM_CPUBW_HWMON)	+= governor_cpubw_hwmon.o
 
 # DEVFREQ Drivers
 obj-$(CONFIG_ARM_EXYNOS4_BUS_DEVFREQ)	+= exynos4_bus.o
diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
index 9e49b3e..e13fb5f 100644
--- a/drivers/devfreq/devfreq.c
+++ b/drivers/devfreq/devfreq.c
@@ -125,14 +125,20 @@
 	cur_time = jiffies;
 	devfreq->time_in_state[lev] +=
 			 cur_time - devfreq->last_stat_updated;
-	if (freq != devfreq->previous_freq) {
-		prev_lev = devfreq_get_freq_level(devfreq,
-						devfreq->previous_freq);
+	devfreq->last_stat_updated = cur_time;
+
+	if (freq == devfreq->previous_freq)
+		return 0;
+
+	prev_lev = devfreq_get_freq_level(devfreq, devfreq->previous_freq);
+	if (prev_lev < 0)
+		return 0;
+
+	if (lev != prev_lev) {
 		devfreq->trans_table[(prev_lev *
 				devfreq->profile->max_state) + lev]++;
 		devfreq->total_trans++;
 	}
-	devfreq->last_stat_updated = cur_time;
 
 	return 0;
 }
diff --git a/drivers/devfreq/governor_cpubw_hwmon.c b/drivers/devfreq/governor_cpubw_hwmon.c
new file mode 100644
index 0000000..aa7ff69
--- /dev/null
+++ b/drivers/devfreq/governor_cpubw_hwmon.c
@@ -0,0 +1,470 @@
+/*
+ * 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.
+ */
+
+#define pr_fmt(fmt) "cpubw-hwmon: " fmt
+
+#include <linux/kernel.h>
+#include <asm/sizes.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/ktime.h>
+#include <linux/time.h>
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/mutex.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/devfreq.h>
+#include "governor.h"
+
+#include <mach/msm-krait-l2-accessors.h>
+
+#define L2PMRESR2		0x412
+#define L2PMCR			0x400
+#define L2PMCNTENCLR		0x402
+#define L2PMCNTENSET		0x403
+#define L2PMINTENCLR		0x404
+#define L2PMINTENSET		0x405
+#define L2PMOVSR		0x406
+#define L2PMOVSSET		0x407
+#define L2PMnEVCNTCR(n)		(0x420 + n * 0x10)
+#define L2PMnEVCNTR(n)		(0x421 + n * 0x10)
+#define L2PMnEVCNTSR(n)		(0x422 + n * 0x10)
+#define L2PMnEVFILTER(n)	(0x423 + n * 0x10)
+#define L2PMnEVTYPER(n)		(0x424 + n * 0x10)
+
+#define show_attr(name) \
+static ssize_t show_##name(struct device *dev,				\
+			struct device_attribute *attr, char *buf)	\
+{									\
+	return sprintf(buf, "%u\n", name);				\
+}
+
+#define store_attr(name, _min, _max) \
+static ssize_t store_##name(struct device *dev,				\
+			struct device_attribute *attr, const char *buf,	\
+			size_t count)					\
+{									\
+	int ret;							\
+	unsigned int val;						\
+	ret = sscanf(buf, "%u", &val);					\
+	if (ret != 1)							\
+		return -EINVAL;						\
+	val = max(val, _min);				\
+	val = min(val, _max);				\
+	name = val;							\
+	return count;							\
+}
+
+#define gov_attr(__attr, min, max)	\
+show_attr(__attr)			\
+store_attr(__attr, min, max)		\
+static DEVICE_ATTR(__attr, 0644, show_##__attr, store_##__attr)
+
+
+static int l2pm_irq;
+static unsigned int bytes_per_beat;
+static unsigned int tolerance_percent = 10;
+static unsigned int guard_band_mbps = 100;
+static unsigned int decay_rate = 90;
+static unsigned int io_percent = 16;
+static unsigned int bw_step = 190;
+
+#define MIN_MS	10U
+#define MAX_MS	500U
+static unsigned int sample_ms = 50;
+static u32 prev_r_start_val;
+static u32 prev_w_start_val;
+static unsigned long prev_ab;
+static ktime_t prev_ts;
+
+#define RD_MON	0
+#define WR_MON	1
+static void mon_init(void)
+{
+	/* Set up counters 0/1 to count write/read beats */
+	set_l2_indirect_reg(L2PMRESR2, 0x8B0B0000);
+	set_l2_indirect_reg(L2PMnEVCNTCR(RD_MON), 0x0);
+	set_l2_indirect_reg(L2PMnEVCNTCR(WR_MON), 0x0);
+	set_l2_indirect_reg(L2PMnEVCNTR(RD_MON), 0xFFFFFFFF);
+	set_l2_indirect_reg(L2PMnEVCNTR(WR_MON), 0xFFFFFFFF);
+	set_l2_indirect_reg(L2PMnEVFILTER(RD_MON), 0xF003F);
+	set_l2_indirect_reg(L2PMnEVFILTER(WR_MON), 0xF003F);
+	set_l2_indirect_reg(L2PMnEVTYPER(RD_MON), 0xA);
+	set_l2_indirect_reg(L2PMnEVTYPER(WR_MON), 0xB);
+}
+
+static void global_mon_enable(bool en)
+{
+	u32 regval;
+
+	/* Global counter enable */
+	regval = get_l2_indirect_reg(L2PMCR);
+	if (en)
+		regval |= BIT(0);
+	else
+		regval &= ~BIT(0);
+	set_l2_indirect_reg(L2PMCR, regval);
+}
+
+static void mon_enable(int n)
+{
+	/* Clear previous overflow state for event counter n */
+	set_l2_indirect_reg(L2PMOVSR, BIT(n));
+
+	/* Enable event counter n */
+	set_l2_indirect_reg(L2PMCNTENSET, BIT(n));
+}
+
+static void mon_disable(int n)
+{
+	/* Disable event counter n */
+	set_l2_indirect_reg(L2PMCNTENCLR, BIT(n));
+}
+
+static void mon_irq_enable(int n, bool en)
+{
+	if (en)
+		set_l2_indirect_reg(L2PMINTENSET, BIT(n));
+	else
+		set_l2_indirect_reg(L2PMINTENCLR, BIT(n));
+}
+
+/* Returns start counter value to be used with mon_get_mbps() */
+static u32 mon_set_limit_mbyte(int n, unsigned int mbytes)
+{
+	u32 regval, beats;
+
+	beats = mult_frac(mbytes, SZ_1M, bytes_per_beat);
+	regval = 0xFFFFFFFF - beats;
+	set_l2_indirect_reg(L2PMnEVCNTR(n), regval);
+	pr_debug("EV%d MB: %d, start val: %x\n", n, mbytes, regval);
+
+	return regval;
+}
+
+long mon_get_count(int n, u32 start_val)
+{
+	u32 overflow, count;
+
+	count = get_l2_indirect_reg(L2PMnEVCNTR(n));
+	overflow = get_l2_indirect_reg(L2PMOVSR);
+
+	pr_debug("EV%d ov: %x, cnt: %x\n", n, overflow, count);
+
+	if (overflow & BIT(n))
+		return 0xFFFFFFFF - start_val + count;
+	else
+		return count - start_val;
+}
+
+/* Returns MBps of read/writes for the sampling window. */
+unsigned int beats_to_mbps(long long beats, unsigned int us)
+{
+	beats *= USEC_PER_SEC;
+	beats *= bytes_per_beat;
+	do_div(beats, us);
+	beats = DIV_ROUND_UP_ULL(beats, SZ_1M);
+
+	return beats;
+}
+
+static int to_limit(int mbps)
+{
+	mbps *= (100 + tolerance_percent) * sample_ms;
+	mbps /= 100;
+	mbps = DIV_ROUND_UP(mbps, MSEC_PER_SEC);
+	return mbps;
+}
+
+unsigned long measure_bw_and_set_irq(void)
+{
+	long r_mbps, w_mbps, mbps;
+	ktime_t ts;
+	unsigned int us;
+
+	/*
+	 * Since we are stopping the counters, we don't want this short work
+	 * to be interrupted by other tasks and cause the measurements to be
+	 * wrong. Not blocking interrupts to avoid affecting interrupt
+	 * latency and since they should be short anyway because they run in
+	 * atomic context.
+	 */
+	preempt_disable();
+
+	ts = ktime_get();
+	us = ktime_to_us(ktime_sub(ts, prev_ts));
+	if (!us)
+		us = 1;
+
+	mon_disable(RD_MON);
+	mon_disable(WR_MON);
+
+	r_mbps = mon_get_count(RD_MON, prev_r_start_val);
+	r_mbps = beats_to_mbps(r_mbps, us);
+	w_mbps = mon_get_count(WR_MON, prev_w_start_val);
+	w_mbps = beats_to_mbps(w_mbps, us);
+
+	prev_r_start_val = mon_set_limit_mbyte(RD_MON, to_limit(r_mbps));
+	prev_w_start_val = mon_set_limit_mbyte(WR_MON, to_limit(w_mbps));
+	prev_ts = ts;
+
+	mon_enable(RD_MON);
+	mon_enable(WR_MON);
+
+	preempt_enable();
+
+	mbps = r_mbps + w_mbps;
+	pr_debug("R/W/BW/us = %ld/%ld/%ld/%d\n", r_mbps, w_mbps, mbps, us);
+
+	return mbps;
+}
+
+static void compute_bw(int mbps, unsigned long *freq, unsigned long *ab)
+{
+	int new_bw;
+
+	mbps += guard_band_mbps;
+
+	if (mbps > prev_ab) {
+		new_bw = mbps;
+	} else {
+		new_bw = mbps * decay_rate + prev_ab * (100 - decay_rate);
+		new_bw /= 100;
+	}
+
+	prev_ab = new_bw;
+	*ab = roundup(new_bw, bw_step);
+	*freq = (new_bw * 100) / io_percent;
+}
+
+#define TOO_SOON_US	(1 * USEC_PER_MSEC)
+static irqreturn_t mon_intr_handler(int irq, void *dev)
+{
+	struct devfreq *df = dev;
+	ktime_t ts;
+	unsigned int us;
+	u32 regval;
+	int ret;
+
+	regval = get_l2_indirect_reg(L2PMOVSR);
+	pr_debug("Got interrupt: %x\n", regval);
+
+	devfreq_monitor_stop(df);
+
+	/*
+	 * Don't recalc bandwidth if the interrupt comes right after a
+	 * previous bandwidth calculation.  This is done for two reasons:
+	 *
+	 * 1. Sampling the BW during a very short duration can result in a
+	 *    very inaccurate measurement due to very short bursts.
+	 * 2. This can only happen if the limit was hit very close to the end
+	 *    of the previous sample period. Which means the current BW
+	 *    estimate is not very off and doesn't need to be readjusted.
+	 */
+	ts = ktime_get();
+	us = ktime_to_us(ktime_sub(ts, prev_ts));
+	if (us > TOO_SOON_US) {
+		mutex_lock(&df->lock);
+		ret = update_devfreq(df);
+		if (ret)
+			pr_err("Unable to update freq on IRQ!\n");
+		mutex_unlock(&df->lock);
+	}
+
+	devfreq_monitor_start(df);
+
+	return IRQ_HANDLED;
+}
+
+static int start_monitoring(struct devfreq *df)
+{
+	int ret, mbyte;
+
+	ret = request_threaded_irq(l2pm_irq, NULL, mon_intr_handler,
+			  IRQF_ONESHOT | IRQF_SHARED,
+			  "cpubw_hwmon", df);
+	if (ret) {
+		pr_err("Unable to register interrupt handler\n");
+		return ret;
+	}
+
+	mon_init();
+	mon_disable(RD_MON);
+	mon_disable(WR_MON);
+
+	mbyte = (df->previous_freq * io_percent) / (2 * 100);
+	prev_r_start_val = mon_set_limit_mbyte(RD_MON, mbyte);
+	prev_w_start_val = mon_set_limit_mbyte(WR_MON, mbyte);
+	prev_ts = ktime_get();
+	prev_ab = 0;
+
+	mon_irq_enable(RD_MON, true);
+	mon_irq_enable(WR_MON, true);
+	mon_enable(RD_MON);
+	mon_enable(WR_MON);
+	global_mon_enable(true);
+
+	return 0;
+}
+
+static void stop_monitoring(struct devfreq *df)
+{
+	global_mon_enable(false);
+	mon_disable(RD_MON);
+	mon_disable(WR_MON);
+	mon_irq_enable(RD_MON, false);
+	mon_irq_enable(WR_MON, false);
+
+	disable_irq(l2pm_irq);
+	free_irq(l2pm_irq, df);
+}
+
+static int devfreq_cpubw_hwmon_get_freq(struct devfreq *df,
+					unsigned long *freq,
+					u32 *flag)
+{
+	unsigned long mbps;
+
+	mbps = measure_bw_and_set_irq();
+	compute_bw(mbps, freq, df->data);
+
+	return 0;
+}
+
+gov_attr(tolerance_percent, 0U, 30U);
+gov_attr(guard_band_mbps, 0U, 2000U);
+gov_attr(decay_rate, 0U, 100U);
+gov_attr(io_percent, 1U, 100U);
+gov_attr(bw_step, 50U, 1000U);
+
+static struct attribute *dev_attr[] = {
+	&dev_attr_tolerance_percent.attr,
+	&dev_attr_guard_band_mbps.attr,
+	&dev_attr_decay_rate.attr,
+	&dev_attr_io_percent.attr,
+	&dev_attr_bw_step.attr,
+	NULL,
+};
+
+static struct attribute_group dev_attr_group = {
+	.name = "cpubw_hwmon",
+	.attrs = dev_attr,
+};
+
+static int devfreq_cpubw_hwmon_ev_handler(struct devfreq *df,
+					unsigned int event, void *data)
+{
+	int ret;
+
+	switch (event) {
+	case DEVFREQ_GOV_START:
+		ret = start_monitoring(df);
+		if (ret)
+			return ret;
+		ret = sysfs_create_group(&df->dev.kobj, &dev_attr_group);
+		if (ret)
+			return ret;
+
+		sample_ms = df->profile->polling_ms;
+		sample_ms = max(MIN_MS, sample_ms);
+		sample_ms = min(MAX_MS, sample_ms);
+		df->profile->polling_ms = sample_ms;
+		devfreq_monitor_start(df);
+
+		pr_debug("Enabled CPU BW HW monitor governor\n");
+		break;
+
+	case DEVFREQ_GOV_STOP:
+		sysfs_remove_group(&df->dev.kobj, &dev_attr_group);
+		devfreq_monitor_stop(df);
+		*(unsigned long *)df->data = 0;
+		stop_monitoring(df);
+		pr_debug("Disabled CPU BW HW monitor governor\n");
+		break;
+
+	case DEVFREQ_GOV_INTERVAL:
+		sample_ms = *(unsigned int *)data;
+		sample_ms = max(MIN_MS, sample_ms);
+		sample_ms = min(MAX_MS, sample_ms);
+		devfreq_interval_update(df, &sample_ms);
+		break;
+	}
+
+	return 0;
+}
+
+static struct devfreq_governor devfreq_cpubw_hwmon = {
+	.name = "cpubw_hwmon",
+	.get_target_freq = devfreq_cpubw_hwmon_get_freq,
+	.event_handler = devfreq_cpubw_hwmon_ev_handler,
+};
+
+static int cpubw_hwmon_driver_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	int ret;
+
+	l2pm_irq = platform_get_irq(pdev, 0);
+	if (l2pm_irq < 0) {
+		pr_err("Unable to get IRQ number\n");
+		return l2pm_irq;
+	}
+
+	ret = of_property_read_u32(dev->of_node, "qcom,bytes-per-beat",
+			     &bytes_per_beat);
+	if (ret) {
+		pr_err("Unable to read bytes per beat\n");
+		return ret;
+	}
+
+	ret = devfreq_add_governor(&devfreq_cpubw_hwmon);
+	if (ret) {
+		pr_err("devfreq governor registration failed\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static struct of_device_id match_table[] = {
+	{ .compatible = "qcom,kraitbw-l2pm" },
+	{}
+};
+
+static struct platform_driver cpubw_hwmon_driver = {
+	.probe = cpubw_hwmon_driver_probe,
+	.driver = {
+		.name = "kraitbw-l2pm",
+		.of_match_table = match_table,
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init cpubw_hwmon_init(void)
+{
+	return platform_driver_register(&cpubw_hwmon_driver);
+}
+module_init(cpubw_hwmon_init);
+
+static void __exit cpubw_hwmon_exit(void)
+{
+	platform_driver_unregister(&cpubw_hwmon_driver);
+}
+module_exit(cpubw_hwmon_exit);
+
+MODULE_DESCRIPTION("HW monitor based CPU DDR bandwidth voting driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/devfreq/governor_msm_cpufreq.c b/drivers/devfreq/governor_msm_cpufreq.c
new file mode 100644
index 0000000..9b13e26
--- /dev/null
+++ b/drivers/devfreq/governor_msm_cpufreq.c
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/devfreq.h>
+#include <mach/cpufreq.h>
+#include "governor.h"
+
+DEFINE_MUTEX(df_lock);
+static struct devfreq *df;
+
+static int devfreq_msm_cpufreq_get_freq(struct devfreq *df,
+					unsigned long *freq,
+					u32 *flag)
+{
+	*freq = msm_cpufreq_get_bw();
+	return 0;
+}
+
+int devfreq_msm_cpufreq_update_bw(void)
+{
+	int ret = 0;
+
+	mutex_lock(&df_lock);
+	if (df) {
+		mutex_lock(&df->lock);
+		ret = update_devfreq(df);
+		mutex_unlock(&df->lock);
+	}
+	mutex_unlock(&df_lock);
+	return ret;
+}
+
+static int devfreq_msm_cpufreq_ev_handler(struct devfreq *devfreq,
+					unsigned int event, void *data)
+{
+	int ret;
+
+	switch (event) {
+	case DEVFREQ_GOV_START:
+		mutex_lock(&df_lock);
+		df = devfreq;
+		mutex_unlock(&df_lock);
+
+		ret = devfreq_msm_cpufreq_update_bw();
+		if (ret) {
+			pr_err("Unable to update BW! Gov start failed!\n");
+			return ret;
+		}
+
+		devfreq_monitor_stop(df);
+		pr_debug("Enabled MSM CPUfreq governor\n");
+		break;
+
+	case DEVFREQ_GOV_STOP:
+		mutex_lock(&df_lock);
+		df = NULL;
+		mutex_unlock(&df_lock);
+
+		pr_debug("Disabled MSM CPUfreq governor\n");
+		break;
+	}
+
+	return 0;
+}
+
+static struct devfreq_governor devfreq_msm_cpufreq = {
+	.name = "msm_cpufreq",
+	.get_target_freq = devfreq_msm_cpufreq_get_freq,
+	.event_handler = devfreq_msm_cpufreq_ev_handler,
+};
+
+int register_devfreq_msm_cpufreq(void)
+{
+	return devfreq_add_governor(&devfreq_msm_cpufreq);
+}
diff --git a/drivers/devfreq/governor_performance.c b/drivers/devfreq/governor_performance.c
index af2edc2..74ae3bb 100644
--- a/drivers/devfreq/governor_performance.c
+++ b/drivers/devfreq/governor_performance.c
@@ -32,13 +32,26 @@
 				unsigned int event, void *data)
 {
 	int ret = 0;
+	unsigned long freq;
 
-	if (event == DEVFREQ_GOV_START || event == DEVFREQ_GOV_RESUME) {
-		mutex_lock(&devfreq->lock);
+	mutex_lock(&devfreq->lock);
+	freq = devfreq->previous_freq;
+	switch (event) {
+	case DEVFREQ_GOV_START:
+		devfreq->profile->target(devfreq->dev.parent,
+				&freq,
+				DEVFREQ_FLAG_WAKEUP_MAXFREQ);
+		/* fall through */
+	case DEVFREQ_GOV_RESUME:
 		ret = update_devfreq(devfreq);
-		mutex_unlock(&devfreq->lock);
+		break;
+	case DEVFREQ_GOV_SUSPEND:
+		devfreq->profile->target(devfreq->dev.parent,
+				&freq,
+				DEVFREQ_FLAG_WAKEUP_MAXFREQ);
+		break;
 	}
-
+	mutex_unlock(&devfreq->lock);
 	return ret;
 }
 
diff --git a/drivers/devfreq/governor_simpleondemand.c b/drivers/devfreq/governor_simpleondemand.c
index bb29360..d37997d 100644
--- a/drivers/devfreq/governor_simpleondemand.c
+++ b/drivers/devfreq/governor_simpleondemand.c
@@ -29,6 +29,7 @@
 	unsigned int dfso_downdifferential = DFSO_DOWNDIFFERENCTIAL;
 	struct devfreq_simple_ondemand_data *data = df->data;
 	unsigned long max = (df->max_freq) ? df->max_freq : UINT_MAX;
+	unsigned long min = (df->min_freq) ? df->min_freq : 0;
 
 	if (err)
 		return err;
@@ -43,18 +44,30 @@
 	    dfso_upthreshold < dfso_downdifferential)
 		return -EINVAL;
 
-	/* Assume MAX if it is going to be divided by zero */
-	if (stat.total_time == 0) {
-		*freq = max;
-		return 0;
-	}
-
 	/* Prevent overflow */
 	if (stat.busy_time >= (1 << 24) || stat.total_time >= (1 << 24)) {
 		stat.busy_time >>= 7;
 		stat.total_time >>= 7;
 	}
 
+	if (data && data->simple_scaling) {
+		if (stat.busy_time * 100 >
+		    stat.total_time * dfso_upthreshold)
+			*freq = max;
+		else if (stat.busy_time * 100 <
+		    stat.total_time * dfso_downdifferential)
+			*freq = min;
+		else
+			*freq = df->previous_freq;
+		return 0;
+	}
+
+	/* Assume MAX if it is going to be divided by zero */
+	if (stat.total_time == 0) {
+		*freq = max;
+		return 0;
+	}
+
 	/* Set MAX if it's busy enough */
 	if (stat.busy_time * 100 >
 	    stat.total_time * dfso_upthreshold) {
diff --git a/drivers/gpio/gpio-msm-common.c b/drivers/gpio/gpio-msm-common.c
index 3d18809..4a69cd5 100644
--- a/drivers/gpio/gpio-msm-common.c
+++ b/drivers/gpio/gpio-msm-common.c
@@ -112,16 +112,11 @@
  * @wake_irqs: a bitmap for tracking which interrupt lines are enabled
  * as wakeup sources.  When the device is suspended, interrupts which are
  * not wakeup sources are disabled.
- *
- * @dual_edge_irqs: a bitmap used to track which irqs are configured
- * as dual-edge, as this is not supported by the hardware and requires
- * some special handling in the driver.
  */
 struct msm_gpio_dev {
 	struct gpio_chip gpio_chip;
 	unsigned long *enabled_irqs;
 	unsigned long *wake_irqs;
-	unsigned long *dual_edge_irqs;
 	struct irq_domain *domain;
 };
 
@@ -219,64 +214,11 @@
 	},
 };
 
-static void switch_mpm_config(struct irq_data *d, unsigned val)
-{
-	/* switch the configuration in the mpm as well */
-	if (!msm_gpio_irq_extn.irq_set_type)
-		return;
-
-	if (val)
-		msm_gpio_irq_extn.irq_set_type(d, IRQF_TRIGGER_FALLING);
-	else
-		msm_gpio_irq_extn.irq_set_type(d, IRQF_TRIGGER_RISING);
-}
-
-/* For dual-edge interrupts in software, since the hardware has no
- * such support:
- *
- * At appropriate moments, this function may be called to flip the polarity
- * settings of both-edge irq lines to try and catch the next edge.
- *
- * The attempt is considered successful if:
- * - the status bit goes high, indicating that an edge was caught, or
- * - the input value of the gpio doesn't change during the attempt.
- * If the value changes twice during the process, that would cause the first
- * test to fail but would force the second, as two opposite
- * transitions would cause a detection no matter the polarity setting.
- *
- * The do-loop tries to sledge-hammer closed the timing hole between
- * the initial value-read and the polarity-write - if the line value changes
- * during that window, an interrupt is lost, the new polarity setting is
- * incorrect, and the first success test will fail, causing a retry.
- *
- * Algorithm comes from Google's msmgpio driver, see mach-msm/gpio.c.
- */
-static void msm_gpio_update_dual_edge_pos(struct irq_data *d, unsigned gpio)
-{
-	int loop_limit = 100;
-	unsigned val, val2, intstat;
-
-	do {
-		val = __msm_gpio_get_inout(gpio);
-		__msm_gpio_set_polarity(gpio, val);
-		val2 = __msm_gpio_get_inout(gpio);
-		intstat = __msm_gpio_get_intr_status(gpio);
-		if (intstat || val == val2) {
-			switch_mpm_config(d, val);
-			return;
-		}
-	} while (loop_limit-- > 0);
-	pr_err("%s: dual-edge irq failed to stabilize, %#08x != %#08x\n",
-	       __func__, val, val2);
-}
-
 static void msm_gpio_irq_ack(struct irq_data *d)
 {
 	int gpio = msm_irq_to_gpio(&msm_gpio.gpio_chip, d->irq);
 
 	__msm_gpio_set_intr_status(gpio);
-	if (test_bit(gpio, msm_gpio.dual_edge_irqs))
-		msm_gpio_update_dual_edge_pos(d, gpio);
 	mb();
 }
 
@@ -327,29 +269,18 @@
 
 	spin_lock_irqsave(&tlmm_lock, irq_flags);
 
-	if (flow_type & IRQ_TYPE_EDGE_BOTH) {
+	if (flow_type & IRQ_TYPE_EDGE_BOTH)
 		__irq_set_handler_locked(d->irq, handle_edge_irq);
-		if ((flow_type & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH)
-			__set_bit(gpio, msm_gpio.dual_edge_irqs);
-		else
-			__clear_bit(gpio, msm_gpio.dual_edge_irqs);
-	} else {
+	else
 		__irq_set_handler_locked(d->irq, handle_level_irq);
-		__clear_bit(gpio, msm_gpio.dual_edge_irqs);
-	}
 
 	__msm_gpio_set_intr_cfg_type(gpio, flow_type);
 
-	if ((flow_type & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH)
-		msm_gpio_update_dual_edge_pos(d, gpio);
-
 	mb();
 	spin_unlock_irqrestore(&tlmm_lock, irq_flags);
 
-	if ((flow_type & IRQ_TYPE_EDGE_BOTH) != IRQ_TYPE_EDGE_BOTH) {
-		if (msm_gpio_irq_extn.irq_set_type)
-			msm_gpio_irq_extn.irq_set_type(d, flow_type);
-	}
+	if (msm_gpio_irq_extn.irq_set_type)
+		msm_gpio_irq_extn.irq_set_type(d, flow_type);
 
 	return 0;
 }
@@ -609,17 +540,9 @@
 				, __func__);
 		return -ENOMEM;
 	}
-	msm_gpio.dual_edge_irqs = devm_kzalloc(&pdev->dev, sizeof(unsigned long)
-					* BITS_TO_LONGS(ngpio), GFP_KERNEL);
-	if (!msm_gpio.dual_edge_irqs) {
-		dev_err(&pdev->dev, "%s failed to allocated dual_edge_irqs bitmap\n"
-				, __func__);
-		return -ENOMEM;
-	}
 
 	bitmap_zero(msm_gpio.enabled_irqs, ngpio);
 	bitmap_zero(msm_gpio.wake_irqs, ngpio);
-	bitmap_zero(msm_gpio.dual_edge_irqs, ngpio);
 	ret = gpiochip_add(&msm_gpio.gpio_chip);
 	if (ret < 0)
 		return ret;
diff --git a/drivers/gpio/qpnp-pin.c b/drivers/gpio/qpnp-pin.c
index ed001f0..6176df9 100644
--- a/drivers/gpio/qpnp-pin.c
+++ b/drivers/gpio/qpnp-pin.c
@@ -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
@@ -55,11 +55,13 @@
 #define Q_GPIO_SUBTYPE_GPIOC_8CH	0xD
 
 /* mpp peripheral type and subtype values */
-#define Q_MPP_TYPE			0x11
-#define Q_MPP_SUBTYPE_4CH_NO_ANA_OUT	0x3
-#define Q_MPP_SUBTYPE_4CH_NO_SINK	0x5
-#define Q_MPP_SUBTYPE_4CH_FULL_FUNC	0x7
-#define Q_MPP_SUBTYPE_8CH_FULL_FUNC	0xF
+#define Q_MPP_TYPE				0x11
+#define Q_MPP_SUBTYPE_4CH_NO_ANA_OUT		0x3
+#define Q_MPP_SUBTYPE_ULT_4CH_NO_ANA_OUT	0x4
+#define Q_MPP_SUBTYPE_4CH_NO_SINK		0x5
+#define Q_MPP_SUBTYPE_ULT_4CH_NO_SINK		0x6
+#define Q_MPP_SUBTYPE_4CH_FULL_FUNC		0x7
+#define Q_MPP_SUBTYPE_8CH_FULL_FUNC		0xF
 
 /* control register base address offsets */
 #define Q_REG_MODE_CTL			0x40
@@ -180,6 +182,7 @@
 	struct device_node	*int_ctrl;
 	struct list_head	chip_list;
 	struct dentry		*dfs_dir;
+	bool			chip_registered;
 };
 
 static LIST_HEAD(qpnp_pin_chips);
@@ -235,22 +238,29 @@
 static int qpnp_pin_check_config(enum qpnp_pin_param_type idx,
 				 struct qpnp_pin_spec *q_spec, uint32_t val)
 {
+	u8 subtype = q_spec->subtype;
+
 	switch (idx) {
 	case Q_PIN_CFG_MODE:
 		if (q_spec->type == Q_GPIO_TYPE &&
 		    val >= QPNP_PIN_GPIO_MODE_INVALID)
 				return -EINVAL;
-		else if (q_spec->type == Q_MPP_TYPE &&
-			 val >= QPNP_PIN_MPP_MODE_INVALID)
+		else if (q_spec->type == Q_MPP_TYPE) {
+			if (val >= QPNP_PIN_MPP_MODE_INVALID)
 				return -EINVAL;
+			if ((subtype == Q_MPP_SUBTYPE_ULT_4CH_NO_ANA_OUT ||
+			     subtype == Q_MPP_SUBTYPE_ULT_4CH_NO_SINK) &&
+			     (val == QPNP_PIN_MODE_BIDIR))
+				return -ENXIO;
+		}
 		break;
 	case Q_PIN_CFG_OUTPUT_TYPE:
 		if (q_spec->type != Q_GPIO_TYPE)
 			return -ENXIO;
 		if ((val == QPNP_PIN_OUT_BUF_OPEN_DRAIN_NMOS ||
 		    val == QPNP_PIN_OUT_BUF_OPEN_DRAIN_PMOS) &&
-		    (q_spec->subtype == Q_GPIO_SUBTYPE_GPIOC_4CH ||
-		    (q_spec->subtype == Q_GPIO_SUBTYPE_GPIOC_8CH)))
+		    (subtype == Q_GPIO_SUBTYPE_GPIOC_4CH ||
+		    (subtype == Q_GPIO_SUBTYPE_GPIOC_8CH)))
 			return -EINVAL;
 		else if (val >= QPNP_PIN_OUT_BUF_INVALID)
 			return -EINVAL;
@@ -263,22 +273,28 @@
 		if (q_spec->type == Q_GPIO_TYPE &&
 		    val >= QPNP_PIN_GPIO_PULL_INVALID)
 			return -EINVAL;
-		if (q_spec->type == Q_MPP_TYPE &&
-		    val >= QPNP_PIN_MPP_PULL_INVALID)
-			return -EINVAL;
+		if (q_spec->type == Q_MPP_TYPE) {
+			if (val >= QPNP_PIN_MPP_PULL_INVALID)
+				return -EINVAL;
+			if (subtype == Q_MPP_SUBTYPE_ULT_4CH_NO_ANA_OUT ||
+			    subtype == Q_MPP_SUBTYPE_ULT_4CH_NO_SINK)
+				return -ENXIO;
+		}
 		break;
 	case Q_PIN_CFG_VIN_SEL:
 		if (val >= QPNP_PIN_VIN_8CH_INVALID)
 			return -EINVAL;
 		else if (val >= QPNP_PIN_VIN_4CH_INVALID) {
 			if (q_spec->type == Q_GPIO_TYPE &&
-			   (q_spec->subtype == Q_GPIO_SUBTYPE_GPIO_4CH ||
-			    q_spec->subtype == Q_GPIO_SUBTYPE_GPIOC_4CH))
+			   (subtype == Q_GPIO_SUBTYPE_GPIO_4CH ||
+			    subtype == Q_GPIO_SUBTYPE_GPIOC_4CH))
 				return -EINVAL;
 			if (q_spec->type == Q_MPP_TYPE &&
-			   (q_spec->subtype == Q_MPP_SUBTYPE_4CH_NO_ANA_OUT ||
-			    q_spec->subtype == Q_MPP_SUBTYPE_4CH_NO_SINK ||
-			    q_spec->subtype == Q_MPP_SUBTYPE_4CH_FULL_FUNC))
+			   (subtype == Q_MPP_SUBTYPE_4CH_NO_ANA_OUT ||
+			    subtype == Q_MPP_SUBTYPE_4CH_NO_SINK ||
+			    subtype == Q_MPP_SUBTYPE_4CH_FULL_FUNC ||
+			    subtype == Q_MPP_SUBTYPE_ULT_4CH_NO_ANA_OUT ||
+			    subtype == Q_MPP_SUBTYPE_ULT_4CH_NO_SINK))
 				return -EINVAL;
 		}
 		break;
@@ -304,7 +320,8 @@
 	case Q_PIN_CFG_AOUT_REF:
 		if (q_spec->type != Q_MPP_TYPE)
 			return -ENXIO;
-		if (q_spec->subtype == Q_MPP_SUBTYPE_4CH_NO_ANA_OUT)
+		if (subtype == Q_MPP_SUBTYPE_4CH_NO_ANA_OUT ||
+		    subtype == Q_MPP_SUBTYPE_ULT_4CH_NO_ANA_OUT)
 			return -ENXIO;
 		if (val >= QPNP_PIN_AOUT_REF_INVALID)
 			return -EINVAL;
@@ -318,7 +335,8 @@
 	case Q_PIN_CFG_CS_OUT:
 		if (q_spec->type != Q_MPP_TYPE)
 			return -ENXIO;
-		if (q_spec->subtype == Q_MPP_SUBTYPE_4CH_NO_SINK)
+		if (subtype == Q_MPP_SUBTYPE_4CH_NO_SINK ||
+		    subtype == Q_MPP_SUBTYPE_ULT_4CH_NO_SINK)
 			return -ENXIO;
 		if (val >= QPNP_PIN_CS_OUT_INVALID)
 			return -EINVAL;
@@ -410,9 +428,11 @@
 	else if (q_spec->type == Q_MPP_TYPE)
 		switch (q_spec->subtype) {
 		case Q_MPP_SUBTYPE_4CH_NO_SINK:
+		case Q_MPP_SUBTYPE_ULT_4CH_NO_SINK:
 			q_spec->num_ctl_regs = 12;
 			break;
 		case Q_MPP_SUBTYPE_4CH_NO_ANA_OUT:
+		case Q_MPP_SUBTYPE_ULT_4CH_NO_ANA_OUT:
 		case Q_MPP_SUBTYPE_4CH_FULL_FUNC:
 		case Q_MPP_SUBTYPE_8CH_FULL_FUNC:
 			q_spec->num_ctl_regs = 13;
@@ -627,11 +647,28 @@
 {
 	struct qpnp_pin_chip *q_chip = dev_get_drvdata(gpio_chip->dev);
 	struct qpnp_pin_spec *q_spec;
+	u32 intspec[3];
 
 	q_spec = qpnp_chip_gpio_get_spec(q_chip, offset);
 	if (!q_spec)
 		return -EINVAL;
 
+	/* if we have mapped this pin previously return the virq */
+	if (q_spec->irq)
+		return q_spec->irq;
+
+	/* call into irq_domain to get irq mapping */
+	intspec[0] = q_chip->spmi->sid;
+	intspec[1] = (q_spec->offset >> 8) & 0xFF;
+	intspec[2] = 0;
+	q_spec->irq = irq_create_of_mapping(q_chip->int_ctrl, intspec, 3);
+	if (!q_spec->irq) {
+		dev_err(&q_chip->spmi->dev, "%s: invalid irq for gpio %u\n",
+						__func__, q_spec->pmic_pin);
+		WARN_ON(1);
+		return -EINVAL;
+	}
+
 	return q_spec->irq;
 }
 
@@ -876,7 +913,7 @@
 static int qpnp_pin_free_chip(struct qpnp_pin_chip *q_chip)
 {
 	struct spmi_device *spmi = q_chip->spmi;
-	int rc, i;
+	int i, rc = 0;
 
 	if (q_chip->chip_gpios)
 		for (i = 0; i < spmi->num_dev_node; i++)
@@ -885,10 +922,12 @@
 	mutex_lock(&qpnp_pin_chips_lock);
 	list_del(&q_chip->chip_list);
 	mutex_unlock(&qpnp_pin_chips_lock);
-	rc = gpiochip_remove(&q_chip->gpio_chip);
-	if (rc)
-		dev_err(&q_chip->spmi->dev, "%s: unable to remove gpio\n",
-				__func__);
+	if (q_chip->chip_registered) {
+		rc = gpiochip_remove(&q_chip->gpio_chip);
+		if (rc)
+			dev_err(&q_chip->spmi->dev, "%s: unable to remove gpio\n",
+					__func__);
+	}
 	kfree(q_chip->chip_gpios);
 	kfree(q_chip->pmic_pins);
 	kfree(q_chip);
@@ -1127,7 +1166,9 @@
 	else if (q_spec->type == Q_MPP_TYPE)
 		switch (q_spec->subtype) {
 		case Q_MPP_SUBTYPE_4CH_NO_ANA_OUT:
+		case Q_MPP_SUBTYPE_ULT_4CH_NO_ANA_OUT:
 		case Q_MPP_SUBTYPE_4CH_NO_SINK:
+		case Q_MPP_SUBTYPE_ULT_4CH_NO_SINK:
 		case Q_MPP_SUBTYPE_4CH_FULL_FUNC:
 		case Q_MPP_SUBTYPE_8CH_FULL_FUNC:
 			return 1;
@@ -1144,7 +1185,7 @@
 	struct spmi_resource *d_node;
 	int i, rc;
 	int lowest_gpio = UINT_MAX, highest_gpio = 0;
-	u32 intspec[3], gpio;
+	u32 gpio;
 	char version[Q_REG_SUBTYPE - Q_REG_DIG_MAJOR_REV + 1];
 	const char *dev_name;
 
@@ -1279,18 +1320,6 @@
 		if (rc)
 			goto err_probe;
 
-		/* call into irq_domain to get irq mapping */
-		intspec[0] = q_chip->spmi->sid;
-		intspec[1] = (q_spec->offset >> 8) & 0xFF;
-		intspec[2] = 0;
-		q_spec->irq = irq_create_of_mapping(q_chip->int_ctrl,
-							intspec, 3);
-		if (!q_spec->irq) {
-			dev_err(&spmi->dev, "%s: invalid irq for gpio %u\n",
-								__func__, gpio);
-			rc = -EINVAL;
-			goto err_probe;
-		}
 		/* initialize lookup table params */
 		qpnp_pmic_pin_set_spec(q_chip, gpio, q_spec);
 		qpnp_chip_gpio_set_spec(q_chip, i, q_spec);
@@ -1316,6 +1345,7 @@
 		goto err_probe;
 	}
 
+	q_chip->chip_registered = true;
 	/* now configure gpio config defaults if they exist */
 	for (i = 0; i < spmi->num_dev_node; i++) {
 		q_spec = qpnp_chip_gpio_get_spec(q_chip, i);
diff --git a/drivers/gpu/ion/ion_cma_secure_heap.c b/drivers/gpu/ion/ion_cma_secure_heap.c
index d375c00..da68d05 100644
--- a/drivers/gpu/ion/ion_cma_secure_heap.c
+++ b/drivers/gpu/ion/ion_cma_secure_heap.c
@@ -444,18 +444,19 @@
 	ret = ion_secure_cma_alloc_from_pool(sheap, &info->phys, len);
 
 	if (ret) {
+retry:
 		ret = ion_secure_cma_add_to_pool(sheap, len);
 		if (ret) {
+			mutex_unlock(&sheap->alloc_lock);
 			dev_err(sheap->dev, "Fail to allocate buffer\n");
 			goto err;
 		}
 		ret = ion_secure_cma_alloc_from_pool(sheap, &info->phys, len);
 		if (ret) {
 			/*
-			 * We just added memory to the pool, we shouldn't be
-			 * failing to get memory
+			 * Lost the race with the shrinker, try again
 			 */
-			BUG();
+			goto retry;
 		}
 	}
 	mutex_unlock(&sheap->alloc_lock);
diff --git a/drivers/gpu/ion/ion_heap.c b/drivers/gpu/ion/ion_heap.c
index 9d33bf4..aa2551a 100644
--- a/drivers/gpu/ion/ion_heap.c
+++ b/drivers/gpu/ion/ion_heap.c
@@ -108,8 +108,7 @@
  *
  * Note that the `pages' array should be composed of all 4K pages.
  */
-int ion_heap_pages_zero(struct page **pages, int num_pages,
-				bool should_invalidate)
+int ion_heap_pages_zero(struct page **pages, int num_pages)
 {
 	int i, j, k, npages_to_vmap;
 	void *ptr = NULL;
@@ -142,21 +141,22 @@
 		if (!ptr)
 			return -ENOMEM;
 
-		memset(ptr, 0, npages_to_vmap * PAGE_SIZE);
-		if (should_invalidate) {
-			/*
-			 * invalidate the cache to pick up the zeroing
-			 */
-			for (k = 0; k < npages_to_vmap; k++) {
-				void *p = kmap_atomic(pages[i + k]);
-				phys_addr_t phys = page_to_phys(
-							pages[i + k]);
+		/*
+		 * We have to invalidate the cache here because there
+		 * might be dirty lines to these physical pages (which
+		 * we don't care about) that could get written out at
+		 * any moment.
+		 */
+		for (k = 0; k < npages_to_vmap; k++) {
+			void *p = kmap_atomic(pages[i + k]);
+			phys_addr_t phys = page_to_phys(
+				pages[i + k]);
 
-				dmac_inv_range(p, p + PAGE_SIZE);
-				outer_inv_range(phys, phys + PAGE_SIZE);
-				kunmap_atomic(p);
-			}
+			dmac_inv_range(p, p + PAGE_SIZE);
+			outer_inv_range(phys, phys + PAGE_SIZE);
+			kunmap_atomic(p);
 		}
+		memset(ptr, 0, npages_to_vmap * PAGE_SIZE);
 		vunmap(ptr);
 	}
 
@@ -196,8 +196,7 @@
 	pages_mem->free_fn(pages_mem->pages);
 }
 
-int ion_heap_high_order_page_zero(struct page *page,
-				int order, bool should_invalidate)
+int ion_heap_high_order_page_zero(struct page *page, int order)
 {
 	int i, ret;
 	struct pages_mem pages_mem;
@@ -210,8 +209,7 @@
 	for (i = 0; i < (1 << order); ++i)
 		pages_mem.pages[i] = page + i;
 
-	ret = ion_heap_pages_zero(pages_mem.pages, npages,
-				should_invalidate);
+	ret = ion_heap_pages_zero(pages_mem.pages, npages);
 	ion_heap_free_pages_mem(&pages_mem);
 	return ret;
 }
@@ -240,49 +238,11 @@
 			pages_mem.pages[npages++] = page + j;
 	}
 
-	ret = ion_heap_pages_zero(pages_mem.pages, npages,
-				ion_buffer_cached(buffer));
+	ret = ion_heap_pages_zero(pages_mem.pages, npages);
 	ion_heap_free_pages_mem(&pages_mem);
 	return ret;
 }
 
-int ion_heap_buffer_zero_old(struct ion_buffer *buffer)
-{
-	struct sg_table *table = buffer->sg_table;
-	pgprot_t pgprot;
-	struct scatterlist *sg;
-	struct vm_struct *vm_struct;
-	int i, j, ret = 0;
-
-	if (buffer->flags & ION_FLAG_CACHED)
-		pgprot = PAGE_KERNEL;
-	else
-		pgprot = pgprot_writecombine(PAGE_KERNEL);
-
-	vm_struct = get_vm_area(PAGE_SIZE, VM_ALLOC);
-	if (!vm_struct)
-		return -ENOMEM;
-
-	for_each_sg(table->sgl, sg, table->nents, i) {
-		struct page *page = sg_page(sg);
-		unsigned long len = sg_dma_len(sg);
-
-		for (j = 0; j < len / PAGE_SIZE; j++) {
-			struct page *sub_page = page + j;
-			struct page **pages = &sub_page;
-			ret = map_vm_area(vm_struct, pgprot, &pages);
-			if (ret)
-				goto end;
-			memset(vm_struct->addr, 0, PAGE_SIZE);
-			unmap_kernel_range((unsigned long)vm_struct->addr,
-					   PAGE_SIZE);
-		}
-	}
-end:
-	free_vm_area(vm_struct);
-	return ret;
-}
-
 void ion_heap_free_page(struct ion_buffer *buffer, struct page *page,
 		       unsigned int order)
 {
@@ -333,11 +293,11 @@
 		if (total_drained >= size)
 			break;
 		list_del(&buffer->list);
-		ion_buffer_destroy(buffer);
 		heap->free_list_size -= buffer->size;
 		if (skip_pools)
 			buffer->flags |= ION_FLAG_FREED_FROM_SHRINKER;
 		total_drained += buffer->size;
+		ion_buffer_destroy(buffer);
 	}
 	rt_mutex_unlock(&heap->lock);
 
diff --git a/drivers/gpu/ion/ion_page_pool.c b/drivers/gpu/ion/ion_page_pool.c
index 94f9445..cc2a36d 100644
--- a/drivers/gpu/ion/ion_page_pool.c
+++ b/drivers/gpu/ion/ion_page_pool.c
@@ -40,8 +40,7 @@
 		return NULL;
 
 	if (pool->gfp_mask & __GFP_ZERO)
-		if (ion_heap_high_order_page_zero(
-				page, pool->order, pool->should_invalidate))
+		if (ion_heap_high_order_page_zero(page, pool->order))
 			goto error_free_pages;
 
 	sg_init_table(&sg, 1);
@@ -175,8 +174,7 @@
 	return nr_freed;
 }
 
-struct ion_page_pool *ion_page_pool_create(gfp_t gfp_mask, unsigned int order,
-	bool should_invalidate)
+struct ion_page_pool *ion_page_pool_create(gfp_t gfp_mask, unsigned int order)
 {
 	struct ion_page_pool *pool = kmalloc(sizeof(struct ion_page_pool),
 					     GFP_KERNEL);
@@ -188,7 +186,6 @@
 	INIT_LIST_HEAD(&pool->high_items);
 	pool->gfp_mask = gfp_mask;
 	pool->order = order;
-	pool->should_invalidate = should_invalidate;
 	mutex_init(&pool->mutex);
 	plist_node_init(&pool->list, order);
 
diff --git a/drivers/gpu/ion/ion_priv.h b/drivers/gpu/ion/ion_priv.h
index aa0a9e2..c57efc1 100644
--- a/drivers/gpu/ion/ion_priv.h
+++ b/drivers/gpu/ion/ion_priv.h
@@ -234,11 +234,9 @@
 void ion_heap_unmap_kernel(struct ion_heap *, struct ion_buffer *);
 int ion_heap_map_user(struct ion_heap *, struct ion_buffer *,
 			struct vm_area_struct *);
-int ion_heap_pages_zero(struct page **pages, int num_pages,
-			bool should_invalidate);
+int ion_heap_pages_zero(struct page **pages, int num_pages);
 int ion_heap_buffer_zero(struct ion_buffer *buffer);
-int ion_heap_high_order_page_zero(struct page *page,
-				int order, bool should_invalidate);
+int ion_heap_high_order_page_zero(struct page *page, int order);
 
 /**
  * ion_heap_init_deferred_free -- initialize deferred free functionality
@@ -357,8 +355,6 @@
  * @gfp_mask:		gfp_mask to use from alloc
  * @order:		order of pages in the pool
  * @list:		plist node for list of pools
- * @should_invalidate:	whether or not the cache needs to be invalidated at
- *			page allocation time.
  *
  * Allows you to keep a pool of pre allocated pages to use from your heap.
  * Keeping a pool of pages that is ready for dma, ie any cached mapping have
@@ -374,11 +370,9 @@
 	gfp_t gfp_mask;
 	unsigned int order;
 	struct plist_node list;
-	bool should_invalidate;
 };
 
-struct ion_page_pool *ion_page_pool_create(gfp_t gfp_mask, unsigned int order,
-	bool should_invalidate);
+struct ion_page_pool *ion_page_pool_create(gfp_t gfp_mask, unsigned int order);
 void ion_page_pool_destroy(struct ion_page_pool *);
 void *ion_page_pool_alloc(struct ion_page_pool *);
 void ion_page_pool_free(struct ion_page_pool *, struct page *);
diff --git a/drivers/gpu/ion/ion_system_heap.c b/drivers/gpu/ion/ion_system_heap.c
index 8e885b2..cfdd5f4 100644
--- a/drivers/gpu/ion/ion_system_heap.c
+++ b/drivers/gpu/ion/ion_system_heap.c
@@ -2,7 +2,7 @@
  * drivers/gpu/ion/ion_system_heap.c
  *
  * Copyright (C) 2011 Google, Inc.
- * Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011-2014, The Linux Foundation. All rights reserved.
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
@@ -34,7 +34,7 @@
 					    __GFP_NO_KSWAPD) & ~__GFP_WAIT;
 static unsigned int low_order_gfp_flags  = (GFP_HIGHUSER | __GFP_ZERO |
 					 __GFP_NOWARN);
-static const unsigned int orders[] = {8, 4, 0};
+static const unsigned int orders[] = {9, 8, 4, 0};
 static const int num_orders = ARRAY_SIZE(orders);
 static int order_to_index(unsigned int order)
 {
@@ -355,18 +355,16 @@
  * nothing. If it succeeds you'll eventually need to use
  * ion_system_heap_destroy_pools to destroy the pools.
  */
-static int ion_system_heap_create_pools(struct ion_page_pool **pools,
-					bool should_invalidate)
+static int ion_system_heap_create_pools(struct ion_page_pool **pools)
 {
 	int i;
 	for (i = 0; i < num_orders; i++) {
 		struct ion_page_pool *pool;
 		gfp_t gfp_flags = low_order_gfp_flags;
 
-		if (orders[i] > 4)
+		if (orders[i])
 			gfp_flags = high_order_gfp_flags;
-		pool = ion_page_pool_create(gfp_flags, orders[i],
-					should_invalidate);
+		pool = ion_page_pool_create(gfp_flags, orders[i]);
 		if (!pool)
 			goto err_create_pool;
 		pools[i] = pool;
@@ -397,10 +395,10 @@
 	if (!heap->cached_pools)
 		goto err_alloc_cached_pools;
 
-	if (ion_system_heap_create_pools(heap->uncached_pools, false))
+	if (ion_system_heap_create_pools(heap->uncached_pools))
 		goto err_create_uncached_pools;
 
-	if (ion_system_heap_create_pools(heap->cached_pools, true))
+	if (ion_system_heap_create_pools(heap->cached_pools))
 		goto err_create_cached_pools;
 
 	heap->heap.shrinker.shrink = ion_system_heap_shrink;
diff --git a/drivers/gpu/ion/msm/msm_ion.c b/drivers/gpu/ion/msm/msm_ion.c
index cdd31e1..a6fc3d5 100644
--- a/drivers/gpu/ion/msm/msm_ion.c
+++ b/drivers/gpu/ion/msm/msm_ion.c
@@ -973,7 +973,7 @@
 					sizeof(struct ion_flush_data)))
 			return -EFAULT;
 
-		if (data.handle >= 0) {
+		if (data.handle > 0) {
 			handle = ion_handle_get_by_id(client, (int)data.handle);
 			if (IS_ERR(handle)) {
 				pr_info("%s: Could not find handle: %d\n",
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index eba60ea..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,18 +1198,22 @@
 	 * 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
 	 * after the command has been retired
 	 */
 	if (result)
-		kgsl_mmu_disable_clk_on_ts(&device->mmu, 0, false);
+		kgsl_mmu_disable_clk(&device->mmu,
+						KGSL_IOMMU_CONTEXT_USER);
 	else
-		kgsl_mmu_disable_clk_on_ts(&device->mmu, rb->global_ts, true);
+		kgsl_mmu_disable_clk_on_ts(&device->mmu, rb->global_ts,
+						KGSL_IOMMU_CONTEXT_USER);
 
 done:
+	kfree(link);
 	kgsl_context_put(context);
 	return result;
 }
@@ -1623,17 +1627,19 @@
 			goto err;
 		}
 
-		ret = of_property_read_u32_array(child, "reg", reg_val, 2);
-		if (ret) {
-			KGSL_CORE_ERR("Unable to read KGSL IOMMU 'reg'\n");
+		if (!strcmp("gfx3d_user", ctxs[ctx_index].iommu_ctx_name)) {
+			ctxs[ctx_index].ctx_id = 0;
+		} else if (!strcmp("gfx3d_priv",
+					ctxs[ctx_index].iommu_ctx_name)) {
+			ctxs[ctx_index].ctx_id = 1;
+		} else if (!strcmp("gfx3d_spare",
+					ctxs[ctx_index].iommu_ctx_name)) {
+			ctxs[ctx_index].ctx_id = 2;
+		} else {
+			KGSL_CORE_ERR("dt: IOMMU context %s is invalid\n",
+				ctxs[ctx_index].iommu_ctx_name);
 			goto err;
 		}
-		if (msm_soc_version_supports_iommu_v0())
-			ctxs[ctx_index].ctx_id = (reg_val[0] -
-				data->physstart) >> KGSL_IOMMU_CTX_SHIFT;
-		else
-			ctxs[ctx_index].ctx_id = ((reg_val[0] -
-				data->physstart) >> KGSL_IOMMU_CTX_SHIFT) - 8;
 
 		ctx_index++;
 	}
@@ -1688,6 +1694,12 @@
 	if (ret)
 		goto err;
 
+	/* get pm-qos-latency from target, set it to default if not found */
+	if (adreno_of_read_property(pdev->dev.of_node, "qcom,pm-qos-latency",
+		&pdata->pm_qos_latency))
+		pdata->pm_qos_latency = 501;
+
+
 	if (adreno_of_read_property(pdev->dev.of_node, "qcom,idle-timeout",
 		&pdata->idle_timeout))
 		pdata->idle_timeout = HZ/12;
@@ -1950,6 +1962,10 @@
 	for (i = 6; i < FT_DETECT_REGS_COUNT; i++)
 		ft_detect_regs[i] = 0;
 
+	/* turn on hang interrupt for a330v2 by default */
+	if (adreno_is_a330v2(adreno_dev))
+		set_bit(ADRENO_DEVICE_HANG_INTR, &adreno_dev->priv);
+
 	ret = adreno_perfcounter_init(device);
 	if (ret)
 		goto done;
@@ -2089,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
@@ -2109,7 +2125,7 @@
 		_status = _adreno_start(adreno_dev);
 	else
 		_status = 0;
-	mutex_unlock(&device->mutex);
+	kgsl_mutex_unlock(&device->mutex, &device->mutex_owner);
 }
 
 /**
@@ -2134,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;
 }
@@ -2336,15 +2352,33 @@
 				     const char *buf, size_t count)
 {
 	struct adreno_device *adreno_dev = _get_adreno_dev(dev);
-	int ret;
+	int ret = 0;
+	unsigned int policy = 0;
 	if (adreno_dev == NULL)
 		return 0;
 
 	mutex_lock(&adreno_dev->dev.mutex);
-	ret = _ft_sysfs_store(buf, count, &adreno_dev->ft_pf_policy);
+
+	/* MMU option changed call function to reset MMU options */
+	if (count != _ft_sysfs_store(buf, count, &policy))
+		ret = -EINVAL;
+
+	if (!ret) {
+		policy &= (KGSL_FT_PAGEFAULT_INT_ENABLE |
+				KGSL_FT_PAGEFAULT_GPUHALT_ENABLE |
+				KGSL_FT_PAGEFAULT_LOG_ONE_PER_PAGE |
+				KGSL_FT_PAGEFAULT_LOG_ONE_PER_INT);
+		ret = kgsl_mmu_set_pagefault_policy(&(adreno_dev->dev.mmu),
+				adreno_dev->ft_pf_policy);
+		if (!ret)
+			adreno_dev->ft_pf_policy = policy;
+	}
 	mutex_unlock(&adreno_dev->dev.mutex);
 
-	return ret;
+	if (!ret)
+		return count;
+	else
+		return 0;
 }
 
 /**
@@ -2395,9 +2429,12 @@
 
 	if (tmp != adreno_dev->fast_hang_detect) {
 		if (adreno_dev->fast_hang_detect) {
-			if (adreno_dev->gpudev->fault_detect_start)
+			if (adreno_dev->gpudev->fault_detect_start &&
+				!kgsl_active_count_get(&adreno_dev->dev)) {
 				adreno_dev->gpudev->fault_detect_start(
 					adreno_dev);
+				kgsl_active_count_put(&adreno_dev->dev);
+			}
 		} else {
 			if (adreno_dev->gpudev->fault_detect_stop)
 				adreno_dev->gpudev->fault_detect_stop(
@@ -2506,6 +2543,88 @@
 	return snprintf(buf, PAGE_SIZE, "%d\n", _wake_timeout);
 }
 
+/**
+ * _ft_hang_intr_status_store -  Routine to enable/disable h/w hang interrupt
+ * @dev: device ptr
+ * @attr: Device attribute
+ * @buf: value to write
+ * @count: size of the value to write
+ */
+static ssize_t _ft_hang_intr_status_store(struct device *dev,
+				struct device_attribute *attr,
+				const char *buf, size_t count)
+{
+	unsigned int new_setting, old_setting;
+	struct kgsl_device *device = kgsl_device_from_dev(dev);
+	struct adreno_device *adreno_dev;
+	int ret;
+	if (device == NULL)
+		return 0;
+	adreno_dev = ADRENO_DEVICE(device);
+
+	mutex_lock(&device->mutex);
+	ret = _ft_sysfs_store(buf, count, &new_setting);
+	if (ret != count)
+		goto done;
+	if (new_setting)
+		new_setting = 1;
+	old_setting =
+		(test_bit(ADRENO_DEVICE_HANG_INTR, &adreno_dev->priv) ? 1 : 0);
+	if (new_setting != old_setting) {
+		if (new_setting)
+			set_bit(ADRENO_DEVICE_HANG_INTR, &adreno_dev->priv);
+		else
+			clear_bit(ADRENO_DEVICE_HANG_INTR, &adreno_dev->priv);
+		/* Set the new setting based on device state */
+		switch (device->state) {
+		case KGSL_STATE_NAP:
+		case KGSL_STATE_SLEEP:
+			kgsl_pwrctrl_wake(device, 0);
+		case KGSL_STATE_ACTIVE:
+			adreno_dev->gpudev->irq_control(adreno_dev, 1);
+		/*
+		 * For following states setting will be picked up on device
+		 * start. Still need them in switch statement to differentiate
+		 * from default
+		 */
+		case KGSL_STATE_SLUMBER:
+		case KGSL_STATE_SUSPEND:
+			break;
+		default:
+			ret = -EACCES;
+			/* reset back to old setting on error */
+			if (new_setting)
+				clear_bit(ADRENO_DEVICE_HANG_INTR,
+					&adreno_dev->priv);
+			else
+				set_bit(ADRENO_DEVICE_HANG_INTR,
+					&adreno_dev->priv);
+			goto done;
+		}
+	}
+done:
+	mutex_unlock(&device->mutex);
+	return ret;
+}
+
+/**
+ * _ft_hang_intr_status_show() -  Routine to read hardware hang interrupt
+ * enablement
+ * @dev: device ptr
+ * @attr: Device attribute
+ * @buf: value read
+ */
+static ssize_t _ft_hang_intr_status_show(struct device *dev,
+					struct device_attribute *attr,
+					char *buf)
+{
+	struct adreno_device *adreno_dev = _get_adreno_dev(dev);
+	if (adreno_dev == NULL)
+		return 0;
+	return snprintf(buf, PAGE_SIZE, "%d\n",
+		test_bit(ADRENO_DEVICE_HANG_INTR, &adreno_dev->priv) ? 1 : 0);
+}
+
 #define FT_DEVICE_ATTR(name) \
 	DEVICE_ATTR(name, 0644,	_ ## name ## _show, _ ## name ## _store);
 
@@ -2513,6 +2632,7 @@
 FT_DEVICE_ATTR(ft_pagefault_policy);
 FT_DEVICE_ATTR(ft_fast_hang_detect);
 FT_DEVICE_ATTR(ft_long_ib_detect);
+FT_DEVICE_ATTR(ft_hang_intr_status);
 
 static DEVICE_INT_ATTR(wake_nice, 0644, _wake_nice);
 static FT_DEVICE_ATTR(wake_timeout);
@@ -2524,6 +2644,7 @@
 	&dev_attr_ft_long_ib_detect,
 	&dev_attr_wake_nice.attr,
 	&dev_attr_wake_timeout,
+	&dev_attr_ft_hang_intr_status,
 	NULL,
 };
 
@@ -2635,12 +2756,56 @@
 	return status;
 }
 
-static int adreno_setproperty(struct kgsl_device *device,
+static int adreno_set_constraint(struct kgsl_device *device,
+				struct kgsl_context *context,
+				struct kgsl_device_constraint *constraint)
+{
+	int status = 0;
+
+	switch (constraint->type) {
+	case KGSL_CONSTRAINT_PWRLEVEL: {
+		struct kgsl_device_constraint_pwrlevel pwr;
+
+		if (constraint->size != sizeof(pwr)) {
+			status = -EINVAL;
+			break;
+		}
+
+		if (copy_from_user(&pwr,
+				(void __user *)constraint->data,
+				sizeof(pwr))) {
+			status = -EFAULT;
+			break;
+		}
+		if (pwr.level >= KGSL_CONSTRAINT_PWR_MAXLEVELS) {
+			status = -EINVAL;
+			break;
+		}
+
+		context->pwr_constraint.type =
+				KGSL_CONSTRAINT_PWRLEVEL;
+		context->pwr_constraint.sub_type = pwr.level;
+		}
+		break;
+	case KGSL_CONSTRAINT_NONE:
+		context->pwr_constraint.type = KGSL_CONSTRAINT_NONE;
+		break;
+
+	default:
+		status = -EINVAL;
+		break;
+	}
+
+	return status;
+}
+
+static int adreno_setproperty(struct kgsl_device_private *dev_priv,
 				enum kgsl_property_type type,
 				void *value,
 				unsigned int sizebytes)
 {
 	int status = -EINVAL;
+	struct kgsl_device *device = dev_priv->device;
 	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
 
 	switch (type) {
@@ -2678,6 +2843,28 @@
 			status = 0;
 		}
 		break;
+	case KGSL_PROP_PWR_CONSTRAINT: {
+			struct kgsl_device_constraint constraint;
+			struct kgsl_context *context;
+
+			if (sizebytes != sizeof(constraint))
+				break;
+
+			if (copy_from_user(&constraint, value,
+				sizeof(constraint))) {
+				status = -EFAULT;
+				break;
+			}
+
+			context = kgsl_context_get_owner(dev_priv,
+							constraint.context_id);
+			if (context == NULL)
+				break;
+			status = adreno_set_constraint(device, context,
+								&constraint);
+			kgsl_context_put(context);
+		}
+		break;
 	default:
 		break;
 	}
@@ -2692,7 +2879,7 @@
  * Return true if the RBBM status register for the GPU type indicates that the
  * hardware is idle
  */
-static bool adreno_hw_isidle(struct kgsl_device *device)
+bool adreno_hw_isidle(struct kgsl_device *device)
 {
 	unsigned int reg_rbbm_status;
 	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
@@ -2805,6 +2992,12 @@
 
 	rptr = adreno_get_rptr(&adreno_dev->ringbuffer);
 
+	/*
+	 * wptr is updated when we add commands to ringbuffer, add a barrier
+	 * to make sure updated wptr is compared to rptr
+	 */
+	smp_mb();
+
 	if (rptr == adreno_dev->ringbuffer.wptr)
 		return adreno_hw_isidle(device);
 
@@ -3069,7 +3262,7 @@
 		return -EINVAL;
 
 	ret = adreno_drawctxt_wait(ADRENO_DEVICE(device), context,
-		timestamp, msecs_to_jiffies(msecs));
+		timestamp, msecs);
 
 	/* If the context got invalidated then return a specific error */
 	drawctxt = ADRENO_CONTEXT(context);
diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h
index 800caf1..3d9206b 100644
--- a/drivers/gpu/msm/adreno.h
+++ b/drivers/gpu/msm/adreno.h
@@ -20,6 +20,8 @@
 #include "kgsl_iommu.h"
 #include <mach/ocmem.h>
 
+#include "a3xx_reg.h"
+
 #define DEVICE_3D_NAME "kgsl-3d"
 #define DEVICE_3D0_NAME "kgsl-3d0"
 
@@ -189,8 +191,6 @@
 	unsigned int fast_hang_detect;
 	unsigned int ft_policy;
 	unsigned int long_ib_detect;
-	unsigned int long_ib;
-	unsigned int long_ib_ts;
 	unsigned int ft_pf_policy;
 	unsigned int gpulist_index;
 	struct ocmem_buf *ocmem_hdl;
@@ -217,6 +217,7 @@
 	ADRENO_DEVICE_PWRON_FIXUP = 1,
 	ADRENO_DEVICE_INITIALIZED = 2,
 	ADRENO_DEVICE_STARTED = 3,
+	ADRENO_DEVICE_HANG_INTR = 4,
 };
 
 #define PERFCOUNTER_FLAG_NONE 0x0
@@ -341,6 +342,7 @@
 	ADRENO_REG_TC_CNTL_STATUS,
 	ADRENO_REG_TP0_CHICKEN,
 	ADRENO_REG_RBBM_RBBM_CTL,
+	ADRENO_REG_UCHE_INVALIDATE0,
 	ADRENO_REG_REGISTER_MAX,
 };
 
@@ -413,7 +415,10 @@
 #define  KGSL_FT_SKIPFRAME                3
 #define  KGSL_FT_DISABLE                  4
 #define  KGSL_FT_TEMP_DISABLE             5
-#define  KGSL_FT_DEFAULT_POLICY (BIT(KGSL_FT_REPLAY) + BIT(KGSL_FT_SKIPIB))
+#define  KGSL_FT_THROTTLE                 6
+#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 */
 #define  KGSL_FT_SKIP_PMDUMP              31
@@ -431,7 +436,9 @@
 	{ BIT(KGSL_FT_SKIPIB), "skipib" }, \
 	{ BIT(KGSL_FT_SKIPFRAME), "skipframe" }, \
 	{ BIT(KGSL_FT_DISABLE), "disable" }, \
-	{ BIT(KGSL_FT_TEMP_DISABLE), "temp" }
+	{ BIT(KGSL_FT_TEMP_DISABLE), "temp" }, \
+	{ BIT(KGSL_FT_THROTTLE), "throttle"}, \
+	{ BIT(KGSL_FT_SKIPCMD), "skipcmd" }
 
 extern struct adreno_gpudev adreno_a2xx_gpudev;
 extern struct adreno_gpudev adreno_a3xx_gpudev;
@@ -461,6 +468,7 @@
 void adreno_coresight_remove(struct platform_device *pdev);
 int adreno_coresight_init(struct platform_device *pdev);
 
+bool adreno_hw_isidle(struct kgsl_device *device);
 int adreno_idle(struct kgsl_device *device);
 bool adreno_isidle(struct kgsl_device *device);
 
@@ -510,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);
 
@@ -712,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;
 }
@@ -895,4 +912,48 @@
 	return result;
 }
 
+/*
+ * adreno_set_protected_registers() - Protect the specified range of registers
+ * from being accessed by the GPU
+ * @device: pointer to the KGSL device
+ * @index: Pointer to the index of the protect mode register to write to
+ * @reg: Starting dword register to write
+ * @mask_len: Size of the mask to protect (# of registers = 2 ** mask_len)
+ *
+ * Add the range of registers to the list of protected mode registers that will
+ * cause an exception if the GPU accesses them.  There are 16 available
+ * protected mode registers.  Index is used to specify which register to write
+ * to - the intent is to call this function multiple times with the same index
+ * pointer for each range and the registers will be magically programmed in
+ * incremental fashion
+ */
+static inline void adreno_set_protected_registers(struct kgsl_device *device,
+	unsigned int *index, unsigned int reg, int mask_len)
+{
+	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+	unsigned int val;
+
+	/* This function is only for adreno A3XX and beyond */
+	BUG_ON(adreno_is_a2xx(adreno_dev));
+
+	/* There are only 16 registers available */
+	BUG_ON(*index >= 16);
+
+	val = 0x60000000 | ((mask_len & 0x1F) << 24) | ((reg << 2) & 0x1FFFF);
+
+	/*
+	 * Write the protection range to the next available protection
+	 * register
+	 */
+
+	kgsl_regwrite(device, A3XX_CP_PROTECT_REG_0 + *index, val);
+	*index = *index + 1;
+}
+
+#ifdef CONFIG_DEBUG_FS
+void adreno_debugfs_init(struct kgsl_device *device);
+#else
+static inline void adreno_debugfs_init(struct kgsl_device *device) { }
+#endif
+
 #endif /*__ADRENO_H */
diff --git a/drivers/gpu/msm/adreno_a3xx.c b/drivers/gpu/msm/adreno_a3xx.c
index 3d4c66a..2025d73 100644
--- a/drivers/gpu/msm/adreno_a3xx.c
+++ b/drivers/gpu/msm/adreno_a3xx.c
@@ -3029,8 +3029,8 @@
 	GSL_RB_WRITE(rb->device, cmds, cmds_gpu, 0x00000001);
 	GSL_RB_WRITE(rb->device, cmds, cmds_gpu, 0x00000000);
 	GSL_RB_WRITE(rb->device, cmds, cmds_gpu, 0x00000000);
-	/* Protected mode control - turned off for A3XX */
-	GSL_RB_WRITE(rb->device, cmds, cmds_gpu, 0x00000000);
+	/* Enable protected mode */
+	GSL_RB_WRITE(rb->device, cmds, cmds_gpu, 0x20000000);
 	GSL_RB_WRITE(rb->device, cmds, cmds_gpu, 0x00000000);
 	GSL_RB_WRITE(rb->device, cmds, cmds_gpu, 0x00000000);
 
@@ -3039,6 +3039,25 @@
 	return 0;
 }
 
+static void a3xx_fatal_err_callback(struct adreno_device *adreno_dev, int bit)
+{
+	struct kgsl_device *device = &adreno_dev->dev;
+	const char *err = "";
+
+	switch (bit) {
+	case A3XX_INT_MISC_HANG_DETECT:
+		err = "MISC: GPU hang detected\n";
+		break;
+	default:
+		return;
+	}
+	KGSL_DRV_CRIT(device, "%s\n", err);
+	kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_OFF);
+
+	/* Trigger a fault in the dispatcher - this will effect a restart */
+	adreno_dispatcher_irq_fault(device);
+}
+
 static void a3xx_err_callback(struct adreno_device *adreno_dev, int bit)
 {
 	struct kgsl_device *device = &adreno_dev->dev;
@@ -3063,7 +3082,7 @@
 
 		/* Clear the error */
 		kgsl_regwrite(device, A3XX_RBBM_AHB_CMD, (1 << 3));
-		goto done;
+		return;
 	}
 	case A3XX_INT_RBBM_REG_TIMEOUT:
 		err = "RBBM: AHB register timeout";
@@ -3092,15 +3111,18 @@
 	case A3XX_INT_CP_HW_FAULT:
 		err = "ringbuffer hardware fault";
 		break;
-	case A3XX_INT_CP_REG_PROTECT_FAULT:
-		err = "ringbuffer protected mode error interrupt";
-		break;
+	case A3XX_INT_CP_REG_PROTECT_FAULT: {
+		unsigned int reg;
+		kgsl_regread(device, A3XX_CP_PROTECT_STATUS, &reg);
+
+		KGSL_DRV_CRIT(device,
+			"CP | Protected mode error| %s | addr=%x\n",
+			reg & (1 << 24) ? "WRITE" : "READ",
+			(reg & 0x1FFFF) >> 2);
+	}
 	case A3XX_INT_CP_AHB_ERROR_HALT:
 		err = "ringbuffer AHB error interrupt";
 		break;
-	case A3XX_INT_MISC_HANG_DETECT:
-		err = "MISC: GPU hang detected";
-		break;
 	case A3XX_INT_UCHE_OOB_ACCESS:
 		err = "UCHE:  Out of bounds access";
 		break;
@@ -3108,11 +3130,6 @@
 		return;
 	}
 	KGSL_DRV_CRIT(device, "%s\n", err);
-	kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_OFF);
-
-done:
-	/* Trigger a fault in the dispatcher - this will effect a restart */
-	adreno_dispatcher_irq_fault(device);
 }
 
 static void a3xx_cp_callback(struct adreno_device *adreno_dev, int irq)
@@ -3554,7 +3571,7 @@
 	A3XX_IRQ_CALLBACK(a3xx_err_callback),  /* 21 - CP_AHB_ERROR_FAULT */
 	A3XX_IRQ_CALLBACK(NULL),	       /* 22 - Unused */
 	A3XX_IRQ_CALLBACK(NULL),	       /* 23 - Unused */
-	A3XX_IRQ_CALLBACK(NULL),	       /* 24 - MISC_HANG_DETECT */
+	A3XX_IRQ_CALLBACK(a3xx_fatal_err_callback),/* 24 - MISC_HANG_DETECT */
 	A3XX_IRQ_CALLBACK(a3xx_err_callback),  /* 25 - UCHE_OOB_ACCESS */
 	/* 26 to 31 - Unused */
 };
@@ -3595,7 +3612,9 @@
 	struct kgsl_device *device = &adreno_dev->dev;
 
 	if (state)
-		kgsl_regwrite(device, A3XX_RBBM_INT_0_MASK, A3XX_INT_MASK);
+		kgsl_regwrite(device, A3XX_RBBM_INT_0_MASK, A3XX_INT_MASK |
+			(test_bit(ADRENO_DEVICE_HANG_INTR, &adreno_dev->priv) ?
+				(1 << A3XX_INT_MISC_HANG_DETECT) : 0));
 	else
 		kgsl_regwrite(device, A3XX_RBBM_INT_0_MASK, 0);
 }
@@ -4115,29 +4134,36 @@
  */
 static void a3xx_protect_init(struct kgsl_device *device)
 {
+	int index = 0;
+
 	/* enable access protection to privileged registers */
 	kgsl_regwrite(device, A3XX_CP_PROTECT_CTRL, 0x00000007);
 
 	/* RBBM registers */
-	kgsl_regwrite(device, A3XX_CP_PROTECT_REG_0, 0x63000040);
-	kgsl_regwrite(device, A3XX_CP_PROTECT_REG_1, 0x62000080);
-	kgsl_regwrite(device, A3XX_CP_PROTECT_REG_2, 0x600000CC);
-	kgsl_regwrite(device, A3XX_CP_PROTECT_REG_3, 0x60000108);
-	kgsl_regwrite(device, A3XX_CP_PROTECT_REG_4, 0x64000140);
-	kgsl_regwrite(device, A3XX_CP_PROTECT_REG_5, 0x66000400);
+	adreno_set_protected_registers(device, &index, 0x18, 0);
+	adreno_set_protected_registers(device, &index, 0x20, 2);
+	adreno_set_protected_registers(device, &index, 0x33, 0);
+	adreno_set_protected_registers(device, &index, 0x42, 0);
+	adreno_set_protected_registers(device, &index, 0x50, 4);
+	adreno_set_protected_registers(device, &index, 0x63, 0);
+	adreno_set_protected_registers(device, &index, 0x100, 4);
 
 	/* CP registers */
-	kgsl_regwrite(device, A3XX_CP_PROTECT_REG_6, 0x65000700);
-	kgsl_regwrite(device, A3XX_CP_PROTECT_REG_7, 0x610007D8);
-	kgsl_regwrite(device, A3XX_CP_PROTECT_REG_8, 0x620007E0);
-	kgsl_regwrite(device, A3XX_CP_PROTECT_REG_9, 0x61001178);
-	kgsl_regwrite(device, A3XX_CP_PROTECT_REG_A, 0x64001180);
+	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);
+	adreno_set_protected_registers(device, &index, 0x460, 4);
 
 	/* RB registers */
-	kgsl_regwrite(device, A3XX_CP_PROTECT_REG_B, 0x60003300);
+	adreno_set_protected_registers(device, &index, 0xCC0, 0);
 
 	/* VBIF registers */
-	kgsl_regwrite(device, A3XX_CP_PROTECT_REG_C, 0x6B00C000);
+	adreno_set_protected_registers(device, &index, 0x3000, 6);
+
+	/* SMMU registers */
+	adreno_set_protected_registers(device, &index, 0x4000, 14);
 }
 
 static void a3xx_start(struct adreno_device *adreno_dev)
@@ -4180,9 +4206,12 @@
 
 	/* Turn on hang detection - this spews a lot of useful information
 	 * into the RBBM registers on a hang */
-
-	kgsl_regwrite(device, A3XX_RBBM_INTERFACE_HANG_INT_CTL,
-			(1 << 16) | 0xFFF);
+	if (adreno_is_a330v2(adreno_dev))
+		kgsl_regwrite(device, A3XX_RBBM_INTERFACE_HANG_INT_CTL,
+				(1 << 31) | 0xFFFF);
+	else
+		kgsl_regwrite(device, A3XX_RBBM_INTERFACE_HANG_INT_CTL,
+				(1 << 16) | 0xFFF);
 
 	/* Enable 64-byte cacheline size. HW Default is 32-byte (0x000000E0). */
 	kgsl_regwrite(device, A3XX_UCHE_CACHE_MODE_CONTROL_REG, 0x00000001);
@@ -4222,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,
@@ -4243,7 +4272,7 @@
 				0x00000001);
 		kgsl_active_count_put(device);
 	}
-	mutex_unlock(&device->mutex);
+	kgsl_mutex_unlock(&device->mutex, &device->mutex_owner);
 	return 0;
 }
 
@@ -4254,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);
@@ -4267,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,
@@ -4564,6 +4593,8 @@
 	ADRENO_REG_DEFINE(ADRENO_REG_TC_CNTL_STATUS, REG_TC_CNTL_STATUS),
 	ADRENO_REG_DEFINE(ADRENO_REG_TP0_CHICKEN, REG_TP0_CHICKEN),
 	ADRENO_REG_DEFINE(ADRENO_REG_RBBM_RBBM_CTL, A3XX_RBBM_RBBM_CTL),
+	ADRENO_REG_DEFINE(ADRENO_REG_UCHE_INVALIDATE0,
+			A3XX_UCHE_CACHE_INVALIDATE0_REG),
 };
 
 struct adreno_reg_offsets a3xx_reg_offsets = {
diff --git a/drivers/gpu/msm/adreno_a3xx_snapshot.c b/drivers/gpu/msm/adreno_a3xx_snapshot.c
index 56c4305..9f5765d 100644
--- a/drivers/gpu/msm/adreno_a3xx_snapshot.c
+++ b/drivers/gpu/msm/adreno_a3xx_snapshot.c
@@ -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
@@ -492,6 +492,22 @@
 	/* Reading these will hang the GPU if it isn't already hung */
 
 	if (hang) {
+		unsigned int reg;
+
+		/*
+		 * Reading the microcode while the CP will is running will
+		 * basically basically move the CP instruction pointer to
+		 * whatever address we read. Big badaboom ensues. Stop the CP
+		 * (if it isn't already stopped) to ensure that we are safe.
+		 * We do this here and not earlier to avoid corrupting the RBBM
+		 * status and CP registers - by the time we get here we don't
+		 * care about the contents of the CP anymore.
+		 */
+
+		adreno_readreg(adreno_dev, ADRENO_REG_CP_ME_CNTL, &reg);
+		reg |= (1 << 27) | (1 << 28);
+		adreno_writereg(adreno_dev, ADRENO_REG_CP_ME_CNTL, reg);
+
 		snapshot = kgsl_snapshot_add_section(device,
 			KGSL_SNAPSHOT_SECTION_DEBUG, snapshot, remain,
 			a3xx_snapshot_cp_pfp_ram, NULL);
diff --git a/drivers/gpu/msm/adreno_coresight.c b/drivers/gpu/msm/adreno_coresight.c
index 1b827ff..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
@@ -55,7 +55,12 @@
 int adreno_coresight_enable(struct coresight_device *csdev)
 {
 	struct kgsl_device *device = dev_get_drvdata(csdev->dev.parent);
-	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+	struct adreno_device *adreno_dev;
+
+	if (device == NULL)
+		return -ENODEV;
+
+	adreno_dev = ADRENO_DEVICE(device);
 
 	/* Check if coresight compatible device, return error otherwise */
 	if (adreno_dev->gpudev->coresight_enable)
@@ -80,7 +85,12 @@
 void adreno_coresight_disable(struct coresight_device *csdev)
 {
 	struct kgsl_device *device = dev_get_drvdata(csdev->dev.parent);
-	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+	struct adreno_device *adreno_dev;
+
+	if (device == NULL)
+		return;
+
+	adreno_dev = ADRENO_DEVICE(device);
 
 	/* Check if coresight compatible device, bail otherwise */
 	if (adreno_dev->gpudev->coresight_disable)
@@ -107,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);
 }
 
@@ -134,6 +144,10 @@
 	struct kgsl_device *device = dev_get_drvdata(dev->parent);
 	struct coresight_attr *csight_attr = container_of(attr,
 			struct coresight_attr, attr);
+
+	if (device == NULL)
+		return -ENODEV;
+
 	return coresight_read_reg(device, csight_attr->regname, buf);
 }
 
@@ -142,11 +156,16 @@
 		const char *buf, size_t size)
 {
 	struct kgsl_device *device = dev_get_drvdata(dev->parent);
-	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+	struct adreno_device *adreno_dev;
 	struct coresight_attr *csight_attr = container_of(attr,
 			struct coresight_attr, attr);
 	unsigned int regval = 0;
 
+	if (device == NULL)
+		return -ENODEV;
+
+	adreno_dev = ADRENO_DEVICE(device);
+
 	regval = coresight_convert_reg(buf);
 
 	if (adreno_dev->gpudev->coresight_config_debug_reg)
diff --git a/drivers/gpu/msm/adreno_dispatch.c b/drivers/gpu/msm/adreno_dispatch.c
index 2da36b6..588c243 100644
--- a/drivers/gpu/msm/adreno_dispatch.c
+++ b/drivers/gpu/msm/adreno_dispatch.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
@@ -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))
 
@@ -33,6 +34,15 @@
 /* Number of command batches sent at a time from a single context */
 static unsigned int _context_cmdbatch_burst = 5;
 
+/*
+ * GFT throttle parameters. If GFT recovered more than
+ * X times in Y ms invalidate the context and do not attempt recovery.
+ * X -> _fault_throttle_burst
+ * Y -> _fault_throttle_time
+ */
+static unsigned int _fault_throttle_time = 3000;
+static unsigned int _fault_throttle_burst = 3;
+
 /* Number of command batches inflight in the ringbuffer at any time */
 static unsigned int _dispatcher_inflight = 15;
 
@@ -40,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];
@@ -78,15 +88,24 @@
 static inline bool _isidle(struct kgsl_device *device)
 {
 	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
-	unsigned int ts;
+	unsigned int ts, i;
+
+	if (!kgsl_pwrctrl_isenabled(device))
+		goto ret;
 
 	ts = kgsl_readtimestamp(device, NULL, KGSL_TIMESTAMP_RETIRED);
 
-	if (adreno_isidle(device) == true &&
-		(ts >= adreno_dev->ringbuffer.global_ts))
-		return true;
+	/* If GPU HW status is idle return true */
+	if (adreno_hw_isidle(device) ||
+			(ts == adreno_dev->ringbuffer.global_ts))
+		goto ret;
 
 	return false;
+
+ret:
+	for (i = 0; i < FT_DETECT_REGS_COUNT; i++)
+		fault_detect_regs[i] = 0;
+	return true;
 }
 
 /**
@@ -251,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)) {
@@ -259,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;
 		}
 
@@ -282,7 +301,7 @@
 		}
 	}
 
-	mutex_unlock(&device->mutex);
+	kgsl_mutex_unlock(&device->mutex, &device->mutex_owner);
 
 	if (ret) {
 		dispatcher->inflight--;
@@ -397,7 +416,7 @@
 	 */
 
 	if (count)
-		wake_up_interruptible_all(&drawctxt->wq);
+		wake_up_all(&drawctxt->wq);
 
 	/*
 	 * Return positive if the context submitted commands or if we figured
@@ -752,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;
 
@@ -765,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)
 {
@@ -834,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);
 		}
@@ -907,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);
@@ -929,6 +1003,12 @@
 	if (dispatcher->inflight == 0) {
 		KGSL_DRV_WARN(device,
 		"dispatcher_do_fault with 0 inflight commands\n");
+		/*
+		 * For certain faults like h/w fault the interrupts are
+		 * turned off, re-enable here
+		 */
+		if (kgsl_pwrctrl_isenabled(device))
+			kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_ON);
 		return 0;
 	}
 
@@ -936,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];
 
@@ -951,9 +1031,6 @@
 		adreno_readreg(adreno_dev, ADRENO_REG_CP_ME_CNTL, &reg);
 		reg |= (1 << 27) | (1 << 28);
 		adreno_writereg(adreno_dev, ADRENO_REG_CP_ME_CNTL, reg);
-
-		/* Skip the PM dump for a timeout because it confuses people */
-		set_bit(KGSL_FT_SKIP_PMDUMP, &cmdbatch->fault_policy);
 	}
 
 	adreno_readreg(adreno_dev, ADRENO_REG_CP_IB1_BASE, &base);
@@ -972,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);
@@ -1018,6 +1095,35 @@
 	cmdbatch = replay[0];
 
 	/*
+	 * If GFT recovered more than X times in Y ms invalidate the context
+	 * and do not attempt recovery.
+	 * Example: X==3 and Y==3000 ms, GPU hung at 500ms, 1700ms, 25000ms and
+	 * 3000ms for the same context, we will not try FT and invalidate the
+	 * context @3000ms because context triggered GFT more than 3 times in
+	 * last 3 seconds. If a context caused recoverable GPU hangs
+	 * where 1st and 4th gpu hang are more than 3 seconds apart we
+	 * won't disable GFT and invalidate the context.
+	 */
+	if (test_bit(KGSL_FT_THROTTLE, &cmdbatch->fault_policy)) {
+		if (time_after(jiffies, (cmdbatch->context->fault_time
+				+ msecs_to_jiffies(_fault_throttle_time)))) {
+			cmdbatch->context->fault_time = jiffies;
+			cmdbatch->context->fault_count = 1;
+		} else {
+			cmdbatch->context->fault_count++;
+			if (cmdbatch->context->fault_count >
+					_fault_throttle_burst) {
+				set_bit(KGSL_FT_DISABLE,
+						&cmdbatch->fault_policy);
+				pr_fault(device, cmdbatch,
+					 "gpu fault threshold exceeded %d faults in %d msecs\n",
+					 _fault_throttle_burst,
+					 _fault_throttle_time);
+			}
+		}
+	}
+
+	/*
 	 * If FT is disabled for this cmdbatch invalidate immediately
 	 */
 
@@ -1104,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));
@@ -1135,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);
 
@@ -1374,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 */
@@ -1393,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
@@ -1411,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);
 }
@@ -1625,6 +1741,10 @@
 static DISPATCHER_UINT_ATTR(context_queue_wait, 0644, 0, _context_queue_wait);
 static DISPATCHER_UINT_ATTR(fault_detect_interval, 0644, 0,
 	_fault_timer_interval);
+static DISPATCHER_UINT_ATTR(fault_throttle_time, 0644, 0,
+	_fault_throttle_time);
+static DISPATCHER_UINT_ATTR(fault_throttle_burst, 0644, 0,
+	_fault_throttle_burst);
 
 static struct attribute *dispatcher_attrs[] = {
 	&dispatcher_attr_inflight.attr,
@@ -1633,6 +1753,8 @@
 	&dispatcher_attr_cmdbatch_timeout.attr,
 	&dispatcher_attr_context_queue_wait.attr,
 	&dispatcher_attr_fault_detect_interval.attr,
+	&dispatcher_attr_fault_throttle_time.attr,
+	&dispatcher_attr_fault_throttle_burst.attr,
 	NULL,
 };
 
diff --git a/drivers/gpu/msm/adreno_drawctxt.c b/drivers/gpu/msm/adreno_drawctxt.c
index 6007a3f..0778cac 100644
--- a/drivers/gpu/msm/adreno_drawctxt.c
+++ b/drivers/gpu/msm/adreno_drawctxt.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2002,2007-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2002,2007-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
@@ -138,7 +138,7 @@
 		u32 timestamp, u32 type)
 {
 	struct adreno_context *drawctxt = priv;
-	wake_up_interruptible_all(&drawctxt->waiting);
+	wake_up_all(&drawctxt->waiting);
 }
 
 #define adreno_wait_event_interruptible_timeout(wq, condition, timeout, io)   \
@@ -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)
@@ -266,20 +266,18 @@
 {
 	struct adreno_context *drawctxt = priv;
 
-	wake_up_interruptible_all(&drawctxt->waiting);
+	wake_up_all(&drawctxt->waiting);
 	kgsl_context_put(&drawctxt->base);
 }
 
 static int _check_global_timestamp(struct kgsl_device *device,
-		unsigned int timestamp)
+		struct adreno_context *drawctxt, unsigned int timestamp)
 {
-	int ret;
+	/* Stop waiting if the context is invalidated */
+	if (drawctxt->state == ADRENO_CONTEXT_STATE_INVALID)
+		return 1;
 
-	mutex_lock(&device->mutex);
-	ret = kgsl_check_timestamp(device, NULL, timestamp);
-	mutex_unlock(&device->mutex);
-
-	return ret;
+	return kgsl_check_timestamp(device, NULL, timestamp);
 }
 
 int adreno_drawctxt_wait_global(struct adreno_device *adreno_dev,
@@ -288,7 +286,7 @@
 {
 	struct kgsl_device *device = &adreno_dev->dev;
 	struct adreno_context *drawctxt = ADRENO_CONTEXT(context);
-	int ret;
+	int ret = 0;
 
 	/* Needs to hold the device mutex */
 	BUG_ON(!mutex_is_locked(&device->mutex));
@@ -298,6 +296,15 @@
 		goto done;
 	}
 
+	/*
+	 * If the context is invalid then return immediately - we may end up
+	 * waiting for a timestamp that will never come
+	 */
+	if (drawctxt->state == ADRENO_CONTEXT_STATE_INVALID) {
+		kgsl_context_put(context);
+		goto done;
+	}
+
 	trace_adreno_drawctxt_wait_start(KGSL_MEMSTORE_GLOBAL, timestamp);
 
 	ret = kgsl_add_event(device, KGSL_MEMSTORE_GLOBAL, timestamp,
@@ -307,11 +314,11 @@
 		goto done;
 	}
 
-	mutex_unlock(&device->mutex);
+	kgsl_mutex_unlock(&device->mutex, &device->mutex_owner);
 
 	if (timeout) {
-		ret = (int) wait_event_interruptible_timeout(drawctxt->waiting,
-			_check_global_timestamp(device, timestamp),
+		ret = (int) wait_event_timeout(drawctxt->waiting,
+			_check_global_timestamp(device, drawctxt, timestamp),
 			msecs_to_jiffies(timeout));
 
 		if (ret == 0)
@@ -319,11 +326,11 @@
 		else if (ret > 0)
 			ret = 0;
 	} else {
-		ret = (int) wait_event_interruptible(drawctxt->waiting,
-			_check_global_timestamp(device, timestamp));
+		wait_event(drawctxt->waiting,
+			_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);
@@ -374,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);
@@ -386,8 +393,8 @@
 	mutex_unlock(&drawctxt->mutex);
 
 	/* Give the bad news to everybody waiting around */
-	wake_up_interruptible_all(&drawctxt->waiting);
-	wake_up_interruptible_all(&drawctxt->wq);
+	wake_up_all(&drawctxt->waiting);
+	wake_up_all(&drawctxt->wq);
 }
 
 /**
@@ -425,11 +432,13 @@
 		KGSL_CONTEXT_PER_CONTEXT_TS |
 		KGSL_CONTEXT_USER_GENERATED_TS |
 		KGSL_CONTEXT_NO_FAULT_TOLERANCE |
-		KGSL_CONTEXT_TYPE_MASK);
+		KGSL_CONTEXT_TYPE_MASK |
+		KGSL_CONTEXT_PWR_CONSTRAINT);
 
 	/* Always enable per-context timestamps */
 	drawctxt->base.flags |= KGSL_CONTEXT_PER_CONTEXT_TS;
-
+	drawctxt->type = (drawctxt->base.flags & KGSL_CONTEXT_TYPE_MASK)
+	>> KGSL_CONTEXT_TYPE_SHIFT;
 	mutex_init(&drawctxt->mutex);
 	init_waitqueue_head(&drawctxt->wq);
 	init_waitqueue_head(&drawctxt->waiting);
@@ -521,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
@@ -543,6 +559,14 @@
 	ret = adreno_drawctxt_wait_global(adreno_dev, context,
 		drawctxt->internal_timestamp, 10 * 1000);
 
+	/*
+	 * If the wait for global fails then nothing after this point is likely
+	 * to work very well - BUG_ON() so we can take advantage of the debug
+	 * tools to figure out what the h - e - double hockey sticks happened
+	 */
+
+	BUG_ON(ret);
+
 	kgsl_sharedmem_writel(device, &device->memstore,
 			KGSL_MEMSTORE_OFFSET(context->id, soptimestamp),
 			drawctxt->timestamp);
@@ -557,8 +581,8 @@
 		drawctxt->ops->detach(drawctxt);
 
 	/* wake threads waiting to submit commands from this context */
-	wake_up_interruptible_all(&drawctxt->waiting);
-	wake_up_interruptible_all(&drawctxt->wq);
+	wake_up_all(&drawctxt->waiting);
+	wake_up_all(&drawctxt->wq);
 
 	return ret;
 }
@@ -590,7 +614,7 @@
 				  struct adreno_context *context)
 {
 	struct kgsl_device *device;
-	unsigned int cmds[5];
+	unsigned int cmds[8];
 
 	if (adreno_dev == NULL || context == NULL)
 		return -EINVAL;
@@ -604,8 +628,14 @@
 	cmds[3] = device->memstore.gpuaddr +
 		KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL, current_context);
 	cmds[4] = context->base.id;
+	/* Flush the UCHE for new context */
+	cmds[5] = cp_type0_packet(
+		adreno_getreg(adreno_dev, ADRENO_REG_UCHE_INVALIDATE0), 2);
+	cmds[6] = 0;
+	if (adreno_is_a3xx(adreno_dev))
+		cmds[7] = 0x90000000;
 	return adreno_ringbuffer_issuecmds(device, context,
-				KGSL_CMD_FLAGS_NONE, cmds, 5);
+				KGSL_CMD_FLAGS_NONE, cmds, 8);
 }
 
 
diff --git a/drivers/gpu/msm/adreno_drawctxt.h b/drivers/gpu/msm/adreno_drawctxt.h
index 7656cd5..8543f39 100644
--- a/drivers/gpu/msm/adreno_drawctxt.h
+++ b/drivers/gpu/msm/adreno_drawctxt.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2002,2007-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2002,2007-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
@@ -130,10 +130,10 @@
  * @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;
-	unsigned int ib_gpu_time_used;
 	unsigned int timestamp;
 	unsigned int internal_timestamp;
 	int state;
@@ -178,6 +178,7 @@
 	int queued;
 
 	const struct adreno_context_ops *ops;
+	unsigned int fault_policy;
 };
 
 /**
@@ -193,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,
@@ -204,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 28fd6d6..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;
 }
@@ -1074,9 +1074,6 @@
 	 */
 	transfer_results(device, shared_buf_tail);
 
-	/* check for any cleanup */
-	check_close_profile(profile);
-
 	return 1;
 }
 
@@ -1106,7 +1103,7 @@
 	if (SIZE_SHARED_ENTRY(count) >= shared_buf_available(profile))
 		goto done;
 
-	if (entry_head + SIZE_SHARED_ENTRY(count) > profile->shared_size) {
+	if (entry_head + SIZE_SHARED_ENTRY(count) >= profile->shared_size) {
 		/* entry_head would wrap, start entry_head at 0 in buffer */
 		entry_head = 0;
 		profile->shared_size = profile->shared_head;
diff --git a/drivers/gpu/msm/adreno_ringbuffer.c b/drivers/gpu/msm/adreno_ringbuffer.c
index 1383a20..57d21f5 100644
--- a/drivers/gpu/msm/adreno_ringbuffer.c
+++ b/drivers/gpu/msm/adreno_ringbuffer.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2002,2007-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2002,2007-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
@@ -665,7 +665,8 @@
 	total_sizedwords += (flags & KGSL_CMD_FLAGS_INTERNAL_ISSUE) ? 2 : 0;
 
 	/* Add two dwords for the CP_INTERRUPT */
-	total_sizedwords += drawctxt ? 2 : 0;
+	total_sizedwords +=
+		(drawctxt || (flags & KGSL_CMD_FLAGS_INTERNAL_ISSUE)) ?  2 : 0;
 
 	if (adreno_is_a3xx(adreno_dev))
 		total_sizedwords += 7;
@@ -695,7 +696,7 @@
 
 	/* Add space for the power on shader fixup if we need it */
 	if (flags & KGSL_CMD_FLAGS_PWRON_FIXUP)
-		total_sizedwords += 5;
+		total_sizedwords += 9;
 
 	ringcmds = adreno_ringbuffer_allocspace(rb, drawctxt, total_sizedwords);
 
@@ -717,6 +718,11 @@
 	}
 
 	if (flags & KGSL_CMD_FLAGS_PWRON_FIXUP) {
+		/* Disable protected mode for the fixup */
+		GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu,
+			cp_type3_packet(CP_SET_PROTECTED_MODE, 1));
+		GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu, 0);
+
 		GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu, cp_nop_packet(1));
 		GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu,
 				KGSL_PWRON_FIXUP_IDENTIFIER);
@@ -726,6 +732,11 @@
 			adreno_dev->pwron_fixup.gpuaddr);
 		GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu,
 			adreno_dev->pwron_fixup_dwords);
+
+		/* Re-enable protected mode */
+		GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu,
+			cp_type3_packet(CP_SET_PROTECTED_MODE, 1));
+		GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu, 1);
 	}
 
 	/* Add any IB required for profiling if it is enabled */
@@ -1131,6 +1142,67 @@
 	return ret;
 }
 
+unsigned int adreno_ringbuffer_get_constraint(struct kgsl_device *device,
+				struct kgsl_context *context)
+{
+	unsigned int pwrlevel = device->pwrctrl.active_pwrlevel;
+
+	switch (context->pwr_constraint.type) {
+	case KGSL_CONSTRAINT_PWRLEVEL: {
+		switch (context->pwr_constraint.sub_type) {
+		case KGSL_CONSTRAINT_PWR_MAX:
+			pwrlevel = device->pwrctrl.max_pwrlevel;
+			break;
+		case KGSL_CONSTRAINT_PWR_MIN:
+			pwrlevel = device->pwrctrl.min_pwrlevel;
+			break;
+		default:
+			break;
+		}
+	}
+	break;
+
+	}
+
+	return pwrlevel;
+}
+
+void adreno_ringbuffer_set_constraint(struct kgsl_device *device,
+			struct kgsl_cmdbatch *cmdbatch)
+{
+	unsigned int constraint;
+	struct kgsl_context *context = cmdbatch->context;
+	/*
+	 * Check if the context has a constraint and constraint flags are
+	 * set.
+	 */
+	if (context->pwr_constraint.type &&
+		((context->flags & KGSL_CONTEXT_PWR_CONSTRAINT) ||
+			(cmdbatch->flags & KGSL_CONTEXT_PWR_CONSTRAINT))) {
+
+		constraint = adreno_ringbuffer_get_constraint(device, context);
+
+		/*
+		 * If a constraint is already set, set a new
+		 * constraint only if it is faster
+		 */
+		if ((device->pwrctrl.constraint.type ==
+			KGSL_CONSTRAINT_NONE) || (constraint <
+			device->pwrctrl.constraint.hint.pwrlevel.level)) {
+
+			kgsl_pwrctrl_pwrlevel_change(device, constraint);
+			device->pwrctrl.constraint.type =
+					context->pwr_constraint.type;
+			device->pwrctrl.constraint.hint.
+					pwrlevel.level = constraint;
+		}
+
+		device->pwrctrl.constraint.expires = jiffies +
+			device->pwrctrl.interval_timeout;
+	}
+
+}
+
 /* adreno_rindbuffer_submitcmd - submit userspace IBs to the GPU */
 int adreno_ringbuffer_submitcmd(struct adreno_device *adreno_dev,
 		struct kgsl_cmdbatch *cmdbatch)
@@ -1156,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 */
@@ -1241,6 +1336,9 @@
 		test_bit(ADRENO_DEVICE_PWRON_FIXUP, &adreno_dev->priv))
 		flags |= KGSL_CMD_FLAGS_PWRON_FIXUP;
 
+	/* Set the constraints before adding to ringbuffer */
+	adreno_ringbuffer_set_constraint(device, cmdbatch);
+
 	ret = adreno_ringbuffer_addcmds(&adreno_dev->ringbuffer,
 					drawctxt,
 					flags,
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index 9aefda6..a96ab2b 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -45,6 +45,10 @@
 #undef MODULE_PARAM_PREFIX
 #define MODULE_PARAM_PREFIX "kgsl."
 
+#ifndef arch_mmap_check
+#define arch_mmap_check(addr, len, flags)	(0)
+#endif
+
 static int kgsl_pagetable_count = KGSL_PAGETABLE_COUNT;
 static char *ksgl_mmu_type;
 module_param_named(ptcount, kgsl_pagetable_count, int, 0);
@@ -624,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 */
@@ -679,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;
 }
@@ -690,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);
@@ -714,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;
 }
@@ -949,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);
@@ -1001,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);
 
@@ -1083,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
@@ -1108,17 +1112,17 @@
 	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 */
 		kgsl_pwrctrl_enable(device);
-		result = device->ftbl->stop(device);
+		device->ftbl->stop(device);
 		kgsl_pwrctrl_set_state(device, KGSL_STATE_INIT);
 		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:
@@ -1375,8 +1379,8 @@
 
 	if (dev_priv->device->ftbl->setproperty)
 		result = dev_priv->device->ftbl->setproperty(
-			dev_priv->device, param->type,
-			param->value, param->sizebytes);
+			dev_priv, param->type, param->value,
+			param->sizebytes);
 
 	return result;
 }
@@ -1458,7 +1462,7 @@
  * @timestamp: Pending timestamp for the event
  * @handle: Pointer to a sync fence handle
  * @device: Pointer to the KGSL device
- * @lock: Spin lock to protect the sync event list
+ * @refcount: Allow event to be destroyed asynchronously
  */
 struct kgsl_cmdbatch_sync_event {
 	int type;
@@ -1468,10 +1472,37 @@
 	unsigned int timestamp;
 	struct kgsl_sync_fence_waiter *handle;
 	struct kgsl_device *device;
-	spinlock_t lock;
+	struct kref refcount;
 };
 
 /**
+ * kgsl_cmdbatch_sync_event_destroy() - Destroy a sync event object
+ * @kref: Pointer to the kref structure for this object
+ *
+ * Actually destroy a sync event object.  Called from
+ * kgsl_cmdbatch_sync_event_put.
+ */
+static void kgsl_cmdbatch_sync_event_destroy(struct kref *kref)
+{
+	struct kgsl_cmdbatch_sync_event *event = container_of(kref,
+		struct kgsl_cmdbatch_sync_event, refcount);
+
+	kgsl_cmdbatch_put(event->cmdbatch);
+	kfree(event);
+}
+
+/**
+ * kgsl_cmdbatch_sync_event_put() - Decrement the refcount for a
+ *                                  sync event object
+ * @event: Pointer to the sync event object
+ */
+static inline void kgsl_cmdbatch_sync_event_put(
+	struct kgsl_cmdbatch_sync_event *event)
+{
+	kref_put(&event->refcount, kgsl_cmdbatch_sync_event_destroy);
+}
+
+/**
  * kgsl_cmdbatch_destroy_object() - Destroy a cmdbatch object
  * @kref: Pointer to the kref structure for this object
  *
@@ -1496,10 +1527,25 @@
 static void kgsl_cmdbatch_sync_expire(struct kgsl_device *device,
 	struct kgsl_cmdbatch_sync_event *event)
 {
+	struct kgsl_cmdbatch_sync_event *e, *tmp;
 	int sched = 0;
+	int removed = 0;
 
 	spin_lock(&event->cmdbatch->lock);
-	list_del(&event->node);
+
+	/*
+	 * sync events that are contained by a cmdbatch which has been
+	 * destroyed may have already been removed from the synclist
+	 */
+
+	list_for_each_entry_safe(e, tmp, &event->cmdbatch->synclist, node) {
+		if (e == event) {
+			list_del_init(&event->node);
+			removed = 1;
+			break;
+		}
+	}
+
 	sched = list_empty(&event->cmdbatch->synclist) ? 1 : 0;
 	spin_unlock(&event->cmdbatch->lock);
 
@@ -1510,6 +1556,10 @@
 
 	if (sched && device->ftbl->drawctxt_sched)
 		device->ftbl->drawctxt_sched(device, event->cmdbatch->context);
+
+	/* Put events that have been removed from the synclist */
+	if (removed)
+		kgsl_cmdbatch_sync_event_put(event);
 }
 
 
@@ -1523,11 +1573,9 @@
 	struct kgsl_cmdbatch_sync_event *event = priv;
 
 	kgsl_cmdbatch_sync_expire(device, event);
-
 	kgsl_context_put(event->context);
-	kgsl_cmdbatch_put(event->cmdbatch);
-
-	kfree(event);
+	/* Put events that have signaled */
+	kgsl_cmdbatch_sync_event_put(event);
 }
 
 /**
@@ -1535,32 +1583,48 @@
  * @cmdbatch: Pointer to the command batch object to destroy
  *
  * Start the process of destroying a command batch.  Cancel any pending events
- * and decrement the refcount.
+ * and decrement the refcount.  Asynchronous events can still signal after
+ * kgsl_cmdbatch_destroy has returned.
  */
 void kgsl_cmdbatch_destroy(struct kgsl_cmdbatch *cmdbatch)
 {
 	struct kgsl_cmdbatch_sync_event *event, *tmp;
+	LIST_HEAD(cancel_synclist);
 
+	/*
+	 * Empty the synclist before canceling events
+	 */
 	spin_lock(&cmdbatch->lock);
+	list_splice_init(&cmdbatch->synclist, &cancel_synclist);
+	spin_unlock(&cmdbatch->lock);
 
-	/* Delete any pending sync points for this command batch */
-	list_for_each_entry_safe(event, tmp, &cmdbatch->synclist, node) {
+	/*
+	 * Finish canceling events outside the cmdbatch spinlock and
+	 * require the cancel function to return if the event was
+	 * successfully canceled meaning that the event is guaranteed
+	 * not to signal the callback. This guarantee ensures that
+	 * the reference count for the event and cmdbatch is correct.
+	 */
+	list_for_each_entry_safe(event, tmp, &cancel_synclist, node) {
 
 		if (event->type == KGSL_CMD_SYNCPOINT_TYPE_TIMESTAMP) {
-			/* Cancel the event if it still exists */
+			/*
+			 * Timestamp events are guaranteed to signal
+			 * when canceled
+			 */
 			kgsl_cancel_event(cmdbatch->device, event->context,
 				event->timestamp, kgsl_cmdbatch_sync_func,
 				event);
 		} else if (event->type == KGSL_CMD_SYNCPOINT_TYPE_FENCE) {
-			if (kgsl_sync_fence_async_cancel(event->handle)) {
-				list_del(&event->node);
-				kfree(event);
-				kgsl_cmdbatch_put(cmdbatch);
-			}
+			/* Put events that are successfully canceled */
+			if (kgsl_sync_fence_async_cancel(event->handle))
+				kgsl_cmdbatch_sync_event_put(event);
 		}
-	}
 
-	spin_unlock(&cmdbatch->lock);
+		/* Put events that have been removed from the synclist */
+		list_del_init(&event->node);
+		kgsl_cmdbatch_sync_event_put(event);
+	}
 	kgsl_cmdbatch_put(cmdbatch);
 }
 EXPORT_SYMBOL(kgsl_cmdbatch_destroy);
@@ -1573,11 +1637,9 @@
 {
 	struct kgsl_cmdbatch_sync_event *event = priv;
 
-	spin_lock(&event->lock);
 	kgsl_cmdbatch_sync_expire(event->device, event);
-	kgsl_cmdbatch_put(event->cmdbatch);
-	spin_unlock(&event->lock);
-	kfree(event);
+	/* Put events that have signaled */
+	kgsl_cmdbatch_sync_event_put(event);
 }
 
 /* kgsl_cmdbatch_add_sync_fence() - Add a new sync fence syncpoint
@@ -1603,28 +1665,33 @@
 	event->type = KGSL_CMD_SYNCPOINT_TYPE_FENCE;
 	event->cmdbatch = cmdbatch;
 	event->device = device;
-	spin_lock_init(&event->lock);
+	event->context = NULL;
+
+	/*
+	 * Initial kref is to ensure async callback does not free the
+	 * event before this function sets the event handle
+	 */
+	kref_init(&event->refcount);
 
 	/*
 	 * Add it to the list first to account for the possiblity that the
 	 * callback will happen immediately after the call to
-	 * kgsl_sync_fence_async_wait
+	 * kgsl_sync_fence_async_wait. Decrement the event refcount when
+	 * removing from the synclist.
 	 */
 
 	spin_lock(&cmdbatch->lock);
+	kref_get(&event->refcount);
 	list_add(&event->node, &cmdbatch->synclist);
 	spin_unlock(&cmdbatch->lock);
 
 	/*
-	 * There is a distinct race condition that can occur if the fence
-	 * callback is fired before the function has a chance to return.  The
-	 * event struct would be freed before we could write event->handle and
-	 * hilarity ensued.  Protect against this by protecting the call to
-	 * kgsl_sync_fence_async_wait and the kfree in the callback with a lock.
+	 * Increment the reference count for the async callback.
+	 * Decrement when the callback is successfully canceled, when
+	 * the callback is signaled or if the async wait fails.
 	 */
 
-	spin_lock(&event->lock);
-
+	kref_get(&event->refcount);
 	event->handle = kgsl_sync_fence_async_wait(sync->fd,
 		kgsl_cmdbatch_sync_fence_func, event);
 
@@ -1632,18 +1699,27 @@
 	if (IS_ERR_OR_NULL(event->handle)) {
 		int ret = PTR_ERR(event->handle);
 
+		/* Failed to add the event to the async callback */
+		kgsl_cmdbatch_sync_event_put(event);
+
+		/* Remove event from the synclist */
 		spin_lock(&cmdbatch->lock);
 		list_del(&event->node);
+		kgsl_cmdbatch_sync_event_put(event);
 		spin_unlock(&cmdbatch->lock);
 
-		kgsl_cmdbatch_put(cmdbatch);
-		spin_unlock(&event->lock);
-		kfree(event);
+		/* Event no longer needed by this function */
+		kgsl_cmdbatch_sync_event_put(event);
 
 		return ret;
 	}
 
-	spin_unlock(&event->lock);
+	/*
+	 * Event was successfully added to the synclist, the async
+	 * callback and handle to cancel event has been set.
+	 */
+	kgsl_cmdbatch_sync_event_put(event);
+
 	return 0;
 }
 
@@ -1698,14 +1774,25 @@
 	event->context = context;
 	event->timestamp = sync->timestamp;
 
+	/*
+	 * Two krefs are required to support events. The first kref is for
+	 * the synclist which holds the event in the cmdbatch. The second
+	 * kref is for the callback which can be asynchronous and be called
+	 * after kgsl_cmdbatch_destroy. The kref should be put when the event
+	 * is removed from the synclist, if the callback is successfully
+	 * canceled or when the callback is signaled.
+	 */
+	kref_init(&event->refcount);
+	kref_get(&event->refcount);
+
 	spin_lock(&cmdbatch->lock);
 	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);
@@ -3438,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 318b10d..c1b3139 100644
--- a/drivers/gpu/msm/kgsl_debugfs.c
+++ b/drivers/gpu/msm/kgsl_debugfs.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2002,2008-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2002,2008-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
@@ -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;
@@ -260,8 +260,10 @@
 
 	kgsl_get_memory_usage(usage, sizeof(usage), m->flags);
 
-	seq_printf(s, "%08x %08lx %8d %5d %5s %10s %16s %5d\n",
-			m->gpuaddr, m->useraddr, m->size, entry->id, flags,
+	seq_printf(s, "%pK %pK %8zd %5d %5s %10s %16s %5d\n",
+			(unsigned long *) m->gpuaddr,
+			(unsigned long *) m->useraddr,
+			m->size, entry->id, flags,
 			memtype_str(entry->memtype), usage, m->sglen);
 }
 
@@ -347,7 +349,7 @@
 	 * So if debugfs is disabled in kernel, return as
 	 * success.
 	 */
-	dentry = debugfs_create_file("mem", 0400, private->debug_root, private,
+	dentry = debugfs_create_file("mem", 0444, private->debug_root, private,
 			    &process_mem_fops);
 
 	if (IS_ERR(dentry)) {
diff --git a/drivers/gpu/msm/kgsl_device.h b/drivers/gpu/msm/kgsl_device.h
index 7fc6fae..47801a4 100644
--- a/drivers/gpu/msm/kgsl_device.h
+++ b/drivers/gpu/msm/kgsl_device.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2002,2007-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2002,2007-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
@@ -28,7 +28,6 @@
 #define KGSL_TIMEOUT_NONE           0
 #define KGSL_TIMEOUT_DEFAULT        0xFFFFFFFF
 #define KGSL_TIMEOUT_PART           50 /* 50 msec */
-#define KGSL_TIMEOUT_LONG_IB_DETECTION  2000 /* 2 sec*/
 
 #define FIRST_TIMEOUT (HZ / 2)
 
@@ -129,7 +128,7 @@
 	void (*drawctxt_destroy) (struct kgsl_context *context);
 	long (*ioctl) (struct kgsl_device_private *dev_priv,
 		unsigned int cmd, void *data);
-	int (*setproperty) (struct kgsl_device *device,
+	int (*setproperty) (struct kgsl_device_private *dev_priv,
 		enum kgsl_property_type type, void *value,
 		unsigned int sizebytes);
 	int (*postmortem_dump) (struct kgsl_device *device, int manual);
@@ -252,6 +251,7 @@
 	int open_count;
 
 	struct mutex mutex;
+	atomic64_t mutex_owner;
 	uint32_t state;
 	uint32_t requested_state;
 
@@ -349,6 +349,9 @@
  * @pagefault_ts: global timestamp of the pagefault, if KGSL_CONTEXT_PAGEFAULT
  * is set.
  * @flags: flags from userspace controlling the behavior of this context
+ * @pwr_constraint: power constraint from userspace for this context
+ * @fault_count: number of times gpu hanged in last _context_throttle_time ms
+ * @fault_time: time of the first gpu hang in last _context_throttle_time ms
  */
 struct kgsl_context {
 	struct kref refcount;
@@ -366,6 +369,9 @@
 	struct list_head events_list;
 	unsigned int pagefault_ts;
 	unsigned int flags;
+	struct kgsl_pwr_constraint pwr_constraint;
+	unsigned int fault_count;
+	unsigned long fault_time;
 };
 
 /**
@@ -721,4 +727,54 @@
 	return ret;
 }
 
+/**
+ * kgsl_sysfs_store() - parse a string from a sysfs store function
+ * @buf: Incoming string to parse
+ * @ptr: Pointer to an unsigned int to store the value
+ */
+static inline int kgsl_sysfs_store(const char *buf, unsigned int *ptr)
+{
+	unsigned int val;
+	int rc;
+
+	rc = kstrtou32(buf, 0, &val);
+	if (rc)
+		return rc;
+
+	if (ptr)
+		*ptr = val;
+
+	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 e21fd88..6cea80f 100644
--- a/drivers/gpu/msm/kgsl_events.c
+++ b/drivers/gpu/msm/kgsl_events.c
@@ -210,7 +210,7 @@
 	kgsl_event_func func, void *priv, void *owner)
 {
 	struct kgsl_event *event;
-	unsigned int queued, cur_ts;
+	unsigned int queued = 0, cur_ts;
 	struct kgsl_context *context = NULL;
 
 	BUG_ON(!mutex_is_locked(&device->mutex));
@@ -224,11 +224,21 @@
 			return -EINVAL;
 	}
 
-	queued = kgsl_readtimestamp(device, context, KGSL_TIMESTAMP_QUEUED);
+	/*
+	 * If the caller is creating their own timestamps, let them schedule
+	 * events in the future. Otherwise only allow timestamps that have been
+	 * queued.
+	 */
+	if (context == NULL ||
+		((context->flags & KGSL_CONTEXT_USER_GENERATED_TS) == 0)) {
 
-	if (timestamp_cmp(ts, queued) > 0) {
-		kgsl_context_put(context);
-		return -EINVAL;
+		queued = kgsl_readtimestamp(device, context,
+						KGSL_TIMESTAMP_QUEUED);
+
+		if (timestamp_cmp(ts, queued) > 0) {
+			kgsl_context_put(context);
+			return -EINVAL;
+		}
 	}
 
 	cur_ts = kgsl_readtimestamp(device, context, KGSL_TIMESTAMP_RETIRED);
@@ -399,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);
@@ -426,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
index 246295b..488e5a8 100644
--- a/drivers/gpu/msm/kgsl_iommu.c
+++ b/drivers/gpu/msm/kgsl_iommu.c
@@ -72,6 +72,11 @@
 
 static struct iommu_access_ops *iommu_access_ops;
 
+static int kgsl_iommu_default_setstate(struct kgsl_mmu *mmu,
+		uint32_t flags);
+static phys_addr_t
+kgsl_iommu_get_current_ptbase(struct kgsl_mmu *mmu);
+
 static void _iommu_lock(struct kgsl_iommu const *iommu)
 {
 	if (iommu_access_ops && iommu_access_ops->iommu_lock_acquire)
@@ -456,7 +461,7 @@
  * Disables iommu clocks
  * Return - void
  */
-static void kgsl_iommu_disable_clk(struct kgsl_mmu *mmu)
+static void kgsl_iommu_disable_clk(struct kgsl_mmu *mmu, int ctx_id)
 {
 	struct kgsl_iommu *iommu = mmu->priv;
 	struct msm_iommu_drvdata *iommu_drvdata;
@@ -465,8 +470,15 @@
 	for (i = 0; i < iommu->unit_count; i++) {
 		struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[i];
 		for (j = 0; j < iommu_unit->dev_count; j++) {
-			if (!iommu_unit->dev[j].clk_enabled)
+			if (ctx_id != iommu_unit->dev[j].ctx_id)
 				continue;
+			atomic_dec(&iommu_unit->dev[j].clk_enable_count);
+			BUG_ON(
+			atomic_read(&iommu_unit->dev[j].clk_enable_count) < 0);
+			/*
+			 * the clock calls have a refcount so call them on every
+			 * enable/disable call
+			 */
 			iommu_drvdata = dev_get_drvdata(
 					iommu_unit->dev[j].dev->parent);
 			if (iommu_drvdata->aclk)
@@ -474,7 +486,6 @@
 			if (iommu_drvdata->clk)
 				clk_disable_unprepare(iommu_drvdata->clk);
 			clk_disable_unprepare(iommu_drvdata->pclk);
-			iommu_unit->dev[j].clk_enabled = false;
 		}
 	}
 }
@@ -495,32 +506,17 @@
 					unsigned int id, unsigned int ts,
 					u32 type)
 {
-	struct kgsl_mmu *mmu = data;
-	struct kgsl_iommu *iommu = mmu->priv;
+	struct kgsl_iommu_disable_clk_param *param = data;
 
-	if (!iommu->clk_event_queued) {
-		if (0 > timestamp_cmp(ts, iommu->iommu_last_cmd_ts))
-			KGSL_DRV_ERR(device,
-			"IOMMU disable clock event being cancelled, "
-			"iommu_last_cmd_ts: %x, retired ts: %x\n",
-			iommu->iommu_last_cmd_ts, ts);
-		return;
-	}
+	if ((0 <= timestamp_cmp(ts, param->ts)) ||
+		(KGSL_EVENT_CANCELLED == type))
+		kgsl_iommu_disable_clk(param->mmu, param->ctx_id);
+	else
+		/* something went wrong with the event handling mechanism */
+		BUG_ON(1);
 
-	if (0 <= timestamp_cmp(ts, iommu->iommu_last_cmd_ts)) {
-		kgsl_iommu_disable_clk(mmu);
-		iommu->clk_event_queued = false;
-	} else {
-		/* add new event to fire when ts is reached, this can happen
-		 * if we queued an event and someone requested the clocks to
-		 * be disbaled on a later timestamp */
-		if (kgsl_add_event(device, id, iommu->iommu_last_cmd_ts,
-			kgsl_iommu_clk_disable_event, mmu, mmu)) {
-				KGSL_DRV_ERR(device,
-				"Failed to add IOMMU disable clk event\n");
-				iommu->clk_event_queued = false;
-		}
-	}
+	/* Free param we are done using it */
+	kfree(param);
 }
 
 /*
@@ -530,6 +526,8 @@
  * @ts_valid - Indicates whether ts parameter is valid, if this parameter
  * is false then it means that the calling function wants to disable the
  * IOMMU clocks immediately without waiting for any timestamp
+ * @ctx_id: Context id of the IOMMU context for which clocks are to be
+ * turned off
  *
  * Creates an event to disable the IOMMU clocks on timestamp and if event
  * already exists then updates the timestamp of disabling the IOMMU clocks
@@ -538,28 +536,25 @@
  * Return - void
  */
 static void
-kgsl_iommu_disable_clk_on_ts(struct kgsl_mmu *mmu, unsigned int ts,
-				bool ts_valid)
+kgsl_iommu_disable_clk_on_ts(struct kgsl_mmu *mmu,
+				unsigned int ts, int ctx_id)
 {
-	struct kgsl_iommu *iommu = mmu->priv;
+	struct kgsl_iommu_disable_clk_param *param;
 
-	if (iommu->clk_event_queued) {
-		if (ts_valid && (0 <
-			timestamp_cmp(ts, iommu->iommu_last_cmd_ts)))
-			iommu->iommu_last_cmd_ts = ts;
-	} else {
-		if (ts_valid) {
-			iommu->iommu_last_cmd_ts = ts;
-			iommu->clk_event_queued = true;
-			if (kgsl_add_event(mmu->device, KGSL_MEMSTORE_GLOBAL,
-				ts, kgsl_iommu_clk_disable_event, mmu, mmu)) {
-				KGSL_DRV_ERR(mmu->device,
-				"Failed to add IOMMU disable clk event\n");
-				iommu->clk_event_queued = false;
-			}
-		} else {
-			kgsl_iommu_disable_clk(mmu);
-		}
+	param = kzalloc(sizeof(*param), GFP_KERNEL);
+	if (!param) {
+		KGSL_CORE_ERR("kzalloc(%d) failed\n", sizeof(*param));
+		return;
+	}
+	param->mmu = mmu;
+	param->ctx_id = ctx_id;
+	param->ts = ts;
+
+	if (kgsl_add_event(mmu->device, KGSL_MEMSTORE_GLOBAL,
+			ts, kgsl_iommu_clk_disable_event, param, mmu)) {
+		KGSL_DRV_ERR(mmu->device,
+			"Failed to add IOMMU disable clk event\n");
+		kfree(param);
 	}
 }
 
@@ -582,8 +577,7 @@
 	for (i = 0; i < iommu->unit_count; i++) {
 		struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[i];
 		for (j = 0; j < iommu_unit->dev_count; j++) {
-			if (iommu_unit->dev[j].clk_enabled ||
-				ctx_id != iommu_unit->dev[j].ctx_id)
+			if (ctx_id != iommu_unit->dev[j].ctx_id)
 				continue;
 			iommu_drvdata =
 			dev_get_drvdata(iommu_unit->dev[j].dev->parent);
@@ -609,12 +603,25 @@
 					goto done;
 				}
 			}
-			iommu_unit->dev[j].clk_enabled = true;
+			atomic_inc(&iommu_unit->dev[j].clk_enable_count);
 		}
 	}
 done:
-	if (ret)
-		kgsl_iommu_disable_clk(mmu);
+	if (ret) {
+		struct kgsl_iommu_unit *iommu_unit;
+		if (iommu->unit_count == i)
+			i--;
+		iommu_unit = &iommu->iommu_units[i];
+		do {
+			for (j--; j >= 0; j--)
+				kgsl_iommu_disable_clk(mmu, ctx_id);
+			i--;
+			if (i >= 0) {
+				iommu_unit = &iommu->iommu_units[i];
+				j = iommu_unit->dev_count;
+			}
+		} while (i >= 0);
+	}
 	return ret;
 }
 
@@ -634,16 +641,18 @@
 				phys_addr_t pt_base)
 {
 	struct kgsl_iommu_pt *iommu_pt = pt ? pt->priv : NULL;
-	phys_addr_t domain_ptbase = iommu_pt ?
-				iommu_get_pt_base_addr(iommu_pt->domain) : 0;
+	phys_addr_t domain_ptbase;
 
-	/* Only compare the valid address bits of the pt_base */
-	domain_ptbase &= KGSL_IOMMU_CTX_TTBR0_ADDR_MASK;
+	if (iommu_pt == NULL)
+		return 0;
+
+	domain_ptbase = iommu_get_pt_base_addr(iommu_pt->domain)
+			& KGSL_IOMMU_CTX_TTBR0_ADDR_MASK;
 
 	pt_base &= KGSL_IOMMU_CTX_TTBR0_ADDR_MASK;
 
-	return domain_ptbase && pt_base &&
-		(domain_ptbase == pt_base);
+	return (domain_ptbase == pt_base);
+
 }
 
 /*
@@ -843,6 +852,9 @@
 			ret = -EINVAL;
 			goto done;
 		}
+		atomic_set(
+		&(iommu_unit->dev[iommu_unit->dev_count].clk_enable_count),
+		0);
 
 		iommu_unit->dev[iommu_unit->dev_count].dev =
 			msm_iommu_get_ctx(data->iommu_ctxs[i].iommu_ctx_name);
@@ -1036,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;
@@ -1050,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;
@@ -1092,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;
@@ -1485,7 +1513,7 @@
 
 	/* If chip is not 8960 then we use the 2nd context bank for pagetable
 	 * switching on the 3D side for which a separate table is allocated */
-	if (!cpu_is_msm8960() && msm_soc_version_supports_iommu_v0()) {
+	if (msm_soc_version_supports_iommu_v0()) {
 		mmu->priv_bank_table =
 			kgsl_mmu_getpagetable(mmu,
 					KGSL_MMU_PRIV_BANK_TABLE_NAME);
@@ -1669,6 +1697,7 @@
 	}
 	status = kgsl_iommu_enable_clk(mmu, KGSL_IOMMU_CONTEXT_PRIV);
 	if (status) {
+		kgsl_iommu_disable_clk(mmu, KGSL_IOMMU_CONTEXT_USER);
 		KGSL_CORE_ERR("clk enable failed\n");
 		goto done;
 	}
@@ -1723,23 +1752,48 @@
 				KGSL_IOMMU_SETSTATE_NOP_OFFSET,
 				cp_nop_packet(1), sizeof(unsigned int));
 
-	kgsl_iommu_disable_clk_on_ts(mmu, 0, false);
+	kgsl_iommu_disable_clk(mmu, KGSL_IOMMU_CONTEXT_USER);
+	kgsl_iommu_disable_clk(mmu, KGSL_IOMMU_CONTEXT_PRIV);
 	mmu->flags |= KGSL_FLAGS_STARTED;
 
 done:
-	if (status) {
-		kgsl_iommu_disable_clk_on_ts(mmu, 0, false);
-		kgsl_detach_pagetable_iommu_domain(mmu);
-	}
 	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;
+	int ret = 0;
 	unsigned int range = memdesc->size;
 	struct kgsl_iommu_pt *iommu_pt = pt->priv;
 
@@ -1756,18 +1810,16 @@
 		range += PAGE_SIZE;
 
 	ret = iommu_unmap_range(iommu_pt->domain, gpuaddr, range);
-	if (ret)
+	if (ret) {
 		KGSL_CORE_ERR("iommu_unmap_range(%p, %x, %d) failed "
 			"with err: %d\n", iommu_pt->domain, gpuaddr,
 			range, ret);
+		return ret;
+	}
 
-	/*
-	 * Flushing only required if per process pagetables are used. With
-	 * global case, flushing will happen inside iommu_map function
-	 */
-	if (!ret && kgsl_mmu_is_perprocess(pt->mmu))
-		*tlb_flags = UINT_MAX;
-	return 0;
+	kgsl_iommu_flush_tlb_pt_current(pt);
+
+	return ret;
 }
 
 static int
@@ -1807,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;
 }
 
@@ -1831,6 +1900,7 @@
 						iommu_unit,
 						iommu_unit->dev[j].ctx_id,
 						FSR, 0);
+					kgsl_iommu_disable_clk(mmu, j);
 					_iommu_unlock(iommu);
 					iommu_unit->dev[j].fault = 0;
 				}
@@ -1843,7 +1913,6 @@
 
 static void kgsl_iommu_stop(struct kgsl_mmu *mmu)
 {
-	struct kgsl_iommu *iommu = mmu->priv;
 	/*
 	 *  stop device mmu
 	 *
@@ -1859,9 +1928,7 @@
 		kgsl_iommu_pagefault_resume(mmu);
 	}
 	/* switch off MMU clocks and cancel any events it has queued */
-	iommu->clk_event_queued = false;
 	kgsl_cancel_events(mmu->device, mmu);
-	kgsl_iommu_disable_clk(mmu);
 }
 
 static int kgsl_iommu_close(struct kgsl_mmu *mmu)
@@ -1911,10 +1978,10 @@
 		return 0;
 	/* Return the current pt base by reading IOMMU pt_base register */
 	kgsl_iommu_enable_clk(mmu, KGSL_IOMMU_CONTEXT_USER);
-	pt_base = KGSL_IOMMU_GET_CTX_REG(iommu, (&iommu->iommu_units[0]),
-					KGSL_IOMMU_CONTEXT_USER,
-					TTBR0);
-	kgsl_iommu_disable_clk_on_ts(mmu, 0, false);
+	pt_base = KGSL_IOMMU_GET_CTX_REG(iommu,
+				(&iommu->iommu_units[0]),
+				KGSL_IOMMU_CONTEXT_USER, TTBR0);
+	kgsl_iommu_disable_clk(mmu, KGSL_IOMMU_CONTEXT_USER);
 	return pt_base & KGSL_IOMMU_CTX_TTBR0_ADDR_MASK;
 }
 
@@ -1942,7 +2009,6 @@
 	phys_addr_t pt_val;
 
 	ret = kgsl_iommu_enable_clk(mmu, KGSL_IOMMU_CONTEXT_USER);
-
 	if (ret) {
 		KGSL_DRV_ERR(mmu->device, "Failed to enable iommu clocks\n");
 		return ret;
@@ -2029,7 +2095,7 @@
 	_iommu_unlock(iommu);
 
 	/* Disable smmu clock */
-	kgsl_iommu_disable_clk_on_ts(mmu, 0, false);
+	kgsl_iommu_disable_clk(mmu, KGSL_IOMMU_CONTEXT_USER);
 	return ret;
 }
 
@@ -2076,6 +2142,72 @@
 	return iommu->unit_count;
 }
 
+/*
+ * kgsl_iommu_set_pf_policy() - Set the pagefault policy for IOMMU
+ * @mmu: Pointer to mmu structure
+ * @pf_policy: The pagefault polict to set
+ *
+ * Check if the new policy indicated by pf_policy is same as current
+ * policy, if same then return else set the policy
+ */
+static int kgsl_iommu_set_pf_policy(struct kgsl_mmu *mmu,
+				unsigned int pf_policy)
+{
+	int i, j;
+	struct kgsl_iommu *iommu = mmu->priv;
+	struct adreno_device *adreno_dev = ADRENO_DEVICE(mmu->device);
+	int ret = 0;
+	unsigned int sctlr_val;
+
+	if ((adreno_dev->ft_pf_policy & KGSL_FT_PAGEFAULT_GPUHALT_ENABLE) ==
+		(pf_policy & KGSL_FT_PAGEFAULT_GPUHALT_ENABLE))
+		return ret;
+	if (msm_soc_version_supports_iommu_v0())
+		return ret;
+
+	ret = kgsl_iommu_enable_clk(mmu, KGSL_IOMMU_CONTEXT_USER);
+
+	if (ret) {
+		KGSL_DRV_ERR(mmu->device, "Failed to enable iommu clocks\n");
+		return ret;
+	}
+	ret = kgsl_iommu_enable_clk(mmu, KGSL_IOMMU_CONTEXT_PRIV);
+
+	if (ret) {
+		KGSL_DRV_ERR(mmu->device, "Failed to enable iommu clocks\n");
+		kgsl_iommu_disable_clk_on_ts(mmu, 0, false);
+		return ret;
+	}
+	/* Need to idle device before changing options */
+	ret = mmu->device->ftbl->idle(mmu->device);
+	if (ret) {
+		kgsl_iommu_disable_clk_on_ts(mmu, 0, false);
+		return ret;
+	}
+
+	for (i = 0; i < iommu->unit_count; i++) {
+		struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[i];
+		for (j = 0; j < iommu_unit->dev_count; j++) {
+			sctlr_val = KGSL_IOMMU_GET_CTX_REG(iommu,
+					iommu_unit,
+					iommu_unit->dev[j].ctx_id,
+					SCTLR);
+			if (pf_policy & KGSL_FT_PAGEFAULT_GPUHALT_ENABLE)
+				sctlr_val &= ~(0x1 <<
+					KGSL_IOMMU_SCTLR_HUPCF_SHIFT);
+			else
+				sctlr_val |= (0x1 <<
+					KGSL_IOMMU_SCTLR_HUPCF_SHIFT);
+			KGSL_IOMMU_SET_CTX_REG(iommu,
+					iommu_unit,
+					iommu_unit->dev[j].ctx_id,
+					SCTLR, sctlr_val);
+		}
+	}
+	kgsl_iommu_disable_clk_on_ts(mmu, 0, false);
+	return ret;
+}
+
 struct kgsl_mmu_ops iommu_ops = {
 	.mmu_init = kgsl_iommu_init,
 	.mmu_close = kgsl_iommu_close,
@@ -2101,6 +2233,7 @@
 	.mmu_cleanup_pt = NULL,
 	.mmu_sync_lock = kgsl_iommu_sync_lock,
 	.mmu_sync_unlock = kgsl_iommu_sync_unlock,
+	.mmu_set_pf_policy = kgsl_iommu_set_pf_policy,
 };
 
 struct kgsl_mmu_pt_ops iommu_pt_ops = {
diff --git a/drivers/gpu/msm/kgsl_iommu.h b/drivers/gpu/msm/kgsl_iommu.h
index 7dca40e..3878107 100644
--- a/drivers/gpu/msm/kgsl_iommu.h
+++ b/drivers/gpu/msm/kgsl_iommu.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
@@ -143,6 +143,7 @@
  * are on, else the clocks are off
  * fault: Flag when set indicates that this iommu device has caused a page
  * fault
+ * @clk_enable_count: The ref count of clock enable calls
  */
 struct kgsl_iommu_device {
 	struct device *dev;
@@ -152,6 +153,7 @@
 	bool clk_enabled;
 	struct kgsl_device *kgsldev;
 	int fault;
+	atomic_t clk_enable_count;
 };
 
 /*
@@ -182,10 +184,6 @@
  * iommu contexts owned by graphics cores
  * @unit_count: Number of IOMMU units that are available for this
  * instance of the IOMMU driver
- * @iommu_last_cmd_ts: The timestamp of last command submitted that
- * aceeses iommu registers
- * @clk_event_queued: Indicates whether an event to disable clocks
- * is already queued or not
  * @device: Pointer to kgsl device
  * @ctx_offset: The context offset to be added to base address when
  * accessing IOMMU registers
@@ -201,8 +199,6 @@
 struct kgsl_iommu {
 	struct kgsl_iommu_unit iommu_units[KGSL_IOMMU_MAX_UNITS];
 	unsigned int unit_count;
-	unsigned int iommu_last_cmd_ts;
-	bool clk_event_queued;
 	struct kgsl_device *device;
 	unsigned int ctx_offset;
 	struct kgsl_iommu_register_list *iommu_reg_list;
@@ -222,4 +218,18 @@
 	struct kgsl_iommu *iommu;
 };
 
+/*
+ * struct kgsl_iommu_disable_clk_param - Parameter struct for disble clk event
+ * @mmu: The mmu pointer
+ * @rb_level: the rb level in which the timestamp of the event belongs to
+ * @ctx_id: The IOMMU context whose clock is to be turned off
+ * @ts: Timestamp on which clock is to be disabled
+ */
+struct kgsl_iommu_disable_clk_param {
+	struct kgsl_mmu *mmu;
+	int rb_level;
+	int ctx_id;
+	unsigned int ts;
+};
+
 #endif
diff --git a/drivers/gpu/msm/kgsl_mmu.c b/drivers/gpu/msm/kgsl_mmu.c
index 6b04aad..65e607b 100644
--- a/drivers/gpu/msm/kgsl_mmu.c
+++ b/drivers/gpu/msm/kgsl_mmu.c
@@ -85,16 +85,8 @@
 	return status;
 }
 
-static void kgsl_destroy_pagetable(struct kref *kref)
+static void _kgsl_destroy_pagetable(struct kgsl_pagetable *pagetable)
 {
-	struct kgsl_pagetable *pagetable = container_of(kref,
-		struct kgsl_pagetable, refcount);
-	unsigned long flags;
-
-	spin_lock_irqsave(&kgsl_driver.ptlock, flags);
-	list_del(&pagetable->list);
-	spin_unlock_irqrestore(&kgsl_driver.ptlock, flags);
-
 	pagetable_remove_sysfs_objects(pagetable);
 
 	kgsl_cleanup_pt(pagetable);
@@ -109,6 +101,29 @@
 	kfree(pagetable);
 }
 
+static void kgsl_destroy_pagetable(struct kref *kref)
+{
+	struct kgsl_pagetable *pagetable = container_of(kref,
+		struct kgsl_pagetable, refcount);
+	unsigned long flags;
+
+	spin_lock_irqsave(&kgsl_driver.ptlock, flags);
+	list_del(&pagetable->list);
+	spin_unlock_irqrestore(&kgsl_driver.ptlock, flags);
+
+	_kgsl_destroy_pagetable(pagetable);
+}
+
+static void kgsl_destroy_pagetable_locked(struct kref *kref)
+{
+	struct kgsl_pagetable *pagetable = container_of(kref,
+		struct kgsl_pagetable, refcount);
+
+	list_del(&pagetable->list);
+
+	_kgsl_destroy_pagetable(pagetable);
+}
+
 static inline void kgsl_put_pagetable(struct kgsl_pagetable *pagetable)
 {
 	if (pagetable)
@@ -128,7 +143,7 @@
 				ret = pt;
 				break;
 			}
-			kref_put(&pt->refcount, kgsl_destroy_pagetable);
+			kref_put(&pt->refcount, kgsl_destroy_pagetable_locked);
 		}
 	}
 
@@ -139,12 +154,12 @@
 static struct kgsl_pagetable *
 _get_pt_from_kobj(struct kobject *kobj)
 {
-	unsigned long ptname;
+	unsigned int ptname;
 
 	if (!kobj)
 		return NULL;
 
-	if (sscanf(kobj->name, "%ld", &ptname) != 1)
+	if (kstrtou32(kobj->name, 0, &ptname))
 		return NULL;
 
 	return kgsl_get_pagetable(ptname);
@@ -328,10 +343,11 @@
 		if (kref_get_unless_zero(&pt->refcount)) {
 			if (mmu->mmu_ops->mmu_pt_equal(mmu, pt, pt_base)) {
 				ptid = (int) pt->name;
-				kref_put(&pt->refcount, kgsl_destroy_pagetable);
+				kref_put(&pt->refcount,
+					kgsl_destroy_pagetable_locked);
 				break;
 			}
-			kref_put(&pt->refcount, kgsl_destroy_pagetable);
+			kref_put(&pt->refcount, kgsl_destroy_pagetable_locked);
 		}
 	}
 	spin_unlock(&kgsl_driver.ptlock);
@@ -356,18 +372,18 @@
 				if ((addr & ~(PAGE_SIZE-1)) == pt->fault_addr) {
 					ret = 1;
 					kref_put(&pt->refcount,
-						kgsl_destroy_pagetable);
+						kgsl_destroy_pagetable_locked);
 					break;
 				} else {
 					pt->fault_addr =
 						(addr & ~(PAGE_SIZE-1));
 					ret = 0;
 					kref_put(&pt->refcount,
-						kgsl_destroy_pagetable);
+						kgsl_destroy_pagetable_locked);
 					break;
 				}
 			}
-			kref_put(&pt->refcount, kgsl_destroy_pagetable);
+			kref_put(&pt->refcount, kgsl_destroy_pagetable_locked);
 		}
 	}
 	spin_unlock(&kgsl_driver.ptlock);
@@ -385,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_mmu.h b/drivers/gpu/msm/kgsl_mmu.h
index 8bc9962..5e3386a 100644
--- a/drivers/gpu/msm/kgsl_mmu.h
+++ b/drivers/gpu/msm/kgsl_mmu.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2002,2007-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2002,2007-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
@@ -144,11 +144,12 @@
 	void (*mmu_pagefault_resume)
 			(struct kgsl_mmu *mmu);
 	void (*mmu_disable_clk_on_ts)
-		(struct kgsl_mmu *mmu, uint32_t ts, bool ts_valid);
+		(struct kgsl_mmu *mmu,
+		uint32_t ts, int ctx_id);
 	int (*mmu_enable_clk)
 		(struct kgsl_mmu *mmu, int ctx_id);
 	void (*mmu_disable_clk)
-		(struct kgsl_mmu *mmu);
+		(struct kgsl_mmu *mmu, int ctx_id);
 	phys_addr_t (*mmu_get_default_ttbr0)(struct kgsl_mmu *mmu,
 				unsigned int unit_id,
 				enum kgsl_iommu_context_id ctx_id);
@@ -173,6 +174,7 @@
 	unsigned int (*mmu_sync_unlock)
 			(struct kgsl_mmu *mmu, unsigned int *cmds);
 	int (*mmu_hw_halt_supported)(struct kgsl_mmu *mmu, int iommu_unit_num);
+	int (*mmu_set_pf_policy)(struct kgsl_mmu *mmu, unsigned int pf_policy);
 };
 
 struct kgsl_mmu_pt_ops {
@@ -326,17 +328,18 @@
 		return 0;
 }
 
-static inline void kgsl_mmu_disable_clk(struct kgsl_mmu *mmu)
+static inline void kgsl_mmu_disable_clk(struct kgsl_mmu *mmu, int ctx_id)
 {
 	if (mmu->mmu_ops && mmu->mmu_ops->mmu_disable_clk)
-		mmu->mmu_ops->mmu_disable_clk(mmu);
+		mmu->mmu_ops->mmu_disable_clk(mmu, ctx_id);
 }
 
 static inline void kgsl_mmu_disable_clk_on_ts(struct kgsl_mmu *mmu,
-						unsigned int ts, bool ts_valid)
+						unsigned int ts,
+						int ctx_id)
 {
 	if (mmu->mmu_ops && mmu->mmu_ops->mmu_disable_clk_on_ts)
-		mmu->mmu_ops->mmu_disable_clk_on_ts(mmu, ts, ts_valid);
+		mmu->mmu_ops->mmu_disable_clk_on_ts(mmu, ts, ctx_id);
 }
 
 static inline unsigned int kgsl_mmu_get_int_mask(void)
@@ -477,4 +480,13 @@
 		return 0;
 }
 
+static inline int kgsl_mmu_set_pagefault_policy(struct kgsl_mmu *mmu,
+						unsigned int pf_policy)
+{
+	if (mmu->mmu_ops && mmu->mmu_ops->mmu_set_pf_policy)
+		return mmu->mmu_ops->mmu_set_pf_policy(mmu, pf_policy);
+	else
+		return 0;
+}
+
 #endif /* __KGSL_MMU_H */
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c
index 3e15580..563f7ef 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.c
+++ b/drivers/gpu/msm/kgsl_pwrctrl.c
@@ -78,7 +78,7 @@
 };
 
 static void kgsl_pwrctrl_clk(struct kgsl_device *device, int state,
-					  int requested_state);
+					int requested_state);
 static void kgsl_pwrctrl_axi(struct kgsl_device *device, int state);
 static void kgsl_pwrctrl_pwrrail(struct kgsl_device *device, int state);
 
@@ -132,6 +132,9 @@
 	int buslevel = 0;
 	if (!pwr->pcl)
 		return;
+	/* the bus should be ON to update the active frequency */
+	if (on && !(test_bit(KGSL_PWRFLAGS_AXI_ON, &pwr->power_flags)))
+		return;
 	/*
 	 * If the bus should remain on calculate our request and submit it,
 	 * otherwise request bus level 0, off.
@@ -175,11 +178,10 @@
 	pwr->bus_mod = 0;
 	pwrlevel = &pwr->pwrlevels[pwr->active_pwrlevel];
 
-	if (test_bit(KGSL_PWRFLAGS_AXI_ON, &pwr->power_flags)) {
-		kgsl_pwrctrl_buslevel_update(device, true);
+	kgsl_pwrctrl_buslevel_update(device, true);
+	if (test_bit(KGSL_PWRFLAGS_AXI_ON, &pwr->power_flags))
 		if (pwr->ebi1_clk)
 			clk_set_rate(pwr->ebi1_clk, pwrlevel->bus_freq);
-	}
 
 	if (test_bit(KGSL_PWRFLAGS_CLK_ON, &pwr->power_flags) ||
 		(device->state == KGSL_STATE_NAP)) {
@@ -218,21 +220,20 @@
 {
 	struct kgsl_device *device = kgsl_device_from_dev(dev);
 	struct kgsl_pwrctrl *pwr;
-	int ret, level;
+	int ret;
+	unsigned int level = 0;
 
 	if (device == NULL)
 		return 0;
 
 	pwr = &device->pwrctrl;
 
-	ret = sscanf(buf, "%d", &level);
-	if (ret != 1)
-		return count;
+	ret = kgsl_sysfs_store(buf, &level);
 
-	if (level < 0)
-		return count;
+	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;
@@ -248,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;
 }
@@ -272,22 +273,19 @@
 {
 	struct kgsl_device *device = kgsl_device_from_dev(dev);
 	struct kgsl_pwrctrl *pwr;
-	int ret, level, max_level;
+	int ret, max_level;
+	unsigned int level = 0;
 
 	if (device == NULL)
 		return 0;
 
 	pwr = &device->pwrctrl;
 
-	ret = sscanf(buf, "%d", &level);
-	if (ret != 1)
-		return count;
+	ret = kgsl_sysfs_store(buf, &level);
+	if (ret)
+		return ret;
 
-	/* If the use specifies a negative number, then don't change anything */
-	if (level < 0)
-		return count;
-
-	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)
@@ -304,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;
 }
@@ -327,22 +325,19 @@
 					 const char *buf, size_t count)
 {	struct kgsl_device *device = kgsl_device_from_dev(dev);
 	struct kgsl_pwrctrl *pwr;
-	int ret, level, min_level;
+	int ret, min_level;
+	unsigned int level = 0;
 
 	if (device == NULL)
 		return 0;
 
 	pwr = &device->pwrctrl;
 
-	ret = sscanf(buf, "%d", &level);
-	if (ret != 1)
-		return count;
+	ret = kgsl_sysfs_store(buf, &level);
+	if (ret)
+		return ret;
 
-	/* Don't do anything on obviously incorrect values */
-	if (level < 0)
-		return count;
-
-	mutex_lock(&device->mutex);
+	kgsl_mutex_lock(&device->mutex, &device->mutex_owner);
 	if (level > pwr->num_pwrlevels - 2)
 		level = pwr->num_pwrlevels - 2;
 
@@ -361,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;
 }
@@ -411,7 +406,7 @@
 {
 	struct kgsl_device *device = kgsl_device_from_dev(dev);
 	struct kgsl_pwrctrl *pwr;
-	unsigned long val;
+	unsigned int val = 0;
 	int ret, level;
 
 	if (device == NULL)
@@ -419,11 +414,11 @@
 
 	pwr = &device->pwrctrl;
 
-	ret = sscanf(buf, "%ld", &val);
-	if (ret != 1)
-		return count;
+	ret = kgsl_sysfs_store(buf, &val);
+	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;
@@ -439,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;
 }
 
@@ -463,7 +458,7 @@
 {
 	struct kgsl_device *device = kgsl_device_from_dev(dev);
 	struct kgsl_pwrctrl *pwr;
-	unsigned long val;
+	unsigned int val = 0;
 	int ret, level;
 
 	if (device == NULL)
@@ -471,16 +466,16 @@
 
 	pwr = &device->pwrctrl;
 
-	ret = sscanf(buf, "%ld", &val);
-	if (ret != 1)
-		return count;
+	ret = kgsl_sysfs_store(buf, &val);
+	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;
 }
 
@@ -500,30 +495,27 @@
 					struct device_attribute *attr,
 					const char *buf, size_t count)
 {
-	char temp[20];
-	unsigned long val;
+	unsigned int val = 0;
 	struct kgsl_device *device = kgsl_device_from_dev(dev);
 	struct kgsl_pwrctrl *pwr;
 	const long div = 1000/HZ;
-	int rc;
+	int ret;
 
 	if (device == NULL)
 		return 0;
 	pwr = &device->pwrctrl;
 
-	snprintf(temp, sizeof(temp), "%.*s",
-			 (int)min(count, sizeof(temp) - 1), buf);
-	rc = strict_strtoul(temp, 0, &val);
-	if (rc)
-		return rc;
+	ret = kgsl_sysfs_store(buf, &val);
+	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;
 }
@@ -545,23 +537,20 @@
 					struct device_attribute *attr,
 					const char *buf, size_t count)
 {
-	char temp[20];
-	unsigned long val;
+	unsigned int val = 0;
 	struct kgsl_device *device = kgsl_device_from_dev(dev);
-	int rc;
+	int ret;
 
 	if (device == NULL)
 		return 0;
 
-	snprintf(temp, sizeof(temp), "%.*s",
-			(int)min(count, sizeof(temp) - 1), buf);
-	rc = kstrtoul(temp, 0, &val);
-	if (rc)
-		return rc;
+	ret = kgsl_sysfs_store(buf, &val);
+	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,23 +681,20 @@
 					const char *buf, size_t count,
 					int flag)
 {
-	char temp[20];
-	unsigned long val;
+	unsigned int val = 0;
 	struct kgsl_device *device = kgsl_device_from_dev(dev);
-	int rc;
+	int ret;
 
 	if (device == NULL)
 		return 0;
 
-	snprintf(temp, sizeof(temp), "%.*s",
-			(int)min(count, sizeof(temp) - 1), buf);
-	rc = kstrtoul(temp, 0, &val);
-	if (rc)
-		return rc;
+	ret = kgsl_sysfs_store(buf, &val);
+	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;
 }
@@ -770,23 +756,20 @@
 					struct device_attribute *attr,
 					const char *buf, size_t count)
 {
-	char temp[20];
-	unsigned long val;
+	unsigned int val = 0;
 	struct kgsl_device *device = kgsl_device_from_dev(dev);
-	int rc;
+	int ret;
 
 	if (device == NULL)
 		return 0;
 
-	snprintf(temp, sizeof(temp), "%.*s",
-			(int)min(count, sizeof(temp) - 1), buf);
-	rc = kstrtoul(temp, 0, &val);
-	if (rc)
-		return rc;
+	ret = kgsl_sysfs_store(buf, &val);
+	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;
 }
@@ -900,7 +883,7 @@
 	}
 }
 
-static void kgsl_pwrctrl_clk(struct kgsl_device *device, int state,
+void kgsl_pwrctrl_clk(struct kgsl_device *device, int state,
 					  int requested_state)
 {
 	struct kgsl_pwrctrl *pwr = &device->pwrctrl;
@@ -1141,8 +1124,7 @@
 					 pwr->pwrlevels[pwr->active_pwrlevel].
 						bus_freq);
 
-	/* Set the CPU latency to 501usec to allow low latency PC modes */
-	pwr->pm_qos_latency = 501;
+	pwr->pm_qos_latency = pdata->pm_qos_latency;
 
 	pm_runtime_enable(device->parentdev);
 
@@ -1260,7 +1242,7 @@
 	if (device == NULL)
 		return;
 
-	mutex_lock(&device->mutex);
+	kgsl_mutex_lock(&device->mutex, &device->mutex_owner);
 
 	kgsl_pwrscale_update(device);
 
@@ -1284,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);
 		}
 
 
@@ -1311,7 +1293,7 @@
 		}
 	}
 
-	mutex_unlock(&device->mutex);
+	kgsl_mutex_unlock(&device->mutex, &device->mutex_owner);
 }
 EXPORT_SYMBOL(kgsl_idle_check);
 
@@ -1428,8 +1410,6 @@
 		break;
 	}
 
-	kgsl_mmu_disable_clk_on_ts(&device->mmu, 0, false);
-
 	return 0;
 }
 
@@ -1569,7 +1549,10 @@
 	struct kgsl_pwrctrl *pwr = &device->pwrctrl;
 	/* Order pwrrail/clk sequence based upon platform */
 	kgsl_pwrctrl_pwrrail(device, KGSL_PWRFLAGS_ON);
-	kgsl_pwrctrl_pwrlevel_change(device, pwr->active_pwrlevel);
+
+	if (pwr->constraint.type == KGSL_CONSTRAINT_NONE)
+		kgsl_pwrctrl_pwrlevel_change(device, pwr->active_pwrlevel);
+
 	kgsl_pwrctrl_clk(device, KGSL_PWRFLAGS_ON, KGSL_STATE_ACTIVE);
 	kgsl_pwrctrl_axi(device, KGSL_PWRFLAGS_ON);
 }
@@ -1644,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);
 	}
@@ -1736,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_pwrctrl.h b/drivers/gpu/msm/kgsl_pwrctrl.h
index 6ec809d..31c5229 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.h
+++ b/drivers/gpu/msm/kgsl_pwrctrl.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
@@ -27,6 +27,9 @@
 
 #define KGSL_MAX_CLKS 6
 
+/* Only two supported levels, min & max */
+#define KGSL_CONSTRAINT_PWR_MAXLEVELS 2
+
 struct platform_device;
 
 struct kgsl_clk_stats {
@@ -40,6 +43,17 @@
 	unsigned int elapsed_old;
 };
 
+struct kgsl_pwr_constraint {
+	unsigned int type;
+	unsigned int sub_type;
+	union {
+		struct {
+			unsigned int level;
+		} pwrlevel;
+	} hint;
+	unsigned long expires;
+};
+
 /**
  * struct kgsl_pwrctrl - Power control settings for a KGSL device
  * @interrupt_num - The interrupt number for the device
@@ -67,6 +81,7 @@
  * @bus_control - true if the bus calculation is independent
  * @bus_index - default bus index into the bus_ib table
  * @bus_ib - the set of unique ib requests needed for the bus calculation
+ * @constraint - currently active power constraint
  */
 
 struct kgsl_pwrctrl {
@@ -98,6 +113,7 @@
 	int bus_mod;
 	unsigned int bus_index[KGSL_MAX_PWRLEVELS];
 	uint64_t bus_ib[KGSL_MAX_PWRLEVELS];
+	struct kgsl_pwr_constraint constraint;
 };
 
 void kgsl_pwrctrl_irq(struct kgsl_device *device, int state);
diff --git a/drivers/gpu/msm/kgsl_pwrscale.c b/drivers/gpu/msm/kgsl_pwrscale.c
index 52732cf..b0b1474 100644
--- a/drivers/gpu/msm/kgsl_pwrscale.c
+++ b/drivers/gpu/msm/kgsl_pwrscale.c
@@ -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
@@ -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;
 
@@ -227,10 +227,27 @@
 			kgsl_pwrctrl_buslevel_update(device, true);
 	}
 
-	kgsl_pwrctrl_pwrlevel_change(device, level);
-	*freq = kgsl_pwrctrl_active_freq(pwr);
+	/*
+	 * The power constraints need an entire interval to do their magic, so
+	 * skip changing the powerlevel if the time hasn't expired yet  and the
+	 * new level is less than the constraint
+	 */
+	if ((pwr->constraint.type != KGSL_CONSTRAINT_NONE) &&
+		(!time_after(jiffies, pwr->constraint.expires)) &&
+		(level >= pwr->constraint.hint.pwrlevel.level))
+			*freq = cur_freq;
+	else {
+		/* Change the power level */
+		kgsl_pwrctrl_pwrlevel_change(device, level);
 
-	mutex_unlock(&device->mutex);
+		/*Invalidate the constraint set */
+		pwr->constraint.type = KGSL_CONSTRAINT_NONE;
+		pwr->constraint.expires = 0;
+
+		*freq = kgsl_pwrctrl_active_freq(pwr);
+	}
+
+	kgsl_mutex_unlock(&device->mutex, &device->mutex_owner);
 	return 0;
 }
 EXPORT_SYMBOL(kgsl_devfreq_target);
@@ -257,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;
@@ -285,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;
 }
@@ -308,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_sharedmem.c b/drivers/gpu/msm/kgsl_sharedmem.c
index d031d5e..c8ea471 100644
--- a/drivers/gpu/msm/kgsl_sharedmem.c
+++ b/drivers/gpu/msm/kgsl_sharedmem.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2002,2007-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2002,2007-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
@@ -73,12 +73,12 @@
 _get_priv_from_kobj(struct kobject *kobj)
 {
 	struct kgsl_process_private *private;
-	unsigned long name;
+	unsigned int name;
 
 	if (!kobj)
 		return NULL;
 
-	if (sscanf(kobj->name, "%ld", &name) != 1)
+	if (kstrtou32(kobj->name, 0, &name))
 		return NULL;
 
 	list_for_each_entry(private, &kgsl_driver.process_list, list) {
@@ -255,13 +255,13 @@
 					 const char *buf, size_t count)
 {
 	int ret;
-	unsigned int thresh;
-	ret = sscanf(buf, "%d", &thresh);
-	if (ret != 1)
-		return count;
+	unsigned int thresh = 0;
+
+	ret = kgsl_sysfs_store(buf, &thresh);
+	if (ret)
+		return ret;
 
 	kgsl_driver.full_cache_threshold = thresh;
-
 	return count;
 }
 
@@ -591,7 +591,6 @@
 
 	sglen_alloc = PAGE_ALIGN(size) >> PAGE_SHIFT;
 
-	memdesc->size = size;
 	memdesc->pagetable = pagetable;
 	memdesc->ops = &kgsl_page_alloc_ops;
 
@@ -654,6 +653,14 @@
 				continue;
 			}
 
+			/*
+			 * Update sglen and memdesc size,as requested allocation
+			 * not served fully. So that they can be correctly freed
+			 * in kgsl_sharedmem_free().
+			 */
+			memdesc->sglen = sglen;
+			memdesc->size = (size - len);
+
 			KGSL_CORE_ERR(
 				"Out of memory: only allocated %dKB of %dKB requested\n",
 				(size - len) >> 10, size >> 10);
@@ -670,6 +677,7 @@
 	}
 
 	memdesc->sglen = sglen;
+	memdesc->size = size;
 
 	/*
 	 * All memory that goes to the user has to be zeroed out before it gets
@@ -716,15 +724,15 @@
 	outer_cache_range_op_sg(memdesc->sg, memdesc->sglen,
 				KGSL_CACHE_OP_FLUSH);
 
-	KGSL_STATS_ADD(size, kgsl_driver.stats.page_alloc,
-		kgsl_driver.stats.page_alloc_max);
-
 	order = get_order(size);
 
 	if (order < 16)
 		kgsl_driver.stats.histogram[order]++;
 
 done:
+	KGSL_STATS_ADD(memdesc->size, kgsl_driver.stats.page_alloc,
+		kgsl_driver.stats.page_alloc_max);
+
 	if ((memdesc->sglen_alloc * sizeof(struct page *)) > PAGE_SIZE)
 		vfree(pages);
 	else
diff --git a/drivers/gpu/msm/kgsl_sharedmem.h b/drivers/gpu/msm/kgsl_sharedmem.h
index 505be69..f0114ad 100644
--- a/drivers/gpu/msm/kgsl_sharedmem.h
+++ b/drivers/gpu/msm/kgsl_sharedmem.h
@@ -141,7 +141,7 @@
 
 static inline void *kgsl_sg_alloc(unsigned int sglen)
 {
-	if (sglen >= ULONG_MAX / sizeof(struct scatterlist))
+	if ((sglen == 0) || (sglen >= ULONG_MAX / sizeof(struct scatterlist)))
 		return NULL;
 
 	if ((sglen * sizeof(struct scatterlist)) <  PAGE_SIZE)
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/gud/Makefile b/drivers/gud/Makefile
index ef0e083..c415ad8 100644
--- a/drivers/gud/Makefile
+++ b/drivers/gud/Makefile
@@ -3,34 +3,35 @@
 #
 GUD_ROOT_FOLDER := drivers/gud
 # add our modules to kernel.
-obj-$(CONFIG_MOBICORE_API) += mckernelapi.o
-obj-$(CONFIG_MOBICORE_SUPPORT) += mcdrvmodule.o
+obj-$(CONFIG_MOBICORE_API) += mcKernelApi.o
+obj-$(CONFIG_MOBICORE_SUPPORT) += mcDrvModule.o
 
-mcdrvmodule-objs := mobicore_driver/logging.o \
-		mobicore_driver/ops.o \
-		mobicore_driver/mem.o \
-		mobicore_driver/api.o \
-		mobicore_driver/main.o \
-		mobicore_driver/pm.o
+mcDrvModule-objs := MobiCoreDriver/logging.o \
+		MobiCoreDriver/ops.o \
+		MobiCoreDriver/mem.o \
+		MobiCoreDriver/api.o \
+		MobiCoreDriver/pm.o \
+		MobiCoreDriver/main.o
 
-mckernelapi-objs := mobicore_kernelapi/main.o \
-		mobicore_kernelapi/clientlib.o \
-		mobicore_kernelapi/device.o \
-		mobicore_kernelapi/session.o \
-		mobicore_kernelapi/connection.o
+mcKernelApi-objs := MobiCoreKernelApi/main.o \
+		MobiCoreKernelApi/clientlib.o \
+		MobiCoreKernelApi/device.o \
+		MobiCoreKernelApi/session.o \
+		MobiCoreKernelApi/connection.o
 
 # Release mode by default
-ccflags-y := -DNDEBUG -include $(PWD)/$(GUD_ROOT_FOLDER)/mobicore_driver/build_tag.h
+ccflags-y := -DNDEBUG -I$(GUD_ROOT_FOLDER)
 ccflags-y += -Wno-declaration-after-statement
 
 ccflags-$(CONFIG_MOBICORE_DEBUG) += -DDEBUG
 ccflags-$(CONFIG_MOBICORE_VERBOSE) += -DDEBUG_VERBOSE
 
 # Choose one platform from the folder
-MOBICORE_PLATFORM := $(shell (ls -1 $(PWD)/$(GUD_ROOT_FOLDER)/mobicore_driver/platforms | tail -1) )
+MOBICORE_PLATFORM := $(shell (ls -1 $(PWD)/$(GUD_ROOT_FOLDER)/MobiCoreDriver/platforms | tail -1) )
 # Use the available platform folder
-ccflags-y += -I$(GUD_ROOT_FOLDER)/mobicore_driver/platforms/$(MOBICORE_PLATFORM)
-
-
-ccflags-y += -I$(GUD_ROOT_FOLDER)/mobicore_driver/public
-ccflags-y += -I$(GUD_ROOT_FOLDER)/mobicore_kernelapi/include
+ccflags-y += -I$(GUD_ROOT_FOLDER)/MobiCoreDriver/platforms/$(MOBICORE_PLATFORM)
+# MobiCore Driver includes
+ccflags-y += -I$(GUD_ROOT_FOLDER)/MobiCoreDriver/public
+# MobiCore KernelApi required incldes
+ccflags-y += -I$(GUD_ROOT_FOLDER)/MobiCoreKernelApi/include
+ccflags-y += -I$(GUD_ROOT_FOLDER)/MobiCoreKernelApi/public
diff --git a/drivers/gud/MobiCoreDriver/Makefile b/drivers/gud/MobiCoreDriver/Makefile
new file mode 100644
index 0000000..c17f35e
--- /dev/null
+++ b/drivers/gud/MobiCoreDriver/Makefile
@@ -0,0 +1,26 @@
+#
+# this makefile is called from the kernel make system. Thus we basically
+# add things to "obj-m" here.
+
+ifeq ($(MODE),release)
+    ccflags-y = -O2 -DNDEBUG
+else
+    ccflags-y = -DDEBUG
+endif # DEBUG/RELEASE
+
+# CFLAGS from the build script
+ifdef MOBICORE_CFLAGS
+	ccflags-y += $(MOBICORE_CFLAGS)
+endif
+#EXTRA_CFLAGS+=-DDEBUG_VERBOSE
+
+ccflags-y += -I$(M) -Wall -D__$(PLATFORM)__
+# add our module to kernel.
+obj-m += mcDrvModule.o
+
+mcDrvModule-objs :=logging.o ops.o mem.o api.o pm.o main.o
+
+clean:
+	rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions \
+		Module.markers Module.symvers modules.order
+
diff --git a/drivers/gud/mobicore_driver/api.c b/drivers/gud/MobiCoreDriver/api.c
similarity index 80%
rename from drivers/gud/mobicore_driver/api.c
rename to drivers/gud/MobiCoreDriver/api.c
index b47383a0..e7fa8e2 100644
--- a/drivers/gud/mobicore_driver/api.c
+++ b/drivers/gud/MobiCoreDriver/api.c
@@ -14,23 +14,12 @@
 #include "mem.h"
 #include "debug.h"
 
-
-/*
- * Map a virtual memory buffer structure to Mobicore
- * @param instance
- * @param addr		address of the buffer(NB it must be kernel virtual!)
- * @param len		buffer length
- * @param handle	pointer to handle
- * @param phys_wsm_l2_table	pointer to physical L2 table(?)
- *
- * @return 0 if no error
- *
- */
 int mobicore_map_vmem(struct mc_instance *instance, void *addr,
-	uint32_t len, uint32_t *handle, uint32_t *phys)
+	uint32_t len, uint32_t *handle)
 {
-	return mc_register_wsm_l2(instance, (uint32_t)addr, len,
-		handle, phys);
+	phys_addr_t phys;
+	return mc_register_wsm_mmu(instance, addr, len,
+		handle, &phys);
 }
 EXPORT_SYMBOL(mobicore_map_vmem);
 
@@ -44,7 +33,7 @@
  */
 int mobicore_unmap_vmem(struct mc_instance *instance, uint32_t handle)
 {
-	return mc_unregister_wsm_l2(instance, handle);
+	return mc_unregister_wsm_mmu(instance, handle);
 }
 EXPORT_SYMBOL(mobicore_unmap_vmem);
 
@@ -70,13 +59,11 @@
  * @param requested_size		size of the WSM
  * @param handle		pointer where the handle will be saved
  * @param virt_kernel_addr	pointer for the kernel virtual address
- * @param phys_addr		pointer for the physical address
  *
  * @return error code or 0 for success
  */
 int mobicore_allocate_wsm(struct mc_instance *instance,
-	unsigned long requested_size, uint32_t *handle, void **virt_kernel_addr,
-	void **phys_addr)
+	unsigned long requested_size, uint32_t *handle, void **virt_kernel_addr)
 {
 	struct mc_buffer *buffer = NULL;
 
@@ -85,7 +72,6 @@
 		return -EFAULT;
 
 	*handle = buffer->handle;
-	*phys_addr = buffer->phys;
 	*virt_kernel_addr = buffer->addr;
 	return 0;
 }
@@ -117,3 +103,14 @@
 }
 EXPORT_SYMBOL(mobicore_release);
 
+/*
+ * Test if mobicore can sleep
+ *
+ * @return true if mobicore can sleep, false if it can't sleep
+ */
+bool mobicore_sleep_ready(void)
+{
+	return mc_sleep_ready();
+}
+EXPORT_SYMBOL(mobicore_sleep_ready);
+
diff --git a/drivers/gud/mobicore_driver/arm.h b/drivers/gud/MobiCoreDriver/arm.h
similarity index 100%
rename from drivers/gud/mobicore_driver/arm.h
rename to drivers/gud/MobiCoreDriver/arm.h
diff --git a/drivers/gud/MobiCoreDriver/build.sh b/drivers/gud/MobiCoreDriver/build.sh
new file mode 100644
index 0000000..db8410c
--- /dev/null
+++ b/drivers/gud/MobiCoreDriver/build.sh
@@ -0,0 +1,28 @@
+#!/bin/bash
+
+#  source the setup script
+if [ -z $COMP_PATH_ROOT ]; then
+	echo "The build environment is not set!"
+	echo "Trying to source setupDrivers.sh automatically!"
+	source ../setupDrivers.sh || exit 1
+fi
+
+ROOT_PATH=$(dirname $(readlink -f $0))
+#  These folders need to be relative to the kernel dir or absolute!
+PLATFORM=EXYNOS_5410_STD
+CODE_INCLUDE=$(readlink -f $ROOT_PATH/Locals/Code)
+PLATFORM_INCLUDE="$CODE_INCLUDE/platforms/$PLATFORM"
+MOBICORE_DAEMON=$COMP_PATH_MobiCoreDriverLib/Public
+
+MOBICORE_CFLAGS="-I$MOBICORE_DRIVER/Public -I$MOBICORE_DAEMON -I$COMP_PATH_MobiCore/inc/Mci -I$COMP_PATH_MobiCore/inc -I${PLATFORM_INCLUDE}"
+
+# Clean first
+make -C $CODE_INCLUDE clean
+
+make -C $LINUX_PATH \
+	MODE=$MODE \
+	ARCH=arm \
+	CROSS_COMPILE=$CROSS_COMPILE \
+	M=$CODE_INCLUDE \
+	"MOBICORE_CFLAGS=$MOBICORE_CFLAGS" \
+	modules
diff --git a/drivers/gud/mobicore_driver/debug.h b/drivers/gud/MobiCoreDriver/debug.h
similarity index 89%
rename from drivers/gud/mobicore_driver/debug.h
rename to drivers/gud/MobiCoreDriver/debug.h
index 1f9a632..d29efef 100644
--- a/drivers/gud/mobicore_driver/debug.h
+++ b/drivers/gud/MobiCoreDriver/debug.h
@@ -15,7 +15,7 @@
 extern struct device *mcd;
 
 #define MCDRV_DBG_ERROR(dev, txt, ...) \
-	dev_err(dev, "MobiCore %s() ### ERROR: " txt, \
+	dev_err(dev, "MobiCore %s() ### ERROR: " txt "\n", \
 		__func__, \
 		##__VA_ARGS__)
 
@@ -32,12 +32,12 @@
 #endif
 
 #define MCDRV_DBG(dev, txt, ...) \
-	dev_info(dev, "MobiCore %s(): " txt, \
+	dev_info(dev, "MobiCore %s(): " txt "\n", \
 		 __func__, \
 		 ##__VA_ARGS__)
 
 #define MCDRV_DBG_WARN(dev, txt, ...) \
-	dev_warn(dev, "MobiCore %s() WARNING: " txt, \
+	dev_warn(dev, "MobiCore %s() WARNING: " txt "\n", \
 		 __func__, \
 		 ##__VA_ARGS__)
 
diff --git a/drivers/gud/mobicore_driver/fastcall.h b/drivers/gud/MobiCoreDriver/fastcall.h
similarity index 70%
rename from drivers/gud/mobicore_driver/fastcall.h
rename to drivers/gud/MobiCoreDriver/fastcall.h
index 1c90520..33538df 100644
--- a/drivers/gud/mobicore_driver/fastcall.h
+++ b/drivers/gud/MobiCoreDriver/fastcall.h
@@ -36,9 +36,10 @@
  */
 #define MC_FC_INIT		-1
 #define MC_FC_INFO		-2
-#define MC_FC_POWER		-3
-#define MC_FC_DUMP		-4
 #define MC_FC_NWD_TRACE		-31 /* Mem trace setup fastcall */
+#ifdef TBASE_CORE_SWITCHER
+#define MC_FC_SWITCH_CORE   0x84000005
+#endif
 
 
 /*
@@ -96,6 +97,23 @@
 	} as_out;
 };
 
+#ifdef TBASE_CORE_SWITCHER
+/* fast call switch Core parameters */
+union mc_fc_swich_core {
+	union fc_generic as_generic;
+	struct {
+		uint32_t cmd;
+		uint32_t core_id;
+		uint32_t rfu[2];
+	} as_in;
+	struct {
+		uint32_t resp;
+		uint32_t ret;
+		uint32_t state;
+		uint32_t ext_info;
+	} as_out;
+};
+#endif
 /*
  * _smc() - fast call to MobiCore
  *
@@ -104,23 +122,22 @@
 static inline long _smc(void *data)
 {
 	int ret = 0;
-	union fc_generic fc_generic;
 
 	if (data == NULL)
 		return -EPERM;
 
 #ifdef MC_SMC_FASTCALL
 	{
-		ret = smc_fastcall(data, sizeof(fc_generic));
+		ret = smc_fastcall(data, sizeof(union fc_generic));
 	}
 #else
-	memcpy(&fc_generic, data, sizeof(union fc_generic));
 	{
-		/* SVC expect values in r0-r3 */
-		register u32 reg0 __asm__("r0") = fc_generic.as_in.cmd;
-		register u32 reg1 __asm__("r1") = fc_generic.as_in.param[0];
-		register u32 reg2 __asm__("r2") = fc_generic.as_in.param[1];
-		register u32 reg3 __asm__("r3") = fc_generic.as_in.param[2];
+		union fc_generic *fc_generic = data;
+		/* SMC expect values in r0-r3 */
+		register u32 reg0 __asm__("r0") = fc_generic->as_in.cmd;
+		register u32 reg1 __asm__("r1") = fc_generic->as_in.param[0];
+		register u32 reg2 __asm__("r2") = fc_generic->as_in.param[1];
+		register u32 reg3 __asm__("r3") = fc_generic->as_in.param[2];
 
 		__asm__ volatile (
 #ifdef MC_ARCH_EXTENSION_SEC
@@ -131,13 +148,23 @@
 			"smc 0\n"
 			: "+r"(reg0), "+r"(reg1), "+r"(reg2), "+r"(reg3)
 		);
+#ifdef __ARM_VE_A9X4_QEMU__
+		/* Qemu does not return to the address following the SMC
+		   instruction so we have to insert several nop instructions to
+		   workaround this Qemu bug. */
+		__asm__ volatile (
+		    "nop\n"
+		    "nop\n"
+		    "nop\n"
+		    "nop"
+		 );
+#endif
 
 		/* set response */
-		fc_generic.as_out.resp     = reg0;
-		fc_generic.as_out.ret      = reg1;
-		fc_generic.as_out.param[0] = reg2;
-		fc_generic.as_out.param[1] = reg3;
-		memcpy(data, &fc_generic, sizeof(union fc_generic));
+		fc_generic->as_out.resp     = reg0;
+		fc_generic->as_out.ret      = reg1;
+		fc_generic->as_out.param[0] = reg2;
+		fc_generic->as_out.param[1] = reg3;
 	}
 #endif
 	return ret;
diff --git a/drivers/gud/mobicore_driver/logging.c b/drivers/gud/MobiCoreDriver/logging.c
similarity index 95%
rename from drivers/gud/mobicore_driver/logging.c
rename to drivers/gud/MobiCoreDriver/logging.c
index 1f599f9..507c4ed 100644
--- a/drivers/gud/mobicore_driver/logging.c
+++ b/drivers/gud/MobiCoreDriver/logging.c
@@ -251,7 +251,7 @@
  */
 long mobicore_log_setup(void)
 {
-	unsigned long phys_log_buf;
+	phys_addr_t phys_log_buf;
 	union fc_generic fc_log;
 	struct sched_param param = { .sched_priority = 1 };
 
@@ -300,11 +300,12 @@
 
 	memset(&fc_log, 0, sizeof(fc_log));
 	fc_log.as_in.cmd = MC_FC_NWD_TRACE;
-	fc_log.as_in.param[0] = phys_log_buf;
-	fc_log.as_in.param[1] = log_size;
+	fc_log.as_in.param[0] = (uint32_t)phys_log_buf;
+	fc_log.as_in.param[1] = (uint32_t)(((uint64_t)phys_log_buf) >> 32);
+	fc_log.as_in.param[2] = log_size;
 
-	MCDRV_DBG(mcd, "fc_log virt=%p phys=%p ",
-		  log_buf, (void *)phys_log_buf);
+	MCDRV_DBG(mcd, "fc_log virt=%p phys=0x%llX",
+		  log_buf, (u64)phys_log_buf);
 	mc_fastcall(&fc_log);
 	MCDRV_DBG(mcd, "fc_log out ret=0x%08x", fc_log.as_out.ret);
 
@@ -319,7 +320,7 @@
 
 	set_task_state(log_thread, TASK_INTERRUPTIBLE);
 
-	MCDRV_DBG(mcd, "fc_log Logger version %u\n", log_buf->version);
+	MCDRV_DBG(mcd, "fc_log Logger version %u", log_buf->version);
 	return 0;
 
 err_stop_kthread:
diff --git a/drivers/gud/mobicore_driver/logging.h b/drivers/gud/MobiCoreDriver/logging.h
similarity index 100%
rename from drivers/gud/mobicore_driver/logging.h
rename to drivers/gud/MobiCoreDriver/logging.h
diff --git a/drivers/gud/mobicore_driver/main.c b/drivers/gud/MobiCoreDriver/main.c
similarity index 81%
rename from drivers/gud/mobicore_driver/main.c
rename to drivers/gud/MobiCoreDriver/main.c
index 0451452..ed2928a 100644
--- a/drivers/gud/mobicore_driver/main.c
+++ b/drivers/gud/MobiCoreDriver/main.c
@@ -112,12 +112,12 @@
 	int i;
 	struct page *page = virt_to_page(addr);
 	for (i = 0; i < (1<<order); i++) {
-		MCDRV_DBG_VERBOSE(mcd, "free page at 0x%p\n", page);
-		ClearPageReserved(page);
+		MCDRV_DBG_VERBOSE(mcd, "free page at 0x%p", page);
+		clear_bit(PG_reserved, &page->flags);
 		page++;
 	}
 
-	MCDRV_DBG_VERBOSE(mcd, "freeing addr:%p, order:%x\n", addr, order);
+	MCDRV_DBG_VERBOSE(mcd, "freeing addr:%p, order:%x", addr, order);
 	free_pages((unsigned long)addr, order);
 }
 
@@ -131,8 +131,9 @@
 		return -EINVAL;
 
 	MCDRV_DBG_VERBOSE(mcd,
-			  "handle=%u phys_addr=0x%p, virt_addr=0x%p len=%u\n",
-		  buffer->handle, buffer->phys, buffer->addr, buffer->len);
+			  "handle=%u phys_addr=0x%llx, virt_addr=0x%p len=%u",
+		  buffer->handle, (u64)buffer->phys,
+		  buffer->addr, buffer->len);
 
 	if (!atomic_dec_and_test(&buffer->usage)) {
 		MCDRV_DBG_VERBOSE(mcd, "Could not free %u", buffer->handle);
@@ -147,7 +148,7 @@
 }
 
 static uint32_t mc_find_cont_wsm_addr(struct mc_instance *instance, void *uaddr,
-	uint32_t *addr, uint32_t len)
+	void **addr, uint32_t len)
 {
 	int ret = 0;
 	struct mc_buffer *buffer;
@@ -162,7 +163,7 @@
 	/* search for the given handle in the buffers list */
 	list_for_each_entry(buffer, &ctx.cont_bufs, list) {
 		if (buffer->uaddr == uaddr && buffer->len == len) {
-			*addr = (uint32_t)buffer->addr;
+			*addr = buffer->addr;
 			goto found;
 		}
 	}
@@ -186,7 +187,7 @@
 	struct task_struct *peer = NULL;
 	bool ret = false;
 
-	MCDRV_DBG(mcd, "Finding wsm for fd = %d\n", fd);
+	MCDRV_DBG_VERBOSE(mcd, "Finding wsm for fd = %d", fd);
 	if (!instance)
 		return false;
 
@@ -197,7 +198,7 @@
 	s = __get_socket(fp);
 	if (s) {
 		peer = get_pid_task(s->sk_peer_pid, PIDTYPE_PID);
-		MCDRV_DBG(mcd, "Found pid for fd %d\n", peer->pid);
+		MCDRV_DBG_VERBOSE(mcd, "Found pid for fd %d", peer->pid);
 	}
 	if (peer) {
 		task_lock(peer);
@@ -209,11 +210,10 @@
 			if (!fp)
 				continue;
 			if (fp->private_data == instance) {
-				MCDRV_DBG(mcd, "Found owner!");
+				MCDRV_DBG_VERBOSE(mcd, "Found owner!");
 				ret = true;
 				goto out;
 			}
-
 		}
 	} else {
 		MCDRV_DBG(mcd, "Owner not found!");
@@ -230,7 +230,7 @@
 #endif
 }
 static uint32_t mc_find_cont_wsm(struct mc_instance *instance, uint32_t handle,
-	int32_t fd, uint32_t *phys, uint32_t *len)
+	int32_t fd, phys_addr_t *phys, uint32_t *len)
 {
 	int ret = 0;
 	struct mc_buffer *buffer;
@@ -239,7 +239,7 @@
 		return -EFAULT;
 
 	if (WARN_ON(!is_daemon(instance))) {
-		MCDRV_DBG_ERROR(mcd, "caller not MobiCore Daemon\n");
+		MCDRV_DBG_ERROR(mcd, "caller not MobiCore Daemon");
 		return -EPERM;
 	}
 
@@ -251,7 +251,7 @@
 	list_for_each_entry(buffer, &ctx.cont_bufs, list) {
 		if (buffer->handle == handle) {
 			if (mc_check_owner_fd(buffer->instance, fd)) {
-				*phys = (uint32_t)buffer->phys;
+				*phys = buffer->phys;
 				*len = buffer->len;
 				goto found;
 			} else {
@@ -326,7 +326,7 @@
 			/* Something is not right if we end up here, better not
 			 * clean the buffer so we just leak memory instead of
 			 * creating security issues */
-			MCDRV_DBG_ERROR(mcd, "Memory can't be unmapped\n");
+			MCDRV_DBG_ERROR(mcd, "Memory can't be unmapped");
 			return -EINVAL;
 		}
 	}
@@ -370,7 +370,7 @@
 {
 	struct mc_buffer *cbuffer = NULL;
 	void *addr = 0;
-	void *phys = 0;
+	phys_addr_t phys = 0;
 	unsigned int order;
 	unsigned long allocated_size;
 	int ret = 0;
@@ -379,13 +379,13 @@
 		return -EFAULT;
 
 	if (len == 0) {
-		MCDRV_DBG_WARN(mcd, "cannot allocate size 0\n");
+		MCDRV_DBG_WARN(mcd, "cannot allocate size 0");
 		return -ENOMEM;
 	}
 
 	order = get_order(len);
 	if (order > MAX_ORDER) {
-		MCDRV_DBG_WARN(mcd, "Buffer size too large\n");
+		MCDRV_DBG_WARN(mcd, "Buffer size too large");
 		return -ENOMEM;
 	}
 	allocated_size = (1 << order) * PAGE_SIZE;
@@ -398,23 +398,23 @@
 
 	if (cbuffer == NULL) {
 		MCDRV_DBG_WARN(mcd,
-			       "MMAP_WSM request: could not allocate buffer\n");
+			       "MMAP_WSM request: could not allocate buffer");
 		ret = -ENOMEM;
 		goto unlock_instance;
 	}
 	mutex_lock(&ctx.bufs_lock);
 
-	MCDRV_DBG_VERBOSE(mcd, "size %ld -> order %d --> %ld (2^n pages)\n",
+	MCDRV_DBG_VERBOSE(mcd, "size %ld -> order %d --> %ld (2^n pages)",
 			  len, order, allocated_size);
 
 	addr = (void *)__get_free_pages(GFP_USER | __GFP_ZERO, order);
 
 	if (addr == NULL) {
-		MCDRV_DBG_WARN(mcd, "get_free_pages failed\n");
+		MCDRV_DBG_WARN(mcd, "get_free_pages failed");
 		ret = -ENOMEM;
 		goto err;
 	}
-	phys = (void *)virt_to_phys(addr);
+	phys = virt_to_phys(addr);
 	cbuffer->handle = get_unique_id();
 	cbuffer->phys = phys;
 	cbuffer->addr = addr;
@@ -429,9 +429,11 @@
 	list_add(&cbuffer->list, &ctx.cont_bufs);
 
 	MCDRV_DBG_VERBOSE(mcd,
-			  "allocated phys=0x%p - 0x%p, size=%ld, kvirt=0x%p, h=%d\n",
-		  phys, (void *)((unsigned int)phys+allocated_size),
-		  allocated_size, addr, cbuffer->handle);
+			  "allocated phys=0x%llx - 0x%llx, size=%ld, kvirt=0x%p"
+			  ", h=%d",
+			  (u64)phys,
+			  (u64)(phys+allocated_size),
+			  allocated_size, addr, cbuffer->handle);
 	*buffer = cbuffer;
 	goto unlock;
 
@@ -457,7 +459,7 @@
 		return -EFAULT;
 
 	if (WARN_ON(!is_daemon(instance))) {
-		MCDRV_DBG_ERROR(mcd, "caller not MobiCore Daemon\n");
+		MCDRV_DBG_ERROR(mcd, "caller not MobiCore Daemon");
 		return -EPERM;
 	}
 
@@ -476,7 +478,7 @@
 	return ret;
 }
 
-void *get_mci_base_phys(unsigned int len)
+static phys_addr_t get_mci_base_phys(unsigned int len)
 {
 	if (ctx.mci_base.phys) {
 		return ctx.mci_base.phys;
@@ -487,45 +489,45 @@
 		ctx.mci_base.addr =
 			(void *)__get_free_pages(GFP_USER | __GFP_ZERO, order);
 		if (ctx.mci_base.addr == NULL) {
-			MCDRV_DBG_WARN(mcd, "get_free_pages failed\n");
+			MCDRV_DBG_WARN(mcd, "get_free_pages failed");
 			memset(&ctx.mci_base, 0, sizeof(ctx.mci_base));
-			return NULL;
+			return 0;
 		}
-		ctx.mci_base.phys = (void *)virt_to_phys(ctx.mci_base.addr);
+		ctx.mci_base.phys = virt_to_phys(ctx.mci_base.addr);
 		return ctx.mci_base.phys;
 	}
 }
 
 /*
- * Create a l2 table from a virtual memory buffer which can be vmalloc
+ * Create a MMU table from a virtual memory buffer which can be vmalloc
  * or user space virtual memory
  */
-int mc_register_wsm_l2(struct mc_instance *instance,
-	uint32_t buffer, uint32_t len,
-	uint32_t *handle, uint32_t *phys)
+int mc_register_wsm_mmu(struct mc_instance *instance,
+	void *buffer, uint32_t len,
+	uint32_t *handle, phys_addr_t *phys)
 {
 	int ret = 0;
-	struct mc_l2_table *table = NULL;
+	struct mc_mmu_table *table = NULL;
 	struct task_struct *task = current;
-	uint32_t kbuff = 0x0;
+	void *kbuff = NULL;
 
 	if (WARN(!instance, "No instance data available"))
 		return -EFAULT;
 
 	if (len == 0) {
-		MCDRV_DBG_ERROR(mcd, "len=0 is not supported!\n");
+		MCDRV_DBG_ERROR(mcd, "len=0 is not supported!");
 		return -EINVAL;
 	}
 
-	MCDRV_DBG_VERBOSE(mcd, "buffer: %p, len=%08x\n", (void *)buffer, len);
+	MCDRV_DBG_VERBOSE(mcd, "buffer: %p, len=%08x", buffer, len);
 
-	if (!mc_find_cont_wsm_addr(instance, (void *)buffer, &kbuff, len))
-		table = mc_alloc_l2_table(instance, NULL, (void *)kbuff, len);
+	if (!mc_find_cont_wsm_addr(instance, buffer, &kbuff, len))
+		table = mc_alloc_mmu_table(instance, NULL, kbuff, len);
 	else
-		table = mc_alloc_l2_table(instance, task, (void *)buffer, len);
+		table = mc_alloc_mmu_table(instance, task, buffer, len);
 
 	if (IS_ERR(table)) {
-		MCDRV_DBG_ERROR(mcd, "new_used_l2_table() failed\n");
+		MCDRV_DBG_ERROR(mcd, "mc_alloc_mmu_table() failed");
 		return -EINVAL;
 	}
 
@@ -533,19 +535,19 @@
 	*handle = table->handle;
 	/* WARNING: daemon shouldn't know this either, but live with it */
 	if (is_daemon(instance))
-		*phys = (uint32_t)table->phys;
+		*phys = table->phys;
 	else
 		*phys = 0;
 
-	MCDRV_DBG_VERBOSE(mcd, "handle: %d, phys=%p\n",
-			  *handle, (void *)*phys);
+	MCDRV_DBG_VERBOSE(mcd, "handle: %d, phys=0x%llX",
+			  *handle, (u64)(*phys));
 
-	MCDRV_DBG_VERBOSE(mcd, "exit with %d/0x%08X\n", ret, ret);
+	MCDRV_DBG_VERBOSE(mcd, "exit with %d/0x%08X", ret, ret);
 
 	return ret;
 }
 
-int mc_unregister_wsm_l2(struct mc_instance *instance, uint32_t handle)
+int mc_unregister_wsm_mmu(struct mc_instance *instance, uint32_t handle)
 {
 	int ret = 0;
 
@@ -553,11 +555,11 @@
 		return -EFAULT;
 
 	/* free table (if no further locks exist) */
-	mc_free_l2_table(instance, handle);
+	mc_free_mmu_table(instance, handle);
 
 	return ret;
 }
-/* Lock the object from handle, it could be a WSM l2 table or a cont buffer! */
+/* Lock the object from handle, it could be a WSM MMU table or a cont buffer! */
 static int mc_lock_handle(struct mc_instance *instance, uint32_t handle)
 {
 	int ret = 0;
@@ -566,14 +568,14 @@
 		return -EFAULT;
 
 	if (WARN_ON(!is_daemon(instance))) {
-		MCDRV_DBG_ERROR(mcd, "caller not MobiCore Daemon\n");
+		MCDRV_DBG_ERROR(mcd, "caller not MobiCore Daemon");
 		return -EPERM;
 	}
 
 	mutex_lock(&instance->lock);
-	ret = mc_lock_l2_table(instance, handle);
+	ret = mc_lock_mmu_table(instance, handle);
 
-	/* Handle was not a l2 table but a cont buffer */
+	/* Handle was not a MMU table but a cont buffer */
 	if (ret == -EINVAL) {
 		/* Call the non locking variant! */
 		ret = __lock_buffer(instance, handle);
@@ -592,14 +594,14 @@
 		return -EFAULT;
 
 	if (WARN_ON(!is_daemon(instance))) {
-		MCDRV_DBG_ERROR(mcd, "caller not MobiCore Daemon\n");
+		MCDRV_DBG_ERROR(mcd, "caller not MobiCore Daemon");
 		return -EPERM;
 	}
 
 	mutex_lock(&instance->lock);
-	ret = mc_free_l2_table(instance, handle);
+	ret = mc_free_mmu_table(instance, handle);
 
-	/* Not a l2 table, then it must be a buffer */
+	/* Not a MMU table, then it must be a buffer */
 	if (ret == -EINVAL) {
 		/* Call the non locking variant! */
 		ret = __free_buffer(instance, handle, true);
@@ -609,35 +611,31 @@
 	return ret;
 }
 
-static uint32_t mc_find_wsm_l2(struct mc_instance *instance,
+static phys_addr_t mc_find_wsm_mmu(struct mc_instance *instance,
 	uint32_t handle, int32_t fd)
 {
-	uint32_t ret = 0;
-
 	if (WARN(!instance, "No instance data available"))
 		return 0;
 
 	if (WARN_ON(!is_daemon(instance))) {
-		MCDRV_DBG_ERROR(mcd, "caller not MobiCore Daemon\n");
+		MCDRV_DBG_ERROR(mcd, "caller not MobiCore Daemon");
 		return 0;
 	}
 
-	ret = mc_find_l2_table(handle, fd);
-
-	return ret;
+	return mc_find_mmu_table(handle, fd);
 }
 
-static int mc_clean_wsm_l2(struct mc_instance *instance)
+static int mc_clean_wsm_mmu(struct mc_instance *instance)
 {
 	if (WARN(!instance, "No instance data available"))
 		return -EFAULT;
 
 	if (WARN_ON(!is_daemon(instance))) {
-		MCDRV_DBG_ERROR(mcd, "caller not MobiCore Daemon\n");
+		MCDRV_DBG_ERROR(mcd, "caller not MobiCore Daemon");
 		return -EPERM;
 	}
 
-	mc_clean_l2_tables();
+	mc_clean_mmu_tables();
 
 	return 0;
 }
@@ -646,19 +644,20 @@
 {
 	struct mc_instance *instance = get_instance(file);
 	unsigned long len = vmarea->vm_end - vmarea->vm_start;
-	void *paddr = (void *)(vmarea->vm_pgoff << PAGE_SHIFT);
+	phys_addr_t paddr = (vmarea->vm_pgoff << PAGE_SHIFT);
 	unsigned int pfn;
 	struct mc_buffer *buffer = 0;
 	int ret = 0;
 
-	MCDRV_DBG_VERBOSE(mcd, "enter (vma start=0x%p, size=%ld, mci=%p)\n",
-			  (void *)vmarea->vm_start, len, ctx.mci_base.phys);
+	MCDRV_DBG_VERBOSE(mcd, "enter (vma start=0x%p, size=%ld, mci=0x%llX)",
+			  (void *)vmarea->vm_start, len,
+			  (u64)ctx.mci_base.phys);
 
 	if (WARN(!instance, "No instance data available"))
 		return -EFAULT;
 
 	if (len == 0) {
-		MCDRV_DBG_ERROR(mcd, "cannot allocate size 0\n");
+		MCDRV_DBG_ERROR(mcd, "cannot allocate size 0");
 		return -ENOMEM;
 	}
 	if (paddr) {
@@ -722,7 +721,7 @@
 			vmarea->vm_page_prot);
 	}
 
-	MCDRV_DBG_VERBOSE(mcd, "exit with %d/0x%08X\n", ret, ret);
+	MCDRV_DBG_VERBOSE(mcd, "exit with %d/0x%08X", ret, ret);
 
 	return ret;
 }
@@ -768,21 +767,24 @@
 
 	case MC_IO_REG_WSM:{
 		struct mc_ioctl_reg_wsm reg;
+		phys_addr_t phys;
 		if (copy_from_user(&reg, uarg, sizeof(reg)))
 			return -EFAULT;
 
-		ret = mc_register_wsm_l2(instance, reg.buffer,
-			reg.len, &reg.handle, &reg.table_phys);
+		ret = mc_register_wsm_mmu(instance, (void *)reg.buffer,
+			reg.len, &reg.handle, &phys);
+		reg.table_phys = phys;
+
 		if (!ret) {
 			if (copy_to_user(uarg, &reg, sizeof(reg))) {
 				ret = -EFAULT;
-				mc_unregister_wsm_l2(instance, reg.handle);
+				mc_unregister_wsm_mmu(instance, reg.handle);
 			}
 		}
 		break;
 	}
 	case MC_IO_UNREG_WSM:
-		ret = mc_unregister_wsm_l2(instance, (uint32_t)arg);
+		ret = mc_unregister_wsm_mmu(instance, (uint32_t)arg);
 		break;
 
 	case MC_IO_VERSION:
@@ -803,7 +805,7 @@
 			return -EFAULT;
 
 		map.handle = buffer->handle;
-		map.phys_addr = (unsigned long)buffer->phys;
+		map.phys_addr = buffer->phys;
 		map.reused = 0;
 		if (copy_to_user(uarg, &map, sizeof(map)))
 			ret = -EFAULT;
@@ -812,7 +814,7 @@
 		break;
 	}
 	default:
-		MCDRV_DBG_ERROR(mcd, "unsupported cmd=%d\n", cmd);
+		MCDRV_DBG_ERROR(mcd, "unsupported cmd=0x%x", cmd);
 		ret = -ENOIOCTLCMD;
 		break;
 
@@ -836,7 +838,7 @@
 		return -EFAULT;
 
 	if (WARN_ON(!is_daemon(instance))) {
-		MCDRV_DBG_ERROR(mcd, "caller not MobiCore Daemon\n");
+		MCDRV_DBG_ERROR(mcd, "caller not MobiCore Daemon");
 		return -EPERM;
 	}
 
@@ -856,8 +858,8 @@
 			return -EFAULT;
 
 		ctx.mcp = ctx.mci_base.addr + init.mcp_offset;
-		ret = mc_init((uint32_t)ctx.mci_base.phys, init.nq_offset,
-			init.nq_length, init.mcp_offset, init.mcp_length);
+		ret = mc_init(ctx.mci_base.phys, init.nq_length,
+			init.mcp_offset, init.mcp_length);
 		break;
 	}
 	case MC_IO_INFO: {
@@ -890,14 +892,14 @@
 		ret = mc_unlock_handle(instance, (uint32_t)arg);
 		break;
 	case MC_IO_CLEAN_WSM:
-		ret = mc_clean_wsm_l2(instance);
+		ret = mc_clean_wsm_mmu(instance);
 		break;
 	case MC_IO_RESOLVE_WSM: {
-		uint32_t phys;
+		phys_addr_t phys;
 		struct mc_ioctl_resolv_wsm wsm;
 		if (copy_from_user(&wsm, uarg, sizeof(wsm)))
 			return -EFAULT;
-		phys = mc_find_wsm_l2(instance, wsm.handle, wsm.fd);
+		phys = mc_find_wsm_mmu(instance, wsm.handle, wsm.fd);
 		if (!phys)
 			return -EINVAL;
 
@@ -909,7 +911,8 @@
 	}
 	case MC_IO_RESOLVE_CONT_WSM: {
 		struct mc_ioctl_resolv_cont_wsm cont_wsm;
-		uint32_t phys = 0, len = 0;
+		phys_addr_t phys = 0;
+		uint32_t len = 0;
 		if (copy_from_user(&cont_wsm, uarg, sizeof(cont_wsm)))
 			return -EFAULT;
 		ret = mc_find_cont_wsm(instance, cont_wsm.handle, cont_wsm.fd,
@@ -928,7 +931,7 @@
 			return -EFAULT;
 
 		map.reused = (ctx.mci_base.phys != 0);
-		map.phys_addr = (unsigned long)get_mci_base_phys(map.len);
+		map.phys_addr = get_mci_base_phys(map.len);
 		if (!map.phys_addr) {
 			MCDRV_DBG_ERROR(mcd, "Failed to setup MCI buffer!");
 			return -EFAULT;
@@ -939,10 +942,6 @@
 		ret = 0;
 		break;
 	}
-	case MC_IO_MAP_PWSM:{
-		break;
-	}
-
 	case MC_IO_LOG_SETUP: {
 #ifdef MC_MEM_TRACES
 		ret = mobicore_log_setup();
@@ -985,27 +984,27 @@
 		return -EFAULT;
 
 	/* avoid debug output on non-error, because this is call quite often */
-	MCDRV_DBG_VERBOSE(mcd, "enter\n");
+	MCDRV_DBG_VERBOSE(mcd, "enter");
 
 	/* only the MobiCore Daemon is allowed to call this function */
 	if (WARN_ON(!is_daemon(instance))) {
-		MCDRV_DBG_ERROR(mcd, "caller not MobiCore Daemon\n");
+		MCDRV_DBG_ERROR(mcd, "caller not MobiCore Daemon");
 		return -EPERM;
 	}
 
 	if (buffer_len < sizeof(unsigned int)) {
-		MCDRV_DBG_ERROR(mcd, "invalid length\n");
+		MCDRV_DBG_ERROR(mcd, "invalid length");
 		return -EINVAL;
 	}
 
 	for (;;) {
 		if (wait_for_completion_interruptible(&ctx.isr_comp)) {
-			MCDRV_DBG_VERBOSE(mcd, "read interrupted\n");
+			MCDRV_DBG_VERBOSE(mcd, "read interrupted");
 			return -ERESTARTSYS;
 		}
 
 		ssiq_counter = atomic_read(&ctx.isr_counter);
-		MCDRV_DBG_VERBOSE(mcd, "ssiq_counter=%i, ctx.counter=%i\n",
+		MCDRV_DBG_VERBOSE(mcd, "ssiq_counter=%i, ctx.counter=%i",
 				  ssiq_counter, ctx.evt_counter);
 
 		if (ssiq_counter != ctx.evt_counter) {
@@ -1017,12 +1016,12 @@
 
 		/* end loop if non-blocking */
 		if (file->f_flags & O_NONBLOCK) {
-			MCDRV_DBG_ERROR(mcd, "non-blocking read\n");
+			MCDRV_DBG_ERROR(mcd, "non-blocking read");
 			return -EAGAIN;
 		}
 
 		if (signal_pending(current)) {
-			MCDRV_DBG_VERBOSE(mcd, "received signal.\n");
+			MCDRV_DBG_VERBOSE(mcd, "received signal.");
 			return -ERESTARTSYS;
 		}
 	}
@@ -1031,7 +1030,7 @@
 	ret = copy_to_user(buffer, &ctx.evt_counter, sizeof(unsigned int));
 
 	if (ret != 0) {
-		MCDRV_DBG_ERROR(mcd, "copy_to_user failed\n");
+		MCDRV_DBG_ERROR(mcd, "copy_to_user failed");
 		return -EFAULT;
 	}
 
@@ -1061,6 +1060,43 @@
 	return instance;
 }
 
+#if defined(TBASE_CORE_SWITCHER) && defined(DEBUG)
+static ssize_t mc_fd_write(struct file *file, const char __user *buffer,
+			size_t buffer_len, loff_t *x)
+{
+	uint32_t cpu_new;
+	/* we only consider one digit */
+	char buf[2];
+	struct mc_instance *instance = get_instance(file);
+
+	if (WARN(!instance, "No instance data available"))
+		return -EFAULT;
+
+	/* Invalid data, nothing to do */
+	if (buffer_len < 1)
+		return -EINVAL;
+
+	/* Invalid data, nothing to do */
+	if (copy_from_user(buf, buffer, min(sizeof(buf), buffer_len)))
+		return -EFAULT;
+
+	if (buf[0] == 'n') {
+		mc_nsiq();
+	/* If it's a digit then switch cores */
+	} else if ((buf[0] >= '0') && (buf[0] <= '9')) {
+		cpu_new = buf[0] - '0';
+		if (cpu_new <= 8) {
+			MCDRV_DBG_VERBOSE(mcd, "Set Active Cpu: %d\n", cpu_new);
+			mc_switch_core(cpu_new);
+		}
+	} else {
+		return -EINVAL;
+	}
+
+	return buffer_len;
+}
+#endif
+
 /*
  * Release a mobicore instance object and all objects related to it
  * @instance:	instance
@@ -1074,7 +1110,7 @@
 		return -EFAULT;
 
 	mutex_lock(&instance->lock);
-	mc_clear_l2_tables(instance);
+	mc_clear_mmu_tables(instance);
 
 	mutex_lock(&ctx.bufs_lock);
 	/* release all mapped data */
@@ -1112,7 +1148,7 @@
 {
 	struct mc_instance *instance;
 
-	MCDRV_DBG_VERBOSE(mcd, "enter\n");
+	MCDRV_DBG_VERBOSE(mcd, "enter");
 
 	instance = mc_alloc_instance();
 	if (instance == NULL)
@@ -1141,7 +1177,7 @@
 		return -ENOMEM;
 	instance = get_instance(file);
 
-	MCDRV_DBG(mcd, "accept this as MobiCore Daemon\n");
+	MCDRV_DBG(mcd, "accept this as MobiCore Daemon");
 
 	ctx.daemon_inst = instance;
 	ctx.daemon = current;
@@ -1172,7 +1208,7 @@
 
 	/* check if daemon closes us. */
 	if (is_daemon(instance)) {
-		MCDRV_DBG_WARN(mcd, "WARNING: MobiCore Daemon died\n");
+		MCDRV_DBG_WARN(mcd, "MobiCore Daemon died");
 		ctx.daemon_inst = NULL;
 		ctx.daemon = NULL;
 	}
@@ -1183,7 +1219,7 @@
 	 * ret is quite irrelevant here as most apps don't care about the
 	 * return value from close() and it's quite difficult to recover
 	 */
-	MCDRV_DBG_VERBOSE(mcd, "exit with %d/0x%08X\n", ret, ret);
+	MCDRV_DBG_VERBOSE(mcd, "exit with %d/0x%08X", ret, ret);
 
 	return (int)ret;
 }
@@ -1200,7 +1236,9 @@
 
 	/* signal the daemon */
 	complete(&ctx.isr_comp);
-
+#ifdef MC_MEM_TRACES
+	mobicore_log_read();
+#endif
 	return IRQ_HANDLED;
 }
 
@@ -1221,6 +1259,9 @@
 	.release	= mc_fd_release,
 	.unlocked_ioctl	= mc_fd_user_ioctl,
 	.mmap		= mc_fd_mmap,
+#if defined(TBASE_CORE_SWITCHER) && defined(DEBUG)
+	.write          = mc_fd_write,
+#endif
 };
 
 static int create_devices(void)
@@ -1239,17 +1280,17 @@
 
 	ret = alloc_chrdev_region(&mc_dev_admin, 0, MC_DEV_MAX, "mobicore");
 	if (ret < 0) {
-		MCDRV_DBG_ERROR(mcd, "failed to allocate char dev region\n");
+		MCDRV_DBG_ERROR(mcd, "failed to allocate char dev region");
 		goto error;
 	}
 	mc_dev_user = MKDEV(MAJOR(mc_dev_admin), 1);
 
-	MCDRV_DBG_VERBOSE(mcd, "%s: dev %d", "mobicore", MAJOR(mc_dev_region));
+	MCDRV_DBG_VERBOSE(mcd, "%s: dev %d", "mobicore", MAJOR(mc_dev_admin));
 
 	/* First the ADMIN node */
 	ret = cdev_add(&mc_admin_cdev,  mc_dev_admin, 1);
 	if (ret != 0) {
-		MCDRV_DBG_ERROR(mcd, "admin device register failed\n");
+		MCDRV_DBG_ERROR(mcd, "admin device register failed");
 		goto error;
 	}
 	mc_admin_cdev.owner = THIS_MODULE;
@@ -1260,7 +1301,7 @@
 
 	ret = cdev_add(&mc_user_cdev, mc_dev_user, 1);
 	if (ret != 0) {
-		MCDRV_DBG_ERROR(mcd, "user device register failed\n");
+		MCDRV_DBG_ERROR(mcd, "user device register failed");
 		goto error_unregister;
 	}
 	mc_user_cdev.owner = THIS_MODULE;
@@ -1301,13 +1342,13 @@
 	/* Hardware does not support ARM TrustZone -> Cannot continue! */
 	if (!has_security_extensions()) {
 		MCDRV_DBG_ERROR(mcd,
-				"Hardware doesn't support ARM TrustZone!\n");
+				"Hardware doesn't support ARM TrustZone!");
 		return -ENODEV;
 	}
 
 	/* Running in secure mode -> Cannot load the driver! */
 	if (is_secure_mode()) {
-		MCDRV_DBG_ERROR(mcd, "Running in secure MODE!\n");
+		MCDRV_DBG_ERROR(mcd, "Running in secure MODE!");
 		return -ENODEV;
 	}
 
@@ -1320,18 +1361,18 @@
 	/* initialize event counter for signaling of an IRQ to zero */
 	atomic_set(&ctx.isr_counter, 0);
 
-	/* set up S-SIQ interrupt handler */
+	/* set up S-SIQ interrupt handler ************************/
 	ret = request_irq(MC_INTR_SSIQ, mc_ssiq_isr, IRQF_TRIGGER_RISING,
 			MC_ADMIN_DEVNODE, &ctx);
 	if (ret != 0) {
-		MCDRV_DBG_ERROR(mcd, "interrupt request failed\n");
+		MCDRV_DBG_ERROR(mcd, "interrupt request failed");
 		goto err_req_irq;
 	}
 
 #ifdef MC_PM_RUNTIME
 	ret = mc_pm_initialize(&ctx);
 	if (ret != 0) {
-		MCDRV_DBG_ERROR(mcd, "Power Management init failed!\n");
+		MCDRV_DBG_ERROR(mcd, "Power Management init failed!");
 		goto free_isr;
 	}
 #endif
@@ -1340,7 +1381,7 @@
 	if (ret != 0)
 		goto free_pm;
 
-	ret = mc_init_l2_tables();
+	ret = mc_init_mmu_tables();
 
 #ifdef MC_CRYPTO_CLOCK_MANAGEMENT
 	ret = mc_pm_clock_initialize();
@@ -1361,7 +1402,7 @@
 	mutex_init(&ctx.bufs_lock);
 
 	memset(&ctx.mci_base, 0, sizeof(ctx.mci_base));
-	MCDRV_DBG(mcd, "initialized\n");
+	MCDRV_DBG(mcd, "initialized");
 	return 0;
 
 free_pm:
@@ -1381,12 +1422,12 @@
  */
 static void __exit mobicore_exit(void)
 {
-	MCDRV_DBG_VERBOSE(mcd, "enter\n");
+	MCDRV_DBG_VERBOSE(mcd, "enter");
 #ifdef MC_MEM_TRACES
 	mobicore_log_free();
 #endif
 
-	mc_release_l2_tables();
+	mc_release_mmu_tables();
 
 #ifdef MC_PM_RUNTIME
 	mc_pm_free();
@@ -1408,6 +1449,15 @@
 	MCDRV_DBG_VERBOSE(mcd, "exit");
 }
 
+bool mc_sleep_ready(void)
+{
+#ifdef MC_PM_RUNTIME
+	return mc_pm_sleep_ready();
+#else
+	return true;
+#endif
+}
+
 /* Linux Driver Module Macros */
 module_init(mobicore_init);
 module_exit(mobicore_exit);
diff --git a/drivers/gud/mobicore_driver/main.h b/drivers/gud/MobiCoreDriver/main.h
similarity index 89%
rename from drivers/gud/mobicore_driver/main.h
rename to drivers/gud/MobiCoreDriver/main.h
index 871191e..11e304c 100644
--- a/drivers/gud/mobicore_driver/main.h
+++ b/drivers/gud/MobiCoreDriver/main.h
@@ -52,7 +52,7 @@
 	/* virtual Userspace start address */
 	void			*uaddr;
 	/* physical start address */
-	void			*phys;
+	phys_addr_t		phys;
 	/* order of number of pages */
 	unsigned int		order;
 	uint32_t		len;
@@ -83,8 +83,8 @@
 };
 
 struct mc_sleep_mode {
-	uint16_t	SleepReq;
-	uint16_t	ReadyToSleep;
+	uint16_t	sleep_req;
+	uint16_t	ready_to_sleep;
 };
 
 /* MobiCore is idle. No scheduling required. */
@@ -129,14 +129,14 @@
 int mc_release_instance(struct mc_instance *instance);
 
 /*
- * mc_register_wsm_l2() - Create a L2 table from a virtual memory buffer which
+ * mc_register_wsm_mmu() - Create a MMU table from a virtual memory buffer which
  * can be vmalloc or user space virtual memory
  */
-int mc_register_wsm_l2(struct mc_instance *instance,
-	uint32_t buffer, uint32_t len,
-	uint32_t *handle, uint32_t *phys);
+int mc_register_wsm_mmu(struct mc_instance *instance,
+	void *buffer, uint32_t len,
+	uint32_t *handle, phys_addr_t *phys);
 /* Unregister the buffer mapped above */
-int mc_unregister_wsm_l2(struct mc_instance *instance, uint32_t handle);
+int mc_unregister_wsm_mmu(struct mc_instance *instance, uint32_t handle);
 
 /* Allocate one mc_buffer of contiguous space */
 int mc_get_buffer(struct mc_instance *instance,
@@ -147,4 +147,7 @@
 /* Check if the other end of the fd owns instance */
 bool mc_check_owner_fd(struct mc_instance *instance, int32_t fd);
 
+/* Test if sleep is possible */
+bool mc_sleep_ready(void);
+
 #endif /* _MC_MAIN_H_ */
diff --git a/drivers/gud/MobiCoreDriver/mem.c b/drivers/gud/MobiCoreDriver/mem.c
new file mode 100644
index 0000000..2d92f74
--- /dev/null
+++ b/drivers/gud/MobiCoreDriver/mem.c
@@ -0,0 +1,743 @@
+/*
+ * MobiCore Driver Kernel Module.
+ *
+ * This module is written as a Linux device driver.
+ * This driver represents the command proxy on the lowest layer, from the
+ * secure world to the non secure world, and vice versa.
+ * This driver is located in the non secure world (Linux).
+ * This driver offers IOCTL commands, for access to the secure world, and has
+ * the interface from the secure world to the normal world.
+ * The access to the driver is possible with a file descriptor,
+ * which has to be created by the fd = open(/dev/mobicore) command.
+ *
+ * <-- Copyright Giesecke & Devrient GmbH 2009-2012 -->
+ * <-- Copyright Trustonic Limited 2013 -->
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include "main.h"
+#include "debug.h"
+#include "mem.h"
+
+#include <linux/highmem.h>
+#include <linux/slab.h>
+#include <linux/kthread.h>
+#include <linux/pagemap.h>
+#include <linux/device.h>
+
+#ifdef LPAE_SUPPORT
+#define MMU_TYPE_PAGE	(3 << 0)
+#define MMU_BUFFERABLE	(1 << 2) /* AttrIndx[0] */
+#define MMU_CACHEABLE	(1 << 3) /* AttrIndx[1] */
+#define MMU_NS		(1 << 5)
+#define MMU_AP_RW_ALL	(1 << 6) /* AP[2:1], RW, at any privilege level */
+#define MMU_EXT_SHARED	(3 << 8) /* SH[1:0], inner shareable */
+#define MMU_EXT_AF	(1 << 10) /* Access Flag */
+#define MMU_EXT_NG	(1 << 11)
+#define MMU_EXT_XN      (((uint64_t)1) << 54) /* XN */
+#else
+#define MMU_TYPE_EXT	(3 << 0)	/* v5 */
+#define MMU_TYPE_SMALL	(2 << 0)
+#define MMU_BUFFERABLE	(1 << 2)
+#define MMU_CACHEABLE	(1 << 3)
+#define MMU_EXT_AP0	(1 << 4)
+#define MMU_EXT_AP1	(2 << 4)
+#define MMU_EXT_TEX(x)	((x) << 6)	/* v5 */
+#define MMU_EXT_SHARED	(1 << 10)	/* v6 */
+#define MMU_EXT_NG	(1 << 11)	/* v6 */
+#endif
+
+/* MobiCore memory context data */
+struct mc_mem_context mem_ctx;
+
+static inline void release_page(struct page *page)
+{
+	set_bit(PG_dirty, &page->flags);
+
+	page_cache_release(page);
+}
+
+static int lock_pages(struct task_struct *task, void *virt_start_page_addr,
+	int pages_no, struct page **pages)
+{
+	int locked_pages;
+
+	/* lock user pages, must hold the mmap_sem to do this. */
+	down_read(&(task->mm->mmap_sem));
+	locked_pages = get_user_pages(
+				task,
+				task->mm,
+				(unsigned long)virt_start_page_addr,
+				pages_no,
+				1, /* write access */
+				0,
+				pages,
+				NULL);
+	up_read(&(task->mm->mmap_sem));
+
+	/* check if we could lock all pages. */
+	if (locked_pages != pages_no) {
+		MCDRV_DBG_ERROR(mcd, "get_user_pages() failed, locked_pages=%d",
+				locked_pages);
+		if (locked_pages > 0) {
+			/* release all locked pages. */
+			release_pages(pages, locked_pages, 0);
+		}
+		return -ENOMEM;
+	}
+
+	return 0;
+}
+
+/* Get kernel pointer to shared MMU table given a per-process reference */
+static void *get_mmu_table_kernel_virt(struct mc_mmu_table *table)
+{
+	if (WARN(!table, "Invalid MMU table"))
+		return NULL;
+
+	if (WARN(!table->set, "Invalid MMU table set"))
+		return NULL;
+
+	if (WARN(!table->set->kernel_virt, "Invalid MMU pointer"))
+		return NULL;
+
+	return &(table->set->kernel_virt->table[table->idx]);
+}
+
+static inline int in_use(struct mc_mmu_table *table)
+{
+	return atomic_read(&table->usage) > 0;
+}
+
+/*
+ * Search the list of used MMU tables and return the one with the handle.
+ * Assumes the table_lock is taken.
+ */
+struct mc_mmu_table *find_mmu_table(unsigned int handle)
+{
+	struct mc_mmu_table *table;
+
+	list_for_each_entry(table, &mem_ctx.mmu_tables, list) {
+		if (table->handle == handle)
+			return table;
+	}
+	return NULL;
+}
+
+/*
+ * Allocate a new MMU table store plus MMU_TABLES_PER_PAGE in the MMU free
+ * tables list. Assumes the table_lock is already taken by the caller above.
+ */
+static int alloc_mmu_table_store(void)
+{
+	unsigned long store;
+	struct mc_mmu_tables_set *mmutable_set;
+	struct mc_mmu_table *mmutable, *mmutable2;
+	struct page *page;
+	int ret = 0, i;
+	/* temp list for holding the MMU tables */
+	LIST_HEAD(temp);
+
+	store = get_zeroed_page(GFP_KERNEL);
+	if (!store)
+		return -ENOMEM;
+
+	/*
+	 * Actually, locking is not necessary, because kernel
+	 * memory is not supposed to get swapped out. But we
+	 * play safe....
+	 */
+	page = virt_to_page(store);
+	set_bit(PG_reserved, &page->flags);
+
+	/* add all the descriptors to the free descriptors list */
+	mmutable_set = kmalloc(sizeof(*mmutable_set), GFP_KERNEL | __GFP_ZERO);
+	if (mmutable_set == NULL) {
+		ret = -ENOMEM;
+		goto free_store;
+	}
+	/* initialize */
+	mmutable_set->kernel_virt = (void *)store;
+	mmutable_set->page = page;
+	mmutable_set->phys = virt_to_phys((void *)store);
+	/* the set is not yet used */
+	atomic_set(&mmutable_set->used_tables, 0);
+
+	/* init add to list. */
+	INIT_LIST_HEAD(&(mmutable_set->list));
+	list_add(&mmutable_set->list, &mem_ctx.mmu_tables_sets);
+
+	for (i = 0; i < MMU_TABLES_PER_PAGE; i++) {
+		/* allocate a WSM MMU descriptor */
+		mmutable  = kmalloc(sizeof(*mmutable), GFP_KERNEL | __GFP_ZERO);
+		if (mmutable == NULL) {
+			ret = -ENOMEM;
+			MCDRV_DBG_ERROR(mcd, "out of memory");
+			/* Free the full temp list and the store in this case */
+			goto free_temp_list;
+		}
+
+		/* set set reference */
+		mmutable->set = mmutable_set;
+		mmutable->idx = i;
+		mmutable->virt = get_mmu_table_kernel_virt(mmutable);
+		mmutable->phys = mmutable_set->phys+i*sizeof(struct mmutable);
+		atomic_set(&mmutable->usage, 0);
+
+		/* add to temp list. */
+		INIT_LIST_HEAD(&mmutable->list);
+		list_add_tail(&mmutable->list, &temp);
+	}
+
+	/*
+	 * If everything went ok then merge the temp list with the global
+	 * free list
+	 */
+	list_splice_tail(&temp, &mem_ctx.free_mmu_tables);
+	return 0;
+free_temp_list:
+	list_for_each_entry_safe(mmutable, mmutable2, &temp, list) {
+		kfree(mmutable);
+	}
+
+	list_del(&mmutable_set->list);
+
+free_store:
+	free_page(store);
+	return ret;
+}
+/*
+ * Get a MMU table from the free tables list or allocate a new one and
+ * initialize it. Assumes the table_lock is already taken.
+ */
+static struct mc_mmu_table *alloc_mmu_table(struct mc_instance *instance)
+{
+	int ret = 0;
+	struct mc_mmu_table *table = NULL;
+
+	if (list_empty(&mem_ctx.free_mmu_tables)) {
+		ret = alloc_mmu_table_store();
+		if (ret) {
+			MCDRV_DBG_ERROR(mcd, "Failed to allocate new store!");
+			return ERR_PTR(-ENOMEM);
+		}
+		/* if it's still empty something wrong has happened */
+		if (list_empty(&mem_ctx.free_mmu_tables)) {
+			MCDRV_DBG_ERROR(mcd,
+					"Free list not updated correctly!");
+			return ERR_PTR(-EFAULT);
+		}
+	}
+
+	/* get a WSM MMU descriptor */
+	table  = list_first_entry(&mem_ctx.free_mmu_tables,
+		struct mc_mmu_table, list);
+	if (table == NULL) {
+		MCDRV_DBG_ERROR(mcd, "out of memory");
+		return ERR_PTR(-ENOMEM);
+	}
+	/* Move it to the used MMU tables list */
+	list_move_tail(&table->list, &mem_ctx.mmu_tables);
+
+	table->handle = get_unique_id();
+	table->owner = instance;
+
+	atomic_inc(&table->set->used_tables);
+	atomic_inc(&table->usage);
+
+	MCDRV_DBG_VERBOSE(mcd,
+			  "chunkPhys=0x%llX, idx=%d",
+			  (u64)table->set->phys, table->idx);
+
+	return table;
+}
+
+/*
+ * Frees the object associated with a MMU table. Initially the object is moved
+ * to the free tables list, but if all the 4 lists of the store are free
+ * then the store is also released.
+ * Assumes the table_lock is already taken.
+ */
+static void free_mmu_table(struct mc_mmu_table *table)
+{
+	struct mc_mmu_tables_set *mmutable_set;
+
+	if (WARN(!table, "Invalid table"))
+		return;
+
+	mmutable_set = table->set;
+	if (WARN(!mmutable_set, "Invalid table set"))
+		return;
+
+	list_move_tail(&table->list, &mem_ctx.free_mmu_tables);
+
+	/* if nobody uses this set, we can release it. */
+	if (atomic_dec_and_test(&mmutable_set->used_tables)) {
+		struct mc_mmu_table *tmp;
+
+		/* remove from list */
+		list_del(&mmutable_set->list);
+		/*
+		 * All the MMU tables are in the free list for this set
+		 * so we can just remove them from there
+		 */
+		list_for_each_entry_safe(table, tmp, &mem_ctx.free_mmu_tables,
+					 list) {
+			if (table->set == mmutable_set) {
+				list_del(&table->list);
+				kfree(table);
+			}
+		} /* end while */
+
+		/*
+		 * We shouldn't recover from this since it was some data
+		 * corruption before
+		 */
+		BUG_ON(!mmutable_set->page);
+		clear_bit(PG_reserved, &(mmutable_set->page)->flags);
+
+
+		BUG_ON(!mmutable_set->kernel_virt);
+		free_page((unsigned long)mmutable_set->kernel_virt);
+
+		kfree(mmutable_set);
+	}
+}
+
+/*
+ * Create a MMU table in a WSM container that has been allocates previously.
+ * Assumes the table lock is already taken or there is no need to take like
+ * when first creating the MMU table the full list is locked.
+ *
+ * @task	pointer to task owning WSM
+ * @wsm_buffer  user space WSM start
+ * @wsm_len     WSM length
+ * @table       Pointer to MMU table details
+ */
+static int map_buffer(struct task_struct *task, void *wsm_buffer,
+		      unsigned int wsm_len, struct mc_mmu_table *table)
+{
+	int		ret = 0;
+	unsigned int	i, nr_of_pages;
+	/* start address of the 4 KiB page of wsm_buffer */
+	void		*virt_addr_page;
+	struct page	*page;
+	struct mmutable	*mmutable;
+	struct page	**mmutable_as_array_of_pointers_to_page;
+	/* page offset in wsm buffer */
+	unsigned int offset;
+
+	if (WARN(!wsm_buffer, "Invalid WSM buffer pointer"))
+		return -EINVAL;
+
+	if (WARN(wsm_len == 0, "Invalid WSM buffer length"))
+		return -EINVAL;
+
+	if (WARN(!table, "Invalid mapping table for WSM"))
+		return -EINVAL;
+
+	/* no size > 1Mib supported */
+	if (wsm_len > SZ_1M) {
+		MCDRV_DBG_ERROR(mcd, "size > 1 MiB");
+		return -EINVAL;
+	}
+
+	MCDRV_DBG_VERBOSE(mcd, "WSM addr=0x%p, len=0x%08x", wsm_buffer,
+			  wsm_len);
+
+	/* calculate page usage */
+	virt_addr_page = (void *)(((unsigned long)(wsm_buffer)) & PAGE_MASK);
+	offset = (unsigned int)	(((unsigned long)(wsm_buffer)) & (~PAGE_MASK));
+	nr_of_pages  = PAGE_ALIGN(offset + wsm_len) / PAGE_SIZE;
+
+	MCDRV_DBG_VERBOSE(mcd, "virt addr page start=0x%p, pages=%d",
+			  virt_addr_page, nr_of_pages);
+
+	/* MMU table can hold max 1MiB in 256 pages. */
+	if ((nr_of_pages * PAGE_SIZE) > SZ_1M) {
+		MCDRV_DBG_ERROR(mcd, "WSM paged exceed 1 MiB");
+		return -EINVAL;
+	}
+
+	mmutable = table->virt;
+	/*
+	 * We use the memory for the MMU table to hold the pointer
+	 * and convert them later. This works, as everything comes
+	 * down to a 32 bit value.
+	 */
+	mmutable_as_array_of_pointers_to_page = (struct page **)mmutable;
+
+	/* Request comes from user space */
+	if (task != NULL && !is_vmalloc_addr(wsm_buffer)) {
+		/*
+		 * lock user page in memory, so they do not get swapped
+		 * out.
+		 * REV axh: Kernel 2.6.27 added a new get_user_pages_fast()
+		 * function, maybe it is called fast_gup() in some versions.
+		 * handle user process doing a fork().
+		 * Child should not get things.
+		 * http://osdir.com/ml/linux-media/2009-07/msg00813.html
+		 * http://lwn.net/Articles/275808/
+		 */
+		ret = lock_pages(task, virt_addr_page, nr_of_pages,
+				 mmutable_as_array_of_pointers_to_page);
+		if (ret != 0) {
+			MCDRV_DBG_ERROR(mcd, "lock_user_pages() failed");
+			return ret;
+		}
+	}
+	/* Request comes from kernel space(cont buffer) */
+	else if (task == NULL && !is_vmalloc_addr(wsm_buffer)) {
+		void *uaddr = wsm_buffer;
+		for (i = 0; i < nr_of_pages; i++) {
+			page = virt_to_page(uaddr);
+			if (!page) {
+				MCDRV_DBG_ERROR(mcd, "failed to map address");
+				return -EINVAL;
+			}
+			get_page(page);
+			mmutable_as_array_of_pointers_to_page[i] = page;
+			uaddr += PAGE_SIZE;
+		}
+	}
+	/* Request comes from kernel space(vmalloc buffer) */
+	else {
+		void *uaddr = wsm_buffer;
+		for (i = 0; i < nr_of_pages; i++) {
+			page = vmalloc_to_page(uaddr);
+			if (!page) {
+				MCDRV_DBG_ERROR(mcd, "failed to map address");
+				return -EINVAL;
+			}
+			get_page(page);
+			mmutable_as_array_of_pointers_to_page[i] = page;
+			uaddr += PAGE_SIZE;
+		}
+	}
+
+	table->pages = nr_of_pages;
+
+	/*
+	 * create MMU Table entries.
+	 * used_mmutable->table contains a list of page pointers here.
+	 * For a proper cleanup we have to ensure that the following
+	 * code either works and used_mmutable contains a valid MMU table
+	 * - or fails and used_mmutable->table contains the list of page
+	 * pointers.
+	 * Any mixed contents will make cleanup difficult.
+	 * Fill the table in reverse order as the table is used as input and
+	 * output.
+	 */
+	i = MC_ARM_MMU_TABLE_ENTRIES-1;
+	do {
+		if (i < nr_of_pages) {
+#ifdef LPAE_SUPPORT
+			uint64_t pte;
+#elif defined(CONFIG_ARM_LPAE) && !defined(LPAE_SUPPORT)
+			/* Nwd supports 64bit addresses, SWD only 32bit */
+			uint64_t pte64;
+			uint32_t pte;
+#else
+			uint32_t pte;
+#endif
+			page = mmutable_as_array_of_pointers_to_page[i];
+
+			/*
+			 * create MMU table entry, see ARM MMU docu for details
+			 * about flags stored in the lowest 12 bits.
+			 * As a side reference, the Article
+			 * "ARM's multiply-mapped memory mess"
+			 * found in the collection at
+			 * http://lwn.net/Articles/409032/
+			 * is also worth reading.
+			 */
+#ifdef LPAE_SUPPORT
+			pte = page_to_phys(page);
+			pte |=	MMU_EXT_XN
+				| MMU_EXT_NG
+				| MMU_EXT_AF
+				| MMU_AP_RW_ALL
+				| MMU_NS
+				| MMU_CACHEABLE | MMU_BUFFERABLE
+				| MMU_TYPE_PAGE;
+#elif defined(CONFIG_ARM_LPAE) && !defined(LPAE_SUPPORT)
+			/*
+			 * NWD uses 64bit addresses but SWD can handle only
+			 * short descriptors
+			 * and physical addresses not bigger than 4GB
+			 */
+			 pte64 = page_to_phys(page);
+			 if ((pte64 >> 32) != 0) {
+				MCDRV_DBG_ERROR(mcd,
+						"physical addresses bigger than 4GB not supported");
+				return -EINVAL;
+				}
+			pte = (uint32_t)pte64;
+			pte |= MMU_EXT_AP1 | MMU_EXT_AP0
+				| MMU_CACHEABLE | MMU_BUFFERABLE
+				| MMU_TYPE_SMALL | MMU_TYPE_EXT | MMU_EXT_NG;
+#else
+			pte = page_to_phys(page);
+			pte |= MMU_EXT_AP1 | MMU_EXT_AP0
+				| MMU_CACHEABLE | MMU_BUFFERABLE
+				| MMU_TYPE_SMALL | MMU_TYPE_EXT | MMU_EXT_NG;
+#endif /* LPAE_SUPPORT */
+			/*
+			 * Linux uses different mappings for SMP systems(the
+			 * sharing flag is set for the pte. In order not to
+			 * confuse things too much in Mobicore make sure the
+			 * shared buffers have the same flags.
+			 * This should also be done in SWD side
+			 */
+#ifdef CONFIG_SMP
+#ifdef LPAE_SUPPORT
+			pte |= MMU_EXT_SHARED;
+#else
+			pte |= MMU_EXT_SHARED | MMU_EXT_TEX(1);
+#endif /* LPAE_SUPPORT */
+#endif /* CONFIG_SMP */
+
+			mmutable->table_entries[i] = pte;
+			MCDRV_DBG_VERBOSE(mcd, "MMU entry %d:  0x%llx", i,
+					  (u64)(pte));
+		} else {
+			/* ensure rest of table is empty */
+			mmutable->table_entries[i] = 0;
+		}
+	} while (i-- != 0);
+
+	return ret;
+}
+
+/*
+ * Remove a MMU table in a WSM container. Afterwards the container may be
+ * released. Assumes the table_lock and the lock is taken.
+ */
+static void unmap_buffers(struct mc_mmu_table *table)
+{
+	struct mmutable *mmutable;
+	int i;
+
+	if (WARN_ON(!table))
+		return;
+
+	/* found the table, now release the resources. */
+	MCDRV_DBG_VERBOSE(mcd,
+			  "clear MMU table, phys_base=0x%llX,nr_of_pages=%d",
+			  (u64)table->phys, table->pages);
+
+	mmutable = table->virt;
+
+	/* release all locked user space pages */
+	for (i = 0; i < table->pages; i++) {
+		/* convert physical entries from MMU table to page pointers */
+		struct page *page;
+		page = phys_to_page(mmutable->table_entries[i]);
+		release_page(page);
+	}
+
+	/* remember that all pages have been freed */
+	table->pages = 0;
+}
+
+/* Delete a used MMU table. Assumes the table_lock and the lock is taken */
+static void unmap_mmu_table(struct mc_mmu_table *table)
+{
+	/* Check if it's not locked by other processes too! */
+	if (!atomic_dec_and_test(&table->usage))
+		return;
+
+	/* release if Nwd and Swd/MC do no longer use it. */
+	unmap_buffers(table);
+	free_mmu_table(table);
+}
+
+int mc_free_mmu_table(struct mc_instance *instance, uint32_t handle)
+{
+	struct mc_mmu_table *table;
+	int ret = 0;
+
+	if (WARN(!instance, "No instance data available"))
+		return -EFAULT;
+
+	mutex_lock(&mem_ctx.table_lock);
+	table = find_mmu_table(handle);
+
+	if (table == NULL) {
+		MCDRV_DBG_VERBOSE(mcd, "entry not found");
+		ret = -EINVAL;
+		goto err_unlock;
+	}
+	if (instance != table->owner && !is_daemon(instance)) {
+		MCDRV_DBG_ERROR(mcd, "instance does no own it");
+		ret = -EPERM;
+		goto err_unlock;
+	}
+	/* free table (if no further locks exist) */
+	unmap_mmu_table(table);
+err_unlock:
+	mutex_unlock(&mem_ctx.table_lock);
+
+	return ret;
+}
+
+int mc_lock_mmu_table(struct mc_instance *instance, uint32_t handle)
+{
+	int ret = 0;
+	struct mc_mmu_table *table = NULL;
+
+	if (WARN(!instance, "No instance data available"))
+		return -EFAULT;
+
+	mutex_lock(&mem_ctx.table_lock);
+	table = find_mmu_table(handle);
+
+	if (table == NULL) {
+		MCDRV_DBG_VERBOSE(mcd, "entry not found %u", handle);
+		ret = -EINVAL;
+		goto table_err;
+	}
+	if (instance != table->owner && !is_daemon(instance)) {
+		MCDRV_DBG_ERROR(mcd, "instance does no own it");
+		ret = -EPERM;
+		goto table_err;
+	}
+
+	/* lock entry */
+	atomic_inc(&table->usage);
+table_err:
+	mutex_unlock(&mem_ctx.table_lock);
+	return ret;
+}
+/*
+ * Allocate MMU table and map buffer into it.
+ * That is, create respective table entries.
+ */
+struct mc_mmu_table *mc_alloc_mmu_table(struct mc_instance *instance,
+	struct task_struct *task, void *wsm_buffer, unsigned int wsm_len)
+{
+	int ret = 0;
+	struct mc_mmu_table *table;
+
+	if (WARN(!instance, "No instance data available"))
+		return ERR_PTR(-EFAULT);
+
+	mutex_lock(&mem_ctx.table_lock);
+	table = alloc_mmu_table(instance);
+	if (IS_ERR(table)) {
+		MCDRV_DBG_ERROR(mcd, "alloc_mmu_table() failed");
+		ret = -ENOMEM;
+		goto err_no_mem;
+	}
+
+	/* create the MMU page for the WSM */
+	ret = map_buffer(task, wsm_buffer, wsm_len, table);
+
+	if (ret != 0) {
+		MCDRV_DBG_ERROR(mcd, "map_buffer() failed");
+		unmap_mmu_table(table);
+		goto err_no_mem;
+	}
+	MCDRV_DBG_VERBOSE(mcd,
+			  "mapped buffer %p to table with handle %d @ 0x%llX",
+			  wsm_buffer, table->handle, (u64)table->phys);
+
+	mutex_unlock(&mem_ctx.table_lock);
+	return table;
+err_no_mem:
+	mutex_unlock(&mem_ctx.table_lock);
+	return ERR_PTR(ret);
+}
+
+phys_addr_t mc_find_mmu_table(uint32_t handle, int32_t fd)
+{
+	phys_addr_t ret = 0;
+	struct mc_mmu_table *table = NULL;
+
+	mutex_lock(&mem_ctx.table_lock);
+	table = find_mmu_table(handle);
+
+	if (table == NULL) {
+		MCDRV_DBG_ERROR(mcd, "entry not found %u", handle);
+		ret = 0;
+		goto table_err;
+	}
+
+	/* It's safe here not to lock the instance since the owner of
+	 * the table will be cleared only with the table lock taken */
+	if (!mc_check_owner_fd(table->owner, fd)) {
+		MCDRV_DBG_ERROR(mcd, "not valid owner %u", handle);
+		ret = 0;
+		goto table_err;
+	}
+
+	ret = table->phys;
+table_err:
+	mutex_unlock(&mem_ctx.table_lock);
+	return ret;
+}
+
+void mc_clean_mmu_tables(void)
+{
+	struct mc_mmu_table *table, *tmp;
+
+	mutex_lock(&mem_ctx.table_lock);
+	/* Check if some WSM is orphaned. */
+	list_for_each_entry_safe(table, tmp, &mem_ctx.mmu_tables, list) {
+		if (table->owner == NULL) {
+			MCDRV_DBG(mcd,
+				  "cleariM MMU: p=0x%llX pages=%d",
+				  (u64)table->phys,
+				  table->pages);
+			unmap_mmu_table(table);
+		}
+	}
+	mutex_unlock(&mem_ctx.table_lock);
+}
+
+void mc_clear_mmu_tables(struct mc_instance *instance)
+{
+	struct mc_mmu_table *table, *tmp;
+
+	mutex_lock(&mem_ctx.table_lock);
+	/* Check if some WSM is still in use. */
+	list_for_each_entry_safe(table, tmp, &mem_ctx.mmu_tables, list) {
+		if (table->owner == instance) {
+			MCDRV_DBG(mcd, "release WSM MMU: p=0x%llX pages=%d",
+				  (u64)table->phys,
+				  table->pages);
+			/* unlock app usage and free or mark it as orphan */
+			table->owner = NULL;
+			unmap_mmu_table(table);
+		}
+	}
+	mutex_unlock(&mem_ctx.table_lock);
+}
+
+int mc_init_mmu_tables(void)
+{
+	/* init list for WSM MMU chunks. */
+	INIT_LIST_HEAD(&mem_ctx.mmu_tables_sets);
+
+	/* MMU table descriptor list. */
+	INIT_LIST_HEAD(&mem_ctx.mmu_tables);
+
+	/* MMU free table descriptor list. */
+	INIT_LIST_HEAD(&mem_ctx.free_mmu_tables);
+
+	mutex_init(&mem_ctx.table_lock);
+
+	return 0;
+}
+
+void mc_release_mmu_tables(void)
+{
+	struct mc_mmu_table *table;
+	/* Check if some WSM is still in use. */
+	list_for_each_entry(table, &mem_ctx.mmu_tables, list) {
+		WARN(1, "WSM MMU still in use: phys=0x%llX ,nr_of_pages=%d",
+		     (u64)table->phys, table->pages);
+	}
+}
diff --git a/drivers/gud/MobiCoreDriver/mem.h b/drivers/gud/MobiCoreDriver/mem.h
new file mode 100644
index 0000000..5c9006a
--- /dev/null
+++ b/drivers/gud/MobiCoreDriver/mem.h
@@ -0,0 +1,139 @@
+/*
+ * MobiCore driver module.(interface to the secure world SWD)
+ *
+ * <-- Copyright Giesecke & Devrient GmbH 2009-2012 -->
+ * <-- Copyright Trustonic Limited 2013 -->
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _MC_MEM_H_
+#define _MC_MEM_H_
+
+#ifdef LPAE_SUPPORT
+/*
+ * Number of page table entries in one MMU table. This is ARM specific, an
+ * MMU table covers 2 MiB by using 512 entries referring to 4KiB pages each.
+ */
+#define MC_ARM_MMU_TABLE_ENTRIES		512
+
+/* ARM level 3 (MMU) table with 512 entries. Size: 4k */
+struct mmutable {
+	uint64_t	table_entries[MC_ARM_MMU_TABLE_ENTRIES];
+};
+
+/* There is 1 table in each page. */
+#define MMU_TABLES_PER_PAGE		1
+#else
+/*
+ * MobiCore specific page tables for world shared memory.
+ * Linux uses shadow page tables, see arch/arm/include/asm/pgtable-2level.
+ * MobiCore uses the default ARM format.
+ *
+ * Number of page table entries in one MMU table. This is ARM specific, an
+ * MMU table covers 1 MiB by using 256 entries referring to 4KiB pages each.
+ */
+#define MC_ARM_MMU_TABLE_ENTRIES		256
+
+/* ARM level 2 (MMU) table with 256 entries. Size: 1k */
+struct mmutable {
+	uint32_t	table_entries[MC_ARM_MMU_TABLE_ENTRIES];
+};
+
+/* There are 4 tables in each page. */
+#define MMU_TABLES_PER_PAGE		4
+#endif
+
+/* Store for four MMU tables in one 4kb page*/
+struct mc_mmu_table_store {
+	struct mmutable table[MMU_TABLES_PER_PAGE];
+};
+
+/* Usage and maintenance information about mc_mmu_table_store */
+struct mc_mmu_tables_set {
+	struct list_head		list;
+	/* kernel virtual address */
+	struct mc_mmu_table_store	*kernel_virt;
+	/* physical address */
+	phys_addr_t			phys;
+	/* pointer to page struct */
+	struct page			*page;
+	/* How many pages from this set are used */
+	atomic_t			used_tables;
+};
+
+/*
+ * MMU table allocated to the Daemon or a TLC describing a world shared
+ * buffer.
+ * When users map a malloc()ed area into SWd, a MMU table is allocated.
+ * In addition, the area of maximum 1MB virtual address space is mapped into
+ * the MMU table and a handle for this table is returned to the user.
+ */
+struct mc_mmu_table {
+	struct list_head	list;
+	/* Table lock */
+	struct mutex		lock;
+	/* handle as communicated to user mode */
+	unsigned int		handle;
+	/* Number of references kept to this MMU table */
+	atomic_t		usage;
+	/* owner of this MMU table */
+	struct mc_instance	*owner;
+	/* set describing where our MMU table is stored */
+	struct mc_mmu_tables_set	*set;
+	/* index into MMU table set */
+	unsigned int		idx;
+	/* size of buffer */
+	unsigned int		pages;
+	/* virtual address*/
+	void			*virt;
+	/* physical address */
+	phys_addr_t		phys;
+};
+
+/* MobiCore Driver Memory context data. */
+struct mc_mem_context {
+	struct mc_instance	*daemon_inst;
+	/* Backing store for MMU tables */
+	struct list_head	mmu_tables_sets;
+	/* Bookkeeping for used MMU tables */
+	struct list_head	mmu_tables;
+	/* Bookkeeping for free MMU tables */
+	struct list_head	free_mmu_tables;
+	/* semaphore to synchronize access to above lists */
+	struct mutex		table_lock;
+};
+
+/*
+ * Allocate MMU table and map buffer into it.
+ * That is, create respective table entries.
+ */
+struct mc_mmu_table *mc_alloc_mmu_table(struct mc_instance *instance,
+	struct task_struct *task, void *wsm_buffer, unsigned int wsm_len);
+
+/* Delete all the MMU tables associated with an instance */
+void mc_clear_mmu_tables(struct mc_instance *instance);
+
+/* Release all orphaned MMU tables */
+void mc_clean_mmu_tables(void);
+
+/* Delete a used MMU table. */
+int mc_free_mmu_table(struct mc_instance *instance, uint32_t handle);
+
+/*
+ * Lock a MMU table - the daemon adds +1 to refcount of the MMU table
+ * marking it in use by SWD so it doesn't get released when the TLC dies.
+ */
+int mc_lock_mmu_table(struct mc_instance *instance, uint32_t handle);
+
+/* Return the phys address of MMU table. */
+phys_addr_t mc_find_mmu_table(uint32_t handle, int32_t fd);
+/* Release all used MMU tables to Linux memory space */
+void mc_release_mmu_tables(void);
+
+/* Initialize all MMU tables structure */
+int mc_init_mmu_tables(void);
+
+#endif /* _MC_MEM_H_ */
diff --git a/drivers/gud/MobiCoreDriver/ops.c b/drivers/gud/MobiCoreDriver/ops.c
new file mode 100644
index 0000000..96b4f4f
--- /dev/null
+++ b/drivers/gud/MobiCoreDriver/ops.c
@@ -0,0 +1,398 @@
+/*
+ * MobiCore Driver Kernel Module.
+ *
+ * This module is written as a Linux device driver.
+ * This driver represents the command proxy on the lowest layer, from the
+ * secure world to the non secure world, and vice versa.
+ * This driver is located in the non secure world (Linux).
+ * This driver offers IOCTL commands, for access to the secure world, and has
+ * the interface from the secure world to the normal world.
+ * The access to the driver is possible with a file descriptor,
+ * which has to be created by the fd = open(/dev/mobicore) command.
+ *
+ * <-- Copyright Giesecke & Devrient GmbH 2009-2012 -->
+ * <-- Copyright Trustonic Limited 2013 -->
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kthread.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/workqueue.h>
+#include <linux/cpu.h>
+
+#include "main.h"
+#include "fastcall.h"
+#include "ops.h"
+#include "mem.h"
+#include "pm.h"
+#include "debug.h"
+
+/* MobiCore context data */
+static struct mc_context *ctx;
+#ifdef TBASE_CORE_SWITCHER
+static uint32_t active_cpu;
+
+static int mobicore_cpu_callback(struct notifier_block *nfb,
+				 unsigned long action, void *hcpu);
+static struct notifier_block mobicore_cpu_notifer = {
+	.notifier_call = mobicore_cpu_callback,
+};
+#endif
+
+static inline long smc(union fc_generic *fc)
+{
+	/* If we request sleep yields must be filtered out as they
+	 * make no sense */
+	if (ctx->mcp)
+		if (ctx->mcp->flags.sleep_mode.sleep_req) {
+			if (fc->as_in.cmd == MC_SMC_N_YIELD)
+				return MC_FC_RET_ERR_INVALID;
+		}
+	return _smc(fc);
+}
+
+struct fastcall_work {
+#ifdef MC_FASTCALL_WORKER_THREAD
+	struct kthread_work work;
+#else
+	struct work_struct work;
+#endif
+	void *data;
+};
+
+#ifdef MC_FASTCALL_WORKER_THREAD
+static void fastcall_work_func(struct kthread_work *work);
+#else
+static void fastcall_work_func(struct work_struct *work);
+#endif
+
+
+#ifdef MC_FASTCALL_WORKER_THREAD
+
+static struct task_struct *fastcall_thread;
+static DEFINE_KTHREAD_WORKER(fastcall_worker);
+
+bool mc_fastcall(void *data)
+{
+	struct fastcall_work fc_work = {
+		KTHREAD_WORK_INIT(fc_work.work, fastcall_work_func),
+		.data = data,
+	};
+
+	if (!queue_kthread_work(&fastcall_worker, &fc_work.work))
+		return false;
+	flush_kthread_work(&fc_work.work);
+	return true;
+}
+
+int mc_fastcall_init(struct mc_context *context)
+{
+	int ret = 0;
+	ctx = context;
+
+	fastcall_thread = kthread_create(kthread_worker_fn, &fastcall_worker,
+					 "mc_fastcall");
+	if (IS_ERR(fastcall_thread)) {
+		ret = PTR_ERR(fastcall_thread);
+		fastcall_thread = NULL;
+		MCDRV_DBG_ERROR(mcd, "cannot create fastcall wq (%d)", ret);
+		return ret;
+	}
+
+	wake_up_process(fastcall_thread);
+
+	/* this thread MUST run on CPU 0 at startup */
+	set_cpus_allowed(fastcall_thread, CPU_MASK_CPU0);
+#ifdef TBASE_CORE_SWITCHER
+	register_cpu_notifier(&mobicore_cpu_notifer);
+#endif
+	return 0;
+}
+
+void mc_fastcall_destroy(void)
+{
+	if (!IS_ERR_OR_NULL(fastcall_thread)) {
+		kthread_stop(fastcall_thread);
+		fastcall_thread = NULL;
+	}
+}
+#else
+
+bool mc_fastcall(void *data)
+{
+	struct fastcall_work work = {
+		.data = data,
+	};
+	INIT_WORK(&work.work, fastcall_work_func);
+	if (!schedule_work_on(0, &work.work))
+		return false;
+	flush_work(&work.work);
+	return true;
+}
+
+int mc_fastcall_init(struct mc_context *context)
+{
+	ctx = context;
+	return 0;
+};
+
+void mc_fastcall_destroy(void) {};
+#endif
+
+#ifdef MC_FASTCALL_WORKER_THREAD
+static void fastcall_work_func(struct kthread_work *work)
+#else
+static void fastcall_work_func(struct work_struct *work)
+#endif
+{
+	struct fastcall_work *fc_work =
+		container_of(work, struct fastcall_work, work);
+	union fc_generic *fc_generic = fc_work->data;
+#ifdef TBASE_CORE_SWITCHER
+	uint32_t cpu_swap = 0, new_cpu;
+	uint32_t cpu_id[] = CPU_IDS;
+#endif
+
+#ifdef MC_CRYPTO_CLOCK_MANAGEMENT
+	mc_pm_clock_enable();
+#endif
+
+
+	if (fc_generic == NULL)
+		return;
+#ifdef TBASE_CORE_SWITCHER
+	if (fc_generic->as_in.cmd == MC_FC_SWITCH_CORE) {
+		cpu_swap = 1;
+		new_cpu = fc_generic->as_in.param[0];
+		fc_generic->as_in.param[0] = cpu_id[fc_generic->as_in.param[0]];
+	}
+#endif
+	smc(fc_work->data);
+#ifdef TBASE_CORE_SWITCHER
+	if (cpu_swap) {
+		if (fc_generic->as_out.ret == 0) {
+			cpumask_t cpu;
+			active_cpu = new_cpu;
+			MCDRV_DBG(mcd, "CoreSwap ok %d -> %d\n",
+				  raw_smp_processor_id(), active_cpu);
+			cpumask_clear(&cpu);
+			cpumask_set_cpu(active_cpu, &cpu);
+#ifdef MC_FASTCALL_WORKER_THREAD
+			set_cpus_allowed(fastcall_thread, cpu);
+#endif
+		} else {
+			MCDRV_DBG(mcd, "CoreSwap failed %d -> %d\n",
+				  raw_smp_processor_id(),
+				  fc_generic->as_in.param[0]);
+		}
+	}
+#endif
+#ifdef MC_CRYPTO_CLOCK_MANAGEMENT
+	mc_pm_clock_disable();
+#endif
+}
+
+int mc_info(uint32_t ext_info_id, uint32_t *state, uint32_t *ext_info)
+{
+	int ret = 0;
+	union mc_fc_info fc_info;
+
+	MCDRV_DBG_VERBOSE(mcd, "enter");
+
+	memset(&fc_info, 0, sizeof(fc_info));
+	fc_info.as_in.cmd = MC_FC_INFO;
+	fc_info.as_in.ext_info_id = ext_info_id;
+
+	MCDRV_DBG(mcd, "<- cmd=0x%08x, ext_info_id=0x%08x",
+		  fc_info.as_in.cmd, fc_info.as_in.ext_info_id);
+
+	mc_fastcall(&(fc_info.as_generic));
+
+	MCDRV_DBG(mcd,
+		  "-> r=0x%08x ret=0x%08x state=0x%08x "
+		  "ext_info=0x%08x",
+		  fc_info.as_out.resp,
+		  fc_info.as_out.ret,
+		  fc_info.as_out.state,
+		  fc_info.as_out.ext_info);
+
+	ret = convert_fc_ret(fc_info.as_out.ret);
+
+	*state  = fc_info.as_out.state;
+	*ext_info = fc_info.as_out.ext_info;
+
+	MCDRV_DBG_VERBOSE(mcd, "exit with %d/0x%08X", ret, ret);
+
+	return ret;
+}
+
+#ifdef TBASE_CORE_SWITCHER
+int mc_switch_core(uint32_t core_num)
+{
+	int32_t ret = 0;
+	union mc_fc_swich_core fc_switch_core;
+
+	if (!cpu_online(core_num))
+		return 1;
+
+	MCDRV_DBG_VERBOSE(mcd, "enter\n");
+
+	memset(&fc_switch_core, 0, sizeof(fc_switch_core));
+	fc_switch_core.as_in.cmd = MC_FC_SWITCH_CORE;
+
+	if (core_num < COUNT_OF_CPUS)
+		fc_switch_core.as_in.core_id = core_num;
+	else
+		fc_switch_core.as_in.core_id = 0;
+
+	MCDRV_DBG(
+			mcd, "<- cmd=0x%08x, core_num=0x%08x, "
+			"active_cpu=0x%08x, active_cpu=0x%08x\n",
+			fc_switch_core.as_in.cmd,
+			fc_switch_core.as_in.core_id,
+			core_num, active_cpu);
+	mc_fastcall(&(fc_switch_core.as_generic));
+
+	ret = convert_fc_ret(fc_switch_core.as_out.ret);
+
+	MCDRV_DBG_VERBOSE(mcd, "exit with %d/0x%08X\n", ret, ret);
+
+	return ret;
+}
+
+void mc_cpu_offfline(int cpu)
+{
+	if (active_cpu == cpu) {
+		int i;
+		/* Chose the first online CPU and switch! */
+		for_each_online_cpu(i) {
+			if (i == cpu) {
+				MCDRV_DBG(mcd, "Skipping CPU %d\n", cpu);
+				continue;
+			}
+			MCDRV_DBG(mcd, "CPU %d is dying, switching to %d\n",
+				  cpu, i);
+			mc_switch_core(i);
+			break;
+		}
+	} else {
+		MCDRV_DBG(mcd, "not active CPU, no action taken\n");
+	}
+}
+
+static int mobicore_cpu_callback(struct notifier_block *nfb,
+				unsigned long action, void *hcpu)
+{
+	unsigned int cpu = (unsigned long)hcpu;
+
+	switch (action) {
+	case CPU_DOWN_PREPARE:
+	case CPU_DOWN_PREPARE_FROZEN:
+		dev_info(mcd, "Cpu %u is going to die\n", cpu);
+		mc_cpu_offfline(cpu);
+		break;
+	case CPU_DEAD:
+	case CPU_DEAD_FROZEN:
+		dev_info(mcd, "Cpu %u is dead\n", cpu);
+		break;
+	}
+	return NOTIFY_OK;
+}
+#endif
+
+/* Yield to MobiCore */
+int mc_yield(void)
+{
+	int ret = 0;
+	union fc_generic yield;
+
+	MCDRV_DBG_VERBOSE(mcd, "enter");
+	memset(&yield, 0, sizeof(yield));
+	yield.as_in.cmd = MC_SMC_N_YIELD;
+	mc_fastcall(&yield);
+	ret = convert_fc_ret(yield.as_out.ret);
+
+	return ret;
+}
+
+/* call common notify */
+int mc_nsiq(void)
+{
+	int ret = 0;
+	union fc_generic nsiq;
+	MCDRV_DBG_VERBOSE(mcd, "enter");
+	memset(&nsiq, 0, sizeof(nsiq));
+	nsiq.as_in.cmd = MC_SMC_N_SIQ;
+	mc_fastcall(&nsiq);
+	ret = convert_fc_ret(nsiq.as_out.ret);
+	return ret;
+}
+
+/* call common notify */
+int _nsiq(void)
+{
+	int ret = 0;
+	union fc_generic nsiq;
+	MCDRV_DBG_VERBOSE(mcd, "enter");
+	memset(&nsiq, 0, sizeof(nsiq));
+	nsiq.as_in.cmd = MC_SMC_N_SIQ;
+	_smc(&nsiq);
+	ret = convert_fc_ret(nsiq.as_out.ret);
+	return ret;
+}
+
+/* Call the INIT fastcall to setup MobiCore initialization */
+int mc_init(phys_addr_t base, uint32_t nq_length,
+	uint32_t mcp_offset, uint32_t mcp_length)
+{
+	int ret = 0;
+	union mc_fc_init fc_init;
+	uint64_t base_addr = (uint64_t)base;
+	uint32_t base_high = (uint32_t)(base_addr >> 32);
+
+	MCDRV_DBG_VERBOSE(mcd, "enter");
+
+	memset(&fc_init, 0, sizeof(fc_init));
+
+	fc_init.as_in.cmd = MC_FC_INIT;
+	/* base address of mci buffer 4KB aligned */
+	fc_init.as_in.base = (uint32_t)base_addr;
+	/* notification buffer start/length [16:16] [start, length] */
+	fc_init.as_in.nq_info = ((base_high && 0xFFFF) << 16) |
+				(nq_length & 0xFFFF);
+	/* mcp buffer start/length [16:16] [start, length] */
+	fc_init.as_in.mcp_info = (mcp_offset << 16) | (mcp_length & 0xFFFF);
+
+	/*
+	 * Set KMOD notification queue to start of MCI
+	 * mciInfo was already set up in mmap
+	 */
+	MCDRV_DBG(mcd,
+		  "cmd=0x%08x, base=0x%08x,nq_info=0x%08x, mcp_info=0x%08x",
+		  fc_init.as_in.cmd, fc_init.as_in.base, fc_init.as_in.nq_info,
+		  fc_init.as_in.mcp_info);
+	mc_fastcall(&fc_init.as_generic);
+	MCDRV_DBG(mcd, "out cmd=0x%08x, ret=0x%08x", fc_init.as_out.resp,
+		  fc_init.as_out.ret);
+
+	ret = convert_fc_ret(fc_init.as_out.ret);
+
+	MCDRV_DBG_VERBOSE(mcd, "exit with %d/0x%08X", ret, ret);
+
+	return ret;
+}
+
+/* Return MobiCore driver version */
+uint32_t mc_get_version(void)
+{
+	MCDRV_DBG(mcd, "MobiCore driver version is %i.%i",
+		  MCDRVMODULEAPI_VERSION_MAJOR,
+		  MCDRVMODULEAPI_VERSION_MINOR);
+
+	return MC_VERSION(MCDRVMODULEAPI_VERSION_MAJOR,
+					MCDRVMODULEAPI_VERSION_MINOR);
+}
diff --git a/drivers/gud/mobicore_driver/ops.h b/drivers/gud/MobiCoreDriver/ops.h
similarity index 78%
rename from drivers/gud/mobicore_driver/ops.h
rename to drivers/gud/MobiCoreDriver/ops.h
index 910c1f4..f04eb3e 100644
--- a/drivers/gud/mobicore_driver/ops.h
+++ b/drivers/gud/MobiCoreDriver/ops.h
@@ -21,10 +21,13 @@
 uint32_t mc_get_version(void);
 
 int mc_info(uint32_t ext_info_id, uint32_t *state, uint32_t *ext_info);
-int mc_init(uint32_t base, uint32_t  nq_offset, uint32_t  nq_length,
-	    uint32_t mcp_offset, uint32_t  mcp_length);
+int mc_init(phys_addr_t base, uint32_t  nq_length, uint32_t mcp_offset,
+		uint32_t  mcp_length);
+#ifdef TBASE_CORE_SWITCHER
+int mc_switch_core(uint32_t core_num);
+#endif
 
-void mc_fastcall(void *data);
+bool mc_fastcall(void *data);
 
 int mc_fastcall_init(struct mc_context *context);
 void mc_fastcall_destroy(void);
diff --git a/drivers/gud/mobicore_driver/platforms/msm8960_surf_std/platform.h b/drivers/gud/MobiCoreDriver/platforms/MSM8960_SURF_STD/platform.h
similarity index 85%
rename from drivers/gud/mobicore_driver/platforms/msm8960_surf_std/platform.h
rename to drivers/gud/MobiCoreDriver/platforms/MSM8960_SURF_STD/platform.h
index 7854fc5..72ea3ed 100644
--- a/drivers/gud/mobicore_driver/platforms/msm8960_surf_std/platform.h
+++ b/drivers/gud/MobiCoreDriver/platforms/MSM8960_SURF_STD/platform.h
@@ -36,20 +36,12 @@
 }
 
 /* Enable mobicore mem traces */
-/* #define MC_MEM_TRACES */
+#define MC_MEM_TRACES
 
 /* Enable the use of vm_unamp instead of the deprecated do_munmap
  * and other 3.7 features
  */
-#ifndef CONFIG_ARCH_MSM8960
 #define MC_VM_UNMAP
-#endif
-
-
-#if defined(CONFIG_ARCH_MSM8974) || defined(CONFIG_ARCH_MSM8226)
-/* Perform clock enable/disable */
-#define MC_CRYPTO_CLOCK_MANAGEMENT
-#endif
 
 /* Enable Power Management for Crypto Engine */
 #define MC_CRYPTO_CLOCK_MANAGEMENT
diff --git a/drivers/gud/mobicore_driver/pm.c b/drivers/gud/MobiCoreDriver/pm.c
similarity index 66%
rename from drivers/gud/mobicore_driver/pm.c
rename to drivers/gud/MobiCoreDriver/pm.c
index 55a1ef7..40365ef 100644
--- a/drivers/gud/mobicore_driver/pm.c
+++ b/drivers/gud/MobiCoreDriver/pm.c
@@ -46,7 +46,7 @@
 	if (!ctx->mcp)
 		return false;
 
-	if (!ctx->mcp->flags.sleep_mode.ReadyToSleep & READY_TO_SLEEP)
+	if (!(ctx->mcp->flags.sleep_mode.ready_to_sleep & READY_TO_SLEEP))
 		return false;
 
 	return true;
@@ -57,7 +57,7 @@
 	if (!ctx->mcp)
 		return;
 
-	ctx->mcp->flags.sleep_mode.SleepReq = REQ_TO_SLEEP;
+	ctx->mcp->flags.sleep_mode.sleep_req = REQ_TO_SLEEP;
 	_nsiq();
 }
 DECLARE_WORK(suspend_work, mc_suspend_handler);
@@ -66,9 +66,9 @@
 {
 	MCDRV_DBG(mcd, "MobiCore IDLE=%d!", flags->schedule);
 	MCDRV_DBG(mcd,
-		  "MobiCore Request Sleep=%d!", flags->sleep_mode.SleepReq);
+		  "MobiCore Request Sleep=%d!", flags->sleep_mode.sleep_req);
 	MCDRV_DBG(mcd,
-		  "MobiCore Sleep Ready=%d!", flags->sleep_mode.ReadyToSleep);
+		  "MobiCore Sleep Ready=%d!", flags->sleep_mode.ready_to_sleep);
 }
 
 static int mc_suspend_notifier(struct notifier_block *nb,
@@ -96,12 +96,12 @@
 		 */
 		dump_sleep_params(&mcp->flags);
 		if (!sleep_ready()) {
-			ctx->mcp->flags.sleep_mode.SleepReq = REQ_TO_SLEEP;
+			ctx->mcp->flags.sleep_mode.sleep_req = REQ_TO_SLEEP;
 			schedule_work_on(0, &suspend_work);
 			flush_work(&suspend_work);
 			if (!sleep_ready()) {
 				dump_sleep_params(&mcp->flags);
-				ctx->mcp->flags.sleep_mode.SleepReq = 0;
+				ctx->mcp->flags.sleep_mode.sleep_req = 0;
 				MCDRV_DBG_ERROR(mcd, "MobiCore can't SLEEP!");
 				return NOTIFY_BAD;
 			}
@@ -109,7 +109,7 @@
 		break;
 	case PM_POST_SUSPEND:
 		MCDRV_DBG(mcd, "Resume MobiCore system!");
-		ctx->mcp->flags.sleep_mode.SleepReq = 0;
+		ctx->mcp->flags.sleep_mode.sleep_req = 0;
 		break;
 	default:
 		break;
@@ -121,57 +121,6 @@
 	.notifier_call = mc_suspend_notifier,
 };
 
-#ifdef MC_BL_NOTIFIER
-
-static int bL_switcher_notifier_handler(struct notifier_block *this,
-			unsigned long event, void *ptr)
-{
-	unsigned int mpidr, cpu, cluster;
-	struct mc_mcp_buffer *mcp = ctx->mcp;
-
-	if (!mcp)
-		return 0;
-
-	asm volatile ("mrc\tp15, 0, %0, c0, c0, 5" : "=r" (mpidr));
-	cpu = mpidr & 0x3;
-	cluster = (mpidr >> 8) & 0xf;
-	MCDRV_DBG(mcd, "%s switching!!, cpu: %u, Out=%u\n",
-		  (event == SWITCH_ENTER ? "Before" : "After"), cpu, cluster);
-
-	if (cpu != 0)
-		return 0;
-
-	switch (event) {
-	case SWITCH_ENTER:
-		if (!sleep_ready()) {
-			ctx->mcp->flags.sleep_mode.SleepReq = REQ_TO_SLEEP;
-			_nsiq();
-			/* By this time we should be ready for sleep or we are
-			 * in the middle of something important */
-			if (!sleep_ready()) {
-				dump_sleep_params(&mcp->flags);
-				MCDRV_DBG(mcd,
-					  "MobiCore: Don't allow switch!\n");
-				ctx->mcp->flags.sleep_mode.SleepReq = 0;
-				return -EPERM;
-			}
-		}
-		break;
-	case SWITCH_EXIT:
-			ctx->mcp->flags.sleep_mode.SleepReq = 0;
-			break;
-	default:
-		MCDRV_DBG(mcd, "MobiCore: Unknown switch event!\n");
-	}
-
-	return 0;
-}
-
-static struct notifier_block switcher_nb = {
-	.notifier_call = bL_switcher_notifier_handler,
-};
-#endif
-
 int mc_pm_initialize(struct mc_context *context)
 {
 	int ret = 0;
@@ -180,12 +129,7 @@
 
 	ret = register_pm_notifier(&mc_notif_block);
 	if (ret)
-		MCDRV_DBG_ERROR(mcd, "device pm register failed\n");
-#ifdef MC_BL_NOTIFIER
-	if (register_bL_swicher_notifier(&switcher_nb))
-		MCDRV_DBG_ERROR(mcd,
-				"Failed to register to bL_switcher_notifier\n");
-#endif
+		MCDRV_DBG_ERROR(mcd, "device pm register failed");
 
 	return ret;
 }
@@ -194,15 +138,16 @@
 {
 	int ret = unregister_pm_notifier(&mc_notif_block);
 	if (ret)
-		MCDRV_DBG_ERROR(mcd, "device pm unregister failed\n");
-#ifdef MC_BL_NOTIFIER
-	ret = unregister_bL_swicher_notifier(&switcher_nb);
-	if (ret)
-		MCDRV_DBG_ERROR(mcd, "device bl unregister failed\n");
-#endif
+		MCDRV_DBG_ERROR(mcd, "device pm unregister failed");
 	return ret;
 }
 
+bool mc_pm_sleep_ready(void)
+{
+	if (ctx == 0)
+		return true;
+	return sleep_ready();
+}
 #endif /* MC_PM_RUNTIME */
 
 #ifdef MC_CRYPTO_CLOCK_MANAGEMENT
@@ -215,7 +160,7 @@
 	mc_ce_core_clk = clk_get(mcd, "core_clk");
 	if (IS_ERR(mc_ce_core_clk)) {
 		ret = PTR_ERR(mc_ce_core_clk);
-		MCDRV_DBG_ERROR(mcd, "cannot get core clock\n");
+		MCDRV_DBG_ERROR(mcd, "cannot get core clock");
 		goto error;
 	}
 	/* Get Interface clk */
@@ -223,7 +168,7 @@
 	if (IS_ERR(mc_ce_iface_clk)) {
 		clk_put(mc_ce_core_clk);
 		ret = PTR_ERR(mc_ce_iface_clk);
-		MCDRV_DBG_ERROR(mcd, "cannot get iface clock\n");
+		MCDRV_DBG_ERROR(mcd, "cannot get iface clock");
 		goto error;
 	}
 	/* Get AXI clk */
@@ -232,7 +177,7 @@
 		clk_put(mc_ce_iface_clk);
 		clk_put(mc_ce_core_clk);
 		ret = PTR_ERR(mc_ce_bus_clk);
-		MCDRV_DBG_ERROR(mcd, "cannot get AXI bus clock\n");
+		MCDRV_DBG_ERROR(mcd, "cannot get AXI bus clock");
 		goto error;
 	}
 	return ret;
@@ -263,17 +208,17 @@
 
 	rc = clk_prepare_enable(mc_ce_core_clk);
 	if (rc) {
-		MCDRV_DBG_ERROR(mcd, "cannot enable clock\n");
+		MCDRV_DBG_ERROR(mcd, "cannot enable clock");
 	} else {
 		rc = clk_prepare_enable(mc_ce_iface_clk);
 		if (rc) {
 			clk_disable_unprepare(mc_ce_core_clk);
-			MCDRV_DBG_ERROR(mcd, "cannot enable clock\n");
+			MCDRV_DBG_ERROR(mcd, "cannot enable clock");
 		} else {
 			rc = clk_prepare_enable(mc_ce_bus_clk);
 			if (rc) {
 				clk_disable_unprepare(mc_ce_iface_clk);
-				MCDRV_DBG_ERROR(mcd, "cannot enable clock\n");
+				MCDRV_DBG_ERROR(mcd, "cannot enable clock");
 			}
 		}
 	}
diff --git a/drivers/gud/mobicore_driver/pm.h b/drivers/gud/MobiCoreDriver/pm.h
similarity index 94%
rename from drivers/gud/mobicore_driver/pm.h
rename to drivers/gud/MobiCoreDriver/pm.h
index 332da34..b71c603 100644
--- a/drivers/gud/mobicore_driver/pm.h
+++ b/drivers/gud/MobiCoreDriver/pm.h
@@ -13,10 +13,6 @@
 #define _MC_PM_H_
 
 #include "main.h"
-#ifdef MC_BL_NOTIFIER
-#include <asm/bL_switcher.h>
-#endif
-
 
 #define NO_SLEEP_REQ	0
 #define REQ_TO_SLEEP	1
@@ -39,5 +35,7 @@
 int mc_pm_clock_enable(void);
 /* Disable secure crypto clocks */
 void mc_pm_clock_disable(void);
+/* Test if sleep is possible */
+bool mc_pm_sleep_ready(void);
 
 #endif /* _MC_PM_H_ */
diff --git a/drivers/gud/mobicore_driver/public/mc_kernel_api.h b/drivers/gud/MobiCoreDriver/public/mc_kernel_api.h
similarity index 89%
rename from drivers/gud/mobicore_driver/public/mc_kernel_api.h
rename to drivers/gud/MobiCoreDriver/public/mc_kernel_api.h
index cca0636..15fd4a2 100644
--- a/drivers/gud/mobicore_driver/public/mc_kernel_api.h
+++ b/drivers/gud/MobiCoreDriver/public/mc_kernel_api.h
@@ -35,13 +35,12 @@
  * @requested_size:	memory size requested in bytes
  * @handle:		pointer to handle
  * @kernel_virt_addr:	virtual user start address
- * @phys_addr:		physical start address
  *
  * Returns 0 if OK
  */
 int mobicore_allocate_wsm(struct mc_instance *instance,
 			  unsigned long requested_size, uint32_t *handle,
-			  void **virt_kernel_addr, void **phys_addr);
+			  void **virt_kernel_addr);
 
 /*
  * mobicore_free() - Free a WSM buffer allocated with mobicore_allocate_wsm
@@ -58,12 +57,11 @@
  * @addr:		address of the buffer (NB it must be kernel virtual!)
  * @len:		buffer length (in bytes)
  * @handle:		unique handle
- * @phys:		pointer for physical address of L2 table
  *
  * Returns 0 if no error
  */
 int mobicore_map_vmem(struct mc_instance *instance, void *addr,
-		      uint32_t len, uint32_t *handle, uint32_t *phys);
+		      uint32_t len, uint32_t *handle);
 
 /*
  * mobicore_unmap_vmem() - Unmap a virtual memory buffer from MobiCore
@@ -74,4 +72,12 @@
  */
 int mobicore_unmap_vmem(struct mc_instance *instance, uint32_t handle);
 
+/*
+ * mobicore_sleep_ready() - Test if mobicore can sleep
+ *
+ * Returns true if mobicore can sleep, false if it can't sleep
+ */
+bool mobicore_sleep_ready(void);
+
+
 #endif /* _MC_KERNEL_API_H_ */
diff --git a/drivers/gud/mobicore_driver/public/mc_linux.h b/drivers/gud/MobiCoreDriver/public/mc_linux.h
similarity index 81%
rename from drivers/gud/mobicore_driver/public/mc_linux.h
rename to drivers/gud/MobiCoreDriver/public/mc_linux.h
index af027dc..98e7af1 100644
--- a/drivers/gud/mobicore_driver/public/mc_linux.h
+++ b/drivers/gud/MobiCoreDriver/public/mc_linux.h
@@ -1,7 +1,7 @@
 /*
  * The MobiCore Driver Kernel Module is a Linux device driver, which represents
  * the command proxy on the lowest layer to the secure world (Swd). Additional
- * services like memory allocation via mmap and generation of a L2 tables for
+ * services like memory allocation via mmap and generation of a MMU tables for
  * given virtual memory are also supported. IRQ functionality receives
  * information from the SWd in the non secure world (NWd).
  * As customary the driver is handled as linux device driver with "open",
@@ -55,8 +55,6 @@
  * INIT request data to SWD
  */
 struct mc_ioctl_init {
-	/* notification buffer start/length [16:16] [start, length] */
-	uint32_t  nq_offset;
 	/* length of notification queue */
 	uint32_t  nq_length;
 	/* mcp buffer start/length [16:16] [start, length] */
@@ -76,8 +74,7 @@
 };
 
 /*
- * Data exchange structure of the MC_IO_MAP_WSM, MC_IO_MAP_MCI, and
- *				  MC_IO_MAP_PWSM commands.
+ * Data exchange structure of the MC_IO_MAP_WSM and MC_IO_MAP_MCI commands.
  *
  * Allocate a contiguous memory buffer for a process.
  * The physical address can be used as for later calls to mmap.
@@ -86,19 +83,19 @@
  * already. I.e. Daemon was restarted.
  */
 struct mc_ioctl_map {
-	size_t	      len;	/* Buffer length */
-	uint32_t      handle;	/* WSM handle */
-	unsigned long addr;	/* Virtual address */
-	unsigned long phys_addr;/* physical address of WSM (or NULL) */
-	bool	      reused;	/* if WSM memory was reused, or new allocated */
+	size_t		len;	/* Buffer length */
+	uint32_t	handle;	/* WSM handle */
+	uint64_t	phys_addr; /* physical address of WSM (or 0) */
+	unsigned long	addr;	/* Virtual address */
+	bool		reused;	/* if WSM memory was reused, or new allocated */
 };
 
 /*
  * Data exchange structure of the MC_IO_REG_WSM command.
  *
- * Allocates a physical L2 table and maps the buffer into this page.
- * Returns the physical address of the L2 table.
- * The page alignment will be created and the appropriated pSize and pOffsetL2
+ * Allocates a physical MMU table and maps the buffer into this page.
+ * Returns the physical address of the MMU table.
+ * The page alignment will be created and the appropriated pSize and pOffsetMMU
  * will be modified to the used values.
  */
 struct mc_ioctl_reg_wsm {
@@ -106,19 +103,7 @@
 	uint32_t len;		/* size of the virtual address space */
 	uint32_t pid;		/* process id */
 	uint32_t handle;	/* driver handle for locked memory */
-	uint32_t table_phys;	/* physical address of the L2 table */
-};
-
-
-/*
- * Data exchange structure of the MC_DRV_MODULE_FC_EXECUTE ioctl command.
- * internal, unsupported
- */
-struct mc_ioctl_execute {
-	/* base address of mobicore binary */
-	uint32_t phys_start_addr;
-	/* length of DDR area */
-	uint32_t length;
+	uint64_t table_phys;	/* physical address of the MMU table */
 };
 
 /*
@@ -127,10 +112,10 @@
 struct mc_ioctl_resolv_cont_wsm {
 	/* driver handle for buffer */
 	uint32_t handle;
-	/* base address of memory */
-	uint32_t phys;
 	/* length memory */
 	uint32_t length;
+	/* base address of memory */
+	uint64_t phys;
 	/* fd to owner of the buffer */
 	int32_t fd;
 };
@@ -144,7 +129,7 @@
 	/* fd to owner of the buffer */
 	int32_t fd;
 	/* base address of memory */
-	uint32_t phys;
+	uint64_t phys;
 };
 
 
@@ -180,28 +165,24 @@
  */
 #define MC_IO_FREE		_IO(MC_IOC_MAGIC, 5)
 /*
- * Creates a L2 Table of the given base address and the size of the
+ * Creates a MMU Table of the given base address and the size of the
  * data.
- * Parameter: mc_ioctl_app_reg_wsm_l2_params
+ * Parameter: mc_ioctl_reg_wsm
  */
 #define MC_IO_REG_WSM		_IOWR(MC_IOC_MAGIC, 6, struct mc_ioctl_reg_wsm)
 #define MC_IO_UNREG_WSM		_IO(MC_IOC_MAGIC, 7)
 #define MC_IO_LOCK_WSM		_IO(MC_IOC_MAGIC, 8)
 #define MC_IO_UNLOCK_WSM	_IO(MC_IOC_MAGIC, 9)
-#define MC_IO_EXECUTE		_IOWR(MC_IOC_MAGIC, 10, struct mc_ioctl_execute)
 
 /*
  * Allocate contiguous memory for a process for later mapping with mmap.
- * MC_DRV_KMOD_MMAP_WSM	usual operation, pages are registered in
+ * MC_IO_MAP_WSM	usual operation, pages are registered in
  *					device structure and freed later.
- * MC_DRV_KMOD_MMAP_MCI	get Instance of MCI, allocates or mmaps
+ * MC_IO_MAP_MCI	get Instance of MCI, allocates or mmaps
  *					the MCI to daemon
- * MC_DRV_KMOD_MMAP_PERSISTENTWSM	special operation, without
- *						registration of pages
  */
 #define MC_IO_MAP_WSM		_IOWR(MC_IOC_MAGIC, 11, struct mc_ioctl_map)
 #define MC_IO_MAP_MCI		_IOWR(MC_IOC_MAGIC, 12, struct mc_ioctl_map)
-#define MC_IO_MAP_PWSM		_IOWR(MC_IOC_MAGIC, 13, struct mc_ioctl_map)
 
 /*
  * Clean orphaned WSM buffers. Only available to the daemon and should
@@ -215,7 +196,7 @@
 #define MC_IO_CLEAN_WSM		_IO(MC_IOC_MAGIC, 14)
 
 /*
- * Get L2 phys address of a buffer handle allocated to the user.
+ * Get MMU phys address of a buffer handle allocated to the user.
  * Only available to the daemon.
  */
 #define MC_IO_RESOLVE_WSM	_IOWR(MC_IOC_MAGIC, 15, \
diff --git a/drivers/gud/mobicore_driver/public/version.h b/drivers/gud/MobiCoreDriver/public/version.h
similarity index 100%
rename from drivers/gud/mobicore_driver/public/version.h
rename to drivers/gud/MobiCoreDriver/public/version.h
diff --git a/drivers/gud/MobiCoreKernelApi/Makefile b/drivers/gud/MobiCoreKernelApi/Makefile
new file mode 100644
index 0000000..9b37eea
--- /dev/null
+++ b/drivers/gud/MobiCoreKernelApi/Makefile
@@ -0,0 +1,52 @@
+#
+# this makefile is called from the kernel make syste
+ifeq ($(MODE),release)
+    ccflags-y += -O2 -DNDEBUG
+else  # DEBUG
+    # "-O" is needed to expand inlines
+    ccflags-y += -O -g3 -DDEBUG
+endif # DEBUG/RELEASE
+
+ifdef MOBICORE_CFLAGS
+    ccflags-y +=$(MOBICORE_CFLAGS)
+endif
+
+#Set the extra symbols
+ifdef MCDRV_SYMBOLS_FILE
+    KBUILD_EXTRA_SYMBOLS=$(MCDRV_SYMBOLS_FILE)
+endif
+
+ifeq ($(PLATFORM), ARM_VE_A9X4_QEMU)
+	ccflags-y += -DMC_NETLINK_COMPAT_V37
+endif
+
+ifeq ($(PLATFORM), MSM8974_SURF_STD)
+	ccflags-y += -DMC_NETLINK_COMPAT_V37
+endif
+
+ifeq ($(PLATFORM), EXYNOS_5422_STD)
+	ccflags-y += -DMC_NETLINK_COMPAT_V37
+endif
+
+ifeq ($(PLATFORM), EXYNOS_5430_STD)
+	ccflags-y += -DMC_NETLINK_COMPAT_V37
+endif
+
+#EXTRA_CFLAGS += -DDEBUG -DDEBUG_VERBOSE
+#EXTRA_CFLAGS += -Wno-declaration-after-statement
+ccflags-y += -Wno-declaration-after-statement
+# add our module to kernel.
+obj-m += mcKernelApi.o
+
+mcKernelApi-objs := main.o clientlib.o device.o session.o connection.o
+
+clean:
+	rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions \
+		Module.markers Module.symvers modules.order
+
+depend .depend dep:
+	$(CC) $(CFLAGS) -M *.c > .depend
+
+ifeq (.depend,$(wildcard .depend))
+    include .depend
+endif
diff --git a/drivers/gud/MobiCoreKernelApi/build.sh b/drivers/gud/MobiCoreKernelApi/build.sh
new file mode 100644
index 0000000..86fe1b8
--- /dev/null
+++ b/drivers/gud/MobiCoreKernelApi/build.sh
@@ -0,0 +1,34 @@
+#!/bin/bash
+
+if [ -z $COMP_PATH_ROOT ]; then
+	echo "The build environment is not set!"
+	echo "Trying to source setupDrivers.sh automatically!"
+	source ../setupDrivers.sh || exit 1
+fi
+
+ROOT_PATH=$(dirname $(readlink -f $BASH_SOURCE))
+# These folders need to be relative to the kernel dir or absolute!
+PLATFORM=EXYNOS_4X12_STD
+CODE_INCLUDE=$(readlink -f $ROOT_PATH/Locals/Code)
+
+MOBICORE_DRIVER=$COMP_PATH_MobiCoreDriverMod
+MOBICORE_DAEMON=$COMP_PATH_MobiCoreDriverLib/Public
+MOBICORE_CFLAGS="-I$MOBICORE_DRIVER/Public -I$MOBICORE_DAEMON -I$COMP_PATH_MobiCore/inc/Mci -I$COMP_PATH_MobiCore/inc -I$CODE_INCLUDE/include -I$CODE_INCLUDE/public"
+MCDRV_SYMBOLS_FILE="$COMP_PATH_ROOT/MobiCoreDriverMod/Locals/Code/Module.symvers"
+
+if [ ! -f $MCDRV_SYMBOLS_FILE ]; then
+	echo "Please build the Mobicore Driver Module first!"
+	echo "Otherwise you will see warnings of missing symbols"
+fi
+
+# Clean first
+make -C $CODE_INCLUDE clean
+
+make -C $LINUX_PATH \
+	MODE=$MODE \
+	ARCH=arm \
+	CROSS_COMPILE=$CROSS_COMPILE \
+	M=$CODE_INCLUDE \
+	"MOBICORE_CFLAGS=$MOBICORE_CFLAGS" \
+	MCDRV_SYMBOLS_FILE=$MCDRV_SYMBOLS_FILE \
+	modules
diff --git a/drivers/gud/mobicore_kernelapi/clientlib.c b/drivers/gud/MobiCoreKernelApi/clientlib.c
similarity index 95%
rename from drivers/gud/mobicore_kernelapi/clientlib.c
rename to drivers/gud/MobiCoreKernelApi/clientlib.c
index 16b52e5..65b4a1c 100644
--- a/drivers/gud/mobicore_kernelapi/clientlib.c
+++ b/drivers/gud/MobiCoreKernelApi/clientlib.c
@@ -25,6 +25,7 @@
 
 /* device list */
 LIST_HEAD(devices);
+atomic_t device_usage = ATOMIC_INIT(0);
 
 static struct mcore_device_t *resolve_device_id(uint32_t device_id)
 {
@@ -71,14 +72,20 @@
 	do {
 		struct mcore_device_t *device = resolve_device_id(device_id);
 		if (device != NULL) {
-			MCDRV_DBG_ERROR(mc_kapi,
-					"Device %d already opened", device_id);
-			mc_result = MC_DRV_ERR_INVALID_OPERATION;
+			MCDRV_DBG(mc_kapi,
+				  "Device %d already opened\n", device_id);
+			atomic_inc(&device_usage);
+			mc_result = MC_DRV_OK;
 			break;
 		}
 
 		/* Open new connection to device */
 		dev_con = connection_new();
+		if (dev_con == NULL) {
+			mc_result = MC_DRV_ERR_NO_FREE_MEMORY;
+			break;
+		}
+
 		if (!connection_connect(dev_con, MC_DAEMON_PID)) {
 			MCDRV_DBG_ERROR(
 				mc_kapi,
@@ -144,6 +151,10 @@
 		/* there is no payload to read */
 
 		device = mcore_device_create(device_id, dev_con);
+		if (device == NULL) {
+			mc_result = MC_DRV_ERR_NO_FREE_MEMORY;
+			break;
+		}
 		if (!mcore_device_open(device, MC_DRV_MOD_DEVNODE_FULLPATH)) {
 			mcore_device_cleanup(device);
 			MCDRV_DBG_ERROR(mc_kapi,
@@ -154,6 +165,7 @@
 		}
 
 		add_device(device);
+		atomic_inc(&device_usage);
 
 	} while (false);
 
@@ -177,6 +189,12 @@
 			mc_result = MC_DRV_ERR_UNKNOWN_DEVICE;
 			break;
 		}
+		/* Check if it's not used by other modules */
+		if (!atomic_dec_and_test(&device_usage)) {
+			mc_result = MC_DRV_OK;
+			break;
+		}
+
 		struct connection *dev_con = device->connection;
 
 		/* Return if not all sessions have been closed */
@@ -274,12 +292,12 @@
 		}
 		struct connection *dev_con = device->connection;
 
-		/* Get the physical address of the given TCI */
+		/* Get the wsm of the given TCI */
 		struct wsm *wsm =
 			mcore_device_find_contiguous_wsm(device, tci);
 		if (wsm == NULL) {
 			MCDRV_DBG_ERROR(mc_kapi,
-					"Could not resolve TCI phy address ");
+					"Could not resolve TCI address ");
 			mc_result = MC_DRV_ERR_INVALID_PARAMETER;
 			break;
 		}
@@ -292,14 +310,14 @@
 		}
 
 		/* Prepare open session command */
-		struct mc_drv_cmd_open_session_t cmdOpenSession = {
+		struct mc_drv_cmd_open_session_t cmd_open_session = {
 			{
 				MC_DRV_CMD_OPEN_SESSION
 			},
 			{
 				session->device_id,
 				*uuid,
-				(uint32_t)(wsm->phys_addr) & 0xFFF,
+				(uint32_t)(wsm->virt_addr) & 0xFFF,
 				wsm->handle,
 				len
 			}
@@ -307,9 +325,9 @@
 
 		/* Transmit command data */
 		int len = connection_write_data(dev_con,
-						&cmdOpenSession,
-						sizeof(cmdOpenSession));
-		if (len != sizeof(cmdOpenSession)) {
+						&cmd_open_session,
+						sizeof(cmd_open_session));
+		if (len != sizeof(cmd_open_session)) {
 			MCDRV_DBG_ERROR(mc_kapi,
 					"CMD_OPEN_SESSION writeData failed %d",
 					len);
@@ -370,6 +388,10 @@
 
 		/* Set up second channel for notifications */
 		struct connection *session_connection = connection_new();
+		if (session_connection == NULL) {
+			mc_result = MC_DRV_ERR_NO_FREE_MEMORY;
+			break;
+		}
 
 		if (!connection_connect(session_connection, MC_DAEMON_PID)) {
 			MCDRV_DBG_ERROR(
@@ -422,9 +444,13 @@
 		/* there is no payload. */
 
 		/* Session established, new session object must be created */
-		mcore_device_create_new_session(device,
-						session->session_id,
-						session_connection);
+		if (!mcore_device_create_new_session(device,
+						     session->session_id,
+						     session_connection)) {
+			connection_cleanup(session_connection);
+			mc_result = MC_DRV_ERR_NO_FREE_MEMORY;
+			break;
+		}
 
 	} while (false);
 
@@ -706,7 +732,6 @@
 	MCDRV_DBG_VERBOSE(mc_kapi, "===%s()===", __func__);
 
 	do {
-
 		/* Get the device associated wit the given session */
 		device = resolve_device_id(device_id);
 		if (device == NULL) {
@@ -805,7 +830,7 @@
 			{
 				session->session_id,
 				bulk_buf->handle,
-				(uint32_t)bulk_buf->phys_addr_wsm_l2,
+				0,
 				(uint32_t)(bulk_buf->virt_addr) & 0xFFF,
 				bulk_buf->len
 			}
@@ -819,8 +844,8 @@
 		/* Read command response */
 		struct mc_drv_response_header_t rsp_header;
 		int len = connection_read_datablock(dev_con,
-						    &rsp_header,
-						    sizeof(rsp_header));
+							&rsp_header,
+							sizeof(rsp_header));
 		if (len != sizeof(rsp_header)) {
 			MCDRV_DBG_ERROR(mc_kapi,
 					"CMD_MAP_BULK_BUF readRsp failed %d",
diff --git a/drivers/gud/mobicore_kernelapi/common.h b/drivers/gud/MobiCoreKernelApi/common.h
similarity index 100%
rename from drivers/gud/mobicore_kernelapi/common.h
rename to drivers/gud/MobiCoreKernelApi/common.h
diff --git a/drivers/gud/mobicore_kernelapi/connection.c b/drivers/gud/MobiCoreKernelApi/connection.c
similarity index 96%
rename from drivers/gud/mobicore_kernelapi/connection.c
rename to drivers/gud/MobiCoreKernelApi/connection.c
index 03288a0..0372b82 100644
--- a/drivers/gud/mobicore_kernelapi/connection.c
+++ b/drivers/gud/MobiCoreKernelApi/connection.c
@@ -28,6 +28,10 @@
 	struct connection *conn;
 
 	conn = kzalloc(sizeof(*conn), GFP_KERNEL);
+	if (conn == NULL) {
+		MCDRV_DBG_ERROR(mc_kapi, "Allocation failure");
+		return NULL;
+	}
 	conn->sequence_magic = mcapi_unique_id();
 	mutex_init(&conn->data_lock);
 	sema_init(&conn->data_available_sem, SEM_NO_DATA_AVAILABLE);
@@ -36,14 +40,6 @@
 	return conn;
 }
 
-struct connection *connection_create(int socket_descriptor, pid_t dest)
-{
-	struct connection *conn = connection_new();
-
-	conn->peer_pid = dest;
-	return conn;
-}
-
 void connection_cleanup(struct connection *conn)
 {
 	if (!conn)
diff --git a/drivers/gud/mobicore_kernelapi/connection.h b/drivers/gud/MobiCoreKernelApi/connection.h
similarity index 95%
rename from drivers/gud/mobicore_kernelapi/connection.h
rename to drivers/gud/MobiCoreKernelApi/connection.h
index 6c3ff00..57e783b 100644
--- a/drivers/gud/mobicore_kernelapi/connection.h
+++ b/drivers/gud/MobiCoreKernelApi/connection.h
@@ -44,7 +44,6 @@
 };
 
 struct connection *connection_new(void);
-struct connection *connection_create(int socket_descriptor, pid_t dest);
 void connection_cleanup(struct connection *conn);
 bool connection_connect(struct connection *conn, pid_t dest);
 size_t connection_read_datablock(struct connection *conn, void *buffer,
diff --git a/drivers/gud/mobicore_kernelapi/device.c b/drivers/gud/MobiCoreKernelApi/device.c
similarity index 85%
rename from drivers/gud/mobicore_kernelapi/device.c
rename to drivers/gud/MobiCoreKernelApi/device.c
index a176322..04db4c3 100644
--- a/drivers/gud/mobicore_kernelapi/device.c
+++ b/drivers/gud/MobiCoreKernelApi/device.c
@@ -18,16 +18,18 @@
 #include "device.h"
 #include "common.h"
 
-struct wsm *wsm_create(void *virt_addr, uint32_t len, uint32_t handle,
-		       void *phys_addr)
+static struct wsm *wsm_create(void *virt_addr, uint32_t len, uint32_t handle)
 {
 	struct wsm *wsm;
 
 	wsm = kzalloc(sizeof(*wsm), GFP_KERNEL);
+	if (wsm == NULL) {
+		MCDRV_DBG_ERROR(mc_kapi, "Allocation failure");
+		return NULL;
+	}
 	wsm->virt_addr = virt_addr;
 	wsm->len = len;
 	wsm->handle = handle;
-	wsm->phys_addr = phys_addr;
 	return wsm;
 }
 
@@ -37,11 +39,15 @@
 	struct mcore_device_t *dev;
 
 	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+	if (dev == NULL) {
+		MCDRV_DBG_ERROR(mc_kapi, "Allocation failure");
+		return NULL;
+	}
 	dev->device_id = device_id;
 	dev->connection = connection;
 
 	INIT_LIST_HEAD(&dev->session_vector);
-	INIT_LIST_HEAD(&dev->wsm_l2_vector);
+	INIT_LIST_HEAD(&dev->wsm_mmu_vector);
 
 	return dev;
 }
@@ -63,7 +69,7 @@
 	}
 
 	/* Free all allocated WSM descriptors */
-	list_for_each_safe(pos, q, &dev->wsm_l2_vector) {
+	list_for_each_safe(pos, q, &dev->wsm_mmu_vector) {
 		wsm = list_entry(pos, struct wsm, list);
 		list_del(pos);
 		kfree(wsm);
@@ -74,7 +80,7 @@
 	kfree(dev);
 }
 
-bool mcore_device_open(struct mcore_device_t *dev, const char *deviceName)
+bool mcore_device_open(struct mcore_device_t *dev, const char *device_name)
 {
 	dev->instance = mobicore_open();
 	return (dev->instance != NULL);
@@ -102,6 +108,8 @@
 	}
 	struct session *session =
 			session_create(session_id, dev->instance, connection);
+	if (session == NULL)
+		return false;
 	list_add_tail(&(session->list), &(dev->session_vector));
 	return true;
 }
@@ -154,16 +162,19 @@
 		/* Allocate shared memory */
 		void *virt_addr;
 		uint32_t handle;
-		void *phys_addr;
 		int ret = mobicore_allocate_wsm(dev->instance, len, &handle,
-						&virt_addr, &phys_addr);
+						&virt_addr);
 		if (ret != 0)
 			break;
 
-		/* Register (vaddr,paddr) with device */
-		wsm = wsm_create(virt_addr, len, handle, phys_addr);
+		/* Register (vaddr) with device */
+		wsm = wsm_create(virt_addr, len, handle);
+		if (wsm == NULL) {
+			mobicore_free_wsm(dev->instance, handle);
+			break;
+		}
 
-		list_add_tail(&(wsm->list), &(dev->wsm_l2_vector));
+		list_add_tail(&(wsm->list), &(dev->wsm_mmu_vector));
 
 	} while (0);
 
@@ -177,7 +188,7 @@
 	struct wsm *tmp;
 	struct list_head *pos;
 
-	list_for_each(pos, &dev->wsm_l2_vector) {
+	list_for_each(pos, &dev->wsm_mmu_vector) {
 		tmp = list_entry(pos, struct wsm, list);
 		if (tmp == wsm) {
 			ret = true;
@@ -205,7 +216,7 @@
 	struct wsm *wsm;
 	struct list_head *pos;
 
-	list_for_each(pos, &dev->wsm_l2_vector) {
+	list_for_each(pos, &dev->wsm_mmu_vector) {
 		wsm = list_entry(pos, struct wsm, list);
 		if (virt_addr == wsm->virt_addr)
 			return wsm;
diff --git a/drivers/gud/mobicore_kernelapi/device.h b/drivers/gud/MobiCoreKernelApi/device.h
similarity index 95%
rename from drivers/gud/mobicore_kernelapi/device.h
rename to drivers/gud/MobiCoreKernelApi/device.h
index 16626bd..c795ee8 100644
--- a/drivers/gud/mobicore_kernelapi/device.h
+++ b/drivers/gud/MobiCoreKernelApi/device.h
@@ -21,7 +21,7 @@
 struct mcore_device_t {
 	/* MobiCore Trustlet session associated with the device */
 	struct list_head	session_vector;
-	struct list_head	 wsm_l2_vector; /* WSM L2 Table  */
+	struct list_head	wsm_mmu_vector; /* WSM L2 or L3 Table  */
 
 	uint32_t		device_id;	/* Device identifier */
 	struct connection	*connection;	/* The device connection */
@@ -36,7 +36,7 @@
 void mcore_device_cleanup(struct mcore_device_t *dev);
 
 
-bool mcore_device_open(struct mcore_device_t *dev, const char *deviceName);
+bool mcore_device_open(struct mcore_device_t *dev, const char *device_name);
 void mcore_device_close(struct mcore_device_t *dev);
 bool mcore_device_has_sessions(struct mcore_device_t *dev);
 bool mcore_device_create_new_session(
diff --git a/drivers/gud/mobicore_kernelapi/include/mcinq.h b/drivers/gud/MobiCoreKernelApi/include/mcinq.h
similarity index 100%
rename from drivers/gud/mobicore_kernelapi/include/mcinq.h
rename to drivers/gud/MobiCoreKernelApi/include/mcinq.h
diff --git a/drivers/gud/mobicore_kernelapi/include/mcuuid.h b/drivers/gud/MobiCoreKernelApi/include/mcuuid.h
similarity index 100%
rename from drivers/gud/mobicore_kernelapi/include/mcuuid.h
rename to drivers/gud/MobiCoreKernelApi/include/mcuuid.h
diff --git a/drivers/gud/mobicore_kernelapi/main.c b/drivers/gud/MobiCoreKernelApi/main.c
similarity index 97%
rename from drivers/gud/mobicore_kernelapi/main.c
rename to drivers/gud/MobiCoreKernelApi/main.c
index 8943c26..5da3ef7 100644
--- a/drivers/gud/mobicore_kernelapi/main.c
+++ b/drivers/gud/MobiCoreKernelApi/main.c
@@ -150,6 +150,10 @@
 	dev_info(mc_kapi, "Mobicore API module initialized!\n");
 
 	mod_ctx = kzalloc(sizeof(struct mc_kernelapi_ctx), GFP_KERNEL);
+	if (mod_ctx == NULL) {
+		MCDRV_DBG_ERROR(mc_kapi, "Allocation failure");
+		return -ENOMEM;
+	}
 #ifdef MC_NETLINK_COMPAT_V37
 	mod_ctx->sk = netlink_kernel_create(&init_net, MC_DAEMON_NETLINK,
 					    &cfg);
diff --git a/drivers/gud/mobicore_kernelapi/public/mobicore_driver_api.h b/drivers/gud/MobiCoreKernelApi/public/mobicore_driver_api.h
similarity index 100%
rename from drivers/gud/mobicore_kernelapi/public/mobicore_driver_api.h
rename to drivers/gud/MobiCoreKernelApi/public/mobicore_driver_api.h
diff --git a/drivers/gud/mobicore_kernelapi/public/mobicore_driver_cmd.h b/drivers/gud/MobiCoreKernelApi/public/mobicore_driver_cmd.h
similarity index 99%
rename from drivers/gud/mobicore_kernelapi/public/mobicore_driver_cmd.h
rename to drivers/gud/MobiCoreKernelApi/public/mobicore_driver_cmd.h
index eaf7e6c..993d581 100644
--- a/drivers/gud/mobicore_kernelapi/public/mobicore_driver_cmd.h
+++ b/drivers/gud/MobiCoreKernelApi/public/mobicore_driver_cmd.h
@@ -171,7 +171,7 @@
 struct mc_drv_cmd_map_bulk_mem_payload_t {
 	uint32_t session_id;
 	uint32_t handle;
-	uint32_t phys_addr_l2;
+	uint32_t rfu;
 	uint32_t offset_payload;
 	uint32_t len_bulk_mem;
 };
diff --git a/drivers/gud/mobicore_kernelapi/session.c b/drivers/gud/MobiCoreKernelApi/session.c
similarity index 86%
rename from drivers/gud/mobicore_kernelapi/session.c
rename to drivers/gud/MobiCoreKernelApi/session.c
index dae2c00..2ea50e8 100644
--- a/drivers/gud/mobicore_kernelapi/session.c
+++ b/drivers/gud/MobiCoreKernelApi/session.c
@@ -14,15 +14,18 @@
 #include "session.h"
 
 struct bulk_buffer_descriptor *bulk_buffer_descriptor_create(
-	void *virt_addr, uint32_t len, uint32_t handle, void *phys_addr_wsm_l2)
+	void *virt_addr, uint32_t len, uint32_t handle)
 {
 	struct bulk_buffer_descriptor *desc;
 
 	desc = kzalloc(sizeof(*desc), GFP_KERNEL);
+	if (desc == NULL) {
+		MCDRV_DBG_ERROR(mc_kapi, "Allocation failure");
+		return NULL;
+	}
 	desc->virt_addr = virt_addr;
 	desc->len = len;
 	desc->handle = handle;
-	desc->phys_addr_wsm_l2 = phys_addr_wsm_l2;
 
 	return desc;
 }
@@ -33,6 +36,10 @@
 	struct session *session;
 
 	session = kzalloc(sizeof(*session), GFP_KERNEL);
+	if (session == NULL) {
+		MCDRV_DBG_ERROR(mc_kapi, "Allocation failure");
+		return NULL;
+	}
 	session->session_id = session_id;
 	session->instance = instance;
 	session->notification_connection = connection;
@@ -47,19 +54,14 @@
 {
 	struct bulk_buffer_descriptor *bulk_buf_descr;
 	struct list_head *pos, *q;
-	unsigned int phys_addr_wsm_l2;
 
 	/* Unmap still mapped buffers */
 	list_for_each_safe(pos, q, &session->bulk_buffer_descriptors) {
 		bulk_buf_descr =
 			list_entry(pos, struct bulk_buffer_descriptor, list);
 
-		phys_addr_wsm_l2 =
-			(unsigned int)bulk_buf_descr->phys_addr_wsm_l2;
-
 		MCDRV_DBG_VERBOSE(mc_kapi,
-				  "Phys Addr of L2 Table = 0x%X, handle= %d",
-				  phys_addr_wsm_l2,
+				  "handle= %d",
 				  bulk_buf_descr->handle);
 
 		/* ignore any error, as we cannot do anything in this case. */
@@ -110,11 +112,10 @@
 		 * Prepare the interface structure for memory registration in
 		 * Kernel Module
 		 */
-		uint32_t l2_table_phys;
 		uint32_t handle;
 
 		int ret = mobicore_map_vmem(session->instance, buf, len,
-					    &handle, &l2_table_phys);
+					    &handle);
 
 		if (ret != 0) {
 			MCDRV_DBG_ERROR(mc_kapi,
@@ -123,15 +124,15 @@
 			break;
 		}
 
-		MCDRV_DBG_VERBOSE(mc_kapi,
-				  "Phys Addr of L2 Table = 0x%X, handle=%d",
-				  (unsigned int)l2_table_phys, handle);
+		MCDRV_DBG_VERBOSE(mc_kapi, "handle=%d", handle);
 
 		/* Create new descriptor */
 		bulk_buf_descr =
-			bulk_buffer_descriptor_create(buf, len,
-						      handle,
-						      (void *)l2_table_phys);
+			bulk_buffer_descriptor_create(buf, len, handle);
+		if (bulk_buf_descr == NULL) {
+			mobicore_unmap_vmem(session->instance, handle);
+			break;
+		}
 
 		/* Add to vector of descriptors */
 		list_add_tail(&(bulk_buf_descr->list),
@@ -165,8 +166,7 @@
 		MCDRV_DBG_ERROR(mc_kapi, "Virtual Address not found");
 		ret = false;
 	} else {
-		MCDRV_DBG_VERBOSE(mc_kapi, "WsmL2 phys=0x%X, handle=%d",
-				  (unsigned int)bulk_buf->phys_addr_wsm_l2,
+		MCDRV_DBG_VERBOSE(mc_kapi, "Wsm handle=%d",
 				  bulk_buf->handle);
 
 		/* ignore any error, as we cannot do anything */
diff --git a/drivers/gud/mobicore_kernelapi/session.h b/drivers/gud/MobiCoreKernelApi/session.h
similarity index 96%
rename from drivers/gud/mobicore_kernelapi/session.h
rename to drivers/gud/MobiCoreKernelApi/session.h
index 4a834e5..edcadcd 100644
--- a/drivers/gud/mobicore_kernelapi/session.h
+++ b/drivers/gud/MobiCoreKernelApi/session.h
@@ -19,9 +19,6 @@
 	uint32_t	len;		/* Length of the Bulk buffer */
 	uint32_t	handle;
 
-	/* The physical address of the L2 table of the Bulk buffer*/
-	void		*phys_addr_wsm_l2;
-
 	/* The list param for using the kernel lists*/
 	struct list_head list;
 };
@@ -29,8 +26,7 @@
 struct bulk_buffer_descriptor *bulk_buffer_descriptor_create(
 	void		*virt_addr,
 	uint32_t	len,
-	uint32_t	handle,
-	void		*phys_addr_wsm_l2
+	uint32_t	handle
 );
 
 /*
diff --git a/drivers/gud/mobicore_kernelapi/wsm.h b/drivers/gud/MobiCoreKernelApi/wsm.h
similarity index 74%
rename from drivers/gud/mobicore_kernelapi/wsm.h
rename to drivers/gud/MobiCoreKernelApi/wsm.h
index f8a107c..3a1767d 100644
--- a/drivers/gud/mobicore_kernelapi/wsm.h
+++ b/drivers/gud/MobiCoreKernelApi/wsm.h
@@ -17,17 +17,7 @@
 	void			*virt_addr;
 	uint32_t		len;
 	uint32_t		handle;
-	void			*phys_addr;
 	struct list_head	list;
 };
 
-struct wsm *wsm_create(
-	void			*virt_addr,
-	uint32_t		len,
-	uint32_t		handle,
-
-	/* NULL this may be unknown, so is can be omitted */
-	void			*phys_addr
-);
-
 #endif /* _MC_KAPI_WSM_H_ */
diff --git a/drivers/gud/mobicore_driver/build_tag.h b/drivers/gud/build_tag.h
similarity index 96%
rename from drivers/gud/mobicore_driver/build_tag.h
rename to drivers/gud/build_tag.h
index 4a24275..18faf5a 100644
--- a/drivers/gud/mobicore_driver/build_tag.h
+++ b/drivers/gud/build_tag.h
@@ -26,4 +26,4 @@
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 #define MOBICORE_COMPONENT_BUILD_TAG \
-		"*** t-base-202_V001 ###"
+		"*** t-base-300-QC-8974-Android-V001 ###"
diff --git a/drivers/gud/mobicore_driver/mem.c b/drivers/gud/mobicore_driver/mem.c
deleted file mode 100644
index 33c51b6..0000000
--- a/drivers/gud/mobicore_driver/mem.c
+++ /dev/null
@@ -1,708 +0,0 @@
-/*
- * MobiCore Driver Kernel Module.
- *
- * This module is written as a Linux device driver.
- * This driver represents the command proxy on the lowest layer, from the
- * secure world to the non secure world, and vice versa.
- * This driver is located in the non secure world (Linux).
- * This driver offers IOCTL commands, for access to the secure world, and has
- * the interface from the secure world to the normal world.
- * The access to the driver is possible with a file descriptor,
- * which has to be created by the fd = open(/dev/mobicore) command.
- *
- * <-- Copyright Giesecke & Devrient GmbH 2009-2012 -->
- * <-- Copyright Trustonic Limited 2013 -->
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-#include "main.h"
-#include "debug.h"
-#include "mem.h"
-
-#include <linux/highmem.h>
-#include <linux/slab.h>
-#include <linux/kthread.h>
-#include <linux/pagemap.h>
-#include <linux/device.h>
-
-
-/* MobiCore memory context data */
-struct mc_mem_context mem_ctx;
-
-/* convert L2 PTE to page pointer */
-static inline struct page *l2_pte_to_page(pte_t pte)
-{
-	unsigned long phys_page_addr = ((unsigned long)pte & PAGE_MASK);
-	unsigned int pfn = phys_page_addr >> PAGE_SHIFT;
-	struct page *page = pfn_to_page(pfn);
-	return page;
-}
-
-/* convert page pointer to L2 PTE */
-static inline pte_t page_to_l2_pte(struct page *page)
-{
-	unsigned long pfn = page_to_pfn(page);
-	unsigned long phys_addr = (pfn << PAGE_SHIFT);
-	pte_t pte = (pte_t)(phys_addr & PAGE_MASK);
-	return pte;
-}
-
-static inline void release_page(struct page *page)
-{
-	SetPageDirty(page);
-
-	page_cache_release(page);
-}
-
-static int lock_pages(struct task_struct *task, void *virt_start_page_addr,
-	int pages_no, struct page **pages)
-{
-	int locked_pages;
-
-	/* lock user pages, must hold the mmap_sem to do this. */
-	down_read(&(task->mm->mmap_sem));
-	locked_pages = get_user_pages(
-				task,
-				task->mm,
-				(unsigned long)virt_start_page_addr,
-				pages_no,
-				1, /* write access */
-				0,
-				pages,
-				NULL);
-	up_read(&(task->mm->mmap_sem));
-
-	/* check if we could lock all pages. */
-	if (locked_pages != pages_no) {
-		MCDRV_DBG_ERROR(mcd, "get_user_pages() failed, locked_pages=%d",
-				locked_pages);
-		if (locked_pages > 0) {
-			/* release all locked pages. */
-			release_pages(pages, locked_pages, 0);
-		}
-		return -ENOMEM;
-	}
-
-	return 0;
-}
-
-/* Get kernel pointer to shared L2 table given a per-process reference */
-struct l2table *get_l2_table_kernel_virt(struct mc_l2_table *table)
-{
-	if (WARN(!table, "Invalid L2 table"))
-		return NULL;
-
-	if (WARN(!table->set, "Invalid L2 table set"))
-		return NULL;
-
-	if (WARN(!table->set->kernel_virt, "Invalid L2 pointer"))
-		return NULL;
-
-	return &(table->set->kernel_virt->table[table->idx]);
-}
-
-/* Get physical address of a shared L2 table given a per-process reference */
-struct l2table *get_l2_table_phys(struct mc_l2_table *table)
-{
-	if (WARN(!table, "Invalid L2 table"))
-		return NULL;
-	if (WARN(!table->set, "Invalid L2 table set"))
-		return NULL;
-	if (WARN(!table->set->kernel_virt, "Invalid L2 phys pointer"))
-		return NULL;
-
-	return &(table->set->phys->table[table->idx]);
-}
-
-static inline int in_use(struct mc_l2_table *table)
-{
-	return atomic_read(&table->usage) > 0;
-}
-
-/*
- * Search the list of used l2 tables and return the one with the handle.
- * Assumes the table_lock is taken.
- */
-struct mc_l2_table *find_l2_table(unsigned int handle)
-{
-	struct mc_l2_table *table;
-
-	list_for_each_entry(table, &mem_ctx.l2_tables, list) {
-		if (table->handle == handle)
-			return table;
-	}
-	return NULL;
-}
-
-/*
- * Allocate a new l2 table store plus L2_TABLES_PER_PAGE in the l2 free tables
- * list. Assumes the table_lock is already taken by the caller above.
- */
-static int alloc_table_store(void)
-{
-	unsigned long store;
-	struct mc_l2_tables_set *l2table_set;
-	struct mc_l2_table *l2table, *l2table2;
-	struct page *page;
-	int ret = 0, i;
-	/* temp list for holding the l2 tables */
-	LIST_HEAD(temp);
-
-	store = get_zeroed_page(GFP_KERNEL);
-	if (!store)
-		return -ENOMEM;
-
-	/*
-	 * Actually, locking is not necessary, because kernel
-	 * memory is not supposed to get swapped out. But we
-	 * play safe....
-	 */
-	page = virt_to_page(store);
-	SetPageReserved(page);
-
-	/* add all the descriptors to the free descriptors list */
-	l2table_set = kmalloc(sizeof(*l2table_set), GFP_KERNEL | __GFP_ZERO);
-	if (l2table_set == NULL) {
-		ret = -ENOMEM;
-		goto free_store;
-	}
-	/* initialize */
-	l2table_set->kernel_virt = (void *)store;
-	l2table_set->page = page;
-	l2table_set->phys = (void *)virt_to_phys((void *)store);
-	/* the set is not yet used */
-	atomic_set(&l2table_set->used_tables, 0);
-
-	/* init add to list. */
-	INIT_LIST_HEAD(&(l2table_set->list));
-	list_add(&l2table_set->list, &mem_ctx.l2_tables_sets);
-
-	for (i = 0; i < L2_TABLES_PER_PAGE; i++) {
-		/* allocate a WSM L2 descriptor */
-		l2table  = kmalloc(sizeof(*l2table), GFP_KERNEL | __GFP_ZERO);
-		if (l2table == NULL) {
-			ret = -ENOMEM;
-			MCDRV_DBG_ERROR(mcd, "out of memory\n");
-			/* Free the full temp list and the store in this case */
-			goto free_temp_list;
-		}
-
-		/* set set reference */
-		l2table->set = l2table_set;
-		l2table->idx = i;
-		l2table->virt = get_l2_table_kernel_virt(l2table);
-		l2table->phys = (unsigned long)get_l2_table_phys(l2table);
-		atomic_set(&l2table->usage, 0);
-
-		/* add to temp list. */
-		INIT_LIST_HEAD(&l2table->list);
-		list_add_tail(&l2table->list, &temp);
-	}
-
-	/*
-	 * If everything went ok then merge the temp list with the global
-	 * free list
-	 */
-	list_splice_tail(&temp, &mem_ctx.free_l2_tables);
-	return 0;
-free_temp_list:
-	list_for_each_entry_safe(l2table, l2table2, &temp, list) {
-		kfree(l2table);
-	}
-
-	list_del(&l2table_set->list);
-
-free_store:
-	free_page(store);
-	return ret;
-
-}
-/*
- * Get a l2 table from the free tables list or allocate a new one and
- * initialize it. Assumes the table_lock is already taken.
- */
-static struct mc_l2_table *alloc_l2_table(struct mc_instance *instance)
-{
-	int ret = 0;
-	struct mc_l2_table *table = NULL;
-
-	if (list_empty(&mem_ctx.free_l2_tables)) {
-		ret = alloc_table_store();
-		if (ret) {
-			MCDRV_DBG_ERROR(mcd, "Failed to allocate new store!");
-			return ERR_PTR(-ENOMEM);
-		}
-		/* if it's still empty something wrong has happened */
-		if (list_empty(&mem_ctx.free_l2_tables)) {
-			MCDRV_DBG_ERROR(mcd,
-					"Free list not updated correctly!");
-			return ERR_PTR(-EFAULT);
-		}
-	}
-
-	/* get a WSM L2 descriptor */
-	table  = list_first_entry(&mem_ctx.free_l2_tables,
-		struct mc_l2_table, list);
-	if (table == NULL) {
-		MCDRV_DBG_ERROR(mcd, "out of memory\n");
-		return ERR_PTR(-ENOMEM);
-	}
-	/* Move it to the used l2 tables list */
-	list_move_tail(&table->list, &mem_ctx.l2_tables);
-
-	table->handle = get_unique_id();
-	table->owner = instance;
-
-	atomic_inc(&table->set->used_tables);
-	atomic_inc(&table->usage);
-
-	MCDRV_DBG_VERBOSE(mcd,
-			  "chunkPhys=%p,idx=%d", table->set->phys, table->idx);
-
-	return table;
-}
-
-/*
- * Frees the object associated with a l2 table. Initially the object is moved
- * to the free tables list, but if all the 4 lists of the store are free
- * then the store is also released.
- * Assumes the table_lock is already taken.
- */
-static void free_l2_table(struct mc_l2_table *table)
-{
-	struct mc_l2_tables_set *l2table_set;
-
-	if (WARN(!table, "Invalid table"))
-		return;
-
-	l2table_set = table->set;
-	if (WARN(!l2table_set, "Invalid table set"))
-		return;
-
-	list_move_tail(&table->list, &mem_ctx.free_l2_tables);
-
-	/* if nobody uses this set, we can release it. */
-	if (atomic_dec_and_test(&l2table_set->used_tables)) {
-		struct mc_l2_table *tmp;
-
-		/* remove from list */
-		list_del(&l2table_set->list);
-		/*
-		 * All the l2 tables are in the free list for this set
-		 * so we can just remove them from there
-		 */
-		list_for_each_entry_safe(table, tmp, &mem_ctx.free_l2_tables,
-					 list) {
-			if (table->set == l2table_set) {
-				list_del(&table->list);
-				kfree(table);
-			}
-		} /* end while */
-
-		/*
-		 * We shouldn't recover from this since it was some data
-		 * corruption before
-		 */
-		BUG_ON(!l2table_set->page);
-		ClearPageReserved(l2table_set->page);
-
-		BUG_ON(!l2table_set->kernel_virt);
-		free_page((unsigned long)l2table_set->kernel_virt);
-
-		kfree(l2table_set);
-	}
-}
-
-/*
- * Create a L2 table in a WSM container that has been allocates previously.
- * Assumes the table lock is already taken or there is no need to take like
- * when first creating the l2 table the full list is locked.
- *
- * @task	pointer to task owning WSM
- * @wsm_buffer	user space WSM start
- * @wsm_len	WSM length
- * @table	Pointer to L2 table details
- */
-static int map_buffer(struct task_struct *task, void *wsm_buffer,
-		      unsigned int wsm_len, struct mc_l2_table *table)
-{
-	int		ret = 0;
-	unsigned int	i, nr_of_pages;
-	/* start address of the 4 KiB page of wsm_buffer */
-	void		*virt_addr_page;
-	struct page	*page;
-	struct l2table	*l2table;
-	struct page	**l2table_as_array_of_pointers_to_page;
-	/* page offset in wsm buffer */
-	unsigned int offset;
-
-	if (WARN(!wsm_buffer, "Invalid WSM buffer pointer"))
-		return -EINVAL;
-
-	if (WARN(wsm_len == 0, "Invalid WSM buffer length"))
-		return -EINVAL;
-
-	if (WARN(!table, "Invalid mapping table for WSM"))
-		return -EINVAL;
-
-	/* no size > 1Mib supported */
-	if (wsm_len > SZ_1M) {
-		MCDRV_DBG_ERROR(mcd, "size > 1 MiB\n");
-		return -EINVAL;
-	}
-
-	MCDRV_DBG_VERBOSE(mcd, "WSM addr=0x%p, len=0x%08x\n", wsm_buffer,
-			  wsm_len);
-
-
-	/* calculate page usage */
-	virt_addr_page = (void *)(((unsigned long)(wsm_buffer)) & PAGE_MASK);
-	offset = (unsigned int)	(((unsigned long)(wsm_buffer)) & (~PAGE_MASK));
-	nr_of_pages  = PAGE_ALIGN(offset + wsm_len) / PAGE_SIZE;
-
-	MCDRV_DBG_VERBOSE(mcd, "virt addr page start=0x%p, pages=%d\n",
-			  virt_addr_page, nr_of_pages);
-
-	/* L2 table can hold max 1MiB in 256 pages. */
-	if ((nr_of_pages * PAGE_SIZE) > SZ_1M) {
-		MCDRV_DBG_ERROR(mcd, "WSM paged exceed 1 MiB\n");
-		return -EINVAL;
-	}
-
-	l2table = table->virt;
-	/*
-	 * We use the memory for the L2 table to hold the pointer
-	 * and convert them later. This works, as everything comes
-	 * down to a 32 bit value.
-	 */
-	l2table_as_array_of_pointers_to_page = (struct page **)l2table;
-
-	/* Request comes from user space */
-	if (task != NULL && !is_vmalloc_addr(wsm_buffer)) {
-		/*
-		 * lock user page in memory, so they do not get swapped
-		 * out.
-		 * REV axh: Kernel 2.6.27 added a new get_user_pages_fast()
-		 * function, maybe it is called fast_gup() in some versions.
-		 * handle user process doing a fork().
-		 * Child should not get things.
-		 * http://osdir.com/ml/linux-media/2009-07/msg00813.html
-		 * http://lwn.net/Articles/275808/
-		 */
-		ret = lock_pages(task, virt_addr_page, nr_of_pages,
-				 l2table_as_array_of_pointers_to_page);
-		if (ret != 0) {
-			MCDRV_DBG_ERROR(mcd, "lock_user_pages() failed\n");
-			return ret;
-		}
-	}
-	/* Request comes from kernel space(cont buffer) */
-	else if (task == NULL && !is_vmalloc_addr(wsm_buffer)) {
-		void *uaddr = wsm_buffer;
-		for (i = 0; i < nr_of_pages; i++) {
-			page = virt_to_page(uaddr);
-			if (!page) {
-				MCDRV_DBG_ERROR(mcd, "failed to map address");
-				return -EINVAL;
-			}
-			get_page(page);
-			l2table_as_array_of_pointers_to_page[i] = page;
-			uaddr += PAGE_SIZE;
-		}
-	}
-	/* Request comes from kernel space(vmalloc buffer) */
-	else {
-		void *uaddr = wsm_buffer;
-		for (i = 0; i < nr_of_pages; i++) {
-			page = vmalloc_to_page(uaddr);
-			if (!page) {
-				MCDRV_DBG_ERROR(mcd, "failed to map address");
-				return -EINVAL;
-			}
-			get_page(page);
-			l2table_as_array_of_pointers_to_page[i] = page;
-			uaddr += PAGE_SIZE;
-		}
-	}
-
-	table->pages = nr_of_pages;
-
-	/*
-	 * create L2 Table entries.
-	 * used_l2table->table contains a list of page pointers here.
-	 * For a proper cleanup we have to ensure that the following
-	 * code either works and used_l2table contains a valid L2 table
-	 * - or fails and used_l2table->table contains the list of page
-	 * pointers.
-	 * Any mixed contents will make cleanup difficult.
-	 */
-	for (i = 0; i < nr_of_pages; i++) {
-		pte_t pte;
-		page = l2table_as_array_of_pointers_to_page[i];
-
-		/*
-		 * create L2 table entry, see ARM MMU docu for details
-		 * about flags stored in the lowest 12 bits.
-		 * As a side reference, the Article
-		 * "ARM's multiply-mapped memory mess"
-		 * found in the collection at
-		 * http://lwn.net/Articles/409032/
-		 * is also worth reading.
-		 */
-		pte = page_to_l2_pte(page)
-				| PTE_EXT_AP1 | PTE_EXT_AP0
-				| PTE_CACHEABLE | PTE_BUFFERABLE
-				| PTE_TYPE_SMALL | PTE_TYPE_EXT | PTE_EXT_NG;
-		/*
-		 * Linux uses different mappings for SMP systems(the
-		 * sharing flag is set for the pte. In order not to
-		 * confuse things too much in Mobicore make sure the
-		 * shared buffers have the same flags.
-		 * This should also be done in SWD side
-		 */
-#ifdef CONFIG_SMP
-		pte |= PTE_EXT_SHARED | PTE_EXT_TEX(1);
-#endif
-
-		l2table->table_entries[i] = pte;
-		MCDRV_DBG_VERBOSE(mcd, "L2 entry %d:  0x%08x\n", i,
-				  (unsigned int)(pte));
-	}
-
-	/* ensure rest of table is empty */
-	while (i < 255)
-		l2table->table_entries[i++] = (pte_t)0;
-
-
-	return ret;
-}
-
-/*
- * Remove a L2 table in a WSM container. Afterwards the container may be
- * released. Assumes the table_lock and the lock is taken.
- */
-static void unmap_buffers(struct mc_l2_table *table)
-{
-	struct l2table *l2table;
-	int i;
-
-	if (WARN_ON(!table))
-		return;
-
-	/* found the table, now release the resources. */
-	MCDRV_DBG_VERBOSE(mcd, "clear L2 table, phys_base=%p, nr_of_pages=%d\n",
-			  (void *)table->phys, table->pages);
-
-	l2table = table->virt;
-
-	/* release all locked user space pages */
-	for (i = 0; i < table->pages; i++) {
-		/* convert physical entries from L2 table to page pointers */
-		pte_t pte = l2table->table_entries[i];
-		struct page *page = l2_pte_to_page(pte);
-		release_page(page);
-	}
-
-	/* remember that all pages have been freed */
-	table->pages = 0;
-}
-
-/* Delete a used l2 table. Assumes the table_lock and the lock is taken */
-static void unmap_l2_table(struct mc_l2_table *table)
-{
-	/* Check if it's not locked by other processes too! */
-	if (!atomic_dec_and_test(&table->usage))
-		return;
-
-	/* release if Nwd and Swd/MC do no longer use it. */
-	unmap_buffers(table);
-	free_l2_table(table);
-}
-
-int mc_free_l2_table(struct mc_instance *instance, uint32_t handle)
-{
-	struct mc_l2_table *table;
-	int ret = 0;
-
-	if (WARN(!instance, "No instance data available"))
-		return -EFAULT;
-
-	mutex_lock(&mem_ctx.table_lock);
-	table = find_l2_table(handle);
-
-	if (table == NULL) {
-		MCDRV_DBG_VERBOSE(mcd, "entry not found");
-		ret = -EINVAL;
-		goto err_unlock;
-	}
-	if (instance != table->owner && !is_daemon(instance)) {
-		MCDRV_DBG_ERROR(mcd, "instance does no own it");
-		ret = -EPERM;
-		goto err_unlock;
-	}
-	/* free table (if no further locks exist) */
-	unmap_l2_table(table);
-err_unlock:
-	mutex_unlock(&mem_ctx.table_lock);
-
-	return ret;
-}
-
-int mc_lock_l2_table(struct mc_instance *instance, uint32_t handle)
-{
-	int ret = 0;
-	struct mc_l2_table *table = NULL;
-
-	if (WARN(!instance, "No instance data available"))
-		return -EFAULT;
-
-	mutex_lock(&mem_ctx.table_lock);
-	table = find_l2_table(handle);
-
-	if (table == NULL) {
-		MCDRV_DBG_VERBOSE(mcd, "entry not found %u\n", handle);
-		ret = -EINVAL;
-		goto table_err;
-	}
-	if (instance != table->owner && !is_daemon(instance)) {
-		MCDRV_DBG_ERROR(mcd, "instance does no own it\n");
-		ret = -EPERM;
-		goto table_err;
-	}
-
-	/* lock entry */
-	atomic_inc(&table->usage);
-table_err:
-	mutex_unlock(&mem_ctx.table_lock);
-	return ret;
-}
-/*
- * Allocate L2 table and map buffer into it.
- * That is, create respective table entries.
- * Must hold Semaphore mem_ctx.wsm_l2_sem
- */
-struct mc_l2_table *mc_alloc_l2_table(struct mc_instance *instance,
-	struct task_struct *task, void *wsm_buffer, unsigned int wsm_len)
-{
-	int ret = 0;
-	struct mc_l2_table *table;
-
-	if (WARN(!instance, "No instance data available"))
-		return ERR_PTR(-EFAULT);
-
-	mutex_lock(&mem_ctx.table_lock);
-	table = alloc_l2_table(instance);
-	if (IS_ERR(table)) {
-		MCDRV_DBG_ERROR(mcd, "allocate_used_l2_table() failed\n");
-		ret = -ENOMEM;
-		goto err_no_mem;
-	}
-
-	/* create the L2 page for the WSM */
-	ret = map_buffer(task, wsm_buffer, wsm_len, table);
-
-	if (ret != 0) {
-		MCDRV_DBG_ERROR(mcd, "map_buffer() failed\n");
-		unmap_l2_table(table);
-		goto err_no_mem;
-	}
-	MCDRV_DBG(mcd, "mapped buffer %p to table with handle %d @ %lx",
-		  wsm_buffer, table->handle, table->phys);
-
-	mutex_unlock(&mem_ctx.table_lock);
-	return table;
-err_no_mem:
-	mutex_unlock(&mem_ctx.table_lock);
-	return ERR_PTR(ret);
-}
-
-uint32_t mc_find_l2_table(uint32_t handle, int32_t fd)
-{
-	uint32_t ret = 0;
-	struct mc_l2_table *table = NULL;
-
-	mutex_lock(&mem_ctx.table_lock);
-	table = find_l2_table(handle);
-
-	if (table == NULL) {
-		MCDRV_DBG_ERROR(mcd, "entry not found %u\n", handle);
-		ret = 0;
-		goto table_err;
-	}
-
-	/* It's safe here not to lock the instance since the owner of
-	 * the table will be cleared only with the table lock taken */
-	if (!mc_check_owner_fd(table->owner, fd)) {
-		MCDRV_DBG_ERROR(mcd, "not valid owner%u\n", handle);
-		ret = 0;
-		goto table_err;
-	}
-
-	ret = table->phys;
-table_err:
-	mutex_unlock(&mem_ctx.table_lock);
-	return ret;
-}
-
-void mc_clean_l2_tables(void)
-{
-	struct mc_l2_table *table, *tmp;
-
-	mutex_lock(&mem_ctx.table_lock);
-	/* Check if some WSM is orphaned. */
-	list_for_each_entry_safe(table, tmp, &mem_ctx.l2_tables, list) {
-		if (table->owner == NULL) {
-			MCDRV_DBG(mcd,
-				  "clearing orphaned WSM L2: p=%lx pages=%d\n",
-				  table->phys, table->pages);
-			unmap_l2_table(table);
-		}
-	}
-	mutex_unlock(&mem_ctx.table_lock);
-}
-
-void mc_clear_l2_tables(struct mc_instance *instance)
-{
-	struct mc_l2_table *table, *tmp;
-
-	mutex_lock(&mem_ctx.table_lock);
-	/* Check if some WSM is still in use. */
-	list_for_each_entry_safe(table, tmp, &mem_ctx.l2_tables, list) {
-		if (table->owner == instance) {
-			MCDRV_DBG(mcd, "release WSM L2: p=%lx pages=%d\n",
-				  table->phys, table->pages);
-			/* unlock app usage and free or mark it as orphan */
-			table->owner = NULL;
-			unmap_l2_table(table);
-		}
-	}
-	mutex_unlock(&mem_ctx.table_lock);
-}
-
-int mc_init_l2_tables(void)
-{
-	/* init list for WSM L2 chunks. */
-	INIT_LIST_HEAD(&mem_ctx.l2_tables_sets);
-
-	/* L2 table descriptor list. */
-	INIT_LIST_HEAD(&mem_ctx.l2_tables);
-
-	/* L2 table descriptor list. */
-	INIT_LIST_HEAD(&mem_ctx.free_l2_tables);
-
-	mutex_init(&mem_ctx.table_lock);
-
-	return 0;
-}
-
-void mc_release_l2_tables()
-{
-	struct mc_l2_table *table;
-	/* Check if some WSM is still in use. */
-	list_for_each_entry(table, &mem_ctx.l2_tables, list) {
-		WARN(1, "WSM L2 still in use: phys=%lx ,nr_of_pages=%d\n",
-		     table->phys, table->pages);
-	}
-}
diff --git a/drivers/gud/mobicore_driver/mem.h b/drivers/gud/mobicore_driver/mem.h
deleted file mode 100644
index 397a6cc..0000000
--- a/drivers/gud/mobicore_driver/mem.h
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * MobiCore driver module.(interface to the secure world SWD)
- *
- * <-- Copyright Giesecke & Devrient GmbH 2009-2012 -->
- * <-- Copyright Trustonic Limited 2013 -->
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#ifndef _MC_MEM_H_
-#define _MC_MEM_H_
-
-#define FREE_FROM_SWD	1
-#define FREE_FROM_NWD	0
-
-#define LOCKED_BY_APP	(1U << 0)
-#define LOCKED_BY_MC	(1U << 1)
-
-/*
- * MobiCore specific page tables for world shared memory.
- * Linux uses shadow page tables, see arch/arm/include/asm/pgtable-2level.
- * MobiCore uses the default ARM format.
- *
- * Number of page table entries in one L2 table. This is ARM specific, an
- * L2 table covers 1 MiB by using 256 entry referring to 4KiB pages each.
- */
-#define MC_ARM_L2_TABLE_ENTRIES		256
-
-/* ARM level 2 (L2) table with 256 entries. Size: 1k */
-struct l2table {
-	pte_t	table_entries[MC_ARM_L2_TABLE_ENTRIES];
-};
-
-/* Number of pages for L2 tables. There are 4 table in each page. */
-#define L2_TABLES_PER_PAGE		4
-
-/* Store for four L2 tables in one 4kb page*/
-struct mc_l2_table_store {
-	struct l2table table[L2_TABLES_PER_PAGE];
-};
-
-/* Usage and maintenance information about mc_l2_table_store */
-struct mc_l2_tables_set {
-	struct list_head		list;
-	/* kernel virtual address */
-	struct mc_l2_table_store	*kernel_virt;
-	/* physical address */
-	struct mc_l2_table_store	*phys;
-	/* pointer to page struct */
-	struct page			*page;
-	/* How many pages from this set are used */
-	atomic_t			used_tables;
-};
-
-/*
- * L2 table allocated to the Daemon or a TLC describing a world shared buffer.
- * When users map a malloc()ed area into SWd, a L2 table is allocated.
- * In addition, the area of maximum 1MB virtual address space is mapped into
- * the L2 table and a handle for this table is returned to the user.
- */
-struct mc_l2_table {
-	struct list_head	list;
-	/* Table lock */
-	struct mutex		lock;
-	/* handle as communicated to user mode */
-	unsigned int		handle;
-	/* Number of references kept to this l2 table */
-	atomic_t		usage;
-	/* owner of this L2 table */
-	struct mc_instance	*owner;
-	/* set describing where our L2 table is stored */
-	struct mc_l2_tables_set	*set;
-	/* index into L2 table set */
-	unsigned int		idx;
-	/* size of buffer */
-	unsigned int		pages;
-	/* virtual address*/
-	void			*virt;
-	unsigned long		phys;
-};
-
-/* MobiCore Driver Memory context data. */
-struct mc_mem_context {
-	struct mc_instance	*daemon_inst;
-	/* Backing store for L2 tables */
-	struct list_head	l2_tables_sets;
-	/* Bookkeeping for used L2 tables */
-	struct list_head	l2_tables;
-	/* Bookkeeping for free L2 tables */
-	struct list_head	free_l2_tables;
-	/* semaphore to synchronize access to above lists */
-	struct mutex		table_lock;
-};
-
-/*
- * Allocate L2 table and map buffer into it.
- * That is, create respective table entries.
- */
-struct mc_l2_table *mc_alloc_l2_table(struct mc_instance *instance,
-	struct task_struct *task, void *wsm_buffer, unsigned int wsm_len);
-
-/* Delete all the l2 tables associated with an instance */
-void mc_clear_l2_tables(struct mc_instance *instance);
-
-/* Release all orphaned L2 tables */
-void mc_clean_l2_tables(void);
-
-/* Delete a used l2 table. */
-int mc_free_l2_table(struct mc_instance *instance, uint32_t handle);
-
-/*
- * Lock a l2 table - the daemon adds +1 to refcount of the L2 table
- * marking it in use by SWD so it doesn't get released when the TLC dies.
- */
-int mc_lock_l2_table(struct mc_instance *instance, uint32_t handle);
-/* Unlock l2 table. */
-int mc_unlock_l2_table(struct mc_instance *instance, uint32_t handle);
-/* Return the phys address of l2 table. */
-uint32_t mc_find_l2_table(uint32_t handle, int32_t fd);
-/* Release all used l2 tables to Linux memory space */
-void mc_release_l2_tables(void);
-
-/* Initialize all l2 tables structure */
-int mc_init_l2_tables(void);
-
-#endif /* _MC_MEM_H_ */
diff --git a/drivers/gud/mobicore_driver/ops.c b/drivers/gud/mobicore_driver/ops.c
deleted file mode 100644
index 9d4af72..0000000
--- a/drivers/gud/mobicore_driver/ops.c
+++ /dev/null
@@ -1,286 +0,0 @@
-/*
- * MobiCore Driver Kernel Module.
- *
- * This module is written as a Linux device driver.
- * This driver represents the command proxy on the lowest layer, from the
- * secure world to the non secure world, and vice versa.
- * This driver is located in the non secure world (Linux).
- * This driver offers IOCTL commands, for access to the secure world, and has
- * the interface from the secure world to the normal world.
- * The access to the driver is possible with a file descriptor,
- * which has to be created by the fd = open(/dev/mobicore) command.
- *
- * <-- Copyright Giesecke & Devrient GmbH 2009-2012 -->
- * <-- Copyright Trustonic Limited 2013 -->
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/kthread.h>
-#include <linux/module.h>
-#include <linux/device.h>
-#include <linux/workqueue.h>
-#include <linux/cpu.h>
-
-#include "main.h"
-#include "fastcall.h"
-#include "ops.h"
-#include "mem.h"
-#include "pm.h"
-#include "debug.h"
-
-/* MobiCore context data */
-static struct mc_context *ctx;
-
-static inline long smc(union fc_generic *fc)
-{
-	/* If we request sleep yields must be filtered out as they
-	 * make no sense */
-	if (ctx->mcp)
-		if (ctx->mcp->flags.sleep_mode.SleepReq) {
-			if (fc->as_in.cmd == MC_SMC_N_YIELD)
-				return MC_FC_RET_ERR_INVALID;
-		}
-	return _smc(fc);
-}
-
-#ifdef MC_FASTCALL_WORKER_THREAD
-
-static struct task_struct *fastcall_thread;
-static DEFINE_KTHREAD_WORKER(fastcall_worker);
-
-struct fastcall_work {
-	struct kthread_work work;
-	void *data;
-};
-
-static void fastcall_work_func(struct kthread_work *work)
-{
-	struct fastcall_work *fc_work =
-		container_of(work, struct fastcall_work, work);
-
-#ifdef MC_CRYPTO_CLOCK_MANAGEMENT
-	mc_pm_clock_enable();
-#endif
-
-	smc(fc_work->data);
-
-#ifdef MC_CRYPTO_CLOCK_MANAGEMENT
-	mc_pm_clock_disable();
-#endif
-}
-
-void mc_fastcall(void *data)
-{
-	struct fastcall_work fc_work = {
-		KTHREAD_WORK_INIT(fc_work.work, fastcall_work_func),
-		.data = data,
-	};
-
-	queue_kthread_work(&fastcall_worker, &fc_work.work);
-	flush_kthread_work(&fc_work.work);
-}
-
-int mc_fastcall_init(struct mc_context *context)
-{
-	int ret = 0;
-
-	ctx = context;
-
-	fastcall_thread = kthread_create(kthread_worker_fn, &fastcall_worker,
-					 "mc_fastcall");
-	if (IS_ERR(fastcall_thread)) {
-		ret = PTR_ERR(fastcall_thread);
-		fastcall_thread = NULL;
-		MCDRV_DBG_ERROR(mcd, "cannot create fastcall wq (%d)\n", ret);
-		return ret;
-	}
-
-	/* this thread MUST run on CPU 0 */
-	kthread_bind(fastcall_thread, 0);
-	wake_up_process(fastcall_thread);
-
-	return 0;
-}
-
-void mc_fastcall_destroy(void)
-{
-	if (!IS_ERR_OR_NULL(fastcall_thread)) {
-		kthread_stop(fastcall_thread);
-		fastcall_thread = NULL;
-	}
-}
-#else
-
-struct fastcall_work_struct {
-	struct work_struct work;
-	void *data;
-};
-
-static void fastcall_work_func(struct work_struct *work)
-{
-	struct fastcall_work_struct *fc_work =
-		container_of(work, struct fastcall_work_struct, work);
-
-#ifdef MC_CRYPTO_CLOCK_MANAGEMENT
-	mc_pm_clock_enable();
-#endif
-
-	smc(fc_work->data);
-
-#ifdef MC_CRYPTO_CLOCK_MANAGEMENT
-	mc_pm_clock_disable();
-#endif
-}
-
-void mc_fastcall(void *data)
-{
-	struct fastcall_work_struct work = {
-		.data = data,
-	};
-	INIT_WORK(&work.work, fastcall_work_func);
-	schedule_work_on(0, &work.work);
-
-	flush_work(&work.work);
-}
-
-int mc_fastcall_init(struct mc_context *context)
-{
-	ctx = context;
-	return 0;
-};
-
-void mc_fastcall_destroy(void) {};
-#endif
-
-int mc_info(uint32_t ext_info_id, uint32_t *state, uint32_t *ext_info)
-{
-	int ret = 0;
-	union mc_fc_info fc_info;
-
-	MCDRV_DBG_VERBOSE(mcd, "enter\n");
-
-	memset(&fc_info, 0, sizeof(fc_info));
-	fc_info.as_in.cmd = MC_FC_INFO;
-	fc_info.as_in.ext_info_id = ext_info_id;
-
-	MCDRV_DBG(mcd, "fc_info <- cmd=0x%08x, ext_info_id=0x%08x\n",
-		  fc_info.as_in.cmd, fc_info.as_in.ext_info_id);
-
-	mc_fastcall(&(fc_info.as_generic));
-
-	MCDRV_DBG(mcd,
-		  "fc_info -> r=0x%08x ret=0x%08x state=0x%08x ext_info=0x%08x",
-		  fc_info.as_out.resp,
-		  fc_info.as_out.ret,
-		  fc_info.as_out.state,
-		  fc_info.as_out.ext_info);
-
-	ret = convert_fc_ret(fc_info.as_out.ret);
-
-	*state  = fc_info.as_out.state;
-	*ext_info = fc_info.as_out.ext_info;
-
-	MCDRV_DBG_VERBOSE(mcd, "exit with %d/0x%08X\n", ret, ret);
-
-	return ret;
-}
-
-/* Yield to MobiCore */
-int mc_yield(void)
-{
-	int ret = 0;
-	union fc_generic yield;
-
-	MCDRV_DBG_VERBOSE(mcd, "enter\n");
-
-	memset(&yield, 0, sizeof(yield));
-	yield.as_in.cmd = MC_SMC_N_YIELD;
-	mc_fastcall(&yield);
-	ret = convert_fc_ret(yield.as_out.ret);
-
-	return ret;
-}
-
-/* call common notify */
-int mc_nsiq(void)
-{
-	int ret = 0;
-	union fc_generic nsiq;
-	MCDRV_DBG_VERBOSE(mcd, "enter\n");
-
-	memset(&nsiq, 0, sizeof(nsiq));
-	nsiq.as_in.cmd = MC_SMC_N_SIQ;
-	mc_fastcall(&nsiq);
-	ret = convert_fc_ret(nsiq.as_out.ret);
-
-	return ret;
-}
-
-/* call common notify */
-int _nsiq(void)
-{
-	int ret = 0;
-	union fc_generic nsiq;
-	MCDRV_DBG_VERBOSE(mcd, "enter\n");
-
-	memset(&nsiq, 0, sizeof(nsiq));
-	nsiq.as_in.cmd = MC_SMC_N_SIQ;
-	_smc(&nsiq);
-	ret = convert_fc_ret(nsiq.as_out.ret);
-
-	return ret;
-}
-
-/* Call the INIT fastcall to setup MobiCore initialization */
-int mc_init(uint32_t base, uint32_t nq_offset, uint32_t nq_length,
-	uint32_t mcp_offset, uint32_t mcp_length)
-{
-	int ret = 0;
-	union mc_fc_init fc_init;
-
-	MCDRV_DBG_VERBOSE(mcd, "enter\n");
-
-	memset(&fc_init, 0, sizeof(fc_init));
-
-	fc_init.as_in.cmd = MC_FC_INIT;
-	/* base address of mci buffer 4KB aligned */
-	fc_init.as_in.base = base;
-	/* notification buffer start/length [16:16] [start, length] */
-	fc_init.as_in.nq_info = (nq_offset << 16) | (nq_length & 0xFFFF);
-	/* mcp buffer start/length [16:16] [start, length] */
-	fc_init.as_in.mcp_info = (mcp_offset << 16) | (mcp_length & 0xFFFF);
-
-	/*
-	 * Set KMOD notification queue to start of MCI
-	 * mciInfo was already set up in mmap
-	 */
-	MCDRV_DBG(mcd,
-		  "cmd=0x%08x, base=0x%08x,nq_info=0x%08x, mcp_info=0x%08x\n",
-		  fc_init.as_in.cmd, fc_init.as_in.base, fc_init.as_in.nq_info,
-		  fc_init.as_in.mcp_info);
-
-	mc_fastcall(&fc_init.as_generic);
-
-	MCDRV_DBG(mcd, "out cmd=0x%08x, ret=0x%08x\n", fc_init.as_out.resp,
-		  fc_init.as_out.ret);
-
-	ret = convert_fc_ret(fc_init.as_out.ret);
-
-	MCDRV_DBG_VERBOSE(mcd, "exit with %d/0x%08X\n", ret, ret);
-
-	return ret;
-}
-
-/* Return MobiCore driver version */
-uint32_t mc_get_version(void)
-{
-	MCDRV_DBG(mcd, "MobiCore driver version is %i.%i\n",
-		  MCDRVMODULEAPI_VERSION_MAJOR,
-		  MCDRVMODULEAPI_VERSION_MINOR);
-
-	return MC_VERSION(MCDRVMODULEAPI_VERSION_MAJOR,
-					MCDRVMODULEAPI_VERSION_MINOR);
-}
diff --git a/drivers/gud/setupDrivers.sh b/drivers/gud/setupDrivers.sh
new file mode 100644
index 0000000..8f877b7
--- /dev/null
+++ b/drivers/gud/setupDrivers.sh
@@ -0,0 +1,19 @@
+#!/bin/bash
+export COMP_PATH_ROOT=$(dirname $(readlink -f $BASH_SOURCE)) #set this to the absolute path of the folder containing this file
+
+# This part has to be set by the customer
+# To be set, absolute path of kernel folder
+export LINUX_PATH=
+# To be set, absolute path! CROSS_COMPILE variable needed by kernel eg /home/user/arm-2009q3/bin/arm-none-linux-gnueabi-
+export CROSS_COMPILE=
+# To be set, build mode debug or release
+export MODE=debug
+# To be set, the absolute path to the Linux Android NDK
+export NDK_PATH=
+
+# Global variables needed by build scripts
+export COMP_PATH_Logwrapper=$COMP_PATH_ROOT/Logwrapper/Out
+export COMP_PATH_MobiCore=$COMP_PATH_ROOT/MobiCore/Out
+export COMP_PATH_MobiCoreDriverMod=$COMP_PATH_ROOT/mobicore_driver/Out
+export COMP_PATH_MobiCoreDriverLib=$COMP_PATH_ROOT/daemon/Out
+export COMP_PATH_AndroidNdkLinux=$NDK_PATH
\ No newline at end of file
diff --git a/drivers/hwmon/epm_adc.c b/drivers/hwmon/epm_adc.c
index f7cf2df..2f5ed9d 100644
--- a/drivers/hwmon/epm_adc.c
+++ b/drivers/hwmon/epm_adc.c
@@ -888,6 +888,12 @@
 	init_resp->num_dev		= rx_buf[6];
 	init_resp->num_channel		= rx_buf[7];
 
+	pr_debug("EPM PSOC response for hello command: resp_cmd:0x%x\n",
+							rx_buf[0]);
+	pr_debug("EPM PSOC version:0x%x\n", rx_buf[1]);
+	pr_debug("EPM PSOC firmware version:0x%x\n",
+			rx_buf[6] | rx_buf[5] | rx_buf[4] | rx_buf[3]);
+
 	return rc;
 }
 
diff --git a/drivers/hwmon/qpnp-adc-common.c b/drivers/hwmon/qpnp-adc-common.c
index 9e0be59..96b058b 100644
--- a/drivers/hwmon/qpnp-adc-common.c
+++ b/drivers/hwmon/qpnp-adc-common.c
@@ -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
@@ -238,6 +238,60 @@
 	{800,	549},
 };
 
+static const struct qpnp_vadc_map_pt adcmap_qrd_skug_btm_threshold[] = {
+	{-200,	1338},
+	{-180,	1307},
+	{-160,	1276},
+	{-140,	1244},
+	{-120,	1213},
+	{-100,	1182},
+	{-80,	1151},
+	{-60,	1121},
+	{-40,	1092},
+	{-20,	1063},
+	{0,	1035},
+	{20,	1008},
+	{40,	982},
+	{60,	957},
+	{80,	933},
+	{100,	910},
+	{120,	889},
+	{140,	868},
+	{160,	848},
+	{180,	830},
+	{200,	812},
+	{220,	795},
+	{240,	780},
+	{260,	765},
+	{280,	751},
+	{300,	738},
+	{320,	726},
+	{340,	714},
+	{360,	704},
+	{380,	694},
+	{400,	684},
+	{420,	675},
+	{440,	667},
+	{460,	659},
+	{480,	652},
+	{500,	645},
+	{520,	639},
+	{540,	633},
+	{560,	627},
+	{580,	622},
+	{600,	617},
+	{620,	613},
+	{640,	608},
+	{660,	604},
+	{680,	600},
+	{700,	597},
+	{720,	593},
+	{740,	590},
+	{760,	587},
+	{780,	585},
+	{800,	582},
+};
+
 /* Voltage to temperature */
 static const struct qpnp_vadc_map_pt adcmap_100k_104ef_104fb[] = {
 	{1758,	-40},
@@ -442,7 +496,8 @@
 
 	if (!chan_properties || !chan_properties->offset_gain_numerator ||
 		!chan_properties->offset_gain_denominator || !adc_properties
-		|| !adc_chan_result)
+		|| !adc_chan_result
+		|| !chan_properties->adc_graph[CALIB_ABSOLUTE].dy)
 		return -EINVAL;
 
 	pmic_voltage = (adc_code -
@@ -612,6 +667,24 @@
 }
 EXPORT_SYMBOL(qpnp_adc_scale_qrd_skuaa_batt_therm);
 
+int32_t qpnp_adc_scale_qrd_skug_batt_therm(struct qpnp_vadc_chip *chip,
+		int32_t adc_code,
+		const struct qpnp_adc_properties *adc_properties,
+		const struct qpnp_vadc_chan_properties *chan_properties,
+		struct qpnp_vadc_result *adc_chan_result)
+{
+	int64_t bat_voltage = 0;
+
+	bat_voltage = qpnp_adc_scale_ratiometric_calib(adc_code,
+			adc_properties, chan_properties);
+
+	return qpnp_adc_map_temp_voltage(
+			adcmap_qrd_skug_btm_threshold,
+			ARRAY_SIZE(adcmap_qrd_skug_btm_threshold),
+			bat_voltage,
+			&adc_chan_result->physical);
+}
+EXPORT_SYMBOL(qpnp_adc_scale_qrd_skug_batt_therm);
 int32_t qpnp_adc_scale_therm_pu1(struct qpnp_vadc_chip *chip,
 		int32_t adc_code,
 		const struct qpnp_adc_properties *adc_properties,
@@ -741,17 +814,22 @@
 		return -EINVAL;
 
 	scale_voltage = (adc_code -
-		chan_properties->adc_graph[CALIB_ABSOLUTE].adc_gnd)
-		* chan_properties->adc_graph[CALIB_ABSOLUTE].dx;
+		chan_properties->adc_graph[chan_properties->calib_type].adc_gnd)
+		* chan_properties->adc_graph[chan_properties->calib_type].dx;
 	if (scale_voltage < 0) {
 		negative_offset = 1;
 		scale_voltage = -scale_voltage;
 	}
 	do_div(scale_voltage,
-		chan_properties->adc_graph[CALIB_ABSOLUTE].dy);
+		chan_properties->adc_graph[chan_properties->calib_type].dy);
 	if (negative_offset)
 		scale_voltage = -scale_voltage;
-	scale_voltage += chan_properties->adc_graph[CALIB_ABSOLUTE].dx;
+
+	if (chan_properties->calib_type == CALIB_ABSOLUTE)
+		scale_voltage +=
+		chan_properties->adc_graph[chan_properties->calib_type].dx;
+	else
+		scale_voltage *= 1000;
 
 	if (scale_voltage < 0) {
 		if (adc_properties->bipolar) {
@@ -913,6 +991,92 @@
 }
 EXPORT_SYMBOL(qpnp_vadc_check_result);
 
+int qpnp_adc_get_revid_version(struct device *dev)
+{
+	struct pmic_revid_data *revid_data;
+	struct device_node *revid_dev_node;
+
+	revid_dev_node = of_parse_phandle(dev->of_node,
+						"qcom,pmic-revid", 0);
+	if (!revid_dev_node) {
+		pr_debug("Missing qcom,pmic-revid property\n");
+		return -EINVAL;
+	}
+
+	revid_data = get_revid_data(revid_dev_node);
+	if (IS_ERR(revid_data)) {
+		pr_debug("revid error rc = %ld\n", PTR_ERR(revid_data));
+		return -EINVAL;
+	}
+
+	if ((revid_data->rev1 == PM8941_V3P1_REV1) &&
+		(revid_data->rev2 == PM8941_V3P1_REV2) &&
+		(revid_data->rev3 == PM8941_V3P1_REV3) &&
+		(revid_data->rev4 == PM8941_V3P1_REV4) &&
+		(revid_data->pmic_type == PM8941_V3P1_TYPE) &&
+		(revid_data->pmic_subtype == PM8941_V3P1_SUBTYPE))
+			return QPNP_REV_ID_8941_3_1;
+	else if ((revid_data->rev1 == PM8941_V3P0_REV1) &&
+		(revid_data->rev2 == PM8941_V3P0_REV2) &&
+		(revid_data->rev3 == PM8941_V3P0_REV3) &&
+		(revid_data->rev4 == PM8941_V3P0_REV4) &&
+		(revid_data->pmic_type == PM8941_V3P0_TYPE) &&
+		(revid_data->pmic_subtype == PM8941_V3P0_SUBTYPE))
+			return QPNP_REV_ID_8941_3_0;
+	else if ((revid_data->rev1 == PM8941_V2P0_REV1) &&
+		(revid_data->rev2 == PM8941_V2P0_REV2) &&
+		(revid_data->rev3 == PM8941_V2P0_REV3) &&
+		(revid_data->rev4 == PM8941_V2P0_REV4) &&
+		(revid_data->pmic_type == PM8941_V2P0_TYPE) &&
+		(revid_data->pmic_subtype == PM8941_V2P0_SUBTYPE))
+			return QPNP_REV_ID_8941_2_0;
+	else if ((revid_data->rev1 == PM8226_V2P2_REV1) &&
+		(revid_data->rev2 == PM8226_V2P2_REV2) &&
+		(revid_data->rev3 == PM8226_V2P2_REV3) &&
+		(revid_data->rev4 == PM8226_V2P2_REV4) &&
+		(revid_data->pmic_type == PM8226_V2P2_TYPE) &&
+		(revid_data->pmic_subtype == PM8226_V2P2_SUBTYPE))
+			return QPNP_REV_ID_8026_2_2;
+	else if ((revid_data->rev1 == PM8226_V2P1_REV1) &&
+		(revid_data->rev2 == PM8226_V2P1_REV2) &&
+		(revid_data->rev3 == PM8226_V2P1_REV3) &&
+		(revid_data->rev4 == PM8226_V2P1_REV4) &&
+		(revid_data->pmic_type == PM8226_V2P1_TYPE) &&
+		(revid_data->pmic_subtype == PM8226_V2P1_SUBTYPE))
+			return QPNP_REV_ID_8026_2_1;
+	else if ((revid_data->rev1 == PM8226_V2P0_REV1) &&
+		(revid_data->rev2 == PM8226_V2P0_REV2) &&
+		(revid_data->rev3 == PM8226_V2P0_REV3) &&
+		(revid_data->rev4 == PM8226_V2P0_REV4) &&
+		(revid_data->pmic_type == PM8226_V2P0_TYPE) &&
+		(revid_data->pmic_subtype == PM8226_V2P0_SUBTYPE))
+			return QPNP_REV_ID_8026_2_0;
+	else if ((revid_data->rev1 == PM8226_V1P0_REV1) &&
+		(revid_data->rev2 == PM8226_V1P0_REV2) &&
+		(revid_data->rev3 == PM8226_V1P0_REV3) &&
+		(revid_data->rev4 == PM8226_V1P0_REV4) &&
+		(revid_data->pmic_type == PM8226_V1P0_TYPE) &&
+		(revid_data->pmic_subtype == PM8226_V1P0_SUBTYPE))
+			return QPNP_REV_ID_8026_1_0;
+	else if ((revid_data->rev1 == PM8110_V1P0_REV1) &&
+		(revid_data->rev2 == PM8110_V1P0_REV2) &&
+		(revid_data->rev3 == PM8110_V1P0_REV3) &&
+		(revid_data->rev4 == PM8110_V1P0_REV4) &&
+		(revid_data->pmic_type == PM8110_V1P0_TYPE) &&
+		(revid_data->pmic_subtype == PM8110_V1P0_SUBTYPE))
+			return QPNP_REV_ID_8110_1_0;
+	else if ((revid_data->rev1 == PM8110_V2P0_REV1) &&
+		(revid_data->rev2 == PM8110_V2P0_REV2) &&
+		(revid_data->rev3 == PM8110_V2P0_REV3) &&
+		(revid_data->rev4 == PM8110_V2P0_REV4) &&
+		(revid_data->pmic_type == PM8110_V2P0_TYPE) &&
+		(revid_data->pmic_subtype == PM8110_V2P0_SUBTYPE))
+			return QPNP_REV_ID_8110_2_0;
+	else
+		return -EINVAL;
+}
+EXPORT_SYMBOL(qpnp_adc_get_revid_version);
+
 int32_t qpnp_adc_get_devicetree_data(struct spmi_device *spmi,
 			struct qpnp_adc_drv *adc_qpnp)
 {
@@ -1031,6 +1195,7 @@
 		adc_channel_list[i].adc_scale_fn = post_scaling;
 		adc_channel_list[i].hw_settle_time = hw_settle_time;
 		adc_channel_list[i].fast_avg_setup = fast_avg_setup;
+		adc_channel_list[i].calib_type = calib_type;
 		i++;
 	}
 
diff --git a/drivers/hwmon/qpnp-adc-current.c b/drivers/hwmon/qpnp-adc-current.c
index 9839595..dddbbd0 100644
--- a/drivers/hwmon/qpnp-adc-current.c
+++ b/drivers/hwmon/qpnp-adc-current.c
@@ -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
@@ -129,6 +129,13 @@
 #define QPNP_BIT_SHIFT_8				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_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
+#define QPNP_IADC_RSENSE_DEFAULT_TYPEB_SMIC		9700000
 
 struct qpnp_iadc_comp {
 	bool	ext_rsense;
@@ -143,6 +150,7 @@
 	struct qpnp_adc_drv			*adc;
 	int32_t					rsense;
 	bool					external_rsense;
+	bool					default_internal_rsense;
 	struct device				*iadc_hwmon;
 	struct list_head			list;
 	int64_t					die_temp;
@@ -153,11 +161,21 @@
 	struct work_struct			trigger_completion_work;
 	bool					skip_auto_calibrations;
 	bool					iadc_poll_eoc;
+	u16					batt_id_trim_cnst_rds;
+	int					rds_trim_default_type;
+	bool					rds_trim_default_check;
+	int32_t					rsense_workaround_value;
 	struct sensor_device_attribute		sens_attr[0];
 };
 
 LIST_HEAD(qpnp_iadc_device_list);
 
+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,
 						uint32_t reg, u8 *data)
 {
@@ -324,48 +342,8 @@
 	return 0;
 }
 
-#define QPNP_IADC_PM8941_3_1_REV2	3
-#define QPNP_IADC_PM8941_3_1_REV3	2
-#define QPNP_IADC_PM8026_1_REV2		1
-#define QPNP_IADC_PM8026_1_REV3		2
-#define QPNP_IADC_PM8026_2_REV2		4
-#define QPNP_IADC_PM8026_2_REV3		2
-#define QPNP_IADC_PM8110_1_REV2		2
-#define QPNP_IADC_PM8110_1_REV3		2
-
-#define QPNP_IADC_REV_ID_8941_3_1	1
-#define QPNP_IADC_REV_ID_8026_1_0	2
-#define QPNP_IADC_REV_ID_8026_2_0	3
-#define QPNP_IADC_REV_ID_8110_1_0	4
-
-static void qpnp_temp_comp_version_check(struct qpnp_iadc_chip *iadc,
-						int32_t *version)
-{
-	if ((iadc->iadc_comp.revision_dig_major ==
-			QPNP_IADC_PM8941_3_1_REV2) &&
-			(iadc->iadc_comp.revision_ana_minor ==
-			QPNP_IADC_PM8941_3_1_REV3))
-		*version = QPNP_IADC_REV_ID_8941_3_1;
-	else if ((iadc->iadc_comp.revision_dig_major ==
-			QPNP_IADC_PM8026_1_REV2) &&
-			(iadc->iadc_comp.revision_ana_minor ==
-			QPNP_IADC_PM8026_1_REV3))
-		*version = QPNP_IADC_REV_ID_8026_1_0;
-	else if ((iadc->iadc_comp.revision_dig_major ==
-			QPNP_IADC_PM8026_2_REV2) &&
-			(iadc->iadc_comp.revision_ana_minor ==
-			QPNP_IADC_PM8026_2_REV3))
-		*version = QPNP_IADC_REV_ID_8026_2_0;
-	else if ((iadc->iadc_comp.revision_dig_major ==
-			QPNP_IADC_PM8110_1_REV2) &&
-			(iadc->iadc_comp.revision_ana_minor ==
-			QPNP_IADC_PM8110_1_REV3))
-		*version = QPNP_IADC_REV_ID_8110_1_0;
-	else
-		*version = -EINVAL;
-
-	return;
-}
+#define QPNP_IADC_PM8026_2_REV2	4
+#define QPNP_IADC_PM8026_2_REV3	2
 
 #define QPNP_COEFF_1					969000
 #define QPNP_COEFF_2					32
@@ -392,15 +370,19 @@
 #define QPNP_COEFF_22					5000000
 #define QPNP_COEFF_23					3722500
 #define QPNP_COEFF_24					84
+#define QPNP_COEFF_25					33
+#define QPNP_COEFF_26					22
+#define QPNP_COEFF_27					53
+#define QPNP_COEFF_28					48
 
 static int32_t qpnp_iadc_comp(int64_t *result, struct qpnp_iadc_chip *iadc,
 							int64_t die_temp)
 {
 	int64_t temp_var = 0, sys_gain_coeff = 0, old;
 	int32_t coeff_a = 0, coeff_b = 0;
-	int32_t version;
+	int version = 0;
 
-	qpnp_temp_comp_version_check(iadc, &version);
+	version = qpnp_adc_get_revid_version(iadc->dev);
 	if (version == -EINVAL)
 		return 0;
 
@@ -415,7 +397,7 @@
 				iadc->iadc_comp.sys_gain;
 
 	switch (version) {
-	case QPNP_IADC_REV_ID_8941_3_1:
+	case QPNP_REV_ID_8941_3_1:
 		switch (iadc->iadc_comp.id) {
 		case COMP_ID_GF:
 			if (!iadc->iadc_comp.ext_rsense) {
@@ -454,7 +436,60 @@
 			break;
 		}
 		break;
-	case QPNP_IADC_REV_ID_8026_1_0:
+	case QPNP_REV_ID_8026_2_1:
+	case QPNP_REV_ID_8026_2_2:
+		/* pm8026 rev 2.1 and 2.2 */
+		switch (iadc->iadc_comp.id) {
+		case COMP_ID_GF:
+			if (!iadc->iadc_comp.ext_rsense) {
+				/* internal rsense */
+				if (*result < 0) {
+					/* charge */
+					coeff_a = 0;
+					coeff_b = 0;
+				} else {
+					coeff_a = QPNP_COEFF_25;
+					coeff_b = 0;
+				}
+			} else {
+				if (*result < 0) {
+					/* charge */
+					coeff_a = 0;
+					coeff_b = 0;
+				} else {
+					/* discharge */
+					coeff_a = 0;
+					coeff_b = 0;
+				}
+			}
+			break;
+		case COMP_ID_TSMC:
+		default:
+			if (!iadc->iadc_comp.ext_rsense) {
+				/* internal rsense */
+				if (*result < 0) {
+					/* charge */
+					coeff_a = 0;
+					coeff_b = 0;
+				} else {
+					coeff_a = QPNP_COEFF_26;
+					coeff_b = 0;
+				}
+			} else {
+				if (*result < 0) {
+					/* charge */
+					coeff_a = 0;
+					coeff_b = 0;
+				} else {
+					/* discharge */
+					coeff_a = 0;
+					coeff_b = 0;
+				}
+			}
+			break;
+		}
+		break;
+	case QPNP_REV_ID_8026_1_0:
 		/* pm8026 rev 1.0 */
 		switch (iadc->iadc_comp.id) {
 		case COMP_ID_GF:
@@ -506,7 +541,7 @@
 			break;
 		}
 		break;
-	case QPNP_IADC_REV_ID_8110_1_0:
+	case QPNP_REV_ID_8110_1_0:
 		/* pm8110 rev 1.0 */
 		switch (iadc->iadc_comp.id) {
 		case COMP_ID_GF:
@@ -538,8 +573,41 @@
 			break;
 		}
 		break;
+	case QPNP_REV_ID_8110_2_0:
+		die_temp -= 25000;
+		/* pm8110 rev 2.0 */
+		switch (iadc->iadc_comp.id) {
+		case COMP_ID_GF:
+			if (!iadc->iadc_comp.ext_rsense) {
+				/* internal rsense */
+				if (*result < 0) {
+					/* charge */
+					coeff_a = 0;
+					coeff_b = 0;
+				} else {
+					coeff_a = QPNP_COEFF_27;
+					coeff_b = 0;
+				}
+			}
+			break;
+		case COMP_ID_SMIC:
+		default:
+			if (!iadc->iadc_comp.ext_rsense) {
+				/* internal rsense */
+				if (*result < 0) {
+					/* charge */
+					coeff_a = 0;
+					coeff_b = 0;
+				} else {
+					coeff_a = QPNP_COEFF_28;
+					coeff_b = 0;
+				}
+			}
+			break;
+		}
+		break;
 	default:
-	case QPNP_IADC_REV_ID_8026_2_0:
+	case QPNP_REV_ID_8026_2_0:
 		/* pm8026 rev 1.0 */
 		coeff_a = 0;
 		coeff_b = 0;
@@ -562,7 +630,8 @@
 		temp_var = div64_s64(temp_var * sys_gain_coeff, 1000000);
 		*result = div64_s64(*result * 1000, temp_var);
 	}
-	pr_debug("%lld compensated into %lld\n", old, *result);
+	pr_debug("%lld compensated into %lld, a: %d, b: %d, sys_gain: %lld\n",
+			old, *result, coeff_a, coeff_b, sys_gain_coeff);
 
 	return 0;
 }
@@ -573,6 +642,82 @@
 }
 EXPORT_SYMBOL(qpnp_iadc_comp_result);
 
+static int qpnp_iadc_rds_trim_update_check(struct qpnp_iadc_chip *iadc)
+{
+	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");
+		return 0;
+	}
+
+	rc = qpnp_iadc_read_reg(iadc, QPNP_IADC_NOMINAL_RSENSE, &trim2_val);
+	if (rc < 0) {
+		pr_err("qpnp adc trim2_fullscale1 reg read failed %d\n", rc);
+		return rc;
+	}
+
+	rc = spmi_ext_register_readl(iadc->adc->spmi->ctrl, iadc->adc->slave,
+		iadc->batt_id_trim_cnst_rds, &smbb_batt_trm_data, 1);
+	if (rc < 0) {
+		pr_err("batt_id trim_cnst rds reg read failed %d\n", rc);
+		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_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 (iadc->rds_trim_default_type ==
+						QPNP_IADC_RDS_DEFAULT_TYPEB) {
+		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_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) {
+				iadc->rsense_workaround_value =
+					QPNP_IADC_RSENSE_DEFAULT_TYPEB_GF;
+				iadc->default_internal_rsense = true;
+			} else if (iadc->iadc_comp.id == COMP_ID_SMIC) {
+				iadc->rsense_workaround_value =
+					QPNP_IADC_RSENSE_DEFAULT_TYPEB_SMIC;
+				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;
+}
+
 static int32_t qpnp_iadc_comp_info(struct qpnp_iadc_chip *iadc)
 {
 	int rc = 0;
@@ -767,9 +912,10 @@
 							bool batfet_closed)
 {
 	uint8_t rslt_lsb, rslt_msb;
-	int32_t rc = 0;
+	int32_t rc = 0, version = 0;
 	uint16_t raw_data;
 	uint32_t mode_sel = 0;
+	bool iadc_offset_ch_batfet_check;
 
 	if (qpnp_iadc_is_valid(iadc) < 0)
 		return -EPROBE_DEFER;
@@ -791,13 +937,22 @@
 	iadc->adc->calib.gain_raw = raw_data;
 
 	/*
-	 * there is a features in the BMS where if the batfet is opened
-	 * the BMS reads from INTERNAL_RSENSE (channel 0) actually go to
+	 * there is a features on PM8941 in the BMS where if the batfet is
+	 * opened the BMS reads from INTERNAL_RSENSE (channel 0) actually go to
 	 * OFFSET_CALIBRATION_CSP_CSN (channel 5). Hence if batfet is opened
 	 * we have to calibrate based on OFFSET_CALIBRATION_CSP_CSN even for
 	 * internal rsense.
 	 */
-	if (!batfet_closed || iadc->external_rsense) {
+	version = qpnp_adc_get_revid_version(iadc->dev);
+	if ((version == QPNP_REV_ID_8941_3_1) ||
+			(version == QPNP_REV_ID_8941_3_0) ||
+			(version == QPNP_REV_ID_8941_2_0))
+		iadc_offset_ch_batfet_check = true;
+	else
+		iadc_offset_ch_batfet_check = false;
+
+	if ((iadc_offset_ch_batfet_check && !batfet_closed) ||
+						(iadc->external_rsense)) {
 		/* external offset calculation */
 		rc = qpnp_iadc_configure(iadc, OFFSET_CALIBRATION_CSP_CSN,
 						&raw_data, mode_sel);
@@ -937,7 +1092,7 @@
 
 int32_t qpnp_iadc_get_rsense(struct qpnp_iadc_chip *iadc, int32_t *rsense)
 {
-	uint8_t	rslt_rsense;
+	uint8_t	rslt_rsense = 0;
 	int32_t	rc = 0, sign_bit = 0;
 
 	if (qpnp_iadc_is_valid(iadc) < 0)
@@ -945,28 +1100,36 @@
 
 	if (iadc->external_rsense) {
 		*rsense = iadc->rsense;
-		return rc;
-	}
+	} else if (iadc->default_internal_rsense) {
+		*rsense = iadc->rsense_workaround_value;
+	} else {
 
-	rc = qpnp_iadc_read_reg(iadc, QPNP_IADC_NOMINAL_RSENSE, &rslt_rsense);
-	if (rc < 0) {
-		pr_err("qpnp adc rsense read failed with %d\n", rc);
-		return rc;
-	}
+		rc = qpnp_iadc_read_reg(iadc, QPNP_IADC_NOMINAL_RSENSE,
+							&rslt_rsense);
+		if (rc < 0) {
+			pr_err("qpnp adc rsense read failed with %d\n", rc);
+			return rc;
+		}
 
-	pr_debug("rsense:0%x\n", rslt_rsense);
+		pr_debug("rsense:0%x\n", rslt_rsense);
 
-	if (rslt_rsense & QPNP_RSENSE_MSB_SIGN_CHECK)
-		sign_bit = 1;
+		if (rslt_rsense & QPNP_RSENSE_MSB_SIGN_CHECK)
+			sign_bit = 1;
 
-	rslt_rsense &= ~QPNP_RSENSE_MSB_SIGN_CHECK;
+		rslt_rsense &= ~QPNP_RSENSE_MSB_SIGN_CHECK;
 
-	if (sign_bit)
-		*rsense = QPNP_IADC_INTERNAL_RSENSE_N_OHMS_FACTOR -
+		if (sign_bit)
+			*rsense = QPNP_IADC_INTERNAL_RSENSE_N_OHMS_FACTOR -
 			(rslt_rsense * QPNP_IADC_RSENSE_LSB_N_OHMS_PER_BIT);
-	else
-		*rsense = QPNP_IADC_INTERNAL_RSENSE_N_OHMS_FACTOR +
+		else
+			*rsense = QPNP_IADC_INTERNAL_RSENSE_N_OHMS_FACTOR +
 			(rslt_rsense * QPNP_IADC_RSENSE_LSB_N_OHMS_PER_BIT);
+	}
+	pr_debug("rsense value is %d\n", *rsense);
+
+	if (*rsense == 0)
+		pr_err("incorrect rsens value:%d rslt_rsense:%d\n",
+				*rsense, rslt_rsense);
 
 	return rc;
 }
@@ -1011,6 +1174,11 @@
 	if (qpnp_iadc_is_valid(iadc) < 0)
 		return -EPROBE_DEFER;
 
+	if ((iadc->adc->calib.gain_raw - iadc->adc->calib.offset_raw) == 0) {
+		pr_err("raw offset errors! run iadc calibration again\n");
+		return -EINVAL;
+	}
+
 	rc = qpnp_check_pmic_temp(iadc);
 	if (rc) {
 		pr_err("Error checking pmic therm temp\n");
@@ -1051,10 +1219,12 @@
 		result->result_uv = -result->result_uv;
 		result_current = -result_current;
 	}
+	result_current *= -1;
 	rc = qpnp_iadc_comp_result(iadc, &result_current);
 	if (rc < 0)
 		pr_err("Error during compensating the IADC\n");
 	rc = 0;
+	result_current *= -1;
 
 	result->result_ua = (int32_t) result_current;
 fail:
@@ -1126,6 +1296,11 @@
 	if (qpnp_iadc_is_valid(iadc) < 0)
 		return -EPROBE_DEFER;
 
+	if ((iadc->adc->calib.gain_raw - iadc->adc->calib.offset_raw) == 0) {
+		pr_err("raw offset errors! run iadc calibration again\n");
+		return -EINVAL;
+	}
+
 	mutex_lock(&iadc->adc->adc_lock);
 
 	if (iadc->iadc_poll_eoc) {
@@ -1162,6 +1337,11 @@
 	result_current = i_result->result_uv;
 	result_current *= QPNP_IADC_NANO_VOLTS_FACTOR;
 	/* Intentional fall through. Process the result w/o comp */
+	if (!rsense_u_ohms) {
+		pr_err("rsense error=%d\n", rsense_u_ohms);
+		goto fail_release_vadc;
+	}
+
 	do_div(result_current, rsense_u_ohms);
 
 	if (sign) {
@@ -1253,6 +1433,7 @@
 	struct qpnp_adc_drv *adc_qpnp;
 	struct device_node *node = spmi->dev.of_node;
 	struct device_node *child;
+	struct resource *res;
 	int rc, count_adc_channel_list = 0, i = 0;
 
 	for_each_child_of_node(node, child)
@@ -1287,6 +1468,22 @@
 		return rc;
 	}
 
+	res = spmi_get_resource_byname(spmi, NULL, IORESOURCE_MEM,
+		"batt-id-trim-cnst-rds");
+	if (!res) {
+		dev_err(&spmi->dev, "failed to read batt_id trim register\n");
+		return -EINVAL;
+	}
+	iadc->batt_id_trim_cnst_rds = res->start;
+	rc = of_property_read_u32(node, "qcom,use-default-rds-trim",
+			&iadc->rds_trim_default_type);
+	if (rc)
+		pr_debug("No trim workaround needed\n");
+	else {
+		pr_debug("Use internal RDS trim workaround\n");
+		iadc->rds_trim_default_check = true;
+	}
+
 	iadc->vadc_dev = qpnp_get_vadc(&spmi->dev, "iadc");
 	if (IS_ERR(iadc->vadc_dev)) {
 		rc = PTR_ERR(iadc->vadc_dev);
@@ -1340,6 +1537,12 @@
 		goto fail;
 	}
 
+	rc = qpnp_iadc_rds_trim_update_check(iadc);
+	if (rc) {
+		dev_err(&spmi->dev, "Rds trim update failed!\n");
+		goto fail;
+	}
+
 	dev_set_drvdata(&spmi->dev, iadc);
 	list_add(&iadc->list, &qpnp_iadc_device_list);
 	rc = qpnp_iadc_calibrate_for_trim(iadc, true);
diff --git a/drivers/hwmon/qpnp-adc-voltage.c b/drivers/hwmon/qpnp-adc-voltage.c
index b2b846a..ee69840 100644
--- a/drivers/hwmon/qpnp-adc-voltage.c
+++ b/drivers/hwmon/qpnp-adc-voltage.c
@@ -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
@@ -129,6 +129,7 @@
 	[SCALE_THERM_150K_PULLUP] = {qpnp_adc_scale_therm_pu1},
 	[SCALE_QRD_BATT_THERM] = {qpnp_adc_scale_qrd_batt_therm},
 	[SCALE_QRD_SKUAA_BATT_THERM] = {qpnp_adc_scale_qrd_skuaa_batt_therm},
+	[SCALE_QRD_SKUG_BATT_THERM] = {qpnp_adc_scale_qrd_skug_batt_therm},
 };
 
 static int32_t qpnp_vadc_read_reg(struct qpnp_vadc_chip *vadc, int16_t reg,
@@ -511,63 +512,52 @@
 #define QPNP_VBAT_COEFF_13	102640000
 #define QPNP_VBAT_COEFF_14	22220000
 #define QPNP_VBAT_COEFF_15	83060000
-
-#define QPNP_VADC_REV_ID_8941_3_1	1
-#define QPNP_VADC_REV_ID_8026_1_0	2
-#define QPNP_VADC_REV_ID_8026_2_0	3
-
-static void qpnp_temp_comp_version_check(struct qpnp_vadc_chip *vadc,
-							int32_t *version)
-{
-	if (vadc->revision_dig_major == 3 &&
-			vadc->revision_ana_minor == 2)
-		*version = QPNP_VADC_REV_ID_8941_3_1;
-	else if (vadc->revision_dig_major == 1 &&
-			vadc->revision_ana_minor == 2)
-		*version = QPNP_VADC_REV_ID_8026_1_0;
-	else if (vadc->revision_dig_major == 2 &&
-			vadc->revision_ana_minor == 2)
-		*version = QPNP_VADC_REV_ID_8026_2_0;
-	else
-		*version = -EINVAL;
-
-	return;
-}
+#define QPNP_VBAT_COEFF_16	2810
+#define QPNP_VBAT_COEFF_17	5260
+#define QPNP_VBAT_COEFF_18	8027
+#define QPNP_VBAT_COEFF_19	2347
+#define QPNP_VBAT_COEFF_20	6043
+#define QPNP_VBAT_COEFF_21	1914
+#define QPNP_VBAT_OFFSET_SMIC	9446
+#define QPNP_VBAT_OFFSET_GF	9441
+#define QPNP_OCV_OFFSET_SMIC	4596
+#define QPNP_OCV_OFFSET_GF	5896
+#define QPNP_VBAT_COEFF_22	6800
+#define QPNP_VBAT_COEFF_23	3500
+#define QPNP_VBAT_COEFF_24	4360
+#define QPNP_VBAT_COEFF_25	8060
 
 static int32_t qpnp_ocv_comp(int64_t *result,
 			struct qpnp_vadc_chip *vadc, int64_t die_temp)
 {
 	int64_t temp_var = 0;
 	int64_t old = *result;
-	int32_t version;
+	int version;
 
-	qpnp_temp_comp_version_check(vadc, &version);
+	version = qpnp_adc_get_revid_version(vadc->dev);
 	if (version == -EINVAL)
 		return 0;
 
-	if (die_temp < 25000)
-		return 0;
-
-	if (die_temp > 60000)
-		die_temp = 60000;
+	if (version == QPNP_REV_ID_8026_2_2) {
+		if (die_temp > 25000)
+			return 0;
+	}
 
 	switch (version) {
-	case QPNP_VADC_REV_ID_8941_3_1:
+	case QPNP_REV_ID_8941_3_1:
 		switch (vadc->id) {
 		case COMP_ID_TSMC:
-			temp_var = (((die_temp *
-			(-QPNP_VBAT_COEFF_4))
-			+ QPNP_VBAT_COEFF_5));
+			 temp_var = ((die_temp - 25000) *
+			(-QPNP_VBAT_COEFF_4));
 			break;
 		default:
 		case COMP_ID_GF:
-			temp_var = (((die_temp *
-			(-QPNP_VBAT_COEFF_1))
-			+ QPNP_VBAT_COEFF_2));
+			temp_var = ((die_temp - 25000) *
+			(-QPNP_VBAT_COEFF_1));
 			break;
 		}
 		break;
-	case QPNP_VADC_REV_ID_8026_1_0:
+	case QPNP_REV_ID_8026_1_0:
 		switch (vadc->id) {
 		case COMP_ID_TSMC:
 			temp_var = (((die_temp *
@@ -582,19 +572,56 @@
 			break;
 		}
 		break;
-	case QPNP_VADC_REV_ID_8026_2_0:
+	case QPNP_REV_ID_8026_2_0:
+	case QPNP_REV_ID_8026_2_1:
 		switch (vadc->id) {
 		case COMP_ID_TSMC:
-			temp_var = ((die_temp - 2500) *
+			temp_var = ((die_temp - 25000) *
 			(-QPNP_VBAT_COEFF_10));
 			break;
 		default:
 		case COMP_ID_GF:
-			temp_var = ((die_temp - 2500) *
+			temp_var = ((die_temp - 25000) *
 			(-QPNP_VBAT_COEFF_8));
 			break;
 		}
 		break;
+	case QPNP_REV_ID_8026_2_2:
+		switch (vadc->id) {
+		case COMP_ID_TSMC:
+			*result -= QPNP_VBAT_COEFF_22;
+			temp_var = (die_temp - 25000) *
+					QPNP_VBAT_COEFF_24;
+			break;
+		default:
+		case COMP_ID_GF:
+			*result -= QPNP_VBAT_COEFF_22;
+			temp_var = (die_temp - 25000) *
+					QPNP_VBAT_COEFF_25;
+			break;
+		}
+		break;
+	case QPNP_REV_ID_8110_2_0:
+		switch (vadc->id) {
+		case COMP_ID_SMIC:
+			*result -= QPNP_OCV_OFFSET_SMIC;
+			if (die_temp < 25000)
+				temp_var = QPNP_VBAT_COEFF_18;
+			else
+				temp_var = QPNP_VBAT_COEFF_19;
+			temp_var = (die_temp - 25000) * temp_var;
+			break;
+		default:
+		case COMP_ID_GF:
+			*result -= QPNP_OCV_OFFSET_GF;
+			if (die_temp < 25000)
+				temp_var = QPNP_VBAT_COEFF_20;
+			else
+				temp_var = QPNP_VBAT_COEFF_21;
+			temp_var = (die_temp - 25000) * temp_var;
+			break;
+		}
+		break;
 	default:
 		temp_var = 0;
 		break;
@@ -617,35 +644,36 @@
 {
 	int64_t temp_var = 0;
 	int64_t old = *result;
-	int32_t version;
+	int version;
 
-	qpnp_temp_comp_version_check(vadc, &version);
+	version = qpnp_adc_get_revid_version(vadc->dev);
 	if (version == -EINVAL)
 		return 0;
 
-	if (die_temp < 25000)
-		return 0;
-
-	/* min(die_temp_c, 60_degC) */
-	if (die_temp > 60000)
-		die_temp = 60000;
+	if (version != QPNP_REV_ID_8941_3_1) {
+		/* min(die_temp_c, 60_degC) */
+		if (die_temp > 60000)
+			die_temp = 60000;
+	}
 
 	switch (version) {
-	case QPNP_VADC_REV_ID_8941_3_1:
+	case QPNP_REV_ID_8941_3_1:
 		switch (vadc->id) {
 		case COMP_ID_TSMC:
-			temp_var = (die_temp *
+			temp_var = ((die_temp - 25000) *
 			(-QPNP_VBAT_COEFF_1));
 			break;
 		default:
 		case COMP_ID_GF:
-			temp_var = (((die_temp *
-			(-QPNP_VBAT_COEFF_6))
-			+ QPNP_VBAT_COEFF_7));
+			/* min(die_temp_c, 60_degC) */
+			if (die_temp > 60000)
+				die_temp = 60000;
+			temp_var = ((die_temp - 25000) *
+			(-QPNP_VBAT_COEFF_1));
 			break;
 		}
 		break;
-	case QPNP_VADC_REV_ID_8026_1_0:
+	case QPNP_REV_ID_8026_1_0:
 		switch (vadc->id) {
 		case COMP_ID_TSMC:
 			temp_var = (((die_temp *
@@ -660,19 +688,48 @@
 			break;
 		}
 		break;
-	case QPNP_VADC_REV_ID_8026_2_0:
+	case QPNP_REV_ID_8026_2_0:
+	case QPNP_REV_ID_8026_2_1:
 		switch (vadc->id) {
 		case COMP_ID_TSMC:
-			temp_var = ((die_temp - 2500) *
+			temp_var = ((die_temp - 25000) *
 			(-QPNP_VBAT_COEFF_11));
 			break;
 		default:
 		case COMP_ID_GF:
-			temp_var = ((die_temp - 2500) *
+			temp_var = ((die_temp - 25000) *
 			(-QPNP_VBAT_COEFF_9));
 			break;
 		}
 		break;
+	case QPNP_REV_ID_8026_2_2:
+		switch (vadc->id) {
+		case COMP_ID_TSMC:
+			*result -= QPNP_VBAT_COEFF_23;
+			temp_var = 0;
+			break;
+		default:
+		case COMP_ID_GF:
+			*result -= QPNP_VBAT_COEFF_23;
+			temp_var = 0;
+			break;
+		}
+		break;
+	case QPNP_REV_ID_8110_2_0:
+		switch (vadc->id) {
+		case COMP_ID_SMIC:
+			*result -= QPNP_VBAT_OFFSET_SMIC;
+			temp_var = ((die_temp - 25000) *
+			(QPNP_VBAT_COEFF_17));
+			break;
+		default:
+		case COMP_ID_GF:
+			*result -= QPNP_VBAT_OFFSET_GF;
+			temp_var = ((die_temp - 25000) *
+			(QPNP_VBAT_COEFF_16));
+			break;
+		}
+		break;
 	default:
 		temp_var = 0;
 		break;
@@ -691,7 +748,7 @@
 }
 
 int32_t qpnp_vbat_sns_comp_result(struct qpnp_vadc_chip *vadc,
-						int64_t *result)
+					int64_t *result, bool is_pon_ocv)
 {
 	struct qpnp_vadc_result die_temp_result;
 	int rc = 0;
@@ -707,7 +764,12 @@
 		return rc;
 	}
 
-	rc = qpnp_ocv_comp(result, vadc, die_temp_result.physical);
+	if (is_pon_ocv)
+		rc = qpnp_ocv_comp(result, vadc, die_temp_result.physical);
+	else
+		rc = qpnp_vbat_sns_comp(result, vadc,
+				die_temp_result.physical);
+
 	if (rc < 0)
 		pr_err("Error with vbat compensation\n");
 
@@ -808,7 +870,14 @@
 	}
 
 	pr_debug("absolute reference raw: 625mV:0x%x 1.25V:0x%x\n",
-				calib_read_1, calib_read_2);
+				calib_read_2, calib_read_1);
+
+	if (calib_read_1 == calib_read_2) {
+		pr_err("absolute reference raw: 625mV:0x%x 1.25V:0x%x\n",
+				calib_read_2, calib_read_1);
+		rc = -EINVAL;
+		goto calib_fail;
+	}
 
 	vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_ABSOLUTE].dy =
 					(calib_read_1 - calib_read_2);
@@ -888,6 +957,14 @@
 
 	pr_debug("ratiometric reference raw: VDD:0x%x GND:0x%x\n",
 				calib_read_1, calib_read_2);
+
+	if (calib_read_1 == calib_read_2) {
+		pr_err("ratiometric reference raw: VDD:0x%x GND:0x%x\n",
+				calib_read_1, calib_read_2);
+		rc = -EINVAL;
+		goto calib_fail;
+	}
+
 	vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_RATIOMETRIC].dy =
 					(calib_read_1 - calib_read_2);
 	vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_RATIOMETRIC].dx =
@@ -1098,6 +1175,8 @@
 		qpnp_vadc_amux_scaling_ratio[amux_prescaling].num;
 	vadc->adc->amux_prop->chan_prop->offset_gain_denominator =
 		 qpnp_vadc_amux_scaling_ratio[amux_prescaling].den;
+	vadc->adc->amux_prop->chan_prop->calib_type =
+		vadc->adc->adc_channels[dt_index].calib_type;
 
 	scale_type = vadc->adc->adc_channels[dt_index].adc_scale_fn;
 	if (scale_type >= SCALE_NONE) {
diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c
index 57aa835..1704105 100644
--- a/drivers/i2c/busses/i2c-qup.c
+++ b/drivers/i2c/busses/i2c-qup.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2009-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 @@
 #include <linux/err.h>
 #include <linux/init.h>
 #include <linux/i2c.h>
+#include <linux/i2c/i2c-qup.h>
 #include <linux/interrupt.h>
 #include <linux/platform_device.h>
 #include <linux/delay.h>
@@ -85,10 +86,11 @@
 	QUP_MX_INPUT_DONE       = 1U << 11,
 };
 
-/* I2C mini core related values */
+/* QUP_CONFIG values and flags */
 enum {
 	I2C_MINI_CORE           = 2U << 8,
 	I2C_N_VAL               = 0xF,
+	I2C_CORE_CLK_ON_EN      = BIT(13),
 
 };
 
@@ -129,6 +131,12 @@
 	I2C_CLK_FORCED_LOW_STATE	= 5,
 };
 
+enum msm_i2c_state {
+	MSM_I2C_PM_ACTIVE,
+	MSM_I2C_PM_SUSPENDED,
+	MSM_I2C_SYS_SUSPENDING,
+	MSM_I2C_SYS_SUSPENDED,
+};
 #define QUP_MAX_CLK_STATE_RETRIES	300
 #define DEFAULT_CLK_RATE		(19200000)
 #define I2C_STATUS_CLK_STATE		13
@@ -184,8 +192,7 @@
 	int                          in_blk_sz;
 	int                          wr_sz;
 	struct msm_i2c_platform_data *pdata;
-	int                          suspended;
-	int                          pwr_state;
+	enum msm_i2c_state           pwr_state;
 	struct mutex                 mlock;
 	void                         *complete;
 	int                          i2c_gpios[ARRAY_SIZE(i2c_rsrcs)];
@@ -339,22 +346,6 @@
 	return 0;
 }
 
-/*
- * Before calling qup_config_core_on_en(), please make
- * sure that QuPE core is in RESET state.
- */
-static void
-qup_config_core_on_en(struct qup_i2c_dev *dev)
-{
-	uint32_t status;
-
-	status = readl_relaxed(dev->base + QUP_CONFIG);
-	status |= BIT(13);
-	writel_relaxed(status, dev->base + QUP_CONFIG);
-	/* making sure that write has really gone through */
-	mb();
-}
-
 #define MSM_I2C_CLK_PATH_SUSPEND (0)
 #define MSM_I2C_CLK_PATH_RESUME  (1)
 #define MSM_I2C_CLK_PATH_MAX_BW(dev) ((dev->pdata->src_clk_rate * 8) / 1000)
@@ -500,27 +491,97 @@
 	}
 }
 
-static void
-qup_i2c_pwr_mgmt(struct qup_i2c_dev *dev, unsigned int state)
+static int i2c_qup_gpio_request(struct qup_i2c_dev *dev)
 {
-	dev->pwr_state = state;
-	if (state != 0) {
-		i2c_qup_clk_path_postponed_register(dev);
-		if (!dev->pdata->active_only)
-			i2c_qup_clk_path_vote(dev);
+	int i;
+	int result = 0;
 
-		clk_prepare_enable(dev->clk);
-		if (!dev->pdata->keep_ahb_clk_on)
-			clk_prepare_enable(dev->pclk);
-	} else {
-		qup_update_state(dev, QUP_RESET_STATE);
-		clk_disable_unprepare(dev->clk);
-		qup_config_core_on_en(dev);
-		if (!dev->pdata->keep_ahb_clk_on)
-			clk_disable_unprepare(dev->pclk);
-		if (!dev->pdata->active_only)
-			i2c_qup_clk_path_unvote(dev);
+	for (i = 0; i < ARRAY_SIZE(i2c_rsrcs); ++i) {
+		if (dev->i2c_gpios[i] >= 0) {
+			result = gpio_request(dev->i2c_gpios[i], i2c_rsrcs[i]);
+			if (result) {
+				dev_err(dev->dev,
+					"gpio_request for pin %d failed with error %d\n",
+					dev->i2c_gpios[i], result);
+				goto error;
+			}
+		}
 	}
+	return 0;
+
+error:
+	for (; --i >= 0;) {
+		if (dev->i2c_gpios[i] >= 0)
+			gpio_free(dev->i2c_gpios[i]);
+	}
+	return result;
+}
+
+static void i2c_qup_gpio_free(struct qup_i2c_dev *dev)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(i2c_rsrcs); ++i) {
+		if (dev->i2c_gpios[i] >= 0)
+			gpio_free(dev->i2c_gpios[i]);
+	}
+}
+
+static void i2c_qup_pm_suspend_clk(struct qup_i2c_dev *dev)
+{
+	uint32_t status;
+
+	/* reset core and enable conditional dynamic clock gating */
+	qup_update_state(dev, QUP_RESET_STATE);
+	status = readl_relaxed(dev->base + QUP_CONFIG);
+	status |= I2C_CORE_CLK_ON_EN;
+	writel_relaxed(status, dev->base + QUP_CONFIG);
+	/* ensure that write has really gone through */
+	mb();
+
+	clk_disable_unprepare(dev->clk);
+	if (!dev->pdata->keep_ahb_clk_on)
+		clk_disable_unprepare(dev->pclk);
+}
+
+static void i2c_qup_pm_resume_clk(struct qup_i2c_dev *dev)
+{
+	clk_prepare_enable(dev->clk);
+	if (!dev->pdata->keep_ahb_clk_on)
+		clk_prepare_enable(dev->pclk);
+}
+
+static void i2c_qup_pm_suspend(struct qup_i2c_dev *dev)
+{
+	if (dev->pwr_state == MSM_I2C_PM_SUSPENDED) {
+		dev_err(dev->dev, "attempt to suspend when suspended\n");
+		return;
+	}
+
+	if (!dev->pdata->clk_ctl_xfer)
+		i2c_qup_pm_suspend_clk(dev);
+
+	if (!dev->pdata->active_only)
+		i2c_qup_clk_path_unvote(dev);
+
+	i2c_qup_gpio_free(dev);
+	dev->pwr_state = MSM_I2C_PM_SUSPENDED;
+}
+
+static void i2c_qup_pm_resume(struct qup_i2c_dev *dev)
+{
+	if (dev->pwr_state == MSM_I2C_PM_ACTIVE)
+		return;
+
+	i2c_qup_gpio_request(dev);
+
+	i2c_qup_clk_path_postponed_register(dev);
+	if (!dev->pdata->active_only)
+		i2c_qup_clk_path_vote(dev);
+
+	if (!dev->pdata->clk_ctl_xfer)
+		i2c_qup_pm_resume_clk(dev);
+	dev->pwr_state = MSM_I2C_PM_ACTIVE;
 }
 
 static int
@@ -595,43 +656,6 @@
 	return -ETIMEDOUT;
 }
 
-static inline int qup_i2c_request_gpios(struct qup_i2c_dev *dev)
-{
-	int i;
-	int result = 0;
-
-	for (i = 0; i < ARRAY_SIZE(i2c_rsrcs); ++i) {
-		if (dev->i2c_gpios[i] >= 0) {
-			result = gpio_request(dev->i2c_gpios[i], i2c_rsrcs[i]);
-			if (result) {
-				dev_err(dev->dev,
-					"gpio_request for pin %d failed\
-					with error %d\n", dev->i2c_gpios[i],
-					result);
-				goto error;
-			}
-		}
-	}
-	return 0;
-
-error:
-	for (; --i >= 0;) {
-		if (dev->i2c_gpios[i] >= 0)
-			gpio_free(dev->i2c_gpios[i]);
-	}
-	return result;
-}
-
-static inline void qup_i2c_free_gpios(struct qup_i2c_dev *dev)
-{
-	int i;
-
-	for (i = 0; i < ARRAY_SIZE(i2c_rsrcs); ++i) {
-		if (dev->i2c_gpios[i] >= 0)
-			gpio_free(dev->i2c_gpios[i]);
-	}
-}
-
 #ifdef DEBUG
 static void qup_verify_fifo(struct qup_i2c_dev *dev, uint32_t val,
 				uint32_t addr, int rdwr)
@@ -948,19 +972,35 @@
 	long timeout;
 	int err;
 
-	/* Alternate if runtime power management is disabled */
-	if (!pm_runtime_enabled(dev->dev)) {
-		dev_dbg(dev->dev, "Runtime PM is disabled\n");
-		i2c_qup_pm_resume_runtime(dev->dev);
-	} else {
-		pm_runtime_get_sync(dev->dev);
-	}
+	/*
+	 * If all slaves of this controller behave as expected, they will
+	 * implement suspend and won't call any transaction if they are
+	 * suspended. Since controller is its parent, controller's suspend
+	 * will be called only AFTER alls slaves are suspended.
+	 * However reality is differe and some slave don't implement suspend
+	 * If a slave tries to initiate transfer when we are suspended,
+	 * pm_runtime_enabled is set to false by system-pm.
+	 * Make sure we return error when transaction is initiated while
+	 * we are in suspended state
+	 */
 	mutex_lock(&dev->mlock);
-
-	if (dev->suspended) {
+	if (dev->pwr_state >= MSM_I2C_SYS_SUSPENDING) {
+		dev_err(dev->dev,
+			"xfer not allowed when ctrl is suspended addr:0x%x\n",
+			msgs->addr);
 		mutex_unlock(&dev->mlock);
 		return -EIO;
 	}
+	if (!pm_runtime_enabled(dev->dev)) {
+		dev_dbg(dev->dev, "Runtime PM FEATURE is disabled\n");
+		i2c_qup_pm_resume(dev);
+	} else {
+		pm_runtime_get_sync(dev->dev);
+	}
+
+
+	if (dev->pdata->clk_ctl_xfer)
+		i2c_qup_pm_resume_clk(dev);
 
 	/* Initialize QUP registers during first transfer */
 	if (dev->clk_ctl == 0) {
@@ -1263,6 +1303,8 @@
 	dev->pos = 0;
 	dev->err = 0;
 	dev->cnt = 0;
+	if (dev->pdata->clk_ctl_xfer)
+		i2c_qup_pm_suspend_clk(dev);
 	mutex_unlock(&dev->mlock);
 	pm_runtime_mark_last_busy(dev->dev);
 	pm_runtime_put_autosuspend(dev->dev);
@@ -1296,14 +1338,15 @@
 	struct device_node *node = pdev->dev.of_node;
 	struct msm_i2c_dt_to_pdata_map *itr;
 	struct msm_i2c_dt_to_pdata_map  map[] = {
-	{"qcom,i2c-bus-freq", &pdata->clk_freq    , DT_REQUIRED , DT_U32 ,  0},
-	{"cell-index"       , &pdev->id           , DT_REQUIRED , DT_U32 , -1},
+	{"qcom,i2c-bus-freq", &pdata->clk_freq,     DT_REQUIRED,  DT_U32,   0},
+	{"cell-index",        &pdev->id,            DT_REQUIRED,  DT_U32,  -1},
 	{"qcom,i2c-src-freq", &pdata->src_clk_rate, DT_SUGGESTED, DT_U32,   0},
-	{"qcom,master-id"   , &pdata->master_id   , DT_SUGGESTED, DT_U32,   0},
-	{"qcom,scl-gpio"    , gpios               , DT_OPTIONAL , DT_GPIO, -1},
-	{"qcom,sda-gpio"    , gpios + 1           , DT_OPTIONAL , DT_GPIO, -1},
-	{"qcom,active-only" , &pdata->active_only , DT_OPTIONAL , DT_BOOL,  0},
-	{NULL               , NULL                , 0           , 0      ,  0},
+	{"qcom,master-id",    &pdata->master_id,    DT_SUGGESTED, DT_U32,   0},
+	{"qcom,scl-gpio",      gpios,               DT_OPTIONAL,  DT_GPIO, -1},
+	{"qcom,sda-gpio",      gpios + 1,           DT_OPTIONAL,  DT_GPIO, -1},
+	{"qcom,clk-ctl-xfer", &pdata->clk_ctl_xfer, DT_OPTIONAL,  DT_BOOL, -1},
+	{"qcom,active-only",  &pdata->active_only,  DT_OPTIONAL,  DT_BOOL,  0},
+	{NULL,                 NULL,                0,            0,        0},
 	};
 
 	for (itr = map; itr->dt_name ; ++itr) {
@@ -1611,7 +1654,7 @@
 		pdata->msm_i2c_config_gpio(dev->adapter.nr, 1);
 
 	mutex_init(&dev->mlock);
-	dev->pwr_state = 0;
+	dev->pwr_state = MSM_I2C_PM_SUSPENDED;
 	/* If the same AHB clock is used on Modem side
 	 * switch it on here itself and don't switch it
 	 * on and off during suspend and resume.
@@ -1685,13 +1728,11 @@
 
 	/* Grab mutex to ensure ongoing transaction is over */
 	mutex_lock(&dev->mlock);
-	dev->suspended = 1;
+	dev->pwr_state = MSM_I2C_SYS_SUSPENDING;
 	mutex_unlock(&dev->mlock);
+	i2c_qup_pm_suspend(dev);
+	dev->pwr_state = MSM_I2C_SYS_SUSPENDED;
 	mutex_destroy(&dev->mlock);
-	if (dev->pwr_state != 0) {
-		qup_i2c_pwr_mgmt(dev, 0);
-		qup_i2c_free_gpios(dev);
-	}
 	platform_set_drvdata(pdev, NULL);
 	if (dev->num_irqs == 3) {
 		free_irq(dev->out_irq, dev);
@@ -1732,14 +1773,7 @@
 	struct platform_device *pdev = to_platform_device(device);
 	struct qup_i2c_dev *dev = platform_get_drvdata(pdev);
 	dev_dbg(device, "pm_runtime: suspending...\n");
-	/* Grab mutex to ensure ongoing transaction is over */
-	mutex_lock(&dev->mlock);
-	dev->suspended = 1;
-	mutex_unlock(&dev->mlock);
-	if (dev->pwr_state != 0) {
-		qup_i2c_pwr_mgmt(dev, 0);
-		qup_i2c_free_gpios(dev);
-	}
+	i2c_qup_pm_suspend(dev);
 	return 0;
 }
 
@@ -1747,23 +1781,22 @@
 {
 	struct platform_device *pdev = to_platform_device(device);
 	struct qup_i2c_dev *dev = platform_get_drvdata(pdev);
-	int ret = 0;
 	dev_dbg(device, "pm_runtime: resuming...\n");
-	if (dev->pwr_state == 0) {
-		ret = qup_i2c_request_gpios(dev);
-		if (ret != 0)
-			return ret;
-		qup_i2c_pwr_mgmt(dev, 1);
-	}
-	dev->suspended = 0;
+	i2c_qup_pm_resume(dev);
 	return 0;
 }
 
-static int qup_i2c_suspend(struct device *device)
+static int i2c_qup_pm_suspend_sys(struct device *device)
 {
+	struct platform_device *pdev = to_platform_device(device);
+	struct qup_i2c_dev *dev = platform_get_drvdata(pdev);
+	/* Acquire mutex to ensure current transaction is over */
+	mutex_lock(&dev->mlock);
+	dev->pwr_state = MSM_I2C_SYS_SUSPENDING;
+	mutex_unlock(&dev->mlock);
 	if (!pm_runtime_enabled(device) || !pm_runtime_suspended(device)) {
-		dev_dbg(device, "system suspend");
-		i2c_qup_pm_suspend_runtime(device);
+		dev_dbg(device, "system suspend\n");
+		i2c_qup_pm_suspend(dev);
 		/*
 		 * set the device's runtime PM status to 'suspended'
 		 */
@@ -1771,25 +1804,29 @@
 		pm_runtime_set_suspended(device);
 		pm_runtime_enable(device);
 	}
+	dev->pwr_state = MSM_I2C_SYS_SUSPENDED;
 	return 0;
 }
 
-static int qup_i2c_resume(struct device *device)
+static int i2c_qup_pm_resume_sys(struct device *device)
 {
+	struct platform_device *pdev = to_platform_device(device);
+	struct qup_i2c_dev *dev = 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 ON and gpio configuration
 	 */
-	dev_dbg(device, "system resume");
+	dev_dbg(device, "system resume\n");
+	dev->pwr_state = MSM_I2C_PM_SUSPENDED;
 	return 0;
 }
 #endif /* CONFIG_PM */
 
 static const struct dev_pm_ops i2c_qup_dev_pm_ops = {
 	SET_SYSTEM_SLEEP_PM_OPS(
-		qup_i2c_suspend,
-		qup_i2c_resume
+		i2c_qup_pm_suspend_sys,
+		i2c_qup_pm_resume_sys
 	)
 	SET_RUNTIME_PM_OPS(
 		i2c_qup_pm_suspend_runtime,
@@ -1817,11 +1854,18 @@
 };
 
 /* QUP may be needed to bring up other drivers */
-static int __init
-qup_i2c_init_driver(void)
+int __init qup_i2c_init_driver(void)
 {
+	static bool initialized;
+
+	if (initialized)
+		return 0;
+	else
+		initialized = true;
+
 	return platform_driver_register(&qup_i2c_driver);
 }
+EXPORT_SYMBOL(qup_i2c_init_driver);
 arch_initcall(qup_i2c_init_driver);
 
 static void __exit qup_i2c_exit_driver(void)
diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
index 716ea0d..0c22694 100644
--- a/drivers/input/misc/Kconfig
+++ b/drivers/input/misc/Kconfig
@@ -73,6 +73,16 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called bma150.
 
+config INPUT_HBTP_INPUT
+	tristate "HBTP input driver support"
+	help
+	  Say Y to enable HBTP input driver.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called hbtp_input.
+
+endif
+
 config INPUT_PCSPKR
 	tristate "PC Speaker support"
 	depends on PCSPKR_PLATFORM
@@ -714,4 +724,3 @@
 
 	  To compile this driver as a module, choose M here: the
 	  module will be called CM36283.
-endif
diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile
index c927e0e..c9a65fc 100644
--- a/drivers/input/misc/Makefile
+++ b/drivers/input/misc/Makefile
@@ -26,6 +26,7 @@
 obj-$(CONFIG_INPUT_GP2A)		+= gp2ap002a00f.o
 obj-$(CONFIG_INPUT_GPIO_TILT_POLLED)	+= gpio_tilt_polled.o
 obj-$(CONFIG_INPUT_GPIO)		+= gpio_event.o gpio_matrix.o gpio_input.o gpio_output.o gpio_axis.o
+obj-$(CONFIG_INPUT_HBTP_INPUT)		+= hbtp_input.o
 obj-$(CONFIG_HP_SDC_RTC)		+= hp_sdc_rtc.o
 obj-$(CONFIG_INPUT_IXP4XX_BEEPER)	+= ixp4xx-beeper.o
 obj-$(CONFIG_INPUT_KEYCHORD)		+= keychord.o
diff --git a/drivers/input/misc/bmp18x-core.c b/drivers/input/misc/bmp18x-core.c
index 001a804..6f82277 100644
--- a/drivers/input/misc/bmp18x-core.c
+++ b/drivers/input/misc/bmp18x-core.c
@@ -75,35 +75,6 @@
 #define ABS_MAX_PRESSURE	120000
 #define BMP_DELAY_DEFAULT   200
 
-struct bmp18x_calibration_data {
-	s16 AC1, AC2, AC3;
-	u16 AC4, AC5, AC6;
-	s16 B1, B2;
-	s16 MB, MC, MD;
-};
-
-/* Each client has this additional data */
-struct bmp18x_data {
-	struct	bmp18x_data_bus data_bus;
-	struct	device *dev;
-	struct	mutex lock;
-	struct	bmp18x_calibration_data calibration;
-	u8	oversampling_setting;
-	u8	sw_oversampling_setting;
-	u32	raw_temperature;
-	u32	raw_pressure;
-	u32	temp_measurement_period;
-	u32	last_temp_measurement;
-	s32	b6; /* calculated temperature correction coefficient */
-#ifdef CONFIG_HAS_EARLYSUSPEND
-	struct early_suspend early_suspend;
-#endif
-	struct input_dev	*input;
-	struct delayed_work work;
-	u32					delay;
-	u32					enable;
-};
-
 static struct sensors_classdev sensors_cdev = {
 	.name = "bmp18x-pressure",
 	.vendor = "Bosch",
@@ -113,9 +84,13 @@
 	.max_range = "1100.0",
 	.resolution = "0.01",
 	.sensor_power = "0.67",
-	.min_delay = 20000,
+	.min_delay = 20000,	/* microsecond */
 	.fifo_reserved_event_count = 0,
 	.fifo_max_event_count = 0,
+	.enabled = 0,
+	.delay_msec = 200,	/* millisecond */
+	.sensors_enable = NULL,
+	.sensors_poll_delay = NULL,
 };
 
 #ifdef CONFIG_HAS_EARLYSUSPEND
@@ -403,6 +378,19 @@
 static DEVICE_ATTR(sw_oversampling, S_IWUSR | S_IRUGO,
 				show_sw_oversampling, set_sw_oversampling);
 
+static ssize_t bmp18x_poll_delay_set(struct sensors_classdev *sensors_cdev,
+						unsigned int delay_msec)
+{
+	struct bmp18x_data *data = container_of(sensors_cdev,
+					struct bmp18x_data, cdev);
+	mutex_lock(&data->lock);
+	data->delay = delay_msec;
+	mutex_unlock(&data->lock);
+
+	return 0;
+}
+
+
 static ssize_t show_delay(struct device *dev,
 				 struct device_attribute *attr, char *buf)
 {
@@ -416,17 +404,51 @@
 {
 	struct bmp18x_data *data = dev_get_drvdata(dev);
 	unsigned long delay;
-	int success = kstrtoul(buf, 10, &delay);
-	if (success == 0) {
-		mutex_lock(&data->lock);
-		data->delay = delay;
-		mutex_unlock(&data->lock);
-	}
-	return success;
+	int err = kstrtoul(buf, 10, &delay);
+	if (err < 0)
+		return err;
+
+	err = bmp18x_poll_delay_set(&data->cdev, delay);
+	if (err < 0)
+		return err;
+
+	return count;
 }
-static DEVICE_ATTR(delay, S_IWUSR | S_IRUGO,
+
+static DEVICE_ATTR(poll_delay, S_IWUSR | S_IRUGO,
 				show_delay, set_delay);
 
+static ssize_t bmp18x_enable_set(struct sensors_classdev *sensors_cdev,
+						unsigned int enabled)
+{
+	struct bmp18x_data *data = container_of(sensors_cdev,
+					struct bmp18x_data, cdev);
+	struct device *dev = data->dev;
+
+	enabled = enabled ? 1 : 0;
+	mutex_lock(&data->lock);
+
+	if (data->enable == enabled) {
+		dev_warn(dev, "already %s\n", enabled ? "enabled" : "disabled");
+		goto out;
+	}
+
+	data->enable = enabled;
+
+	if (data->enable) {
+		bmp18x_enable(dev);
+		schedule_delayed_work(&data->work,
+					msecs_to_jiffies(data->delay));
+	} else {
+		cancel_delayed_work_sync(&data->work);
+		bmp18x_disable(dev);
+	}
+
+out:
+	mutex_unlock(&data->lock);
+	return 0;
+}
+
 static ssize_t show_enable(struct device *dev,
 				 struct device_attribute *attr, char *buf)
 {
@@ -440,24 +462,17 @@
 {
 	struct bmp18x_data *data = dev_get_drvdata(dev);
 	unsigned long enable;
-	int success = kstrtoul(buf, 10, &enable);
-	if (success == 0) {
-		mutex_lock(&data->lock);
-		data->enable = enable ? 1 : 0;
+	int err = kstrtoul(buf, 10, &enable);
+	if (err < 0)
+		return err;
 
-		if (data->enable) {
-			bmp18x_enable(dev);
-			schedule_delayed_work(&data->work,
-						msecs_to_jiffies(data->delay));
-		} else {
-			cancel_delayed_work_sync(&data->work);
-			bmp18x_disable(dev);
-		}
-		mutex_unlock(&data->lock);
+	err = bmp18x_enable_set(&data->cdev, enable);
+	if (err < 0)
+		return err;
 
-	}
 	return count;
 }
+
 static DEVICE_ATTR(enable, S_IWUSR | S_IRUGO,
 				show_enable, set_enable);
 
@@ -499,7 +514,7 @@
 	&dev_attr_pressure0_input.attr,
 	&dev_attr_oversampling.attr,
 	&dev_attr_sw_oversampling.attr,
-	&dev_attr_delay.attr,
+	&dev_attr_poll_delay.attr,
 	&dev_attr_enable.attr,
 	NULL
 };
@@ -628,7 +643,10 @@
 	if (err)
 		goto error_sysfs;
 
-	err = sensors_classdev_register(&data->input->dev, &sensors_cdev);
+	data->cdev = sensors_cdev;
+	data->cdev.sensors_enable = bmp18x_enable_set;
+	data->cdev.sensors_poll_delay = bmp18x_poll_delay_set;
+	err = sensors_classdev_register(&data->input->dev, &data->cdev);
 	if (err) {
 		pr_err("class device create failed: %d\n", err);
 		goto error_class_sysfs;
@@ -646,6 +664,8 @@
 	register_early_suspend(&data->early_suspend);
 #endif
 
+	pdata->set_power(data, 0);
+	data->power_enabled = 0;
 	dev_info(dev, "Succesfully initialized bmp18x!\n");
 	return 0;
 
@@ -680,10 +700,12 @@
 {
 	struct bmp18x_platform_data *pdata = dev->platform_data;
 	struct bmp18x_data *data = dev_get_drvdata(dev);
-	if (pdata && pdata->deinit_hw)
-		pdata->deinit_hw(&data->data_bus);
+	int ret = 0;
 
-	return 0;
+	if (pdata && pdata->set_power)
+		ret = pdata->set_power(data, 0);
+
+	return ret;
 }
 EXPORT_SYMBOL(bmp18x_disable);
 
@@ -691,10 +713,12 @@
 {
 	struct bmp18x_platform_data *pdata = dev->platform_data;
 	struct bmp18x_data *data = dev_get_drvdata(dev);
-	if (pdata && pdata->init_hw)
-		return pdata->init_hw(&data->data_bus);
+	int ret = 0;
 
-	return 0;
+	if (pdata && pdata->set_power)
+		ret = pdata->set_power(data, 1);
+
+	return ret;
 }
 EXPORT_SYMBOL(bmp18x_enable);
 #endif
diff --git a/drivers/input/misc/bmp18x-i2c.c b/drivers/input/misc/bmp18x-i2c.c
index abbe6e5..75edd0b 100644
--- a/drivers/input/misc/bmp18x-i2c.c
+++ b/drivers/input/misc/bmp18x-i2c.c
@@ -24,6 +24,7 @@
 #include <linux/i2c.h>
 #include <linux/err.h>
 #include <linux/regulator/consumer.h>
+#include <linux/delay.h>
 #include "bmp18x.h"
 
 struct sensor_regulator {
@@ -102,9 +103,13 @@
 
 static int bmp18x_init_hw(struct bmp18x_data_bus *data_bus)
 {
-	if (data_bus->client)
-		return bmp18x_config_regulator(data_bus->client, 1);
-	return 0;
+	int ret = 0;
+	if (data_bus->client) {
+		ret = bmp18x_config_regulator(data_bus->client, 1);
+		/* The minimum start up time of bmp18x is 10ms */
+		usleep_range(15000, 20000);
+	}
+	return ret;
 }
 
 static void bmp18x_deinit_hw(struct bmp18x_data_bus *data_bus)
@@ -113,6 +118,43 @@
 		bmp18x_config_regulator(data_bus->client, 0);
 }
 
+static int bmp18x_set_power(struct bmp18x_data *data, int on)
+{
+	int rc = 0;
+	int num_vreg = ARRAY_SIZE(bmp_vreg);
+	int i;
+
+	if (!on && data->power_enabled) {
+		for (i = 0; i < num_vreg; i++) {
+			rc = regulator_disable(bmp_vreg[i].vreg);
+			if (rc) {
+				dev_err(data->dev, "Regulator vdd disable failed rc=%d\n",
+						rc);
+				return rc;
+			}
+		}
+		data->power_enabled = false;
+	} else if (on && !data->power_enabled) {
+		for (i = 0; i < num_vreg; i++) {
+			rc = regulator_enable(bmp_vreg[i].vreg);
+			if (rc) {
+				dev_err(data->dev, "Regulator vdd enable failed rc=%d\n",
+						rc);
+				return rc;
+			}
+		}
+		/* The minimum start up time of bmp18x is 10ms */
+		usleep_range(15000, 20000);
+		data->power_enabled = true;
+	} else {
+		dev_warn(data->dev,
+				"Power on=%d. enabled=%d\n",
+				on, data->power_enabled);
+	}
+
+	return rc;
+}
+
 #ifdef CONFIG_OF
 static int bmp18x_parse_dt(struct device *dev,
 			struct bmp18x_platform_data *pdata)
@@ -198,6 +240,7 @@
 		}
 		pdata->init_hw = bmp18x_init_hw;
 		pdata->deinit_hw = bmp18x_deinit_hw;
+		pdata->set_power = bmp18x_set_power;
 		client->dev.platform_data = pdata;
 	}
 	return bmp18x_probe(&client->dev, &data_bus);
@@ -216,12 +259,24 @@
 #ifdef CONFIG_PM
 static int bmp18x_i2c_suspend(struct device *dev)
 {
-	return bmp18x_disable(dev);
+	int ret = 0;
+	struct bmp18x_data *data = dev_get_drvdata(dev);
+
+	if (data->enable)
+		ret = bmp18x_disable(dev);
+
+	return ret;
 }
 
 static int bmp18x_i2c_resume(struct device *dev)
 {
-	return bmp18x_enable(dev);
+	int ret = 0;
+	struct bmp18x_data *data = dev_get_drvdata(dev);
+
+	if (data->enable)
+		ret = bmp18x_enable(dev);
+
+	return ret;
 }
 
 static const struct dev_pm_ops bmp18x_i2c_pm_ops = {
diff --git a/drivers/input/misc/bmp18x.h b/drivers/input/misc/bmp18x.h
index d1b1ee7..6b6c4b1 100644
--- a/drivers/input/misc/bmp18x.h
+++ b/drivers/input/misc/bmp18x.h
@@ -18,6 +18,7 @@
 */
 #ifndef _BMP18X_H
 #define _BMP18X_H
+#include <linux/sensors.h>
 
 #define BMP18X_NAME "bmp18x"
 
@@ -46,13 +47,47 @@
 	void	*client;
 };
 
+struct bmp18x_calibration_data {
+	s16 AC1, AC2, AC3;
+	u16 AC4, AC5, AC6;
+	s16 B1, B2;
+	s16 MB, MC, MD;
+};
+
+/* Each client has this additional data */
+struct bmp18x_data {
+	struct	bmp18x_data_bus data_bus;
+	struct	device *dev;
+	struct	mutex lock;
+	struct	bmp18x_calibration_data calibration;
+	struct	sensors_classdev cdev;
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	struct	early_suspend early_suspend;
+#endif
+	struct	input_dev	*input;
+	struct	delayed_work work;
+
+	u8	oversampling_setting;
+	u8	sw_oversampling_setting;
+	u32	raw_temperature;
+	u32	raw_pressure;
+	u32	temp_measurement_period;
+	u32	last_temp_measurement;
+	s32	b6; /* calculated temperature correction coefficient */
+	u32	delay;
+	u32	enable;
+	u32	power_enabled;
+};
+
 struct bmp18x_platform_data {
 	u8	chip_id;
 	u8	default_oversampling;
 	u8	default_sw_oversampling;
 	u32	temp_measurement_period;
+	u32	power_enabled;
 	int	(*init_hw)(struct bmp18x_data_bus *);
 	void	(*deinit_hw)(struct bmp18x_data_bus *);
+	int	(*set_power)(struct bmp18x_data*, int);
 };
 
 int bmp18x_probe(struct device *dev, struct bmp18x_data_bus *data_bus);
diff --git a/drivers/input/misc/cm36283.c b/drivers/input/misc/cm36283.c
index 5c89c0c..a7b4735 100644
--- a/drivers/input/misc/cm36283.c
+++ b/drivers/input/misc/cm36283.c
@@ -3,7 +3,7 @@
  * Copyright (C) 2012 Capella Microsystems Inc.
  * Author: Frank Hsieh <pengyueh@gmail.com>
  *
- * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
@@ -75,6 +75,10 @@
 	.min_delay = 0,
 	.fifo_reserved_event_count = 0,
 	.fifo_max_event_count = 0,
+	.enabled = 0,
+	.delay_msec = CM36283_LS_DEFAULT_POLL_DELAY,
+	.sensors_enable = NULL,
+	.sensors_poll_delay = NULL,
 };
 
 static struct sensors_classdev sensors_proximity_cdev = {
@@ -89,6 +93,10 @@
 	.min_delay = 0,
 	.fifo_reserved_event_count = 0,
 	.fifo_max_event_count = 0,
+	.enabled = 0,
+	.delay_msec = CM36283_PS_DEFAULT_POLL_DELAY,
+	.sensors_enable = NULL,
+	.sensors_poll_delay = NULL,
 };
 
 
@@ -159,6 +167,8 @@
 	struct regulator *vio;
 	struct delayed_work ldwork;
 	struct delayed_work pdwork;
+	struct sensors_classdev als_cdev;
+	struct sensors_classdev ps_cdev;
 };
 struct cm36283_info *lp_info;
 int fLevel=-1;
@@ -640,12 +650,6 @@
 	.unlocked_ioctl = psensor_ioctl
 };
 
-struct miscdevice psensor_misc = {
-	.minor = MISC_DYNAMIC_MINOR,
-	.name = "proximity",
-	.fops = &psensor_fops
-};
-
 void lightsensor_set_kvalue(struct cm36283_info *lpi)
 {
 	if (!lpi) {
@@ -793,13 +797,6 @@
 	.unlocked_ioctl = lightsensor_ioctl
 };
 
-static struct miscdevice lightsensor_misc = {
-	.minor = MISC_DYNAMIC_MINOR,
-	.name = "lightsensor",
-	.fops = &lightsensor_fops
-};
-
-
 static ssize_t ps_adc_show(struct device *dev,
 			struct device_attribute *attr, char *buf)
 {
@@ -819,6 +816,21 @@
 	return ret;
 }
 
+static int ps_enable_set(struct sensors_classdev *sensors_cdev,
+		unsigned int enable)
+{
+	struct cm36283_info *lpi = container_of(sensors_cdev,
+			struct cm36283_info, ps_cdev);
+	int ret;
+
+	if (enable)
+		ret = psensor_enable(lpi);
+	else
+		ret = psensor_disable(lpi);
+
+	return ret;
+}
+
 static ssize_t ps_enable_store(struct device *dev,
 				struct device_attribute *attr,
 				const char *buf, size_t count)
@@ -844,7 +856,6 @@
 	return count;
 }
 
-static DEVICE_ATTR(ps_adc, 0664, ps_adc_show, ps_enable_store);
 
 static ssize_t ps_parameters_show(struct device *dev,
 			struct device_attribute *attr, char *buf)
@@ -888,10 +899,6 @@
 	return count;
 }
 
-static DEVICE_ATTR(ps_parameters, 0664,
-	ps_parameters_show, ps_parameters_store);
-
-
 static ssize_t ps_conf_show(struct device *dev,
 			struct device_attribute *attr, char *buf)
 {
@@ -917,7 +924,6 @@
 
 	return count;
 }
-static DEVICE_ATTR(ps_conf, 0664, ps_conf_show, ps_conf_store);
 
 static ssize_t ps_thd_show(struct device *dev,
 			struct device_attribute *attr, char *buf)
@@ -946,7 +952,6 @@
 
 	return count;
 }
-static DEVICE_ATTR(ps_thd, 0664, ps_thd_show, ps_thd_store);
 
 static ssize_t ps_hw_show(struct device *dev,
 			struct device_attribute *attr, char *buf)
@@ -969,7 +974,6 @@
 
 	return count;
 }
-static DEVICE_ATTR(ps_hw, 0664, ps_hw_show, ps_hw_store);
 
 static ssize_t ls_adc_show(struct device *dev,
 				  struct device_attribute *attr, char *buf)
@@ -983,7 +987,26 @@
 	return ret;
 }
 
-static DEVICE_ATTR(ls_adc, 0664, ls_adc_show, NULL);
+static int ls_enable_set(struct sensors_classdev *sensors_cdev,
+		unsigned int enable)
+{
+	struct cm36283_info *lpi = container_of(sensors_cdev,
+			struct cm36283_info, als_cdev);
+	int ret;
+
+	if (enable)
+		ret = lightsensor_enable(lpi);
+	else
+		ret = lightsensor_disable(lpi);
+
+	if (ret < 0) {
+		dev_err(&lpi->i2c_client->dev, "%s: set auto light sensor fail\n",
+				__func__);
+		return -EIO;
+	}
+
+	return 0;
+}
 
 static ssize_t ls_enable_show(struct device *dev,
 				  struct device_attribute *attr, char *buf)
@@ -1026,15 +1049,15 @@
 			lpi->ls_calibrate);
 	dev_dbg(&lpi->i2c_client->dev, "ls_auto:0x%x\n", ls_auto);
 
-	if (ret < 0)
+	if (ret < 0) {
 		dev_err(&lpi->i2c_client->dev, "%s: set auto light sensor fail\n",
 		__func__);
+		return ret;
+	}
 
 	return count;
 }
 
-static DEVICE_ATTR(ls_auto, 0664,
-	ls_enable_show, ls_enable_store);
 
 static ssize_t ls_kadc_show(struct device *dev,
 				  struct device_attribute *attr, char *buf)
@@ -1077,7 +1100,6 @@
 	return count;
 }
 
-static DEVICE_ATTR(ls_kadc, 0664, ls_kadc_show, ls_kadc_store);
 
 static ssize_t ls_gadc_show(struct device *dev,
 				  struct device_attribute *attr, char *buf)
@@ -1117,7 +1139,6 @@
 	return count;
 }
 
-static DEVICE_ATTR(ls_gadc, 0664, ls_gadc_show, ls_gadc_store);
 
 static ssize_t ls_adc_table_show(struct device *dev,
 			struct device_attribute *attr, char *buf)
@@ -1168,9 +1189,6 @@
 	return count;
 }
 
-static DEVICE_ATTR(ls_adc_table, 0664,
-	ls_adc_table_show, ls_adc_table_store);
-
 static ssize_t ls_conf_show(struct device *dev,
 				  struct device_attribute *attr, char *buf)
 {
@@ -1192,7 +1210,6 @@
 	_cm36283_I2C_Write_Word(lpi->slave_addr, ALS_CONF, lpi->ls_cmd);
 	return count;
 }
-static DEVICE_ATTR(ls_conf, 0664, ls_conf_show, ls_conf_store);
 
 static ssize_t ls_poll_delay_show(struct device *dev,
 		struct device_attribute *attr, char *buf)
@@ -1219,8 +1236,20 @@
 	return count;
 }
 
-static DEVICE_ATTR(ls_poll_delay, 0664, ls_poll_delay_show,
-		ls_poll_delay_store);
+static int ls_poll_delay_set(struct sensors_classdev *sensors_cdev,
+		unsigned int delay_msec)
+{
+	struct cm36283_info *lpi = container_of(sensors_cdev,
+			struct cm36283_info, als_cdev);
+
+	if ((delay_msec < CM36283_LS_MIN_POLL_DELAY) ||
+			(delay_msec > CM36283_LS_MAX_POLL_DELAY))
+		return -EINVAL;
+
+	atomic_set(&lpi->ls_poll_delay, delay_msec);
+
+	return 0;
+}
 
 static ssize_t ps_poll_delay_show(struct device *dev,
 		struct device_attribute *attr, char *buf)
@@ -1247,8 +1276,19 @@
 	return count;
 }
 
-static DEVICE_ATTR(ps_poll_delay, 0664, ps_poll_delay_show,
-		ps_poll_delay_store);
+static int ps_poll_delay_set(struct sensors_classdev *sensors_cdev,
+		unsigned int delay_msec)
+{
+	struct cm36283_info *lpi = container_of(sensors_cdev,
+			struct cm36283_info, als_cdev);
+
+	if ((delay_msec < CM36283_PS_MIN_POLL_DELAY) ||
+			(delay_msec > CM36283_PS_MAX_POLL_DELAY))
+		return -EINVAL;
+
+	atomic_set(&lpi->ps_poll_delay, delay_msec);
+	return 0;
+}
 
 static ssize_t ls_fLevel_show(struct device *dev,
 				  struct device_attribute *attr, char *buf)
@@ -1271,7 +1311,6 @@
 	fLevel=-1;
 	return count;
 }
-static DEVICE_ATTR(ls_flevel, 0664, ls_fLevel_show, ls_fLevel_store);
 
 static int lightsensor_setup(struct cm36283_info *lpi)
 {
@@ -1286,6 +1325,7 @@
 		return -ENOMEM;
 	}
 	lpi->ls_input_dev->name = "cm36283-ls";
+	lpi->ls_input_dev->id.bustype = BUS_I2C;
 	set_bit(EV_ABS, lpi->ls_input_dev->evbit);
 
 	range = get_als_range();
@@ -1298,17 +1338,8 @@
 		goto err_free_ls_input_device;
 	}
 
-	ret = misc_register(&lightsensor_misc);
-	if (ret < 0) {
-		pr_err("[LS][CM36283 error]%s: can not register ls misc device\n",
-				__func__);
-		goto err_unregister_ls_input_device;
-	}
-
 	return ret;
 
-err_unregister_ls_input_device:
-	input_unregister_device(lpi->ls_input_dev);
 err_free_ls_input_device:
 	input_free_device(lpi->ls_input_dev);
 	return ret;
@@ -1326,6 +1357,7 @@
 		return -ENOMEM;
 	}
 	lpi->ps_input_dev->name = "cm36283-ps";
+	lpi->ps_input_dev->id.bustype = BUS_I2C;
 	set_bit(EV_ABS, lpi->ps_input_dev->evbit);
 	input_set_abs_params(lpi->ps_input_dev, ABS_DISTANCE, 0, 1, 0, 0);
 
@@ -1337,18 +1369,8 @@
 		goto err_free_ps_input_device;
 	}
 
-	ret = misc_register(&psensor_misc);
-	if (ret < 0) {
-		pr_err(
-			"[PS][CM36283 error]%s: could not register ps misc device\n",
-			__func__);
-		goto err_unregister_ps_input_device;
-	}
-
 	return ret;
 
-err_unregister_ps_input_device:
-	input_unregister_device(lpi->ps_input_dev);
 err_free_ps_input_device:
 	input_free_device(lpi->ps_input_dev);
 	return ret;
@@ -1496,6 +1518,59 @@
 	return 0;
 }
 
+static int create_sysfs_interfaces(struct device *dev,
+		struct device_attribute *attributes, int len)
+{
+	int i;
+	int err;
+	for (i = 0; i < len; i++) {
+		err = device_create_file(dev, attributes + i);
+		if (err)
+			goto error;
+	}
+	return 0;
+
+error:
+	for (; i >= 0; i--)
+		device_remove_file(dev, attributes + i);
+	dev_err(dev, "%s:Unable to create interface\n", __func__);
+	return err;
+}
+
+static int remove_sysfs_interfaces(struct device *dev,
+		struct device_attribute *attributes, int len)
+{
+	int i;
+	for (i = 0; i < len; i++)
+		device_remove_file(dev, attributes + i);
+	return 0;
+}
+
+static struct device_attribute light_attr[] = {
+	__ATTR(ls_adc, 0664, ls_adc_show, NULL),
+	__ATTR(ls_kadc, 0664, ls_kadc_show, ls_kadc_store),
+	__ATTR(ls_gadc, 0664, ls_gadc_show, ls_gadc_store),
+	__ATTR(ls_conf, 0664, ls_conf_show, ls_conf_store),
+	__ATTR(ls_adc_table, 0664,
+			ls_adc_table_show, ls_adc_table_store),
+	__ATTR(poll_delay, 0664, ls_poll_delay_show,
+			ls_poll_delay_store),
+	__ATTR(enable, 0664,
+			ls_enable_show, ls_enable_store),
+};
+
+static struct device_attribute proximity_attr[] = {
+	__ATTR(enable, 0664, ps_adc_show, ps_enable_store),
+	__ATTR(ps_parameters, 0664,
+			ps_parameters_show, ps_parameters_store),
+	__ATTR(ps_conf, 0664, ps_conf_show, ps_conf_store),
+	__ATTR(ps_hw, 0664, ps_hw_show, ps_hw_store),
+	__ATTR(ps_thd, 0664, ps_thd_show, ps_thd_store),
+	__ATTR(poll_delay, 0664, ps_poll_delay_show,
+			ps_poll_delay_store),
+	__ATTR(ls_flevel, 0664, ls_fLevel_show, ls_fLevel_store),
+};
+
 static int cm36283_probe(struct i2c_client *client,
 	const struct i2c_device_id *id)
 {
@@ -1633,97 +1708,35 @@
 		goto err_psensor_setup;
 	}
 
-	lpi->cm36283_class = class_create(THIS_MODULE, "optical_sensors");
-	if (IS_ERR(lpi->cm36283_class)) {
-		ret = PTR_ERR(lpi->cm36283_class);
-		lpi->cm36283_class = NULL;
-		goto err_create_class;
+	ret = create_sysfs_interfaces(&lpi->ls_input_dev->dev, light_attr,
+			ARRAY_SIZE(light_attr));
+	if (ret < 0) {
+		dev_err(&client->dev, "failed to create sysfs\n");
+		goto err_input_cleanup;
 	}
 
-	lpi->ls_dev = device_create(lpi->cm36283_class,
-				NULL, 0, "%s", "lightsensor");
-	if (unlikely(IS_ERR(lpi->ls_dev))) {
-		ret = PTR_ERR(lpi->ls_dev);
-		lpi->ls_dev = NULL;
-		goto err_create_ls_device;
+	ret = create_sysfs_interfaces(&lpi->ps_input_dev->dev, proximity_attr,
+			ARRAY_SIZE(proximity_attr));
+	if (ret < 0) {
+		dev_err(&client->dev, "failed to create sysfs\n");
+		goto err_light_sysfs_cleanup;
 	}
 
-	/* register the attributes */
-	ret = device_create_file(lpi->ls_dev, &dev_attr_ls_adc);
+	lpi->als_cdev = sensors_light_cdev;
+	lpi->als_cdev.sensors_enable = ls_enable_set;
+	lpi->als_cdev.sensors_poll_delay = ls_poll_delay_set;
+	lpi->als_cdev.min_delay = CM36283_LS_MIN_POLL_DELAY * 1000;
+
+	lpi->ps_cdev = sensors_proximity_cdev;
+	lpi->ps_cdev.sensors_enable = ps_enable_set;
+	lpi->ps_cdev.sensors_poll_delay = ps_poll_delay_set;
+	lpi->ps_cdev.min_delay = CM36283_PS_MIN_POLL_DELAY * 1000;
+
+	ret = sensors_classdev_register(&client->dev, &lpi->als_cdev);
 	if (ret)
-		goto err_create_ls_device_file;
+		goto err_proximity_sysfs_cleanup;
 
-	/* register the attributes */
-	ret = device_create_file(lpi->ls_dev, &dev_attr_ls_auto);
-	if (ret)
-		goto err_create_ls_device_file;
-
-	/* register the attributes */
-	ret = device_create_file(lpi->ls_dev, &dev_attr_ls_kadc);
-	if (ret)
-		goto err_create_ls_device_file;
-
-	ret = device_create_file(lpi->ls_dev, &dev_attr_ls_gadc);
-	if (ret)
-		goto err_create_ls_device_file;
-
-	ret = device_create_file(lpi->ls_dev, &dev_attr_ls_adc_table);
-	if (ret)
-		goto err_create_ls_device_file;
-
-	ret = device_create_file(lpi->ls_dev, &dev_attr_ls_conf);
-	if (ret)
-		goto err_create_ls_device_file;
-
-	ret = device_create_file(lpi->ls_dev, &dev_attr_ls_flevel);
-	if (ret)
-		goto err_create_ls_device_file;
-
-	ret = device_create_file(lpi->ls_dev, &dev_attr_ls_poll_delay);
-	if (ret)
-		goto err_create_ls_device_file;
-
-	lpi->ps_dev = device_create(lpi->cm36283_class,
-				NULL, 0, "%s", "proximity");
-	if (unlikely(IS_ERR(lpi->ps_dev))) {
-		ret = PTR_ERR(lpi->ps_dev);
-		lpi->ps_dev = NULL;
-		goto err_create_ps_device;
-	}
-
-	/* register the attributes */
-	ret = device_create_file(lpi->ps_dev, &dev_attr_ps_adc);
-	if (ret)
-		goto err_create_ps_device_file;
-
-	ret = device_create_file(lpi->ps_dev,
-		&dev_attr_ps_parameters);
-	if (ret)
-		goto err_create_ps_device_file;
-
-	/* register the attributes */
-	ret = device_create_file(lpi->ps_dev, &dev_attr_ps_conf);
-	if (ret)
-		goto err_create_ps_device_file;
-
-	/* register the attributes */
-	ret = device_create_file(lpi->ps_dev, &dev_attr_ps_thd);
-	if (ret)
-		goto err_create_ps_device_file;
-
-	ret = device_create_file(lpi->ps_dev, &dev_attr_ps_hw);
-	if (ret)
-		goto err_create_ps_device_file;
-
-	ret = device_create_file(lpi->ps_dev, &dev_attr_ps_poll_delay);
-	if (ret)
-		goto err_create_ps_device_file;
-
-	ret = sensors_classdev_register(&client->dev, &sensors_light_cdev);
-	if (ret)
-		goto err_create_ps_device_file;
-
-	ret = sensors_classdev_register(&client->dev, &sensors_proximity_cdev);
+	ret = sensors_classdev_register(&client->dev, &lpi->ps_cdev);
 	if (ret)
 		goto err_create_class_sysfs;
 
@@ -1734,20 +1747,17 @@
 
 	return ret;
 err_create_class_sysfs:
-	sensors_classdev_unregister(&sensors_light_cdev);
-err_create_ps_device_file:
-	device_unregister(lpi->ps_dev);
-err_create_ps_device:
-err_create_ls_device_file:
-	device_unregister(lpi->ls_dev);
-err_create_ls_device:
-	class_destroy(lpi->cm36283_class);
-err_create_class:
-	misc_deregister(&psensor_misc);
+	sensors_classdev_unregister(&lpi->als_cdev);
+err_proximity_sysfs_cleanup:
+	remove_sysfs_interfaces(&lpi->ps_input_dev->dev, proximity_attr,
+			ARRAY_SIZE(proximity_attr));
+err_light_sysfs_cleanup:
+	remove_sysfs_interfaces(&lpi->ls_input_dev->dev, light_attr,
+			ARRAY_SIZE(light_attr));
+err_input_cleanup:
 	input_unregister_device(lpi->ps_input_dev);
 	input_free_device(lpi->ps_input_dev);
 err_psensor_setup:
-	misc_deregister(&lightsensor_misc);
 	input_unregister_device(lpi->ls_input_dev);
 	input_free_device(lpi->ls_input_dev);
 err_lightsensor_setup:
diff --git a/drivers/input/misc/hbtp_input.c b/drivers/input/misc/hbtp_input.c
new file mode 100644
index 0000000..83ba652
--- /dev/null
+++ b/drivers/input/misc/hbtp_input.c
@@ -0,0 +1,477 @@
+
+/* 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/poll.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/hbtp_input.h>
+#include <linux/input/mt.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include "../input-compat.h"
+
+#if defined(CONFIG_FB)
+#include <linux/notifier.h>
+#include <linux/fb.h>
+#endif
+
+#define HBTP_INPUT_NAME			"hbtp_input"
+#define HBTP_AFE_LOAD_UA		150000
+#define HBTP_AFE_VTG_MIN_UV		2700000
+#define HBTP_AFE_VTG_MAX_UV		3300000
+
+struct hbtp_data {
+	struct platform_device *pdev;
+	struct input_dev *input_dev;
+	s32 count;
+	bool touch_status[HBTP_MAX_FINGER];
+#if defined(CONFIG_FB)
+	struct notifier_block fb_notif;
+#endif
+	struct regulator *vcc_ana;
+};
+
+static struct hbtp_data *hbtp;
+
+#if defined(CONFIG_FB)
+static int fb_notifier_callback(struct notifier_block *self,
+				 unsigned long event, void *data)
+{
+	int blank;
+	struct fb_event *evdata = data;
+	struct hbtp_data *hbtp_data =
+		container_of(self, struct hbtp_data, fb_notif);
+
+	if (evdata && evdata->data && event == FB_EVENT_BLANK &&
+		hbtp_data && hbtp_data->input_dev) {
+		blank = *(int *)(evdata->data);
+		if (blank == FB_BLANK_UNBLANK)
+			kobject_uevent(&hbtp_data->input_dev->dev.kobj,
+					KOBJ_ONLINE);
+		else if (blank == FB_BLANK_POWERDOWN)
+			kobject_uevent(&hbtp_data->input_dev->dev.kobj,
+					KOBJ_OFFLINE);
+	}
+
+	return 0;
+}
+#endif
+
+static int hbtp_input_open(struct inode *inode, struct file *file)
+{
+	if (hbtp->count) {
+		pr_err("%s is busy\n", HBTP_INPUT_NAME);
+		return -EBUSY;
+	}
+	hbtp->count++;
+
+	return 0;
+}
+
+static int hbtp_input_release(struct inode *inode, struct file *file)
+{
+	if (!hbtp->count) {
+		pr_err("%s wasn't opened\n", HBTP_INPUT_NAME);
+		return -ENOTTY;
+	}
+	hbtp->count--;
+
+	return 0;
+}
+
+static int hbtp_input_create_input_dev(struct hbtp_input_absinfo *absinfo)
+{
+	struct input_dev *input_dev;
+	struct hbtp_input_absinfo *abs;
+	int error;
+	int i;
+
+	input_dev = input_allocate_device();
+	if (!input_dev) {
+		pr_err("%s: input_allocate_device failed\n", __func__);
+		return -ENOMEM;
+	}
+
+	kfree(input_dev->name);
+	input_dev->name = kstrndup(HBTP_INPUT_NAME, sizeof(HBTP_INPUT_NAME),
+					GFP_KERNEL);
+	__set_bit(EV_ABS, input_dev->evbit);
+	__set_bit(EV_KEY, input_dev->evbit);
+	__set_bit(BTN_TOUCH, input_dev->keybit);
+	__set_bit(INPUT_PROP_DIRECT, input_dev->propbit);
+
+	/* For multi touch */
+	input_mt_init_slots(input_dev, HBTP_MAX_FINGER);
+	for (i = 0; i <= ABS_MT_LAST - ABS_MT_FIRST; i++) {
+		abs = absinfo + i;
+		if (abs->active)
+			input_set_abs_params(input_dev, abs->code,
+					abs->minimum, abs->maximum, 0, 0);
+	}
+
+	error = input_register_device(input_dev);
+	if (error) {
+		pr_err("%s: input_register_device failed\n", __func__);
+		goto err_input_reg_dev;
+	}
+
+	hbtp->input_dev = input_dev;
+	return 0;
+
+err_input_reg_dev:
+	input_free_device(input_dev);
+
+	return error;
+}
+
+static int hbtp_input_report_events(struct hbtp_data *hbtp_data,
+				struct hbtp_input_mt *mt_data)
+{
+	int i;
+	struct hbtp_input_touch *tch;
+
+	for (i = 0; i < HBTP_MAX_FINGER; i++) {
+		tch = &(mt_data->touches[i]);
+		if (tch->active || hbtp_data->touch_status[i]) {
+			input_mt_slot(hbtp_data->input_dev, i);
+			input_mt_report_slot_state(hbtp_data->input_dev,
+					MT_TOOL_FINGER, tch->active);
+
+			if (tch->active) {
+				input_report_abs(hbtp_data->input_dev,
+						ABS_MT_TOOL_TYPE,
+						tch->tool);
+				input_report_abs(hbtp_data->input_dev,
+						ABS_MT_TOUCH_MAJOR,
+						tch->major);
+				input_report_abs(hbtp_data->input_dev,
+						ABS_MT_TOUCH_MINOR,
+						tch->minor);
+				input_report_abs(hbtp_data->input_dev,
+						ABS_MT_ORIENTATION,
+						tch->orientation);
+				input_report_abs(hbtp_data->input_dev,
+						ABS_MT_PRESSURE,
+						tch->pressure);
+				input_report_abs(hbtp_data->input_dev,
+						ABS_MT_POSITION_X,
+						tch->x);
+				input_report_abs(hbtp_data->input_dev,
+						ABS_MT_POSITION_Y,
+						tch->y);
+			}
+			hbtp_data->touch_status[i] = tch->active;
+		}
+	}
+
+	input_report_key(hbtp->input_dev, BTN_TOUCH, mt_data->num_touches > 0);
+	input_sync(hbtp->input_dev);
+
+	return 0;
+}
+
+static int reg_set_optimum_mode_check(struct regulator *reg, int load_uA)
+{
+	return (regulator_count_voltages(reg) > 0) ?
+		regulator_set_optimum_mode(reg, load_uA) : 0;
+}
+
+static int hbtp_pdev_power_on(struct hbtp_data *hbtp, bool on)
+{
+	int ret, error;
+
+	if (!hbtp->vcc_ana) {
+		pr_err("%s: regulator is not available\n", __func__);
+		return -EINVAL;
+	}
+
+	if (!on)
+		goto reg_off;
+
+	ret = reg_set_optimum_mode_check(hbtp->vcc_ana, HBTP_AFE_LOAD_UA);
+	if (ret < 0) {
+		pr_err("%s: Regulator vcc_ana set_opt failed rc=%d\n",
+			__func__, ret);
+		return -EINVAL;
+	}
+
+	ret = regulator_enable(hbtp->vcc_ana);
+	if (ret) {
+		pr_err("%s: Regulator vcc_ana enable failed rc=%d\n",
+			__func__, ret);
+		error = -EINVAL;
+		goto error_reg_en_vcc_ana;
+	}
+
+	return 0;
+
+error_reg_en_vcc_ana:
+	reg_set_optimum_mode_check(hbtp->vcc_ana, 0);
+	return error;
+
+reg_off:
+	reg_set_optimum_mode_check(hbtp->vcc_ana, 0);
+	regulator_disable(hbtp->vcc_ana);
+	return 0;
+}
+
+static long hbtp_input_ioctl_handler(struct file *file, unsigned int cmd,
+				 unsigned long arg, void __user *p)
+{
+	int error;
+	struct hbtp_input_mt mt_data;
+	struct hbtp_input_absinfo absinfo[ABS_MT_LAST - ABS_MT_FIRST + 1];
+	enum hbtp_afe_power_cmd power_cmd;
+
+	switch (cmd) {
+	case HBTP_SET_ABSPARAM:
+		if (hbtp && hbtp->input_dev) {
+			pr_err("%s: The input device is already created\n",
+				__func__);
+			return 0;
+		}
+
+		if (copy_from_user(absinfo, (void *)arg,
+					sizeof(struct hbtp_input_absinfo) *
+					(ABS_MT_LAST - ABS_MT_FIRST + 1))) {
+			pr_err("%s: Error copying data for ABS param\n",
+				__func__);
+			return -EFAULT;
+		}
+
+		error = hbtp_input_create_input_dev(absinfo);
+		if (error)
+			pr_err("%s, hbtp_input_create_input_dev failed (%d)\n",
+				__func__, error);
+		break;
+
+	case HBTP_SET_TOUCHDATA:
+		if (!hbtp || !hbtp->input_dev) {
+			pr_err("%s: The input device hasn't been created\n",
+				__func__);
+			return -EFAULT;
+		}
+
+		if (copy_from_user(&mt_data, (void *)arg,
+					sizeof(struct hbtp_input_mt))) {
+			pr_err("%s: Error copying data\n", __func__);
+			return -EFAULT;
+		}
+
+		hbtp_input_report_events(hbtp, &mt_data);
+		error = 0;
+		break;
+
+	case HBTP_SET_POWERSTATE:
+		if (!hbtp || !hbtp->input_dev) {
+			pr_err("%s: The input device hasn't been created\n",
+				__func__);
+			return -EFAULT;
+		}
+
+		if (copy_from_user(&power_cmd, (void *)arg,
+					sizeof(enum hbtp_afe_power_cmd))) {
+			pr_err("%s: Error copying data\n", __func__);
+			return -EFAULT;
+		}
+
+		switch (power_cmd) {
+		case HBTP_AFE_POWER_ON:
+			error = hbtp_pdev_power_on(hbtp, true);
+			if (error)
+				pr_err("%s: failed to power on\n", __func__);
+			break;
+		case HBTP_AFE_POWER_OFF:
+			error = hbtp_pdev_power_on(hbtp, false);
+			if (error)
+				pr_err("%s: failed to power off\n", __func__);
+			break;
+		default:
+			pr_err("%s: Unsupported command for power state, %d\n",
+				__func__, power_cmd);
+			return -EINVAL;
+		}
+		break;
+
+	default:
+		pr_err("%s: Unsupported ioctl command %u\n", __func__, cmd);
+		error = -EINVAL;
+		break;
+	}
+
+	return error;
+}
+
+static long hbtp_input_ioctl(struct file *file, unsigned int cmd,
+				unsigned long arg)
+{
+	return hbtp_input_ioctl_handler(file, cmd, arg, (void __user *)arg);
+}
+
+#ifdef CONFIG_COMPAT
+static long hbtp_input_compat_ioctl(struct file *file, unsigned int cmd,
+					unsigned long arg)
+{
+	return hbtp_input_ioctl_handler(file, cmd, arg, compat_ptr(arg));
+}
+#endif
+
+static const struct file_operations hbtp_input_fops = {
+	.owner		= THIS_MODULE,
+	.open		= hbtp_input_open,
+	.release	= hbtp_input_release,
+	.unlocked_ioctl	= hbtp_input_ioctl,
+#ifdef CONFIG_COMPAT
+	.compat_ioctl	= hbtp_input_compat_ioctl,
+#endif
+};
+
+static struct miscdevice hbtp_input_misc = {
+	.fops		= &hbtp_input_fops,
+	.minor		= MISC_DYNAMIC_MINOR,
+	.name		= HBTP_INPUT_NAME,
+};
+MODULE_ALIAS_MISCDEV(MISC_DYNAMIC_MINOR);
+MODULE_ALIAS("devname:" HBTP_INPUT_NAME);
+
+static int __devinit hbtp_pdev_probe(struct platform_device *pdev)
+{
+	int ret, error;
+	struct regulator *vcc_ana;
+
+	vcc_ana = regulator_get(&pdev->dev, "vcc_ana");
+	if (IS_ERR(vcc_ana)) {
+		ret = PTR_ERR(vcc_ana);
+		pr_err("%s: Regulator get failed vcc_ana rc=%d\n",
+			__func__, ret);
+		return -EINVAL;
+	}
+
+	if (regulator_count_voltages(vcc_ana) > 0) {
+		ret = regulator_set_voltage(vcc_ana,
+				HBTP_AFE_VTG_MIN_UV, HBTP_AFE_VTG_MAX_UV);
+		if (ret) {
+			pr_err("%s: regulator set_vtg failed rc=%d\n",
+				__func__, ret);
+			error = -EINVAL;
+			goto error_set_vtg_vcc_ana;
+		}
+	}
+
+	hbtp->vcc_ana = vcc_ana;
+	hbtp->pdev = pdev;
+	return 0;
+
+error_set_vtg_vcc_ana:
+	regulator_put(vcc_ana);
+
+	return error;
+};
+
+static int __devexit hbtp_pdev_remove(struct platform_device *pdev)
+{
+	if (hbtp->vcc_ana) {
+		hbtp_pdev_power_on(hbtp, false);
+		regulator_put(hbtp->vcc_ana);
+	}
+
+	return 0;
+}
+
+#ifdef CONFIG_OF
+static struct of_device_id hbtp_match_table[] = {
+	{ .compatible = "qcom,hbtp",},
+	{ },
+};
+#else
+#define hbtp_match_table NULL
+#endif
+
+static struct platform_driver hbtp_pdev_driver = {
+	.probe		= hbtp_pdev_probe,
+	.remove		= __devexit_p(hbtp_pdev_remove),
+	.driver		= {
+		.name		= "hbtp",
+		.owner		= THIS_MODULE,
+		.of_match_table = hbtp_match_table,
+	},
+};
+
+static int __init hbtp_init(void)
+{
+	int error;
+
+	hbtp = kzalloc(sizeof(struct hbtp_data), GFP_KERNEL);
+	if (!hbtp)
+		return -ENOMEM;
+
+	error = misc_register(&hbtp_input_misc);
+	if (error) {
+		pr_err("%s: misc_register failed\n", HBTP_INPUT_NAME);
+		goto err_misc_reg;
+	}
+
+#if defined(CONFIG_FB)
+	hbtp->fb_notif.notifier_call = fb_notifier_callback;
+	error = fb_register_client(&hbtp->fb_notif);
+	if (error) {
+		pr_err("%s: Unable to register fb_notifier: %d\n",
+			HBTP_INPUT_NAME, error);
+		goto err_fb_reg;
+	}
+#endif
+
+	error = platform_driver_register(&hbtp_pdev_driver);
+	if (error) {
+		pr_err("Failed to register platform driver: %d\n", error);
+		goto err_platform_drv_reg;
+	}
+
+	return 0;
+
+err_platform_drv_reg:
+#if defined(CONFIG_FB)
+	fb_unregister_client(&hbtp->fb_notif);
+err_fb_reg:
+#endif
+	misc_deregister(&hbtp_input_misc);
+err_misc_reg:
+	kfree(hbtp);
+
+	return error;
+}
+
+static void __exit hbtp_exit(void)
+{
+	misc_deregister(&hbtp_input_misc);
+	if (hbtp->input_dev)
+		input_unregister_device(hbtp->input_dev);
+
+#if defined(CONFIG_FB)
+	fb_unregister_client(&hbtp->fb_notif);
+#endif
+
+	platform_driver_unregister(&hbtp_pdev_driver);
+
+	kfree(hbtp);
+}
+
+MODULE_DESCRIPTION("Kernel driver to support host based touch processing");
+MODULE_LICENSE("GPLv2");
+
+module_init(hbtp_init);
+module_exit(hbtp_exit);
diff --git a/drivers/input/misc/kxtj9.c b/drivers/input/misc/kxtj9.c
index f5d8441..0883ac5 100644
--- a/drivers/input/misc/kxtj9.c
+++ b/drivers/input/misc/kxtj9.c
@@ -90,9 +90,13 @@
 	.max_range = "19.6",
 	.resolution = "0.01",
 	.sensor_power = "0.2",
-	.min_delay = 2000,
+	.min_delay = 2000,	/* microsecond */
 	.fifo_reserved_event_count = 0,
 	.fifo_max_event_count = 0,
+	.enabled = 0,
+	.delay_msec = 200,	/* millisecond */
+	.sensors_enable = NULL,
+	.sensors_poll_delay = NULL,
 };
 
 static const struct {
@@ -124,6 +128,7 @@
 	bool	power_enabled;
 	struct regulator *vdd;
 	struct regulator *vio;
+	struct sensors_classdev cdev;
 };
 
 static int kxtj9_i2c_read(struct kxtj9_data *tj9, u8 addr, u8 *data, int len)
@@ -486,6 +491,36 @@
 	return 0;
 }
 
+static int kxtj9_enable_set(struct sensors_classdev *sensors_cdev,
+					unsigned int enabled)
+{
+	struct kxtj9_data *tj9 = container_of(sensors_cdev,
+					struct kxtj9_data, cdev);
+	struct input_dev *input_dev = tj9->input_dev;
+
+	mutex_lock(&input_dev->mutex);
+
+	if (enabled == 0) {
+		disable_irq(tj9->client->irq);
+		kxtj9_disable(tj9);
+		tj9->enable = false;
+	} else if (enabled == 1) {
+		if (!kxtj9_enable(tj9)) {
+			enable_irq(tj9->client->irq);
+			tj9->enable = true;
+		}
+	} else {
+		dev_err(&tj9->client->dev,
+			"Invalid value of input, input=%d\n", enabled);
+		mutex_unlock(&input_dev->mutex);
+		return -EINVAL;
+	}
+
+	mutex_unlock(&input_dev->mutex);
+
+	return 0;
+}
+
 static ssize_t kxtj9_enable_show(struct device *dev,
 				struct device_attribute *attr, char *buf)
 {
@@ -501,31 +536,16 @@
 {
 	struct i2c_client *client = to_i2c_client(dev);
 	struct kxtj9_data *tj9 = i2c_get_clientdata(client);
-	struct input_dev *input_dev = tj9->input_dev;
 	unsigned long data;
 	int error;
 
 	error = kstrtoul(buf, 10, &data);
-	if (error)
+	if (error < 0)
 		return error;
-	mutex_lock(&input_dev->mutex);
 
-	if (data == 0) {
-		disable_irq(client->irq);
-		kxtj9_disable(tj9);
-		tj9->enable = false;
-	} else if (data == 1) {
-		if (!kxtj9_enable(tj9)) {
-			enable_irq(client->irq);
-			tj9->enable = true;
-		}
-	} else {
-		dev_err(&tj9->client->dev,
-			"Invalid value of input, input=%ld\n", data);
-	}
-
-	mutex_unlock(&input_dev->mutex);
-
+	error = kxtj9_enable_set(&tj9->cdev, data);
+	if (error < 0)
+		return error;
 	return count;
 }
 
@@ -542,6 +562,29 @@
  * will be responsible for retrieving data from the input node at the desired
  * interval.
  */
+static int kxtj9_poll_delay_set(struct sensors_classdev *sensors_cdev,
+					unsigned int delay_msec)
+{
+	struct kxtj9_data *tj9 = container_of(sensors_cdev,
+					struct kxtj9_data, cdev);
+	struct input_dev *input_dev = tj9->input_dev;
+
+	/* Lock the device to prevent races with open/close (and itself) */
+	mutex_lock(&input_dev->mutex);
+
+	if (tj9->enable)
+		disable_irq(tj9->client->irq);
+
+	tj9->last_poll_interval = max(delay_msec, tj9->pdata.min_interval);
+
+	if (tj9->enable) {
+		kxtj9_update_odr(tj9, tj9->last_poll_interval);
+		enable_irq(tj9->client->irq);
+	}
+	mutex_unlock(&input_dev->mutex);
+
+	return 0;
+}
 
 /* Returns currently selected poll interval (in ms) */
 static ssize_t kxtj9_get_poll_delay(struct device *dev,
@@ -560,7 +603,6 @@
 {
 	struct i2c_client *client = to_i2c_client(dev);
 	struct kxtj9_data *tj9 = i2c_get_clientdata(client);
-	struct input_dev *input_dev = tj9->input_dev;
 	unsigned int interval;
 	int error;
 
@@ -568,24 +610,9 @@
 	if (error < 0)
 		return error;
 
-	/* Lock the device to prevent races with open/close (and itself) */
-	mutex_lock(&input_dev->mutex);
-
-	if (tj9->enable)
-		disable_irq(client->irq);
-
-	/*
-	 * Set current interval to the greater of the minimum interval or
-	 * the requested interval
-	 */
-	tj9->last_poll_interval = max(interval, tj9->pdata.min_interval);
-
-	if (tj9->enable) {
-		kxtj9_update_odr(tj9, tj9->last_poll_interval);
-		enable_irq(client->irq);
-	}
-	mutex_unlock(&input_dev->mutex);
-
+	error = kxtj9_poll_delay_set(&tj9->cdev, interval);
+	if (error < 0)
+		return error;
 	return count;
 }
 
@@ -602,7 +629,6 @@
 	.attrs = kxtj9_attributes
 };
 
-
 #ifdef CONFIG_INPUT_KXTJ9_POLLED_MODE
 static void kxtj9_poll(struct input_polled_dev *dev)
 {
@@ -858,7 +884,13 @@
 	tj9->ctrl_reg1 = tj9->pdata.res_ctl | tj9->pdata.g_range;
 	tj9->last_poll_interval = tj9->pdata.init_interval;
 
-	err = sensors_classdev_register(&client->dev, &sensors_cdev);
+	tj9->cdev = sensors_cdev;
+	/* The min_delay is used by userspace and the unit is microsecond. */
+	tj9->cdev.min_delay = tj9->pdata.min_interval * 1000;
+	tj9->cdev.delay_msec = tj9->pdata.init_interval;
+	tj9->cdev.sensors_enable = kxtj9_enable_set;
+	tj9->cdev.sensors_poll_delay = kxtj9_poll_delay_set;
+	err = sensors_classdev_register(&client->dev, &tj9->cdev);
 	if (err) {
 		dev_err(&client->dev, "class device create failed: %d\n", err);
 		goto err_power_off;
@@ -871,7 +903,7 @@
 
 		err = kxtj9_setup_input_device(tj9);
 		if (err)
-			goto err_power_off;
+			goto err_class_sysfs;
 
 		err = request_threaded_irq(client->irq, NULL, kxtj9_isr,
 					   IRQF_TRIGGER_RISING | IRQF_ONESHOT,
@@ -892,7 +924,7 @@
 	} else {
 		err = kxtj9_setup_polled_device(tj9);
 		if (err)
-			goto err_power_off;
+			goto err_class_sysfs;
 	}
 
 	dev_dbg(&client->dev, "%s: kxtj9_probe OK.\n", __func__);
@@ -903,6 +935,8 @@
 	free_irq(client->irq, tj9);
 err_destroy_input:
 	input_unregister_device(tj9->input_dev);
+err_class_sysfs:
+	sensors_classdev_unregister(&tj9->cdev);
 err_power_off:
 	kxtj9_device_power_off(tj9);
 err_power_deinit:
diff --git a/drivers/input/misc/mma8x5x.c b/drivers/input/misc/mma8x5x.c
index d5053eb..85b4317 100644
--- a/drivers/input/misc/mma8x5x.c
+++ b/drivers/input/misc/mma8x5x.c
@@ -2,7 +2,7 @@
  *  mma8x5x.c - Linux kernel modules for 3-Axis Orientation/Motion
  *  Detection Sensor MMA8451/MMA8452/MMA8453
  *
- *  Copyright (c) 2013, The Linux Foundation. All Rights Reserved.
+ *  Copyright (c) 2013-2014, The Linux Foundation. All Rights Reserved.
  *  Linux Foundation chooses to take subject only to the GPLv2 license
  *  terms, and distributes only under these terms.
  *  Copyright (C) 2010-2011 Freescale Semiconductor, Inc. All Rights Reserved.
@@ -26,10 +26,11 @@
 #include <linux/slab.h>
 #include <linux/delay.h>
 #include <linux/i2c.h>
-#include <linux/input-polldev.h>
 #include <linux/sensors.h>
+#include <linux/input.h>
 #include <linux/regulator/consumer.h>
 #include <linux/of_gpio.h>
+#include <linux/irq.h>
 
 #define ACCEL_INPUT_DEV_NAME		"accelerometer"
 #define MMA8451_ID			0x1A
@@ -38,13 +39,11 @@
 #define MMA8652_ID			0x4A
 #define MMA8653_ID			0x5A
 
-
+/* Polling delay in msecs */
 #define POLL_INTERVAL_MIN	1
-#define POLL_INTERVAL_MAX	500
+#define POLL_INTERVAL_MAX	10000
 #define POLL_INTERVAL		100 /* msecs */
 
-/* if sensor is standby ,set POLL_STOP_TIME to slow down the poll */
-#define POLL_STOP_TIME		10000
 #define INPUT_FUZZ			32
 #define INPUT_FLAT			32
 #define INPUT_DATA_DIVIDER	16
@@ -68,8 +67,20 @@
 	.min_delay = 2000,
 	.fifo_reserved_event_count = 0,
 	.fifo_max_event_count = 0,
+	.enabled = 0,
+	.delay_msec = POLL_INTERVAL,
+	.sensors_enable = NULL,
+	.sensors_poll_delay = NULL,
 };
 
+#define MMA_WAKE_CFG		0x02
+#define MMA_INT_EN_DRDY		0x01
+#define MMA_INT_EN_FF_MT	0x04
+#define MMA_INT_ROUTING_CFG	0x01
+
+#define MMA_POWER_CFG_MASK	0xFE
+#define MMA_ODR_MASK		0x38
+
 struct sensor_regulator {
 	struct regulator *vreg;
 	const char *name;
@@ -82,6 +93,23 @@
 	{NULL, "vio", 1800000, 1800000},
 };
 
+struct mma_odr_selection_table {
+	u32 odr_cfg;
+	u32 delay_bottom;
+	u32 delay_top;
+};
+
+static struct mma_odr_selection_table mma_odr_table[] = {
+	{0x00, 0, 1500},
+	{0x08, 1501, 3500},
+	{0x10, 3501, 7500},
+	{0x18, 7501, 15000},
+	{0x20, 15001, 50000},
+	{0x28, 50001, 120000},
+	{0x30, 120001, 400000},
+	{0x38, 400001, 10000000},
+};
+
 /* register enum for mma8x5x registers */
 enum {
 	MMA8X5X_STATUS = 0x00,
@@ -160,14 +188,18 @@
 };
 struct mma8x5x_data {
 	struct i2c_client *client;
-	struct input_polled_dev *poll_dev;
+	struct delayed_work dwork;
+	struct input_dev *idev;
 	struct mutex data_lock;
+	struct sensors_classdev cdev;
 	int active;
 	int position;
 	u8 chip_id;
 	int mode;
 	int int_pin;
 	u32 int_flags;
+	int poll_delay;
+	bool use_int;
 };
 /* Addresses scanned */
 static const unsigned short normal_i2c[] = {0x1c, 0x1d, I2C_CLIENT_END};
@@ -196,7 +228,6 @@
 	{{ 0,  1,  0}, { 1,  0,	0}, {0, 0,  -1} },
 	{{ 1,  0,  0}, { 0, -1,	0}, {0, 0,  -1} },
 };
-
 static int mma8x5x_config_regulator(struct i2c_client *client, bool on)
 {
 	int rc = 0, i;
@@ -342,6 +373,103 @@
 	return -EIO;
 }
 
+static int mma8x5x_delay2odr(u32 delay_ms)
+{
+	int i;
+	u32 delay_us;
+
+	delay_us = delay_ms * 1000;
+	for (i = 0; i < sizeof(mma_odr_table) /
+		sizeof(struct mma_odr_selection_table); i++) {
+		if ((delay_us <= mma_odr_table[i].delay_top) &&
+			(delay_us > mma_odr_table[i].delay_bottom))
+			break;
+	}
+	if (i < sizeof(mma_odr_table) /
+		sizeof(struct mma_odr_selection_table))
+		return mma_odr_table[i].odr_cfg;
+	else
+		return -EINVAL;
+}
+
+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;
+	val = (u8)result;
+
+	result = i2c_smbus_read_byte_data(client, MMA8X5X_CTRL_REG1);
+	if (result < 0)
+		goto out;
+
+	val = ((u8)result & ~MMA_ODR_MASK) | val;
+	result = i2c_smbus_write_byte_data(client, MMA8X5X_CTRL_REG1,
+					   (val & MMA_POWER_CFG_MASK));
+	if (result < 0)
+		goto out;
+
+	result = i2c_smbus_write_byte_data(client, MMA8X5X_CTRL_REG4,
+					   MMA_INT_EN_DRDY);
+	if (result < 0)
+		goto out;
+
+	result = i2c_smbus_write_byte_data(client, MMA8X5X_CTRL_REG5,
+					   MMA_INT_ROUTING_CFG);
+	if (result < 0)
+		goto out;
+
+	result = i2c_smbus_write_byte_data(client, MMA8X5X_CTRL_REG1,
+					   val);
+	if (result < 0)
+		goto out;
+
+	return 0;
+out:
+	dev_err(&client->dev, "error when set ODR mma8x5x:(%d)", result);
+	return result;
+}
+static int mma8x5x_device_int_init(struct i2c_client *client)
+{
+	struct mma8x5x_data *pdata = i2c_get_clientdata(client);
+	int result;
+	int val;
+
+	result = mma8x5x_device_set_odr(client, pdata->poll_delay);
+	if (result < 0)
+		goto out;
+
+	val = MMA_WAKE_CFG;
+	result = i2c_smbus_write_byte_data(client, MMA8X5X_CTRL_REG3,
+					   val);
+	if (result < 0)
+		goto out;
+
+	val = MMA_INT_EN_DRDY;
+	result = i2c_smbus_write_byte_data(client, MMA8X5X_CTRL_REG4,
+					   val);
+	if (result < 0)
+		goto out;
+
+	val = MMA_INT_ROUTING_CFG;
+	result = i2c_smbus_write_byte_data(client, MMA8X5X_CTRL_REG5,
+					   val);
+	if (result < 0)
+		goto out;
+
+	return 0;
+out:
+	dev_err(&client->dev, "error when int init mma8x5x:(%d)", result);
+	return result;
+}
 static int mma8x5x_read_data(struct i2c_client *client,
 		struct mma8x5x_data_axis *data)
 {
@@ -349,7 +477,7 @@
 	int ret;
 
 	ret = i2c_smbus_read_i2c_block_data(client,
-					    MMA8X5X_OUT_X_MSB, 7, tmp_data);
+					MMA8X5X_OUT_X_MSB, 7, tmp_data);
 	if (ret < MMA8X5X_BUF_SIZE) {
 		dev_err(&client->dev, "i2c block read failed\n");
 		return -EIO;
@@ -362,43 +490,151 @@
 
 static void mma8x5x_report_data(struct mma8x5x_data *pdata)
 {
-	struct input_polled_dev *poll_dev = pdata->poll_dev;
 	struct mma8x5x_data_axis data;
+
 	mutex_lock(&pdata->data_lock);
-	if ((pdata->active & MMA_STATE_MASK) == MMA_STANDBY) {
-		poll_dev->poll_interval = POLL_STOP_TIME;
-		/* if standby ,set as 10s to slow the poll. */
-		goto out;
-	} else {
-		if (poll_dev->poll_interval == POLL_STOP_TIME)
-			poll_dev->poll_interval = POLL_INTERVAL;
-	}
 	if (mma8x5x_read_data(pdata->client, &data) != 0)
 		goto out;
 	mma8x5x_data_convert(pdata, &data);
-	input_report_abs(poll_dev->input, ABS_X, data.x);
-	input_report_abs(poll_dev->input, ABS_Y, data.y);
-	input_report_abs(poll_dev->input, ABS_Z, data.z);
-	input_sync(poll_dev->input);
+	input_report_abs(pdata->idev, ABS_X, data.x);
+	input_report_abs(pdata->idev, ABS_Y, data.y);
+	input_report_abs(pdata->idev, ABS_Z, data.z);
+	input_sync(pdata->idev);
 out:
 	mutex_unlock(&pdata->data_lock);
 }
 
-static void mma8x5x_dev_poll(struct input_polled_dev *dev)
+static void mma8x5x_dev_poll(struct work_struct *work)
 {
-	struct mma8x5x_data *pdata = (struct mma8x5x_data *)dev->private;
-	mma8x5x_report_data(pdata);
+	struct mma8x5x_data *pdata = container_of((struct delayed_work *)work,
+				struct mma8x5x_data, dwork);
+
+	if ((pdata->active & MMA_STATE_MASK) == MMA_ACTIVED) {
+		mma8x5x_report_data(pdata);
+		schedule_delayed_work(&pdata->dwork,
+					msecs_to_jiffies(pdata->poll_delay));
+	}
+}
+
+static irqreturn_t mma8x5x_interrupt(int vec, void *data)
+{
+	struct i2c_client *client = (struct i2c_client *)data;
+	struct mma8x5x_data *pdata = i2c_get_clientdata(client);
+	struct input_dev *idev = pdata->idev;
+	struct mma8x5x_data_axis data_axis;
+
+	mutex_lock(&pdata->data_lock);
+
+	if (mma8x5x_read_data(pdata->client, &data_axis) != 0)
+		goto out;
+	mma8x5x_data_convert(pdata, &data_axis);
+	input_report_abs(idev, ABS_X, data_axis.x);
+	input_report_abs(idev, ABS_Y, data_axis.y);
+	input_report_abs(idev, ABS_Z, data_axis.z);
+	input_sync(idev);
+out:
+	mutex_unlock(&pdata->data_lock);
+
+	return IRQ_HANDLED;
+}
+
+static int mma8x5x_enable_set(struct sensors_classdev *sensors_cdev,
+		unsigned int enable)
+{
+	struct mma8x5x_data *pdata = container_of(sensors_cdev,
+			struct mma8x5x_data, cdev);
+	struct i2c_client *client = pdata->client;
+	int ret;
+	u8 val = 0;
+
+	mutex_lock(&pdata->data_lock);
+	if (enable) {
+		if (pdata->active & MMA_SHUTTEDDOWN) {
+			ret = mma8x5x_config_regulator(client, 1);
+			if (ret)
+				goto err_failed;
+
+			ret = mma8x5x_device_start(client);
+			if (ret)
+				goto err_failed;
+
+			ret = mma8x5x_device_set_odr(client, pdata->poll_delay);
+			if (ret)
+				goto err_failed;
+			pdata->active &= ~MMA_SHUTTEDDOWN;
+		}
+		if (pdata->active == MMA_STANDBY) {
+			val = i2c_smbus_read_byte_data(client,
+					MMA8X5X_CTRL_REG1);
+			if (val < 0) {
+				dev_err(&client->dev, "read device state failed!");
+				ret = val;
+				goto err_failed;
+			}
+
+			ret = i2c_smbus_write_byte_data(client,
+					MMA8X5X_CTRL_REG1, val | 0x01);
+			if (ret) {
+				dev_err(&client->dev, "change device state failed!");
+				goto err_failed;
+			}
+			if (!pdata->use_int)
+				schedule_delayed_work(&pdata->dwork,
+					msecs_to_jiffies(pdata->poll_delay));
+
+			pdata->active = MMA_ACTIVED;
+			dev_dbg(&client->dev, "%s:mma enable setting active.\n",
+					__func__);
+		}
+	} else if (enable == 0) {
+		if (pdata->active == MMA_ACTIVED) {
+			val = i2c_smbus_read_byte_data(client,
+					MMA8X5X_CTRL_REG1);
+			if (val < 0) {
+				dev_err(&client->dev, "read device state failed!");
+				ret = val;
+				goto err_failed;
+			}
+
+			ret = i2c_smbus_write_byte_data(client,
+				MMA8X5X_CTRL_REG1, val & 0xFE);
+			if (ret) {
+				dev_err(&client->dev, "change device state failed!");
+				goto err_failed;
+			}
+			/*
+			 * Set standby state,
+			 * polling work queue will stop after next call.
+			 */
+			pdata->active = MMA_STANDBY;
+			dev_dbg(&client->dev, "%s:mma enable setting inactive.\n",
+					__func__);
+		}
+		if (!mma8x5x_config_regulator(client, 0))
+			pdata->active |= MMA_SHUTTEDDOWN;
+	}
+	mutex_unlock(&pdata->data_lock);
+	return 0;
+
+err_failed:
+	mutex_unlock(&pdata->data_lock);
+	return ret;
 }
 
 static ssize_t mma8x5x_enable_show(struct device *dev,
 				   struct device_attribute *attr, char *buf)
 {
-	struct input_polled_dev *poll_dev = dev_get_drvdata(dev);
-	struct mma8x5x_data *pdata = (struct mma8x5x_data *)(poll_dev->private);
-	struct i2c_client *client = pdata->client;
+	struct mma8x5x_data *pdata = dev_get_drvdata(dev);
+	struct i2c_client *client;
 	u8 val;
 	int enable;
 
+	if (!pdata) {
+		dev_err(dev, "Invalid driver private data!");
+		return -EINVAL;
+	}
+	client = pdata->client;
+
 	mutex_lock(&pdata->data_lock);
 	val = i2c_smbus_read_byte_data(client, MMA8X5X_CTRL_REG1);
 	if ((val & 0x01) && pdata->active == MMA_ACTIVED)
@@ -413,86 +649,35 @@
 				    struct device_attribute *attr,
 				    const char *buf, size_t count)
 {
-	struct input_polled_dev *poll_dev = dev_get_drvdata(dev);
-	struct mma8x5x_data *pdata = (struct mma8x5x_data *)(poll_dev->private);
-	struct i2c_client *client = pdata->client;
+	struct mma8x5x_data *pdata = dev_get_drvdata(dev);
+	struct i2c_client *client;
 	int ret;
 	unsigned long enable;
-	u8 val = 0;
 
+	if (!pdata) {
+		dev_err(dev, "Invalid driver private data!");
+		return -EINVAL;
+	}
+	client = pdata->client;
 	ret = kstrtoul(buf, 10, &enable);
 	if (ret)
 		return ret;
-	mutex_lock(&pdata->data_lock);
 	enable = (enable > 0) ? 1 : 0;
-	if (enable) {
-		if (pdata->active & MMA_SHUTTEDDOWN) {
-			ret = mma8x5x_config_regulator(client, 1);
-			if (ret)
-				goto err_failed;
-
-			ret = mma8x5x_device_start(client);
-			if (ret)
-				goto err_failed;
-
-			pdata->active &= ~MMA_SHUTTEDDOWN;
-		}
-		if (pdata->active == MMA_STANDBY) {
-			val = i2c_smbus_read_byte_data(client,
-					MMA8X5X_CTRL_REG1);
-			if (val < 0) {
-				dev_err(dev, "read device state failed!");
-				ret = val;
-				goto err_failed;
-			}
-
-			ret = i2c_smbus_write_byte_data(client,
-					MMA8X5X_CTRL_REG1, val | 0x01);
-			if (ret) {
-				dev_err(dev, "change device state failed!");
-				goto err_failed;
-			}
-			pdata->active = MMA_ACTIVED;
-			dev_dbg(dev, "%s:mma enable setting active.\n",
-					__func__);
-		}
-	} else if (enable == 0) {
-		if (pdata->active == MMA_ACTIVED) {
-			val = i2c_smbus_read_byte_data(client,
-					MMA8X5X_CTRL_REG1);
-			if (val < 0) {
-				dev_err(dev, "read device state failed!");
-				ret = val;
-				goto err_failed;
-			}
-
-			ret = i2c_smbus_write_byte_data(client,
-				MMA8X5X_CTRL_REG1, val & 0xFE);
-			if (ret) {
-				dev_err(dev, "change device state failed!");
-				goto err_failed;
-			}
-
-			pdata->active = MMA_STANDBY;
-			dev_dbg(dev, "%s:mma enable setting inactive.\n",
-					__func__);
-		}
-		if (!mma8x5x_config_regulator(client, 0))
-			pdata->active |= MMA_SHUTTEDDOWN;
-	}
-	mutex_unlock(&pdata->data_lock);
+	ret = mma8x5x_enable_set(&pdata->cdev, enable);
+	if (ret < 0)
+		return ret;
 	return count;
-
-err_failed:
-	mutex_unlock(&pdata->data_lock);
-	return ret;
 }
 static ssize_t mma8x5x_position_show(struct device *dev,
 				   struct device_attribute *attr, char *buf)
 {
-	struct input_polled_dev *poll_dev = dev_get_drvdata(dev);
-	struct mma8x5x_data *pdata = (struct mma8x5x_data *)(poll_dev->private);
+	struct mma8x5x_data *pdata = dev_get_drvdata(dev);
 	int position = 0;
+
+	if (!pdata) {
+		dev_err(dev, "Invalid driver private data!");
+		return -EINVAL;
+	}
 	mutex_lock(&pdata->data_lock);
 	position = pdata->position ;
 	mutex_unlock(&pdata->data_lock);
@@ -503,10 +688,14 @@
 				    struct device_attribute *attr,
 				    const char *buf, size_t count)
 {
-	struct input_polled_dev *poll_dev = dev_get_drvdata(dev);
-	struct mma8x5x_data *pdata = (struct mma8x5x_data *)(poll_dev->private);
+	struct mma8x5x_data *pdata = dev_get_drvdata(dev);
 	int position;
 	int ret;
+
+	if (!pdata) {
+		dev_err(dev, "Invalid driver private data!");
+		return -EINVAL;
+	}
 	ret = kstrtoint(buf, 10, &position);
 	if (ret)
 		return ret;
@@ -516,14 +705,78 @@
 	return count;
 }
 
+static int mma8x5x_poll_delay_set(struct sensors_classdev *sensors_cdev,
+		unsigned int delay_ms)
+{
+	struct mma8x5x_data *pdata = container_of(sensors_cdev,
+			struct mma8x5x_data, cdev);
+	int ret;
+
+	if (pdata->use_int) {
+		mutex_lock(&pdata->data_lock);
+		pdata->poll_delay = delay_ms;
+		ret = mma8x5x_device_set_odr(pdata->client, delay_ms);
+		mutex_unlock(&pdata->data_lock);
+		if (ret < 0)
+			return ret;
+	} else {
+		mutex_lock(&pdata->data_lock);
+		pdata->poll_delay = delay_ms;
+		mutex_unlock(&pdata->data_lock);
+	}
+
+	return 0;
+}
+
+static ssize_t mma8x5x_poll_delay_show(struct device *dev,
+				   struct device_attribute *attr, char *buf)
+{
+	struct mma8x5x_data *pdata = dev_get_drvdata(dev);
+
+	if (!pdata) {
+		dev_err(dev, "Invalid driver private data!");
+		return -EINVAL;
+	}
+
+	return snprintf(buf, PAGE_SIZE, "%d\n", pdata->poll_delay);
+}
+
+static ssize_t mma8x5x_poll_delay_store(struct device *dev,
+				    struct device_attribute *attr,
+				    const char *buf, size_t count)
+{
+	struct mma8x5x_data *pdata = dev_get_drvdata(dev);
+	int delay;
+	int ret;
+
+	if (!pdata) {
+		dev_err(dev, "Invalid driver private data!");
+		return -EINVAL;
+	}
+	ret = kstrtoint(buf, 10, &delay);
+	if (ret)
+		return ret;
+	if (delay <= POLL_INTERVAL_MIN)
+		delay = POLL_INTERVAL_MIN;
+	if (delay > POLL_INTERVAL_MAX)
+		delay = POLL_INTERVAL_MAX;
+
+	mma8x5x_poll_delay_set(&pdata->cdev, delay);
+
+	return count;
+}
+
 static DEVICE_ATTR(enable, S_IWUSR | S_IRUGO,
 		   mma8x5x_enable_show, mma8x5x_enable_store);
 static DEVICE_ATTR(position, S_IWUSR | S_IRUGO,
 		   mma8x5x_position_show, mma8x5x_position_store);
+static DEVICE_ATTR(poll_delay, S_IWUSR | S_IRUGO,
+		   mma8x5x_poll_delay_show, mma8x5x_poll_delay_store);
 
 static struct attribute *mma8x5x_attributes[] = {
 	&dev_attr_enable.attr,
 	&dev_attr_position.attr,
+	&dev_attr_poll_delay.attr,
 	NULL
 };
 
@@ -567,6 +820,8 @@
 		return rc;
 	}
 
+	data->use_int = of_property_read_bool(np, "fsl,use-interrupt");
+
 	return 0;
 }
 
@@ -577,7 +832,6 @@
 	struct input_dev *idev;
 	struct mma8x5x_data *pdata;
 	struct i2c_adapter *adapter;
-	struct input_polled_dev *poll_dev;
 	adapter = to_i2c_adapter(client->dev.parent);
 	/* power on the device */
 	result = mma8x5x_config_regulator(client, 1);
@@ -588,7 +842,7 @@
 					 I2C_FUNC_SMBUS_BYTE |
 					 I2C_FUNC_SMBUS_BYTE_DATA);
 	if (!result)
-		goto err_out;
+		goto err_check_id;
 
 	chip_id = i2c_smbus_read_byte_data(client, MMA8X5X_WHO_AM_I);
 
@@ -598,20 +852,20 @@
 			chip_id, MMA8451_ID, MMA8452_ID, MMA8453_ID,
 			MMA8652_ID, MMA8653_ID);
 		result = -EINVAL;
-		goto err_out;
+		goto err_check_id;
 	}
 	/* set the private data */
 	pdata = kzalloc(sizeof(struct mma8x5x_data), GFP_KERNEL);
 	if (!pdata) {
 		result = -ENOMEM;
 		dev_err(&client->dev, "alloc data memory error!\n");
-		goto err_out;
+		goto err_check_id;
 	}
 
 	if (client->dev.of_node) {
 		result = mma8x5x_parse_dt(&client->dev, pdata);
 		if (result)
-			return result;
+			goto err_parse_dt;
 	} else {
 		pdata->position = CONFIG_SENSORS_MMA_POSITION;
 		pdata->int_pin = -1;
@@ -622,24 +876,53 @@
 	pdata->client = client;
 	pdata->chip_id = chip_id;
 	pdata->mode = MODE_2G;
+	pdata->poll_delay = POLL_INTERVAL;
 
 	mutex_init(&pdata->data_lock);
 	i2c_set_clientdata(client, pdata);
 	/* Initialize the MMA8X5X chip */
 	mma8x5x_device_init(client);
-	/* create the input poll device */
-	poll_dev = input_allocate_polled_device();
-	if (!poll_dev) {
+	if (pdata->use_int) {
+		if (pdata->int_pin >= 0)
+			client->irq = gpio_to_irq(pdata->int_pin);
+
+		if (gpio_is_valid(pdata->int_pin)) {
+			result = gpio_request(pdata->int_pin,
+				"mma8x5x_irq_gpio");
+			if (result) {
+				dev_err(&client->dev, "irq gpio(%d) request failed",
+					pdata->int_pin);
+				goto err_request_gpio;
+			}
+			result = gpio_direction_input(pdata->int_pin);
+			if (result) {
+				dev_err(&client->dev,
+					"set_direction for irq gpio failed\n");
+				goto err_set_gpio_direction;
+			}
+		}
+		device_init_wakeup(&client->dev, true);
+		enable_irq_wake(client->irq);
+		result = request_threaded_irq(client->irq, NULL,
+			mma8x5x_interrupt,
+			IRQ_TYPE_EDGE_RISING | IRQF_ONESHOT | IRQF_NO_SUSPEND,
+			ACCEL_INPUT_DEV_NAME, (void *)client);
+		if (result) {
+			dev_err(&client->dev, "Could not allocate irq(%d) !\n",
+				client->irq);
+			goto err_register_irq;
+		}
+		mma8x5x_device_int_init(client);
+	} else {
+		INIT_DELAYED_WORK(&pdata->dwork, mma8x5x_dev_poll);
+	}
+	idev = input_allocate_device();
+	if (!idev) {
 		result = -ENOMEM;
-		dev_err(&client->dev, "alloc poll device failed!\n");
+		dev_err(&client->dev, "alloc input device failed!\n");
 		goto err_alloc_poll_device;
 	}
-	poll_dev->poll = mma8x5x_dev_poll;
-	poll_dev->poll_interval = POLL_STOP_TIME;
-	poll_dev->poll_interval_min = POLL_INTERVAL_MIN;
-	poll_dev->poll_interval_max = POLL_INTERVAL_MAX;
-	poll_dev->private = pdata;
-	idev = poll_dev->input;
+	input_set_drvdata(idev, pdata);
 	idev->name = ACCEL_INPUT_DEV_NAME;
 	idev->uniq = mma8x5x_id2name(pdata->chip_id);
 	idev->id.bustype = BUS_I2C;
@@ -647,19 +930,25 @@
 	input_set_abs_params(idev, ABS_X, -0x7fff, 0x7fff, 0, 0);
 	input_set_abs_params(idev, ABS_Y, -0x7fff, 0x7fff, 0, 0);
 	input_set_abs_params(idev, ABS_Z, -0x7fff, 0x7fff, 0, 0);
-	pdata->poll_dev = poll_dev;
-	result = input_register_polled_device(pdata->poll_dev);
+	result = input_register_device(idev);
 	if (result) {
-		dev_err(&client->dev, "register poll device failed!\n");
-		goto err_register_polled_device;
+		dev_err(&client->dev, "register input device failed!\n");
+		goto err_register_device;
 	}
+	pdata->idev = idev;
+
 	result = sysfs_create_group(&idev->dev.kobj, &mma8x5x_attr_group);
 	if (result) {
 		dev_err(&client->dev, "create device file failed!\n");
 		result = -EINVAL;
 		goto err_create_sysfs;
 	}
-	result = sensors_classdev_register(&client->dev, &sensors_cdev);
+	pdata->cdev = sensors_cdev;
+	pdata->cdev.min_delay = POLL_INTERVAL_MIN * 1000;
+	pdata->cdev.delay_msec = pdata->poll_delay;
+	pdata->cdev.sensors_enable = mma8x5x_enable_set;
+	pdata->cdev.sensors_poll_delay = mma8x5x_poll_delay_set;
+	result = sensors_classdev_register(&client->dev, &pdata->cdev);
 	if (result) {
 		dev_err(&client->dev, "create class device file failed!\n");
 		result = -EINVAL;
@@ -673,12 +962,20 @@
 err_create_class_sysfs:
 	sysfs_remove_group(&idev->dev.kobj, &mma8x5x_attr_group);
 err_create_sysfs:
-	input_unregister_polled_device(pdata->poll_dev);
-err_register_polled_device:
-	input_free_polled_device(poll_dev);
+	input_unregister_device(idev);
+err_register_device:
+	input_free_device(idev);
 err_alloc_poll_device:
+err_register_irq:
+	if (pdata->use_int)
+		device_init_wakeup(&client->dev, false);
+err_set_gpio_direction:
+	if (gpio_is_valid(pdata->int_pin) && pdata->use_int)
+		gpio_free(pdata->int_pin);
+err_request_gpio:
+err_parse_dt:
 	kfree(pdata);
-err_out:
+err_check_id:
 	mma8x5x_config_regulator(client, 0);
 err_power_on:
 	return result;
@@ -686,14 +983,22 @@
 static int __devexit mma8x5x_remove(struct i2c_client *client)
 {
 	struct mma8x5x_data *pdata = i2c_get_clientdata(client);
-	struct input_polled_dev *poll_dev;
+	struct input_dev *idev;
+
 	mma8x5x_device_stop(client);
 	if (pdata) {
-		poll_dev = pdata->poll_dev;
-		input_unregister_polled_device(poll_dev);
-		input_free_polled_device(poll_dev);
+		idev = pdata->idev;
+		sysfs_remove_group(&idev->dev.kobj, &mma8x5x_attr_group);
+		if (pdata->use_int) {
+			device_init_wakeup(&client->dev, false);
+			if (gpio_is_valid(pdata->int_pin))
+				gpio_free(pdata->int_pin);
+		}
+		input_unregister_device(idev);
+		input_free_device(idev);
 		kfree(pdata);
 	}
+	mma8x5x_config_regulator(client, 0);
 	return 0;
 }
 
@@ -702,8 +1007,13 @@
 {
 	struct i2c_client *client = to_i2c_client(dev);
 	struct mma8x5x_data *pdata = i2c_get_clientdata(client);
-	if (pdata->active == MMA_ACTIVED)
+
+	if (pdata->use_int && pdata->active == MMA_ACTIVED)
+		return 0;
+	if (pdata->active == MMA_ACTIVED) {
 		mma8x5x_device_stop(client);
+		cancel_delayed_work_sync(&pdata->dwork);
+	}
 	if (pdata->active & MMA_SHUTTEDDOWN)
 		return 0;
 	if (!mma8x5x_config_regulator(client, 0))
@@ -718,6 +1028,8 @@
 	struct i2c_client *client = to_i2c_client(dev);
 	struct mma8x5x_data *pdata = i2c_get_clientdata(client);
 
+	if (pdata->use_int && pdata->active == MMA_ACTIVED)
+		return 0;
 	/* No need to power on while device is shutdowned from standby state */
 	if (pdata->active == (MMA_SHUTTEDDOWN | MMA_STANDBY))
 		return 0;
@@ -732,6 +1044,8 @@
 	if (pdata->active == MMA_ACTIVED) {
 		val = i2c_smbus_read_byte_data(client, MMA8X5X_CTRL_REG1);
 		i2c_smbus_write_byte_data(client, MMA8X5X_CTRL_REG1, val|0x01);
+		schedule_delayed_work(&pdata->dwork,
+				msecs_to_jiffies(pdata->poll_delay));
 	}
 
 	return 0;
diff --git a/drivers/input/misc/mpu3050.c b/drivers/input/misc/mpu3050.c
index fab209e..9629aae 100644
--- a/drivers/input/misc/mpu3050.c
+++ b/drivers/input/misc/mpu3050.c
@@ -122,6 +122,7 @@
 	struct input_dev *idev;
 	struct mpu3050_gyro_platform_data *platform_data;
 	struct delayed_work input_work;
+	struct sensors_classdev cdev;
 	u32    use_poll;
 	u32    poll_interval;
 	u32    dlpf_index;
@@ -141,6 +142,10 @@
 	.min_delay = 2000,
 	.fifo_reserved_event_count = 0,
 	.fifo_max_event_count = 0,
+	.enabled = 0,
+	.delay_msec = MPU3050_DEFAULT_POLL_INTERVAL,
+	.sensors_enable = NULL,
+	.sensors_poll_delay = NULL,
 };
 
 struct sensor_regulator {
@@ -258,6 +263,40 @@
 	return rc;
 }
 
+static int mpu3050_poll_delay_set(struct sensors_classdev *sensors_cdev,
+		unsigned int delay_msec)
+{
+	struct mpu3050_sensor *sensor = container_of(sensors_cdev,
+			struct mpu3050_sensor, cdev);
+	unsigned int  dlpf_index;
+	u8  divider, reg;
+	int ret;
+
+	dlpf_index = interval_to_dlpf_cfg(delay_msec);
+	divider = delay_msec * dlpf_table[dlpf_index].sample_rate - 1;
+
+	if (sensor->dlpf_index != dlpf_index) {
+		/* Set low pass filter and full scale */
+		reg = dlpf_table[dlpf_index].cfg;
+		reg |= MPU3050_DEFAULT_FS_RANGE << 3;
+		reg |= MPU3050_EXT_SYNC_NONE << 5;
+		ret = i2c_smbus_write_byte_data(sensor->client,
+				MPU3050_DLPF_FS_SYNC, reg);
+		if (!ret)
+			sensor->dlpf_index = dlpf_index;
+	}
+
+	if (sensor->poll_interval != delay_msec) {
+		/* Output frequency divider. The poll interval */
+		ret = i2c_smbus_write_byte_data(sensor->client,
+				MPU3050_SMPLRT_DIV, divider);
+		if (!ret)
+			sensor->poll_interval = delay_msec;
+	}
+
+	return 0;
+}
+
 /**
  *	mpu3050_attr_get_polling_rate	-	get the sampling rate
  */
@@ -280,8 +319,6 @@
 {
 	struct mpu3050_sensor *sensor = dev_get_drvdata(dev);
 	unsigned long interval_ms;
-	unsigned int  dlpf_index;
-	u8  divider, reg;
 	int ret;
 
 	if (kstrtoul(buf, 10, &interval_ms))
@@ -290,29 +327,39 @@
 		(interval_ms > MPU3050_MAX_POLL_INTERVAL))
 		return -EINVAL;
 
-	dlpf_index = interval_to_dlpf_cfg(interval_ms);
-	divider = interval_ms * dlpf_table[dlpf_index].sample_rate - 1;
+	ret = mpu3050_poll_delay_set(&sensor->cdev, interval_ms);
 
-	if (sensor->dlpf_index != dlpf_index) {
-		/* Set low pass filter and full scale */
-		reg = dlpf_table[dlpf_index].cfg;
-		reg |= MPU3050_DEFAULT_FS_RANGE << 3;
-		reg |= MPU3050_EXT_SYNC_NONE << 5;
-		ret = i2c_smbus_write_byte_data(sensor->client,
-				MPU3050_DLPF_FS_SYNC, reg);
-		if (ret == 0)
-			sensor->dlpf_index = dlpf_index;
+	return ret < 0 ? ret : size;
+}
+static int mpu3050_enable_set(struct sensors_classdev *sensors_cdev,
+		unsigned int enabled)
+{
+	struct mpu3050_sensor *sensor = container_of(sensors_cdev,
+			struct mpu3050_sensor, cdev);
+
+
+	if (enabled && (!sensor->enable)) {
+		sensor->enable = enabled;
+		pm_runtime_get_sync(sensor->dev);
+		if (sensor->use_poll)
+			schedule_delayed_work(&sensor->input_work,
+				msecs_to_jiffies(sensor->poll_interval));
+		else
+			enable_irq(sensor->client->irq);
+	} else if (!enabled && sensor->enable) {
+		if (sensor->use_poll)
+			cancel_delayed_work_sync(&sensor->input_work);
+		else
+			disable_irq(sensor->client->irq);
+		pm_runtime_put_sync(sensor->dev);
+		sensor->enable = enabled;
+	} else {
+		dev_warn(&sensor->client->dev,
+				"ignore enable state change from %d to %d\n",
+				sensor->enable, enabled);
 	}
 
-	if (sensor->poll_interval != interval_ms) {
-		/* Output frequency divider. The poll interval */
-		ret = i2c_smbus_write_byte_data(sensor->client,
-				MPU3050_SMPLRT_DIV, divider);
-		if (ret == 0)
-			sensor->poll_interval = interval_ms;
-	}
-
-	return size;
+	return 0;
 }
 
 /**
@@ -325,31 +372,13 @@
 {
 	struct mpu3050_sensor *sensor = dev_get_drvdata(dev);
 	unsigned long val;
-	u32 enable;
+	int err;
 
 	if (kstrtoul(buf, 10, &val))
 		return -EINVAL;
-	enable = (u32)val == 0 ? 0 : 1;
-	if (enable && (!sensor->enable)) {
-		sensor->enable = enable;
-		pm_runtime_get_sync(sensor->dev);
-		if (sensor->use_poll)
-			schedule_delayed_work(&sensor->input_work,
-				msecs_to_jiffies(sensor->poll_interval));
-		else
-			enable_irq(sensor->client->irq);
-	} else if (!enable && sensor->enable) {
-		if (sensor->use_poll)
-			cancel_delayed_work_sync(&sensor->input_work);
-		else
-			disable_irq(sensor->client->irq);
-		pm_runtime_put_sync(sensor->dev);
-		sensor->enable = enable;
-	} else {
-		dev_warn(&sensor->client->dev,
-				"ignore enable state change from %d to %d\n",
-				sensor->enable, enable);
-	}
+	err = mpu3050_enable_set(&sensor->cdev, val);
+	if (err < 0)
+		return err;
 
 	return count;
 }
@@ -679,6 +708,19 @@
 		sensor->enable_gpio = -EINVAL;
 	}
 
+	sensor->cdev = sensors_cdev;
+	sensor->cdev.min_delay = MPU3050_MIN_POLL_INTERVAL * 1000;
+	sensor->cdev.delay_msec = sensor->poll_interval;
+	sensor->cdev.sensors_enable = mpu3050_enable_set;
+	sensor->cdev.sensors_poll_delay = mpu3050_poll_delay_set;
+	ret = sensors_classdev_register(&client->dev, &sensor->cdev);
+
+	if (ret) {
+		dev_err(&client->dev, "class device create failed: %d\n", ret);
+		error = -EINVAL;
+		goto err_free_mem;
+	}
+
 	if (gpio_is_valid(sensor->enable_gpio)) {
 		ret = gpio_request(sensor->enable_gpio, "GYRO_EN_PM");
 		gpio_direction_output(sensor->enable_gpio, 1);
@@ -690,7 +732,7 @@
 	if (ret < 0) {
 		dev_err(&client->dev, "failed to detect device\n");
 		error = -ENXIO;
-		goto err_free_mem;
+		goto err_class_sysfs;
 	}
 
 	for (i = 0; i < ARRAY_SIZE(mpu3050_chip_ids); i++)
@@ -700,7 +742,7 @@
 	if (i == ARRAY_SIZE(mpu3050_chip_ids)) {
 		dev_err(&client->dev, "unsupported chip id\n");
 		error = -ENXIO;
-		goto err_free_mem;
+		goto err_class_sysfs;
 	}
 
 	idev->name = "MPU3050";
@@ -775,16 +817,10 @@
 		goto err_free_irq;
 	}
 
-	error = sensors_classdev_register(&client->dev, &sensors_cdev);
-	if (error < 0) {
-		dev_err(&client->dev, "failed to create class device\n");
-		goto err_input_cleanup;
-	}
-
 	error = create_sysfs_interfaces(&idev->dev);
 	if (error < 0) {
 		dev_err(&client->dev, "failed to create sysfs\n");
-		goto err_class_sysfs;
+		goto err_input_cleanup;
 	}
 
 	pm_runtime_enable(&client->dev);
@@ -792,8 +828,6 @@
 
 	return 0;
 
-err_class_sysfs:
-	sensors_classdev_unregister(&sensors_cdev);
 err_input_cleanup:
 	input_unregister_device(idev);
 err_free_irq:
@@ -805,6 +839,8 @@
 		gpio_free(sensor->platform_data->gpio_int);
 err_pm_set_suspended:
 	pm_runtime_set_suspended(&client->dev);
+err_class_sysfs:
+	sensors_classdev_unregister(&sensor->cdev);
 err_free_mem:
 	input_free_device(idev);
 	kfree(sensor);
diff --git a/drivers/input/misc/stk3x1x.c b/drivers/input/misc/stk3x1x.c
index f1b060e..f9d3478 100644
--- a/drivers/input/misc/stk3x1x.c
+++ b/drivers/input/misc/stk3x1x.c
@@ -64,8 +64,6 @@
 #define STK_POLL_PS
 #define STK_POLL_ALS		/* ALS interrupt is valid only when STK_PS_INT_MODE = 1	or 4*/
 
-#define STK_DEBUG_PRINTF
-
 /* Define Register Map */
 #define STK_STATE_REG 			0x00
 #define STK_PSCTRL_REG 			0x01
@@ -192,9 +190,13 @@
 	.max_range = "6500",
 	.resolution = "0.0625",
 	.sensor_power = "0.09",
-	.min_delay = 0,
+	.min_delay = (MIN_ALS_POLL_DELAY_NS / 1000),	/* us */
 	.fifo_reserved_event_count = 0,
 	.fifo_max_event_count = 0,
+	.enabled = 0,
+	.delay_msec = 200,
+	.sensors_enable = NULL,
+	.sensors_poll_delay = NULL,
 };
 
 static struct sensors_classdev sensors_proximity_cdev = {
@@ -209,6 +211,10 @@
 	.min_delay = 0,
 	.fifo_reserved_event_count = 0,
 	.fifo_max_event_count = 0,
+	.enabled = 0,
+	.delay_msec = 200,
+	.sensors_enable = NULL,
+	.sensors_poll_delay = NULL,
 };
 
 struct data_filter {
@@ -221,6 +227,8 @@
 struct stk3x1x_data {
 	struct i2c_client *client;
 	struct stk3x1x_platform_data *pdata;
+	struct sensors_classdev als_cdev;
+	struct sensors_classdev ps_cdev;
 #if (!defined(STK_POLL_PS) || !defined(STK_POLL_ALS))
     int32_t irq;
     struct work_struct stk_work;
@@ -238,7 +246,7 @@
 	int32_t ps_distance_last;
 	bool ps_enabled;
 	struct wake_lock ps_wakelock;
-    struct work_struct stk_ps_work;
+	struct work_struct stk_ps_work;
 	struct workqueue_struct *stk_ps_wq;
 #ifdef STK_POLL_PS
 	struct wake_lock ps_nosuspend_wl;
@@ -321,11 +329,11 @@
     for (i=1,j=0;i<LUX_THD_TABLE_SIZE;i++,j++)
     {
         alscode = stk_lux2alscode(ps_data, lux_threshold_table[j]);
-        printk(KERN_INFO "alscode[%d]=%d\n",i,alscode);
+		dev_dbg(&ps_data->client->dev, "alscode[%d]=%d\n", i, alscode);
         code_threshold_table[i] = (uint16_t)(alscode);
     }
     code_threshold_table[i] = 0xffff;
-    printk(KERN_INFO "alscode[%d]=%d\n",i,alscode);
+	dev_dbg(&ps_data->client->dev, "alscode[%d]=%d\n", i, alscode);
 }
 
 static uint32_t stk_get_lux_interval_index(uint16_t alscode)
@@ -458,7 +466,6 @@
         printk(KERN_ERR "%s: read i2c error, err=%d\n", __func__, err2);
         return -1;
     }
-	printk(KERN_INFO "%s: PID=0x%x, RID=0x%x\n", __func__, err1, err2);
 	if(err2 == 0xC0)
 		printk(KERN_INFO "%s: RID=0xC0!!!!!!!!!!!!!\n", __func__);
 
@@ -685,7 +692,9 @@
 		input_sync(ps_data->ps_input_dev);
 		wake_lock_timeout(&ps_data->ps_wakelock, 3*HZ);
 		reading = stk3x1x_get_ps_reading(ps_data);
-		printk(KERN_INFO "%s: ps input event=%d, ps code = %d\n",__func__, near_far_state, reading);
+		dev_dbg(&ps_data->client->dev,
+			"%s: ps input event=%d, ps code = %d\n",
+			__func__, near_far_state, reading);
 #endif	/* #ifndef STK_POLL_PS */
 	}
 	else
@@ -904,6 +913,21 @@
     return scnprintf(buf, PAGE_SIZE, "%d\n", reading);
 }
 
+static ssize_t stk_als_enable_set(struct sensors_classdev *sensors_cdev,
+						unsigned int enabled)
+{
+	struct stk3x1x_data *als_data = container_of(sensors_cdev,
+						struct stk3x1x_data, als_cdev);
+	int err;
+
+	mutex_lock(&als_data->io_lock);
+	err = stk3x1x_enable_als(als_data, enabled);
+	mutex_unlock(&als_data->io_lock);
+
+	if (err < 0)
+		return err;
+	return 0;
+}
 
 static ssize_t stk_als_enable_show(struct device *dev, struct device_attribute *attr, char *buf)
 {
@@ -935,7 +959,7 @@
 		printk(KERN_ERR "%s, invalid value %d\n", __func__, *buf);
 		return -EINVAL;
 	}
-    printk(KERN_INFO "%s: Enable ALS : %d\n", __func__, en);
+	dev_dbg(dev, "%s: Enable ALS : %d\n", __func__, en);
     mutex_lock(&ps_data->io_lock);
     stk3x1x_enable_als(ps_data, en);
     mutex_unlock(&ps_data->io_lock);
@@ -971,7 +995,7 @@
 	input_report_abs(ps_data->als_input_dev, ABS_MISC, value);
 	input_sync(ps_data->als_input_dev);
 	mutex_unlock(&ps_data->io_lock);
-	printk(KERN_INFO "%s: als input event %ld lux\n",__func__, value);
+	dev_dbg(dev, "%s: als input event %ld lux\n", __func__, value);
 
     return size;
 }
@@ -1009,7 +1033,8 @@
 static ssize_t stk_als_delay_show(struct device *dev, struct device_attribute *attr, char *buf)
 {
 	struct stk3x1x_data *ps_data =  dev_get_drvdata(dev);
-	return scnprintf(buf, PAGE_SIZE, "%lld\n", ktime_to_ns(ps_data->als_poll_delay));
+	return scnprintf(buf, PAGE_SIZE, "%u\n",
+			(u32)ktime_to_ms(ps_data->als_poll_delay));
 }
 
 static inline void stk_als_delay_store_fir(struct stk3x1x_data *ps_data)
@@ -1018,34 +1043,48 @@
 	ps_data->fir.idx = 0;
 	ps_data->fir.sum = 0;
 }
+
+static ssize_t stk_als_poll_delay_set(struct sensors_classdev *sensors_cdev,
+						unsigned int delay_msec)
+{
+	struct stk3x1x_data *als_data = container_of(sensors_cdev,
+						struct stk3x1x_data, als_cdev);
+	uint64_t value = 0;
+
+	value = delay_msec * 1000000;
+
+	if (value < MIN_ALS_POLL_DELAY_NS)
+		value = MIN_ALS_POLL_DELAY_NS;
+
+	mutex_lock(&als_data->io_lock);
+	if (value != ktime_to_ns(als_data->als_poll_delay))
+		als_data->als_poll_delay = ns_to_ktime(value);
+
+	if (als_data->use_fir)
+		stk_als_delay_store_fir(als_data);
+
+	mutex_unlock(&als_data->io_lock);
+
+	return 0;
+}
+
 static ssize_t stk_als_delay_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
 {
     uint64_t value = 0;
 	int ret;
-	struct stk3x1x_data *ps_data =  dev_get_drvdata(dev);
+	struct stk3x1x_data *als_data =  dev_get_drvdata(dev);
 	ret = kstrtoull(buf, 10, &value);
 	if(ret < 0)
 	{
-		printk(KERN_ERR "%s:kstrtoull failed, ret=0x%x\n",
-			__func__, ret);
+		dev_err(dev, "%s:kstrtoull failed, ret=0x%x\n",	__func__, ret);
 		return ret;
 	}
 #ifdef STK_DEBUG_PRINTF
-	printk(KERN_INFO "%s: set als poll delay=%lld\n", __func__, value);
+	dev_dbg(dev, "%s: set als poll delay=%lld\n", __func__, value);
 #endif
-	if(value < MIN_ALS_POLL_DELAY_NS)
-	{
-		printk(KERN_ERR "%s: delay is too small\n", __func__);
-		value = MIN_ALS_POLL_DELAY_NS;
-	}
-	mutex_lock(&ps_data->io_lock);
-	if(value != ktime_to_ns(ps_data->als_poll_delay))
-		ps_data->als_poll_delay = ns_to_ktime(value);
-
-	if (ps_data->use_fir)
-		stk_als_delay_store_fir(ps_data);
-
-	mutex_unlock(&ps_data->io_lock);
+	ret = stk_als_poll_delay_set(&als_data->als_cdev, value);
+	if (ret < 0)
+		return ret;
 	return size;
 }
 
@@ -1136,6 +1175,22 @@
     return scnprintf(buf, PAGE_SIZE, "%d\n", reading);
 }
 
+static ssize_t stk_ps_enable_set(struct sensors_classdev *sensors_cdev,
+						unsigned int enabled)
+{
+	struct stk3x1x_data *ps_data = container_of(sensors_cdev,
+						struct stk3x1x_data, ps_cdev);
+	int err;
+
+	mutex_lock(&ps_data->io_lock);
+	err = stk3x1x_enable_ps(ps_data, enabled);
+	mutex_unlock(&ps_data->io_lock);
+
+	if (err < 0)
+		return err;
+	return 0;
+}
+
 static ssize_t stk_ps_enable_show(struct device *dev, struct device_attribute *attr, char *buf)
 {
     int32_t enable, ret;
@@ -1166,7 +1221,7 @@
 		printk(KERN_ERR "%s, invalid value %d\n", __func__, *buf);
 		return -EINVAL;
 	}
-    printk(KERN_INFO "%s: Enable PS : %d\n", __func__, en);
+	dev_dbg(dev, "%s: Enable PS : %d\n", __func__, en);
     mutex_lock(&ps_data->io_lock);
     stk3x1x_enable_ps(ps_data, en);
     mutex_unlock(&ps_data->io_lock);
@@ -1200,7 +1255,7 @@
 		printk(KERN_ERR "%s, invalid value %d\n", __func__, *buf);
 		return -EINVAL;
 	}
-    printk(KERN_INFO "%s: Enable PS ASO : %d\n", __func__, en);
+	dev_dbg(dev, "%s: Enable PS ASO : %d\n", __func__, en);
 
     ret = i2c_smbus_read_byte_data(ps_data->client, STK_STATE_REG);
     if (ret < 0)
@@ -1288,7 +1343,7 @@
 	input_sync(ps_data->ps_input_dev);
     mutex_unlock(&ps_data->io_lock);
 	wake_lock_timeout(&ps_data->ps_wakelock, 3*HZ);
-	printk(KERN_INFO "%s: ps input event %d cm\n",__func__, dist);
+	dev_dbg(dev, "%s: ps input event %d cm\n", __func__, dist);
     return scnprintf(buf, PAGE_SIZE, "%d\n", dist);
 }
 
@@ -1311,7 +1366,7 @@
 	input_sync(ps_data->ps_input_dev);
     mutex_unlock(&ps_data->io_lock);
 	wake_lock_timeout(&ps_data->ps_wakelock, 3*HZ);
-	printk(KERN_INFO "%s: ps input event %ld cm\n",__func__, value);
+	dev_dbg(dev, "%s: ps input event %ld cm\n", __func__, value);
     return size;
 }
 
@@ -1507,7 +1562,7 @@
 		}
 		else
 		{
-			printk(KERN_INFO "reg[0x%2X]=0x%2X\n", cnt, ps_reg[cnt]);
+			dev_dbg(dev, "reg[0x%2X]=0x%2X\n", cnt, ps_reg[cnt]);
 		}
 	}
 	ps_reg[cnt] = i2c_smbus_read_byte_data(ps_data->client, STK_PDT_ID_REG);
@@ -1517,7 +1572,7 @@
 		printk( KERN_ERR "all_reg_show:i2c_smbus_read_byte_data fail, ret=%d", ps_reg[cnt]);
 		return -EINVAL;
 	}
-	printk( KERN_INFO "reg[0x%x]=0x%2X\n", STK_PDT_ID_REG, ps_reg[cnt]);
+	dev_dbg(dev, "reg[0x%x]=0x%2X\n", STK_PDT_ID_REG, ps_reg[cnt]);
 	cnt++;
 	ps_reg[cnt] = i2c_smbus_read_byte_data(ps_data->client, STK_RSRVD_REG);
 	if(ps_reg[cnt] < 0)
@@ -1526,7 +1581,7 @@
 		printk( KERN_ERR "all_reg_show:i2c_smbus_read_byte_data fail, ret=%d", ps_reg[cnt]);
 		return -EINVAL;
 	}
-	printk( KERN_INFO "reg[0x%x]=0x%2X\n", STK_RSRVD_REG, ps_reg[cnt]);
+	dev_dbg(dev, "reg[0x%x]=0x%2X\n", STK_RSRVD_REG, ps_reg[cnt]);
     mutex_unlock(&ps_data->io_lock);
 
     return scnprintf(buf, PAGE_SIZE, "%2X %2X %2X %2X %2X,%2X %2X %2X %2X %2X,%2X %2X %2X %2X %2X,%2X %2X %2X %2X %2X,%2X %2X %2X %2X %2X,%2X %2X\n",
@@ -1589,8 +1644,7 @@
 			__func__, ret);
 		return ret;
 	}
-	printk(KERN_INFO "%s: write reg 0x%x=0x%x\n", __func__, addr, cmd);
-
+	dev_dbg(dev, "%s: write reg 0x%x=0x%x\n", __func__, addr, cmd);
 	addr_u8 = (u8) addr;
 	cmd_u8 = (u8) cmd;
 	//mutex_lock(&ps_data->io_lock);
@@ -1688,7 +1742,6 @@
 	input_report_abs(ps_data->als_input_dev, ABS_MISC, ps_data->als_lux_last);
 	input_sync(ps_data->als_input_dev);
 	mutex_unlock(&ps_data->io_lock);
-	//printk(KERN_INFO "%s: als input event %d lux\n",__func__, ps_data->als_lux_last);
 }
 #endif
 
@@ -1948,7 +2001,6 @@
 	int err;
 #endif
 
-	printk(KERN_INFO "%s", __func__);
     mutex_lock(&ps_data->io_lock);
 	if(ps_data->als_enabled)
 	{
@@ -1976,7 +2028,6 @@
 	int err;
 #endif
 
-	printk(KERN_INFO "%s", __func__);
     mutex_lock(&ps_data->io_lock);
 	if(ps_data->als_enabled)
 		stk3x1x_enable_als(ps_data, 1);
@@ -2394,10 +2445,16 @@
 	register_early_suspend(&ps_data->stk_early_suspend);
 #endif
 	/* make sure everything is ok before registering the class device */
-	err = sensors_classdev_register(&client->dev, &sensors_light_cdev);
+	ps_data->als_cdev = sensors_light_cdev;
+	ps_data->als_cdev.sensors_enable = stk_als_enable_set;
+	ps_data->als_cdev.sensors_poll_delay = stk_als_poll_delay_set;
+	err = sensors_classdev_register(&client->dev, &ps_data->als_cdev);
 	if (err)
 		goto err_power_on;
-	err = sensors_classdev_register(&client->dev, &sensors_proximity_cdev);
+
+	ps_data->ps_cdev = sensors_proximity_cdev;
+	ps_data->ps_cdev.sensors_enable = stk_ps_enable_set;
+	err = sensors_classdev_register(&client->dev, &ps_data->ps_cdev);
 	if (err)
 		goto err_class_sysfs;
 
@@ -2411,9 +2468,9 @@
 
 err_init_all_setting:
 	stk3x1x_power_ctl(ps_data, false);
-	sensors_classdev_unregister(&sensors_proximity_cdev);
+	sensors_classdev_unregister(&ps_data->ps_cdev);
 err_class_sysfs:
-	sensors_classdev_unregister(&sensors_light_cdev);
+	sensors_classdev_unregister(&ps_data->als_cdev);
 err_power_on:
 	stk3x1x_power_init(ps_data, false);
 err_power_init:
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index 9b0c5c7..1e08169 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -110,6 +110,18 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called atmel_mxt_ts.
 
+config TOUCHSCREEN_ATMEL_MAXTOUCH_TS
+	tristate "Atmel Maxtouch Touchscreen Family"
+	depends on I2C
+	help
+	  Say Y here if you have Atmel MaXTouch Touchscreen
+	  using i2c connected to your system.
+
+	  If unsure, say N.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called atmel_maxtouch_ts.
+
 config TOUCHSCREEN_AUO_PIXCIR
 	tristate "AUO in-cell touchscreen using Pixcir ICs"
 	depends on I2C
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
index 3acc612..dc3bbe0 100644
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -14,6 +14,7 @@
 obj-$(CONFIG_TOUCHSCREEN_ADS7846)	+= ads7846.o
 obj-$(CONFIG_TOUCHSCREEN_ATMEL_MAXTOUCH)	+= atmel_maxtouch.o
 obj-$(CONFIG_TOUCHSCREEN_ATMEL_MXT)	+= atmel_mxt_ts.o
+obj-$(CONFIG_TOUCHSCREEN_ATMEL_MAXTOUCH_TS)	+= atmel_maxtouch_ts.o
 obj-$(CONFIG_TOUCHSCREEN_ATMEL_TSADCC)	+= atmel_tsadcc.o
 obj-$(CONFIG_TOUCHSCREEN_AUO_PIXCIR)	+= auo-pixcir-ts.o
 obj-$(CONFIG_TOUCHSCREEN_BITSY)		+= h3600_ts_input.o
@@ -79,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/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 3731561..be7c3c6 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -3,7 +3,7 @@
  *
  * Copyright (C) 2010 Samsung Electronics Co.Ltd
  * Author: Joonyoung Shim <jy0922.shim@samsung.com>
- * 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 as published by the
@@ -882,7 +882,7 @@
 		status = MXT_RELEASE;
 	}
 
-	if (status != MXT_RELEASE) {
+	if ((status != MXT_RELEASE) && status) {
 		input_report_abs(input_dev, ABS_X, finger[single_id].x);
 		input_report_abs(input_dev, ABS_Y, finger[single_id].y);
 		input_report_abs(input_dev,
@@ -1983,6 +1983,7 @@
 				    const char *buf, size_t count)
 {
 	struct mxt_data *data = dev_get_drvdata(dev);
+	struct device *adapter = data->client->adapter->dev.parent;
 	unsigned long value;
 	int err = 0;
 
@@ -2000,7 +2001,7 @@
 		if (atomic_read(&data->st_enabled) == 0)
 			break;
 
-		pm_runtime_put(data->client->adapter->dev.parent);
+		pm_runtime_put(adapter);
 		atomic_set(&data->st_enabled, 0);
 		mxt_secure_touch_notify(data);
 		mxt_interrupt(data->client->irq, data);
@@ -2012,7 +2013,7 @@
 			break;
 		}
 
-		if (pm_runtime_get(data->client->adapter->dev.parent) < 0) {
+		if (pm_runtime_get_sync(adapter) < 0) {
 			dev_err(&data->client->dev, "pm_runtime_get failed\n");
 			err = -EIO;
 			break;
@@ -2049,14 +2050,17 @@
 	return scnprintf(buf, PAGE_SIZE, "%u", val);
 }
 
-static DEVICE_ATTR(secure_touch_enable, 0666, mxt_secure_touch_enable_show,
-	mxt_secure_touch_enable_store);
-static DEVICE_ATTR(secure_touch, 0444, mxt_secure_touch_show, NULL);
+static DEVICE_ATTR(secure_touch_enable, S_IRUGO | S_IWUSR | S_IWGRP ,
+			 mxt_secure_touch_enable_show,
+			 mxt_secure_touch_enable_store);
+static DEVICE_ATTR(secure_touch, S_IRUGO, mxt_secure_touch_show, NULL);
 #endif
 
-static DEVICE_ATTR(object, 0444, mxt_object_show, NULL);
-static DEVICE_ATTR(update_fw, 0664, NULL, mxt_update_fw_store);
-static DEVICE_ATTR(force_cfg_update, 0664, NULL, mxt_force_cfg_update_store);
+static DEVICE_ATTR(object, S_IRUGO, mxt_object_show, NULL);
+static DEVICE_ATTR(update_fw, S_IWUSR | S_IWGRP , NULL, mxt_update_fw_store);
+static DEVICE_ATTR(force_cfg_update, S_IWUSR | S_IWGRP ,
+			 NULL,
+			 mxt_force_cfg_update_store);
 
 static struct attribute *mxt_attrs[] = {
 	&dev_attr_object.attr,
@@ -2547,6 +2551,15 @@
 	.resume		= mxt_resume,
 #endif
 };
+#else
+static int mxt_suspend(struct device *dev)
+{
+	return 0;
+};
+static int mxt_resume(struct device *dev)
+{
+	return 0;
+};
 #endif
 
 static int mxt_debugfs_object_show(struct seq_file *m, void *v)
diff --git a/drivers/input/touchscreen/ft5x06_ts.c b/drivers/input/touchscreen/ft5x06_ts.c
index 9a4301e..1da84fa 100644
--- a/drivers/input/touchscreen/ft5x06_ts.c
+++ b/drivers/input/touchscreen/ft5x06_ts.c
@@ -3,7 +3,7 @@
  * FocalTech ft5x06 TouchScreen driver.
  *
  * Copyright (c) 2010  Focal tech Ltd.
- * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2014, The Linux Foundation. All rights reserved.
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
@@ -69,7 +69,6 @@
 #define FT_REG_THGROUP		0x80
 #define FT_REG_ECC		0xCC
 #define FT_REG_RESET_FW		0x07
-#define FT_REG_FW_MAJ_VER	0xB1
 #define FT_REG_FW_MIN_VER	0xB2
 #define FT_REG_FW_SUB_MIN_VER	0xB3
 
@@ -289,7 +288,7 @@
 	u8 reg_addr;
 	int err;
 
-	reg_addr = FT_REG_FW_MAJ_VER;
+	reg_addr = FT_REG_FW_VER;
 	err = ft5x06_i2c_read(client, &reg_addr, 1, &data->fw_ver[0], 1);
 	if (err < 0)
 		dev_err(&client->dev, "fw major version read failed");
@@ -877,6 +876,11 @@
 	u8 fw_file_maj, fw_file_min, fw_file_sub_min;
 	bool fw_upgrade = false;
 
+	if (data->suspended) {
+		dev_info(dev, "Device is in suspend state: Exit FW upgrade\n");
+		return -EBUSY;
+	}
+
 	rc = request_firmware(&fw, data->fw_name, dev);
 	if (rc < 0) {
 		dev_err(dev, "Request firmware failed - %s (%d)\n",
@@ -899,17 +903,10 @@
 	dev_info(dev, "New firmware: %d.%d.%d", fw_file_maj,
 				fw_file_min, fw_file_sub_min);
 
-	if (force) {
+	if (force)
 		fw_upgrade = true;
-	} else if (data->fw_ver[0] == fw_file_maj) {
-			if (data->fw_ver[1] < fw_file_min)
-				fw_upgrade = true;
-			else if (data->fw_ver[2] < fw_file_sub_min)
-				fw_upgrade = true;
-			else
-				dev_info(dev, "No need to upgrade\n");
-	} else
-		dev_info(dev, "Firmware versions do not match\n");
+	else if (data->fw_ver[0] < fw_file_maj)
+		fw_upgrade = true;
 
 	if (!fw_upgrade) {
 		dev_info(dev, "Exiting fw upgrade...\n");
@@ -1546,8 +1543,9 @@
 	data->family_id = pdata->family_id;
 
 	err = request_threaded_irq(client->irq, NULL,
-				   ft5x06_ts_interrupt, pdata->irqflags,
-				   client->dev.driver->name, data);
+				ft5x06_ts_interrupt,
+				pdata->irqflags | IRQF_ONESHOT,
+				client->dev.driver->name, data);
 	if (err) {
 		dev_err(&client->dev, "request irq failed\n");
 		goto free_reset_gpio;
diff --git a/drivers/input/touchscreen/gt9xx/goodix_tool.c b/drivers/input/touchscreen/gt9xx/goodix_tool.c
index aa8159f..521599a 100644
--- a/drivers/input/touchscreen/gt9xx/goodix_tool.c
+++ b/drivers/input/touchscreen/gt9xx/goodix_tool.c
@@ -23,16 +23,15 @@
 
 #include "gt9xx.h"
 #include <linux/mutex.h>
+#include <linux/proc_fs.h>
+#include <linux/debugfs.h>
 
 #define DATA_LENGTH_UINT    512
-#define CMD_HEAD_LENGTH     (sizeof(st_cmd_head) - sizeof(u8 *))
+#define CMD_HEAD_LENGTH     (sizeof(struct st_cmd_head) - sizeof(u8 *))
 static char procname[20] = {0};
 
-#define UPDATE_FUNCTIONS
-
-#pragma pack(1)
-struct {
-	u8  wr;		/* write read flag£¬0:R  1:W  2:PID 3: */
+struct st_cmd_head {
+	u8  wr;		/* write read flag 0:R 1:W 2:PID 3: */
 	u8  flag;	/* 0:no need flag/int 1: need flag  2:need int */
 	u8 flag_addr[2];/* flag address */
 	u8  flag_val;	/* flag val */
@@ -46,9 +45,9 @@
 	u8  addr[2];	/* address */
 	u8  res[3];	/* reserved */
 	u8  *data;	/* data pointer */
-} st_cmd_head;
-#pragma pack()
-st_cmd_head cmd_head;
+} __packed;
+
+static struct st_cmd_head cmd_head;
 
 static struct i2c_client *gt_client;
 
@@ -56,15 +55,11 @@
 
 static struct mutex lock;
 
-static s32 goodix_tool_write(struct file *filp, const char __user *buff,
-						unsigned long len, void *data);
-static s32 goodix_tool_read(char *page, char **start, off_t off, int count,
-							int *eof, void *data);
 static s32 (*tool_i2c_read)(u8 *, u16);
 static s32 (*tool_i2c_write)(u8 *, u16);
 
-s32 DATA_LENGTH;
-s8 IC_TYPE[16] = {0};
+s32 data_length;
+s8 ic_type[16] = {0};
 
 static void tool_set_proc_name(char *procname)
 {
@@ -75,7 +70,7 @@
 	int i = 0, n_month = 1, n_day = 0, n_year = 0;
 	snprintf(date, 20, "%s", __DATE__);
 
-	/* GTP_DEBUG("compile date: %s", date); */
+	/* pr_debug("compile date: %s", date); */
 
 	sscanf(date, "%s %d %d", month, &n_day, &n_year);
 
@@ -87,24 +82,27 @@
 	}
 
 	snprintf(procname, 20, "gmnode%04d%02d%02d", n_year, n_month, n_day);
-	/* GTP_DEBUG("procname = %s", procname); */
+	/* pr_debug("procname = %s", procname); */
 }
 
 static s32 tool_i2c_read_no_extra(u8 *buf, u16 len)
 {
 	s32 ret = -1;
-	s32 i = 0;
-	struct i2c_msg msgs[2];
-
-	msgs[0].flags = !I2C_M_RD;
-	msgs[0].addr  = gt_client->addr;
-	msgs[0].len   = cmd_head.addr_len;
-	msgs[0].buf   = &buf[0];
-
-	msgs[1].flags = I2C_M_RD;
-	msgs[1].addr  = gt_client->addr;
-	msgs[1].len   = len;
-	msgs[1].buf   = &buf[GTP_ADDR_LENGTH];
+	u8 i = 0;
+	struct i2c_msg msgs[2] = {
+		{
+			.flags = !I2C_M_RD,
+			.addr  = gt_client->addr,
+			.len   = cmd_head.addr_len,
+			.buf   = &buf[0],
+		},
+		{
+			.flags = I2C_M_RD,
+			.addr  = gt_client->addr,
+			.len   = len,
+			.buf   = &buf[GTP_ADDR_LENGTH],
+		},
+	};
 
 	for (i = 0; i < cmd_head.retry; i++) {
 		ret = i2c_transfer(gt_client->adapter, msgs, 2);
@@ -112,25 +110,35 @@
 			break;
 	}
 
+	if (i == cmd_head.retry) {
+		dev_err(&gt_client->dev, "I2C read retry limit over.\n");
+		ret = -EIO;
+	}
+
 	return ret;
 }
 
 static s32 tool_i2c_write_no_extra(u8 *buf, u16 len)
 {
 	s32 ret = -1;
-	s32 i = 0;
-	struct i2c_msg msg;
-
-	msg.flags = !I2C_M_RD;
-	msg.addr  = gt_client->addr;
-	msg.len   = len;
-	msg.buf   = buf;
+	u8 i = 0;
+	struct i2c_msg msg = {
+		.flags = !I2C_M_RD,
+		.addr  = gt_client->addr,
+		.len   = len,
+		.buf   = buf,
+	};
 
 	for (i = 0; i < cmd_head.retry; i++) {
 		ret = i2c_transfer(gt_client->adapter, &msg, 1);
 		if (ret > 0)
 			break;
-		}
+	}
+
+	if (i == cmd_head.retry) {
+		dev_err(&gt_client->dev, "I2C write retry limit over.\n");
+		ret = -EIO;
+	}
 
 	return ret;
 }
@@ -163,22 +171,17 @@
 
 static void register_i2c_func(void)
 {
-	/* if (!strncmp(IC_TYPE, "GT818", 5) || !strncmp(IC_TYPE, "GT816", 5)
-	|| !strncmp(IC_TYPE, "GT811", 5) || !strncmp(IC_TYPE, "GT818F", 6)
-	|| !strncmp(IC_TYPE, "GT827", 5) || !strncmp(IC_TYPE,"GT828", 5)
-	|| !strncmp(IC_TYPE, "GT813", 5)) */
-
-	if (strncmp(IC_TYPE, "GT8110", 6) && strncmp(IC_TYPE, "GT8105", 6)
-	&& strncmp(IC_TYPE, "GT801", 5) && strncmp(IC_TYPE, "GT800", 5)
-	&& strncmp(IC_TYPE, "GT801PLUS", 9) && strncmp(IC_TYPE, "GT811", 5)
-	&& strncmp(IC_TYPE, "GTxxx", 5)) {
+	if (strcmp(ic_type, "GT8110") && strcmp(ic_type, "GT8105")
+	&& strcmp(ic_type, "GT801") && strcmp(ic_type, "GT800")
+	&& strcmp(ic_type, "GT801PLUS") && strcmp(ic_type, "GT811")
+	&& strcmp(ic_type, "GTxxx")) {
 		tool_i2c_read = tool_i2c_read_with_extra;
 		tool_i2c_write = tool_i2c_write_with_extra;
-		GTP_DEBUG("I2C function: with pre and end cmd!");
+		pr_debug("I2C function: with pre and end cmd!");
 	} else {
 		tool_i2c_read = tool_i2c_read_no_extra;
 		tool_i2c_write = tool_i2c_write_no_extra;
-		GTP_INFO("I2C function: without pre and end cmd!");
+		pr_info("I2C function: without pre and end cmd!");
 	}
 }
 
@@ -186,55 +189,11 @@
 {
 	tool_i2c_read = NULL;
 	tool_i2c_write = NULL;
-	GTP_INFO("I2C function: unregister i2c transfer function!");
-}
-
-s32 init_wr_node(struct i2c_client *client)
-{
-	u8 i;
-
-	gt_client = client;
-	memset(&cmd_head, 0, sizeof(cmd_head));
-	cmd_head.data = NULL;
-
-	i = 5;
-	while ((!cmd_head.data) && i) {
-		cmd_head.data = kzalloc(i * DATA_LENGTH_UINT, GFP_KERNEL);
-		if (NULL != cmd_head.data)
-			break;
-		i--;
-	}
-	if (i) {
-		DATA_LENGTH = i * DATA_LENGTH_UINT;
-		dev_dbg(&client->dev, "Applied memory size:%d.", DATA_LENGTH);
-	} else {
-		GTP_ERROR("Apply for memory failed.");
-		return FAIL;
-	}
-
-	cmd_head.addr_len = 2;
-	cmd_head.retry = 5;
-
-	register_i2c_func();
-
-	mutex_init(&lock);
-	tool_set_proc_name(procname);
-	goodix_proc_entry = create_proc_entry(procname, 0660, NULL);
-	if (goodix_proc_entry == NULL) {
-		GTP_ERROR("Couldn't create proc entry!");
-		return FAIL;
-	} else {
-		GTP_INFO("Create proc entry success!");
-		goodix_proc_entry->write_proc = goodix_tool_write;
-		dix_proc_entry->read_proc = goodix_tool_read;
-	}
-
-	return SUCCESS;
+	pr_info("I2C function: unregister i2c transfer function!");
 }
 
 void uninit_wr_node(void)
 {
-	kfree(cmd_head.data);
 	cmd_head.data = NULL;
 	unregister_i2c_func();
 	remove_proc_entry(procname, NULL);
@@ -252,7 +211,7 @@
 
 	case 1:
 		ret = (src == dst) ? true : false;
-		GTP_DEBUG("equal:src:0x%02x   dst:0x%02x  ret:%d.",
+		pr_debug("equal:src:0x%02x   dst:0x%02x  ret:%d.",
 					src, dst, (s32)ret);
 		break;
 
@@ -293,22 +252,18 @@
 	s32 i = 0;
 	u8 buf[32];
 
-/*    memcpy(&buf[GTP_ADDR_LENGTH - cmd_head.addr_len],
-			&cmd_head.flag_addr, cmd_head.addr_len);
-    memcpy(buf, &cmd_head.flag_addr, cmd_head.addr_len);
-		//Modified by Scott, 2012-02-17 */
 	memcpy(buf, cmd_head.flag_addr, cmd_head.addr_len);
 
 	for (i = 0; i < cmd_head.times; i++) {
 		if (tool_i2c_read(buf, 1) <= 0) {
-			GTP_ERROR("Read flag data failed!");
+			dev_err(&gt_client->dev, "Read flag data failed!");
 			return FAIL;
 		}
 		if (true == relation(buf[GTP_ADDR_LENGTH], cmd_head.flag_val,
 						cmd_head.flag_relation)) {
-			GTP_DEBUG("value at flag addr:0x%02x.",
+			pr_debug("value at flag addr:0x%02x.",
 						buf[GTP_ADDR_LENGTH]);
-			GTP_DEBUG("flag value:0x%02x.", cmd_head.flag_val);
+			pr_debug("flag value:0x%02x.", cmd_head.flag_val);
 			break;
 		}
 
@@ -316,13 +271,34 @@
 	}
 
 	if (i >= cmd_head.times) {
-		GTP_ERROR("Didn't get the flag to continue!");
+		dev_err(&gt_client->dev, "Didn't get the flag to continue!");
 		return FAIL;
 	}
 
 	return SUCCESS;
 }
 
+#ifdef CONFIG_GT9XX_TOUCHPANEL_UPDATE
+static s32 fill_update_info(char __user *user_buf,
+				    size_t count, loff_t *ppos)
+{
+	u8 buf[4];
+
+	buf[0] = show_len >> 8;
+	buf[1] = show_len & 0xff;
+	buf[2] = total_len >> 8;
+	buf[3] = total_len & 0xff;
+	return simple_read_from_buffer(user_buf, count, ppos,
+			buf, sizeof(buf));
+}
+#else
+static s32 fill_update_info(char __user *user_buf,
+				    size_t count, loff_t *ppos)
+{
+	return -ENODEV;
+}
+#endif
+
 /********************************************************
 Function:
     Goodix tool write function.
@@ -331,117 +307,99 @@
 Output:
     Return write length.
 ********************************************************/
-static s32 goodix_tool_write(struct file *filp, const char __user *buff,
-						unsigned long len, void *data)
+static s32 goodix_tool_write(struct file *filp, const char __user *userbuf,
+						size_t count, loff_t *ppos)
 {
 	s32 ret = 0;
-	GTP_DEBUG_FUNC();
-	GTP_DEBUG_ARRAY((u8 *)buff, len);
 
 	mutex_lock(&lock);
-	ret = copy_from_user(&cmd_head, buff, CMD_HEAD_LENGTH);
+	ret = copy_from_user(&cmd_head, userbuf, CMD_HEAD_LENGTH);
 	if (ret) {
-		GTP_ERROR("copy_from_user failed.");
+		dev_err(&gt_client->dev, "copy_from_user failed.");
 		ret = -EACCES;
 		goto exit;
 	}
 
-	GTP_DEBUG("wr  :0x%02x.", cmd_head.wr);
-	GTP_DEBUG("flag:0x%02x.", cmd_head.flag);
-	GTP_DEBUG("flag addr:0x%02x%02x.", cmd_head.flag_addr[0],
-						cmd_head.flag_addr[1]);
-	GTP_DEBUG("flag val:0x%02x.", cmd_head.flag_val);
-	GTP_DEBUG("flag rel:0x%02x.", cmd_head.flag_relation);
-	GTP_DEBUG("circle  :%d.", (s32)cmd_head.circle);
-	GTP_DEBUG("times   :%d.", (s32)cmd_head.times);
-	GTP_DEBUG("retry   :%d.", (s32)cmd_head.retry);
-	GTP_DEBUG("delay   :%d.", (s32)cmd_head.delay);
-	GTP_DEBUG("data len:%d.", (s32)cmd_head.data_len);
-	GTP_DEBUG("addr len:%d.", (s32)cmd_head.addr_len);
-	GTP_DEBUG("addr:0x%02x%02x.", cmd_head.addr[0], cmd_head.addr[1]);
-	GTP_DEBUG("len:%d.", (s32)len);
-	GTP_DEBUG("buf[20]:0x%02x.", buff[CMD_HEAD_LENGTH]);
+	dev_dbg(&gt_client->dev, "wr:0x%02x, flag:0x%02x, flag addr:0x%02x%02x, flag val:0x%02x, flag rel:0x%02x, circle:%d, times:%d, retry:%d, delay:%d, data len:%d, addr len:%d, addr:0x%02x%02x, write len: %d.",
+		cmd_head.wr, cmd_head.flag, cmd_head.flag_addr[0],
+		cmd_head.flag_addr[1], cmd_head.flag_val,
+		cmd_head.flag_relation,	(s32)cmd_head.circle,
+		(s32)cmd_head.times, (s32)cmd_head.retry, (s32)cmd_head.delay,
+		(s32)cmd_head.data_len, (s32)cmd_head.addr_len,
+		cmd_head.addr[0], cmd_head.addr[1], (s32)count);
 
-	if (cmd_head.data_len > (DATA_LENGTH - GTP_ADDR_LENGTH)) {
-		pr_err("data len %d > data buff %d, rejected!\n",
-			cmd_head.data_len, (DATA_LENGTH - GTP_ADDR_LENGTH));
+	if (cmd_head.data_len > (data_length - GTP_ADDR_LENGTH)) {
+		dev_err(&gt_client->dev, "data len %d > data buff %d, rejected!\n",
+			cmd_head.data_len, (data_length - GTP_ADDR_LENGTH));
 		ret = -EINVAL;
 		goto exit;
 	}
 	if (cmd_head.addr_len > GTP_ADDR_LENGTH) {
-		pr_err(" addr len %d > data buff %d, rejected!\n",
+		dev_err(&gt_client->dev, "addr len %d > data buff %d, rejected!\n",
 			cmd_head.addr_len, GTP_ADDR_LENGTH);
 		ret = -EINVAL;
 		goto exit;
 	}
 
-	if (cmd_head.wr == 1) {
-		/*  copy_from_user(&cmd_head.data[cmd_head.addr_len],
-				&buff[CMD_HEAD_LENGTH], cmd_head.data_len); */
+	if (cmd_head.wr == GTP_RW_WRITE) {
 		ret = copy_from_user(&cmd_head.data[GTP_ADDR_LENGTH],
-				&buff[CMD_HEAD_LENGTH], cmd_head.data_len);
-		if (ret)
-			GTP_ERROR("copy_from_user failed.");
+				&userbuf[CMD_HEAD_LENGTH], cmd_head.data_len);
+		if (ret) {
+			dev_err(&gt_client->dev, "copy_from_user failed.");
+			goto exit;
+		}
 
 		memcpy(&cmd_head.data[GTP_ADDR_LENGTH - cmd_head.addr_len],
 					cmd_head.addr, cmd_head.addr_len);
 
-		GTP_DEBUG_ARRAY(cmd_head.data,
-				cmd_head.data_len + cmd_head.addr_len);
-		GTP_DEBUG_ARRAY((u8 *)&buff[CMD_HEAD_LENGTH],
-							cmd_head.data_len);
-
-		if (cmd_head.flag == 1) {
-			if (FAIL == comfirm()) {
-				GTP_ERROR("[WRITE]Comfirm fail!");
+		if (cmd_head.flag == GTP_NEED_FLAG) {
+			if (comfirm() ==  FAIL) {
+				dev_err(&gt_client->dev, "Comfirm fail!");
 				ret = -EINVAL;
 				goto exit;
 			}
-		} else if (cmd_head.flag == 2) {
+		} else if (cmd_head.flag == GTP_NEED_INTERRUPT) {
 			/* Need interrupt! */
 		}
 		if (tool_i2c_write(
 		&cmd_head.data[GTP_ADDR_LENGTH - cmd_head.addr_len],
 		cmd_head.data_len + cmd_head.addr_len) <= 0) {
-			GTP_ERROR("[WRITE]Write data failed!");
+			dev_err(&gt_client->dev, "Write data failed!");
 			ret = -EIO;
 			goto exit;
 		}
 
-		GTP_DEBUG_ARRAY(
-			&cmd_head.data[GTP_ADDR_LENGTH - cmd_head.addr_len],
-			cmd_head.data_len + cmd_head.addr_len);
 		if (cmd_head.delay)
 			msleep(cmd_head.delay);
 
 		ret = cmd_head.data_len + CMD_HEAD_LENGTH;
 		goto exit;
-	} else if (cmd_head.wr == 3) {  /* Write ic type */
-
-		ret = copy_from_user(&cmd_head.data[0], &buff[CMD_HEAD_LENGTH],
+	} else if (cmd_head.wr == GTP_RW_WRITE_IC_TYPE) {  /* Write ic type */
+		ret = copy_from_user(&cmd_head.data[0],
+				&userbuf[CMD_HEAD_LENGTH],
 				cmd_head.data_len);
-		if (ret)
-			GTP_ERROR("copy_from_user failed.");
+		if (ret) {
+			dev_err(&gt_client->dev, "copy_from_user failed.");
+			goto exit;
+		}
 
-		if (cmd_head.data_len > sizeof(IC_TYPE)) {
-			pr_err("<<-GTP->> data len %d > data buff %d, rejected!\n",
-			cmd_head.data_len, sizeof(IC_TYPE));
+		if (cmd_head.data_len > sizeof(ic_type)) {
+			dev_err(&gt_client->dev,
+				"data len %d > data buff %d, rejected!\n",
+				cmd_head.data_len, sizeof(ic_type));
 			ret = -EINVAL;
 			goto exit;
 		}
-		memcpy(IC_TYPE, cmd_head.data, cmd_head.data_len);
+		memcpy(ic_type, cmd_head.data, cmd_head.data_len);
 
 		register_i2c_func();
 
 		ret = cmd_head.data_len + CMD_HEAD_LENGTH;
 		goto exit;
-	} else if (cmd_head.wr == 5) {
-
-		/* memcpy(IC_TYPE, cmd_head.data, cmd_head.data_len); */
-
+	} else if (cmd_head.wr == GTP_RW_NO_WRITE) {
 		ret = cmd_head.data_len + CMD_HEAD_LENGTH;
 		goto exit;
-	} else if (cmd_head.wr == 7) { /* disable irq! */
+	} else if (cmd_head.wr == GTP_RW_DISABLE_IRQ) { /* disable irq! */
 		gtp_irq_disable(i2c_get_clientdata(gt_client));
 
 		#if GTP_ESD_PROTECT
@@ -449,7 +407,7 @@
 		#endif
 		ret = CMD_HEAD_LENGTH;
 		goto exit;
-	} else if (cmd_head.wr == 9) { /* enable irq! */
+	} else if (cmd_head.wr == GTP_RW_ENABLE_IRQ) { /* enable irq! */
 		gtp_irq_enable(i2c_get_clientdata(gt_client));
 
 		#if GTP_ESD_PROTECT
@@ -457,49 +415,51 @@
 		#endif
 		ret = CMD_HEAD_LENGTH;
 		goto exit;
-	} else if (cmd_head.wr == 17) {
+	} else if (cmd_head.wr == GTP_RW_CHECK_RAWDIFF_MODE) {
 		struct goodix_ts_data *ts = i2c_get_clientdata(gt_client);
 		ret = copy_from_user(&cmd_head.data[GTP_ADDR_LENGTH],
-				&buff[CMD_HEAD_LENGTH], cmd_head.data_len);
-		if (ret)
-			GTP_DEBUG("copy_from_user failed.");
+				&userbuf[CMD_HEAD_LENGTH], cmd_head.data_len);
+		if (ret) {
+			pr_debug("copy_from_user failed.");
+			goto exit;
+		}
 		if (cmd_head.data[GTP_ADDR_LENGTH]) {
-			GTP_DEBUG("gtp enter rawdiff.");
+			pr_debug("gtp enter rawdiff.");
 			ts->gtp_rawdiff_mode = true;
 		} else {
 			ts->gtp_rawdiff_mode = false;
-			GTP_DEBUG("gtp leave rawdiff.");
+			pr_debug("gtp leave rawdiff.");
 		}
 		ret = CMD_HEAD_LENGTH;
 		goto exit;
-	}
-#ifdef UPDATE_FUNCTIONS
-	else if (cmd_head.wr == 11) { /* Enter update mode! */
-		if (FAIL == gup_enter_update_mode(gt_client)) {
+	} else if (cmd_head.wr == GTP_RW_ENTER_UPDATE_MODE) {
+		/* Enter update mode! */
+		if (gup_enter_update_mode(gt_client) ==  FAIL) {
 			ret = -EBUSY;
 			goto exit;
 		}
-	} else if (cmd_head.wr == 13) { /* Leave update mode! */
-		gup_leave_update_mode();
-	} else if (cmd_head.wr == 15) { /* Update firmware! */
+	} else if (cmd_head.wr == GTP_RW_LEAVE_UPDATE_MODE) {
+		/* Leave update mode! */
+		gup_leave_update_mode(gt_client);
+	} else if (cmd_head.wr == GTP_RW_UPDATE_FW) {
+		/* Update firmware! */
 		show_len = 0;
 		total_len = 0;
-		if (cmd_head.data_len + 1 > DATA_LENGTH) {
-			pr_err("<<-GTP->> data len %d > data buff %d, rejected!\n",
-			cmd_head.data_len + 1, DATA_LENGTH);
+		if (cmd_head.data_len + 1 > data_length) {
+			dev_err(&gt_client->dev, "data len %d > data buff %d, rejected!\n",
+			cmd_head.data_len + 1, data_length);
 			ret = -EINVAL;
 			goto exit;
 		}
 		memset(cmd_head.data, 0, cmd_head.data_len + 1);
-		memcpy(cmd_head.data, &buff[CMD_HEAD_LENGTH],
+		memcpy(cmd_head.data, &userbuf[CMD_HEAD_LENGTH],
 					cmd_head.data_len);
 
-		if (FAIL == gup_update_proc((void *)cmd_head.data)) {
+		if (gup_update_proc((void *)cmd_head.data) == FAIL) {
 			ret = -EBUSY;
 			goto exit;
 		}
 	}
-#endif
 	ret = CMD_HEAD_LENGTH;
 
 exit:
@@ -511,95 +471,130 @@
 Function:
     Goodix tool read function.
 Input:
-  standard proc read function param.
+  standard seq file read function param.
 Output:
     Return read length.
 ********************************************************/
-static s32 goodix_tool_read(char *page, char **start, off_t off, int count,
-							int *eof, void *data)
+static s32 goodix_tool_read(struct file *file, char __user *user_buf,
+					size_t count, loff_t *ppos)
 {
+	u16 data_len = 0;
 	s32 ret;
-	GTP_DEBUG_FUNC();
+	u8 buf[32];
 
 	mutex_lock(&lock);
-	if (cmd_head.wr % 2) {
-		pr_err("<< [READ]command head wrong\n");
+	if (cmd_head.wr & 0x1) {
+		dev_err(&gt_client->dev, "command head wrong\n");
 		ret = -EINVAL;
 		goto exit;
-	} else if (!cmd_head.wr) {
-		u16 len = 0;
-		s16 data_len = 0;
-		u16 loc = 0;
+	}
 
-		if (cmd_head.flag == 1) {
-			if (FAIL == comfirm()) {
-				GTP_ERROR("[READ]Comfirm fail!");
+	switch (cmd_head.wr) {
+	case GTP_RW_READ:
+		if (cmd_head.flag == GTP_NEED_FLAG) {
+			if (comfirm() == FAIL) {
+				dev_err(&gt_client->dev, "Comfirm fail!");
 				ret = -EINVAL;
 				goto exit;
 			}
-		} else if (cmd_head.flag == 2) {
+		} else if (cmd_head.flag == GTP_NEED_INTERRUPT) {
 			/* Need interrupt! */
 		}
 
 		memcpy(cmd_head.data, cmd_head.addr, cmd_head.addr_len);
 
-		GTP_DEBUG("[CMD HEAD DATA] ADDR:0x%02x%02x.", cmd_head.data[0],
+		pr_debug("[CMD HEAD DATA] ADDR:0x%02x%02x.", cmd_head.data[0],
 							cmd_head.data[1]);
-		GTP_DEBUG("[CMD HEAD ADDR] ADDR:0x%02x%02x.", cmd_head.addr[0],
+		pr_debug("[CMD HEAD ADDR] ADDR:0x%02x%02x.", cmd_head.addr[0],
 							cmd_head.addr[1]);
 
 		if (cmd_head.delay)
 			msleep(cmd_head.delay);
 
 		data_len = cmd_head.data_len;
-		while (data_len > 0) {
-			if (data_len > DATA_LENGTH)
-				len = DATA_LENGTH;
-			else
-				len = data_len;
-
-			data_len -= len;
-
-			if (tool_i2c_read(cmd_head.data, len) <= 0) {
-				GTP_ERROR("[READ]Read data failed!");
-				ret = -EINVAL;
-				goto exit;
-			}
-			memcpy(&page[loc], &cmd_head.data[GTP_ADDR_LENGTH],
-									len);
-			loc += len;
-
-			GTP_DEBUG_ARRAY(&cmd_head.data[GTP_ADDR_LENGTH], len);
-			GTP_DEBUG_ARRAY(page, len);
+		if (data_len <= 0 || (data_len > data_length)) {
+			dev_err(&gt_client->dev, "Invalid data length %d\n",
+				data_len);
+			ret = -EINVAL;
+			goto exit;
 		}
-	} else if (cmd_head.wr == 2) {
-		/* memcpy(page, "gt8", cmd_head.data_len);
-		memcpy(page, "GT818", 5);
-		page[5] = 0; */
+		if (data_len > count)
+			data_len = count;
 
-		GTP_DEBUG("Return ic type:%s len:%d.", page,
-						(s32)cmd_head.data_len);
-		ret = cmd_head.data_len;
-		goto exit;
-		/* return sizeof(IC_TYPE_NAME); */
-	} else if (cmd_head.wr == 4) {
-		page[0] = show_len >> 8;
-		page[1] = show_len & 0xff;
-		page[2] = total_len >> 8;
-		page[3] = total_len & 0xff;
-	} else if (6 == cmd_head.wr) {
-		/* Read error code! */
-	} else if (8 == cmd_head.wr) { /*Read driver version */
-		/* memcpy(page, GTP_DRIVER_VERSION,
-				strlen(GTP_DRIVER_VERSION)); */
-		s32 tmp_len;
-		tmp_len = strlen(GTP_DRIVER_VERSION);
-		memcpy(page, GTP_DRIVER_VERSION, tmp_len);
-		page[tmp_len] = 0;
+		if (tool_i2c_read(cmd_head.data, data_len) <= 0) {
+			dev_err(&gt_client->dev, "Read data failed!\n");
+			ret = -EIO;
+			goto exit;
+		}
+		ret = simple_read_from_buffer(user_buf, count, ppos,
+			&cmd_head.data[GTP_ADDR_LENGTH], data_len);
+		break;
+	case GTP_RW_FILL_INFO:
+		ret = fill_update_info(user_buf, count, ppos);
+		break;
+	case GTP_RW_READ_VERSION:
+		/* Read driver version */
+		data_len = scnprintf(buf, sizeof(buf), "%s\n",
+			GTP_DRIVER_VERSION);
+		ret = simple_read_from_buffer(user_buf, count, ppos,
+			buf, data_len);
+		break;
+	default:
+		ret = -EINVAL;
+		break;
 	}
-	ret = cmd_head.data_len;
 
 exit:
 	mutex_unlock(&lock);
 	return ret;
 }
+
+static const struct file_operations goodix_proc_fops = {
+	.write = goodix_tool_write,
+	.read = goodix_tool_read,
+	.open = simple_open,
+	.owner = THIS_MODULE,
+};
+
+s32 init_wr_node(struct i2c_client *client)
+{
+	u8 i;
+
+	gt_client = client;
+	memset(&cmd_head, 0, sizeof(cmd_head));
+	cmd_head.data = NULL;
+
+	i = GTP_I2C_RETRY_5;
+	while ((!cmd_head.data) && i) {
+		cmd_head.data = devm_kzalloc(&client->dev,
+				i * DATA_LENGTH_UINT, GFP_KERNEL);
+		if (cmd_head.data)
+			break;
+		i--;
+	}
+	if (i) {
+		data_length = i * DATA_LENGTH_UINT;
+		dev_dbg(&client->dev, "Applied memory size:%d.", data_length);
+	} else {
+		dev_err(&client->dev, "Apply for memory failed.");
+		return FAIL;
+	}
+
+	cmd_head.addr_len = 2;
+	cmd_head.retry = GTP_I2C_RETRY_5;
+
+	register_i2c_func();
+
+	mutex_init(&lock);
+	tool_set_proc_name(procname);
+	goodix_proc_entry = proc_create(procname,
+			S_IWUSR | S_IWGRP | S_IRUSR | S_IRGRP,
+			goodix_proc_entry,
+			&goodix_proc_fops);
+	if (goodix_proc_entry == NULL) {
+		dev_err(&client->dev, "Couldn't create proc entry!");
+		return FAIL;
+	}
+
+	return SUCCESS;
+}
diff --git a/drivers/input/touchscreen/gt9xx/gt9xx.c b/drivers/input/touchscreen/gt9xx/gt9xx.c
index b39cb0d..0d75869 100644
--- a/drivers/input/touchscreen/gt9xx/gt9xx.c
+++ b/drivers/input/touchscreen/gt9xx/gt9xx.c
@@ -1,6 +1,6 @@
 /* drivers/input/touchscreen/gt9xx.c
  *
- * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
  *
  * Linux Foundation chooses to take subject only to the GPLv2 license
  * terms, and distributes only under these terms.
@@ -47,17 +47,16 @@
 #include "gt9xx.h"
 
 #include <linux/of_gpio.h>
-
+#include <linux/irq.h>
+#include <linux/module.h>
 #include <linux/input/mt.h>
+#include <linux/debugfs.h>
 
 #define GOODIX_DEV_NAME	"Goodix-CTP"
 #define CFG_MAX_TOUCH_POINTS	5
 #define GOODIX_COORDS_ARR_SIZE	4
 #define MAX_BUTTONS		4
 
-/* HIGH: 0x28/0x29, LOW: 0xBA/0xBB */
-#define GTP_I2C_ADDRESS_HIGH	0x14
-#define GTP_I2C_ADDRESS_LOW	0x5D
 #define CFG_GROUP_LEN(p_cfg_grp)  (sizeof(p_cfg_grp) / sizeof(p_cfg_grp[0]))
 
 #define GOODIX_VTG_MIN_UV	2600000
@@ -78,21 +77,6 @@
 #define GTP_MAX_TOUCH		5
 #define GTP_ESD_CHECK_CIRCLE_MS	2000
 
-#if GTP_HAVE_TOUCH_KEY
-static const u16 touch_key_array[] = {KEY_MENU, KEY_HOMEPAGE, KEY_BACK};
-#define GTP_MAX_KEY_NUM  (sizeof(touch_key_array)/sizeof(touch_key_array[0]))
-
-#if GTP_DEBUG_ON
-static const int  key_codes[] = {
-	KEY_HOME, KEY_BACK, KEY_MENU, KEY_SEARCH
-};
-static const char *const key_names[] = {
-	"Key_Home", "Key_Back", "Key_Menu", "Key_Search"
-};
-#endif
-#endif
-
-static void gtp_reset_guitar(struct goodix_ts_data *ts, int ms);
 static void gtp_int_sync(struct goodix_ts_data *ts, int ms);
 static int gtp_i2c_test(struct i2c_client *client);
 static int goodix_power_off(struct goodix_ts_data *ts);
@@ -100,7 +84,9 @@
 
 #if defined(CONFIG_FB)
 static int fb_notifier_callback(struct notifier_block *self,
-				 unsigned long event, void *data);
+				unsigned long event, void *data);
+static int goodix_ts_suspend(struct device *dev);
+static int goodix_ts_resume(struct device *dev);
 #elif defined(CONFIG_HAS_EARLYSUSPEND)
 static void goodix_ts_early_suspend(struct early_suspend *h);
 static void goodix_ts_late_resume(struct early_suspend *h);
@@ -111,21 +97,25 @@
 static struct workqueue_struct *gtp_esd_check_workqueue;
 static void gtp_esd_check_func(struct work_struct *work);
 static int gtp_init_ext_watchdog(struct i2c_client *client);
-struct i2c_client  *i2c_connect_client;
 #endif
 
-#if GTP_SLIDE_WAKEUP
-enum doze_status {
+enum doze {
 	DOZE_DISABLED = 0,
 	DOZE_ENABLED = 1,
 	DOZE_WAKEUP = 2,
 };
-static enum doze_status = DOZE_DISABLED;
+static enum doze doze_status = DOZE_DISABLED;
 static s8 gtp_enter_doze(struct goodix_ts_data *ts);
-#endif
+
 bool init_done;
 static u8 chip_gt9xxs;  /* true if ic is gt9xxs, like gt915s */
 u8 grp_cfg_version;
+struct i2c_client  *i2c_connect_client;
+
+#define GTP_DEBUGFS_DIR			"ts_debug"
+#define GTP_DEBUGFS_FILE_SUSPEND	"suspend"
+#define GTP_DEBUGFS_FILE_DATA		"data"
+#define GTP_DEBUGFS_FILE_ADDR		"addr"
 
 /*******************************************************
 Function:
@@ -142,37 +132,40 @@
 int gtp_i2c_read(struct i2c_client *client, u8 *buf, int len)
 {
 	struct goodix_ts_data *ts = i2c_get_clientdata(client);
-	struct i2c_msg msgs[2];
 	int ret = -EIO;
-	int retries = 0;
+	u8 retries;
+	struct i2c_msg msgs[2] = {
+		{
+			.flags	= !I2C_M_RD,
+			.addr	= client->addr,
+			.len	= GTP_ADDR_LENGTH,
+			.buf	= &buf[0],
+		},
+		{
+			.flags	= I2C_M_RD,
+			.addr	= client->addr,
+			.len	= len - GTP_ADDR_LENGTH,
+			.buf	= &buf[GTP_ADDR_LENGTH],
+		},
+	};
 
-	msgs[0].flags = !I2C_M_RD;
-	msgs[0].addr = client->addr;
-	msgs[0].len = GTP_ADDR_LENGTH;
-	msgs[0].buf = &buf[0];
-
-	msgs[1].flags = I2C_M_RD;
-	msgs[1].addr = client->addr;
-	msgs[1].len = len - GTP_ADDR_LENGTH;
-	msgs[1].buf = &buf[GTP_ADDR_LENGTH];
-
-	while (retries < 5) {
+	for (retries = 0; retries < GTP_I2C_RETRY_5; retries++) {
 		ret = i2c_transfer(client->adapter, msgs, 2);
 		if (ret == 2)
 			break;
-		retries++;
+		dev_err(&client->dev, "I2C retry: %d\n", retries + 1);
 	}
-	if (retries >= 5) {
-#if GTP_SLIDE_WAKEUP
-		/* reset chip would quit doze mode */
-		if (DOZE_ENABLED == doze_status)
-			return ret;
-#endif
+	if (retries == GTP_I2C_RETRY_5) {
+		if (ts->pdata->slide_wakeup)
+			/* reset chip would quit doze mode */
+			if (DOZE_ENABLED == doze_status)
+				return ret;
+
 		if (init_done)
 			gtp_reset_guitar(ts, 10);
 		else
 			dev_warn(&client->dev,
-				"<GTP> gtp_reset_guitar exit init_done=%d:\n",
+				"gtp_reset_guitar exit init_done=%d:\n",
 				init_done);
 	}
 	return ret;
@@ -193,35 +186,36 @@
 int gtp_i2c_write(struct i2c_client *client, u8 *buf, int len)
 {
 	struct goodix_ts_data *ts = i2c_get_clientdata(client);
-	struct i2c_msg msg;
 	int ret = -EIO;
-	int retries = 0;
+	u8 retries;
+	struct i2c_msg msg = {
+		.flags = !I2C_M_RD,
+		.addr = client->addr,
+		.len = len,
+		.buf = buf,
+	};
 
-	msg.flags = !I2C_M_RD;
-	msg.addr = client->addr;
-	msg.len = len;
-	msg.buf = buf;
-
-	while (retries < 5) {
+	for (retries = 0; retries < GTP_I2C_RETRY_5; retries++) {
 		ret = i2c_transfer(client->adapter, &msg, 1);
 		if (ret == 1)
 			break;
-		retries++;
+		dev_err(&client->dev, "I2C retry: %d\n", retries + 1);
 	}
-	if ((retries >= 5)) {
-#if GTP_SLIDE_WAKEUP
-		if (DOZE_ENABLED == doze_status)
-			return ret;
-#endif
+	if ((retries == GTP_I2C_RETRY_5)) {
+		if (ts->pdata->slide_wakeup)
+			if (DOZE_ENABLED == doze_status)
+				return ret;
+
 		if (init_done)
 			gtp_reset_guitar(ts, 10);
 		else
 			dev_warn(&client->dev,
-				"<GTP> gtp_reset_guitar exit init_done=%d:\n",
+				"gtp_reset_guitar exit init_done=%d:\n",
 				init_done);
 	}
 	return ret;
 }
+
 /*******************************************************
 Function:
 	i2c read twice, compare the results
@@ -241,7 +235,7 @@
 	u8 confirm_buf[16] = {0};
 	u8 retry = 0;
 
-	while (retry++ < 3) {
+	while (retry++ < GTP_I2C_RETRY_3) {
 		memset(buf, 0xAA, 16);
 		buf[0] = (u8)(addr >> 8);
 		buf[1] = (u8)(addr & 0xFF);
@@ -255,7 +249,7 @@
 		if (!memcmp(buf, confirm_buf, len + 2))
 			break;
 	}
-	if (retry < 3) {
+	if (retry < GTP_I2C_RETRY_3) {
 		memcpy(rxbuf, confirm_buf + 2, len);
 		return SUCCESS;
 	} else {
@@ -275,26 +269,27 @@
 	result of i2c write operation.
 	> 0: succeed, otherwise: failed
 *********************************************************/
-static int gtp_send_cfg(struct goodix_ts_data *ts)
+int gtp_send_cfg(struct goodix_ts_data *ts)
 {
-	int ret;
-#if GTP_DRIVER_SEND_CFG
-	int retry = 0;
+	int ret = 0;
+	int retry;
 
-	if (ts->fixed_cfg) {
-		dev_dbg(&ts->client->dev,
-			"Ic fixed config, no config sent!");
-		ret = 2;
-	} else {
-		for (retry = 0; retry < 5; retry++) {
-			ret = gtp_i2c_write(ts->client,
-				ts->config_data,
-				GTP_CONFIG_MAX_LENGTH + GTP_ADDR_LENGTH);
-			if (ret > 0)
-				break;
+	if (ts->pdata->driver_send_cfg) {
+		if (ts->fixed_cfg) {
+			dev_dbg(&ts->client->dev,
+				"Ic fixed config, no config sent!");
+			ret = 2;
+		} else {
+			for (retry = 0; retry < GTP_I2C_RETRY_5; retry++) {
+				ret = gtp_i2c_write(ts->client,
+					ts->config_data,
+					GTP_CONFIG_MAX_LENGTH +
+						GTP_ADDR_LENGTH);
+				if (ret > 0)
+					break;
+			}
 		}
 	}
-#endif
 
 	return ret;
 }
@@ -354,9 +349,8 @@
 static void gtp_touch_down(struct goodix_ts_data *ts, int id, int x, int y,
 		int w)
 {
-#if GTP_CHANGE_X2Y
-	swap(x, y);
-#endif
+	if (ts->pdata->change_x2y)
+		swap(x, y);
 
 	input_mt_slot(ts->input_dev, id);
 	input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, true);
@@ -401,9 +395,7 @@
 	u8 finger = 0;
 	static u16 pre_touch;
 	static u8 pre_key;
-#if GTP_WITH_PEN
 	static u8 pre_pen;
-#endif
 	u8 key_value = 0;
 	u8 *coor_data = NULL;
 	s32 input_x = 0;
@@ -413,10 +405,7 @@
 	s32 i = 0;
 	int ret = -1;
 	struct goodix_ts_data *ts = NULL;
-
-#if GTP_SLIDE_WAKEUP
 	u8 doze_buf[3] = {0x81, 0x4B};
-#endif
 
 	ts = container_of(work, struct goodix_ts_data, work);
 #ifdef CONFIG_GT9XX_TOUCHPANEL_UPDATE
@@ -424,55 +413,59 @@
 		return;
 #endif
 
-#if GTP_SLIDE_WAKEUP
-	if (DOZE_ENABLED == doze_status) {
-		ret = gtp_i2c_read(ts->client, doze_buf, 3);
-		if (ret > 0) {
-			if (doze_buf[2] == 0xAA) {
-				dev_dbg(&ts->client->dev,
-					"Slide(0xAA) To Light up the screen!");
-				doze_status = DOZE_WAKEUP;
-				input_report_key(
-					ts->input_dev, KEY_POWER, 1);
-				input_sync(ts->input_dev);
-				input_report_key(
-					ts->input_dev, KEY_POWER, 0);
-				input_sync(ts->input_dev);
-				/* clear 0x814B */
-				doze_buf[2] = 0x00;
-				gtp_i2c_write(ts->client, doze_buf, 3);
-			} else if (doze_buf[2] == 0xBB) {
-				dev_dbg(&ts->client->dev,
-					"Slide(0xBB) To Light up the screen!");
-				doze_status = DOZE_WAKEUP;
-				input_report_key(ts->input_dev, KEY_POWER, 1);
-				input_sync(ts->input_dev);
-				input_report_key(ts->input_dev, KEY_POWER, 0);
-				input_sync(ts->input_dev);
-				/* clear 0x814B*/
-				doze_buf[2] = 0x00;
-				gtp_i2c_write(ts->client, doze_buf, 3);
-			} else if (0xC0 == (doze_buf[2] & 0xC0)) {
-				dev_dbg(&ts->client->dev,
-					"double click to light up the screen!");
-				doze_status = DOZE_WAKEUP;
-				input_report_key(ts->input_dev, KEY_POWER, 1);
-				input_sync(ts->input_dev);
-				input_report_key(ts->input_dev, KEY_POWER, 0);
-				input_sync(ts->input_dev);
-				/* clear 0x814B */
-				doze_buf[2] = 0x00;
-				gtp_i2c_write(ts->client, doze_buf, 3);
-			} else {
-				gtp_enter_doze(ts);
+	if (ts->pdata->slide_wakeup) {
+		if (DOZE_ENABLED == doze_status) {
+			ret = gtp_i2c_read(ts->client, doze_buf, 3);
+			if (ret > 0) {
+				if (doze_buf[2] == 0xAA) {
+					dev_dbg(&ts->client->dev,
+						"Slide(0xAA) To Light up the screen!");
+					doze_status = DOZE_WAKEUP;
+					input_report_key(
+						ts->input_dev, KEY_POWER, 1);
+					input_sync(ts->input_dev);
+					input_report_key(
+						ts->input_dev, KEY_POWER, 0);
+					input_sync(ts->input_dev);
+					/* clear 0x814B */
+					doze_buf[2] = 0x00;
+					gtp_i2c_write(ts->client, doze_buf, 3);
+				} else if (doze_buf[2] == 0xBB) {
+					dev_dbg(&ts->client->dev,
+						"Slide(0xBB) To Light up the screen!");
+					doze_status = DOZE_WAKEUP;
+					input_report_key(ts->input_dev,
+								KEY_POWER, 1);
+					input_sync(ts->input_dev);
+					input_report_key(ts->input_dev,
+								KEY_POWER, 0);
+					input_sync(ts->input_dev);
+					/* clear 0x814B*/
+					doze_buf[2] = 0x00;
+					gtp_i2c_write(ts->client, doze_buf, 3);
+				} else if (0xC0 == (doze_buf[2] & 0xC0)) {
+					dev_dbg(&ts->client->dev,
+						"double click to light up the screen!");
+					doze_status = DOZE_WAKEUP;
+					input_report_key(ts->input_dev,
+								KEY_POWER, 1);
+					input_sync(ts->input_dev);
+					input_report_key(ts->input_dev,
+								KEY_POWER, 0);
+					input_sync(ts->input_dev);
+					/* clear 0x814B */
+					doze_buf[2] = 0x00;
+					gtp_i2c_write(ts->client, doze_buf, 3);
+				} else {
+					gtp_enter_doze(ts);
+				}
 			}
-		}
-		if (ts->use_irq)
-			gtp_irq_enable(ts);
+			if (ts->use_irq)
+				gtp_irq_enable(ts);
 
-		return;
+			return;
+		}
 	}
-#endif
 
 	ret = gtp_i2c_read(ts->client, point_data, 12);
 	if (ret < 0) {
@@ -498,42 +491,31 @@
 		memcpy(&point_data[12], &buf[2], 8 * (touch_num - 1));
 	}
 
-#if GTP_HAVE_TOUCH_KEY
+
 	key_value = point_data[3 + 8 * touch_num];
 
 	if (key_value || pre_key) {
-		for (i = 0; i < GTP_MAX_KEY_NUM; i++) {
-
-#if GTP_DEBUG_ON
-			for (ret = 0; ret < 4; ++ret) {
-				if (key_codes[ret] == touch_key_array[i]) {
-					GTP_DEBUG("Key: %s %s",
-						key_names[ret],
-						(key_value & (0x01 << i))
-						? "Down" : "Up");
-					break;
-				}
-			}
-#endif
-
+		for (i = 0; i < ts->pdata->num_button; i++) {
 			input_report_key(ts->input_dev,
-				touch_key_array[i], key_value & (0x01<<i));
+				ts->pdata->button_map[i],
+				key_value & (0x01<<i));
 		}
 		touch_num = 0;
 		pre_touch = 0;
 	}
-#endif
+
 	pre_key = key_value;
 
-#if GTP_WITH_PEN
-	if (pre_pen && (touch_num == 0)) {
-		dev_dbg(&ts->client->dev, "Pen touch UP(Slot)!");
-		input_report_key(ts->input_dev, BTN_TOOL_PEN, 0);
-		input_mt_slot(ts->input_dev, 5);
-		input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, -1);
-		pre_pen = 0;
+	if (ts->pdata->with_pen) {
+		if (pre_pen && (touch_num == 0)) {
+			dev_dbg(&ts->client->dev, "Pen touch UP(Slot)!");
+			input_report_key(ts->input_dev, BTN_TOOL_PEN, 0);
+			input_mt_slot(ts->input_dev, 5);
+			input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, -1);
+			pre_pen = 0;
+		}
 	}
-#endif
+
 	if (pre_touch || touch_num) {
 		s32 pos = 0;
 		u16 touch_index = 0;
@@ -541,45 +523,45 @@
 		coor_data = &point_data[3];
 		if (touch_num) {
 			id = coor_data[pos] & 0x0F;
-#if GTP_WITH_PEN
-			id = coor_data[pos];
-			if (id == 128) {
-				dev_dbg(&ts->client->dev,
-						"Pen touch DOWN(Slot)!");
-				input_x  = coor_data[pos + 1]
-					| (coor_data[pos + 2] << 8);
-				input_y  = coor_data[pos + 3]
-					| (coor_data[pos + 4] << 8);
-				input_w  = coor_data[pos + 5]
-					| (coor_data[pos + 6] << 8);
+			if (ts->pdata->with_pen) {
+				id = coor_data[pos];
+				if (id == 128) {
+					dev_dbg(&ts->client->dev,
+							"Pen touch DOWN(Slot)!");
+					input_x  = coor_data[pos + 1]
+						| (coor_data[pos + 2] << 8);
+					input_y  = coor_data[pos + 3]
+						| (coor_data[pos + 4] << 8);
+					input_w  = coor_data[pos + 5]
+						| (coor_data[pos + 6] << 8);
 
-				input_report_key(ts->input_dev,
-					BTN_TOOL_PEN, 1);
-				input_mt_slot(ts->input_dev, 5);
-				input_report_abs(ts->input_dev,
-					ABS_MT_TRACKING_ID, 5);
-				input_report_abs(ts->input_dev,
-					ABS_MT_POSITION_X, input_x);
-				input_report_abs(ts->input_dev,
-					ABS_MT_POSITION_Y, input_y);
-				input_report_abs(ts->input_dev,
-					ABS_MT_TOUCH_MAJOR, input_w);
-				dev_dbg(&ts->client->dev,
-					"Pen/Stylus: (%d, %d)[%d]",
-					input_x, input_y, input_w);
-				pre_pen = 1;
-				pre_touch = 0;
+					input_report_key(ts->input_dev,
+						BTN_TOOL_PEN, 1);
+					input_mt_slot(ts->input_dev, 5);
+					input_report_abs(ts->input_dev,
+						ABS_MT_TRACKING_ID, 5);
+					input_report_abs(ts->input_dev,
+						ABS_MT_POSITION_X, input_x);
+					input_report_abs(ts->input_dev,
+						ABS_MT_POSITION_Y, input_y);
+					input_report_abs(ts->input_dev,
+						ABS_MT_TOUCH_MAJOR, input_w);
+					dev_dbg(&ts->client->dev,
+						"Pen/Stylus: (%d, %d)[%d]",
+						input_x, input_y, input_w);
+					pre_pen = 1;
+					pre_touch = 0;
+				}
 			}
-#endif
 
 			touch_index |= (0x01<<id);
 		}
 
 		for (i = 0; i < GTP_MAX_TOUCH; i++) {
-#if GTP_WITH_PEN
-			if (pre_pen == 1)
-				break;
-#endif
+			if (ts->pdata->with_pen)
+				if (pre_pen == 1)
+					break;
+
 			if (touch_index & (0x01<<i)) {
 				input_x = coor_data[pos + 1] |
 						coor_data[pos + 2] << 8;
@@ -618,26 +600,6 @@
 
 /*******************************************************
 Function:
-	Timer interrupt service routine for polling mode.
-Input:
-	timer: timer struct pointer
-Output:
-	Timer work mode.
-	HRTIMER_NORESTART: no restart mode
-*********************************************************/
-static enum hrtimer_restart goodix_ts_timer_handler(struct hrtimer *timer)
-{
-	struct goodix_ts_data
-		*ts = container_of(timer, struct goodix_ts_data, timer);
-
-	queue_work(ts->goodix_wq, &ts->work);
-	hrtimer_start(&ts->timer, ktime_set(0, (GTP_POLL_TIME + 6) * 1000000),
-			HRTIMER_MODE_REL);
-	return HRTIMER_NORESTART;
-}
-
-/*******************************************************
-Function:
 	External interrupt service routine for interrupt mode.
 Input:
 	irq:  interrupt number.
@@ -679,7 +641,7 @@
 Output:
 	None.
 *******************************************************/
-static void gtp_reset_guitar(struct goodix_ts_data *ts, int ms)
+void gtp_reset_guitar(struct goodix_ts_data *ts, int ms)
 {
 	/* This reset sequence will selcet I2C slave address */
 	gpio_direction_output(ts->pdata->reset_gpio, 0);
@@ -704,7 +666,6 @@
 }
 
 #if defined(CONFIG_HAS_EARLYSUSPEND) || defined(CONFIG_FB)
-#if GTP_SLIDE_WAKEUP
 /*******************************************************
 Function:
 	Enter doze mode for sliding wakeup.
@@ -721,12 +682,12 @@
 		(u8)(GTP_REG_SLEEP >> 8),
 		(u8)GTP_REG_SLEEP, 8};
 
-#if GTP_DBL_CLK_WAKEUP
-	i2c_control_buf[2] = 0x09;
-#endif
+	if (ts->pdata->dbl_clk_wakeup)
+		i2c_control_buf[2] = 0x09;
+
 	gtp_irq_disable(ts);
 
-	while (retry++ < 5) {
+	while (retry++ < GTP_I2C_RETRY_3) {
 		i2c_control_buf[0] = 0x80;
 		i2c_control_buf[1] = 0x46;
 		ret = gtp_i2c_write(ts->client, i2c_control_buf, 3);
@@ -752,17 +713,13 @@
 	gtp_irq_enable(ts);
 	return ret;
 }
-#else
-/*******************************************************
-Function:
-	Enter sleep mode.
-Input:
-	ts: private data.
-Output:
-	Executive outcomes.
-	>0: succeed, otherwise failed.
-*******************************************************/
-static s8 gtp_enter_sleep(struct goodix_ts_data  *ts)
+/**
+ * gtp_enter_sleep - Enter sleep mode
+ * @ts: driver private data
+ *
+ * Returns zero on success, else an error.
+ */
+static u8 gtp_enter_sleep(struct goodix_ts_data *ts)
 {
 	int ret = -1;
 	s8 retry = 0;
@@ -784,16 +741,16 @@
 		ret = goodix_power_off(ts);
 		if (ret) {
 			dev_err(&ts->client->dev, "GTP power off failed.\n");
-			return 0;
+			return ret;
 		}
-		return 1;
+		return 0;
 	} else {
 		usleep(5000);
-		while (retry++ < 5) {
+		while (retry++ < GTP_I2C_RETRY_5) {
 			ret = gtp_i2c_write(ts->client, i2c_control_buf, 3);
 			if (ret == 1) {
 				dev_dbg(&ts->client->dev, "GTP enter sleep!");
-				return ret;
+				return 0;
 			}
 			msleep(20);
 		}
@@ -801,7 +758,6 @@
 		return ret;
 	}
 }
-#endif /* !GTP_SLIDE_WAKEUP */
 
 /*******************************************************
 Function:
@@ -847,33 +803,33 @@
 				"Wakeup sleep send config success.");
 	} else {
 err_retry:
-#if GTP_SLIDE_WAKEUP
-		/* wakeup not by slide */
-		if (DOZE_WAKEUP != doze_status)
-			gtp_reset_guitar(ts, 10);
-		else
-			/* wakeup by slide */
-			doze_status = DOZE_DISABLED;
-#else
-		if (chip_gt9xxs == 1) {
-			gtp_reset_guitar(ts, 10);
+		if (ts->pdata->slide_wakeup) { /* wakeup not by slide */
+			if (DOZE_WAKEUP != doze_status)
+				gtp_reset_guitar(ts, 10);
+			else
+				/* wakeup by slide */
+				doze_status = DOZE_DISABLED;
 		} else {
-			ret = gpio_direction_output(ts->pdata->irq_gpio, 1);
-			usleep(5000);
+			if (chip_gt9xxs == 1) {
+				gtp_reset_guitar(ts, 10);
+			} else {
+				ret = gpio_direction_output(
+						ts->pdata->irq_gpio, 1);
+				usleep(5000);
+			}
 		}
-#endif
 		ret = gtp_i2c_test(ts->client);
 		if (ret == 2) {
 			dev_dbg(&ts->client->dev, "GTP wakeup sleep.");
-#if (!GTP_SLIDE_WAKEUP)
-			if (chip_gt9xxs == 0) {
-				gtp_int_sync(ts, 25);
-				msleep(20);
+			if (!ts->pdata->slide_wakeup) {
+				if (chip_gt9xxs == 0) {
+					gtp_int_sync(ts, 25);
+					msleep(20);
 #if GTP_ESD_PROTECT
-				gtp_init_ext_watchdog(ts->client);
+					gtp_init_ext_watchdog(ts->client);
 #endif
+				}
 			}
-#endif
 			return ret;
 		}
 		gtp_reset_guitar(ts, 20);
@@ -897,123 +853,126 @@
 static int gtp_init_panel(struct goodix_ts_data *ts)
 {
 	struct i2c_client *client = ts->client;
-	unsigned char *config_data;
+	unsigned char *config_data = NULL;
 	int ret = -EIO;
-
-#if GTP_DRIVER_SEND_CFG
 	int i;
 	u8 check_sum = 0;
 	u8 opr_buf[16];
 	u8 sensor_id = 0;
 
-	for (i = 0; i < GOODIX_MAX_CFG_GROUP; i++)
-		dev_dbg(&client->dev, "Config Groups(%d) Lengths: %d",
-			i, ts->pdata->config_data_len[i]);
+	if (ts->pdata->driver_send_cfg) {
+		for (i = 0; i < GOODIX_MAX_CFG_GROUP; i++)
+			dev_dbg(&client->dev, "Config Groups(%d) Lengths: %d",
+				i, ts->pdata->config_data_len[i]);
 
-	ret = gtp_i2c_read_dbl_check(ts->client, 0x41E4, opr_buf, 1);
-	if (SUCCESS == ret) {
-		if (opr_buf[0] != 0xBE) {
-			ts->fw_error = 1;
+		ret = gtp_i2c_read_dbl_check(ts->client, 0x41E4, opr_buf, 1);
+		if (SUCCESS == ret) {
+			if (opr_buf[0] != 0xBE) {
+				ts->fw_error = 1;
+				dev_err(&client->dev,
+					"Firmware error, no config sent!");
+				return -EINVAL;
+			}
+		}
+
+		for (i = 1; i < GOODIX_MAX_CFG_GROUP; i++) {
+			if (ts->pdata->config_data_len[i])
+				break;
+		}
+
+		if (i == GOODIX_MAX_CFG_GROUP) {
+			sensor_id = 0;
+		} else {
+			ret = gtp_i2c_read_dbl_check(ts->client,
+					GTP_REG_SENSOR_ID, &sensor_id, 1);
+			if (SUCCESS == ret) {
+				if (sensor_id >= GOODIX_MAX_CFG_GROUP) {
+					dev_err(&client->dev,
+						"Invalid sensor_id(0x%02X), No Config Sent!",
+						sensor_id);
+					return -EINVAL;
+				}
+			} else {
+				dev_err(&client->dev,
+					"Failed to get sensor_id, No config sent!");
+				return -EINVAL;
+			}
+		}
+
+		dev_info(&client->dev, "Sensor ID selected: %d", sensor_id);
+
+		if (ts->pdata->config_data_len[sensor_id] <
+			GTP_CONFIG_MIN_LENGTH ||
+			!ts->pdata->config_data[sensor_id]) {
 			dev_err(&client->dev,
-				"Firmware error, no config sent!");
+					"Sensor_ID(%d) matches with NULL or invalid config group!\n",
+					sensor_id);
 			return -EINVAL;
 		}
-	}
 
-	for (i = 1; i < GOODIX_MAX_CFG_GROUP; i++) {
-		if (ts->pdata->config_data_len[i])
-			break;
-	}
-	if (i == GOODIX_MAX_CFG_GROUP) {
-		sensor_id = 0;
-	} else {
-		ret = gtp_i2c_read_dbl_check(ts->client, GTP_REG_SENSOR_ID,
-			&sensor_id, 1);
-		if (SUCCESS == ret) {
-			if (sensor_id >= GOODIX_MAX_CFG_GROUP) {
-				dev_err(&client->dev,
-					"Invalid sensor_id(0x%02X), No Config Sent!",
-					sensor_id);
-				return -EINVAL;
+		ret = gtp_i2c_read_dbl_check(ts->client, GTP_REG_CONFIG_DATA,
+			&opr_buf[0], 1);
+		if (ret == SUCCESS) {
+			if (opr_buf[0] < 90) {
+				/* backup group config version */
+				grp_cfg_version =
+				ts->pdata->
+					config_data[sensor_id][GTP_ADDR_LENGTH];
+				ts->pdata->
+					config_data[sensor_id][GTP_ADDR_LENGTH]
+						= 0x00;
+				ts->fixed_cfg = 0;
+			} else {
+				/* treated as fixed config, not send config */
+				dev_warn(&client->dev,
+					"Ic fixed config with config version(%d, 0x%02X)",
+					opr_buf[0], opr_buf[0]);
+				ts->fixed_cfg = 1;
 			}
 		} else {
 			dev_err(&client->dev,
-				"Failed to get sensor_id, No config sent!");
+				"Failed to get ic config version!No config sent!");
 			return -EINVAL;
 		}
-	}
 
-	dev_info(&client->dev, "Sensor ID selected: %d", sensor_id);
-
-	if (ts->pdata->config_data_len[sensor_id] < GTP_CONFIG_MIN_LENGTH ||
-		!ts->pdata->config_data[sensor_id]) {
-		dev_err(&client->dev,
-				"Sensor_ID(%d) matches with NULL or invalid config group!\n",
-				sensor_id);
-		return -EINVAL;
-	}
-
-	ret = gtp_i2c_read_dbl_check(ts->client, GTP_REG_CONFIG_DATA,
-		&opr_buf[0], 1);
-	if (ret == SUCCESS) {
-		if (opr_buf[0] < 90) {
-			/* backup group config version */
-			grp_cfg_version =
-			ts->pdata->config_data[sensor_id][GTP_ADDR_LENGTH];
-			ts->pdata->config_data[sensor_id][GTP_ADDR_LENGTH] =
-				0x00;
-			ts->fixed_cfg = 0;
-		} else {
-			/* treated as fixed config, not send config */
-			dev_warn(&client->dev,
-				"Ic fixed config with config version(%d, 0x%02X)",
-				opr_buf[0], opr_buf[0]);
-			ts->fixed_cfg = 1;
-		}
-	} else {
-		dev_err(&client->dev,
-			"Failed to get ic config version!No config sent!");
-		return -EINVAL;
-	}
-
-	config_data = ts->pdata->config_data[sensor_id];
-	ts->config_data = ts->pdata->config_data[sensor_id];
-	ts->gtp_cfg_len = ts->pdata->config_data_len[sensor_id];
+		config_data = ts->pdata->config_data[sensor_id];
+		ts->config_data = ts->pdata->config_data[sensor_id];
+		ts->gtp_cfg_len = ts->pdata->config_data_len[sensor_id];
 
 #if GTP_CUSTOM_CFG
-	config_data[RESOLUTION_LOC] =
-	(unsigned char)(GTP_MAX_WIDTH && 0xFF);
-	config_data[RESOLUTION_LOC + 1] =
-	(unsigned char)(GTP_MAX_WIDTH >> 8);
-	config_data[RESOLUTION_LOC + 2] =
-	(unsigned char)(GTP_MAX_HEIGHT && 0xFF);
-	config_data[RESOLUTION_LOC + 3] =
-	(unsigned char)(GTP_MAX_HEIGHT >> 8);
+		config_data[RESOLUTION_LOC] =
+		(unsigned char)(GTP_MAX_WIDTH && 0xFF);
+		config_data[RESOLUTION_LOC + 1] =
+		(unsigned char)(GTP_MAX_WIDTH >> 8);
+		config_data[RESOLUTION_LOC + 2] =
+		(unsigned char)(GTP_MAX_HEIGHT && 0xFF);
+		config_data[RESOLUTION_LOC + 3] =
+		(unsigned char)(GTP_MAX_HEIGHT >> 8);
 
-	if (GTP_INT_TRIGGER == 0)
-		config_data[TRIGGER_LOC] &= 0xfe;
-	else if (GTP_INT_TRIGGER == 1)
-		config_data[TRIGGER_LOC] |= 0x01;
+		if (GTP_INT_TRIGGER == 0)
+			config_data[TRIGGER_LOC] &= 0xfe;
+		else if (GTP_INT_TRIGGER == 1)
+			config_data[TRIGGER_LOC] |= 0x01;
 #endif  /* !GTP_CUSTOM_CFG */
 
-	check_sum = 0;
-	for (i = GTP_ADDR_LENGTH; i < ts->gtp_cfg_len; i++)
-		check_sum += config_data[i];
+		check_sum = 0;
+		for (i = GTP_ADDR_LENGTH; i < ts->gtp_cfg_len; i++)
+			check_sum += config_data[i];
 
-	config_data[ts->gtp_cfg_len] = (~check_sum) + 1;
+		config_data[ts->gtp_cfg_len] = (~check_sum) + 1;
 
-#else /* DRIVER NOT SEND CONFIG */
-	ts->gtp_cfg_len = GTP_CONFIG_MAX_LENGTH;
-	ret = gtp_i2c_read(ts->client, config_data,
+	} else { /* DRIVER NOT SEND CONFIG */
+		ts->gtp_cfg_len = GTP_CONFIG_MAX_LENGTH;
+		ret = gtp_i2c_read(ts->client, config_data,
 			ts->gtp_cfg_len + GTP_ADDR_LENGTH);
-	if (ret < 0) {
-		dev_err(&client->dev,
+		if (ret < 0) {
+			dev_err(&client->dev,
 				"Read Config Failed, Using DEFAULT Resolution & INT Trigger!\n");
-		ts->abs_x_max = GTP_MAX_WIDTH;
-		ts->abs_y_max = GTP_MAX_HEIGHT;
-		ts->int_trigger_type = GTP_INT_TRIGGER;
-	}
-#endif /* !DRIVER NOT SEND CONFIG */
+			ts->abs_x_max = GTP_MAX_WIDTH;
+			ts->abs_y_max = GTP_MAX_HEIGHT;
+			ts->int_trigger_type = GTP_INT_TRIGGER;
+		}
+	} /* !DRIVER NOT SEND CONFIG */
 
 	if ((ts->abs_x_max == 0) && (ts->abs_y_max == 0)) {
 		ts->abs_x_max = (config_data[RESOLUTION_LOC + 1] << 8)
@@ -1077,7 +1036,7 @@
 
 	ret = gtp_i2c_read(client, buf, sizeof(buf));
 	if (ret < 0) {
-		dev_err(&client->dev, "GTP read version failed.\n");
+		dev_err(&client->dev, "GTP read product_id failed.\n");
 		return -EIO;
 	}
 
@@ -1112,7 +1071,7 @@
 static int gtp_i2c_test(struct i2c_client *client)
 {
 	u8 buf[3] = { GTP_REG_CONFIG_DATA >> 8, GTP_REG_CONFIG_DATA & 0xff };
-	int retry = 5;
+	int retry = GTP_I2C_RETRY_5;
 	int ret = -EIO;
 
 	while (retry--) {
@@ -1217,28 +1176,20 @@
 *******************************************************/
 static int gtp_request_irq(struct goodix_ts_data *ts)
 {
-	int ret;
+	int ret = 0;
 	const u8 irq_table[] = GTP_IRQ_TAB;
 
-	ret = request_irq(ts->client->irq, goodix_ts_irq_handler,
+	ret = request_threaded_irq(ts->client->irq, NULL,
+			goodix_ts_irq_handler,
 			irq_table[ts->int_trigger_type],
 			ts->client->name, ts);
 	if (ret) {
-		dev_err(&ts->client->dev, "Request IRQ failed!ERRNO:%d.\n",
-				ret);
-		gpio_direction_input(ts->pdata->irq_gpio);
-
-		hrtimer_init(&ts->timer, CLOCK_MONOTONIC,
-				HRTIMER_MODE_REL);
-		ts->timer.function = goodix_ts_timer_handler;
-		hrtimer_start(&ts->timer, ktime_set(1, 0),
-				HRTIMER_MODE_REL);
 		ts->use_irq = false;
 		return ret;
 	} else {
 		gtp_irq_disable(ts);
 		ts->use_irq = true;
-		return 0;
+		return ret;
 	}
 }
 
@@ -1255,9 +1206,7 @@
 {
 	int ret;
 	char phys[PHY_BUF_SIZE];
-#if GTP_HAVE_TOUCH_KEY
 	int index = 0;
-#endif
 
 	ts->input_dev = input_allocate_device();
 	if (ts->input_dev == NULL) {
@@ -1272,27 +1221,24 @@
 	__set_bit(INPUT_PROP_DIRECT, ts->input_dev->propbit);
 	input_mt_init_slots(ts->input_dev, 10);/* in case of "out of memory" */
 
-#if GTP_HAVE_TOUCH_KEY
-	for (index = 0; index < GTP_MAX_KEY_NUM; index++) {
-		input_set_capability(ts->input_dev,
-				EV_KEY, touch_key_array[index]);
+	if (ts->pdata->have_touch_key) {
+		for (index = 0; index < ts->pdata->num_button; index++) {
+			input_set_capability(ts->input_dev,
+				EV_KEY, ts->pdata->button_map[index]);
+		}
 	}
-#endif
 
-#if GTP_SLIDE_WAKEUP
-	input_set_capability(ts->input_dev, EV_KEY, KEY_POWER);
-#endif
+	if (ts->pdata->slide_wakeup)
+		input_set_capability(ts->input_dev, EV_KEY, KEY_POWER);
 
-#if GTP_WITH_PEN
-	/* pen support */
-	__set_bit(BTN_TOOL_PEN, ts->input_dev->keybit);
-	__set_bit(INPUT_PROP_DIRECT, ts->input_dev->propbit);
-	__set_bit(INPUT_PROP_POINTER, ts->input_dev->propbit);
-#endif
+	if (ts->pdata->with_pen) {  /* pen support */
+		__set_bit(BTN_TOOL_PEN, ts->input_dev->keybit);
+		__set_bit(INPUT_PROP_DIRECT, ts->input_dev->propbit);
+		__set_bit(INPUT_PROP_POINTER, ts->input_dev->propbit);
+	}
 
-#if GTP_CHANGE_X2Y
-	swap(ts->abs_x_max, ts->abs_y_max);
-#endif
+	if (ts->pdata->change_x2y)
+		swap(ts->abs_x_max, ts->abs_y_max);
 
 	input_set_abs_params(ts->input_dev, ABS_MT_POSITION_X,
 				0, ts->abs_x_max, 0, 0);
@@ -1572,12 +1518,105 @@
 	return size;
 }
 
+static ssize_t gtp_fw_upgrade_show(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	struct goodix_ts_data *ts = dev_get_drvdata(dev);
+	return snprintf(buf, 2, "%d\n", ts->fw_loading);
+}
+
+static ssize_t gtp_fw_upgrade_store(struct device *dev,
+				struct device_attribute *attr,
+				const char *buf, size_t size)
+{
+	struct goodix_ts_data *ts = dev_get_drvdata(dev);
+	unsigned int val;
+	int ret;
+
+	if (size > 2)
+		return -EINVAL;
+
+	if (sscanf(buf, "%u", &val) != 1);
+		return -EINVAL;
+
+	if (ts->gtp_is_suspend) {
+		dev_err(&ts->client->dev,
+			"Can't start fw upgrade. Device is in suspend state.");
+		return -EBUSY;
+	}
+
+	mutex_lock(&ts->input_dev->mutex);
+	if (!ts->fw_loading && val) {
+		disable_irq(ts->client->irq);
+		ts->fw_loading = true;
+		if (config_enabled(CONFIG_GT9XX_TOUCHPANEL_UPDATE)) {
+			ret = gup_update_proc(NULL);
+			if (ret == FAIL)
+				dev_err(&ts->client->dev,
+						"Fail to update GTP firmware.\n");
+		}
+		ts->fw_loading = false;
+		enable_irq(ts->client->irq);
+	}
+	mutex_unlock(&ts->input_dev->mutex);
+
+	return size;
+}
+
+static ssize_t gtp_force_fw_upgrade_store(struct device *dev,
+				struct device_attribute *attr,
+				const char *buf, size_t size)
+{
+	struct goodix_ts_data *ts = dev_get_drvdata(dev);
+	unsigned int val;
+	int ret;
+
+	if (size > 2)
+		return -EINVAL;
+
+	if (sscanf(buf, "%u", &val) != 1);
+		return -EINVAL;
+
+	if (ts->gtp_is_suspend) {
+		dev_err(&ts->client->dev,
+			"Can't start fw upgrade. Device is in suspend state.");
+		return -EBUSY;
+	}
+
+	mutex_lock(&ts->input_dev->mutex);
+	if (!ts->fw_loading && val) {
+		disable_irq(ts->client->irq);
+		ts->fw_loading = true;
+		ts->force_update = true;
+		if (config_enabled(CONFIG_GT9XX_TOUCHPANEL_UPDATE)) {
+			ret = gup_update_proc(NULL);
+			if (ret == FAIL)
+				dev_err(&ts->client->dev,
+				"Fail to force update GTP firmware.\n");
+		}
+		ts->force_update = false;
+		ts->fw_loading = false;
+		enable_irq(ts->client->irq);
+	}
+	mutex_unlock(&ts->input_dev->mutex);
+
+	return size;
+}
+
 static DEVICE_ATTR(fw_name, (S_IRUGO | S_IWUSR | S_IWGRP),
 			gtp_fw_name_show,
 			gtp_fw_name_store);
+static DEVICE_ATTR(fw_upgrade, (S_IRUGO | S_IWUSR | S_IWGRP),
+			gtp_fw_upgrade_show,
+			gtp_fw_upgrade_store);
+static DEVICE_ATTR(force_fw_upgrade, (S_IRUGO | S_IWUSR | S_IWGRP),
+			gtp_fw_upgrade_show,
+			gtp_force_fw_upgrade_store);
 
 static struct attribute *gtp_attrs[] = {
 	&dev_attr_fw_name.attr,
+	&dev_attr_fw_upgrade.attr,
+	&dev_attr_force_fw_upgrade.attr,
 	NULL
 };
 
@@ -1585,6 +1624,154 @@
 	.attrs = gtp_attrs,
 };
 
+static int gtp_debug_addr_is_valid(u16 addr)
+{
+	if (addr < GTP_VALID_ADDR_START || addr > GTP_VALID_ADDR_END) {
+		pr_err("GTP reg address is invalid: 0x%x\n", addr);
+		return false;
+	}
+
+	return true;
+}
+
+static int gtp_debug_data_set(void *_data, u64 val)
+{
+	struct goodix_ts_data *ts = _data;
+
+	mutex_lock(&ts->input_dev->mutex);
+	if (gtp_debug_addr_is_valid(ts->addr))
+		dev_err(&ts->client->dev,
+			"Writing to GTP registers not supported.\n");
+	mutex_unlock(&ts->input_dev->mutex);
+
+	return 0;
+}
+
+static int gtp_debug_data_get(void *_data, u64 *val)
+{
+	struct goodix_ts_data *ts = _data;
+	int ret;
+	u8 buf[3] = {0};
+
+	mutex_lock(&ts->input_dev->mutex);
+	buf[0] = ts->addr >> 8;
+	buf[1] = ts->addr & 0x00ff;
+
+	if (gtp_debug_addr_is_valid(ts->addr)) {
+		ret = gtp_i2c_read(ts->client, buf, 3);
+		if (ret < 0)
+			dev_err(&ts->client->dev,
+				"GTP read register 0x%x failed (%d)\n",
+				ts->addr, ret);
+		else
+			*val = buf[2];
+	}
+	mutex_unlock(&ts->input_dev->mutex);
+
+	return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(debug_data_fops, gtp_debug_data_get,
+				gtp_debug_data_set, "%llx\n");
+
+static int gtp_debug_addr_set(void *_data, u64 val)
+{
+	struct goodix_ts_data *ts = _data;
+
+	if (gtp_debug_addr_is_valid(val)) {
+		mutex_lock(&ts->input_dev->mutex);
+			ts->addr = val;
+		mutex_unlock(&ts->input_dev->mutex);
+	}
+
+	return 0;
+}
+
+static int gtp_debug_addr_get(void *_data, u64 *val)
+{
+	struct goodix_ts_data *ts = _data;
+
+	mutex_lock(&ts->input_dev->mutex);
+	if (gtp_debug_addr_is_valid(ts->addr))
+		*val = ts->addr;
+	mutex_unlock(&ts->input_dev->mutex);
+
+	return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(debug_addr_fops, gtp_debug_addr_get,
+				gtp_debug_addr_set, "%llx\n");
+
+static int gtp_debug_suspend_set(void *_data, u64 val)
+{
+	struct goodix_ts_data *ts = _data;
+
+	mutex_lock(&ts->input_dev->mutex);
+	if (val)
+		goodix_ts_suspend(&ts->client->dev);
+	else
+		goodix_ts_resume(&ts->client->dev);
+	mutex_unlock(&ts->input_dev->mutex);
+
+	return 0;
+}
+
+static int gtp_debug_suspend_get(void *_data, u64 *val)
+{
+	struct goodix_ts_data *ts = _data;
+
+	mutex_lock(&ts->input_dev->mutex);
+	*val = ts->gtp_is_suspend;
+	mutex_unlock(&ts->input_dev->mutex);
+
+	return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(debug_suspend_fops, gtp_debug_suspend_get,
+			gtp_debug_suspend_set, "%lld\n");
+
+static int gtp_debugfs_init(struct goodix_ts_data *data)
+{
+	data->debug_base = debugfs_create_dir(GTP_DEBUGFS_DIR, NULL);
+
+	if (IS_ERR_OR_NULL(data->debug_base)) {
+		dev_err(&data->client->dev, "Failed to create debugfs dir.\n");
+			return -EINVAL;
+	}
+
+	if ((IS_ERR_OR_NULL(debugfs_create_file(GTP_DEBUGFS_FILE_SUSPEND,
+					S_IWUSR | S_IWGRP | S_IRUSR | S_IRGRP,
+					data->debug_base,
+					data,
+					&debug_suspend_fops)))) {
+		dev_err(&data->client->dev, "Failed to create suspend file.\n");
+		debugfs_remove_recursive(data->debug_base);
+		return -EINVAL;
+	}
+
+	if ((IS_ERR_OR_NULL(debugfs_create_file(GTP_DEBUGFS_FILE_DATA,
+					S_IWUSR | S_IWGRP | S_IRUSR | S_IRGRP,
+					data->debug_base,
+					data,
+					&debug_data_fops)))) {
+		dev_err(&data->client->dev, "Failed to create data file.\n");
+		debugfs_remove_recursive(data->debug_base);
+		return -EINVAL;
+	}
+
+	if ((IS_ERR_OR_NULL(debugfs_create_file(GTP_DEBUGFS_FILE_ADDR,
+					S_IWUSR | S_IWGRP | S_IRUSR | S_IRGRP,
+					data->debug_base,
+					data,
+					&debug_addr_fops)))) {
+		dev_err(&data->client->dev, "Failed to create addr file.\n");
+		debugfs_remove_recursive(data->debug_base);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
 static int goodix_ts_get_dt_coords(struct device *dev, char *name,
 				struct goodix_ts_platform_data *pdata)
 {
@@ -1646,11 +1833,30 @@
 	pdata->i2c_pull_up = of_property_read_bool(np,
 						"goodix,i2c-pull-up");
 
-	pdata->no_force_update = of_property_read_bool(np,
-						"goodix,no-force-update");
+	pdata->force_update = of_property_read_bool(np,
+						"goodix,force-update");
 
 	pdata->enable_power_off = of_property_read_bool(np,
 						"goodix,enable-power-off");
+
+	pdata->have_touch_key = of_property_read_bool(np,
+						"goodix,have-touch-key");
+
+	pdata->driver_send_cfg = of_property_read_bool(np,
+						"goodix,driver-send-cfg");
+
+	pdata->change_x2y = of_property_read_bool(np,
+						"goodix,change-x2y");
+
+	pdata->with_pen = of_property_read_bool(np,
+						"goodix,with-pen");
+
+	pdata->slide_wakeup = of_property_read_bool(np,
+						"goodix,slide-wakeup");
+
+	pdata->dbl_clk_wakeup = of_property_read_bool(np,
+						"goodix,dbl_clk_wakeup");
+
 	/* reset, irq gpio info */
 	pdata->reset_gpio = of_get_named_gpio_flags(np, "reset-gpios",
 				0, &pdata->reset_gpio_flags);
@@ -1689,6 +1895,9 @@
 			dev_err(dev, "Unable to read key codes\n");
 			return rc;
 		}
+		pdata->num_button = num_buttons;
+		memcpy(pdata->button_map, button_map,
+			pdata->num_button * sizeof(u32));
 	}
 
 	read_cfg_num = 0;
@@ -1762,16 +1971,14 @@
 		return -EINVAL;
 	}
 
-#if GTP_ESD_PROTECT
 	i2c_connect_client = client;
-#endif
 
 	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
 		dev_err(&client->dev, "GTP I2C not supported\n");
 		return -ENODEV;
 	}
 
-	ts = kzalloc(sizeof(*ts), GFP_KERNEL);
+	ts = devm_kzalloc(&client->dev, sizeof(*ts), GFP_KERNEL);
 	if (!ts) {
 		dev_err(&client->dev, "GTP not enough memory for ts\n");
 		return -ENOMEM;
@@ -1814,19 +2021,21 @@
 		goto exit_power_off;
 	}
 
+	if (pdata->force_update)
+		ts->force_update = true;
+
 	if (pdata->fw_name)
 		strlcpy(ts->fw_name, pdata->fw_name,
 						strlen(pdata->fw_name) + 1);
 
-#if GTP_AUTO_UPDATE
-	ret = gup_init_update_proc(ts);
-	if (ret < 0) {
-		dev_err(&client->dev,
-			"GTP Create firmware update thread error.\n");
-		goto exit_power_off;
+	if (config_enabled(CONFIG_GT9XX_TOUCHPANEL_UPDATE)) {
+		ret = gup_init_update_proc(ts);
+		if (ret < 0) {
+			dev_err(&client->dev,
+					"GTP Create firmware update thread error.\n");
+			goto exit_power_off;
+		}
 	}
-#endif
-
 	ret = gtp_init_panel(ts);
 	if (ret < 0) {
 		dev_err(&client->dev, "GTP init panel failed.\n");
@@ -1861,13 +2070,13 @@
 	INIT_WORK(&ts->work, goodix_ts_work_func);
 
 	ret = gtp_request_irq(ts);
-	if (ret < 0)
-		dev_info(&client->dev, "GTP works in polling mode.\n");
+	if (ret)
+		dev_info(&client->dev, "GTP request irq failed %d.\n", ret);
 	else
 		dev_info(&client->dev, "GTP works in interrupt mode.\n");
 
 	ret = gtp_read_fw_version(client, &version_info);
-	if (ret != 0)
+	if (ret != 2)
 		dev_err(&client->dev, "GTP firmware version read failed.\n");
 
 	ret = gtp_check_product_id(client);
@@ -1878,7 +2087,7 @@
 	if (ts->use_irq)
 		gtp_irq_enable(ts);
 
-#if GTP_CREATE_WR_NODE
+#ifdef CONFIG_GT9XX_TOUCHPANEL_DEBUG
 	init_wr_node(client);
 #endif
 
@@ -1891,6 +2100,13 @@
 		goto exit_free_irq;
 	}
 
+	ret = gtp_debugfs_init(ts);
+	if (ret != 0) {
+		dev_err(&client->dev, "Failed to create debugfs entries, %d\n",
+						ret);
+		goto exit_remove_sysfs;
+	}
+
 	init_done = true;
 	return 0;
 exit_free_irq:
@@ -1904,8 +2120,6 @@
 #endif
 	if (ts->use_irq)
 		free_irq(client->irq, ts);
-	else
-		hrtimer_cancel(&ts->timer);
 	cancel_work_sync(&ts->work);
 	flush_workqueue(ts->goodix_wq);
 	destroy_workqueue(ts->goodix_wq);
@@ -1915,6 +2129,8 @@
 		input_free_device(ts->input_dev);
 		ts->input_dev = NULL;
 	}
+exit_remove_sysfs:
+	sysfs_remove_group(&ts->input_dev->dev.kobj, &gtp_attr_grp);
 exit_free_inputdev:
 	kfree(ts->config_data);
 exit_power_off:
@@ -1928,7 +2144,6 @@
 		gpio_free(pdata->irq_gpio);
 exit_free_client_data:
 	i2c_set_clientdata(client, NULL);
-	kfree(ts);
 	return ret;
 }
 
@@ -1955,7 +2170,7 @@
 #endif
 	mutex_destroy(&ts->lock);
 
-#if GTP_CREATE_WR_NODE
+#ifdef CONFIG_GT9XX_TOUCHPANEL_DEBUG
 	uninit_wr_node();
 #endif
 
@@ -1968,8 +2183,6 @@
 	if (ts) {
 		if (ts->use_irq)
 			free_irq(client->irq, ts);
-		else
-			hrtimer_cancel(&ts->timer);
 
 		cancel_work_sync(&ts->work);
 		flush_workqueue(ts->goodix_wq);
@@ -1980,7 +2193,6 @@
 			input_free_device(ts->input_dev);
 			ts->input_dev = NULL;
 		}
-		kfree(ts->config_data);
 
 		if (gpio_is_valid(ts->pdata->reset_gpio))
 			gpio_free(ts->pdata->reset_gpio);
@@ -1990,8 +2202,8 @@
 		goodix_power_off(ts);
 		goodix_power_deinit(ts);
 		i2c_set_clientdata(client, NULL);
-		kfree(ts);
 	}
+	debugfs_remove_recursive(ts->debug_base);
 
 	return 0;
 }
@@ -2010,34 +2222,45 @@
 	struct goodix_ts_data *ts = dev_get_drvdata(dev);
 	int ret = 0, i;
 
+	if (ts->gtp_is_suspend) {
+		dev_dbg(&ts->client->dev, "Already in suspend state.\n");
+		return 0;
+	}
+
 	mutex_lock(&ts->lock);
+
+	if (ts->fw_loading) {
+		dev_info(&ts->client->dev,
+			"Fw upgrade in progress, can't go to suspend.");
+		mutex_unlock(&ts->lock);
+		return 0;
+	}
+
 #if GTP_ESD_PROTECT
-	ts->gtp_is_suspend = 1;
 	gtp_esd_switch(ts->client, SWITCH_OFF);
 #endif
 
-#if GTP_SLIDE_WAKEUP
-	ret = gtp_enter_doze(ts);
-#else
-	if (ts->use_irq)
-		gtp_irq_disable(ts);
-	else
-		hrtimer_cancel(&ts->timer);
+	if (ts->pdata->slide_wakeup) {
+		ret = gtp_enter_doze(ts);
+	} else {
+		if (ts->use_irq)
+			gtp_irq_disable(ts);
 
-	for (i = 0; i < GTP_MAX_TOUCH; i++)
-		gtp_touch_up(ts, i);
+		for (i = 0; i < GTP_MAX_TOUCH; i++)
+			gtp_touch_up(ts, i);
 
-	input_sync(ts->input_dev);
+		input_sync(ts->input_dev);
 
-	ret = gtp_enter_sleep(ts);
-#endif
-	if (ret <= 0)
-		dev_err(&ts->client->dev, "GTP early suspend failed.\n");
+		ret = gtp_enter_sleep(ts);
+		if (ret < 0)
+			dev_err(&ts->client->dev, "GTP early suspend failed.\n");
+	}
 	/* to avoid waking up while not sleeping,
 	 * delay 48 + 10ms to ensure reliability
 	 */
 	msleep(58);
 	mutex_unlock(&ts->lock);
+	ts->gtp_is_suspend = 1;
 
 	return ret;
 }
@@ -2055,27 +2278,28 @@
 	struct goodix_ts_data *ts = dev_get_drvdata(dev);
 	int ret = 0;
 
+	if (!ts->gtp_is_suspend) {
+		dev_dbg(&ts->client->dev, "Already in awake state.\n");
+		return 0;
+	}
+
 	mutex_lock(&ts->lock);
 	ret = gtp_wakeup_sleep(ts);
 
-#if GTP_SLIDE_WAKEUP
-	doze_status = DOZE_DISABLED;
-#endif
+	if (ts->pdata->slide_wakeup)
+		doze_status = DOZE_DISABLED;
 
 	if (ret <= 0)
 		dev_err(&ts->client->dev, "GTP resume failed.\n");
 
 	if (ts->use_irq)
 		gtp_irq_enable(ts);
-	else
-		hrtimer_start(&ts->timer,
-			ktime_set(1, 0), HRTIMER_MODE_REL);
 
 #if GTP_ESD_PROTECT
-	ts->gtp_is_suspend = 0;
 	gtp_esd_switch(ts->client, SWITCH_ON);
 #endif
 	mutex_unlock(&ts->lock);
+	ts->gtp_is_suspend = 0;
 
 	return ret;
 }
@@ -2192,13 +2416,13 @@
 	msg.len   = 4;
 	msg.buf   = opr_buffer;
 
-	while (retries < 5) {
+	while (retries < GTP_I2C_RETRY_5) {
 		ret = i2c_transfer(client->adapter, &msg, 1);
 		if (ret == 1)
 			return 1;
 		retries++;
 	}
-	if (retries >= 5)
+	if (retries == GTP_I2C_RETRY_5)
 		dev_err(&client->dev, "init external watchdog failed!");
 	return 0;
 }
@@ -2214,7 +2438,7 @@
 *******************************************************/
 static void gtp_esd_check_func(struct work_struct *work)
 {
-	s32 i;
+	s32 retry;
 	s32 ret = -1;
 	struct goodix_ts_data *ts = NULL;
 	u8 test[4] = {0x80, 0x40};
@@ -2231,7 +2455,7 @@
 		return;
 #endif
 
-	for (i = 0; i < 3; i++) {
+	for (retry = 0; retry < GTP_I2C_RETRY_3; retry++) {
 		ret = gtp_i2c_read(ts->client, test, 4);
 
 		if ((ret < 0)) {
@@ -2240,7 +2464,7 @@
 		} else {
 			if ((test[2] == 0xAA) || (test[3] != 0xAA)) {
 				/* IC works abnormally..*/
-				i = 3;
+				retry = GTP_I2C_RETRY_3;
 				break;
 			} else {
 				/* IC works normally, Write 0x8040 0xAA*/
@@ -2250,7 +2474,7 @@
 			}
 		}
 	}
-	if (i >= 3) {
+	if (retry == GTP_I2C_RETRY_3) {
 		dev_err(&ts->client->dev,
 			"IC Working ABNORMALLY, Resetting Guitar...\n");
 		gtp_reset_guitar(ts, 50);
@@ -2268,8 +2492,15 @@
 }
 #endif
 
-static SIMPLE_DEV_PM_OPS(goodix_ts_dev_pm_ops, goodix_ts_suspend,
-					goodix_ts_resume);
+#if (!defined(CONFIG_FB) && !defined(CONFIG_HAS_EARLYSUSPEND))
+static const struct dev_pm_ops goodix_ts_dev_pm_ops = {
+	.suspend = goodix_ts_suspend,
+	.resume = goodix_ts_resume,
+};
+#else
+static const struct dev_pm_ops goodix_ts_dev_pm_ops = {
+};
+#endif
 
 static const struct i2c_device_id goodix_ts_id[] = {
 	{ GTP_I2C_NAME, 0 },
diff --git a/drivers/input/touchscreen/gt9xx/gt9xx.h b/drivers/input/touchscreen/gt9xx/gt9xx.h
index 1d31f2a..3cedf26 100644
--- a/drivers/input/touchscreen/gt9xx/gt9xx.h
+++ b/drivers/input/touchscreen/gt9xx/gt9xx.h
@@ -1,6 +1,6 @@
 /* drivers/input/touchscreen/gt9xx.h
  *
- * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
  *
  * Linux Foundation chooses to take subject only to the GPLv2 license
  * terms, and distributes only under these terms.
@@ -25,18 +25,9 @@
 
 #include <linux/kernel.h>
 #include <linux/i2c.h>
-#include <linux/irq.h>
-#include <linux/input.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
 #include <linux/delay.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
 #include <linux/gpio.h>
-#include <linux/regulator/consumer.h>
-#include <linux/firmware.h>
-#include <linux/debugfs.h>
-#include <linux/mutex.h>
+#include <linux/uaccess.h>
 
 #if defined(CONFIG_FB)
 #include <linux/notifier.h>
@@ -46,6 +37,7 @@
 #define GOODIX_SUSPEND_LEVEL 1
 #endif
 
+#define MAX_BUTTONS 4
 #define GOODIX_MAX_CFG_GROUP	6
 #define GTP_FW_NAME_MAXSIZE	50
 
@@ -64,11 +56,19 @@
 	u32 panel_miny;
 	u32 panel_maxx;
 	u32 panel_maxy;
-	bool no_force_update;
+	bool force_update;
 	bool i2c_pull_up;
 	bool enable_power_off;
 	size_t config_data_len[GOODIX_MAX_CFG_GROUP];
 	u8 *config_data[GOODIX_MAX_CFG_GROUP];
+	u32 button_map[MAX_BUTTONS];
+	u8 num_button;
+	bool have_touch_key;
+	bool driver_send_cfg;
+	bool change_x2y;
+	bool with_pen;
+	bool slide_wakeup;
+	bool dbl_clk_wakeup;
 };
 struct goodix_ts_data {
 	spinlock_t irq_lock;
@@ -79,10 +79,12 @@
 	struct workqueue_struct *goodix_wq;
 	struct work_struct	work;
 	char fw_name[GTP_FW_NAME_MAXSIZE];
+	struct delayed_work goodix_update_work;
 	s32 irq_is_disabled;
 	s32 use_irq;
 	u16 abs_x_max;
 	u16 abs_y_max;
+	u16 addr;
 	u8  max_touch_num;
 	u8  int_trigger_type;
 	u8  green_wake_mode;
@@ -97,6 +99,8 @@
 	u8  fw_error;
 	bool power_on;
 	struct mutex lock;
+	bool fw_loading;
+	bool force_update;
 	struct regulator *avdd;
 	struct regulator *vdd;
 	struct regulator *vcc_i2c;
@@ -105,6 +109,7 @@
 #elif defined(CONFIG_HAS_EARLYSUSPEND)
 	struct early_suspend early_suspend;
 #endif
+	struct dentry *debug_base;
 };
 
 extern u16 show_len;
@@ -112,49 +117,16 @@
 
 /***************************PART1:ON/OFF define*******************************/
 #define GTP_CUSTOM_CFG			0
-#define GTP_CHANGE_X2Y			0
-#define GTP_DRIVER_SEND_CFG		1
-#define GTP_HAVE_TOUCH_KEY		1
-
-/* auto updated by .bin file as default */
-#define GTP_AUTO_UPDATE			0
-/* auto updated by head_fw_array in gt9xx_firmware.h,
- * function together with GTP_AUTO_UPDATE */
-#define GTP_HEADER_FW_UPDATE	0
-
-#define GTP_CREATE_WR_NODE		0
 #define GTP_ESD_PROTECT			0
-#define GTP_WITH_PEN			0
 
-/* This cannot work when enable-power-off is on */
-#define GTP_SLIDE_WAKEUP		0
-/* double-click wakeup, function together with GTP_SLIDE_WAKEUP */
-#define GTP_DBL_CLK_WAKEUP		0
-
-#define GTP_DEBUG_ON			0
-#define GTP_DEBUG_ARRAY_ON		0
-#define GTP_DEBUG_FUNC_ON		0
-
-/*************************** PART2:TODO define *******************************/
-/* STEP_1(REQUIRED): Define Configuration Information Group(s) */
-/* Sensor_ID Map: */
-/* sensor_opt1 sensor_opt2 Sensor_ID
- *	GND			GND			0
- *	VDDIO		GND			1
- *	NC			GND			2
- *	GND			NC/300K		3
- *	VDDIO		NC/300K		4
- *	NC			NC/300K		5
-*/
-
-#define GTP_IRQ_TAB		{\
+#define GTP_IRQ_TAB            {\
 				IRQ_TYPE_EDGE_RISING,\
 				IRQ_TYPE_EDGE_FALLING,\
 				IRQ_TYPE_LEVEL_LOW,\
 				IRQ_TYPE_LEVEL_HIGH\
 				}
 
-/* STEP_3(optional): Specify your special config info if needed */
+
 #define GTP_IRQ_TAB_RISING	0
 #define GTP_IRQ_TAB_FALLING	1
 #if GTP_CUSTOM_CFG
@@ -193,53 +165,61 @@
 #define GTP_REG_FW_VERSION	0x8144
 #define GTP_REG_PRODUCT_ID	0x8140
 
+#define GTP_I2C_RETRY_3		3
+#define GTP_I2C_RETRY_5		5
+#define GTP_I2C_RETRY_10	10
+
 #define RESOLUTION_LOC		3
 #define TRIGGER_LOC		8
 
+/* HIGH: 0x28/0x29, LOW: 0xBA/0xBB */
+#define GTP_I2C_ADDRESS_HIGH	0x14
+#define GTP_I2C_ADDRESS_LOW	0x5D
+#define GTP_VALID_ADDR_START	0x8040
+#define GTP_VALID_ADDR_END	0x8177
+
 #define CFG_GROUP_LEN(p_cfg_grp) (sizeof(p_cfg_grp) / sizeof(p_cfg_grp[0]))
-/* Log define */
-#define GTP_DEBUG(fmt, arg...)	do {\
-		if (GTP_DEBUG_ON) {\
-			pr_debug("<<-GTP-DEBUG->> [%d]"fmt"\n",\
-				__LINE__, ##arg); } \
-		} while (0)
 
-#define GTP_DEBUG_ARRAY(array, num)    do {\
-		s32 i; \
-		u8 *a = array; \
-		if (GTP_DEBUG_ARRAY_ON) {\
-			pr_debug("<<-GTP-DEBUG-ARRAY->>\n");\
-			for (i = 0; i < (num); i++) { \
-				pr_debug("%02x   ", (a)[i]);\
-				if ((i + 1) % 10 == 0) { \
-					pr_debug("\n");\
-				} \
-			} \
-			pr_debug("\n");\
-		} \
-	} while (0)
+/* GTP CM_HEAD RW flags */
+#define GTP_RW_READ			0
+#define GTP_RW_WRITE			1
+#define GTP_RW_READ_IC_TYPE		2
+#define GTP_RW_WRITE_IC_TYPE		3
+#define GTP_RW_FILL_INFO		4
+#define GTP_RW_NO_WRITE			5
+#define GTP_RW_READ_ERROR		6
+#define GTP_RW_DISABLE_IRQ		7
+#define GTP_RW_READ_VERSION		8
+#define GTP_RW_ENABLE_IRQ		9
+#define GTP_RW_ENTER_UPDATE_MODE	11
+#define GTP_RW_LEAVE_UPDATE_MODE	13
+#define GTP_RW_UPDATE_FW		15
+#define GTP_RW_CHECK_RAWDIFF_MODE	17
 
-#define GTP_DEBUG_FUNC()	do {\
-	if (GTP_DEBUG_FUNC_ON)\
-		pr_debug("<<-GTP-FUNC->> Func:%s@Line:%d\n",\
-					__func__, __LINE__);\
-	} while (0)
+/* GTP need flag or interrupt */
+#define GTP_NO_NEED			0
+#define GTP_NEED_FLAG			1
+#define GTP_NEED_INTERRUPT		2
 
-#define GTP_SWAP(x, y)		do {\
-					typeof(x) z = x;\
-					x = y;\
-					y = z;\
-				} while (0)
 /*****************************End of Part III********************************/
 
 void gtp_esd_switch(struct i2c_client *client, int on);
 
-#if GTP_CREATE_WR_NODE
-extern s32 init_wr_node(struct i2c_client *client);
-extern void uninit_wr_node(void);
+int gtp_i2c_read_dbl_check(struct i2c_client *client, u16 addr,
+					u8 *rxbuf, int len);
+int gtp_send_cfg(struct goodix_ts_data *ts);
+void gtp_reset_guitar(struct goodix_ts_data *ts, int ms);
+void gtp_irq_disable(struct goodix_ts_data *ts);
+void gtp_irq_enable(struct goodix_ts_data *ts);
+
+#ifdef CONFIG_GT9XX_TOUCHPANEL_DEBUG
+s32 init_wr_node(struct i2c_client *client);
+void uninit_wr_node(void);
 #endif
 
-#if GTP_AUTO_UPDATE
-extern u8 gup_init_update_proc(struct goodix_ts_data *ts);
-#endif
+u8 gup_init_update_proc(struct goodix_ts_data *ts);
+s32 gup_enter_update_mode(struct i2c_client *client);
+void gup_leave_update_mode(struct i2c_client *client);
+s32 gup_update_proc(void *dir);
+extern struct i2c_client  *i2c_connect_client;
 #endif /* _GOODIX_GT9XX_H_ */
diff --git a/drivers/input/touchscreen/gt9xx/gt9xx_update.c b/drivers/input/touchscreen/gt9xx/gt9xx_update.c
index cf83154..af80eef 100644
--- a/drivers/input/touchscreen/gt9xx/gt9xx_update.c
+++ b/drivers/input/touchscreen/gt9xx/gt9xx_update.c
@@ -1,7 +1,7 @@
 /* drivers/input/touchscreen/gt9xx_update.c
  *
  * 2010 - 2012 Goodix Technology.
- * 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 as published by
@@ -31,25 +31,19 @@
  *          2. support firmware header array update.
  *                          By Meta, 2013/03/11
  */
-#include <linux/kthread.h>
 #include "gt9xx.h"
+#include <linux/firmware.h>
+#include <linux/workqueue.h>
+#include <linux/kernel.h>
 
-#if GTP_HEADER_FW_UPDATE
-#include <linux/namei.h>
-#include <linux/mount.h>
-#include "gt9xx_firmware.h"
-#endif
+#define FIRMWARE_NAME_LEN_MAX		256
 
 #define GUP_REG_HW_INFO             0x4220
 #define GUP_REG_FW_MSG              0x41E4
 #define GUP_REG_PID_VID             0x8140
 
-#define GUP_SEARCH_FILE_TIMES       50
-#define UPDATE_FILE_PATH_2          "/data/_goodix_update_.bin"
-#define UPDATE_FILE_PATH_1          "/sdcard/_goodix_update_.bin"
-
-#define CONFIG_FILE_PATH_1          "/data/_goodix_config_.cfg"
-#define CONFIG_FILE_PATH_2          "/sdcard/_goodix_config_.cfg"
+#define GOODIX_FIRMWARE_FILE_NAME	"_goodix_update_.bin"
+#define GOODIX_CONFIG_FILE_NAME		"_goodix_config_.cfg"
 
 #define FW_HEAD_LENGTH               14
 #define FW_SECTION_LENGTH            0x2000
@@ -73,24 +67,22 @@
 #define FAIL    0
 #define SUCCESS 1
 
-#pragma pack(1)
-struct {
+struct st_fw_head {
 	u8  hw_info[4];		/* hardware info */
 	u8  pid[8];		/* product id   */
 	u16 vid;		/* version id   */
-} st_fw_head;
-#pragma pack()
+} __packed;
 
-struct {
+struct st_update_msg {
 	u8 force_update;
 	u8 fw_flag;
-	struct file *file;
-	struct file *cfg_file;
-	st_fw_head  ic_fw_msg;
-	mm_segment_t old_fs;
-} st_update_msg;
+	bool need_free;
+	u8 *fw_data;
+	u32 fw_len;
+	struct st_fw_head  ic_fw_msg;
+};
 
-st_update_msg update_msg;
+static struct st_update_msg update_msg;
 u16 show_len;
 u16 total_len;
 u8 got_file_flag;
@@ -107,25 +99,24 @@
     numbers of i2c_msgs to transfer:
       2: succeed, otherwise: failed
 *********************************************************/
-s32 gup_i2c_read(struct i2c_client *client, u8 *buf, s32 len)
+static s32 gup_i2c_read(struct i2c_client *client, u8 *buf, s32 len)
 {
-	struct i2c_msg msgs[2];
 	s32 ret = -1;
-	s32 retries = 0;
-
-	GTP_DEBUG_FUNC();
-
-	msgs[0].flags = !I2C_M_RD;
-	msgs[0].addr  = client->addr;
-	msgs[0].len   = GTP_ADDR_LENGTH;
-	msgs[0].buf   = &buf[0];
-	/* msgs[0].scl_rate = 300 * 1000;  (for Rockchip) */
-
-	msgs[1].flags = I2C_M_RD;
-	msgs[1].addr  = client->addr;
-	msgs[1].len   = len - GTP_ADDR_LENGTH;
-	msgs[1].buf   = &buf[GTP_ADDR_LENGTH];
-	/* msgs[1].scl_rate = 300 * 1000; */
+	u8 retries = 0;
+	struct i2c_msg msgs[2] = {
+		{
+			.flags = !I2C_M_RD,
+			.addr  = client->addr,
+			.len   = GTP_ADDR_LENGTH,
+			.buf   = &buf[0],
+		},
+		{
+			.flags = I2C_M_RD,
+			.addr  = client->addr,
+			.len   = len - GTP_ADDR_LENGTH,
+			.buf   = &buf[GTP_ADDR_LENGTH],
+		},
+	};
 
 	while (retries < 5) {
 		ret = i2c_transfer(client->adapter, msgs, 2);
@@ -134,6 +125,11 @@
 		retries++;
 	}
 
+	if (retries == 5) {
+		dev_err(&client->dev, "I2C read retry limit over.\n");
+		ret = -EIO;
+	}
+
 	return ret;
 }
 
@@ -151,17 +147,14 @@
 *********************************************************/
 s32 gup_i2c_write(struct i2c_client *client, u8 *buf, s32 len)
 {
-	struct i2c_msg msg;
 	s32 ret = -1;
-	s32 retries = 0;
-
-	GTP_DEBUG_FUNC();
-
-	msg.flags = !I2C_M_RD;
-	msg.addr  = client->addr;
-	msg.len   = len;
-	msg.buf   = buf;
-	/* msg.scl_rate = 300 * 1000;    (for Rockchip) */
+	u8 retries = 0;
+	struct i2c_msg msg = {
+		.flags = !I2C_M_RD,
+		.addr  = client->addr,
+		.len   = len,
+		.buf   = buf,
+	};
 
 	while (retries < 5) {
 		ret = i2c_transfer(client->adapter, &msg, 1);
@@ -170,123 +163,105 @@
 		retries++;
 	}
 
+	if (retries == 5) {
+		dev_err(&client->dev, "I2C write retry limit over.\n");
+		ret = -EIO;
+	}
+
 	return ret;
 }
 
 static s32 gup_init_panel(struct goodix_ts_data *ts)
 {
+	struct i2c_client *client = ts->client;
+	u8 *config_data;
 	s32 ret = 0;
 	s32 i = 0;
 	u8 check_sum = 0;
 	u8 opr_buf[16];
 	u8 sensor_id = 0;
 
-	u8 cfg_info_group1[] = CTP_CFG_GROUP1;
-	u8 cfg_info_group2[] = CTP_CFG_GROUP2;
-	u8 cfg_info_group3[] = CTP_CFG_GROUP3;
-	u8 cfg_info_group4[] = CTP_CFG_GROUP4;
-	u8 cfg_info_group5[] = CTP_CFG_GROUP5;
-	u8 cfg_info_group6[] = CTP_CFG_GROUP6;
-	u8 *send_cfg_buf[] = {cfg_info_group1, cfg_info_group2, cfg_info_group3,
-			cfg_info_group4, cfg_info_group5, cfg_info_group6};
-	u8 cfg_info_len[] = { CFG_GROUP_LEN(cfg_info_group1),
-			CFG_GROUP_LEN(cfg_info_group2),
-			CFG_GROUP_LEN(cfg_info_group3),
-			CFG_GROUP_LEN(cfg_info_group4),
-			CFG_GROUP_LEN(cfg_info_group5),
-			CFG_GROUP_LEN(cfg_info_group6)};
+	for (i = 0; i < GOODIX_MAX_CFG_GROUP; i++)
+		if (ts->pdata->config_data_len[i])
+			break;
 
-	if ((!cfg_info_len[1]) && (!cfg_info_len[2]) &&
-	(!cfg_info_len[3]) && (!cfg_info_len[4]) &&
-	(!cfg_info_len[5])) {
+	if (i == GOODIX_MAX_CFG_GROUP) {
 		sensor_id = 0;
 	} else {
-		ret = gtp_i2c_read_dbl_check(ts->client, GTP_REG_SENSOR_ID,
+		ret = gtp_i2c_read_dbl_check(client, GTP_REG_SENSOR_ID,
 							&sensor_id, 1);
 		if (SUCCESS == ret) {
-			if (sensor_id >= 0x06) {
-				GTP_ERROR("Invalid sensor_id(0x%02X), " \
-					"No Config Sent!", sensor_id);
+			if (sensor_id >= GOODIX_MAX_CFG_GROUP) {
+				pr_err("Invalid sensor_id(0x%02X), No Config Sent!",
+					sensor_id);
 				return -EINVAL;
 			}
 		} else {
-			GTP_ERROR("Failed to get sensor_id, No config sent!");
+			pr_err("Failed to get sensor_id, No config sent!");
 			return -EINVAL;
 		}
 	}
 
-	GTP_DEBUG("Sensor_ID: %d", sensor_id);
+	pr_debug("Sensor ID selected: %d", sensor_id);
 
-	ts->gtp_cfg_len = cfg_info_len[sensor_id];
-
-	if (ts->gtp_cfg_len < GTP_CONFIG_MIN_LENGTH) {
-		GTP_ERROR("Sensor_ID(%d) matches with NULL or INVALID CONFIG" \
-			" GROUP! NO Config Sent! You need to check you header" \
-			"  file CFG_GROUP section!", sensor_id);
+	if (ts->pdata->config_data_len[sensor_id] < GTP_CONFIG_MIN_LENGTH ||
+		!ts->pdata->config_data_len[sensor_id]) {
+		pr_err("Sensor_ID(%d) matches with NULL or INVALID CONFIG GROUP!",
+				sensor_id);
 		return -EINVAL;
 	}
 
-	ret = gtp_i2c_read_dbl_check(ts->client, GTP_REG_CONFIG_DATA,
+	ret = gtp_i2c_read_dbl_check(client, GTP_REG_CONFIG_DATA,
 					&opr_buf[0], 1);
-
 	if (ret == SUCCESS) {
-		GTP_DEBUG("CFG_GROUP%d Config Version: %d, IC Config Version:" \
-		" %d", sensor_id+1, send_cfg_buf[sensor_id][0],	opr_buf[0]);
+		pr_debug("CFG_GROUP%d Config Version: %d, IC Config Version: %d",
+			sensor_id + 1,
+			ts->pdata->config_data[sensor_id][0],
+			opr_buf[0]);
 
-		send_cfg_buf[sensor_id][0] = opr_buf[0];
+		ts->pdata->config_data[sensor_id][0] = opr_buf[0];
 		ts->fixed_cfg = 0;
-		/*
-		if (opr_buf[0] < 90) {
-			grp_cfg_version = send_cfg_buf[sensor_id][0];
-				*** backup group config version ***
-			send_cfg_buf[sensor_id][0] = 0x00;
-			ts->fixed_cfg = 0;
-		} else { *** treated as fixed config, not send config ***
-			GTP_INFO("Ic fixed config with config version(%d)",
-							opr_buf[0]);
-			ts->fixed_cfg = 1;
-		}*/
 	} else {
-		GTP_ERROR("Failed to get ic config version!No config sent!");
+		pr_err("Failed to get ic config version!No config sent!");
 		return -EINVAL;
 	}
 
-	memset(&config[GTP_ADDR_LENGTH], 0, GTP_CONFIG_MAX_LENGTH);
-	memcpy(&config[GTP_ADDR_LENGTH], send_cfg_buf[sensor_id],
-						ts->gtp_cfg_len);
+	config_data = ts->pdata->config_data[sensor_id];
+	ts->config_data = ts->pdata->config_data[sensor_id];
+	ts->gtp_cfg_len = ts->pdata->config_data_len[sensor_id];
 
-	GTP_DEBUG("X_MAX = %d, Y_MAX = %d, TRIGGER = 0x%02x",
+	pr_debug("X_MAX = %d, Y_MAX = %d, TRIGGER = 0x%02x",
 	ts->abs_x_max, ts->abs_y_max, ts->int_trigger_type);
 
-	config[RESOLUTION_LOC]     = (u8)GTP_MAX_WIDTH;
-	config[RESOLUTION_LOC + 1] = (u8)(GTP_MAX_WIDTH>>8);
-	config[RESOLUTION_LOC + 2] = (u8)GTP_MAX_HEIGHT;
-	config[RESOLUTION_LOC + 3] = (u8)(GTP_MAX_HEIGHT>>8);
+	config_data[RESOLUTION_LOC]     = (u8)GTP_MAX_WIDTH;
+	config_data[RESOLUTION_LOC + 1] = (u8)(GTP_MAX_WIDTH>>8);
+	config_data[RESOLUTION_LOC + 2] = (u8)GTP_MAX_HEIGHT;
+	config_data[RESOLUTION_LOC + 3] = (u8)(GTP_MAX_HEIGHT>>8);
 
 	if (GTP_INT_TRIGGER == 0)  /* RISING */
-		config[TRIGGER_LOC] &= 0xfe;
+		config_data[TRIGGER_LOC] &= 0xfe;
 	else if (GTP_INT_TRIGGER == 1)  /* FALLING */
-		config[TRIGGER_LOC] |= 0x01;
+		config_data[TRIGGER_LOC] |= 0x01;
 
 	check_sum = 0;
 	for (i = GTP_ADDR_LENGTH; i < ts->gtp_cfg_len; i++)
-		check_sum += config[i];
+		check_sum += config_data[i];
 
-	config[ts->gtp_cfg_len] = (~check_sum) + 1;
+	config_data[ts->gtp_cfg_len] = (~check_sum) + 1;
 
-	GTP_DEBUG_FUNC();
-	ret = gtp_send_cfg(ts->client);
+	ret = gtp_send_cfg(ts);
 	if (ret < 0)
-		GTP_ERROR("Send config error.");
+		pr_err("Send config error.");
 
+	ts->config_data = NULL;
+	ts->gtp_cfg_len = 0;
 	msleep(20);
 	return 0;
 }
 
-
 static u8 gup_get_ic_msg(struct i2c_client *client, u16 addr, u8 *msg, s32 len)
 {
-	s32 i = 0;
+	u8 i = 0;
 
 	msg[0] = (addr >> 8) & 0xff;
 	msg[1] = addr & 0xff;
@@ -296,7 +271,7 @@
 			break;
 
 	if (i >= 5) {
-		GTP_ERROR("Read data from 0x%02x%02x failed!", msg[0], msg[1]);
+		pr_err("Read data from 0x%02x%02x failed!", msg[0], msg[1]);
 		return FAIL;
 	}
 
@@ -305,19 +280,19 @@
 
 static u8 gup_set_ic_msg(struct i2c_client *client, u16 addr, u8 val)
 {
-	s32 i = 0;
-	u8 msg[3];
-
-	msg[0] = (addr >> 8) & 0xff;
-	msg[1] = addr & 0xff;
-	msg[2] = val;
+	u8 i = 0;
+	u8 msg[3] = {
+		(addr >> 8) & 0xff,
+		addr & 0xff,
+		val,
+	};
 
 	for (i = 0; i < 5; i++)
 		if (gup_i2c_write(client, msg, GTP_ADDR_LENGTH + 1) > 0)
 			break;
 
 	if (i >= 5) {
-		GTP_ERROR("Set data to 0x%02x%02x failed!", msg[0], msg[1]);
+		pr_err("Set data to 0x%02x%02x failed!", msg[0], msg[1]);
 		return FAIL;
 	}
 
@@ -335,7 +310,7 @@
 	ret = gtp_i2c_read_dbl_check(client, GUP_REG_HW_INFO,
 					&buf[GTP_ADDR_LENGTH], 4);
 	if (ret == FAIL) {
-		GTP_ERROR("[get_ic_fw_msg]get hw_info failed,exit");
+		pr_err("get hw_info failed,exit");
 		return FAIL;
 	}
 
@@ -344,7 +319,7 @@
 	for (i = 0; i < 4; i++)
 		update_msg.ic_fw_msg.hw_info[i] = buf[GTP_ADDR_LENGTH + 3 - i];
 
-	GTP_DEBUG("IC Hardware info:%02x%02x%02x%02x",
+	pr_debug("IC Hardware info:%02x%02x%02x%02x",
 		update_msg.ic_fw_msg.hw_info[0],
 		update_msg.ic_fw_msg.hw_info[1],
 		update_msg.ic_fw_msg.hw_info[2],
@@ -354,31 +329,31 @@
 	for (retry = 0; retry < 2; retry++) {
 		ret = gup_get_ic_msg(client, GUP_REG_FW_MSG, buf, 1);
 		if (ret == FAIL) {
-			GTP_ERROR("Read firmware message fail.");
+			pr_err("Read firmware message fail.");
 			return ret;
 		}
 
 		update_msg.force_update = buf[GTP_ADDR_LENGTH];
 		if ((0xBE != update_msg.force_update) && (!retry)) {
-			GTP_INFO("The check sum in ic is error.");
-			GTP_INFO("The IC will be updated by force.");
+			pr_info("The check sum in ic is error.");
+			pr_info("The IC will be updated by force.");
 			continue;
 		}
 		break;
 	}
-	GTP_DEBUG("IC force update flag:0x%x", update_msg.force_update);
+	pr_debug("IC force update flag:0x%x", update_msg.force_update);
 
 	/*  step3:get pid & vid */
 	ret = gtp_i2c_read_dbl_check(client, GUP_REG_PID_VID,
 						&buf[GTP_ADDR_LENGTH], 6);
-	if (FAIL == ret) {
-		GTP_ERROR("[get_ic_fw_msg]get pid & vid failed,exit");
+	if (ret == FAIL) {
+		pr_err("get pid & vid failed,exit");
 		return FAIL;
 	}
 
 	memset(update_msg.ic_fw_msg.pid, 0, sizeof(update_msg.ic_fw_msg.pid));
 	memcpy(update_msg.ic_fw_msg.pid, &buf[GTP_ADDR_LENGTH], 4);
-	GTP_DEBUG("IC Product id:%s", update_msg.ic_fw_msg.pid);
+	pr_debug("IC Product id:%s", update_msg.ic_fw_msg.pid);
 
 	/* GT9XX PID MAPPING
 	|-----FLASH-----RAM-----|
@@ -392,7 +367,7 @@
 	|------9110P----9111----|*/
 	if (update_msg.ic_fw_msg.pid[0] != 0) {
 		if (!memcmp(update_msg.ic_fw_msg.pid, "9111", 4)) {
-			GTP_DEBUG("IC Mapping Product id:%s",
+			pr_debug("IC Mapping Product id:%s",
 					update_msg.ic_fw_msg.pid);
 			memcpy(update_msg.ic_fw_msg.pid, "9110P", 5);
 		}
@@ -400,7 +375,7 @@
 
 	update_msg.ic_fw_msg.vid = buf[GTP_ADDR_LENGTH + 4] +
 				(buf[GTP_ADDR_LENGTH + 5] << 8);
-	GTP_DEBUG("IC version id:%04x", update_msg.ic_fw_msg.vid);
+	pr_debug("IC version id:%04x", update_msg.ic_fw_msg.vid);
 
 	return SUCCESS;
 }
@@ -408,19 +383,21 @@
 s32 gup_enter_update_mode(struct i2c_client *client)
 {
 	s32 ret = -1;
-	s32 retry = 0;
+	u8 retry = 0;
 	u8 rd_buf[3];
+	struct goodix_ts_data *ts = i2c_get_clientdata(client);
 
 	/* step1:RST output low last at least 2ms */
-	GTP_GPIO_OUTPUT(GTP_RST_PORT, 0);
-	msleep(20);
+	gpio_direction_output(ts->pdata->reset_gpio, 0);
+	usleep(20000);
 
 	/* step2:select I2C slave addr,INT:0--0xBA;1--0x28. */
-	GTP_GPIO_OUTPUT(GTP_INT_PORT, (client->addr == 0x14));
+	gpio_direction_output(ts->pdata->irq_gpio,
+			(client->addr == GTP_I2C_ADDRESS_HIGH));
 	msleep(20);
 
 	/* step3:RST output high reset guitar */
-	GTP_GPIO_OUTPUT(GTP_RST_PORT, 1);
+	gpio_direction_output(ts->pdata->reset_gpio, 1);
 
 	/* 20121211 modify start */
 	msleep(20);
@@ -428,25 +405,25 @@
 		/* step4:Hold ss51 & dsp */
 		ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x0C);
 		if (ret <= 0) {
-			GTP_DEBUG("Hold ss51 & dsp I2C error,retry:%d", retry);
+			pr_debug("Hold ss51 & dsp I2C error,retry:%d", retry);
 			continue;
 		}
 
 		/* step5:Confirm hold */
 		ret = gup_get_ic_msg(client, _rRW_MISCTL__SWRST_B0_, rd_buf, 1);
 		if (ret <= 0) {
-			GTP_DEBUG("Hold ss51 & dsp I2C error,retry:%d", retry);
+			pr_debug("Hold ss51 & dsp I2C error,retry:%d", retry);
 			continue;
 		}
 		if (rd_buf[GTP_ADDR_LENGTH] == 0x0C) {
-			GTP_DEBUG("Hold ss51 & dsp confirm SUCCESS");
+			pr_debug("Hold ss51 & dsp confirm SUCCESS");
 			break;
 		}
-		GTP_DEBUG("Hold ss51 & dsp confirm 0x4180 failed,value:%d",
+		pr_debug("Hold ss51 & dsp confirm 0x4180 failed,value:%d",
 					rd_buf[GTP_ADDR_LENGTH]);
 	}
 	if (retry >= 200) {
-		GTP_ERROR("Enter update Hold ss51 failed.");
+		pr_err("Enter update Hold ss51 failed.");
 		return FAIL;
 	}
 
@@ -457,12 +434,13 @@
 	return ret;
 }
 
-void gup_leave_update_mode(void)
+void gup_leave_update_mode(struct i2c_client *client)
 {
-	GTP_GPIO_AS_INT(GTP_INT_PORT);
+	struct goodix_ts_data *ts = i2c_get_clientdata(client);
 
-	GTP_DEBUG("[leave_update_mode]reset chip.");
-	gtp_reset_guitar(i2c_connect_client, 20);
+	gpio_direction_input(ts->pdata->irq_gpio);
+	pr_debug("reset chip.");
+	gtp_reset_guitar(ts, 20);
 }
 
 /*	Get the correct nvram data
@@ -483,7 +461,8 @@
 	3. IC PID == 91XX || File PID == 91XX
 */
 
-static u8 gup_enter_update_judge(st_fw_head *fw_head)
+static u8 gup_enter_update_judge(struct i2c_client *client,
+					struct st_fw_head *fw_head)
 {
 	u16 u16_tmp;
 	s32 i = 0;
@@ -491,38 +470,37 @@
 	u16_tmp = fw_head->vid;
 	fw_head->vid = (u16)(u16_tmp>>8) + (u16)(u16_tmp<<8);
 
-	GTP_DEBUG("FILE HARDWARE INFO:%02x%02x%02x%02x", fw_head->hw_info[0],
+	pr_debug("FILE HARDWARE INFO:%02x%02x%02x%02x", fw_head->hw_info[0],
 		fw_head->hw_info[1], fw_head->hw_info[2], fw_head->hw_info[3]);
-	TP_DEBUG("FILE PID:%s", fw_head->pid);
-	TP_DEBUG("FILE VID:%04x", fw_head->vid);
+	pr_debug("FILE PID:%s", fw_head->pid);
+	pr_debug("FILE VID:%04x", fw_head->vid);
 
-	TP_DEBUG("IC HARDWARE INFO:%02x%02x%02x%02x",
+	pr_debug("IC HARDWARE INFO:%02x%02x%02x%02x",
 		update_msg.ic_fw_msg.hw_info[0],
 		update_msg.ic_fw_msg.hw_info[1],
 		update_msg.ic_fw_msg.hw_info[2],
 		update_msg.ic_fw_msg.hw_info[3]);
-	TP_DEBUG("IC PID:%s", update_msg.ic_fw_msg.pid);
-	TP_DEBUG("IC VID:%04x", update_msg.ic_fw_msg.vid);
+	pr_debug("IC PID:%s", update_msg.ic_fw_msg.pid);
+	pr_debug("IC VID:%04x", update_msg.ic_fw_msg.vid);
 
 	/* First two conditions */
 	if (!memcmp(fw_head->hw_info, update_msg.ic_fw_msg.hw_info,
 			sizeof(update_msg.ic_fw_msg.hw_info))) {
-		GTP_DEBUG("Get the same hardware info.");
+		pr_debug("Get the same hardware info.");
 		if (update_msg.force_update != 0xBE) {
-			GTP_INFO("FW chksum error,need enter update.");
+			pr_info("FW chksum error,need enter update.");
 			return SUCCESS;
 		}
 
 		/* 20130523 start */
 		if (strlen(update_msg.ic_fw_msg.pid) < 3) {
-			GTP_INFO("Illegal IC pid, need enter update");
+			pr_info("Illegal IC pid, need enter update");
 			return SUCCESS;
 		} else {
 			for (i = 0; i < 3; i++) {
 				if ((update_msg.ic_fw_msg.pid[i] < 0x30) ||
 					(update_msg.ic_fw_msg.pid[i] > 0x39)) {
-					GTP_INFO("Illegal IC pid, out of " \
-					"bound, need enter update");
+					pr_info("Illegal IC pid, out of bound, need enter update");
 					return SUCCESS;
 				}
 			}
@@ -534,398 +512,243 @@
 		(!memcmp(update_msg.ic_fw_msg.pid, "91XX", 4)) ||
 		(!memcmp(fw_head->pid, "91XX", 4))) {
 			if (!memcmp(fw_head->pid, "91XX", 4))
-				GTP_DEBUG("Force none same pid update mode.");
+				pr_debug("Force none same pid update mode.");
 			else
-				GTP_DEBUG("Get the same pid.");
+				pr_debug("Get the same pid.");
 
 			/* The third condition */
 			if (fw_head->vid > update_msg.ic_fw_msg.vid) {
-				GTP_INFO("Need enter update.");
+				pr_info("Need enter update.");
 				return SUCCESS;
 			}
-			GTP_ERROR("Don't meet the third condition.");
-			GTP_ERROR("File VID <= Ic VID, update aborted!");
+			pr_err("Don't meet the third condition.");
+			pr_err("File VID <= Ic VID, update aborted!");
 		} else {
-			GTP_ERROR("File PID != Ic PID, update aborted!");
+			pr_err("File PID != Ic PID, update aborted!");
 		}
 	} else {
-		GTP_ERROR("Different Hardware, update aborted!");
+		pr_err("Different Hardware, update aborted!");
 	}
 
 	return FAIL;
 }
 
-static u8 ascii2hex(u8 a)
+static s8 gup_update_config(struct i2c_client *client,
+					const struct firmware *cfg)
 {
-	s8 value = 0;
-
-	if (a >= '0' && a <= '9')
-		value = a - '0';
-	else if (a >= 'A' && a <= 'F')
-		value = a - 'A' + 0x0A;
-	else if (a >= 'a' && a <= 'f')
-		value = a - 'a' + 0x0A;
-	else
-		value = 0xff;
-
-	return value;
-}
-
-static s8 gup_update_config(struct i2c_client *client)
-{
-	s32 file_len = 0;
 	s32 ret = 0;
 	s32 i = 0;
 	s32 file_cfg_len = 0;
-	s32 chip_cfg_len = 0;
+	u32 chip_cfg_len = 0;
 	s32 count = 0;
 	u8 *buf;
-	u8 *pre_buf;
 	u8 *file_config;
-	/* u8 checksum = 0; */
 	u8 pid[8];
+	u8 high, low;
 
-	if (update_msg.cfg_file == NULL) {
-		GTP_ERROR("[update_cfg]No need to upgrade config!");
+	if (!cfg || !cfg->data) {
+		pr_err("No need to upgrade config!");
 		return FAIL;
 	}
-	file_len = update_msg.cfg_file->f_op->llseek(update_msg.cfg_file,
-							0, SEEK_END);
 
 	ret = gup_get_ic_msg(client, GUP_REG_PID_VID, pid, 6);
 	if (ret == FAIL) {
-		GTP_ERROR("[update_cfg]Read product id & version id fail.");
+		pr_err("Read product id & version id fail.");
 		return FAIL;
 	}
 	pid[5] = '\0';
-	GTP_DEBUG("update cfg get pid:%s", &pid[GTP_ADDR_LENGTH]);
+	pr_debug("update cfg get pid:%s", &pid[GTP_ADDR_LENGTH]);
 
 	chip_cfg_len = 186;
 	if (!memcmp(&pid[GTP_ADDR_LENGTH], "968", 3) ||
-	!memcmp(&pid[GTP_ADDR_LENGTH], "910", 3) ||
-	!memcmp(&pid[GTP_ADDR_LENGTH], "960", 3)) {
+		!memcmp(&pid[GTP_ADDR_LENGTH], "910", 3) ||
+		!memcmp(&pid[GTP_ADDR_LENGTH], "960", 3)) {
 		chip_cfg_len = 228;
 	}
-	GTP_DEBUG("[update_cfg]config file len:%d", file_len);
-	GTP_DEBUG("[update_cfg]need config len:%d", chip_cfg_len);
-	if ((file_len+5) < chip_cfg_len*5) {
-		GTP_ERROR("Config length error");
+	pr_debug("config file ASCII len:%d", cfg->size);
+	pr_debug("need config binary len:%d", chip_cfg_len);
+	if ((cfg->size + 5) < chip_cfg_len * 5) {
+		pr_err("Config length error");
 		return -EINVAL;
 	}
 
-	buf = kzalloc(file_len, GFP_KERNEL);
-	pre_buf = kzalloc(file_len, GFP_KERNEL);
-	file_config = kzalloc(chip_cfg_len + GTP_ADDR_LENGTH, GFP_KERNEL);
-	update_msg.cfg_file->f_op->llseek(update_msg.cfg_file, 0, SEEK_SET);
-
-	GTP_DEBUG("[update_cfg]Read config from file.");
-	ret = update_msg.cfg_file->f_op->read(update_msg.cfg_file,
-			(char *)pre_buf, file_len, &update_msg.cfg_file->f_pos);
-	if (ret < 0) {
-		GTP_ERROR("[update_cfg]Read config file failed.");
-		goto update_cfg_file_failed;
+	buf = devm_kzalloc(&client->dev, cfg->size, GFP_KERNEL);
+	if (!buf) {
+		dev_err(&client->dev, "Memory allocation failed for buf.");
+		return -ENOMEM;
 	}
 
-	GTP_DEBUG("[update_cfg]Delete illgal charactor.");
-	for (i = 0, count = 0; i < file_len; i++) {
-		if (pre_buf[i] == ' ' || pre_buf[i] == '\r'
-					|| pre_buf[i] == '\n')
+	file_config = devm_kzalloc(&client->dev, chip_cfg_len + GTP_ADDR_LENGTH,
+								GFP_KERNEL);
+	if (!file_config) {
+		dev_err(&client->dev, "Memory allocation failed.");
+		return -ENOMEM;
+	}
+
+	pr_debug("Delete illgal charactor.");
+	for (i = 0, count = 0; i < cfg->size; i++) {
+		if (cfg->data[i] == ' ' || cfg->data[i] == '\r'
+					|| cfg->data[i] == '\n')
 			continue;
-		buf[count++] = pre_buf[i];
+		buf[count++] = cfg->data[i];
 	}
 
-	GTP_DEBUG("[update_cfg]Ascii to hex.");
+	pr_debug("Ascii to hex.");
 	file_config[0] = GTP_REG_CONFIG_DATA >> 8;
 	file_config[1] = GTP_REG_CONFIG_DATA & 0xff;
-	for (i = 0, file_cfg_len = GTP_ADDR_LENGTH; i < count; i + = 5) {
-		if ((buf[i] == '0') && ((buf[i+1] == 'x') ||
-						(buf[i+1] == 'X'))) {
-			u8 high, low;
-			high = ascii2hex(buf[i+2]);
-			low = ascii2hex(buf[i+3]);
+	for (i = 0, file_cfg_len = GTP_ADDR_LENGTH; i < count; i = i + 5) {
+		if ((buf[i] == '0') && ((buf[i + 1] == 'x') ||
+						(buf[i + 1] == 'X'))) {
+			ret = hex2bin(&high, &buf[i + 2], 1);
+			if (ret) {
+				pr_err("Failed to convert high address from hex2bin");
+				return ret;
+			}
+			ret = hex2bin(&low, &buf[i + 3], 1);
+			if (ret) {
+				pr_err("Failed to convert low address from hex2bin");
+				return ret;
+			}
 
 			if ((high == 0xFF) || (low == 0xFF)) {
 				ret = 0;
-				GTP_ERROR("[update_cfg]Illegal config file.");
-				goto update_cfg_file_failed;
+				pr_err("Illegal config file.");
+				return ret;
 			}
 			file_config[file_cfg_len++] = (high<<4) + low;
 		} else {
 			ret = 0;
-			GTP_ERROR("[update_cfg]Illegal config file.");
-			goto update_cfg_file_failed;
+			pr_err("Illegal config file.");
+			return ret;
 		}
 	}
 
-	/* cal checksum */
-	/* for(i=GTP_ADDR_LENGTH; i<chip_cfg_len; i++)
-		checksum += file_config[i];
-	file_config[chip_cfg_len] = (~checksum) + 1;
-	file_config[chip_cfg_len+1] = 0x01; */
-
-	GTP_DEBUG("config:");
-	GTP_DEBUG_ARRAY(file_config+2, file_cfg_len);
-
 	i = 0;
 	while (i++ < 5) {
 		ret = gup_i2c_write(client, file_config, file_cfg_len);
 		if (ret > 0) {
-			GTP_INFO("[update_cfg]Send config SUCCESS.");
+			pr_info("Send config SUCCESS.");
 			break;
 		}
-		GTP_ERROR("[update_cfg]Send config i2c error.");
+		pr_err("Send config i2c error.");
 	}
 
-update_cfg_file_failed:
-	kfree(pre_buf);
-	kfree(buf);
-	kfree(file_config);
 	return ret;
 }
 
-#if GTP_HEADER_FW_UPDATE
-static u8 gup_check_fs_mounted(char *path_name)
+static s32 gup_get_firmware_file(struct i2c_client *client,
+		struct st_update_msg *msg, u8 *path)
 {
-	struct path root_path;
-	struct path path;
-	int err;
-	err = kern_path("/", LOOKUP_FOLLOW, &root_path);
+	s32 ret;
+	const struct firmware *fw = NULL;
 
-	if (err) {
-		GTP_DEBUG("\"/\" NOT Mounted: %d", err);
-		return FAIL;
-	}
-	err = kern_path(path_name, LOOKUP_FOLLOW, &path);
-
-	if (err) {
-		GTP_DEBUG("/data/ NOT Mounted: %d", err);
-		return FAIL;
+	ret = request_firmware(&fw, path, &client->dev);
+	if (ret < 0) {
+		dev_info(&client->dev, "Cannot get firmware - %s (%d)\n",
+					path, ret);
+		return -EEXIST;
 	}
 
-	return SUCCESS;
+	dev_dbg(&client->dev, "Config File: %s size=%d", path, fw->size);
+	msg->fw_data =
+		devm_kzalloc(&client->dev, fw->size, GFP_KERNEL);
+	if (!msg->fw_data) {
+		dev_err(&client->dev,
+			"Not enough memory for firmware data.");
+		release_firmware(fw);
+		return -ENOMEM;
+	}
 
-	/* if (path.mnt->mnt_sb == root_path.mnt->mnt_sb)
-		return FAIL;
-	else
-		return SUCCESS; */
+	memcpy(msg->fw_data, fw->data, fw->size);
+	msg->fw_len = fw->size;
+	msg->need_free = true;
+	release_firmware(fw);
+	return 0;
 }
-#endif
 
-static u8 gup_check_update_file(struct i2c_client *client, st_fw_head *fw_head,
-								u8 *path)
+static u8 gup_check_firmware_name(struct i2c_client *client,
+					u8 **path_p)
+{
+	u8 len;
+	u8 *fname;
+
+	if (!(*path_p)) {
+		*path_p = GOODIX_FIRMWARE_FILE_NAME;
+		return 0;
+	}
+
+	len = strnlen(*path_p, FIRMWARE_NAME_LEN_MAX);
+	if (len >= FIRMWARE_NAME_LEN_MAX) {
+		dev_err(&client->dev, "firmware name too long!");
+		return -EINVAL;
+	}
+
+	fname = strrchr(*path_p, '/');
+	if (fname) {
+		fname = fname + 1;
+		*path_p = fname;
+	}
+	return 0;
+}
+
+static u8 gup_check_update_file(struct i2c_client *client,
+			struct st_fw_head *fw_head, u8 *path)
 {
 	s32 ret = 0;
 	s32 i = 0;
 	s32 fw_checksum = 0;
-	u8 buf[FW_HEAD_LENGTH];
+	u16 temp;
+	const struct firmware *fw = NULL;
 
-	if (path) {
-		GTP_DEBUG("Update File path:%s, %d", path, strlen(path));
-		update_msg.file = file_open(path, O_RDONLY, 0);
-
-		if (IS_ERR(update_msg.file)) {
-			GTP_ERROR("Open update file(%s) error!", path);
-			return FAIL;
-		}
-	} else {
-#if GTP_HEADER_FW_UPDATE
-		for (i = 0; i < (GUP_SEARCH_FILE_TIMES); i++) {
-			GTP_DEBUG("Waiting for /data mounted [%d]", i);
-
-			if (gup_check_fs_mounted("/data") == SUCCESS) {
-				GTP_DEBUG("/data Mounted!");
-				break;
-			}
-			msleep(3000);
-		}
-		if (i >= (GUP_SEARCH_FILE_TIMES)) {
-			GTP_ERROR("Wait for /data mounted timeout!");
-			return FAIL;
-		}
-
-		/* update config */
-		update_msg.cfg_file = file_open(CONFIG_FILE_PATH_1,
-							O_RDONLY, 0);
-
-		if (IS_ERR(update_msg.cfg_file)) {
-			GTP_DEBUG("%s is unavailable", CONFIG_FILE_PATH_1);
-		} else {
-			GTP_INFO("Update Config File: %s", CONFIG_FILE_PATH_1);
-			ret = gup_update_config(client);
-			if (ret <= 0)
-				GTP_ERROR("Update config failed.");
-			filp_close(update_msg.cfg_file, NULL);
-		}
-
-		if (sizeof(header_fw_array) < (FW_HEAD_LENGTH+FW_SECTION_LENGTH
-		*4 + FW_DSP_ISP_LENGTH+FW_DSP_LENGTH + FW_BOOT_LENGTH)) {
-			GTP_ERROR("INVALID header_fw_array, check your " \
-				"gt9xx_firmware.h file!");
-			return FAIL;
-		}
-		update_msg.file = file_open(UPDATE_FILE_PATH_2, O_CREAT |
-								O_RDWR, 0666);
-		if ((IS_ERR(update_msg.file))) {
-			GTP_ERROR("Failed to Create file: %s for fw_header!",
-							UPDATE_FILE_PATH_2);
-			return FAIL;
-		}
-		update_msg.file->f_op->llseek(update_msg.file, 0, SEEK_SET);
-		update_msg.file->f_op->write(update_msg.file,
-			(char *)header_fw_array, sizeof(header_fw_array),
-			&update_msg.file->f_pos);
-		file_close(update_msg.file, NULL);
-		update_msg.file = file_open(UPDATE_FILE_PATH_2, O_RDONLY, 0);
-#else
-		u8 fp_len = max(sizeof(UPDATE_FILE_PATH_1),
-						sizeof(UPDATE_FILE_PATH_2));
-		u8 cfp_len = max(sizeof(CONFIG_FILE_PATH_1),
-						sizeof(CONFIG_FILE_PATH_2));
-		u8 *search_update_path = kzalloc(fp_len, GFP_KERNEL);
-		u8 *search_cfg_path = kzalloc(cfp_len, GFP_KERNEL);
-		/* Begin to search update file,the config file & firmware
-			file must be in the same path,single or double. */
-		searching_file = 1;
-		for (i = 0; i < GUP_SEARCH_FILE_TIMES; i++) {
-			if (searching_file == 0) {
-				kfree(search_update_path);
-				kfree(search_cfg_path);
-				GTP_INFO(".bin/.cfg update file search " \
-						"forcely terminated!");
-				return FAIL;
-			}
-			if (i % 2) {
-				memcpy(search_update_path, UPDATE_FILE_PATH_1,
-						sizeof(UPDATE_FILE_PATH_1));
-				memcpy(search_cfg_path, CONFIG_FILE_PATH_1,
-						sizeof(CONFIG_FILE_PATH_1));
-			} else {
-				memcpy(search_update_path, UPDATE_FILE_PATH_2,
-						sizeof(UPDATE_FILE_PATH_2));
-				memcpy(search_cfg_path, CONFIG_FILE_PATH_2,
-						sizeof(CONFIG_FILE_PATH_2));
-			}
-
-			if (!(got_file_flag&0x0F)) {
-				update_msg.file = file_open(search_update_path,
-						O_RDONLY, 0);
-				if (!IS_ERR(update_msg.file)) {
-					GTP_DEBUG("Find the bin file");
-					got_file_flag |= 0x0F;
-				}
-			}
-			if (!(got_file_flag & 0xF0)) {
-				update_msg.cfg_file = file_open(search_cfg_path,
-						O_RDONLY, 0);
-				if (!IS_ERR(update_msg.cfg_file)) {
-					GTP_DEBUG("Find the cfg file");
-					got_file_flag |= 0xF0;
-				}
-			}
-
-			if (got_file_flag) {
-				if (got_file_flag == 0xFF)
-					break;
-				else
-					i += 4;
-			}
-			GTP_DEBUG("%3d:Searching %s %s file...", i,
-			(got_file_flag & 0x0F) ? "" : "bin",
-			(got_file_flag & 0xF0) ? "" : "cfg");
-
-			msleep(3000);
-		}
-
-		searching_file = 0;
-		kfree(search_update_path);
-		kfree(search_cfg_path);
-
-		if (!got_file_flag) {
-			GTP_ERROR("Can't find update file.");
-			goto load_failed;
-		}
-
-		if (got_file_flag & 0xF0) {
-			GTP_DEBUG("Got the update config file.");
-			ret = gup_update_config(client);
-			if (ret <= 0)
-				GTP_ERROR("Update config failed.");
-			filp_close(update_msg.cfg_file, NULL);
-			msleep(500); /* waiting config to be stored in FLASH. */
-		}
-		if (got_file_flag & 0x0F) {
-			GTP_DEBUG("Got the update firmware file.");
-		} else {
-			GTP_ERROR("No need to upgrade firmware.");
-			goto load_failed;
-		}
-#endif
-	}
-
-	update_msg.old_fs = get_fs();
-	set_fs(KERNEL_DS);
-
-	update_msg.file->f_op->llseek(update_msg.file, 0, SEEK_SET);
-	/* update_msg.file->f_pos = 0; */
-
-	ret = update_msg.file->f_op->read(update_msg.file, (char *)buf,
-				FW_HEAD_LENGTH, &update_msg.file->f_pos);
+	ret = request_firmware(&fw, GOODIX_CONFIG_FILE_NAME, &client->dev);
 	if (ret < 0) {
-		GTP_ERROR("Read firmware head in update file error.");
-		goto load_failed;
+		dev_info(&client->dev, "Cannot get config file - %s (%d)\n",
+						GOODIX_CONFIG_FILE_NAME, ret);
+	} else {
+		dev_dbg(&client->dev,
+			"Update config File: %s", GOODIX_CONFIG_FILE_NAME);
+		ret = gup_update_config(client, fw);
+		if (ret <= 0)
+			dev_err(&client->dev, "Update config failed.");
+		release_firmware(fw);
 	}
-	memcpy(fw_head, buf, FW_HEAD_LENGTH);
+
+	update_msg.need_free = false;
+	update_msg.fw_len = 0;
+
+	if (gup_check_firmware_name(client, &path))
+		goto load_failed;
+
+	if (gup_get_firmware_file(client, &update_msg, path))
+		goto load_failed;
+
+	memcpy(fw_head, update_msg.fw_data, FW_HEAD_LENGTH);
 
 	/* check firmware legality */
 	fw_checksum = 0;
 	for (i = 0; i < FW_SECTION_LENGTH * 4 + FW_DSP_ISP_LENGTH +
-			FW_DSP_LENGTH + FW_BOOT_LENGTH; i + = 2) {
-		u16 temp;
-		ret = update_msg.file->f_op->read(update_msg.file, (char *)buf,
-						2, &update_msg.file->f_pos);
-		if (ret < 0) {
-			GTP_ERROR("Read firmware file error.");
-			goto load_failed;
-		}
-		/* GTP_DEBUG("BUF[0]:%x", buf[0]); */
-		temp = (buf[0]<<8) + buf[1];
+			FW_DSP_LENGTH + FW_BOOT_LENGTH; i += 2) {
+		temp = (update_msg.fw_data[FW_HEAD_LENGTH + i] << 8) +
+			update_msg.fw_data[FW_HEAD_LENGTH + i + 1];
 		fw_checksum += temp;
 	}
 
-	GTP_DEBUG("firmware checksum:%x", fw_checksum&0xFFFF);
+	pr_debug("firmware checksum:%x", fw_checksum & 0xFFFF);
 	if (fw_checksum & 0xFFFF) {
-		GTP_ERROR("Illegal firmware file.");
+		dev_err(&client->dev, "Illegal firmware file.");
 		goto load_failed;
 	}
 
 	return SUCCESS;
 
 load_failed:
-	set_fs(update_msg.old_fs);
+	if (update_msg.need_free) {
+		devm_kfree(&client->dev, update_msg.fw_data);
+		update_msg.need_free = false;
+	}
 	return FAIL;
 }
 
-#if 0
-static u8 gup_check_update_header(struct i2c_client *client,
-			st_fw_head *fw_head)
-{
-	const u8 *pos;
-	int i = 0;
-	u8 mask_num = 0;
-	s32 ret = 0;
-
-	pos = HEADER_UPDATE_DATA;
-
-	memcpy(fw_head, pos, FW_HEAD_LENGTH);
-	pos += FW_HEAD_LENGTH;
-
-	ret = gup_enter_update_judge(fw_head);
-	if (SUCCESS == ret)
-		return SUCCESS;
-	return FAIL;
-}
-#endif
-
 static u8 gup_burn_proc(struct i2c_client *client, u8 *burn_buf, u16 start_addr,
 							u16 total_length)
 {
@@ -937,10 +760,10 @@
 	u8  rd_buf[PACK_SIZE + GTP_ADDR_LENGTH];
 	u8  retry = 0;
 
-	GTP_DEBUG("Begin burn %dk data to addr 0x%x", (total_length/1024),
+	pr_debug("Begin burn %dk data to addr 0x%x", (total_length / 1024),
 								start_addr);
 	while (burn_length < total_length) {
-		GTP_DEBUG("B/T:%04d/%04d", burn_length, total_length);
+		pr_debug("B/T:%04d/%04d", burn_length, total_length);
 		frame_length = ((total_length - burn_length) > PACK_SIZE)
 				? PACK_SIZE : (total_length - burn_length);
 		wr_buf[0] = (u8)(burn_addr>>8);
@@ -954,33 +777,26 @@
 			ret = gup_i2c_write(client, wr_buf,
 					GTP_ADDR_LENGTH + frame_length);
 			if (ret <= 0) {
-				GTP_ERROR("Write frame data i2c error.");
+				pr_err("Write frame data i2c error.");
 				continue;
 			}
 			ret = gup_i2c_read(client, rd_buf, GTP_ADDR_LENGTH +
 							frame_length);
 			if (ret <= 0) {
-				GTP_ERROR("Read back frame data i2c error.");
+				pr_err("Read back frame data i2c error.");
 				continue;
 			}
 
 			if (memcmp(&wr_buf[GTP_ADDR_LENGTH],
 				&rd_buf[GTP_ADDR_LENGTH], frame_length)) {
-				GTP_ERROR("Check frame data fail,not equal.");
-				GTP_DEBUG("write array:");
-				GTP_DEBUG_ARRAY(&wr_buf[GTP_ADDR_LENGTH],
-								frame_length);
-				GTP_DEBUG("read array:");
-				GTP_DEBUG_ARRAY(&rd_buf[GTP_ADDR_LENGTH],
-								frame_length);
+				pr_err("Check frame data fail,not equal.");
 				continue;
 			} else {
-				/* GTP_DEBUG("Check frame data success."); */
 				break;
 			}
 		}
 		if (retry >= MAX_FRAME_CHECK_TIME) {
-			GTP_ERROR("Burn frame data time out,exit.");
+			pr_err("Burn frame data time out,exit.");
 			return FAIL;
 		}
 		burn_length += frame_length;
@@ -991,20 +807,15 @@
 
 static u8 gup_load_section_file(u8 *buf, u16 offset, u16 length)
 {
-	s32 ret = 0;
-
-	if (update_msg.file == NULL) {
-		GTP_ERROR("cannot find update file,load section file fail.");
+	if (!update_msg.fw_data ||
+		update_msg.fw_len < FW_HEAD_LENGTH + offset + length) {
+		pr_err(
+			"<<-GTP->> cannot load section data. fw_len=%d read end=%d\n",
+			update_msg.fw_len ,
+			FW_HEAD_LENGTH + offset + length);
 		return FAIL;
 	}
-	update_msg.file->f_pos = FW_HEAD_LENGTH + offset;
-
-	ret = update_msg.file->f_op->read(update_msg.file, (char *)buf, length,
-						&update_msg.file->f_pos);
-	if (ret < 0) {
-		GTP_ERROR("Read update file fail.");
-		return FAIL;
-	}
+	memcpy(buf, &update_msg.fw_data[FW_HEAD_LENGTH + offset], length);
 
 	return SUCCESS;
 }
@@ -1023,30 +834,26 @@
 				? PACK_SIZE : (chk_length - recall_length);
 		ret = gup_get_ic_msg(client, recall_addr, rd_buf, frame_length);
 		if (ret <= 0) {
-			GTP_ERROR("recall i2c error,exit");
+			pr_err("recall i2c error,exit");
 			return FAIL;
 		}
 
 		if (memcmp(&rd_buf[GTP_ADDR_LENGTH], &chk_src[recall_length],
 			frame_length)) {
-			GTP_ERROR("Recall frame data fail,not equal.");
-			GTP_DEBUG("chk_src array:");
-			GTP_DEBUG_ARRAY(&chk_src[recall_length], frame_length);
-			GTP_DEBUG("recall array:");
-			GTP_DEBUG_ARRAY(&rd_buf[GTP_ADDR_LENGTH], frame_length);
+			pr_err("Recall frame data fail,not equal.");
 			return FAIL;
 		}
 
 		recall_length += frame_length;
 		recall_addr += frame_length;
 	}
-	GTP_DEBUG("Recall check %dk firmware success.", (chk_length/1024));
+	pr_debug("Recall check %dk firmware success.", (chk_length/1024));
 
 	return SUCCESS;
 }
 
 static u8 gup_burn_fw_section(struct i2c_client *client, u8 *fw_section,
-					u16 start_addr, u8 bank_cmdi)
+					u16 start_addr, u8 bank_cmd)
 {
 	s32 ret = 0;
 	u8  rd_buf[5];
@@ -1054,14 +861,14 @@
 	/* step1:hold ss51 & dsp */
 	ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x0C);
 	if (ret <= 0) {
-		GTP_ERROR("[burn_fw_section]hold ss51 & dsp fail.");
+		pr_err("hold ss51 & dsp fail.");
 		return FAIL;
 	}
 
 	 /* step2:set scramble */
 	ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_OPT_B0_, 0x00);
 	if (ret <= 0) {
-		GTP_ERROR("[burn_fw_section]set scramble fail.");
+		pr_err("set scramble fail.");
 		return FAIL;
 	}
 
@@ -1069,7 +876,7 @@
 	ret = gup_set_ic_msg(client, _bRW_MISCTL__SRAM_BANK,
 						(bank_cmd >> 4)&0x0F);
 	if (ret <= 0) {
-		GTP_ERROR("[burn_fw_section]select bank %d fail.",
+		pr_err("select bank %d fail.",
 					(bank_cmd >> 4)&0x0F);
 		return FAIL;
 	}
@@ -1077,21 +884,21 @@
 	/* step4:enable accessing code */
 	ret = gup_set_ic_msg(client, _bRW_MISCTL__MEM_CD_EN, 0x01);
 	if (ret <= 0) {
-		GTP_ERROR("[burn_fw_section]enable accessing code fail.");
+		pr_err("enable accessing code fail.");
 		return FAIL;
 	}
 
 	/* step5:burn 8k fw section */
 	ret = gup_burn_proc(client, fw_section, start_addr, FW_SECTION_LENGTH);
 	if (ret == FAIL)  {
-		GTP_ERROR("[burn_fw_section]burn fw_section fail.");
+		pr_err("burn fw_section fail.");
 		return FAIL;
 	}
 
 	/* step6:hold ss51 & release dsp */
 	ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x04);
 	if (ret <= 0) {
-		GTP_ERROR("[burn_fw_section]hold ss51 & release dsp fail.");
+		pr_err("hold ss51 & release dsp fail.");
 		return FAIL;
 	}
 	/* must delay */
@@ -1100,26 +907,24 @@
 	/* step7:send burn cmd to move data to flash from sram */
 	ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, bank_cmd&0x0f);
 	if (ret <= 0) {
-		GTP_ERROR("[burn_fw_section]send burn cmd fail.");
+		pr_err("send burn cmd fail.");
 		return FAIL;
 	}
-	GTP_DEBUG("[burn_fw_section]Wait for the burn is complete......");
+	pr_debug("Wait for the burn is complete.");
 	do {
 		ret = gup_get_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, rd_buf, 1);
 		if (ret <= 0) {
-			GTP_ERROR("[burn_fw_section]Get burn state fail");
+			pr_err("Get burn state fail");
 			return FAIL;
 		}
 		msleep(20);
-		/* GTP_DEBUG("[burn_fw_section]Get burn state:%d.",
-						rd_buf[GTP_ADDR_LENGTH]); */
 	} while (rd_buf[GTP_ADDR_LENGTH]);
 
 	/* step8:select bank */
 	ret = gup_set_ic_msg(client, _bRW_MISCTL__SRAM_BANK,
 							(bank_cmd >> 4)&0x0F);
 	if (ret <= 0) {
-		GTP_ERROR("[burn_fw_section]select bank %d fail.",
+		pr_err("select bank %d fail.",
 							(bank_cmd >> 4)&0x0F);
 		return FAIL;
 	}
@@ -1127,7 +932,7 @@
 	/* step9:enable accessing code */
 	ret = gup_set_ic_msg(client, _bRW_MISCTL__MEM_CD_EN, 0x01);
 	if (ret <= 0) {
-		GTP_ERROR("[burn_fw_section]enable accessing code fail.");
+		pr_err("enable accessing code fail.");
 		return FAIL;
 	}
 
@@ -1135,14 +940,14 @@
 	ret = gup_recall_check(client, fw_section, start_addr,
 							FW_SECTION_LENGTH);
 	if (ret == FAIL) {
-		GTP_ERROR("[burn_fw_section]recall check 8k firmware fail.");
+		pr_err("recall check 8k firmware fail.");
 		return FAIL;
 	}
 
 	/* step11:disable accessing code */
 	ret = gup_set_ic_msg(client, _bRW_MISCTL__MEM_CD_EN, 0x00);
 	if (ret <= 0) {
-		GTP_ERROR("[burn_fw_section]disable accessing code fail.");
+		pr_err("disable accessing code fail.");
 		return FAIL;
 	}
 
@@ -1155,115 +960,105 @@
 	u8 *fw_dsp_isp = NULL;
 	u8  retry = 0;
 
-	GTP_DEBUG("[burn_dsp_isp]Begin burn dsp isp---->>");
+	pr_debug("Begin burn dsp isp.");
 
 	/* step1:alloc memory */
-	GTP_DEBUG("[burn_dsp_isp]step1:alloc memory");
+	pr_debug("step1:alloc memory");
 	while (retry++ < 5) {
-		fw_dsp_isp = kzalloc(FW_DSP_ISP_LENGTH, GFP_KERNEL);
+		fw_dsp_isp = devm_kzalloc(&client->dev, FW_DSP_ISP_LENGTH,
+								GFP_KERNEL);
 		if (fw_dsp_isp == NULL) {
 			continue;
 		} else {
-			GTP_INFO("[burn_dsp_isp]Alloc %dk byte memory success.",
+			pr_info("Alloc %dk byte memory success.",
 					(FW_DSP_ISP_LENGTH/1024));
 			break;
 		}
 	}
-	if (retry >= 5) {
-		GTP_ERROR("[burn_dsp_isp]Alloc memory fail,exit.");
+	if (retry == 5) {
+		pr_err("Alloc memory fail,exit.");
 		return FAIL;
 	}
 
 	/* step2:load dsp isp file data */
-	GTP_DEBUG("[burn_dsp_isp]step2:load dsp isp file data");
+	pr_debug("step2:load dsp isp file data");
 	ret = gup_load_section_file(fw_dsp_isp, (4 * FW_SECTION_LENGTH +
 		FW_DSP_LENGTH + FW_BOOT_LENGTH), FW_DSP_ISP_LENGTH);
 	if (ret == FAIL) {
-		GTP_ERROR("[burn_dsp_isp]load firmware dsp_isp fail.");
-		goto exit_burn_dsp_isp;
+		pr_err("load firmware dsp_isp fail.");
+		return FAIL;
 	}
 
 	/* step3:disable wdt,clear cache enable */
-	GTP_DEBUG("[burn_dsp_isp]step3:disable wdt,clear cache enable");
+	pr_debug("step3:disable wdt,clear cache enable");
 	ret = gup_set_ic_msg(client, _bRW_MISCTL__TMR0_EN, 0x00);
 	if (ret <= 0) {
-		GTP_ERROR("[burn_dsp_isp]disable wdt fail.");
-		ret = FAIL;
-		goto exit_burn_dsp_isp;
+		pr_err("disable wdt fail.");
+		return FAIL;
 	}
 	ret = gup_set_ic_msg(client, _bRW_MISCTL__CACHE_EN, 0x00);
 	if (ret <= 0) {
-		GTP_ERROR("[burn_dsp_isp]clear cache enable fail.");
-		ret = FAIL;
-		goto exit_burn_dsp_isp;
+		pr_err("clear cache enable fail.");
+		return FAIL;
 	}
 
 	/* step4:hold ss51 & dsp */
-	GTP_DEBUG("[burn_dsp_isp]step4:hold ss51 & dsp");
+	pr_debug("step4:hold ss51 & dsp");
 	ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x0C);
 	if (ret <= 0) {
-		GTP_ERROR("[burn_dsp_isp]hold ss51 & dsp fail.");
-		ret = FAIL;
-		goto exit_burn_dsp_isp;
+		pr_err("hold ss51 & dsp fail.");
+		return FAIL;
 	}
 
 	/* step5:set boot from sram */
-	GTP_DEBUG("[burn_dsp_isp]step5:set boot from sram");
+	pr_debug("step5:set boot from sram");
 	ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOTCTL_B0_, 0x02);
 	if (ret <= 0) {
-		GTP_ERROR("[burn_dsp_isp]set boot from sram fail.");
-		ret = FAIL;
-		goto exit_burn_dsp_isp;
+		pr_err("set boot from sram fail.");
+		return FAIL;
 	}
 
 	/* step6:software reboot */
-	GTP_DEBUG("[burn_dsp_isp]step6:software reboot");
+	pr_debug("step6:software reboot");
 	ret = gup_set_ic_msg(client, _bWO_MISCTL__CPU_SWRST_PULSE, 0x01);
 	if (ret <= 0) {
-		GTP_ERROR("[burn_dsp_isp]software reboot fail.");
-		ret = FAIL;
-		goto exit_burn_dsp_isp;
+		pr_err("software reboot fail.");
+		return FAIL;
 	}
 
 	/* step7:select bank2 */
-	GTP_DEBUG("[burn_dsp_isp]step7:select bank2");
+	pr_debug("step7:select bank2");
 	ret = gup_set_ic_msg(client, _bRW_MISCTL__SRAM_BANK, 0x02);
 	if (ret <= 0) {
-		GTP_ERROR("[burn_dsp_isp]select bank2 fail.");
-		ret = FAIL;
-		goto exit_burn_dsp_isp;
+		pr_err("select bank2 fail.");
+		return FAIL;
 	}
 
 	/* step8:enable accessing code */
-	GTP_DEBUG("[burn_dsp_isp]step8:enable accessing code");
+	pr_debug("step8:enable accessing code");
 	ret = gup_set_ic_msg(client, _bRW_MISCTL__MEM_CD_EN, 0x01);
 	if (ret <= 0) {
-		GTP_ERROR("[burn_dsp_isp]enable accessing code fail.");
-		ret = FAIL;
-		goto exit_burn_dsp_isp;
+		pr_err("enable accessing code fail.");
+		return FAIL;
 	}
 
 	/* step9:burn 4k dsp_isp */
-	GTP_DEBUG("[burn_dsp_isp]step9:burn 4k dsp_isp");
+	pr_debug("step9:burn 4k dsp_isp");
 	ret = gup_burn_proc(client, fw_dsp_isp, 0xC000, FW_DSP_ISP_LENGTH);
 	if (ret == FAIL) {
-		GTP_ERROR("[burn_dsp_isp]burn dsp_isp fail.");
-		goto exit_burn_dsp_isp;
+		pr_err("burn dsp_isp fail.");
+		return FAIL;
 	}
 
 	/* step10:set scramble */
-	GTP_DEBUG("[burn_dsp_isp]step10:set scramble");
+	pr_debug("step10:set scramble");
 	ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_OPT_B0_, 0x00);
 	if (ret <= 0) {
-		GTP_ERROR("[burn_dsp_isp]set scramble fail.");
-		ret = FAIL;
-		goto exit_burn_dsp_isp;
+		pr_err("set scramble fail.");
+		return FAIL;
 	}
-	ret = SUCCESS;
 
-exit_burn_dsp_isp:
-	kfree(fw_dsp_isp);
-	return ret;
+	return SUCCESS;
 }
 
 static u8 gup_burn_fw_ss51(struct i2c_client *client)
@@ -1272,106 +1067,102 @@
 	u8  retry = 0;
 	s32 ret = 0;
 
-	GTP_DEBUG("[burn_fw_ss51]Begin burn ss51 firmware---->>");
+	pr_debug("Begin burn ss51 firmware.");
 
 	/* step1:alloc memory */
-	GTP_DEBUG("[burn_fw_ss51]step1:alloc memory");
+	pr_debug("step1:alloc memory");
 	while (retry++ < 5) {
-		fw_ss51 = kzalloc(FW_SECTION_LENGTH, GFP_KERNEL);
+		fw_ss51 = devm_kzalloc(&client->dev, FW_SECTION_LENGTH,
+							GFP_KERNEL);
 		if (fw_ss51 == NULL) {
 			continue;
 		} else {
-			GTP_INFO("[burn_fw_ss51]Alloc %dk byte memory success.",
+			pr_info("Alloc %dk byte memory success.",
 						(FW_SECTION_LENGTH/1024));
 			break;
 		}
 	}
-	if (retry >= 5) {
-		GTP_ERROR("[burn_fw_ss51]Alloc memory fail,exit.");
+	if (retry == 5) {
+		pr_err("Alloc memory fail,exit.");
 		return FAIL;
 	}
 
 	/* step2:load ss51 firmware section 1 file data */
-	GTP_DEBUG("[burn_fw_ss51]step2:load ss51 firmware section 1 file data");
+	pr_debug("step2:load ss51 firmware section 1 file data");
 	ret = gup_load_section_file(fw_ss51, 0, FW_SECTION_LENGTH);
 	if (ret == FAIL) {
-		GTP_ERROR("[burn_fw_ss51]load ss51 firmware section 1 fail.");
-		goto exit_burn_fw_ss51;
+		pr_err("load ss51 firmware section 1 fail.");
+		return FAIL;
 	}
 
 	/* step3:clear control flag */
-	GTP_DEBUG("[burn_fw_ss51]step3:clear control flag");
+	pr_debug("step3:clear control flag");
 	ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, 0x00);
 	if (ret <= 0) {
-		GTP_ERROR("[burn_fw_ss51]clear control flag fail.");
-		ret = FAIL;
-		goto exit_burn_fw_ss51;
+		pr_err("clear control flag fail.");
+		return FAIL;
 	}
 
 	/* step4:burn ss51 firmware section 1 */
-	GTP_DEBUG("[burn_fw_ss51]step4:burn ss51 firmware section 1");
+	pr_debug("step4:burn ss51 firmware section 1");
 	ret = gup_burn_fw_section(client, fw_ss51, 0xC000, 0x01);
 	if (ret == FAIL) {
-		GTP_ERROR("[burn_fw_ss51]burn ss51 firmware section 1 fail.");
-		goto exit_burn_fw_ss51;
+		pr_err("burn ss51 firmware section 1 fail.");
+		return FAIL;
 	}
 
 	/* step5:load ss51 firmware section 2 file data */
-	GTP_DEBUG("[burn_fw_ss51]step5:load ss51 firmware section 2 file data");
+	pr_debug("step5:load ss51 firmware section 2 file data");
 	ret = gup_load_section_file(fw_ss51, FW_SECTION_LENGTH,
 							FW_SECTION_LENGTH);
 	if (ret == FAIL) {
-		GTP_ERROR("[burn_fw_ss51]load ss51 firmware section 2 fail.");
-		goto exit_burn_fw_ss51;
+		pr_err("[burn_fw_ss51]load ss51 firmware section 2 fail.");
+		return FAIL;
 	}
 
 	/* step6:burn ss51 firmware section 2 */
-	GTP_DEBUG("[burn_fw_ss51]step6:burn ss51 firmware section 2");
+	pr_debug("step6:burn ss51 firmware section 2");
 	ret = gup_burn_fw_section(client, fw_ss51, 0xE000, 0x02);
 	if (ret == FAIL) {
-		GTP_ERROR("[burn_fw_ss51]burn ss51 firmware section 2 fail.");
-		goto exit_burn_fw_ss51;
+		pr_err("burn ss51 firmware section 2 fail.");
+		return FAIL;
 	}
 
 	/* step7:load ss51 firmware section 3 file data */
-	GTP_DEBUG("[burn_fw_ss51]step7:load ss51 firmware section 3 file data");
+	pr_debug("step7:load ss51 firmware section 3 file data");
 	ret = gup_load_section_file(fw_ss51, 2*FW_SECTION_LENGTH,
 							FW_SECTION_LENGTH);
 	if (ret == FAIL) {
-		GTP_ERROR("[burn_fw_ss51]load ss51 firmware section 3 fail.");
-		goto exit_burn_fw_ss51;
+		pr_err("load ss51 firmware section 3 fail.");
+		return FAIL;
 	}
 
 	/* step8:burn ss51 firmware section 3 */
-	GTP_DEBUG("[burn_fw_ss51]step8:burn ss51 firmware section 3");
+	pr_debug("step8:burn ss51 firmware section 3");
 	ret = gup_burn_fw_section(client, fw_ss51, 0xC000, 0x13);
 	if (ret == FAIL) {
-		GTP_ERROR("[burn_fw_ss51]burn ss51 firmware section 3 fail.");
-		goto exit_burn_fw_ss51;
+		pr_err("burn ss51 firmware section 3 fail.");
+		return FAIL;
 	}
 
 	/* step9:load ss51 firmware section 4 file data */
-	GTP_DEBUG("[burn_fw_ss51]step9:load ss51 firmware section 4 file data");
+	pr_debug("step9:load ss51 firmware section 4 file data");
 	ret = gup_load_section_file(fw_ss51, 3*FW_SECTION_LENGTH,
 							FW_SECTION_LENGTH);
 	if (ret == FAIL) {
-		GTP_ERROR("[burn_fw_ss51]load ss51 firmware section 4 fail.");
-		goto exit_burn_fw_ss51;
+		pr_err("load ss51 firmware section 4 fail.");
+		return FAIL;
 	}
 
 	/* step10:burn ss51 firmware section 4 */
-	GTP_DEBUG("[burn_fw_ss51]step10:burn ss51 firmware section 4");
+	pr_debug("step10:burn ss51 firmware section 4");
 	ret = gup_burn_fw_section(client, fw_ss51, 0xE000, 0x14);
 	if (ret == FAIL) {
-		GTP_ERROR("[burn_fw_ss51]burn ss51 firmware section 4 fail.");
-		goto exit_burn_fw_ss51;
+		pr_err("burn ss51 firmware section 4 fail.");
+		return FAIL;
 	}
 
-	ret = SUCCESS;
-
-exit_burn_fw_ss51:
-	kfree(fw_ss51);
-	return ret;
+	return SUCCESS;
 }
 
 static u8 gup_burn_fw_dsp(struct i2c_client *client)
@@ -1381,111 +1172,101 @@
 	u8  retry = 0;
 	u8  rd_buf[5];
 
-	GTP_DEBUG("[burn_fw_dsp]Begin burn dsp firmware---->>");
+	pr_debug("Begin burn dsp firmware.");
 	/* step1:alloc memory */
-	GTP_DEBUG("[burn_fw_dsp]step1:alloc memory");
+	pr_debug("step1:alloc memory");
 	while (retry++ < 5) {
-		fw_dsp = kzalloc(FW_DSP_LENGTH, GFP_KERNEL);
+		fw_dsp = devm_kzalloc(&client->dev, FW_DSP_LENGTH,
+							GFP_KERNEL);
 		if (fw_dsp == NULL) {
 			continue;
 		} else  {
-			GTP_INFO("[burn_fw_dsp]Alloc %dk byte memory success.",
+			pr_info("Alloc %dk byte memory success.",
 					(FW_SECTION_LENGTH/1024));
 			break;
 		}
 	}
-	if (retry >= 5) {
-		GTP_ERROR("[burn_fw_dsp]Alloc memory fail,exit.");
+	if (retry == 5) {
+		pr_err("Alloc memory fail,exit.");
 		return FAIL;
 	}
 
 	/* step2:load firmware dsp */
-	GTP_DEBUG("[burn_fw_dsp]step2:load firmware dsp");
+	pr_debug("step2:load firmware dsp");
 	ret = gup_load_section_file(fw_dsp, 4*FW_SECTION_LENGTH, FW_DSP_LENGTH);
 	if (ret == FAIL) {
-		GTP_ERROR("[burn_fw_dsp]load firmware dsp fail.");
-		goto exit_burn_fw_dsp;
+		pr_err("load firmware dsp fail.");
+		return ret;
 	}
 
 	/* step3:select bank3 */
-	GTP_DEBUG("[burn_fw_dsp]step3:select bank3");
+	pr_debug("step3:select bank3");
 	ret = gup_set_ic_msg(client, _bRW_MISCTL__SRAM_BANK, 0x03);
 	if (ret <= 0) {
-		GTP_ERROR("[burn_fw_dsp]select bank3 fail.");
-		ret = FAIL;
-		goto exit_burn_fw_dsp;
+		pr_err("select bank3 fail.");
+		return FAIL;
 	}
 
 	/* Step4:hold ss51 & dsp */
-	GTP_DEBUG("[burn_fw_dsp]step4:hold ss51 & dsp");
+	pr_debug("step4:hold ss51 & dsp");
 	ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x0C);
 	if (ret <= 0) {
-		GTP_ERROR("[burn_fw_dsp]hold ss51 & dsp fail.");
-		ret = FAIL;
-		goto exit_burn_fw_dsp;
+		pr_err("hold ss51 & dsp fail.");
+		return FAIL;
 	}
 
 	/* step5:set scramble */
-	GTP_DEBUG("[burn_fw_dsp]step5:set scramble");
+	pr_debug("step5:set scramble");
 	ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_OPT_B0_, 0x00);
 	if (ret <= 0) {
-		GTP_ERROR("[burn_fw_dsp]set scramble fail.");
-		ret = FAIL;
-		goto exit_burn_fw_dsp;
+		pr_err("set scramble fail.");
+		return FAIL;
 	}
 
 	/* step6:release ss51 & dsp */
-	GTP_DEBUG("[burn_fw_dsp]step6:release ss51 & dsp");
+	pr_debug("step6:release ss51 & dsp");
 	ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x04);
 	if (ret <= 0) {
-		GTP_ERROR("[burn_fw_dsp]release ss51 & dsp fail.");
-		ret = FAIL;
-		goto exit_burn_fw_dsp;
+		pr_err("release ss51 & dsp fail.");
+		return FAIL;
 	}
 	/* must delay */
 	msleep(20);
 
 	/* step7:burn 4k dsp firmware */
-	GTP_DEBUG("[burn_fw_dsp]step7:burn 4k dsp firmware");
+	pr_debug("step7:burn 4k dsp firmware");
 	ret = gup_burn_proc(client, fw_dsp, 0x9000, FW_DSP_LENGTH);
-	if (FAIL == ret) {
-		GTP_ERROR("[burn_fw_dsp]burn fw_section fail.");
-		goto exit_burn_fw_dsp;
+	if (ret == FAIL) {
+		pr_err("[burn_fw_dsp]burn fw_section fail.");
+		return ret;
 	}
 
 	/* step8:send burn cmd to move data to flash from sram */
-	GTP_DEBUG("[burn_fw_dsp]step8:send burn cmd to move data to flash" \
-						"from sram");
+	pr_debug("step8:send burn cmd to move data to flash from sram");
 	ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, 0x05);
 	if (ret <= 0) {
-		GTP_ERROR("[burn_fw_dsp]send burn cmd fail.");
-		goto exit_burn_fw_dsp;
+		pr_err("send burn cmd fail.");
+		return ret;
 	}
-	GTP_DEBUG("[burn_fw_dsp]Wait for the burn is complete......");
+	pr_debug("Wait for the burn is complete.");
 	do {
 		ret = gup_get_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, rd_buf, 1);
 		if (ret <= 0) {
-			GTP_ERROR("[burn_fw_dsp]Get burn state fail");
-			goto exit_burn_fw_dsp;
+			pr_err("Get burn state fail");
+			return ret;
 		}
 		msleep(20);
-		/* GTP_DEBUG("[burn_fw_dsp]Get burn state:%d.",
-						rd_buf[GTP_ADDR_LENGTH]); */
 	} while (rd_buf[GTP_ADDR_LENGTH]);
 
 	/* step9:recall check 4k dsp firmware */
-	GTP_DEBUG("[burn_fw_dsp]step9:recall check 4k dsp firmware");
+	pr_debug("step9:recall check 4k dsp firmware");
 	ret = gup_recall_check(client, fw_dsp, 0x9000, FW_DSP_LENGTH);
 	if (ret == FAIL) {
-		GTP_ERROR("[burn_fw_dsp]recall check 4k dsp firmware fail.");
-		goto exit_burn_fw_dsp;
+		pr_err("recall check 4k dsp firmware fail.");
+		return ret;
 	}
 
-	ret = SUCCESS;
-
-exit_burn_fw_dsp:
-	kfree(fw_dsp);
-	return ret;
+	return SUCCESS;
 }
 
 static u8 gup_burn_fw_boot(struct i2c_client *client)
@@ -1495,177 +1276,171 @@
 	u8  retry = 0;
 	u8  rd_buf[5];
 
-	GTP_DEBUG("[burn_fw_boot]Begin burn bootloader firmware---->>");
+	pr_debug("Begin burn bootloader firmware.");
 
 	/* step1:Alloc memory */
-	GTP_DEBUG("[burn_fw_boot]step1:Alloc memory");
+	pr_debug("step1:Alloc memory");
 	while (retry++ < 5) {
-		fw_boot = kzalloc(FW_BOOT_LENGTH, GFP_KERNEL);
+		fw_boot = devm_kzalloc(&client->dev, FW_BOOT_LENGTH,
+							GFP_KERNEL);
 		if (fw_boot == NULL) {
 			continue;
 		} else {
-			GTP_INFO("[burn_fw_boot]Alloc %dk byte memory success.",
+			pr_info("Alloc %dk byte memory success.",
 						(FW_BOOT_LENGTH/1024));
 			break;
 		}
 	}
-	if (retry >= 5) {
-		GTP_ERROR("[burn_fw_boot]Alloc memory fail,exit.");
+	if (retry == 5) {
+		pr_err("Alloc memory fail,exit.");
 		return FAIL;
 	}
 
 	/* step2:load firmware bootloader */
-	GTP_DEBUG("[burn_fw_boot]step2:load firmware bootloader");
+	pr_debug("step2:load firmware bootloader");
 	ret = gup_load_section_file(fw_boot, (4 * FW_SECTION_LENGTH +
 				FW_DSP_LENGTH), FW_BOOT_LENGTH);
 	if (ret == FAIL) {
-		GTP_ERROR("[burn_fw_boot]load firmware dsp fail.");
-		goto exit_burn_fw_boot;
+		pr_err("load firmware dsp fail.");
+		return ret;
 	}
 
 	/* step3:hold ss51 & dsp */
-	GTP_DEBUG("[burn_fw_boot]step3:hold ss51 & dsp");
+	pr_debug("step3:hold ss51 & dsp");
 	ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x0C);
 	if (ret <= 0) {
-		GTP_ERROR("[burn_fw_boot]hold ss51 & dsp fail.");
-		ret = FAIL;
-		goto exit_burn_fw_boot;
+		pr_err("hold ss51 & dsp fail.");
+		return FAIL;
 	}
 
 	/* step4:set scramble */
-	GTP_DEBUG("[burn_fw_boot]step4:set scramble");
+	pr_debug("step4:set scramble");
 	ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_OPT_B0_, 0x00);
 	if (ret <= 0) {
-		GTP_ERROR("[burn_fw_boot]set scramble fail.");
-		ret = FAIL;
-		goto exit_burn_fw_boot;
+		pr_err("set scramble fail.");
+		return FAIL;
 	}
 
 	/* step5:release ss51 & dsp */
-	GTP_DEBUG("[burn_fw_boot]step5:release ss51 & dsp");
+	pr_debug("step5:release ss51 & dsp");
 	ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x04);
 	if (ret <= 0) {
-		GTP_ERROR("[burn_fw_boot]release ss51 & dsp fail.");
-		ret = FAIL;
-		goto exit_burn_fw_boot;
+		pr_err("release ss51 & dsp fail.");
+		return FAIL;
 	}
 	/* must delay */
 	msleep(20);
 
 	/* step6:select bank3 */
-	GTP_DEBUG("[burn_fw_boot]step6:select bank3");
+	pr_debug("step6:select bank3");
 	ret = gup_set_ic_msg(client, _bRW_MISCTL__SRAM_BANK, 0x03);
 	if (ret <= 0) {
-		GTP_ERROR("[burn_fw_boot]select bank3 fail.");
-		ret = FAIL;
-		goto exit_burn_fw_boot;
+		pr_err("select bank3 fail.");
+		return FAIL;
 	}
 
 	/* step7:burn 2k bootloader firmware */
-	GTP_DEBUG("[burn_fw_boot]step7:burn 2k bootloader firmware");
+	pr_debug("step7:burn 2k bootloader firmware");
 	ret = gup_burn_proc(client, fw_boot, 0x9000, FW_BOOT_LENGTH);
 	if (ret == FAIL) {
-		GTP_ERROR("[burn_fw_boot]burn fw_section fail.");
-		goto exit_burn_fw_boot;
+		pr_err("burn fw_section fail.");
+		return ret;
 	}
 
 	/* step7:send burn cmd to move data to flash from sram */
-	GTP_DEBUG("[burn_fw_boot]step7:send burn cmd to move data to" \
-				"flash from sram");
+	pr_debug("step7:send burn cmd to flash data from sram");
 	ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, 0x06);
 	if (ret <= 0) {
-		GTP_ERROR("[burn_fw_boot]send burn cmd fail.");
-		goto exit_burn_fw_boot;
+		pr_err("send burn cmd fail.");
+		return ret;
 	}
-	GTP_DEBUG("[burn_fw_boot]Wait for the burn is complete......");
+	pr_debug("Wait for the burn is complete.");
 	do {
 		ret = gup_get_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, rd_buf, 1);
 		if (ret <= 0) {
-			GTP_ERROR("[burn_fw_boot]Get burn state fail");
-			goto exit_burn_fw_boot;
+			pr_err("Get burn state fail");
+			return ret;
 		}
 		msleep(20);
-		/* GTP_DEBUG("[burn_fw_boot]Get burn state:%d.",
-						rd_buf[GTP_ADDR_LENGTH]); */
 	} while (rd_buf[GTP_ADDR_LENGTH]);
 
 	/* step8:recall check 2k bootloader firmware */
-	GTP_DEBUG("[burn_fw_boot]step8:recall check 2k bootloader firmware");
+	pr_debug("step8:recall check 2k bootloader firmware");
 	ret = gup_recall_check(client, fw_boot, 0x9000, FW_BOOT_LENGTH);
 	if (ret == FAIL) {
-		GTP_ERROR("[burn_fw_boot]recall check 4k dsp firmware fail.");
-		goto exit_burn_fw_boot;
+		pr_err("recall check 4k dsp firmware fail.");
+		return ret;
 	}
 
 	/* step9:enable download DSP code  */
-	GTP_DEBUG("[burn_fw_boot]step9:enable download DSP code ");
+	pr_debug("step9:enable download DSP code ");
 	ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, 0x99);
 	if (ret <= 0) {
-		GTP_ERROR("[burn_fw_boot]enable download DSP code fail.");
-		ret = FAIL;
-		goto exit_burn_fw_boot;
+		pr_err("enable download DSP code fail.");
+		return FAIL;
 	}
 
 	/* step10:release ss51 & hold dsp */
-	GTP_DEBUG("[burn_fw_boot]step10:release ss51 & hold dsp");
+	pr_debug("step10:release ss51 & hold dsp");
 	ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x08);
 	if (ret <= 0) {
-		GTP_ERROR("[burn_fw_boot]release ss51 & hold dsp fail.");
-		ret = FAIL;
-		goto exit_burn_fw_boot;
+		pr_err("release ss51 & hold dsp fail.");
+		return FAIL;
 	}
 
-	ret = SUCCESS;
-
-exit_burn_fw_boot:
-	kfree(fw_boot);
-	return ret;
+	return SUCCESS;
 }
 
 s32 gup_update_proc(void *dir)
 {
 	s32 ret = 0;
-	u8  retry = 0;
-	st_fw_head fw_head;
+	u8 retry = 0;
+	struct st_fw_head fw_head;
 	struct goodix_ts_data *ts = NULL;
 
-	GTP_DEBUG("[update_proc]Begin update ......");
+	pr_debug("Begin update.");
+
+	if (!i2c_connect_client) {
+		pr_err("No i2c connect client for %s\n", __func__);
+		return -EIO;
+	}
 
 	show_len = 1;
 	total_len = 100;
-	if (dir == NULL)
-		/* wait main thread to be completed */
-	msleep(3000);
 
 	ts = i2c_get_clientdata(i2c_connect_client);
 
 	if (searching_file) {
 		/* exit .bin update file searching  */
 		searching_file = 0;
-		GTP_INFO("Exiting searching .bin update file...");
+		pr_info("Exiting searching .bin update file.");
 		/* wait for auto update quitted completely */
 		while ((show_len != 200) && (show_len != 100))
 			msleep(100);
 	}
 
-	update_msg.file = NULL;
 	ret = gup_check_update_file(i2c_connect_client, &fw_head, (u8 *)dir);
 	if (ret == FAIL) {
-		GTP_ERROR("[update_proc]check update file fail.");
+		pr_err("check update file fail.");
 		goto file_fail;
 	}
 
 	/* gtp_reset_guitar(i2c_connect_client, 20); */
 	ret = gup_get_ic_fw_msg(i2c_connect_client);
 	if (ret == FAIL) {
-		GTP_ERROR("[update_proc]get ic message fail.");
+		pr_err("get ic message fail.");
 		goto file_fail;
 	}
 
-	ret = gup_enter_update_judge(&fw_head);
-	if (ret == FAIL) {
-		GTP_ERROR("[update_proc]Check *.bin file fail.");
-		goto file_fail;
+	if (ts->force_update) {
+		dev_dbg(&ts->client->dev, "Enter force update.");
+	} else {
+		ret = gup_enter_update_judge(ts->client, &fw_head);
+		if (ret == FAIL) {
+			dev_err(&ts->client->dev,
+					"Check *.bin file fail.");
+			goto file_fail;
+		}
 	}
 
 	ts->enter_update = 1;
@@ -1675,7 +1450,7 @@
 #endif
 	ret = gup_enter_update_mode(i2c_connect_client);
 	if (ret == FAIL) {
-		GTP_ERROR("[update_proc]enter update mode fail.");
+		pr_err("enter update mode fail.");
 		goto update_fail;
 	}
 
@@ -1684,52 +1459,46 @@
 		total_len = 100;
 		ret = gup_burn_dsp_isp(i2c_connect_client);
 		if (ret == FAIL) {
-			GTP_ERROR("[update_proc]burn dsp isp fail.");
+			pr_err("burn dsp isp fail.");
 			continue;
 		}
 
 		show_len += 10;
 		ret = gup_burn_fw_ss51(i2c_connect_client);
 		if (ret == FAIL) {
-			GTP_ERROR("[update_proc]burn ss51 firmware fail.");
+			pr_err("burn ss51 firmware fail.");
 			continue;
 		}
 
 		show_len += 40;
 		ret = gup_burn_fw_dsp(i2c_connect_client);
 		if (ret == FAIL) {
-			GTP_ERROR("[update_proc]burn dsp firmware fail.");
+			pr_err("burn dsp firmware fail.");
 			continue;
 		}
 
 		show_len += 20;
 		ret = gup_burn_fw_boot(i2c_connect_client);
 		if (ret == FAIL) {
-			GTP_ERROR("[update_proc]burn bootloader fw fail.");
+			pr_err("burn bootloader fw fail.");
 			continue;
 		}
 		show_len += 10;
-		GTP_INFO("[update_proc]UPDATE SUCCESS.");
+		pr_info("UPDATE SUCCESS.");
 		break;
 	}
 	if (retry >= 5) {
-		GTP_ERROR("[update_proc]retry timeout,UPDATE FAIL.");
+		pr_err("retry timeout,UPDATE FAIL.");
 		goto update_fail;
 	}
 
-	GTP_DEBUG("[update_proc]leave update mode.");
-	gup_leave_update_mode();
+	pr_debug("leave update mode.");
+	gup_leave_update_mode(i2c_connect_client);
 
 	msleep(100);
 
-	/* GTP_DEBUG("[update_proc]send config.");
-	ret = gtp_send_cfg(i2c_connect_client);
-	if(ret < 0) {
-		GTP_ERROR("[update_proc]send config fail.");
-	} */
-
 	if (ts->fw_error) {
-		GTP_INFO("firmware error auto update, resent config!");
+		pr_info("firmware error auto update, resent config!");
 		gup_init_panel(ts);
 	}
 	show_len = 100;
@@ -1740,7 +1509,11 @@
 #if GTP_ESD_PROTECT
 	gtp_esd_switch(ts->client, SWITCH_ON);
 #endif
-	filp_close(update_msg.file, NULL);
+	if (update_msg.need_free) {
+		devm_kfree(&ts->client->dev, update_msg.fw_data);
+		update_msg.need_free = false;
+	}
+
 	return SUCCESS;
 
 update_fail:
@@ -1752,26 +1525,28 @@
 #endif
 
 file_fail:
-	if (update_msg.file && !IS_ERR(update_msg.file))
-		filp_close(update_msg.file, NULL);
-
 	show_len = 200;
 	total_len = 100;
+	if (update_msg.need_free) {
+		devm_kfree(&ts->client->dev, update_msg.fw_data);
+		update_msg.need_free = false;
+	}
 	return FAIL;
 }
 
-#if GTP_AUTO_UPDATE
+static void gup_update_work(struct work_struct *work)
+{
+	if (gup_update_proc(NULL) == FAIL)
+		pr_err("Goodix update work fail!\n");
+}
+
 u8 gup_init_update_proc(struct goodix_ts_data *ts)
 {
-	struct task_struct *thread = NULL;
+	dev_dbg(&ts->client->dev, "Ready to run update work.");
 
-	GTP_INFO("Ready to run update thread.");
-	thread = kthread_run(gup_update_proc, (void *)NULL, "guitar_update");
-	if (IS_ERR(thread)) {
-		GTP_ERROR("Failed to create update thread.\n");
-		return -EINVAL;
-	}
+	INIT_DELAYED_WORK(&ts->goodix_update_work, gup_update_work);
+	schedule_delayed_work(&ts->goodix_update_work,
+		msecs_to_jiffies(3000));
 
 	return 0;
 }
-#endif
diff --git a/drivers/input/touchscreen/synaptics_fw_update.c b/drivers/input/touchscreen/synaptics_fw_update.c
index 7da0376..dce9dee 100644
--- a/drivers/input/touchscreen/synaptics_fw_update.c
+++ b/drivers/input/touchscreen/synaptics_fw_update.c
@@ -1559,7 +1559,7 @@
 		}
 
 		dev_dbg(&fwu->rmi4_data->i2c_client->dev,
-				"%s: Firmware image size = %d\n",
+				"%s: Firmware image size = %zu\n",
 				__func__, fw_entry->size);
 
 		fwu->data_buffer = fw_entry->data;
@@ -1670,7 +1670,7 @@
 
 	if (count < fwu->config_size) {
 		dev_err(&rmi4_data->i2c_client->dev,
-				"%s: Not enough space (%d bytes) in buffer\n",
+				"%s: Not enough space (%zu bytes) in buffer\n",
 				__func__, count);
 		return -EINVAL;
 	}
@@ -1905,12 +1905,20 @@
 		struct device_attribute *attr, const char *buf, size_t count)
 {
 	int retval;
-	unsigned long config_area;
+	unsigned short config_area;
+	struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
 
-	retval = kstrtoul(buf, 10, &config_area);
+	retval = kstrtou16(buf, 10, &config_area);
 	if (retval)
 		return retval;
 
+	if (config_area < 0x00 || config_area > 0x03) {
+		dev_err(&rmi4_data->i2c_client->dev,
+			"%s: Incorrect value of config_area\n",
+			 __func__);
+		return -EINVAL;
+	}
+
 	fwu->config_area = config_area;
 
 	return count;
diff --git a/drivers/input/touchscreen/synaptics_i2c_rmi4.c b/drivers/input/touchscreen/synaptics_i2c_rmi4.c
index 755084c..ca47547 100644
--- a/drivers/input/touchscreen/synaptics_i2c_rmi4.c
+++ b/drivers/input/touchscreen/synaptics_i2c_rmi4.c
@@ -113,16 +113,15 @@
 
 static void synaptics_rmi4_sensor_wake(struct synaptics_rmi4_data *rmi4_data);
 
-static void synaptics_rmi4_sensor_sleep(struct synaptics_rmi4_data *rmi4_data);
-
 static int synaptics_rmi4_check_configuration(struct synaptics_rmi4_data
 		*rmi4_data);
 
-#ifdef CONFIG_PM
+
 static int synaptics_rmi4_suspend(struct device *dev);
 
 static int synaptics_rmi4_resume(struct device *dev);
 
+#ifdef CONFIG_PM
 static ssize_t synaptics_rmi4_full_pm_cycle_show(struct device *dev,
 		struct device_attribute *attr, char *buf);
 
@@ -425,6 +424,31 @@
 static bool exp_fn_inited;
 static struct mutex exp_fn_list_mutex;
 static struct list_head exp_fn_list;
+
+static int synaptics_rmi4_debug_suspend_set(void *_data, u64 val)
+{
+	struct synaptics_rmi4_data *rmi4_data = _data;
+
+	if (val)
+		synaptics_rmi4_suspend(&rmi4_data->input_dev->dev);
+	else
+		synaptics_rmi4_resume(&rmi4_data->input_dev->dev);
+
+	return 0;
+}
+
+static int synaptics_rmi4_debug_suspend_get(void *_data, u64 *val)
+{
+	struct synaptics_rmi4_data *rmi4_data = _data;
+
+	*val = rmi4_data->suspended;
+
+	return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(debug_suspend_fops, synaptics_rmi4_debug_suspend_get,
+			synaptics_rmi4_debug_suspend_set, "%lld\n");
+
 #ifdef CONFIG_PM
 static ssize_t synaptics_rmi4_full_pm_cycle_show(struct device *dev,
 		struct device_attribute *attr, char *buf)
@@ -449,30 +473,6 @@
 	return count;
 }
 
-static int synaptics_rmi4_debug_suspend_set(void *_data, u64 val)
-{
-	struct synaptics_rmi4_data *rmi4_data = _data;
-
-	if (val)
-		synaptics_rmi4_suspend(&rmi4_data->input_dev->dev);
-	else
-		synaptics_rmi4_resume(&rmi4_data->input_dev->dev);
-
-	return 0;
-}
-
-static ssize_t synaptics_rmi4_debug_suspend_get(void *_data, u64 *val)
-{
-	struct synaptics_rmi4_data *rmi4_data = _data;
-
-	*val = rmi4_data->suspended;
-
-	return 0;
-}
-
-DEFINE_SIMPLE_ATTRIBUTE(debug_suspend_fops, synaptics_rmi4_debug_suspend_get,
-			synaptics_rmi4_debug_suspend_set, "%lld\n");
-
 #ifdef CONFIG_FB
 static void configure_sleep(struct synaptics_rmi4_data *rmi4_data)
 {
@@ -502,6 +502,11 @@
 	return;
 }
 #endif
+#else
+static void configure_sleep(struct synaptics_rmi4_data *rmi4_data)
+{
+	return;
+}
 #endif
 
 static ssize_t synaptics_rmi4_f01_reset_store(struct device *dev,
@@ -2424,6 +2429,8 @@
 		}
 	}
 
+	INIT_LIST_HEAD(&rmi->support_fn_list);
+
 	retval = synaptics_rmi4_query_device(rmi4_data);
 	if (retval < 0) {
 		dev_err(&rmi4_data->i2c_client->dev,
@@ -3663,6 +3670,14 @@
 {
 	return 0;
 };
+static int synaptics_rmi4_suspend(struct device *dev);
+{
+	return 0;
+}
+static int synaptics_rmi4_resume(struct device *dev);
+{
+	return 0;
+}
 #endif
 
 static const struct i2c_device_id synaptics_rmi4_id_table[] = {
diff --git a/drivers/input/touchscreen/synaptics_rmi_dev.c b/drivers/input/touchscreen/synaptics_rmi_dev.c
index 7abd909..8478b24 100644
--- a/drivers/input/touchscreen/synaptics_rmi_dev.c
+++ b/drivers/input/touchscreen/synaptics_rmi_dev.c
@@ -461,7 +461,7 @@
 	return;
 }
 
-static char *rmi_char_devnode(struct device *dev, mode_t *mode)
+static char *rmi_char_devnode(struct device *dev, umode_t *mode)
 {
 	if (!mode)
 		return NULL;
diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig
index 8e70129..cb1dbd4 100644
--- a/drivers/iommu/Kconfig
+++ b/drivers/iommu/Kconfig
@@ -87,6 +87,16 @@
          section mappings and TLB misses should be quite infrequent.
          Most people can probably say Y here.
 
+config MSM_IOMMU_VBIF_CHECK
+	bool "Enable support for VBIF check when IOMMU gets stuck"
+	depends on MSM_IOMMU
+	help
+	  Enables an extra check in the IOMMU driver that logs debugging
+	  information when TLB sync or iommu halt issue occurs. This helps
+	  in debugging such issues.
+
+	  If unsure, say N here.
+
 config IOMMU_NON_SECURE
 	bool "Turns on programming of secure SMMU by kernel"
 	depends on MSM_IOMMU
diff --git a/drivers/iommu/msm_iommu-v1.c b/drivers/iommu/msm_iommu-v1.c
index 84f81bf..50581f8 100644
--- a/drivers/iommu/msm_iommu-v1.c
+++ b/drivers/iommu/msm_iommu-v1.c
@@ -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 @@
 #include <linux/platform_device.h>
 #include <linux/errno.h>
 #include <linux/io.h>
+#include <linux/iopoll.h>
 #include <linux/interrupt.h>
 #include <linux/list.h>
 #include <linux/mutex.h>
@@ -143,13 +144,141 @@
 	.iommu_lock_release = _iommu_lock_release,
 };
 
-void iommu_halt(const struct msm_iommu_drvdata *iommu_drvdata)
+#ifdef CONFIG_MSM_IOMMU_VBIF_CHECK
+
+#define VBIF_XIN_HALT_CTRL0 0x200
+#define VBIF_XIN_HALT_CTRL1 0x204
+#define VBIF_AXI_HALT_CTRL0 0x208
+#define VBIF_AXI_HALT_CTRL1 0x20C
+
+static void __halt_vbif_xin(void __iomem *vbif_base)
+{
+	pr_err("Halting VBIF_XIN\n");
+	writel_relaxed(0xFFFFFFFF, vbif_base + VBIF_XIN_HALT_CTRL0);
+}
+
+static void __dump_vbif_state(void __iomem *base, void __iomem *vbif_base)
+{
+	unsigned int reg_val;
+
+	reg_val = readl_relaxed(base + MICRO_MMU_CTRL);
+	pr_err("Value of SMMU_IMPLDEF_MICRO_MMU_CTRL = 0x%x\n", reg_val);
+
+	reg_val = readl_relaxed(vbif_base + VBIF_XIN_HALT_CTRL0);
+	pr_err("Value of VBIF_XIN_HALT_CTRL0 = 0x%x\n", reg_val);
+	reg_val = readl_relaxed(vbif_base + VBIF_XIN_HALT_CTRL1);
+	pr_err("Value of VBIF_XIN_HALT_CTRL1 = 0x%x\n", reg_val);
+	reg_val = readl_relaxed(vbif_base + VBIF_AXI_HALT_CTRL0);
+	pr_err("Value of VBIF_AXI_HALT_CTRL0 = 0x%x\n", reg_val);
+	reg_val = readl_relaxed(vbif_base + VBIF_AXI_HALT_CTRL1);
+	pr_err("Value of VBIF_AXI_HALT_CTRL1 = 0x%x\n", reg_val);
+}
+
+static int __check_vbif_state(struct msm_iommu_drvdata const *drvdata)
+{
+	phys_addr_t addr = (phys_addr_t) (drvdata->phys_base
+			   - (phys_addr_t) 0x4000);
+	void __iomem *base = ioremap(addr, 0x1000);
+	int ret = 0;
+
+	if (base) {
+		__dump_vbif_state(drvdata->base, base);
+		__halt_vbif_xin(drvdata->base);
+		__dump_vbif_state(drvdata->base, base);
+		iounmap(base);
+	} else {
+		pr_err("%s: Unable to ioremap\n", __func__);
+		ret = -ENOMEM;
+	}
+	return ret;
+}
+
+static void check_halt_state(struct msm_iommu_drvdata const *drvdata)
+{
+	int res;
+	unsigned int val;
+	void __iomem *base = drvdata->base;
+	char const *name = drvdata->name;
+
+	pr_err("Timed out waiting for IOMMU halt to complete for %s\n", name);
+	res = __check_vbif_state(drvdata);
+	if (res)
+		BUG();
+
+	pr_err("Checking if IOMMU halt completed for %s\n", name);
+
+	res = readl_tight_poll_timeout(
+		GLB_REG(MICRO_MMU_CTRL, base), val,
+			(val & MMU_CTRL_IDLE) == MMU_CTRL_IDLE, 5000000);
+
+	if (res) {
+		pr_err("Timed out (again) waiting for IOMMU halt to complete for %s\n",
+			name);
+	} else {
+		pr_err("IOMMU halt completed. VBIF FIFO most likely not getting drained by master\n");
+	}
+	BUG();
+}
+
+static void check_tlb_sync_state(struct msm_iommu_drvdata const *drvdata,
+				int ctx)
+{
+	int res;
+	unsigned int val;
+	void __iomem *base = drvdata->base;
+	char const *name = drvdata->name;
+
+	pr_err("Timed out waiting for TLB SYNC to complete for %s\n", name);
+	res = __check_vbif_state(drvdata);
+	if (res)
+		BUG();
+
+	pr_err("Checking if TLB sync completed for %s\n", name);
+
+	res = readl_tight_poll_timeout(CTX_REG(CB_TLBSTATUS, base, ctx), val,
+				(val & CB_TLBSTATUS_SACTIVE) == 0, 5000000);
+	if (res) {
+		pr_err("Timed out (again) waiting for TLB SYNC to complete for %s\n",
+			name);
+	} else {
+		pr_err("TLB Sync completed. VBIF FIFO most likely not getting drained by master\n");
+	}
+	BUG();
+}
+
+#else
+
+/*
+ * For targets without VBIF or for targets with the VBIF check disabled
+ * we directly just crash to capture the issue
+ */
+static void check_halt_state(struct msm_iommu_drvdata const *drvdata)
+{
+	BUG();
+}
+
+static void check_tlb_sync_state(struct msm_iommu_drvdata const *drvdata,
+				int ctx)
+{
+	BUG();
+}
+
+#endif
+
+void iommu_halt(struct msm_iommu_drvdata const *iommu_drvdata)
 {
 	if (iommu_drvdata->halt_enabled) {
-		SET_MICRO_MMU_CTRL_HALT_REQ(iommu_drvdata->base, 1);
+		unsigned int val;
+		void __iomem *base = iommu_drvdata->base;
+		int res;
 
-		while (GET_MICRO_MMU_CTRL_IDLE(iommu_drvdata->base) == 0)
-			cpu_relax();
+		SET_MICRO_MMU_CTRL_HALT_REQ(base, 1);
+		res = readl_tight_poll_timeout(
+			GLB_REG(MICRO_MMU_CTRL, base), val,
+			     (val & MMU_CTRL_IDLE) == MMU_CTRL_IDLE, 5000000);
+
+		if (res)
+			check_halt_state(iommu_drvdata);
 		/* Ensure device is idle before continuing */
 		mb();
 	}
@@ -173,15 +302,19 @@
 	}
 }
 
-static void __sync_tlb(void __iomem *base, int ctx)
+static void __sync_tlb(struct msm_iommu_drvdata *iommu_drvdata, int ctx)
 {
+	unsigned int val;
+	unsigned int res;
+	void __iomem *base = iommu_drvdata->base;
+
 	SET_TLBSYNC(base, ctx, 0);
-
-	/* No barrier needed due to register proximity */
-	while (GET_CB_TLBSTATUS_SACTIVE(base, ctx))
-		cpu_relax();
-
 	/* No barrier needed due to read dependency */
+
+	res = readl_tight_poll_timeout(CTX_REG(CB_TLBSTATUS, base, ctx), val,
+				(val & CB_TLBSTATUS_SACTIVE) == 0, 5000000);
+	if (res)
+		check_tlb_sync_state(iommu_drvdata, ctx);
 }
 
 static int __flush_iotlb_va(struct iommu_domain *domain, unsigned int va)
@@ -205,7 +338,7 @@
 		SET_TLBIVA(iommu_drvdata->base, ctx_drvdata->num,
 			   ctx_drvdata->asid | (va & CB_TLBIVA_VA));
 		mb();
-		__sync_tlb(iommu_drvdata->base, ctx_drvdata->num);
+		__sync_tlb(iommu_drvdata, ctx_drvdata->num);
 		__disable_clocks(iommu_drvdata);
 	}
 fail:
@@ -232,7 +365,7 @@
 		SET_TLBIASID(iommu_drvdata->base, ctx_drvdata->num,
 			     ctx_drvdata->asid);
 		mb();
-		__sync_tlb(iommu_drvdata->base, ctx_drvdata->num);
+		__sync_tlb(iommu_drvdata, ctx_drvdata->num);
 		__disable_clocks(iommu_drvdata);
 	}
 
@@ -343,15 +476,14 @@
 	mb();
 }
 
-static void __release_smg(void __iomem *base, int ctx)
+static void __release_smg(void __iomem *base)
 {
 	int i, smt_size;
 	smt_size = GET_IDR0_NUMSMRG(base);
 
-	/* Invalidate any SMGs associated with this context */
+	/* Invalidate all SMGs */
 	for (i = 0; i < smt_size; i++)
-		if (GET_SMR_VALID(base, i) &&
-		    GET_S2CR_CBNDX(base, i) == ctx)
+		if (GET_SMR_VALID(base, i))
 			SET_SMR_VALID(base, i, 0);
 }
 
@@ -394,17 +526,52 @@
 	}
 }
 
+
+static int program_m2v_table(struct device *dev, void __iomem *base)
+{
+	struct msm_iommu_ctx_drvdata *ctx_drvdata = dev_get_drvdata(dev);
+	u32 *sids = ctx_drvdata->sids;
+	unsigned int ctx = ctx_drvdata->num;
+	int num = 0, i, smt_size;
+	int len = ctx_drvdata->nsid;
+
+	smt_size = GET_IDR0_NUMSMRG(base);
+	/* Program the M2V tables for this context */
+	for (i = 0; i < len / sizeof(*sids); i++) {
+		for (; num < smt_size; num++)
+			if (GET_SMR_VALID(base, num) == 0)
+				break;
+		BUG_ON(num >= smt_size);
+
+		SET_SMR_VALID(base, num, 1);
+		SET_SMR_MASK(base, num, 0);
+		SET_SMR_ID(base, num, sids[i]);
+
+		SET_S2CR_N(base, num, 0);
+		SET_S2CR_CBNDX(base, num, ctx);
+		SET_S2CR_MEMATTR(base, num, 0x0A);
+		/* Set security bit override to be Non-secure */
+		SET_S2CR_NSCFG(base, num, 3);
+	}
+
+	return 0;
+}
+
+static void program_all_m2v_tables(struct msm_iommu_drvdata *iommu_drvdata)
+{
+	device_for_each_child(iommu_drvdata->dev, iommu_drvdata->base,
+						program_m2v_table);
+}
+
 static void __program_context(struct msm_iommu_drvdata *iommu_drvdata,
 			      struct msm_iommu_ctx_drvdata *ctx_drvdata,
-			      struct msm_iommu_priv *priv, bool is_secure)
+			      struct msm_iommu_priv *priv, bool is_secure,
+			      bool program_m2v)
 {
 	unsigned int prrr, nmrr;
-	unsigned int pn;
-	int num = 0, i, smt_size;
+	phys_addr_t pn;
 	void __iomem *base = iommu_drvdata->base;
 	unsigned int ctx = ctx_drvdata->num;
-	u32 *sids = ctx_drvdata->sids;
-	int len = ctx_drvdata->nsid;
 	phys_addr_t pgtable = __pa(priv->pt.fl_table);
 
 	__reset_context(base, ctx);
@@ -445,24 +612,9 @@
 	}
 
 	if (!is_secure) {
-		smt_size = GET_IDR0_NUMSMRG(base);
-		/* Program the M2V tables for this context */
-		for (i = 0; i < len / sizeof(*sids); i++) {
-			for (; num < smt_size; num++)
-				if (GET_SMR_VALID(base, num) == 0)
-					break;
-			BUG_ON(num >= smt_size);
+		if (program_m2v)
+			program_all_m2v_tables(iommu_drvdata);
 
-			SET_SMR_VALID(base, num, 1);
-			SET_SMR_MASK(base, num, 0);
-			SET_SMR_ID(base, num, sids[i]);
-
-			SET_S2CR_N(base, num, 0);
-			SET_S2CR_CBNDX(base, num, ctx);
-			SET_S2CR_MEMATTR(base, num, 0x0A);
-			/* Set security bit override to be Non-secure */
-			SET_S2CR_NSCFG(base, num, 3);
-		}
 		SET_CBAR_N(base, ctx, 0);
 
 		/* Stage 1 Context with Stage 2 bypass */
@@ -534,49 +686,55 @@
 	struct msm_iommu_drvdata *iommu_drvdata;
 	struct msm_iommu_ctx_drvdata *ctx_drvdata;
 	struct msm_iommu_ctx_drvdata *tmp_drvdata;
-	int ret;
+	int ret = 0;
 	int is_secure;
+	bool set_m2v = false;
 
 	mutex_lock(&msm_iommu_lock);
 
 	priv = domain->priv;
 	if (!priv || !dev) {
 		ret = -EINVAL;
-		goto fail;
+		goto unlock;
 	}
 
 	iommu_drvdata = dev_get_drvdata(dev->parent);
 	ctx_drvdata = dev_get_drvdata(dev);
 	if (!iommu_drvdata || !ctx_drvdata) {
 		ret = -EINVAL;
-		goto fail;
+		goto unlock;
 	}
 
+	++ctx_drvdata->attach_count;
+
+	if (ctx_drvdata->attach_count > 1)
+		goto already_attached;
+
 	if (!list_empty(&ctx_drvdata->attached_elm)) {
 		ret = -EBUSY;
-		goto fail;
+		goto unlock;
 	}
 
 	list_for_each_entry(tmp_drvdata, &priv->list_attached, attached_elm)
 		if (tmp_drvdata == ctx_drvdata) {
 			ret = -EBUSY;
-			goto fail;
+			goto unlock;
 		}
 
 	is_secure = iommu_drvdata->sec_id != -1;
 
 	ret = __enable_regulators(iommu_drvdata);
 	if (ret)
-		goto fail;
+		goto unlock;
 
 	ret = apply_bus_vote(iommu_drvdata, 1);
 	if (ret)
-		goto fail;
+		goto unlock;
 
 	ret = __enable_clocks(iommu_drvdata);
 	if (ret) {
 		__disable_regulators(iommu_drvdata);
-		goto fail;
+		goto unlock;
 	}
 
 	/* We can only do this once */
@@ -591,16 +749,17 @@
 			if (ret) {
 				__disable_regulators(iommu_drvdata);
 				__disable_clocks(iommu_drvdata);
-				goto fail;
+				goto unlock;
 			}
 		}
 		program_iommu_bfb_settings(iommu_drvdata->base,
 					   iommu_drvdata->bfb_settings);
+		set_m2v = true;
 	}
 
 	iommu_halt(iommu_drvdata);
 
-	__program_context(iommu_drvdata, ctx_drvdata, priv, is_secure);
+	__program_context(iommu_drvdata, ctx_drvdata, priv, is_secure, set_m2v);
 
 	iommu_resume(iommu_drvdata);
 
@@ -610,11 +769,12 @@
 	ctx_drvdata->attached_domain = domain;
 	++iommu_drvdata->ctx_attach_count;
 
+already_attached:
 	mutex_unlock(&msm_iommu_lock);
 
 	msm_iommu_attached(dev->parent);
 	return ret;
-fail:
+unlock:
 	mutex_unlock(&msm_iommu_lock);
 	return ret;
 }
@@ -633,16 +793,22 @@
 	mutex_lock(&msm_iommu_lock);
 	priv = domain->priv;
 	if (!priv || !dev)
-		goto fail;
+		goto unlock;
 
 	iommu_drvdata = dev_get_drvdata(dev->parent);
 	ctx_drvdata = dev_get_drvdata(dev);
 	if (!iommu_drvdata || !ctx_drvdata || !ctx_drvdata->attached_domain)
-		goto fail;
+		goto unlock;
+
+	--ctx_drvdata->attach_count;
+	BUG_ON(ctx_drvdata->attach_count < 0);
+
+	if (ctx_drvdata->attach_count > 0)
+		goto unlock;
 
 	ret = __enable_clocks(iommu_drvdata);
 	if (ret)
-		goto fail;
+		goto unlock;
 
 	is_secure = iommu_drvdata->sec_id != -1;
 
@@ -652,13 +818,15 @@
 	iommu_drvdata->asid[ctx_drvdata->asid - 1]--;
 	ctx_drvdata->asid = -1;
 
-	iommu_halt(iommu_drvdata);
-
 	__reset_context(iommu_drvdata->base, ctx_drvdata->num);
-	if (!is_secure)
-		__release_smg(iommu_drvdata->base, ctx_drvdata->num);
 
-	iommu_resume(iommu_drvdata);
+	/*
+	 * Only reset the M2V tables on the very last detach */
+	if (!is_secure && iommu_drvdata->ctx_attach_count == 1) {
+		iommu_halt(iommu_drvdata);
+		__release_smg(iommu_drvdata->base);
+		iommu_resume(iommu_drvdata);
+	}
 
 	__disable_clocks(iommu_drvdata);
 
@@ -670,7 +838,7 @@
 	ctx_drvdata->attached_domain = NULL;
 	BUG_ON(iommu_drvdata->ctx_attach_count == 0);
 	--iommu_drvdata->ctx_attach_count;
-fail:
+unlock:
 	mutex_unlock(&msm_iommu_lock);
 }
 
diff --git a/drivers/iommu/msm_iommu_dev-v1.c b/drivers/iommu/msm_iommu_dev-v1.c
index bbbe77b..ff6b58c 100644
--- a/drivers/iommu/msm_iommu_dev-v1.c
+++ b/drivers/iommu/msm_iommu_dev-v1.c
@@ -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
@@ -208,10 +208,14 @@
 	ret = of_platform_populate(pdev->dev.of_node,
 				   msm_iommu_v1_ctx_match_table,
 				   NULL, &pdev->dev);
-	if (ret)
+	if (ret) {
 		pr_err("Failed to create iommu context device\n");
+		goto fail;
+	}
 
 	msm_iommu_add_drv(drvdata);
+	return 0;
+
 fail:
 	__put_bus_vote_client(drvdata);
 	return ret;
@@ -295,6 +299,7 @@
 	if (!drvdata->base)
 		return -ENOMEM;
 
+	drvdata->phys_base = r->start;
 	drvdata->glb_base = drvdata->base;
 
 	if (of_get_property(pdev->dev.of_node, "vdd-supply", NULL)) {
diff --git a/drivers/iommu/msm_iommu_sec.c b/drivers/iommu/msm_iommu_sec.c
index 5a1806e..38dd41b 100644
--- a/drivers/iommu/msm_iommu_sec.c
+++ b/drivers/iommu/msm_iommu_sec.c
@@ -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
@@ -43,6 +43,7 @@
 #define IOMMU_SECURE_CFG	2
 #define IOMMU_SECURE_PTBL_SIZE  3
 #define IOMMU_SECURE_PTBL_INIT  4
+#define IOMMU_SET_CP_POOL_SIZE	5
 #define IOMMU_SECURE_MAP	6
 #define IOMMU_SECURE_UNMAP      7
 #define IOMMU_SECURE_MAP2 0x0B
@@ -51,9 +52,21 @@
 
 /* commands for SCM_SVC_UTIL */
 #define IOMMU_DUMP_SMMU_FAULT_REGS 0X0C
+#define MAXIMUM_VIRT_SIZE	(300*SZ_1M)
+
+
+#define MAKE_CP_VERSION(major, minor, patch) \
+	(((major & 0x3FF) << 22) | ((minor & 0x3FF) << 12) | (patch & 0xFFF))
+
 
 static struct iommu_access_ops *iommu_access_ops;
 
+static const struct of_device_id msm_smmu_list[] = {
+	{ .compatible = "qcom,msm-smmu-v1", },
+	{ .compatible = "qcom,msm-smmu-v2", },
+	{ }
+};
+
 struct msm_scm_paddr_list {
 	unsigned int list;
 	unsigned int list_size;
@@ -78,6 +91,11 @@
 	unsigned int flags;
 };
 
+struct msm_cp_pool_size {
+	uint32_t size;
+	uint32_t spare;
+};
+
 #define NUM_DUMP_REGS 14
 /*
  * some space to allow the number of registers returned by the secure
@@ -282,15 +300,37 @@
 	int psize[2] = {0, 0};
 	unsigned int spare;
 	int ret, ptbl_ret = 0;
+	int version;
 
-	for_each_compatible_node(np, NULL, "qcom,msm-smmu-v1")
-		if (of_find_property(np, "qcom,iommu-secure-id", NULL))
+	for_each_matching_node(np, msm_smmu_list)
+		if (of_find_property(np, "qcom,iommu-secure-id", NULL) &&
+				of_device_is_available(np))
 			break;
 
 	if (!np)
 		return 0;
 
 	of_node_put(np);
+
+	version = scm_get_feat_version(SCM_SVC_MP);
+
+	if (version >= MAKE_CP_VERSION(1, 1, 1)) {
+		struct msm_cp_pool_size psize;
+		int retval;
+
+		psize.size = MAXIMUM_VIRT_SIZE;
+		psize.spare = 0;
+
+		ret = scm_call(SCM_SVC_MP, IOMMU_SET_CP_POOL_SIZE, &psize,
+				sizeof(psize), &retval, sizeof(retval));
+
+		if (ret) {
+			pr_err("scm call IOMMU_SET_CP_POOL_SIZE failed\n");
+			goto fail;
+		}
+
+	}
+
 	ret = scm_call(SCM_SVC_MP, IOMMU_SECURE_PTBL_SIZE, &spare,
 			sizeof(spare), psize, sizeof(psize));
 	if (ret) {
diff --git a/drivers/leds/leds-qpnp.c b/drivers/leds/leds-qpnp.c
index e776dbb..0413472 100644
--- a/drivers/leds/leds-qpnp.c
+++ b/drivers/leds/leds-qpnp.c
@@ -136,11 +136,11 @@
 #define	FLASH_SELFCHECK_ENABLE		0x80
 #define FLASH_RAMP_STEP_27US		0xBF
 
-#define FLASH_STROBE_SW			0xC0
-#define FLASH_STROBE_HW			0x04
+#define FLASH_HW_SW_STROBE_SEL_MASK	0x04
 #define FLASH_STROBE_MASK		0xC7
 #define FLASH_LED_0_OUTPUT		0x80
 #define FLASH_LED_1_OUTPUT		0x40
+#define FLASH_TORCH_OUTPUT		0xC0
 
 #define FLASH_CURRENT_PRGM_MIN		1
 #define FLASH_CURRENT_PRGM_SHIFT	1
@@ -255,7 +255,7 @@
 	WLED_OVP_35V,
 	WLED_OVP_32V,
 	WLED_OVP_29V,
-	WLED_OVP_37V,
+	WLED_OVP_27V,
 };
 
 enum flash_headroom {
@@ -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)
@@ -619,7 +620,7 @@
 		for (i = 0; i < num_wled_strings; i++) {
 			rc = qpnp_led_masked_write(led,
 				WLED_FULL_SCALE_REG(led->base, i),
-				WLED_MAX_CURR_MASK, led->max_current);
+				WLED_MAX_CURR_MASK, (u8)led->max_current);
 			if (rc) {
 				dev_err(&led->spmi_dev->dev,
 					"Write max current failure (%d)\n",
@@ -689,8 +690,9 @@
 
 static int qpnp_mpp_set(struct qpnp_led_data *led)
 {
-	int rc, val;
-	int duty_us;
+	int rc;
+	u8 val;
+	int duty_us, duty_ns, period_us;
 
 	if (led->cdev.brightness) {
 		if (led->cdev.brightness < led->mpp_cfg->min_brightness) {
@@ -709,13 +711,23 @@
 			}
 		}
 		if (led->mpp_cfg->pwm_mode == PWM_MODE) {
-			pwm_disable(led->mpp_cfg->pwm_cfg->pwm_dev);
-			duty_us = (led->mpp_cfg->pwm_cfg->pwm_period_us *
-					led->cdev.brightness) / LED_FULL;
 			/*config pwm for brightness scaling*/
-			rc = pwm_config_us(led->mpp_cfg->pwm_cfg->pwm_dev,
+			period_us = led->mpp_cfg->pwm_cfg->pwm_period_us;
+			if (period_us > INT_MAX / NSEC_PER_USEC) {
+				duty_us = (period_us * led->cdev.brightness) /
+					LED_FULL;
+				rc = pwm_config_us(
+					led->mpp_cfg->pwm_cfg->pwm_dev,
 					duty_us,
-					led->mpp_cfg->pwm_cfg->pwm_period_us);
+					period_us);
+			} else {
+				duty_ns = ((period_us * NSEC_PER_USEC) /
+					LED_FULL) * led->cdev.brightness;
+				rc = pwm_config(
+					led->mpp_cfg->pwm_cfg->pwm_dev,
+					duty_ns,
+					period_us * NSEC_PER_USEC);
+			}
 			if (rc < 0) {
 				dev_err(&led->spmi_dev->dev, "Failed to " \
 					"configure pwm for new values\n");
@@ -1001,6 +1013,13 @@
 				goto error_reg_write;
 			}
 
+			if (!led->flash_cfg->strobe_type)
+				led->flash_cfg->trigger_flash &=
+						~FLASH_HW_SW_STROBE_SEL_MASK;
+			else
+				led->flash_cfg->trigger_flash |=
+						FLASH_HW_SW_STROBE_SEL_MASK;
+
 			rc = qpnp_led_masked_write(led,
 				FLASH_LED_STROBE_CTRL(led->base),
 				led->flash_cfg->trigger_flash,
@@ -1080,30 +1099,22 @@
 			 */
 			usleep(FLASH_RAMP_UP_DELAY_US);
 
-			if (!led->flash_cfg->strobe_type) {
-				rc = qpnp_led_masked_write(led,
-					FLASH_LED_STROBE_CTRL(led->base),
-					led->flash_cfg->trigger_flash,
-					led->flash_cfg->trigger_flash);
-				if (rc) {
-					dev_err(&led->spmi_dev->dev,
-					"LED %d strobe reg write failed(%d)\n",
-					led->id, rc);
-					goto error_flash_set;
-				}
-			} else {
-				rc = qpnp_led_masked_write(led,
-					FLASH_LED_STROBE_CTRL(led->base),
-					(led->flash_cfg->trigger_flash |
-					FLASH_STROBE_HW),
-					(led->flash_cfg->trigger_flash |
-					FLASH_STROBE_HW));
-				if (rc) {
-					dev_err(&led->spmi_dev->dev,
-					"LED %d strobe reg write failed(%d)\n",
-					led->id, rc);
-					goto error_flash_set;
-				}
+			if (!led->flash_cfg->strobe_type)
+				led->flash_cfg->trigger_flash &=
+						~FLASH_HW_SW_STROBE_SEL_MASK;
+			else
+				led->flash_cfg->trigger_flash |=
+						FLASH_HW_SW_STROBE_SEL_MASK;
+
+			rc = qpnp_led_masked_write(led,
+				FLASH_LED_STROBE_CTRL(led->base),
+				led->flash_cfg->trigger_flash,
+				led->flash_cfg->trigger_flash);
+			if (rc) {
+				dev_err(&led->spmi_dev->dev,
+				"LED %d strobe reg write failed(%d)\n",
+				led->id, rc);
+				goto error_flash_set;
 			}
 		}
 	} else {
@@ -1219,8 +1230,8 @@
 
 static int qpnp_kpdbl_set(struct qpnp_led_data *led)
 {
-	int duty_us;
 	int rc;
+	int duty_us, duty_ns, period_us;
 
 	if (led->cdev.brightness) {
 		if (!led->kpdbl_cfg->pwm_cfg->blinking)
@@ -1237,11 +1248,22 @@
 		}
 
 		if (led->kpdbl_cfg->pwm_cfg->mode == PWM_MODE) {
-			duty_us = (led->kpdbl_cfg->pwm_cfg->pwm_period_us *
-				led->cdev.brightness) / KPDBL_MAX_LEVEL;
-			rc = pwm_config_us(led->kpdbl_cfg->pwm_cfg->pwm_dev,
+			period_us = led->kpdbl_cfg->pwm_cfg->pwm_period_us;
+			if (period_us > INT_MAX / NSEC_PER_USEC) {
+				duty_us = (period_us * led->cdev.brightness) /
+					KPDBL_MAX_LEVEL;
+				rc = pwm_config_us(
+					led->kpdbl_cfg->pwm_cfg->pwm_dev,
 					duty_us,
-					led->kpdbl_cfg->pwm_cfg->pwm_period_us);
+					period_us);
+			} else {
+				duty_ns = ((period_us * NSEC_PER_USEC) /
+					KPDBL_MAX_LEVEL) * led->cdev.brightness;
+				rc = pwm_config(
+					led->kpdbl_cfg->pwm_cfg->pwm_dev,
+					duty_ns,
+					period_us * NSEC_PER_USEC);
+			}
 			if (rc < 0) {
 				dev_err(&led->spmi_dev->dev, "pwm config failed\n");
 				return rc;
@@ -1262,7 +1284,7 @@
 
 		if (led->kpdbl_cfg->always_on) {
 			rc = pwm_config_us(led->kpdbl_cfg->pwm_cfg->pwm_dev, 0,
-					led->kpdbl_cfg->pwm_cfg->pwm_period_us);
+				led->kpdbl_cfg->pwm_cfg->pwm_period_us);
 			if (rc < 0) {
 				dev_err(&led->spmi_dev->dev,
 						"pwm config failed\n");
@@ -1300,19 +1322,30 @@
 
 static int qpnp_rgb_set(struct qpnp_led_data *led)
 {
-	int duty_us;
 	int rc;
+	int duty_us, duty_ns, period_us;
 
 	if (led->cdev.brightness) {
 		if (!led->rgb_cfg->pwm_cfg->blinking)
 			led->rgb_cfg->pwm_cfg->mode =
 				led->rgb_cfg->pwm_cfg->default_mode;
 		if (led->rgb_cfg->pwm_cfg->mode == PWM_MODE) {
-			duty_us = (led->rgb_cfg->pwm_cfg->pwm_period_us *
-				led->cdev.brightness) / LED_FULL;
-			rc = pwm_config_us(led->rgb_cfg->pwm_cfg->pwm_dev,
+			period_us = led->rgb_cfg->pwm_cfg->pwm_period_us;
+			if (period_us > INT_MAX / NSEC_PER_USEC) {
+				duty_us = (period_us * led->cdev.brightness) /
+					LED_FULL;
+				rc = pwm_config_us(
+					led->rgb_cfg->pwm_cfg->pwm_dev,
 					duty_us,
-					led->rgb_cfg->pwm_cfg->pwm_period_us);
+					period_us);
+			} else {
+				duty_ns = ((period_us * NSEC_PER_USEC) /
+					LED_FULL) * led->cdev.brightness;
+				rc = pwm_config(
+					led->rgb_cfg->pwm_cfg->pwm_dev,
+					duty_ns,
+					period_us * NSEC_PER_USEC);
+			}
 			if (rc < 0) {
 				dev_err(&led->spmi_dev->dev,
 					"pwm config failed\n");
@@ -1376,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:
@@ -1416,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);
 
 }
 
@@ -1496,7 +1535,7 @@
 	num_wled_strings = led->wled_cfg->num_strings;
 
 	/* verify ranges */
-	if (led->wled_cfg->ovp_val > WLED_OVP_37V) {
+	if (led->wled_cfg->ovp_val > WLED_OVP_27V) {
 		dev_err(&led->spmi_dev->dev, "Invalid ovp value\n");
 		return -EINVAL;
 	}
@@ -1605,7 +1644,7 @@
 
 		rc = qpnp_led_masked_write(led,
 			WLED_FULL_SCALE_REG(led->base, i), WLED_MAX_CURR_MASK,
-			led->max_current);
+			(u8)led->max_current);
 		if (rc) {
 			dev_err(&led->spmi_dev->dev,
 				"WLED max current reg write failed(%d)\n", rc);
@@ -1614,6 +1653,15 @@
 
 	}
 
+	/* Reset WLED enable register */
+	rc = qpnp_led_masked_write(led, WLED_MOD_CTRL_REG(led->base),
+		WLED_8_BIT_MASK, WLED_BOOST_OFF);
+	if (rc) {
+		dev_err(&led->spmi_dev->dev,
+			"WLED write ctrl reg failed(%d)\n", rc);
+		return rc;
+	}
+
 	/* dump wled registers */
 	qpnp_dump_regs(led, wled_debug_regs, ARRAY_SIZE(wled_debug_regs));
 
@@ -1707,7 +1755,7 @@
 				return -EINVAL;
 			}
 			rc = pwm_lut_config(pwm_cfg->pwm_dev,
-				PM_PWM_PERIOD_MIN, /* ignored by hardware */
+				pwm_cfg->pwm_period_us,
 				pwm_cfg->duty_cycles->duty_pcts,
 				pwm_cfg->lut_params);
 			if (rc < 0) {
@@ -2437,8 +2485,8 @@
 
 static int __devinit qpnp_mpp_init(struct qpnp_led_data *led)
 {
-	int rc, val;
-
+	int rc;
+	u8 val;
 
 	if (led->max_current < LED_MPP_CURRENT_MIN ||
 		led->max_current > LED_MPP_CURRENT_MAX) {
@@ -2733,7 +2781,7 @@
 			led->flash_cfg->enable_module = FLASH_ENABLE_MODULE;
 		} else
 			led->flash_cfg->enable_module = FLASH_ENABLE_ALL;
-		led->flash_cfg->trigger_flash = FLASH_STROBE_SW;
+		led->flash_cfg->trigger_flash = FLASH_TORCH_OUTPUT;
 	}
 
 	rc = of_property_read_u32(node, "qcom,current", &val);
@@ -2814,7 +2862,7 @@
 	else
 		return rc;
 
-	if (pwm_cfg->mode == PWM_MODE) {
+	if (pwm_cfg->mode != MANUAL_MODE) {
 		rc = of_property_read_u32(node, "qcom,pwm-us", &val);
 		if (!rc)
 			pwm_cfg->pwm_period_us = val;
@@ -3273,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);
@@ -3368,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);
 	}
 
@@ -3382,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:
@@ -3440,10 +3495,15 @@
 
 	return 0;
 }
+
+#ifdef CONFIG_OF
 static struct of_device_id spmi_match_table[] = {
-	{	.compatible = "qcom,leds-qpnp",
-	}
+	{ .compatible = "qcom,leds-qpnp",},
+	{ },
 };
+#else
+#define spmi_match_table NULL
+#endif
 
 static struct spmi_driver qpnp_leds_driver = {
 	.driver		= {
diff --git a/drivers/md/Kconfig b/drivers/md/Kconfig
index 10f122a..67df573 100644
--- a/drivers/md/Kconfig
+++ b/drivers/md/Kconfig
@@ -237,6 +237,23 @@
 
 	  If unsure, say N.
 
+config DM_REQ_CRYPT
+	tristate "Crypt target support"
+	depends on BLK_DEV_DM
+	select XTS
+	select CRYPTO_XTS
+	---help---
+	  This request based device-mapper target allows you to create a device that
+	  transparently encrypts the data on it. You'll need to activate
+	  the ciphers you're going to use in the cryptoapi configuration.
+          The DM REQ CRYPT operates on requests (bigger payloads) to utilize 
+          crypto hardware better.	  
+
+	  To compile this code as a module, choose M here: the module will
+	  be called dm-req-crypt.
+
+	  If unsure, say N.
+	  
 config DM_SNAPSHOT
        tristate "Snapshot target"
        depends on BLK_DEV_DM
diff --git a/drivers/md/Makefile b/drivers/md/Makefile
index 8b2e0df..7b16079 100644
--- a/drivers/md/Makefile
+++ b/drivers/md/Makefile
@@ -43,7 +43,7 @@
 obj-$(CONFIG_DM_RAID)	+= dm-raid.o
 obj-$(CONFIG_DM_THIN_PROVISIONING)	+= dm-thin-pool.o
 obj-$(CONFIG_DM_VERITY)		+= dm-verity.o
-
+obj-$(CONFIG_DM_REQ_CRYPT)		+= dm-req-crypt.o
 ifeq ($(CONFIG_DM_UEVENT),y)
 dm-mod-objs			+= dm-uevent.o
 endif
diff --git a/drivers/md/dm-req-crypt.c b/drivers/md/dm-req-crypt.c
new file mode 100644
index 0000000..87a4ab9
--- /dev/null
+++ b/drivers/md/dm-req-crypt.c
@@ -0,0 +1,807 @@
+/* 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/completion.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/bio.h>
+#include <linux/blkdev.h>
+#include <linux/mempool.h>
+#include <linux/slab.h>
+#include <linux/crypto.h>
+#include <linux/workqueue.h>
+#include <linux/backing-dev.h>
+#include <linux/atomic.h>
+#include <linux/scatterlist.h>
+#include <crypto/scatterwalk.h>
+#include <asm/page.h>
+#include <asm/unaligned.h>
+#include <crypto/hash.h>
+#include <crypto/md5.h>
+#include <crypto/algapi.h>
+#include <mach/qcrypto.h>
+
+#include <linux/device-mapper.h>
+
+
+#define DM_MSG_PREFIX "req-crypt"
+
+#define MAX_SG_LIST	1024
+#define REQ_DM_512_KB (512*1024)
+#define MAX_ENCRYPTION_BUFFERS 1
+#define MIN_IOS 16
+#define MIN_POOL_PAGES 32
+#define KEY_SIZE_XTS 64
+#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;
+	int err;
+};
+
+struct dm_dev *dev;
+static struct kmem_cache *_req_crypt_io_pool;
+sector_t start_sector_orig;
+struct workqueue_struct *req_crypt_queue;
+mempool_t *req_io_pool;
+mempool_t *req_page_pool;
+struct crypto_ablkcipher *tfm;
+
+struct req_dm_crypt_io {
+	struct work_struct work;
+	struct request *cloned_request;
+	int error;
+	atomic_t pending;
+	struct timespec start_time;
+};
+
+static void req_crypt_cipher_complete
+		(struct crypto_async_request *req, int err);
+
+
+static void req_crypt_inc_pending(struct req_dm_crypt_io *io)
+{
+	atomic_inc(&io->pending);
+}
+
+static void req_crypt_dec_pending_encrypt(struct req_dm_crypt_io *io)
+{
+	int error = 0;
+	struct request *clone = NULL;
+
+	if (io) {
+		error = io->error;
+		if (io->cloned_request) {
+			clone = io->cloned_request;
+		} else {
+			DMERR("%s io->cloned_request is NULL\n",
+								__func__);
+			/*
+			 * If Clone is NULL we cannot do anything,
+			 * this should never happen
+			 */
+			BUG();
+		}
+	} else {
+		DMERR("%s io is NULL\n", __func__);
+		/*
+		 * If Clone is NULL we cannot do anything,
+		 * this should never happen
+		 */
+		BUG();
+	}
+
+	atomic_dec(&io->pending);
+
+	if (error < 0) {
+		dm_kill_unmapped_request(clone, error);
+		mempool_free(io, req_io_pool);
+	} else
+		dm_dispatch_request(clone);
+}
+
+static void req_crypt_dec_pending_decrypt(struct req_dm_crypt_io *io)
+{
+	int error = 0;
+	struct request *clone = NULL;
+
+	if (io) {
+		error = io->error;
+		if (io->cloned_request) {
+			clone = io->cloned_request;
+		} else {
+			DMERR("%s io->cloned_request is NULL\n",
+								__func__);
+			/*
+			 * If Clone is NULL we cannot do anything,
+			 * this should never happen
+			 */
+			BUG();
+		}
+	} else {
+		DMERR("%s io is NULL\n",
+							__func__);
+		/*
+		 * If Clone is NULL we cannot do anything,
+		 * this should never happen
+		 */
+		BUG();
+	}
+
+	/* Should never get here if io or Clone is NULL */
+	dm_end_request(clone, error);
+	atomic_dec(&io->pending);
+	mempool_free(io, req_io_pool);
+}
+
+/*
+ * The callback that will be called by the worker queue to perform Decryption
+ * for reads and use the dm function to complete the bios and requests.
+ */
+static void req_cryptd_crypt_read_convert(struct req_dm_crypt_io *io)
+{
+	struct request *clone = NULL;
+	int error = 0;
+	int total_sg_len = 0, rc = 0, total_bytes_in_req = 0;
+	struct ablkcipher_request *req = NULL;
+	struct req_crypt_result result;
+	struct scatterlist *req_sg_read = NULL;
+	int err = 0;
+	u8 IV[AES_XTS_IV_LEN];
+
+	if (io) {
+		error = io->error;
+		if (io->cloned_request) {
+			clone = io->cloned_request;
+		} else {
+			DMERR("%s io->cloned_request is NULL\n",
+								__func__);
+			error = DM_REQ_CRYPT_ERROR;
+			goto submit_request;
+		}
+	} else {
+		DMERR("%s io is NULL\n",
+							__func__);
+		error = DM_REQ_CRYPT_ERROR;
+		goto submit_request;
+	}
+
+	req_crypt_inc_pending(io);
+
+	if (error != 0) {
+		err = error;
+		goto submit_request;
+	}
+
+	req = ablkcipher_request_alloc(tfm, GFP_KERNEL);
+	if (!req) {
+		DMERR("%s ablkcipher request allocation failed\n", __func__);
+		err = DM_REQ_CRYPT_ERROR;
+		goto ablkcipher_req_alloc_failure;
+	}
+
+	ablkcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
+					req_crypt_cipher_complete, &result);
+	init_completion(&result.completion);
+	qcrypto_cipher_set_flag(req,
+		QCRYPTO_CTX_USE_PIPE_KEY | QCRYPTO_CTX_XTS_DU_SIZE_512B);
+	crypto_ablkcipher_clear_flags(tfm, ~0);
+	crypto_ablkcipher_setkey(tfm, NULL, KEY_SIZE_XTS);
+
+	req_sg_read = kzalloc(sizeof(struct scatterlist) *
+			MAX_SG_LIST, GFP_KERNEL);
+	if (!req_sg_read) {
+		DMERR("%s req_sg_read allocation failed\n",
+						__func__);
+		err = DM_REQ_CRYPT_ERROR;
+		goto ablkcipher_req_alloc_failure;
+	}
+
+	total_sg_len = blk_rq_map_sg(clone->q, clone, req_sg_read);
+	if ((total_sg_len <= 0) || (total_sg_len > MAX_SG_LIST)) {
+		DMERR("%s Request Error%d", __func__, total_sg_len);
+		err = DM_REQ_CRYPT_ERROR;
+		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);
+		err = DM_REQ_CRYPT_ERROR;
+		goto ablkcipher_req_alloc_failure;
+	}
+
+	memset(IV, 0, AES_XTS_IV_LEN);
+	memcpy(IV, &clone->__sector, sizeof(sector_t));
+
+	ablkcipher_request_set_crypt(req, req_sg_read, req_sg_read,
+			total_bytes_in_req, (void *) IV);
+
+	rc = crypto_ablkcipher_decrypt(req);
+
+	switch (rc) {
+	case 0:
+		break;
+
+	case -EBUSY:
+		/*
+		 * Lets make this synchronous request by waiting on
+		 * in progress as well
+		 */
+	case -EINPROGRESS:
+		wait_for_completion_io(&result.completion);
+		if (result.err) {
+			DMERR("%s error = %d encrypting the request\n",
+				 __func__, result.err);
+			err = DM_REQ_CRYPT_ERROR;
+		}
+		break;
+
+	default:
+		err = DM_REQ_CRYPT_ERROR;
+		break;
+	}
+
+ablkcipher_req_alloc_failure:
+
+	if (req)
+		ablkcipher_request_free(req);
+
+	kfree(req_sg_read);
+
+submit_request:
+	if (io)
+		io->error = err;
+	req_crypt_dec_pending_decrypt(io);
+}
+
+/*
+ * The callback that will be called by the worker queue to perform Encryption
+ * for writes and submit the request using the elevelator.
+ */
+static void req_cryptd_crypt_write_convert(struct req_dm_crypt_io *io)
+{
+	struct request *clone = NULL;
+	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 = {0, NULL};
+	struct req_iterator iter1 = {0, NULL};
+	struct ablkcipher_request *req = NULL;
+	struct req_crypt_result result;
+	struct bio_vec *bvec = NULL;
+	struct scatterlist *req_sg_in = NULL;
+	struct scatterlist *req_sg_out = NULL;
+	int copy_bio_sector_to_req = 0;
+	gfp_t gfp_mask = GFP_NOIO | __GFP_HIGHMEM;
+	struct page *page = NULL;
+	u8 IV[AES_XTS_IV_LEN];
+	int remaining_size = 0;
+
+	if (io) {
+		if (io->cloned_request) {
+			clone = io->cloned_request;
+		} else {
+			DMERR("%s io->cloned_request is NULL\n",
+								__func__);
+			error = DM_REQ_CRYPT_ERROR;
+			goto submit_request;
+		}
+	} else {
+		DMERR("%s io is NULL\n",
+							__func__);
+		error = DM_REQ_CRYPT_ERROR;
+		goto submit_request;
+	}
+
+	req_crypt_inc_pending(io);
+
+	req = ablkcipher_request_alloc(tfm, GFP_KERNEL);
+	if (!req) {
+		DMERR("%s ablkcipher request allocation failed\n",
+					__func__);
+		error = DM_REQ_CRYPT_ERROR;
+		goto ablkcipher_req_alloc_failure;
+	}
+
+	ablkcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
+				req_crypt_cipher_complete, &result);
+
+	init_completion(&result.completion);
+	qcrypto_cipher_set_flag(req,
+		QCRYPTO_CTX_USE_PIPE_KEY | QCRYPTO_CTX_XTS_DU_SIZE_512B);
+	crypto_ablkcipher_clear_flags(tfm, ~0);
+	crypto_ablkcipher_setkey(tfm, NULL, KEY_SIZE_XTS);
+
+	req_sg_in = kzalloc(sizeof(struct scatterlist) * MAX_SG_LIST,
+			GFP_KERNEL);
+	if (!req_sg_in) {
+		DMERR("%s req_sg_in allocation failed\n",
+					__func__);
+		error = DM_REQ_CRYPT_ERROR;
+		goto ablkcipher_req_alloc_failure;
+	}
+
+	req_sg_out = kzalloc(sizeof(struct scatterlist) * MAX_SG_LIST,
+			GFP_KERNEL);
+	if (!req_sg_out) {
+		DMERR("%s req_sg_out allocation failed\n",
+					__func__);
+		error = DM_REQ_CRYPT_ERROR;
+		goto ablkcipher_req_alloc_failure;
+	}
+
+	total_sg_len_req_in = blk_rq_map_sg(clone->q, clone, req_sg_in);
+	if ((total_sg_len_req_in <= 0) ||
+			(total_sg_len_req_in > MAX_SG_LIST)) {
+		DMERR("%s Request Error%d", __func__, total_sg_len_req_in);
+		error = DM_REQ_CRYPT_ERROR;
+		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) {
+		if (bvec->bv_len > remaining_size) {
+			page = NULL;
+			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;
+			remaining_size = PAGE_SIZE -  bvec->bv_len;
+			if (remaining_size < 0)
+				BUG();
+		} else {
+			bvec->bv_page = page;
+			bvec->bv_offset = PAGE_SIZE - remaining_size;
+			remaining_size = remaining_size -  bvec->bv_len;
+		}
+	}
+
+	total_sg_len_req_out = blk_rq_map_sg(clone->q, clone, req_sg_out);
+	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_AFTER_PAGE_MALLOC;
+		goto ablkcipher_req_alloc_failure;
+	}
+
+	memset(IV, 0, AES_XTS_IV_LEN);
+	memcpy(IV, &clone->__sector, sizeof(sector_t));
+
+	ablkcipher_request_set_crypt(req, req_sg_in, req_sg_out,
+			total_bytes_in_req, (void *) IV);
+
+	rc = crypto_ablkcipher_encrypt(req);
+
+	switch (rc) {
+	case 0:
+		break;
+
+	case -EBUSY:
+		/*
+		 * Lets make this synchronous request by waiting on
+		 * in progress as well
+		 */
+	case -EINPROGRESS:
+		wait_for_completion_interruptible(&result.completion);
+		if (result.err) {
+			DMERR("%s error = %d encrypting the request\n",
+				 __func__, result.err);
+			error = DM_REQ_CRYPT_ERROR_AFTER_PAGE_MALLOC;
+			goto ablkcipher_req_alloc_failure;
+		}
+		break;
+
+	default:
+		error = DM_REQ_CRYPT_ERROR_AFTER_PAGE_MALLOC;
+		goto ablkcipher_req_alloc_failure;
+	}
+
+	__rq_for_each_bio(bio_src, clone) {
+		if (copy_bio_sector_to_req == 0) {
+			clone->buffer = bio_data(bio_src);
+			copy_bio_sector_to_req++;
+		}
+		blk_queue_bounce(clone->q, &bio_src);
+	}
+
+
+ablkcipher_req_alloc_failure:
+	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:
+	if (io)
+		io->error = error;
+	req_crypt_dec_pending_encrypt(io);
+}
+
+/* Queue callback function that will get triggered */
+static void req_cryptd_crypt(struct work_struct *work)
+{
+	struct req_dm_crypt_io *io =
+			container_of(work, struct req_dm_crypt_io, work);
+
+	if (rq_data_dir(io->cloned_request) == WRITE)
+		req_cryptd_crypt_write_convert(io);
+	else if (rq_data_dir(io->cloned_request) == READ)
+		req_cryptd_crypt_read_convert(io);
+	else
+		DMERR("%s received non-read/write request for Clone %u\n",
+				__func__, (unsigned int)io->cloned_request);
+}
+
+static void req_cryptd_queue_crypt(struct req_dm_crypt_io *io)
+{
+	INIT_WORK(&io->work, req_cryptd_crypt);
+	queue_work(req_crypt_queue, &io->work);
+}
+
+/*
+ * Cipher complete callback, this is triggered by the Linux crypto api once
+ * the operation is done. This signals the waiting thread that the crypto
+ * operation is complete.
+ */
+static void req_crypt_cipher_complete(struct crypto_async_request *req, int err)
+{
+	struct req_crypt_result *res = req->data;
+
+	if (err == -EINPROGRESS)
+		return;
+
+	res->err = err;
+	complete(&res->completion);
+}
+
+/*
+ * If bio->bi_dev is a partition, remap the location
+ */
+static inline void req_crypt_blk_partition_remap(struct bio *bio)
+{
+	struct block_device *bdev = bio->bi_bdev;
+
+	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;
+	}
+}
+
+/*
+ * The endio function is called from ksoftirqd context (atomic).
+ * For write operations the new pages created form the mempool
+ * is freed and returned.  * For read operations, decryption is
+ * required, since this is called in a atomic  * context, the
+ * request is sent to a worker queue to complete decryptiona and
+ * free the request once done.
+ */
+static int req_crypt_endio(struct dm_target *ti, struct request *clone,
+			    int error, union map_info *map_context)
+{
+	int err = 0;
+	struct req_iterator iter1;
+	struct bio_vec *bvec = NULL;
+	struct req_dm_crypt_io *req_io = map_context->ptr;
+
+	/* If it is a write request, do nothing just return. */
+	bvec = NULL;
+	if (rq_data_dir(clone) == WRITE) {
+		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;
+		}
+		mempool_free(req_io, req_io_pool);
+		goto submit_request;
+	} else if (rq_data_dir(clone) == READ) {
+		req_io->error = error;
+		req_cryptd_queue_crypt(req_io);
+		err = DM_ENDIO_INCOMPLETE;
+		goto submit_request;
+	}
+
+submit_request:
+	return err;
+}
+
+/*
+ * This function is called with interrupts disabled
+ * The function remaps the clone for the underlying device.
+ * If it is a write request, it calls into the worker queue to
+ * encrypt the data
+ * and submit the request directly using the elevator
+ * For a read request no pre-processing is required the request
+ * is returned to dm once mapping is done
+ */
+
+static int req_crypt_map(struct dm_target *ti, struct request *clone,
+			 union map_info *map_context)
+{
+	struct req_dm_crypt_io *req_io = NULL;
+	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__);
+		error = DM_REQ_CRYPT_ERROR;
+		goto submit_request;
+	}
+
+	/* Save the clone in the req_io, the callback to the worker
+	 * queue will get the req_io
+	 */
+	req_io->cloned_request = clone;
+	map_context->ptr = req_io;
+	atomic_set(&req_io->pending, 0);
+
+	/* Get the queue of the underlying original device */
+	clone->q = bdev_get_queue(dev->bdev);
+	clone->rq_disk = dev->bdev->bd_disk;
+
+	__rq_for_each_bio(bio_src, clone) {
+		bio_src->bi_bdev = dev->bdev;
+		/* Currently the way req-dm works is that once the underlying
+		 * device driver completes the request by calling into the
+		 * block layer. The block layer completes the bios (clones) and
+		 * then the cloned request. This is undesirable for req-dm-crypt
+		 * hence added a flag BIO_DONTFREE, this flag will ensure that
+		 * blk layer does not complete the cloned bios before completing
+		 * the request. When the crypt endio is called, post-processsing
+		 * is done and then the dm layer will complete the bios (clones)
+		 * and free them.
+		 */
+		bio_src->bi_flags |= 1 << BIO_DONTFREE;
+
+		/*
+		 * If this device has partitions, remap block n
+		 * of partition p to block n+start(p) of the disk.
+		 */
+		req_crypt_blk_partition_remap(bio_src);
+		if (copy_bio_sector_to_req == 0) {
+			clone->__sector = bio_src->bi_sector;
+			clone->buffer = bio_data(bio_src);
+			copy_bio_sector_to_req++;
+		}
+		blk_queue_bounce(clone->q, &bio_src);
+	}
+
+	if (rq_data_dir(clone) == READ) {
+		error = DM_MAPIO_REMAPPED;
+		goto submit_request;
+	} else if (rq_data_dir(clone) == WRITE) {
+		req_cryptd_queue_crypt(req_io);
+		error = DM_MAPIO_SUBMITTED;
+		goto submit_request;
+	}
+
+submit_request:
+	return error;
+
+}
+
+static void req_crypt_dtr(struct dm_target *ti)
+{
+	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;
+	}
+}
+
+
+/*
+ * Construct an encryption mapping:
+ * <cipher> <key> <iv_offset> <dev_path> <start>
+ */
+static int req_crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv)
+{
+	unsigned long long tmpll;
+	char dummy;
+	int err = DM_REQ_CRYPT_ERROR;
+
+	if (argc < 5) {
+		DMERR(" %s Not enough args\n", __func__);
+		err = DM_REQ_CRYPT_ERROR;
+		goto ctr_exit;
+	}
+
+	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_NON_REENTRANT |
+					WQ_HIGHPRI |
+					WQ_CPU_INTENSIVE|
+					WQ_MEM_RECLAIM,
+					1);
+	if (!req_crypt_queue) {
+		DMERR("%s req_crypt_queue not allocated\n", __func__);
+		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\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__);
+		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__);
+		err =  DM_REQ_CRYPT_ERROR;
+		goto ctr_exit;
+	}
+	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,
+				 iterate_devices_callout_fn fn, void *data)
+{
+	return fn(ti, dev, start_sector_orig, ti->len, data);
+}
+
+static struct target_type req_crypt_target = {
+	.name   = "req-crypt",
+	.version = {1, 0, 0},
+	.module = THIS_MODULE,
+	.ctr    = req_crypt_ctr,
+	.dtr    = req_crypt_dtr,
+	.map_rq = req_crypt_map,
+	.rq_end_io = req_crypt_endio,
+	.iterate_devices = req_crypt_iterate_devices,
+};
+
+static int __init req_dm_crypt_init(void)
+{
+	int r;
+
+	_req_crypt_io_pool = KMEM_CACHE(req_dm_crypt_io, 0);
+	if (!_req_crypt_io_pool)
+		return -ENOMEM;
+
+	r = dm_register_target(&req_crypt_target);
+	if (r < 0) {
+		DMERR("register failed %d", r);
+		kmem_cache_destroy(_req_crypt_io_pool);
+	}
+
+	return r;
+}
+
+static void __exit req_dm_crypt_exit(void)
+{
+	kmem_cache_destroy(_req_crypt_io_pool);
+	dm_unregister_target(&req_crypt_target);
+}
+
+module_init(req_dm_crypt_init);
+module_exit(req_dm_crypt_exit);
+
+MODULE_DESCRIPTION(DM_NAME " target for request based transparent encryption / decryption");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/md/dm.c b/drivers/md/dm.c
index e24143c..5d240d1 100644
--- a/drivers/md/dm.c
+++ b/drivers/md/dm.c
@@ -775,7 +775,7 @@
  * Complete the clone and the original request.
  * Must be called without queue lock.
  */
-static void dm_end_request(struct request *clone, int error)
+void dm_end_request(struct request *clone, int error)
 {
 	int rw = rq_data_dir(clone);
 	struct dm_rq_target_io *tio = clone->end_io_data;
diff --git a/drivers/media/media-device.c b/drivers/media/media-device.c
index 6f9eb94..7d97c26 100644
--- a/drivers/media/media-device.c
+++ b/drivers/media/media-device.c
@@ -140,6 +140,8 @@
 
 		for (p = 0; p < entity->num_pads; p++) {
 			struct media_pad_desc pad;
+
+			memset(&pad, 0, sizeof(pad));
 			media_device_kpad_to_upad(&entity->pads[p], &pad);
 			if (copy_to_user(&links.pads[p], &pad, sizeof(pad)))
 				return -EFAULT;
@@ -157,6 +159,7 @@
 			if (entity->links[l].source->entity != entity)
 				continue;
 
+			memset(&link, 0, sizeof(link));
 			media_device_kpad_to_upad(entity->links[l].source,
 						  &link.source);
 			media_device_kpad_to_upad(entity->links[l].sink,
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 eda6150..170efa8 100644
--- a/drivers/media/platform/msm/camera_v2/camera/camera.c
+++ b/drivers/media/platform/msm/camera_v2/camera/camera.c
@@ -64,9 +64,13 @@
 	struct msm_v4l2_event_data *event_data =
 		(struct msm_v4l2_event_data *)&event->u.data[0];
 
-	if (event_data->status > MSM_CAMERA_ERR_EVT_BASE)
+	if (event_data->status > MSM_CAMERA_ERR_EVT_BASE) {
+		pr_err("%s : event_data status out of bounds\n",
+				__func__);
+		pr_err("%s : Line %d event_data->status 0X%x\n",
+				__func__, __LINE__, event_data->status);
 		return -EFAULT;
-
+	}
 	return 0;
 }
 
@@ -341,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,
@@ -461,9 +462,11 @@
 	struct camera_v4l2_private *sp;
 
 	sp = kzalloc(sizeof(*sp), GFP_KERNEL);
-	if (!sp)
-		return -ENOMEM;
 
+	if (!sp) {
+		pr_err("%s : memory not available\n", __func__);
+		return -ENOMEM;
+	}
 	filep->private_data = &sp->fh;
 
 	/* stream_id = open id */
@@ -498,9 +501,10 @@
 	/* free up this buffer when stream is done */
 	q->drv_priv =
 		kzalloc(sizeof(struct msm_v4l2_format_data), GFP_KERNEL);
-	if (!q->drv_priv)
+	if (!q->drv_priv) {
+		pr_err("%s : memory not available\n", __func__);
 		return -ENOMEM;
-
+	}
 	q->mem_ops = msm_vb2_get_q_mem_ops();
 	q->ops = msm_vb2_get_q_ops();
 
@@ -530,38 +534,60 @@
 	BUG_ON(!pvdev);
 
 	rc = camera_v4l2_fh_open(filep);
-	if (rc < 0)
-		goto fh_open_fail;
 
+	if (rc < 0) {
+		pr_err("%s : camera_v4l2_fh_open failed Line %d rc %d\n",
+				__func__, __LINE__, rc);
+		goto fh_open_fail;
+	}
 	/* every stream has a vb2 queue */
 	rc = camera_v4l2_vb2_q_init(filep);
-	if (rc < 0)
-		goto vb2_q_fail;
 
+	if (rc < 0) {
+		pr_err("%s : vb2 queue init fails Line %d rc %d\n",
+				__func__, __LINE__, rc);
+		goto vb2_q_fail;
+	}
 	if (!atomic_read(&pvdev->opened)) {
 		pm_stay_awake(&pvdev->vdev->dev);
 
 		/* create a new session when first opened */
 		rc = msm_create_session(pvdev->vdev->num, pvdev->vdev);
-		if (rc < 0)
+		if (rc < 0) {
+			pr_err("%s : session creation failed Line %d rc %d\n",
+					__func__, __LINE__, rc);
 			goto session_fail;
+		}
 		rc = msm_create_command_ack_q(pvdev->vdev->num, 0);
-		if (rc < 0)
-			goto command_ack_q_fail;
 
+		if (rc < 0) {
+			pr_err("%s : creation of command_ack queue failed\n",
+					__func__);
+			pr_err("%s : Line %d rc %d\n", __func__, __LINE__, rc);
+			goto command_ack_q_fail;
+		}
 		camera_pack_event(filep, MSM_CAMERA_NEW_SESSION, 0, -1, &event);
 		rc = msm_post_event(&event, MSM_POST_EVT_TIMEOUT);
-		if (rc < 0)
+		if (rc < 0) {
+			pr_err("%s : posting of NEW_SESSION event failed\n",
+					__func__);
+			pr_err("%s : Line %d rc %d\n", __func__, __LINE__, rc);
 			goto post_fail;
-
+		}
 		rc = camera_check_event_status(&event);
-		if (rc < 0)
+		if (rc < 0) {
+			pr_err("%s : checking event status fails Line %d rc %d\n",
+					__func__, __LINE__, rc);
 			goto post_fail;
+		}
 	} else {
 		rc = msm_create_command_ack_q(pvdev->vdev->num,
 			atomic_read(&pvdev->stream_cnt));
-		if (rc < 0)
+		if (rc < 0) {
+			pr_err("%s : creation of command_ack queue failed Line %d rc %d\n",
+					__func__, __LINE__, rc);
 			goto session_fail;
+		}
 	}
 
 	atomic_add(1, &pvdev->opened);
@@ -644,12 +670,22 @@
 	return rc;
 }
 
+#ifdef CONFIG_COMPAT
+long camera_v4l2_compat_ioctl(struct file *file, unsigned int cmd,
+	unsigned long arg)
+{
+	return -ENOIOCTLCMD;
+}
+#endif
 static struct v4l2_file_operations camera_v4l2_fops = {
 	.owner   = THIS_MODULE,
 	.open	= camera_v4l2_open,
 	.poll	= camera_v4l2_poll,
 	.release = camera_v4l2_close,
 	.ioctl   = video_ioctl2,
+#ifdef CONFIG_COMPAT
+	.compat_ioctl32 = camera_v4l2_compat_ioctl,
+#endif
 };
 
 int camera_init_v4l2(struct device *dev, unsigned int *session)
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c b/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c
index 59b648d..f9855c0 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c
@@ -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
@@ -188,7 +188,6 @@
 					mapped_info->handle,
 					buf_mgr->iommu_domain_num, 0);
 				ion_free(buf_mgr->client, mapped_info->handle);
-
 				list_del_init(&buf_pending->list);
 				kfree(buf_pending);
 				break;
@@ -309,6 +308,9 @@
 	struct msm_isp_buffer *temp_buf_info;
 	struct msm_isp_bufq *bufq = NULL;
 	struct vb2_buffer *vb2_buf = NULL;
+	struct buffer_cmd *buf_pending = NULL;
+	struct msm_isp_buffer_mapped_info *mped_info_tmp1;
+	struct msm_isp_buffer_mapped_info *mped_info_tmp2;
 	bufq = msm_isp_get_bufq(buf_mgr, bufq_handle);
 	if (!bufq) {
 		pr_err("%s: Invalid bufq\n", __func__);
@@ -348,9 +350,22 @@
 		list_for_each_entry(temp_buf_info, &bufq->head, list) {
 			if (temp_buf_info->state ==
 					MSM_ISP_BUFFER_STATE_QUEUED) {
-				/* found one buf */
-				list_del_init(&temp_buf_info->list);
-				*buf_info = temp_buf_info;
+
+				list_for_each_entry(buf_pending, &buf_mgr->buffer_q, list) {
+					if (!buf_pending)
+						break;
+					mped_info_tmp1 = buf_pending->mapped_info;
+					mped_info_tmp2 = &temp_buf_info->mapped_info[0];
+
+					if (mped_info_tmp1 == mped_info_tmp2
+						&& (mped_info_tmp1->len == mped_info_tmp2->len)
+						&& (mped_info_tmp1->paddr == mped_info_tmp2->paddr)) {
+						/* found one buf */
+						list_del_init(&temp_buf_info->list);
+						*buf_info = temp_buf_info;
+						break;
+					}
+				}
 				break;
 			}
 		}
@@ -359,9 +374,22 @@
 			bufq->session_id, bufq->stream_id);
 		if (vb2_buf) {
 			if (vb2_buf->v4l2_buf.index < bufq->num_bufs) {
-				*buf_info =
-					&bufq->bufs[vb2_buf->v4l2_buf.index];
-				(*buf_info)->vb2_buf = vb2_buf;
+
+				list_for_each_entry(buf_pending, &buf_mgr->buffer_q, list) {
+					if (!buf_pending)
+						break;
+					mped_info_tmp1 = buf_pending->mapped_info;
+					mped_info_tmp2 =
+						&bufq->bufs[vb2_buf->v4l2_buf.index].mapped_info[0];
+
+					if (mped_info_tmp1 == mped_info_tmp2
+						&& (mped_info_tmp1->len == mped_info_tmp2->len)
+						&& (mped_info_tmp1->paddr == mped_info_tmp2->paddr)) {
+						*buf_info = &bufq->bufs[vb2_buf->v4l2_buf.index];
+						(*buf_info)->vb2_buf = vb2_buf;
+						break;
+					}
+				}
 			} else {
 				pr_err("%s: Incorrect buf index %d\n",
 					__func__, vb2_buf->v4l2_buf.index);
@@ -374,11 +402,14 @@
 		if (bufq->buf_type == ISP_SHARE_BUF) {
 			temp_buf_info = kzalloc(
 			   sizeof(struct msm_isp_buffer), GFP_ATOMIC);
-			temp_buf_info->buf_reuse_flag = 1;
-			temp_buf_info->buf_used[id] = 1;
-			temp_buf_info->buf_get_count = 1;
-			list_add_tail(&temp_buf_info->share_list,
-						  &bufq->share_head);
+			if (temp_buf_info) {
+				temp_buf_info->buf_reuse_flag = 1;
+				temp_buf_info->buf_used[id] = 1;
+				temp_buf_info->buf_get_count = 1;
+				list_add_tail(&temp_buf_info->share_list,
+							  &bufq->share_head);
+			} else
+				rc = -ENOMEM;
 		}
 	} else {
 		(*buf_info)->state = MSM_ISP_BUFFER_STATE_DEQUEUED;
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp.c
index 80a0073..d35869c 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp.c
@@ -52,8 +52,82 @@
 	{}
 };
 
+#define MAX_OVERFLOW_COUNTERS  15
+#define OVERFLOW_LENGTH 512
+#define OVERFLOW_BUFFER_LENGTH 32
 static struct msm_isp_buf_mgr vfe_buf_mgr;
+static int msm_isp_enable_debugfs(struct msm_isp_statistics *stats);
+static char *stats_str[MAX_OVERFLOW_COUNTERS] = {
+	"imgmaster0_overflow_cnt",
+	"imgmaster1_overflow_cnt",
+	"imgmaster2_overflow_cnt",
+	"imgmaster3_overflow_cnt",
+	"imgmaster4_overflow_cnt",
+	"imgmaster5_overflow_cnt",
+	"imgmaster6_overflow_cnt",
+	"be_overflow_cnt",
+	"bg_overflow_cnt",
+	"bf_overflow_cnt",
+	"awb_overflow_cnt",
+	"rs_overflow_cnt",
+	"cs_overflow_cnt",
+	"ihist_overflow_cnt",
+	"skinbhist_overflow_cnt",
+};
+static int vfe_debugfs_statistics_open(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	return 0;
+}
 
+static ssize_t vfe_debugfs_statistics_read(struct file *t_file, char *t_char,
+	size_t t_size_t, loff_t *t_loff_t)
+{
+	int i;
+	char name[OVERFLOW_LENGTH] = {0};
+	int *ptr;
+	char buffer[OVERFLOW_BUFFER_LENGTH] = {0};
+	struct msm_isp_statistics  *stats = (struct msm_isp_statistics *)
+		t_file->private_data;
+	ptr = (int *)(stats);
+	for (i = 0; i < MAX_OVERFLOW_COUNTERS; i++) {
+		strlcat(name, stats_str[i], sizeof(name));
+		strlcat(name, "     ", sizeof(name));
+		snprintf(buffer, sizeof(buffer), "%d", ptr[i]);
+		strlcat(name, buffer, sizeof(name));
+		strlcat(name, "\r\n", sizeof(name));
+	}
+	return simple_read_from_buffer(t_char, t_size_t,
+		t_loff_t, name, strlen(name));
+}
+
+static ssize_t vfe_debugfs_statistics_write(struct file *t_file,
+	const char *t_char, size_t t_size_t, loff_t *t_loff_t)
+{
+	struct msm_isp_statistics *stats = (struct msm_isp_statistics *)
+		t_file->private_data;
+	memset(stats, 0, sizeof(struct msm_isp_statistics));
+
+	return sizeof(struct msm_isp_statistics);
+}
+
+static const struct file_operations vfe_debugfs_error = {
+	.open = vfe_debugfs_statistics_open,
+	.read = vfe_debugfs_statistics_read,
+	.write = vfe_debugfs_statistics_write,
+};
+
+static int msm_isp_enable_debugfs(struct msm_isp_statistics *stats)
+{
+	struct dentry *debugfs_base;
+	debugfs_base = debugfs_create_dir("msm_isp", NULL);
+	if (!debugfs_base)
+		return -ENOMEM;
+	if (!debugfs_create_file("stats", S_IRUGO | S_IWUSR, debugfs_base,
+		stats, &vfe_debugfs_error))
+		return -ENOMEM;
+	return 0;
+}
 static int __devinit vfe_probe(struct platform_device *pdev)
 {
 	struct vfe_device *vfe_dev;
@@ -73,6 +147,7 @@
 	};
 
 	vfe_dev = kzalloc(sizeof(struct vfe_device), GFP_KERNEL);
+	vfe_dev->stats = kzalloc(sizeof(struct msm_isp_statistics), GFP_KERNEL);
 	if (!vfe_dev) {
 		pr_err("%s: no enough memory\n", __func__);
 		return -ENOMEM;
@@ -144,6 +219,7 @@
 		kfree(vfe_dev);
 		return -EINVAL;
 	}
+	msm_isp_enable_debugfs(vfe_dev->stats);
 	vfe_dev->buf_mgr->ops->register_ctx(vfe_dev->buf_mgr,
 		&vfe_dev->iommu_ctx[0], vfe_dev->hw_info->num_iommu_ctx);
 	vfe_dev->vfe_open_cnt = 0;
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp.h b/drivers/media/platform/msm/camera_v2/isp/msm_isp.h
index 9dd0085..4700469 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp.h
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp.h
@@ -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
@@ -24,7 +24,6 @@
 #include <media/msmb_isp.h>
 #include <mach/msm_bus.h>
 #include <mach/msm_bus_board.h>
-
 #include "msm_buf_mgr.h"
 
 #define MAX_IOMMU_CTX 2
@@ -71,6 +70,12 @@
 	DISABLE_CAMIF_IMMEDIATELY
 };
 
+enum msm_isp_reset_type {
+	ISP_RST_HARD,
+	ISP_RST_SOFT,
+	ISP_RST_MAX
+};
+
 struct msm_isp_timestamp {
 	/*Monotonic clock for v4l2 buffer*/
 	struct timeval buf_time;
@@ -147,7 +152,8 @@
 
 struct msm_vfe_core_ops {
 	void (*reg_update) (struct vfe_device *vfe_dev);
-	long (*reset_hw) (struct vfe_device *vfe_dev);
+	long (*reset_hw) (struct vfe_device *vfe_dev,
+		enum msm_isp_reset_type reset_type);
 	int (*init_hw) (struct vfe_device *vfe_dev);
 	void (*init_hw_reg) (struct vfe_device *vfe_dev);
 	void (*release_hw) (struct vfe_device *vfe_dev);
@@ -397,6 +403,29 @@
 	uint32_t error_count;
 };
 
+struct msm_vfe_frame_ts {
+	struct timeval buf_time;
+	uint32_t frame_id;
+};
+
+struct msm_isp_statistics {
+	int32_t imagemaster0_overflow;
+	int32_t imagemaster1_overflow;
+	int32_t imagemaster2_overflow;
+	int32_t imagemaster3_overflow;
+	int32_t imagemaster4_overflow;
+	int32_t imagemaster5_overflow;
+	int32_t imagemaster6_overflow;
+	int32_t be_overflow;
+	int32_t bg_overflow;
+	int32_t bf_overflow;
+	int32_t awb_overflow;
+	int32_t rs_overflow;
+	int32_t cs_overflow;
+	int32_t ihist_overflow;
+	int32_t skinbhist_overflow;
+};
+
 struct vfe_device {
 	struct platform_device *pdev;
 	struct msm_sd_subdev subdev;
@@ -439,6 +468,7 @@
 	struct msm_vfe_axi_shared_data axi_data;
 	struct msm_vfe_stats_shared_data stats_data;
 	struct msm_vfe_error_info error_info;
+	struct msm_vfe_frame_ts frame_ts;
 	struct msm_isp_buf_mgr *buf_mgr;
 	int dump_reg;
 	int vfe_clk_idx;
@@ -446,6 +476,8 @@
 	uint8_t vt_enable;
 	void __iomem *p_avtimer_msw;
 	void __iomem *p_avtimer_lsw;
+	uint8_t ignore_error;
+	struct msm_isp_statistics *stats;
 };
 
 #endif
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 410fe8f..cf76131 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},
@@ -152,6 +154,11 @@
 	msm_camera_io_w_mb(0x1CFFFFFF, vfe_dev->vfe_base + 0x20);
 	msm_camera_io_w(0xFFFFFFFF, vfe_dev->vfe_base + 0x24);
 	msm_camera_io_w_mb(0x1FFFFFFF, vfe_dev->vfe_base + 0x28);
+	msm_camera_io_w(0x0, vfe_dev->vfe_base+0x6FC);
+	msm_camera_io_w( 0x10000000,vfe_dev->vfe_base + VFE32_RDI_BASE(1));
+	msm_camera_io_w( 0x10000000,vfe_dev->vfe_base + VFE32_RDI_BASE(2));
+	msm_camera_io_w(0x0, vfe_dev->vfe_base + VFE32_XBAR_BASE(0));
+	msm_camera_io_w(0x0, vfe_dev->vfe_base + VFE32_XBAR_BASE(4));
 
 }
 
@@ -171,15 +178,15 @@
 	uint32_t irq_status0, uint32_t irq_status1,
 	struct msm_isp_timestamp *ts)
 {
+	uint32_t cnt;
 	if (!(irq_status0 & 0x1F))
 		return;
 
 	if (irq_status0 & BIT(0)) {
 		ISP_DBG("%s: SOF IRQ\n", __func__);
-		if (vfe_dev->axi_data.src_info[VFE_PIX_0].raw_stream_count > 0
-			&& vfe_dev->axi_data.src_info[VFE_PIX_0].
-			pix_stream_count == 0) {
-			msm_isp_sof_notify(vfe_dev, VFE_PIX_0, ts);
+		cnt = vfe_dev->axi_data.src_info[VFE_PIX_0].raw_stream_count;
+		if (cnt > 0) {
+			msm_isp_sof_notify(vfe_dev, VFE_RAW_0, ts);
 			if (vfe_dev->axi_data.stream_update)
 				msm_isp_axi_stream_update(vfe_dev);
 			msm_isp_update_framedrop_reg(vfe_dev);
@@ -248,7 +255,6 @@
 static void msm_vfe32_process_error_status(struct vfe_device *vfe_dev)
 {
 	uint32_t error_status1 = vfe_dev->error_info.error_mask1;
-
 	if (error_status1 & BIT(0))
 		pr_err("%s: camif error status: 0x%x\n",
 			__func__, vfe_dev->error_info.camif_status);
@@ -268,34 +274,62 @@
 		pr_err("%s: violation\n", __func__);
 		msm_vfe32_process_violation_status(vfe_dev);
 	}
-	if (error_status1 & BIT(8))
+	if (error_status1 & BIT(8)) {
+		vfe_dev->stats->imagemaster0_overflow++;
 		pr_err("%s: image master 0 bus overflow\n", __func__);
-	if (error_status1 & BIT(9))
+	}
+	if (error_status1 & BIT(9)) {
+		vfe_dev->stats->imagemaster1_overflow++;
 		pr_err("%s: image master 1 bus overflow\n", __func__);
-	if (error_status1 & BIT(10))
+	}
+	if (error_status1 & BIT(10)) {
+		vfe_dev->stats->imagemaster2_overflow++;
 		pr_err("%s: image master 2 bus overflow\n", __func__);
-	if (error_status1 & BIT(11))
+	}
+	if (error_status1 & BIT(11)) {
+		vfe_dev->stats->imagemaster3_overflow++;
 		pr_err("%s: image master 3 bus overflow\n", __func__);
-	if (error_status1 & BIT(12))
+	}
+	if (error_status1 & BIT(12)) {
+		vfe_dev->stats->imagemaster4_overflow++;
 		pr_err("%s: image master 4 bus overflow\n", __func__);
-	if (error_status1 & BIT(13))
+	}
+	if (error_status1 & BIT(13)) {
+		vfe_dev->stats->imagemaster5_overflow++;
 		pr_err("%s: image master 5 bus overflow\n", __func__);
-	if (error_status1 & BIT(14))
+	}
+	if (error_status1 & BIT(14)) {
+		vfe_dev->stats->imagemaster6_overflow++;
 		pr_err("%s: image master 6 bus overflow\n", __func__);
-	if (error_status1 & BIT(15))
+	}
+	if (error_status1 & BIT(15)) {
+		vfe_dev->stats->bg_overflow++;
 		pr_err("%s: status ae/bg bus overflow\n", __func__);
-	if (error_status1 & BIT(16))
+	}
+	if (error_status1 & BIT(16)) {
+		vfe_dev->stats->bf_overflow++;
 		pr_err("%s: status af/bf bus overflow\n", __func__);
-	if (error_status1 & BIT(17))
+	}
+	if (error_status1 & BIT(17)) {
+		vfe_dev->stats->awb_overflow++;
 		pr_err("%s: status awb bus overflow\n", __func__);
-	if (error_status1 & BIT(18))
+	}
+	if (error_status1 & BIT(18)) {
+		vfe_dev->stats->rs_overflow++;
 		pr_err("%s: status rs bus overflow\n", __func__);
-	if (error_status1 & BIT(19))
+	}
+	if (error_status1 & BIT(19)) {
+		vfe_dev->stats->cs_overflow++;
 		pr_err("%s: status cs bus overflow\n", __func__);
-	if (error_status1 & BIT(20))
+	}
+	if (error_status1 & BIT(20)) {
+		vfe_dev->stats->ihist_overflow++;
 		pr_err("%s: status ihist bus overflow\n", __func__);
-	if (error_status1 & BIT(21))
+	}
+	if (error_status1 & BIT(21)) {
+		vfe_dev->stats->skinbhist_overflow++;
 		pr_err("%s: status skin bhist bus overflow\n", __func__);
+	}
 	if (error_status1 & BIT(22))
 		pr_err("%s: axi error\n", __func__);
 }
@@ -322,7 +356,6 @@
 	uint32_t irq_status0, uint32_t irq_status1,
 	struct msm_isp_timestamp *ts)
 {
-	uint32_t rdi_status;
 	if (!(irq_status0 & 0x20) && !(irq_status1 & 0x1C000000))
 		return;
 
@@ -335,18 +368,6 @@
 	if (irq_status1 & BIT(28))
 		msm_isp_sof_notify(vfe_dev, VFE_RAW_2, ts);
 
-	if (vfe_dev->axi_data.stream_update) {
-		rdi_status = msm_camera_io_r(vfe_dev->vfe_base +
-						VFE32_XBAR_BASE(0));
-		rdi_status |= msm_camera_io_r(vfe_dev->vfe_base +
-						VFE32_XBAR_BASE(4));
-
-		if (((rdi_status & BIT(7)) || (rdi_status & BIT(7)) ||
-			(rdi_status & BIT(7)) || (rdi_status & BIT(7))) &&
-			(!(irq_status0 & 0x20)))
-			return;
-	}
-
 	if (vfe_dev->axi_data.stream_update)
 		msm_isp_axi_stream_update(vfe_dev);
 	if (atomic_read(&vfe_dev->stats_data.stats_update))
@@ -365,11 +386,25 @@
 	msm_camera_io_w_mb(0xF, vfe_dev->vfe_base + 0x260);
 }
 
-static long msm_vfe32_reset_hardware(struct vfe_device *vfe_dev)
+static uint32_t msm_vfe32_reset_values[ISP_RST_MAX] =
 {
+	0x3FF, /* ISP_RST_HARD reset everything */
+	0x3EF /* ISP_RST_SOFT same as HARD RESET */
+};
+
+static long msm_vfe32_reset_hardware(struct vfe_device *vfe_dev ,
+				enum msm_isp_reset_type reset_type)
+{
+
+	uint32_t rst_val;
+	if (reset_type >= ISP_RST_MAX) {
+		pr_err("%s: Error Invalid parameter\n", __func__);
+		reset_type = ISP_RST_HARD;
+	}
+	rst_val = msm_vfe32_reset_values[reset_type];
 	init_completion(&vfe_dev->reset_complete);
-	msm_camera_io_w_mb(0x3FF, vfe_dev->vfe_base + 0x4);
-	return wait_for_completion_interruptible_timeout(
+	msm_camera_io_w_mb(rst_val, vfe_dev->vfe_base + 0x4);
+	return wait_for_completion_timeout(
 	   &vfe_dev->reset_complete, msecs_to_jiffies(50));
 }
 
@@ -381,9 +416,8 @@
 		msm_camera_io_w_mb(reload_mask, vfe_dev->vfe_base + 0x38);
 	} else {
 		/*vfe32 B-family: 8610*/
-		msm_camera_io_w(0x0, vfe_dev->vfe_base + 0x24);
 		msm_camera_io_w(0x0, vfe_dev->vfe_base + 0x28);
-		msm_camera_io_w(0x0, vfe_dev->vfe_base + 0x20);
+		msm_camera_io_w(0x1C800000, vfe_dev->vfe_base + 0x20);
 		msm_camera_io_w_mb(0x1, vfe_dev->vfe_base + 0x18);
 		msm_camera_io_w(0x9AAAAAAA , vfe_dev->vfe_base + 0x600);
 		msm_camera_io_w(reload_mask, vfe_dev->vfe_base + 0x38);
@@ -632,9 +666,6 @@
 		vfe_dev->axi_data.src_info[VFE_PIX_0].active = 0;
 	} else if (update_state == DISABLE_CAMIF_IMMEDIATELY) {
 		msm_camera_io_w_mb(0x6, vfe_dev->vfe_base + 0x1E0);
-		vfe_dev->hw_info->vfe_ops.axi_ops.halt(vfe_dev);
-		vfe_dev->hw_info->vfe_ops.core_ops.reset_hw(vfe_dev);
-		vfe_dev->hw_info->vfe_ops.core_ops.init_hw_reg(vfe_dev);
 		vfe_dev->axi_data.src_info[VFE_PIX_0].active = 0;
 	}
 }
@@ -708,6 +739,8 @@
 {
 	uint32_t val = 0;
 	uint32_t wm_base = VFE32_WM_BASE(stream_info->wm[plane_idx]);
+	/* FRAME BASED */
+	msm_camera_io_w(val, vfe_dev->vfe_base + wm_base);
 	/*WR_IMAGE_SIZE*/
 	msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x10);
 	/*WR_BUFFER_CFG*/
@@ -783,7 +816,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;
@@ -805,6 +874,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)
 {
@@ -1065,6 +1144,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 ad4b75f..04136d0 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp40.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
@@ -13,7 +13,7 @@
 #include <linux/module.h>
 #include <mach/iommu.h>
 #include <linux/ratelimit.h>
-
+#include <asm/div64.h>
 #include "msm_isp40.h"
 #include "msm_isp_util.h"
 #include "msm_isp_axi_util.h"
@@ -36,8 +36,8 @@
 #define VFE40_8x26_VERSION 0x20000013
 #define VFE40_8x26V2_VERSION 0x20010014
 
-#define VFE40_BURST_LEN 3
-#define VFE40_STATS_BURST_LEN 2
+#define VFE40_BURST_LEN 1
+#define VFE40_STATS_BURST_LEN 1
 #define VFE40_UB_SIZE 1536
 #define VFE40_EQUAL_SLICE_UB 228
 #define VFE40_WM_BASE(idx) (0x6C + 0x24 * idx)
@@ -370,15 +370,16 @@
 	uint32_t irq_status0, uint32_t irq_status1,
 	struct msm_isp_timestamp *ts)
 {
+	int cnt;
+
 	if (!(irq_status0 & 0xF))
 		return;
 
 	if (irq_status0 & (1 << 0)) {
 		ISP_DBG("%s: SOF IRQ\n", __func__);
-		if (vfe_dev->axi_data.src_info[VFE_PIX_0].raw_stream_count > 0
-			&& vfe_dev->axi_data.src_info[VFE_PIX_0].
-			pix_stream_count == 0) {
-			msm_isp_sof_notify(vfe_dev, VFE_PIX_0, ts);
+		cnt = vfe_dev->axi_data.src_info[VFE_PIX_0].raw_stream_count;
+		if (cnt > 0) {
+			msm_isp_sof_notify(vfe_dev, VFE_RAW_0, ts);
 			if (vfe_dev->axi_data.stream_update)
 				msm_isp_axi_stream_update(vfe_dev);
 			msm_isp_update_framedrop_reg(vfe_dev);
@@ -461,54 +462,92 @@
 {
 	uint32_t error_status1 = vfe_dev->error_info.error_mask1;
 	if (error_status1 & (1 << 0))
-		pr_err("%s: camif error status: 0x%x\n",
+		pr_err_ratelimited("%s: camif error status: 0x%x\n",
 			__func__, vfe_dev->error_info.camif_status);
 	if (error_status1 & (1 << 1))
-		pr_err("%s: stats bhist overwrite\n", __func__);
+		pr_err_ratelimited("%s: stats bhist overwrite\n", __func__);
 	if (error_status1 & (1 << 2))
-		pr_err("%s: stats cs overwrite\n", __func__);
+		pr_err_ratelimited("%s: stats cs overwrite\n", __func__);
 	if (error_status1 & (1 << 3))
-		pr_err("%s: stats ihist overwrite\n", __func__);
+		pr_err_ratelimited("%s: stats ihist overwrite\n", __func__);
 	if (error_status1 & (1 << 4))
-		pr_err("%s: realign buf y overflow\n", __func__);
+		pr_err_ratelimited("%s: realign buf y overflow\n", __func__);
 	if (error_status1 & (1 << 5))
-		pr_err("%s: realign buf cb overflow\n", __func__);
+		pr_err_ratelimited("%s: realign buf cb overflow\n", __func__);
 	if (error_status1 & (1 << 6))
-		pr_err("%s: realign buf cr overflow\n", __func__);
+		pr_err_ratelimited("%s: realign buf cr overflow\n", __func__);
 	if (error_status1 & (1 << 7)) {
-		pr_err("%s: violation\n", __func__);
+		pr_err_ratelimited("%s: violation\n", __func__);
 		msm_vfe40_process_violation_status(vfe_dev);
 	}
-	if (error_status1 & (1 << 9))
-		pr_err("%s: image master 0 bus overflow\n", __func__);
-	if (error_status1 & (1 << 10))
-		pr_err("%s: image master 1 bus overflow\n", __func__);
-	if (error_status1 & (1 << 11))
-		pr_err("%s: image master 2 bus overflow\n", __func__);
-	if (error_status1 & (1 << 12))
-		pr_err("%s: image master 3 bus overflow\n", __func__);
-	if (error_status1 & (1 << 13))
-		pr_err("%s: image master 4 bus overflow\n", __func__);
-	if (error_status1 & (1 << 14))
-		pr_err("%s: image master 5 bus overflow\n", __func__);
-	if (error_status1 & (1 << 15))
-		pr_err("%s: image master 6 bus overflow\n", __func__);
-	if (error_status1 & (1 << 16))
-		pr_err("%s: status be bus overflow\n", __func__);
-	if (error_status1 & (1 << 17))
-		pr_err("%s: status bg bus overflow\n", __func__);
-	if (error_status1 & (1 << 18))
-		pr_err("%s: status bf bus overflow\n", __func__);
-	if (error_status1 & (1 << 19))
-		pr_err("%s: status awb bus overflow\n", __func__);
-	if (error_status1 & (1 << 20))
-		pr_err("%s: status rs bus overflow\n", __func__);
-	if (error_status1 & (1 << 21))
-		pr_err("%s: status cs bus overflow\n", __func__);
-	if (error_status1 & (1 << 22))
-		pr_err("%s: status ihist bus overflow\n", __func__);
-	if (error_status1 & (1 << 23))
-		pr_err("%s: status skin bhist bus overflow\n", __func__);
+	if (error_status1 & (1 << 9)) {
+		vfe_dev->stats->imagemaster0_overflow++;
+		pr_err_ratelimited("%s: image master 0 bus overflow\n",
+			__func__);
+	}
+	if (error_status1 & (1 << 10)) {
+		vfe_dev->stats->imagemaster1_overflow++;
+		pr_err_ratelimited("%s: image master 1 bus overflow\n",
+			__func__);
+	}
+	if (error_status1 & (1 << 11)) {
+		vfe_dev->stats->imagemaster2_overflow++;
+		pr_err_ratelimited("%s: image master 2 bus overflow\n",
+			__func__);
+	}
+	if (error_status1 & (1 << 12)) {
+		vfe_dev->stats->imagemaster3_overflow++;
+		pr_err_ratelimited("%s: image master 3 bus overflow\n",
+			__func__);
+	}
+	if (error_status1 & (1 << 13)) {
+		vfe_dev->stats->imagemaster4_overflow++;
+		pr_err_ratelimited("%s: image master 4 bus overflow\n",
+			__func__);
+	}
+	if (error_status1 & (1 << 14)) {
+		vfe_dev->stats->imagemaster5_overflow++;
+		pr_err_ratelimited("%s: image master 5 bus overflow\n",
+			__func__);
+	}
+	if (error_status1 & (1 << 15)) {
+		vfe_dev->stats->imagemaster6_overflow++;
+		pr_err_ratelimited("%s: image master 6 bus overflow\n",
+			__func__);
+	}
+	if (error_status1 & (1 << 16)) {
+		vfe_dev->stats->be_overflow++;
+		pr_err_ratelimited("%s: status be bus overflow\n", __func__);
+	}
+	if (error_status1 & (1 << 17)) {
+		vfe_dev->stats->bg_overflow++;
+		pr_err_ratelimited("%s: status bg bus overflow\n", __func__);
+	}
+	if (error_status1 & (1 << 18)) {
+		vfe_dev->stats->bf_overflow++;
+		pr_err_ratelimited("%s: status bf bus overflow\n", __func__);
+	}
+	if (error_status1 & (1 << 19)) {
+		vfe_dev->stats->awb_overflow++;
+		pr_err_ratelimited("%s: status awb bus overflow\n", __func__);
+	}
+	if (error_status1 & (1 << 20)) {
+		vfe_dev->stats->imagemaster0_overflow++;
+		pr_err_ratelimited("%s: status rs bus overflow\n", __func__);
+	}
+	if (error_status1 & (1 << 21)) {
+		vfe_dev->stats->cs_overflow++;
+		pr_err_ratelimited("%s: status cs bus overflow\n", __func__);
+	}
+	if (error_status1 & (1 << 22)) {
+		vfe_dev->stats->ihist_overflow++;
+		pr_err_ratelimited("%s: status ihist bus overflow\n", __func__);
+	}
+	if (error_status1 & (1 << 23)) {
+		vfe_dev->stats->skinbhist_overflow++;
+		pr_err_ratelimited("%s: status skin bhist bus overflow\n",
+			__func__);
+	}
 }
 
 static void msm_vfe40_read_irq_status(struct vfe_device *vfe_dev,
@@ -573,11 +612,25 @@
 	msm_camera_io_w_mb(0xF, vfe_dev->vfe_base + 0x378);
 }
 
-static long msm_vfe40_reset_hardware(struct vfe_device *vfe_dev)
+static uint32_t msm_vfe40_reset_values[ISP_RST_MAX] =
 {
+	0x1FF, /* ISP_RST_HARD reset everything */
+	0x1EF /* ISP_RST_SOFT all modules without registers */
+};
+
+
+static long msm_vfe40_reset_hardware(struct vfe_device *vfe_dev ,
+				enum msm_isp_reset_type reset_type)
+{
+	uint32_t rst_val;
+	if (reset_type >= ISP_RST_MAX) {
+		pr_err("%s: Error Invalid parameter\n", __func__);
+		reset_type = ISP_RST_HARD;
+	}
+	rst_val = msm_vfe40_reset_values[reset_type];
 	init_completion(&vfe_dev->reset_complete);
-	msm_camera_io_w_mb(0x1FF, vfe_dev->vfe_base + 0xC);
-	return wait_for_completion_interruptible_timeout(
+	msm_camera_io_w_mb(rst_val, vfe_dev->vfe_base + 0xC);
+	return wait_for_completion_timeout(
 		&vfe_dev->reset_complete, msecs_to_jiffies(50));
 }
 
@@ -878,9 +931,6 @@
 		vfe_dev->axi_data.src_info[VFE_PIX_0].active = 0;
 	} else if (update_state == DISABLE_CAMIF_IMMEDIATELY) {
 		msm_camera_io_w_mb(0x6, vfe_dev->vfe_base + 0x2F4);
-		vfe_dev->hw_info->vfe_ops.axi_ops.halt(vfe_dev);
-		vfe_dev->hw_info->vfe_ops.core_ops.reset_hw(vfe_dev);
-		vfe_dev->hw_info->vfe_ops.core_ops.init_hw_reg(vfe_dev);
 		vfe_dev->axi_data.src_info[VFE_PIX_0].active = 0;
 	}
 }
@@ -1058,7 +1108,6 @@
 	uint8_t num_used_wms = 0;
 	uint32_t prop_size = 0;
 	uint32_t wm_ub_size;
-	uint32_t delta;
 
 	for (i = 0; i < axi_data->hw_info->num_wm; i++) {
 		if (axi_data->free_wm[i] > 0) {
@@ -1070,9 +1119,11 @@
 		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 =
-				(axi_data->wm_image_size[i] *
-					prop_size)/total_image_size;
+			uint64_t delta = 0;
+			uint64_t temp = (uint64_t)axi_data->wm_image_size[i] *
+					(uint64_t)prop_size;
+			do_div(temp, total_image_size);
+			delta = temp;
 			wm_ub_size = axi_data->hw_info->min_wm_ub + delta;
 			msm_camera_io_w(ub_offset << 16 | (wm_ub_size - 1),
 				vfe_dev->vfe_base + VFE40_WM_BASE(i) + 0x10);
@@ -1099,7 +1150,7 @@
 static void msm_vfe40_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_EQUAL_SLICING;
+	axi_data->wm_ub_cfg_policy = MSM_WM_UB_CFG_DEFAULT;
 	if (axi_data->wm_ub_cfg_policy == MSM_WM_UB_EQUAL_SLICING)
 		msm_vfe40_cfg_axi_ub_equal_slicing(vfe_dev);
 	else
@@ -1388,8 +1439,8 @@
 }
 
 static struct msm_vfe_axi_hardware_info msm_vfe40_axi_hw_info = {
-	.num_wm = 5,
-	.num_comp_mask = 2,
+	.num_wm = 7,
+	.num_comp_mask = 3,
 	.num_rdi = 3,
 	.num_rdi_master = 3,
 	.min_wm_ub = 64,
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
index d1af715..13af92f 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
@@ -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
@@ -84,6 +84,10 @@
 		return rc;
 
 	switch (stream_cfg_cmd->output_format) {
+	case V4L2_PIX_FMT_YUYV:
+	case V4L2_PIX_FMT_YVYU:
+	case V4L2_PIX_FMT_UYVY:
+	case V4L2_PIX_FMT_VYUY:
 	case V4L2_PIX_FMT_SBGGR8:
 	case V4L2_PIX_FMT_SGBRG8:
 	case V4L2_PIX_FMT_SGRBG8:
@@ -170,6 +174,10 @@
 	uint32_t size = 0;
 	struct msm_vfe_axi_plane_cfg *plane_cfg = stream_info->plane_cfg;
 	switch (stream_info->output_format) {
+	case V4L2_PIX_FMT_YUYV:
+	case V4L2_PIX_FMT_YVYU:
+	case V4L2_PIX_FMT_UYVY:
+	case V4L2_PIX_FMT_VYUY:
 	case V4L2_PIX_FMT_SBGGR8:
 	case V4L2_PIX_FMT_SGBRG8:
 	case V4L2_PIX_FMT_SGRBG8:
@@ -214,7 +222,7 @@
 				plane_cfg[plane_idx].output_width;
 		else
 			size = plane_cfg[plane_idx].output_height *
-				plane_cfg[plane_idx].output_width / 2;
+				plane_cfg[plane_idx].output_width;
 		break;
 	case V4L2_PIX_FMT_NV14:
 	case V4L2_PIX_FMT_NV41:
@@ -223,7 +231,7 @@
 				plane_cfg[plane_idx].output_width;
 		else
 			size = plane_cfg[plane_idx].output_height *
-				plane_cfg[plane_idx].output_width / 8;
+				plane_cfg[plane_idx].output_width;
 		break;
 	case V4L2_PIX_FMT_NV16:
 	case V4L2_PIX_FMT_NV61:
@@ -238,6 +246,21 @@
 	return size;
 }
 
+static void msm_isp_get_buffer_ts(struct vfe_device *vfe_dev,
+	struct msm_isp_timestamp *irq_ts, struct msm_isp_timestamp *ts)
+{
+	struct msm_vfe_frame_ts *frame_ts = &vfe_dev->frame_ts;
+	uint32_t frame_count = vfe_dev->error_info.info_dump_frame_count;
+
+	*ts = *irq_ts;
+	if (frame_count == frame_ts->frame_id) {
+		ts->buf_time = frame_ts->buf_time;
+	} else {
+		frame_ts->buf_time = irq_ts->buf_time;
+		frame_ts->frame_id = frame_count;
+	}
+}
+
 void msm_isp_axi_reserve_wm(struct msm_vfe_axi_shared_data *axi_data,
 	struct msm_vfe_axi_stream *stream_info)
 {
@@ -432,7 +455,7 @@
 	sof_event.frame_id = vfe_dev->axi_data.src_info[frame_src].frame_id;
 	sof_event.timestamp = ts->event_time;
 	sof_event.mono_timestamp = ts->buf_time;
-	msm_isp_send_event(vfe_dev, ISP_EVENT_SOF, &sof_event);
+	msm_isp_send_event(vfe_dev, ISP_EVENT_SOF + frame_src, &sof_event);
 }
 
 void msm_isp_calculate_framedrop(
@@ -950,6 +973,68 @@
 	}
 }
 
+static void msm_isp_update_rdi_output_count(
+	  struct vfe_device *vfe_dev,
+	  struct msm_vfe_axi_stream_cfg_cmd *stream_cfg_cmd)
+{
+	int i;
+	struct msm_vfe_axi_stream *stream_info;
+	struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data;
+
+	if (stream_cfg_cmd->num_streams > MAX_NUM_STREAM) {
+		return;
+	}
+
+	for (i = 0; i < stream_cfg_cmd->num_streams; i++) {
+		if (HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i])
+		> MAX_NUM_STREAM) {
+			return;
+		}
+		stream_info =
+			&axi_data->stream_info[
+			HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i])];
+		if (stream_info->stream_src < RDI_INTF_0)
+			continue;
+		if (stream_info->stream_src == RDI_INTF_0) {
+			if (stream_cfg_cmd->cmd == START_STREAM)
+				vfe_dev->axi_data.src_info[VFE_RAW_0].
+					raw_stream_count++;
+			else
+				vfe_dev->axi_data.src_info[VFE_RAW_0].
+					raw_stream_count--;
+		} else if (stream_info->stream_src == RDI_INTF_1) {
+			if (stream_cfg_cmd->cmd == START_STREAM)
+				vfe_dev->axi_data.src_info[VFE_RAW_1].
+					raw_stream_count++;
+			else
+				vfe_dev->axi_data.src_info[VFE_RAW_1].
+					raw_stream_count--;
+		} else if (stream_info->stream_src == RDI_INTF_2) {
+		       if (stream_cfg_cmd->cmd == START_STREAM)
+				vfe_dev->axi_data.src_info[VFE_RAW_2].
+					raw_stream_count++;
+			else
+				vfe_dev->axi_data.src_info[VFE_RAW_2].
+					raw_stream_count--;
+		}
+
+	}
+}
+
+static uint8_t msm_isp_get_curr_stream_cnt(
+	  struct vfe_device *vfe_dev)
+{
+         uint8_t curr_stream_cnt = 0;
+	  curr_stream_cnt = vfe_dev->axi_data.src_info[VFE_RAW_0].
+					raw_stream_count + vfe_dev->axi_data.src_info[VFE_RAW_1].
+					raw_stream_count + vfe_dev->axi_data.src_info[VFE_RAW_2].
+					raw_stream_count + vfe_dev->axi_data.src_info[VFE_PIX_0].
+					pix_stream_count  + vfe_dev->axi_data.src_info[VFE_PIX_0].
+					raw_stream_count;
+
+	  return curr_stream_cnt;
+}
+
 void msm_camera_io_dump_2(void __iomem *addr, int size)
 {
 	char line_str[128], *p_str;
@@ -1007,8 +1092,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;
 	total_streams = num_pix_streams + num_rdi_streams;
 	if (total_streams == 1) {
@@ -1037,7 +1122,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) {
@@ -1151,17 +1236,21 @@
 			msm_isp_axi_stream_enable_cfg(vfe_dev, stream_info);
 			stream_info->state = ACTIVE;
 		}
+		vfe_dev->axi_data.src_info[
+			SRC_TO_INTF(stream_info->stream_src)].frame_id = 0;
 	}
 	msm_isp_update_stream_bandwidth(vfe_dev);
 	vfe_dev->hw_info->vfe_ops.axi_ops.reload_wm(vfe_dev, wm_reload_mask);
 	vfe_dev->hw_info->vfe_ops.core_ops.reg_update(vfe_dev);
 
 	msm_isp_update_camif_output_count(vfe_dev, stream_cfg_cmd);
+	msm_isp_update_rdi_output_count(vfe_dev, stream_cfg_cmd);
 	if (camif_update == ENABLE_CAMIF) {
 		vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id = 0;
 		vfe_dev->hw_info->vfe_ops.core_ops.
 			update_camif_state(vfe_dev, camif_update);
 	}
+
 	if (wait_for_complete)
 		rc = msm_isp_axi_wait_for_cfg_done(vfe_dev, camif_update);
 
@@ -1173,7 +1262,7 @@
 			enum msm_isp_camif_update_state camif_update)
 {
 	int i, rc = 0;
-	uint8_t wait_for_complete = 0;
+	uint8_t wait_for_complete = 0, cur_stream_cnt = 0;
 	struct msm_vfe_axi_stream *stream_info;
 	struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data;
 
@@ -1218,7 +1307,15 @@
 		rc = msm_isp_axi_wait_for_cfg_done(vfe_dev, camif_update);
 		if (rc < 0) {
 			pr_err("%s: wait for config done failed\n", __func__);
-			return rc;
+			for (i = 0; i < stream_cfg_cmd->num_streams; i++) {
+				stream_info = &axi_data->stream_info[
+				HANDLE_TO_IDX(
+					stream_cfg_cmd->stream_handle[i])];
+				stream_info->state = STOP_PENDING;
+				msm_isp_axi_stream_enable_cfg(
+					vfe_dev, stream_info);
+				stream_info->state = INACTIVE;
+			}
 		}
 	}
 	msm_isp_update_stream_bandwidth(vfe_dev);
@@ -1229,6 +1326,17 @@
 		vfe_dev->hw_info->vfe_ops.core_ops.
 			update_camif_state(vfe_dev, DISABLE_CAMIF_IMMEDIATELY);
 	msm_isp_update_camif_output_count(vfe_dev, stream_cfg_cmd);
+	msm_isp_update_rdi_output_count(vfe_dev, stream_cfg_cmd);
+	cur_stream_cnt = msm_isp_get_curr_stream_cnt(vfe_dev);
+	if (cur_stream_cnt == 0) {
+		vfe_dev->ignore_error = 1;
+		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_HARD);
+		vfe_dev->hw_info->vfe_ops.core_ops.init_hw_reg(vfe_dev);
+		vfe_dev->ignore_error = 0;
+	}
 
 	for (i = 0; i < stream_cfg_cmd->num_streams; i++) {
 		stream_info = &axi_data->stream_info[
@@ -1304,7 +1412,10 @@
 			return -EINVAL;
 		}
 		if (stream_info->state == ACTIVE &&
-			stream_info->stream_type == BURST_STREAM) {
+			stream_info->stream_type == BURST_STREAM &&
+			(1 != update_cmd->num_streams ||
+				UPDATE_STREAM_FRAMEDROP_PATTERN !=
+					update_cmd->update_type)) {
 			pr_err("%s: Cannot update active burst stream\n",
 				__func__);
 			return -EINVAL;
@@ -1331,7 +1442,10 @@
 				msm_isp_get_framedrop_period(
 				   update_info->skip_pattern);
 			stream_info->runtime_init_frame_drop = 0;
-			stream_info->framedrop_pattern = 0x1;
+			if (update_info->skip_pattern == SKIP_ALL)
+				stream_info->framedrop_pattern = 0x0;
+			else
+				stream_info->framedrop_pattern = 0x1;
 			stream_info->framedrop_period = framedrop_period - 1;
 			vfe_dev->hw_info->vfe_ops.axi_ops.
 				cfg_framedrop(vfe_dev, stream_info);
@@ -1378,6 +1492,7 @@
 	struct msm_vfe_axi_stream *stream_info;
 	struct msm_vfe_axi_composite_info *comp_info;
 	struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data;
+	struct msm_isp_timestamp buf_ts;
 
 	comp_mask = vfe_dev->hw_info->vfe_ops.axi_ops.
 		get_comp_mask(irq_status0, irq_status1);
@@ -1390,6 +1505,8 @@
 	pingpong_status =
 		vfe_dev->hw_info->vfe_ops.axi_ops.get_pingpong_status(vfe_dev);
 
+	msm_isp_get_buffer_ts(vfe_dev, ts, &buf_ts);
+
 	for (i = 0; i < axi_data->hw_info->num_comp_mask; i++) {
 		comp_info = &axi_data->composite_info[i];
 		if (comp_mask & (1 << i)) {
@@ -1422,7 +1539,7 @@
 				}
 				if (done_buf && !rc)
 					msm_isp_process_done_buf(vfe_dev,
-					stream_info, done_buf, ts);
+					stream_info, done_buf, &buf_ts);
 			}
 		}
 		wm_mask &= ~(comp_info->stream_composite_mask);
@@ -1454,7 +1571,7 @@
 			}
 			if (done_buf && !rc)
 				msm_isp_process_done_buf(vfe_dev,
-				stream_info, done_buf, ts);
+				stream_info, done_buf, &buf_ts);
 		}
 	}
 	return;
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/isp/msm_isp_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c
index 3cb48d1..cb46e9c 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c
@@ -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
@@ -13,6 +13,7 @@
 #include <linux/io.h>
 #include <media/v4l2-subdev.h>
 #include <linux/ratelimit.h>
+#include <asm/div64.h>
 
 #include "msm.h"
 #include "msm_isp_util.h"
@@ -24,11 +25,10 @@
 static DEFINE_MUTEX(bandwidth_mgr_mutex);
 static struct msm_isp_bandwidth_mgr isp_bandwidth_mgr;
 
-#define MSM_ISP_MIN_AB 300000000
-#define MSM_ISP_MIN_IB 450000000
+#define MSM_ISP_MIN_AB 450000000
+#define MSM_ISP_MIN_IB 900000000
 
 #define VFE40_8974V2_VERSION 0x1001001A
-
 static struct msm_bus_vectors msm_isp_init_vectors[] = {
 	{
 		.src = MSM_BUS_MASTER_VFE,
@@ -217,7 +217,8 @@
 {
 	uint32_t avtimer_msw_1st = 0, avtimer_lsw = 0;
 	uint32_t avtimer_msw_2nd = 0;
-	uint8_t iter = 0;
+	uint64_t av_timer_tick = 0;
+
 	if (!vfe_dev->p_avtimer_msw || !vfe_dev->p_avtimer_lsw) {
 		pr_err("%s: ioremap failed\n", __func__);
 		return;
@@ -226,15 +227,10 @@
 		avtimer_msw_1st = msm_camera_io_r(vfe_dev->p_avtimer_msw);
 		avtimer_lsw = msm_camera_io_r(vfe_dev->p_avtimer_lsw);
 		avtimer_msw_2nd = msm_camera_io_r(vfe_dev->p_avtimer_msw);
-	} while ((avtimer_msw_1st != avtimer_msw_2nd)
-		&& (iter++ < AVTIMER_ITERATION_CTR));
-	/*Just return if the MSW TimeStamps don't converge after
-	a few iterations Application needs to handle the zero TS values*/
-	if (iter >= AVTIMER_ITERATION_CTR) {
-		pr_err("%s: AVTimer MSW TS did not converge !!!\n", __func__);
-		return;
-	}
-	time_stamp->vt_time.tv_sec = avtimer_msw_1st;
+	} while (avtimer_msw_1st != avtimer_msw_2nd);
+	av_timer_tick = ((uint64_t)avtimer_msw_1st << 32) | avtimer_lsw;
+	avtimer_lsw = do_div(av_timer_tick, USEC_PER_SEC);
+	time_stamp->vt_time.tv_sec = (uint32_t)(av_timer_tick);
 	time_stamp->vt_time.tv_usec = avtimer_lsw;
 }
 
@@ -277,6 +273,43 @@
 	return rc;
 }
 
+static int msm_isp_get_max_clk_rate(struct vfe_device *vfe_dev, long *rate)
+{
+	int           clk_idx = 0;
+	unsigned long max_value = ~0;
+	long          round_rate = 0;
+
+	if (!vfe_dev || !rate) {
+		pr_err("%s:%d failed: vfe_dev %p rate %p\n", __func__, __LINE__,
+			vfe_dev, rate);
+		return -EINVAL;
+	}
+
+	*rate = 0;
+	if (!vfe_dev->hw_info) {
+		pr_err("%s:%d failed: vfe_dev->hw_info %p\n", __func__,
+			__LINE__, vfe_dev->hw_info);
+		return -EINVAL;
+	}
+
+	clk_idx = vfe_dev->hw_info->vfe_clk_idx;
+	if (clk_idx >= ARRAY_SIZE(vfe_dev->vfe_clk)) {
+		pr_err("%s:%d failed: clk_idx %d max array size %d\n",
+			__func__, __LINE__, clk_idx,
+			ARRAY_SIZE(vfe_dev->vfe_clk));
+		return -EINVAL;
+	}
+
+	round_rate = clk_round_rate(vfe_dev->vfe_clk[clk_idx], max_value);
+	if (round_rate < 0) {
+		pr_err("%s: Invalid vfe clock rate\n", __func__);
+		return -EINVAL;
+	}
+
+	*rate = round_rate;
+	return 0;
+}
+
 static int msm_isp_set_clk_rate(struct vfe_device *vfe_dev, long *rate)
 {
 	int rc = 0;
@@ -445,7 +478,7 @@
 		break;
 
 	default:
-		pr_err("%s: Invalid ISP command\n", __func__);
+		pr_err_ratelimited("%s: Invalid ISP command\n", __func__);
 		rc = -EINVAL;
 	}
 	return rc;
@@ -618,6 +651,23 @@
 	case GET_SOC_HW_VER:
 		*cfg_data = vfe_dev->soc_hw_version;
 		break;
+	case GET_MAX_CLK_RATE: {
+		int rc = 0;
+
+		if (cmd_len < sizeof(unsigned long)) {
+			pr_err("%s:%d failed: invalid cmd len %d exp %d\n",
+				__func__, __LINE__, cmd_len,
+				sizeof(unsigned long));
+			return -EINVAL;
+		}
+		rc = msm_isp_get_max_clk_rate(vfe_dev,
+			(unsigned long *)cfg_data);
+		if (rc < 0) {
+			pr_err("%s:%d failed: rc %d\n", __func__, __LINE__, rc);
+			return -EINVAL;
+		}
+		break;
+	}
 	}
 	return 0;
 }
@@ -752,6 +802,12 @@
 	case V4L2_PIX_FMT_NV61:
 		val = CAL_WORD(pixel_per_line, 1, 8);
 		break;
+	case V4L2_PIX_FMT_YUYV:
+	case V4L2_PIX_FMT_YVYU:
+	case V4L2_PIX_FMT_UYVY:
+	case V4L2_PIX_FMT_VYUY:
+		val = CAL_WORD(pixel_per_line, 2, 8);
+		break;
 		/*TD: Add more image format*/
 	default:
 		msm_isp_print_fourcc_error(__func__, output_format);
@@ -941,7 +997,8 @@
 	error_mask1 &= irq_status1;
 	irq_status0 &= ~error_mask0;
 	irq_status1 &= ~error_mask1;
-	if ((error_mask0 != 0) || (error_mask1 != 0))
+	if (!vfe_dev->ignore_error &&
+		((error_mask0 != 0) || (error_mask1 != 0)))
 		msm_isp_update_error_info(vfe_dev, error_mask0, error_mask1);
 
 	if ((irq_status0 == 0) && (irq_status1 == 0) &&
@@ -1048,7 +1105,7 @@
 		return -EBUSY;
 	}
 
-	rc = vfe_dev->hw_info->vfe_ops.core_ops.reset_hw(vfe_dev);
+	rc = vfe_dev->hw_info->vfe_ops.core_ops.reset_hw(vfe_dev, ISP_RST_HARD);
 	if (rc <= 0) {
 		pr_err("%s: reset timeout\n", __func__);
 		mutex_unlock(&vfe_dev->core_mutex);
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 de098c9..8f99ff6 100755
--- a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c
+++ b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.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
@@ -19,6 +19,7 @@
 #include <linux/platform_device.h>
 #include <linux/gpio.h>
 #include <linux/iopoll.h>
+#include <linux/ratelimit.h>
 #include <media/msmb_isp.h>
 
 #include "msm_ispif.h"
@@ -63,6 +64,25 @@
 		false : true;
 }
 
+static struct msm_cam_clk_info ispif_8626_reset_clk_info[] = {
+	{"ispif_ahb_clk", NO_SET_RATE},
+	{"camss_top_ahb_clk", NO_SET_RATE},
+	{"csi0_ahb_clk", NO_SET_RATE},
+	{"csi0_src_clk", NO_SET_RATE},
+	{"csi0_phy_clk", NO_SET_RATE},
+	{"csi0_clk", NO_SET_RATE},
+	{"csi0_pix_clk", NO_SET_RATE},
+	{"csi0_rdi_clk", NO_SET_RATE},
+	{"csi1_ahb_clk", NO_SET_RATE},
+	{"csi1_src_clk", NO_SET_RATE},
+	{"csi1_phy_clk", NO_SET_RATE},
+	{"csi1_clk", NO_SET_RATE},
+	{"csi1_pix_clk", NO_SET_RATE},
+	{"csi1_rdi_clk", NO_SET_RATE},
+	{"camss_vfe_vfe_clk", NO_SET_RATE},
+	{"camss_csi_vfe_clk", NO_SET_RATE},
+};
+
 static struct msm_cam_clk_info ispif_8974_ahb_clk_info[] = {
 	{"ispif_ahb_clk", -1},
 };
@@ -97,13 +117,26 @@
 	int rc = 0;
 	long timeout = 0;
 	struct clk *reset_clk[ARRAY_SIZE(ispif_8974_reset_clk_info)];
+	struct clk *reset_clk1[ARRAY_SIZE(ispif_8626_reset_clk_info)];
+	ispif->clk_idx = 0;
 
 	rc = msm_cam_clk_enable(&ispif->pdev->dev,
 		ispif_8974_reset_clk_info, reset_clk,
 		ARRAY_SIZE(ispif_8974_reset_clk_info), 1);
 	if (rc < 0) {
-		pr_err("%s: cannot enable clock, error = %d",
-			__func__, rc);
+		rc = msm_cam_clk_enable(&ispif->pdev->dev,
+			ispif_8626_reset_clk_info, reset_clk1,
+			ARRAY_SIZE(ispif_8626_reset_clk_info), 1);
+		if (rc < 0){
+			pr_err("%s: cannot enable clock, error = %d",
+				__func__, rc);
+		} else {
+			/* This is set if device is 8x26 */
+			ispif->clk_idx = 2;
+		}
+	} else {
+		/* This is set if device is 8974 */
+		ispif->clk_idx = 1;
 	}
 
 	init_completion(&ispif->reset_complete[VFE0]);
@@ -117,14 +150,22 @@
 		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) {
 		pr_err("%s: VFE0 reset wait timeout\n", __func__);
-		msm_cam_clk_enable(&ispif->pdev->dev,
+		rc = msm_cam_clk_enable(&ispif->pdev->dev,
 			ispif_8974_reset_clk_info, reset_clk,
 			ARRAY_SIZE(ispif_8974_reset_clk_info), 0);
+		if (rc < 0){
+			rc = msm_cam_clk_enable(&ispif->pdev->dev,
+				ispif_8626_reset_clk_info, reset_clk1,
+				ARRAY_SIZE(ispif_8626_reset_clk_info), 0);
+			if (rc < 0)
+				pr_err("%s: VFE0 reset wait timeout\n", __func__);
+		}
 		return -ETIMEDOUT;
 	}
 
@@ -142,13 +183,26 @@
 		}
 	}
 
-	rc = msm_cam_clk_enable(&ispif->pdev->dev,
-		ispif_8974_reset_clk_info, reset_clk,
-		ARRAY_SIZE(ispif_8974_reset_clk_info), 0);
-	if (rc < 0) {
-		pr_err("%s: cannot disable clock, error = %d",
-			__func__, rc);
+	if (ispif->clk_idx == 1){
+		rc = msm_cam_clk_enable(&ispif->pdev->dev,
+			ispif_8974_reset_clk_info, reset_clk,
+			ARRAY_SIZE(ispif_8974_reset_clk_info), 0);
+		if (rc < 0) {
+			pr_err("%s: cannot disable clock, error = %d",
+				__func__, rc);
+		}
 	}
+
+	if (ispif->clk_idx == 2){
+        	rc = msm_cam_clk_enable(&ispif->pdev->dev,
+			ispif_8626_reset_clk_info, reset_clk1,
+			ARRAY_SIZE(ispif_8626_reset_clk_info), 0);
+        	if (rc < 0) {
+			pr_err("%s: cannot disable clock, error = %d",
+				__func__, rc);
+		}
+	}
+
 	return rc;
 }
 
@@ -200,7 +254,7 @@
 			ispif->base + ISPIF_VFE_m_INTF_CMD_0(i));
 		msm_camera_io_w(ISPIF_STOP_INTF_IMMEDIATELY,
 			ispif->base + ISPIF_VFE_m_INTF_CMD_1(i));
-		pr_debug("%s: base %x", __func__, (unsigned int)ispif->base);
+		pr_debug("%s: base %lx", __func__, (unsigned long)ispif->base);
 		msm_camera_io_w(0, ispif->base +
 			ISPIF_VFE_m_PIX_INTF_n_CID_MASK(i, 0));
 		msm_camera_io_w(0, ispif->base +
@@ -940,11 +994,7 @@
 		goto error_ahb;
 	}
 
-	if (of_device_is_compatible(ispif->pdev->dev.of_node,
-				    "qcom,ispif-v3.0")) {
-		/* currently HW reset is implemented for 8974 only */
-		msm_ispif_reset_hw(ispif);
-	}
+	msm_ispif_reset_hw(ispif);
 
 	rc = msm_ispif_reset(ispif);
 	if (rc == 0) {
@@ -1045,11 +1095,13 @@
 	case MSM_SD_SHUTDOWN: {
 		struct ispif_device *ispif =
 			(struct ispif_device *)v4l2_get_subdevdata(sd);
-		msm_ispif_release(ispif);
+		if (ispif && ispif->base)
+			msm_ispif_release(ispif);
 		return 0;
 	}
 	default:
-		pr_err("%s: invalid cmd 0x%x received\n", __func__, cmd);
+		pr_err_ratelimited("%s: invalid cmd 0x%x received\n",
+			__func__, cmd);
 		return -ENOIOCTLCMD;
 	}
 }
@@ -1197,6 +1249,7 @@
 
 static const struct of_device_id msm_ispif_dt_match[] = {
 	{.compatible = "qcom,ispif"},
+	{}
 };
 
 MODULE_DEVICE_TABLE(of, msm_ispif_dt_match);
diff --git a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.h b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.h
index 45e7354..10dbfb6 100644
--- a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.h
+++ b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.h
@@ -60,5 +60,6 @@
 	struct clk *ahb_clk;
 	struct completion reset_complete[VFE_MAX];
 	uint32_t hw_num_isps;
+	uint32_t clk_idx;
 };
 #endif
diff --git a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif_hwreg_v1.h b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif_hwreg_v1.h
index c8a4366..567a263 100644
--- a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif_hwreg_v1.h
+++ b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif_hwreg_v1.h
@@ -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
@@ -34,12 +34,20 @@
 #define ISPIF_VFE_m_INTF_CMD_0(m)                (0x0004 + ISPIF_VFE(m))
 #define ISPIF_VFE_m_INTF_CMD_1(m)                (0x0030 + ISPIF_VFE(m))
 #define ISPIF_VFE_m_PIX_INTF_n_CID_MASK(m, n)    (0x0010 + ISPIF_VFE(m) + 4*(n))
-#define ISPIF_VFE_m_RDI_INTF_n_CID_MASK(m, n)    (0x0014 + ISPIF_VFE(m) + 4*(n))
+#define ISPIF_VFE_m_RDI_INTF_n_CID_MASK(m, n)    (0x0014 + ISPIF_VFE(m) + \
+							((n > 0) ? (0x20) : 0) \
+							+ 8*(n))
 #define ISPIF_VFE_m_PIX_OUTPUT_n_MISR(m, n)      (0x0290 + ISPIF_VFE(m) + 4*(n))
-#define ISPIF_VFE_m_RDI_OUTPUT_n_MISR_0(m, n)    (0x0298 + ISPIF_VFE(m) + 8*(n))
-#define ISPIF_VFE_m_RDI_OUTPUT_n_MISR_1(m, n)    (0x029C + ISPIF_VFE(m) + 8*(n))
+#define ISPIF_VFE_m_RDI_OUTPUT_n_MISR_0(m, n)    (0x001C + ISPIF_VFE(m) + \
+							((n > 0) ? (0x24) : 0) \
+							+ 0xc*(n))
+#define ISPIF_VFE_m_RDI_OUTPUT_n_MISR_1(m, n)    (0x0020 + ISPIF_VFE(m) + \
+							((n > 0) ? (0x24) : 0) \
+							+ 0xc*(n))
 #define ISPIF_VFE_m_PIX_INTF_n_STATUS(m, n)      (0x0024 + ISPIF_VFE(m) + 4*(n))
-#define ISPIF_VFE_m_RDI_INTF_n_STATUS(m, n)      (0x0028 + ISPIF_VFE(m) + 4*(n))
+#define ISPIF_VFE_m_RDI_INTF_n_STATUS(m, n)      (0x0028 + ISPIF_VFE(m) + \
+							((n > 0) ? (0x34) : 0) \
+							+ 8*(n))
 
 /* Defines for compatibility with newer ISPIF versions */
 #define ISPIF_RST_CMD_1_ADDR                     (0x0000)
diff --git a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_hw.c b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_hw.c
index 44a4014..cd35eb6 100644
--- a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_hw.c
+++ b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_hw.c
@@ -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
@@ -328,7 +328,7 @@
 int msm_jpeg_hw_exec_cmds(struct msm_jpeg_hw_cmd *hw_cmd_p, uint32_t m_cmds,
 	uint32_t max_size, void *base)
 {
-	int is_copy_to_user = -1;
+	int is_copy_to_user = 0;
 	uint32_t data;
 
 	while (m_cmds--) {
diff --git a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_sync.c b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_sync.c
index 5cc51ff..5c0dc22 100644
--- a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_sync.c
+++ b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_sync.c
@@ -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 @@
 #include <linux/list.h>
 #include <linux/uaccess.h>
 #include <linux/slab.h>
+#include <linux/ratelimit.h>
 #include <media/msm_jpeg.h>
 #include "msm_jpeg_sync.h"
 #include "msm_jpeg_core.h"
@@ -721,6 +722,9 @@
 			kfree(hw_cmds_p);
 			return -EFAULT;
 		}
+	} else {
+		kfree(hw_cmds_p);
+		return is_copy_to_user;
 	}
 	kfree(hw_cmds_p);
 	return 0;
@@ -764,11 +768,12 @@
 	for (i = 0; i < 2; i++)
 		kfree(buf_out_free[i]);
 
+	pgmn_dev->state = MSM_JPEG_EXECUTING;
 	JPEG_DBG_HIGH("%s:%d] START\n", __func__, __LINE__);
 	wmb();
 	rc = msm_jpeg_ioctl_hw_cmds(pgmn_dev, arg);
 	wmb();
-	pgmn_dev->state = MSM_JPEG_EXECUTING;
+
 	JPEG_DBG("%s:%d]", __func__, __LINE__);
 	return rc;
 }
@@ -909,7 +914,7 @@
 		rc = msm_jpeg_ioctl_set_clk_rate(pgmn_dev, arg);
 		break;
 	default:
-		JPEG_PR_ERR(KERN_INFO "%s:%d] cmd = %d not supported\n",
+		pr_err_ratelimited("%s:%d] cmd = %d not supported\n",
 			__func__, __LINE__, _IOC_NR(cmd));
 		rc = -EINVAL;
 		break;
diff --git a/drivers/media/platform/msm/camera_v2/msm.c b/drivers/media/platform/msm/camera_v2/msm.c
index 8a2c8e5..e708d37 100644
--- a/drivers/media/platform/msm/camera_v2/msm.c
+++ b/drivers/media/platform/msm/camera_v2/msm.c
@@ -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
@@ -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>
@@ -29,6 +28,8 @@
 #include "msm.h"
 #include "msm_vb2.h"
 #include "msm_sd.h"
+#include <media/msmb_generic_buf_mgr.h>
+
 
 static struct v4l2_device *msm_v4l2_dev;
 static struct list_head    ordered_sd_list;
@@ -341,17 +342,26 @@
 {
 	struct msm_session *session = NULL;
 
-	if (!msm_session_q)
+	if (!msm_session_q) {
+		pr_err("%s : session queue not available Line %d\n",
+				__func__, __LINE__);
 		return -ENODEV;
+	}
 
 	session = msm_queue_find(msm_session_q, struct msm_session,
 		list, __msm_queue_find_session, &session_id);
-	if (session)
+	if (session) {
+		pr_err("%s : Session not found Line %d\n",
+				__func__, __LINE__);
 		return -EINVAL;
+	}
 
 	session = kzalloc(sizeof(*session), GFP_KERNEL);
-	if (!session)
+	if (!session) {
+		pr_err("%s : Memory not available Line %d\n",
+				__func__, __LINE__);
 		return -ENOMEM;
+	}
 
 	session->session_id = session_id;
 	session->event_q.vdev = vdev;
@@ -367,23 +377,31 @@
 	struct msm_session *session;
 	struct msm_command_ack *cmd_ack;
 
-	if (!msm_session_q)
+	if (!msm_session_q) {
+		pr_err("%s : Session queue not available Line %d\n",
+				__func__, __LINE__);
 		return -ENODEV;
+	}
 
 	session = msm_queue_find(msm_session_q, struct msm_session,
 		list, __msm_queue_find_session, &session_id);
-	if (!session)
+	if (!session) {
+		pr_err("%s : Session not found Line %d\n",
+				__func__, __LINE__);
 		return -EINVAL;
+	}
 	mutex_lock(&session->lock);
 	cmd_ack = kzalloc(sizeof(*cmd_ack), GFP_KERNEL);
 	if (!cmd_ack) {
 		mutex_unlock(&session->lock);
+		pr_err("%s : memory not available Line %d\n",
+				__func__, __LINE__);
 		return -ENOMEM;
 	}
 
 	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);
@@ -487,6 +505,7 @@
 int msm_destroy_session(unsigned int session_id)
 {
 	struct msm_session *session;
+	struct v4l2_subdev *buf_mgr_subdev;
 
 	session = msm_queue_find(msm_session_q, struct msm_session,
 		list, __msm_queue_find_session, &session_id);
@@ -498,6 +517,12 @@
 	mutex_destroy(&session->lock);
 	msm_delete_entry(msm_session_q, struct msm_session,
 		list, session);
+	buf_mgr_subdev = msm_buf_mngr_get_subdev();
+	if (buf_mgr_subdev) {
+		v4l2_subdev_call(buf_mgr_subdev, core, ioctl,
+			MSM_SD_SHUTDOWN, NULL);
+	} else
+		pr_err("%s: Buff manger device node is NULL\n", __func__);
 
 	return 0;
 }
@@ -576,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);
 	}
@@ -652,6 +677,8 @@
 	spin_lock_irqsave(&msm_eventq_lock, flags);
 	if (!msm_eventq) {
 		spin_unlock_irqrestore(&msm_eventq_lock, flags);
+		pr_err("%s : msm event queue not available Line %d\n",
+				__func__, __LINE__);
 		return -ENODEV;
 	}
 	spin_unlock_irqrestore(&msm_eventq_lock, flags);
@@ -661,42 +688,47 @@
 	/* send to imaging server and wait for ACK */
 	session = msm_queue_find(msm_session_q, struct msm_session,
 		list, __msm_queue_find_session, &session_id);
-	if (WARN_ON(!session))
+	if (WARN_ON(!session)) {
+		pr_err("%s : session not found Line %d\n",
+				__func__, __LINE__);
 		return -EIO;
+	}
 	mutex_lock(&session->lock);
 	cmd_ack = msm_queue_find(&session->command_ack_q,
 		struct msm_command_ack, list,
 		__msm_queue_find_command_ack_q, &stream_id);
 	if (WARN_ON(!cmd_ack)) {
 		mutex_unlock(&session->lock);
+		pr_err("%s : cmd_ack not found Line %d\n",
+				__func__, __LINE__);
 		return -EIO;
 	}
 
+	/*re-init wait_complete */
+	INIT_COMPLETION(cmd_ack->wait_complete);
+
 	v4l2_event_queue(vdev, event);
 
 	if (timeout < 0) {
 		mutex_unlock(&session->lock);
+		pr_err("%s : timeout cannot be negative Line %d\n",
+				__func__, __LINE__);
 		return rc;
 	}
 
 	/* 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;
 		}
 	}
 
@@ -704,6 +736,8 @@
 		struct msm_command, list);
 	if (!cmd) {
 		mutex_unlock(&session->lock);
+		pr_err("%s : cmd dequeue failed Line %d\n",
+				__func__, __LINE__);
 		return -EINVAL;
 	}
 
@@ -711,9 +745,15 @@
 
 	/* compare cmd_ret and event */
 	if (WARN_ON(event->type != cmd->event.type) ||
-			WARN_ON(event->id != cmd->event.id))
+			WARN_ON(event->id != cmd->event.id)) {
+		pr_err("%s : Either event type or id didnot match Line %d\n",
+				__func__, __LINE__);
+		pr_err("%s : event->type %d event->id %d\n", __func__,
+				event->type, event->id);
+		pr_err("%s : cmd->event.type %d cmd->event.id %d\n", __func__,
+				cmd->event.type, cmd->event.id);
 		rc = -EINVAL;
-
+	}
 	*event = cmd->event;
 
 	kzfree(cmd);
@@ -1036,6 +1076,7 @@
 
 static const struct of_device_id msm_dt_match[] = {
 	{.compatible = "qcom,msm-cam"},
+	{}
 }
 
 MODULE_DEVICE_TABLE(of, msm_dt_match);
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_buf_mgr/msm_generic_buf_mgr.c b/drivers/media/platform/msm/camera_v2/msm_buf_mgr/msm_generic_buf_mgr.c
index 7520ce5..81d4eff 100644
--- a/drivers/media/platform/msm/camera_v2/msm_buf_mgr/msm_generic_buf_mgr.c
+++ b/drivers/media/platform/msm/camera_v2/msm_buf_mgr/msm_generic_buf_mgr.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
@@ -109,8 +109,9 @@
 	if (!list_empty(&buf_mngr_dev->buf_qhead)) {
 		list_for_each_entry_safe(bufs,
 			save, &buf_mngr_dev->buf_qhead, entry) {
-			pr_err("%s: Delete invalid bufs =%x\n", __func__,
-				(unsigned int)bufs);
+			pr_err("%s: Error delete invalid bufs =%x, ses_id=%d, str_id=%d, idx=%d\n",
+				__func__, (unsigned int)bufs, bufs->session_id,
+				bufs->stream_id, bufs->vb2_buf->v4l2_buf.index);
 			list_del_init(&bufs->entry);
 			kfree(bufs);
 		}
@@ -118,6 +119,32 @@
 	spin_unlock_irqrestore(&buf_mngr_dev->buf_q_spinlock, flags);
 }
 
+static int msm_generic_buf_mngr_open(struct v4l2_subdev *sd,
+	struct v4l2_subdev_fh *fh)
+{
+	int rc = 0;
+	struct msm_buf_mngr_device *buf_mngr_dev = v4l2_get_subdevdata(sd);
+	if (!buf_mngr_dev) {
+		pr_err("%s buf manager device NULL\n", __func__);
+		rc = -ENODEV;
+		return rc;
+	}
+	return rc;
+}
+
+static int msm_generic_buf_mngr_close(struct v4l2_subdev *sd,
+	struct v4l2_subdev_fh *fh)
+{
+	int rc = 0;
+	struct msm_buf_mngr_device *buf_mngr_dev = v4l2_get_subdevdata(sd);
+	if (!buf_mngr_dev) {
+		pr_err("%s buf manager device NULL\n", __func__);
+		rc = -ENODEV;
+		return rc;
+	}
+	return rc;
+}
+
 static long msm_buf_mngr_subdev_ioctl(struct v4l2_subdev *sd,
 	unsigned int cmd, void *arg)
 {
@@ -141,6 +168,12 @@
 	case VIDIOC_MSM_BUF_MNGR_PUT_BUF:
 		rc = msm_buf_mngr_put_buf(buf_mngr_dev, argp);
 		break;
+	case VIDIOC_MSM_BUF_MNGR_INIT:
+		rc = msm_generic_buf_mngr_open(sd, NULL);
+		break;
+	case VIDIOC_MSM_BUF_MNGR_DEINIT:
+		rc = msm_generic_buf_mngr_close(sd, NULL);
+		break;
 	case MSM_SD_SHUTDOWN:
 		msm_buf_mngr_sd_shutdown(buf_mngr_dev);
 		break;
@@ -154,12 +187,19 @@
 	.ioctl = msm_buf_mngr_subdev_ioctl,
 };
 
+static const struct v4l2_subdev_internal_ops
+	msm_generic_buf_mngr_subdev_internal_ops = {
+	.open  = msm_generic_buf_mngr_open,
+	.close = msm_generic_buf_mngr_close,
+};
+
 static const struct v4l2_subdev_ops msm_buf_mngr_subdev_ops = {
 	.core = &msm_buf_mngr_subdev_core_ops,
 };
 
 static const struct of_device_id msm_buf_mngr_dt_match[] = {
 	{.compatible = "qcom,msm_buf_mngr"},
+	{}
 };
 
 static int __init msm_buf_mngr_init(void)
@@ -183,6 +223,8 @@
 	msm_buf_mngr_dev->subdev.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV;
 	msm_buf_mngr_dev->subdev.sd.entity.group_id =
 		MSM_CAMERA_SUBDEV_BUF_MNGR;
+	msm_buf_mngr_dev->subdev.sd.internal_ops =
+		&msm_generic_buf_mngr_subdev_internal_ops;
 	msm_buf_mngr_dev->subdev.close_seq = MSM_SD_CLOSE_4TH_CATEGORY;
 	rc = msm_sd_register(&msm_buf_mngr_dev->subdev);
 	if (rc != 0) {
diff --git a/drivers/media/platform/msm/camera_v2/msm_buf_mgr/msm_generic_buf_mgr.h b/drivers/media/platform/msm/camera_v2/msm_buf_mgr/msm_generic_buf_mgr.h
index 56886cd..82ea21f 100644
--- a/drivers/media/platform/msm/camera_v2/msm_buf_mgr/msm_generic_buf_mgr.h
+++ b/drivers/media/platform/msm/camera_v2/msm_buf_mgr/msm_generic_buf_mgr.h
@@ -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
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
index 532bebc..a53ac38 100644
--- a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
+++ b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
@@ -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
@@ -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;
@@ -67,6 +70,9 @@
 /* dump the frame command before writing to the hardware */
 #define  MSM_CPP_DUMP_FRM_CMD 0
 
+static int msm_cpp_buffer_ops(struct cpp_device *cpp_dev,
+	uint32_t buff_mgr_ops, struct msm_buf_mngr_info *buff_mgr_info);
+
 #if CONFIG_MSM_CPP_DBG
 #define CPP_DBG(fmt, args...) pr_err(fmt, ##args)
 #else
@@ -714,6 +720,14 @@
 			goto req_irq_fail;
 		}
 		cpp_dev->buf_mgr_subdev = msm_buf_mngr_get_subdev();
+
+		rc = msm_cpp_buffer_ops(cpp_dev,
+			VIDIOC_MSM_BUF_MNGR_INIT, NULL);
+		if (rc < 0) {
+			pr_err("buf mngr init failed\n");
+			free_irq(cpp_dev->irq->start, cpp_dev);
+			goto req_irq_fail;
+		}
 	}
 
 	cpp_dev->hw_info.cpp_hw_version =
@@ -757,7 +771,12 @@
 
 static void cpp_release_hardware(struct cpp_device *cpp_dev)
 {
+	int32_t rc;
 	if (cpp_dev->state != CPP_STATE_BOOT) {
+		rc = msm_cpp_buffer_ops(cpp_dev,
+			VIDIOC_MSM_BUF_MNGR_DEINIT, NULL);
+		if (rc < 0)
+			pr_err("error in buf mngr deinit rc=%d\n", rc);
 		free_irq(cpp_dev->irq->start, cpp_dev);
 		tasklet_kill(&cpp_dev->cpp_tasklet);
 		atomic_set(&cpp_dev->irq_cnt, 0);
@@ -807,7 +826,10 @@
 
 		/*Start firmware loading*/
 		msm_cpp_write(MSM_CPP_CMD_FW_LOAD, cpp_dev->base);
-		msm_cpp_write(MSM_CPP_END_ADDRESS, cpp_dev->base);
+		if (fw)
+			msm_cpp_write(fw->size, cpp_dev->base);
+		else
+			msm_cpp_write(MSM_CPP_END_ADDRESS, cpp_dev->base);
 		msm_cpp_write(MSM_CPP_START_ADDRESS, cpp_dev->base);
 
 		if (ptr_bin) {
@@ -981,15 +1003,15 @@
 static int msm_cpp_notify_frame_done(struct cpp_device *cpp_dev)
 {
 	struct v4l2_event v4l2_evt;
-	struct msm_queue_cmd *frame_qcmd;
-	struct msm_queue_cmd *event_qcmd;
+	struct msm_queue_cmd *frame_qcmd = NULL;
+	struct msm_queue_cmd *event_qcmd = NULL;
 	struct msm_cpp_frame_info_t *processed_frame;
 	struct msm_device_queue *queue = &cpp_dev->processing_q;
 	struct msm_buf_mngr_info buff_mgr_info;
 	int rc = 0;
 
-	if (queue->len > 0) {
-		frame_qcmd = msm_dequeue(queue, list_frame);
+	frame_qcmd = msm_dequeue(queue, list_frame);
+	if (frame_qcmd) {
 		processed_frame = frame_qcmd->command;
 		do_gettimeofday(&(processed_frame->out_time));
 		kfree(frame_qcmd);
@@ -1101,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,
@@ -1192,7 +1211,7 @@
 	uint32_t *cpp_frame_msg;
 	unsigned long in_phyaddr, out_phyaddr0, out_phyaddr1;
 	uint16_t num_stripes = 0;
-	struct msm_buf_mngr_info buff_mgr_info;
+	struct msm_buf_mngr_info buff_mgr_info, dup_buff_mgr_info;
 	struct msm_cpp_frame_info_t *u_frame_info =
 		(struct msm_cpp_frame_info_t *)ioctl_ptr->ioctl_ptr;
 	int32_t status = 0;
@@ -1279,19 +1298,20 @@
 			new_frame->duplicate_identity);
 		memset(&new_frame->output_buffer_info[1], 0,
 			sizeof(struct msm_cpp_buffer_info_t));
-		memset(&buff_mgr_info, 0, sizeof(struct msm_buf_mngr_info));
-		buff_mgr_info.session_id =
+		memset(&dup_buff_mgr_info, 0, sizeof(struct msm_buf_mngr_info));
+		dup_buff_mgr_info.session_id =
 			((new_frame->duplicate_identity >> 16) & 0xFFFF);
-		buff_mgr_info.stream_id =
+		dup_buff_mgr_info.stream_id =
 			(new_frame->duplicate_identity & 0xFFFF);
 		rc = msm_cpp_buffer_ops(cpp_dev, VIDIOC_MSM_BUF_MNGR_GET_BUF,
-			&buff_mgr_info);
+			&dup_buff_mgr_info);
 		if (rc < 0) {
 			rc = -EAGAIN;
 			pr_debug("error getting buffer rc:%d\n", rc);
-			goto ERROR2;
+			goto ERROR3;
 		}
-		new_frame->output_buffer_info[1].index = buff_mgr_info.index;
+		new_frame->output_buffer_info[1].index =
+			dup_buff_mgr_info.index;
 		out_phyaddr1 = msm_cpp_fetch_buffer_info(cpp_dev,
 			&new_frame->output_buffer_info[1],
 			((new_frame->duplicate_identity >> 16) & 0xFFFF),
@@ -1300,6 +1320,8 @@
 		if (!out_phyaddr1) {
 			pr_err("error gettting output physical address\n");
 			rc = -EINVAL;
+			msm_cpp_buffer_ops(cpp_dev, VIDIOC_MSM_BUF_MNGR_PUT_BUF,
+				&dup_buff_mgr_info);
 			goto ERROR3;
 		}
 		/* set duplicate enable bit */
@@ -1449,6 +1471,7 @@
 	case VIDIOC_MSM_CPP_FLUSH_QUEUE:
 		rc = msm_cpp_flush_frames(cpp_dev);
 		break;
+	case VIDIOC_MSM_CPP_APPEND_STREAM_BUFF_INFO:
 	case VIDIOC_MSM_CPP_ENQUEUE_STREAM_BUFF_INFO: {
 		struct msm_cpp_stream_buff_info_t *u_stream_buff_info;
 		struct msm_cpp_stream_buff_info_t k_stream_buff_info;
@@ -1516,9 +1539,12 @@
 			return -EINVAL;
 		}
 
-		rc = msm_cpp_add_buff_queue_entry(cpp_dev,
-			((k_stream_buff_info.identity >> 16) & 0xFFFF),
-			(k_stream_buff_info.identity & 0xFFFF));
+		if (cmd != VIDIOC_MSM_CPP_APPEND_STREAM_BUFF_INFO) {
+			rc = msm_cpp_add_buff_queue_entry(cpp_dev,
+				((k_stream_buff_info.identity >> 16) & 0xFFFF),
+				(k_stream_buff_info.identity & 0xFFFF));
+		}
+
 		if (!rc)
 			rc = msm_cpp_enqueue_buff_info_list(cpp_dev,
 				&k_stream_buff_info);
@@ -1564,18 +1590,69 @@
 		struct msm_queue_cmd *event_qcmd;
 		struct msm_cpp_frame_info_t *process_frame;
 		event_qcmd = msm_dequeue(queue, list_eventdata);
-		process_frame = event_qcmd->command;
-		CPP_DBG("fid %d\n", process_frame->frame_id);
-		if (copy_to_user((void __user *)ioctl_ptr->ioctl_ptr,
-				process_frame,
-				sizeof(struct msm_cpp_frame_info_t))) {
-					mutex_unlock(&cpp_dev->mutex);
-					return -EINVAL;
+		if(event_qcmd) {
+			process_frame = event_qcmd->command;
+			CPP_DBG("fid %d\n", process_frame->frame_id);
+			if (copy_to_user((void __user *)ioctl_ptr->ioctl_ptr,
+					process_frame,
+					sizeof(struct msm_cpp_frame_info_t))) {
+						mutex_unlock(&cpp_dev->mutex);
+						return -EINVAL;
+			}
+
+			kfree(process_frame->cpp_cmd_msg);
+			kfree(process_frame);
+			kfree(event_qcmd);
+		} else {
+			pr_err("Empty command list\n");
+			return -EFAULT;
+		}
+		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;
 		}
 
-		kfree(process_frame->cpp_cmd_msg);
-		kfree(process_frame);
-		kfree(event_qcmd);
+		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: {
@@ -1850,6 +1927,7 @@
 		rc = -ENOMEM;
 		goto ERROR3;
 	}
+
 	INIT_WORK((struct work_struct *)cpp_dev->work, msm_cpp_do_timeout_work);
 	cpp_dev->cpp_open_cnt = 0;
 	cpp_dev->is_firmware_loaded = 0;
diff --git a/drivers/media/platform/msm/camera_v2/sensor/Makefile b/drivers/media/platform/msm/camera_v2/sensor/Makefile
index 280a9a0..a33cf62 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/Makefile
+++ b/drivers/media/platform/msm/camera_v2/sensor/Makefile
@@ -4,15 +4,12 @@
 ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor/io
 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.o
-obj-$(CONFIG_S5K3L1YX) += s5k3l1yx.o
-obj-$(CONFIG_IMX135) += imx135.o
+obj-$(CONFIG_MSM_CAMERA_SENSOR) += msm_sensor_init.o msm_sensor_driver.o msm_sensor.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/actuator/msm_actuator.c b/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c
index bb2b074..8e7dc2c 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c
@@ -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
@@ -127,31 +127,65 @@
 }
 
 static int32_t msm_actuator_init_focus(struct msm_actuator_ctrl_t *a_ctrl,
-	uint16_t size, enum msm_actuator_data_type type,
-	struct reg_settings_t *settings)
+	uint16_t size, struct reg_settings_t *settings)
 {
 	int32_t rc = -EFAULT;
 	int32_t i = 0;
 	CDBG("Enter\n");
 
 	for (i = 0; i < size; i++) {
-		switch (type) {
-		case MSM_ACTUATOR_BYTE_DATA:
-			rc = a_ctrl->i2c_client.i2c_func_tbl->i2c_write(
-				&a_ctrl->i2c_client,
-				settings[i].reg_addr,
-				settings[i].reg_data, MSM_CAMERA_I2C_BYTE_DATA);
-			break;
-		case MSM_ACTUATOR_WORD_DATA:
-			rc = a_ctrl->i2c_client.i2c_func_tbl->i2c_write(
-				&a_ctrl->i2c_client,
-				settings[i].reg_addr,
-				settings[i].reg_data, MSM_CAMERA_I2C_WORD_DATA);
-			break;
-		default:
-			pr_err("Unsupport data type: %d\n", type);
+		switch (settings[i].i2c_operation) {
+		case MSM_ACT_WRITE: {
+			switch (settings[i].data_type) {
+			case MSM_ACTUATOR_BYTE_DATA:
+				rc = a_ctrl->i2c_client.i2c_func_tbl->i2c_write(
+					&a_ctrl->i2c_client,
+					settings[i].reg_addr,
+					settings[i].reg_data,
+					MSM_CAMERA_I2C_BYTE_DATA);
+				break;
+			case MSM_ACTUATOR_WORD_DATA:
+				rc = a_ctrl->i2c_client.i2c_func_tbl->i2c_write(
+					&a_ctrl->i2c_client,
+					settings[i].reg_addr,
+					settings[i].reg_data,
+					MSM_CAMERA_I2C_WORD_DATA);
+				break;
+			default:
+				pr_err("Unsupport data type: %d\n",
+					settings[i].i2c_operation);
+				break;
+			}
 			break;
 		}
+		case MSM_ACT_POLL: {
+			switch (settings[i].data_type) {
+			case MSM_ACTUATOR_BYTE_DATA:
+				rc = a_ctrl->i2c_client.i2c_func_tbl->i2c_poll(
+					&a_ctrl->i2c_client,
+					settings[i].reg_addr,
+					settings[i].reg_data,
+					MSM_CAMERA_I2C_BYTE_DATA);
+				break;
+			case MSM_ACTUATOR_WORD_DATA:
+				rc = a_ctrl->i2c_client.i2c_func_tbl->i2c_poll(
+					&a_ctrl->i2c_client,
+					settings[i].reg_addr,
+					settings[i].reg_data,
+					MSM_CAMERA_I2C_WORD_DATA);
+				break;
+			default:
+				pr_err("Unsupport data type: %d\n",
+					settings[i].i2c_operation);
+				break;
+			}
+			break;
+		}
+		}
+
+		if (0 != settings[i].delay)
+			msleep(settings[i].delay);
+
 		if (rc < 0)
 			break;
 	}
@@ -254,6 +288,9 @@
 	int32_t num_steps = move_params->num_steps;
 	struct msm_camera_i2c_reg_setting reg_setting;
 
+	curr_lens_pos = a_ctrl->step_position_table[a_ctrl->curr_step_pos];
+	move_params->curr_lens_pos = curr_lens_pos;
+
 	if (copy_from_user(&ringing_params_kernel,
 		&(move_params->ringing_params[a_ctrl->curr_region_index]),
 		sizeof(struct damping_params_t))) {
@@ -267,7 +304,6 @@
 	if (dest_step_pos == a_ctrl->curr_step_pos)
 		return rc;
 
-	curr_lens_pos = a_ctrl->step_position_table[a_ctrl->curr_step_pos];
 	a_ctrl->i2c_tbl_index = 0;
 	CDBG("curr_step_pos =%d dest_step_pos =%d curr_lens_pos=%d\n",
 		a_ctrl->curr_step_pos, dest_step_pos, curr_lens_pos);
@@ -305,6 +341,7 @@
 		a_ctrl->curr_step_pos = target_step_pos;
 	}
 
+	move_params->curr_lens_pos = curr_lens_pos;
 	reg_setting.reg_setting = a_ctrl->i2c_reg_tbl;
 	reg_setting.data_type = a_ctrl->i2c_data_type;
 	reg_setting.size = a_ctrl->i2c_tbl_index;
@@ -408,6 +445,43 @@
 	return rc;
 }
 
+static int32_t msm_actuator_set_position(
+	struct msm_actuator_ctrl_t *a_ctrl,
+	struct msm_actuator_set_position_t *set_pos)
+{
+	int32_t rc = 0;
+	int32_t index;
+	uint16_t next_lens_position;
+	uint16_t delay;
+	uint32_t hw_params = 0;
+	struct msm_camera_i2c_reg_setting reg_setting;
+	CDBG("%s Enter %d\n", __func__, __LINE__);
+	if (set_pos->number_of_steps  == 0)
+		return rc;
+
+	a_ctrl->i2c_tbl_index = 0;
+	for (index = 0; index < set_pos->number_of_steps; index++) {
+		next_lens_position = set_pos->pos[index];
+		delay = set_pos->delay[index];
+		a_ctrl->func_tbl->actuator_parse_i2c_params(a_ctrl,
+		next_lens_position, hw_params, delay);
+
+		reg_setting.reg_setting = a_ctrl->i2c_reg_tbl;
+		reg_setting.size = a_ctrl->i2c_tbl_index;
+		reg_setting.data_type = a_ctrl->i2c_data_type;
+
+		rc = a_ctrl->i2c_client.i2c_func_tbl->i2c_write_table_w_microdelay(
+			&a_ctrl->i2c_client, &reg_setting);
+		if (rc < 0) {
+			pr_err("%s Failed I2C write Line %d\n", __func__, __LINE__);
+			return rc;
+		}
+		a_ctrl->i2c_tbl_index = 0;
+	}
+	CDBG("%s exit %d\n", __func__, __LINE__);
+	return rc;
+}
+
 static int32_t msm_actuator_init(struct msm_actuator_ctrl_t *a_ctrl,
 	struct msm_actuator_set_info_t *set_info) {
 	struct reg_settings_t *init_settings = NULL;
@@ -504,7 +578,6 @@
 			}
 			rc = a_ctrl->func_tbl->actuator_init_focus(a_ctrl,
 				set_info->actuator_params.init_setting_size,
-				a_ctrl->i2c_data_type,
 				init_settings);
 			kfree(init_settings);
 			if (rc < 0) {
@@ -562,6 +635,12 @@
 			pr_err("move focus failed %d\n", rc);
 		break;
 
+	case CFG_SET_POSITION:
+		rc = a_ctrl->func_tbl->actuator_set_position(a_ctrl,
+			&cdata->cfg.setpos);
+		if (rc < 0)
+			pr_err("actuator_set_position failed %d\n", rc);
+		break;
 	default:
 		break;
 	}
@@ -598,6 +677,7 @@
 	.i2c_write_table_w_microdelay =
 		msm_camera_cci_i2c_write_table_w_microdelay,
 	.i2c_util = msm_sensor_cci_i2c_util,
+	.i2c_poll =  msm_camera_cci_i2c_poll,
 };
 
 static struct msm_camera_i2c_fn_t msm_sensor_qup_func_tbl = {
@@ -608,6 +688,7 @@
 	.i2c_write_seq_table = msm_camera_qup_i2c_write_seq_table,
 	.i2c_write_table_w_microdelay =
 		msm_camera_qup_i2c_write_table_w_microdelay,
+	.i2c_poll = msm_camera_qup_i2c_poll,
 };
 
 static int msm_actuator_open(struct v4l2_subdev *sd,
@@ -916,6 +997,7 @@
 		.actuator_set_default_focus = msm_actuator_set_default_focus,
 		.actuator_init_focus = msm_actuator_init_focus,
 		.actuator_parse_i2c_params = msm_actuator_parse_i2c_params,
+		.actuator_set_position = msm_actuator_set_position,
 	},
 };
 
diff --git a/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.h b/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.h
index 809c9cf..772b12e 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.h
+++ b/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.h
@@ -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
@@ -31,7 +31,7 @@
 	int32_t (*actuator_init_step_table)(struct msm_actuator_ctrl_t *,
 		struct msm_actuator_set_info_t *);
 	int32_t (*actuator_init_focus)(struct msm_actuator_ctrl_t *,
-		uint16_t, enum msm_actuator_data_type, struct reg_settings_t *);
+		uint16_t, struct reg_settings_t *);
 	int32_t (*actuator_set_default_focus) (struct msm_actuator_ctrl_t *,
 			struct msm_actuator_move_params_t *);
 	int32_t (*actuator_move_focus) (struct msm_actuator_ctrl_t *,
@@ -43,6 +43,8 @@
 			struct damping_params_t *,
 			int8_t,
 			int16_t);
+	int32_t (*actuator_set_position)(struct msm_actuator_ctrl_t *,
+		struct msm_actuator_set_position_t *);
 };
 
 struct msm_actuator {
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 4e1f73e..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__);
@@ -631,7 +631,11 @@
 static int msm_cci_subdev_g_chip_ident(struct v4l2_subdev *sd,
 			struct v4l2_dbg_chip_ident *chip)
 {
-	BUG_ON(!chip);
+	if (!chip) {
+		pr_err("%s:%d: NULL pointer supplied for chip ident\n",
+			 __func__, __LINE__);
+		return -EINVAL;
+	}
 	chip->ident = V4L2_IDENT_CCI;
 	chip->revision = 0;
 	return 0;
@@ -675,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);
@@ -709,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 229fdb2..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
@@ -13,6 +13,7 @@
 #include <linux/delay.h>
 #include <linux/module.h>
 #include <linux/of.h>
+#include <linux/ratelimit.h>
 #include <linux/irqreturn.h>
 #include "msm_csid.h"
 #include "msm_csid_hwreg.h"
@@ -94,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;
 }
 
@@ -456,9 +457,8 @@
 			break;
 		}
 		for (i = 0; i < csid_params.lut_params.num_cid; i++) {
-			vc_cfg = kzalloc(csid_params.lut_params.num_cid *
-				sizeof(struct msm_camera_csid_vc_cfg),
-				GFP_KERNEL);
+			vc_cfg = kzalloc(sizeof(struct msm_camera_csid_vc_cfg),
+			    GFP_KERNEL);
 			if (!vc_cfg) {
 				pr_err("%s: %d failed\n", __func__, __LINE__);
 				for (i--; i >= 0; i--)
@@ -468,8 +468,7 @@
 			}
 			if (copy_from_user(vc_cfg,
 				(void *)csid_params.lut_params.vc_cfg[i],
-				(csid_params.lut_params.num_cid *
-				sizeof(struct msm_camera_csid_vc_cfg)))) {
+				sizeof(struct msm_camera_csid_vc_cfg))) {
 				pr_err("%s: %d failed\n", __func__, __LINE__);
 				kfree(vc_cfg);
 				for (i--; i >= 0; i--)
@@ -488,7 +487,7 @@
 		rc = msm_csid_release(csid_dev);
 		break;
 	default:
-		pr_err("%s: %d failed\n", __func__, __LINE__);
+		pr_err_ratelimited("%s: %d failed\n", __func__, __LINE__);
 		rc = -ENOIOCTLCMD;
 		break;
 	}
diff --git a/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.c b/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.c
index d8608ae..9a7c057 100755
--- a/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.c
@@ -15,6 +15,7 @@
 #include <linux/io.h>
 #include <linux/of.h>
 #include <linux/module.h>
+#include <linux/ratelimit.h>
 #include <linux/irqreturn.h>
 #include <mach/vreg.h>
 #include "msm_csiphy.h"
@@ -599,7 +600,7 @@
 		rc = msm_csiphy_release(csiphy_dev, &csi_lane_params);
 		break;
 	default:
-		pr_err("%s: %d failed\n", __func__, __LINE__);
+		pr_err_ratelimited("%s: %d failed\n", __func__, __LINE__);
 		rc = -ENOIOCTLCMD;
 		break;
 	}
diff --git a/drivers/media/platform/msm/camera_v2/sensor/eeprom/msm_eeprom.c b/drivers/media/platform/msm/camera_v2/sensor/eeprom/msm_eeprom.c
index 69c1faa..7649a40 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/eeprom/msm_eeprom.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/eeprom/msm_eeprom.c
@@ -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
@@ -13,6 +13,7 @@
 #include <linux/module.h>
 #include <linux/of_gpio.h>
 #include <linux/delay.h>
+#include <linux/crc32.h>
 #include "msm_sd.h"
 #include "msm_cci.h"
 #include "msm_eeprom.h"
@@ -26,17 +27,130 @@
 
 DEFINE_MSM_MUTEX(msm_eeprom_mutex);
 
-int32_t msm_eeprom_config(struct msm_eeprom_ctrl_t *e_ctrl,
-	void __user *argp)
+
+
+/**
+  * msm_eeprom_verify_sum - verify crc32 checksum
+  * @mem:	data buffer
+  * @size:	size of data buffer
+  * @sum:	expected checksum
+  *
+  * Returns 0 if checksum match, -EINVAL otherwise.
+  */
+static int msm_eeprom_verify_sum(const char *mem, uint32_t size, uint32_t sum)
+{
+	uint32_t crc = ~0UL;
+
+	/* check overflow */
+	if (size > crc - sizeof(uint32_t))
+		return -EINVAL;
+
+	crc = crc32_le(crc, mem, size);
+	if (~crc != sum) {
+		CDBG("%s: expect 0x%x, result 0x%x\n", __func__, sum, ~crc);
+		return -EINVAL;
+	}
+	CDBG("%s: checksum pass 0x%x\n", __func__, sum);
+	return 0;
+}
+
+/**
+  * msm_eeprom_match_crc - verify multiple regions using crc
+  * @data:	data block to be verified
+  *
+  * Iterates through all regions stored in @data.  Regions with odd index
+  * are treated as data, and its next region is treated as checksum.  Thus
+  * regions of even index must have valid_size of 4 or 0 (skip verification).
+  * Returns a bitmask of verified regions, starting from LSB.  1 indicates
+  * a checksum match, while 0 indicates checksum mismatch or not verified.
+  */
+static uint32_t msm_eeprom_match_crc(struct msm_eeprom_memory_block_t *data)
+{
+	int j, rc;
+	uint32_t *sum;
+	uint32_t ret = 0;
+	uint8_t *memptr;
+	struct msm_eeprom_memory_map_t *map;
+
+	if (!data) {
+		pr_err("%s data is NULL", __func__);
+		return -EINVAL;
+	}
+	map = data->map;
+	memptr = data->mapdata;
+
+	for (j = 0; j + 1 < data->num_map; j += 2) {
+		/* empty table or no checksum */
+		if (!map[j].mem.valid_size || !map[j+1].mem.valid_size) {
+			memptr += map[j].mem.valid_size
+				+ map[j+1].mem.valid_size;
+			continue;
+		}
+		if (map[j+1].mem.valid_size != sizeof(uint32_t)) {
+			CDBG("%s: malformatted data mapping\n", __func__);
+			return -EINVAL;
+		}
+		sum = (uint32_t *) (memptr + map[j].mem.valid_size);
+		rc = msm_eeprom_verify_sum(memptr, map[j].mem.valid_size,
+					   *sum);
+		if (!rc)
+			ret |= 1 << (j/2);
+		memptr += map[j].mem.valid_size + map[j+1].mem.valid_size;
+	}
+	return ret;
+}
+
+static int msm_eeprom_get_mm_data(struct msm_eeprom_ctrl_t *e_ctrl,
+				       struct msm_eeprom_cfg_data *cdata)
+{
+	int rc = 0;
+	struct msm_eeprom_mm_t *mm_data = &e_ctrl->eboard_info->mm_data;
+	cdata->cfg.get_mm_data.mm_support = mm_data->mm_support;
+	cdata->cfg.get_mm_data.mm_compression = mm_data->mm_compression;
+	cdata->cfg.get_mm_data.mm_size = mm_data->mm_size;
+	return rc;
+}
+
+static int eeprom_config_read_cal_data(struct msm_eeprom_ctrl_t *e_ctrl,
+				       struct msm_eeprom_cfg_data *cdata)
+{
+	int rc;
+
+	/* check range */
+	if (cdata->cfg.read_data.num_bytes >
+	    e_ctrl->cal_data.num_data) {
+		CDBG("%s: Invalid size. exp %u, req %u\n", __func__,
+		     e_ctrl->cal_data.num_data,
+		     cdata->cfg.read_data.num_bytes);
+		return -EINVAL;
+	}
+	if (!e_ctrl->cal_data.mapdata)
+		return -EFAULT;
+
+	rc = copy_to_user(cdata->cfg.read_data.dbuffer,
+		e_ctrl->cal_data.mapdata,
+		cdata->cfg.read_data.num_bytes);
+
+	/* should only be called once.  free kernel resource */
+	if (!rc) {
+		kfree(e_ctrl->cal_data.mapdata);
+		kfree(e_ctrl->cal_data.map);
+		memset(&e_ctrl->cal_data, 0, sizeof(e_ctrl->cal_data));
+	}
+	return rc;
+}
+
+static int msm_eeprom_config(struct msm_eeprom_ctrl_t *e_ctrl,
+			     void __user *argp)
 {
 	struct msm_eeprom_cfg_data *cdata =
 		(struct msm_eeprom_cfg_data *)argp;
-	int32_t rc = 0;
+	int rc = 0;
 
 	CDBG("%s E\n", __func__);
 	switch (cdata->cfgtype) {
 	case CFG_EEPROM_GET_INFO:
-	CDBG("%s E CFG_EEPROM_GET_INFO\n", __func__);
+		CDBG("%s E CFG_EEPROM_GET_INFO\n", __func__);
 		cdata->is_supported = e_ctrl->is_supported;
 		memcpy(cdata->cfg.eeprom_name,
 			e_ctrl->eboard_info->eeprom_name,
@@ -45,25 +159,26 @@
 	case CFG_EEPROM_GET_CAL_DATA:
 		CDBG("%s E CFG_EEPROM_GET_CAL_DATA\n", __func__);
 		cdata->cfg.get_data.num_bytes =
-			e_ctrl->num_bytes;
+			e_ctrl->cal_data.num_data;
 		break;
 	case CFG_EEPROM_READ_CAL_DATA:
-		if (cdata->cfg.read_data.num_bytes <= e_ctrl->num_bytes) {
-			CDBG("%s E CFG_EEPROM_READ_CAL_DATA\n", __func__);
-			rc = copy_to_user(cdata->cfg.read_data.dbuffer,
-			e_ctrl->memory_data,
-			cdata->cfg.read_data.num_bytes);
-		}
+		CDBG("%s E CFG_EEPROM_READ_CAL_DATA\n", __func__);
+		rc = eeprom_config_read_cal_data(e_ctrl, cdata);
+		break;
+	case CFG_EEPROM_GET_MM_INFO:
+		CDBG("%s E CFG_EEPROM_GET_MM_INFO\n", __func__);
+		rc = msm_eeprom_get_mm_data(e_ctrl, cdata);
 		break;
 	default:
 		break;
 	}
 
-	CDBG("%s X\n", __func__);
+	CDBG("%s X rc: %d\n", __func__, rc);
 	return rc;
 }
-static int32_t msm_eeprom_get_subdev_id(
-	struct msm_eeprom_ctrl_t *e_ctrl, void *arg)
+
+static int msm_eeprom_get_subdev_id(struct msm_eeprom_ctrl_t *e_ctrl,
+				    void *arg)
 {
 	uint32_t *subdev_id = (uint32_t *)arg;
 	CDBG("%s E\n", __func__);
@@ -154,24 +269,38 @@
 	.open = msm_eeprom_open,
 	.close = msm_eeprom_close,
 };
-
-int32_t read_eeprom_memory(struct msm_eeprom_ctrl_t *e_ctrl)
+/**
+  * read_eeprom_memory() - read map data into buffer
+  * @e_ctrl:	eeprom control struct
+  * @block:	block to be read
+  *
+  * This function iterates through blocks stored in block->map, reads each
+  * region and concatenate them into the pre-allocated block->mapdata
+  */
+static int read_eeprom_memory(struct msm_eeprom_ctrl_t *e_ctrl,
+			      struct msm_eeprom_memory_block_t *block)
 {
 	int rc = 0;
 	int j;
-	uint8_t *memptr = NULL;
+	struct msm_eeprom_memory_map_t *emap = block->map;
+	uint8_t *memptr = block->mapdata;
 	struct msm_eeprom_board_info *eb_info = NULL;
-	struct eeprom_memory_map_t *emap = NULL;
+
 	if (!e_ctrl) {
 		pr_err("%s e_ctrl is NULL", __func__);
-		rc = -1;
-		return rc;
+		return -EINVAL;
 	}
-	memptr = e_ctrl->memory_data;
-	eb_info = e_ctrl->eboard_info;
-	emap = eb_info->eeprom_map;
 
-	for (j = 0; j < eb_info->num_blocks; j++) {
+	eb_info = e_ctrl->eboard_info;
+	for (j = 0; j < block->num_map; j++) {
+		if (emap[j].saddr.addr) {
+			eb_info->i2c_slaveaddr = emap[j].saddr.addr;
+			e_ctrl->i2c_client.cci_client->sid =
+					eb_info->i2c_slaveaddr >> 1;
+			pr_err("qcom,slave-addr = 0x%X\n",
+				eb_info->i2c_slaveaddr);
+		}
+
 		if (emap[j].page.valid_size) {
 			e_ctrl->i2c_client.addr_type = emap[j].page.addr_t;
 			rc = e_ctrl->i2c_client.i2c_func_tbl->i2c_write(
@@ -230,157 +359,91 @@
 	}
 	return rc;
 }
-
-static int msm_eeprom_get_dt_data(struct msm_eeprom_ctrl_t *e_ctrl)
-{
-	int rc = 0, i = 0;
-	struct msm_eeprom_board_info *eb_info;
-	struct msm_camera_power_ctrl_t *power_info =
-		&e_ctrl->eboard_info->power_info;
-	struct device_node *of_node = NULL;
-	struct msm_camera_gpio_conf *gconf = NULL;
-	uint16_t gpio_array_size = 0;
-	uint16_t *gpio_array = NULL;
-
-	eb_info = e_ctrl->eboard_info;
-	if (e_ctrl->eeprom_device_type == MSM_CAMERA_SPI_DEVICE)
-		of_node = e_ctrl->i2c_client.
-			spi_client->spi_master->dev.of_node;
-	else if (e_ctrl->eeprom_device_type == MSM_CAMERA_PLATFORM_DEVICE)
-		of_node = e_ctrl->pdev->dev.of_node;
-	else if (e_ctrl->eeprom_device_type == MSM_CAMERA_I2C_DEVICE)
-		of_node = e_ctrl->i2c_client.client->dev.of_node;
-
-	rc = msm_camera_get_dt_vreg_data(of_node, &power_info->cam_vreg,
-					     &power_info->num_vreg);
-	if (rc < 0)
-		return rc;
-
-	rc = msm_camera_get_dt_power_setting_data(of_node,
-		power_info->cam_vreg, power_info->num_vreg,
-		&power_info->power_setting, &power_info->power_setting_size);
-	if (rc < 0)
-		goto error1;
-
-	power_info->gpio_conf = kzalloc(sizeof(struct msm_camera_gpio_conf),
-					GFP_KERNEL);
-	if (!power_info->gpio_conf) {
-		rc = -ENOMEM;
-		goto error2;
-	}
-	gconf = power_info->gpio_conf;
-	gpio_array_size = of_gpio_count(of_node);
-	CDBG("%s gpio count %d\n", __func__, gpio_array_size);
-
-	if (gpio_array_size) {
-		gpio_array = kzalloc(sizeof(uint16_t) * gpio_array_size,
-			GFP_KERNEL);
-		if (!gpio_array) {
-			pr_err("%s failed %d\n", __func__, __LINE__);
-			goto error3;
-		}
-		for (i = 0; i < gpio_array_size; i++) {
-			gpio_array[i] = of_get_gpio(of_node, i);
-			CDBG("%s gpio_array[%d] = %d\n", __func__, i,
-				gpio_array[i]);
-		}
-
-		rc = msm_camera_get_dt_gpio_req_tbl(of_node, gconf,
-			gpio_array, gpio_array_size);
-		if (rc < 0) {
-			pr_err("%s failed %d\n", __func__, __LINE__);
-			goto error4;
-		}
-
-		rc = msm_camera_init_gpio_pin_tbl(of_node, gconf,
-			gpio_array, gpio_array_size);
-		if (rc < 0) {
-			pr_err("%s failed %d\n", __func__, __LINE__);
-			goto error4;
-		}
-		kfree(gpio_array);
-	}
-
-	return rc;
-error4:
-	kfree(gpio_array);
-error3:
-	kfree(power_info->gpio_conf);
-error2:
-	kfree(power_info->cam_vreg);
-error1:
-	kfree(power_info->power_setting);
-	return rc;
-}
-
-static int msm_eeprom_alloc_memory_map(struct msm_eeprom_ctrl_t *e_ctrl,
-				       struct device_node *of)
+/**
+  * msm_eeprom_parse_memory_map() - parse memory map in device node
+  * @of:	device node
+  * @data:	memory block for output
+  *
+  * This functions parses @of to fill @data.  It allocates map itself, parses
+  * the @of node, calculate total data length, and allocates required buffer.
+  * It only fills the map, but does not perform actual reading.
+  */
+static int msm_eeprom_parse_memory_map(struct device_node *of,
+				       struct msm_eeprom_memory_block_t *data)
 {
 	int i, rc = 0;
-	char property[14];
+	char property[PROPERTY_MAXSIZE];
 	uint32_t count = 6;
-	struct msm_eeprom_board_info *eb = e_ctrl->eboard_info;
+	struct msm_eeprom_memory_map_t *map;
 
-	rc = of_property_read_u32(of, "qcom,num-blocks", &eb->num_blocks);
-	CDBG("%s: qcom,num_blocks %d\n", __func__, eb->num_blocks);
+	snprintf(property, PROPERTY_MAXSIZE, "qcom,num-blocks");
+	rc = of_property_read_u32(of, property, &data->num_map);
+	CDBG("%s: %s %d\n", __func__, property, data->num_map);
 	if (rc < 0) {
 		pr_err("%s failed rc %d\n", __func__, rc);
 		return rc;
 	}
 
-	eb->eeprom_map = kzalloc((sizeof(struct eeprom_memory_map_t)
-				 * eb->num_blocks), GFP_KERNEL);
-
-	if (!eb->eeprom_map) {
+	map = kzalloc((sizeof(*map) * data->num_map), GFP_KERNEL);
+	if (!map) {
 		pr_err("%s failed line %d\n", __func__, __LINE__);
 		return -ENOMEM;
 	}
+	data->map = map;
 
-	for (i = 0; i < eb->num_blocks; i++) {
-		snprintf(property, 12, "qcom,page%d", i);
+	for (i = 0; i < data->num_map; i++) {
+		snprintf(property, PROPERTY_MAXSIZE, "qcom,page%d", i);
 		rc = of_property_read_u32_array(of, property,
-			(uint32_t *) &eb->eeprom_map[i].page, count);
+				(uint32_t *) &map[i].page, count);
 		if (rc < 0) {
 			pr_err("%s: failed %d\n", __func__, __LINE__);
-			goto out;
+			goto ERROR;
 		}
 
-		snprintf(property, 14, "qcom,pageen%d", i);
+		snprintf(property, PROPERTY_MAXSIZE,
+					"qcom,pageen%d", i);
 		rc = of_property_read_u32_array(of, property,
-			(uint32_t *) &eb->eeprom_map[i].pageen, count);
+			(uint32_t *) &map[i].pageen, count);
 		if (rc < 0)
 			pr_err("%s: pageen not needed\n", __func__);
 
-		snprintf(property, 12, "qcom,poll%d", i);
+		snprintf(property, PROPERTY_MAXSIZE, "qcom,poll%d", i);
 		rc = of_property_read_u32_array(of, property,
-			(uint32_t *) &eb->eeprom_map[i].poll, count);
+				(uint32_t *) &map[i].poll, count);
 		if (rc < 0) {
 			pr_err("%s failed %d\n", __func__, __LINE__);
-			goto out;
+			goto ERROR;
 		}
 
-		snprintf(property, 12, "qcom,mem%d", i);
+		snprintf(property, PROPERTY_MAXSIZE, "qcom,saddr%d", i);
 		rc = of_property_read_u32_array(of, property,
-			(uint32_t *) &eb->eeprom_map[i].mem, count);
+			(uint32_t *) &map[i].saddr.addr, 1);
+		if (rc < 0)
+			CDBG("%s: saddr not needed - block %d\n", __func__, i);
+
+		snprintf(property, PROPERTY_MAXSIZE, "qcom,mem%d", i);
+		rc = of_property_read_u32_array(of, property,
+				(uint32_t *) &map[i].mem, count);
 		if (rc < 0) {
 			pr_err("%s failed %d\n", __func__, __LINE__);
-			goto out;
+			goto ERROR;
 		}
-		e_ctrl->num_bytes += eb->eeprom_map[i].mem.valid_size;
+		data->num_data += map[i].mem.valid_size;
 	}
 
-	CDBG("%s num_bytes %d\n", __func__, e_ctrl->num_bytes);
+	CDBG("%s num_bytes %d\n", __func__, data->num_data);
 
-	e_ctrl->memory_data = kzalloc(e_ctrl->num_bytes, GFP_KERNEL);
-	if (!e_ctrl->memory_data) {
+	data->mapdata = kzalloc(data->num_data, GFP_KERNEL);
+	if (!data->mapdata) {
 		pr_err("%s failed line %d\n", __func__, __LINE__);
 		rc = -ENOMEM;
-		goto out;
+		goto ERROR;
 	}
 	return rc;
 
-out:
-	kfree(eb->eeprom_map);
+ERROR:
+	kfree(data->map);
+	memset(data, 0, sizeof(*data));
 	return rc;
 }
 
@@ -401,28 +464,20 @@
 	.core = &msm_eeprom_subdev_core_ops,
 };
 
-int32_t msm_eeprom_i2c_probe(struct i2c_client *client,
-	const struct i2c_device_id *id) {
+static int msm_eeprom_i2c_probe(struct i2c_client *client,
+			 const struct i2c_device_id *id)
+{
 	int rc = 0;
-	int32_t j = 0;
-	uint32_t temp = 0;
 	struct msm_eeprom_ctrl_t *e_ctrl = NULL;
 	struct msm_camera_power_ctrl_t *power_info = NULL;
-	struct device_node *of_node = client->dev.of_node;
 	CDBG("%s E\n", __func__);
 
-
-	if (!of_node) {
-		pr_err("%s of_node NULL\n", __func__);
-		return -EINVAL;
-	}
-
 	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
 		pr_err("%s i2c_check_functionality failed\n", __func__);
 		goto probe_failure;
 	}
 
-	e_ctrl = kzalloc(sizeof(struct msm_eeprom_ctrl_t), GFP_KERNEL);
+	e_ctrl = kzalloc(sizeof(*e_ctrl), GFP_KERNEL);
 	if (!e_ctrl) {
 		pr_err("%s:%d kzalloc failed\n", __func__, __LINE__);
 		return -ENOMEM;
@@ -430,23 +485,14 @@
 	e_ctrl->eeprom_v4l2_subdev_ops = &msm_eeprom_subdev_ops;
 	e_ctrl->eeprom_mutex = &msm_eeprom_mutex;
 	CDBG("%s client = %x\n", __func__, (unsigned int)client);
-	e_ctrl->eboard_info = kzalloc(sizeof(
-		struct msm_eeprom_board_info), GFP_KERNEL);
+	e_ctrl->eboard_info = (struct msm_eeprom_board_info *)(id->driver_data);
 	if (!e_ctrl->eboard_info) {
 		pr_err("%s:%d board info NULL\n", __func__, __LINE__);
-		return -EINVAL;
+		rc = -EINVAL;
+		goto ectrl_free;
 	}
-
-	rc = of_property_read_u32(of_node, "qcom,slave-addr", &temp);
-	if (rc < 0) {
-		pr_err("%s failed rc %d\n", __func__, rc);
-		return rc;
-	}
-
 	power_info = &e_ctrl->eboard_info->power_info;
-	e_ctrl->eboard_info->i2c_slaveaddr = temp;
 	e_ctrl->i2c_client.client = client;
-	e_ctrl->is_supported = 0;
 
 	/* Set device type as I2C */
 	e_ctrl->eeprom_device_type = MSM_CAMERA_I2C_DEVICE;
@@ -459,45 +505,6 @@
 	power_info->clk_info_size = ARRAY_SIZE(cam_8960_clk_info);
 	power_info->dev = &client->dev;
 
-	rc = of_property_read_string(of_node, "qcom,eeprom-name",
-		&e_ctrl->eboard_info->eeprom_name);
-	CDBG("%s qcom,eeprom-name %s, rc %d\n", __func__,
-		e_ctrl->eboard_info->eeprom_name, rc);
-	if (rc < 0) {
-		pr_err("%s failed %d\n", __func__, __LINE__);
-		goto board_free;
-	}
-
-	rc = msm_eeprom_get_dt_data(e_ctrl);
-	if (rc)
-		goto board_free;
-
-	rc = msm_eeprom_alloc_memory_map(e_ctrl, of_node);
-	if (rc)
-		goto board_free;
-
-	rc = msm_camera_power_up(power_info, e_ctrl->eeprom_device_type,
-		&e_ctrl->i2c_client);
-	if (rc) {
-		pr_err("%s failed power up %d\n", __func__, __LINE__);
-		goto memdata_free;
-	}
-	rc = read_eeprom_memory(e_ctrl);
-	if (rc < 0) {
-		pr_err("%s read_eeprom_memory failed\n", __func__);
-		goto power_down;
-	}
-
-	for (j = 0; j < e_ctrl->num_bytes; j++)
-		CDBG("memory_data[%d] = 0x%X\n", j, e_ctrl->memory_data[j]);
-
-	rc = msm_camera_power_down(power_info, e_ctrl->eeprom_device_type,
-		&e_ctrl->i2c_client);
-	if (rc) {
-		pr_err("failed rc %d\n", rc);
-		goto power_down;
-	}
-
 	/*IMPLEMENT READING PART*/
 	/* Initialize sub device */
 	v4l2_i2c_subdev_init(&e_ctrl->msm_sd.sd,
@@ -510,24 +517,17 @@
 	e_ctrl->msm_sd.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV;
 	e_ctrl->msm_sd.sd.entity.group_id = MSM_CAMERA_SUBDEV_EEPROM;
 	msm_sd_register(&e_ctrl->msm_sd);
-	e_ctrl->is_supported = 1;
 	CDBG("%s success result=%d X\n", __func__, rc);
 	return rc;
 
-power_down:
-	msm_camera_power_down(power_info, e_ctrl->eeprom_device_type,
-		&e_ctrl->i2c_client);
-memdata_free:
-	kfree(e_ctrl->memory_data);
-	kfree(e_ctrl->eboard_info->eeprom_map);
-board_free:
-	kfree(e_ctrl->eboard_info);
+ectrl_free:
+	kfree(e_ctrl);
 probe_failure:
 	pr_err("%s failed! rc = %d\n", __func__, rc);
 	return rc;
 }
 
-static int32_t msm_eeprom_i2c_remove(struct i2c_client *client)
+static int msm_eeprom_i2c_remove(struct i2c_client *client)
 {
 	struct v4l2_subdev *sd = i2c_get_clientdata(client);
 	struct msm_eeprom_ctrl_t  *e_ctrl;
@@ -542,12 +542,12 @@
 		return 0;
 	}
 
-	kfree(e_ctrl->memory_data);
+	kfree(e_ctrl->cal_data.mapdata);
+	kfree(e_ctrl->cal_data.map);
 	if (e_ctrl->eboard_info) {
 		kfree(e_ctrl->eboard_info->power_info.gpio_conf);
-		kfree(e_ctrl->eboard_info->eeprom_map);
+		kfree(e_ctrl->eboard_info);
 	}
-	kfree(e_ctrl->eboard_info);
 	kfree(e_ctrl);
 	return 0;
 }
@@ -585,23 +585,133 @@
 	return 0;
 }
 
-static int msm_eeprom_check_id(struct msm_eeprom_ctrl_t *e_ctrl)
+static int msm_eeprom_match_id(struct msm_eeprom_ctrl_t *e_ctrl)
 {
 	int rc;
 	struct msm_camera_i2c_client *client = &e_ctrl->i2c_client;
 	uint8_t id[2];
 
 	rc = msm_camera_spi_query_id(client, 0, &id[0], 2);
-	if (rc)
+	if (rc < 0)
 		return rc;
+	CDBG("%s: read 0x%x 0x%x, check 0x%x 0x%x\n", __func__, id[0],
+	     id[1], client->spi_client->mfr_id, client->spi_client->device_id);
 	if (id[0] != client->spi_client->mfr_id
-		    || id[1] != client->spi_client->device_id) {
-		CDBG("%s: read 0x%x 0x%x, check 0x%x 0x%x\n", __func__, id[0],
-		     id[1], client->spi_client->mfr_id,
-		     client->spi_client->device_id);
+		    || id[1] != client->spi_client->device_id)
 		return -ENODEV;
+
+	return 0;
+}
+
+static int msm_eeprom_get_dt_data(struct msm_eeprom_ctrl_t *e_ctrl)
+{
+	int rc = 0, i = 0;
+	struct msm_eeprom_board_info *eb_info;
+	struct msm_camera_power_ctrl_t *power_info =
+		&e_ctrl->eboard_info->power_info;
+	struct device_node *of_node = NULL;
+	struct msm_camera_gpio_conf *gconf = NULL;
+	uint16_t gpio_array_size = 0;
+	uint16_t *gpio_array = NULL;
+
+	eb_info = e_ctrl->eboard_info;
+	if (e_ctrl->eeprom_device_type == MSM_CAMERA_SPI_DEVICE)
+		of_node = e_ctrl->i2c_client.
+			spi_client->spi_master->dev.of_node;
+	else if (e_ctrl->eeprom_device_type == MSM_CAMERA_PLATFORM_DEVICE)
+		of_node = e_ctrl->pdev->dev.of_node;
+
+	rc = msm_camera_get_dt_vreg_data(of_node, &power_info->cam_vreg,
+					     &power_info->num_vreg);
+	if (rc < 0)
+		return rc;
+
+	rc = msm_camera_get_dt_power_setting_data(of_node,
+		power_info->cam_vreg, power_info->num_vreg,
+		power_info);
+	if (rc < 0)
+		goto ERROR1;
+
+	power_info->gpio_conf = kzalloc(sizeof(struct msm_camera_gpio_conf),
+					GFP_KERNEL);
+	if (!power_info->gpio_conf) {
+		rc = -ENOMEM;
+		goto ERROR2;
+	}
+	gconf = power_info->gpio_conf;
+	gpio_array_size = of_gpio_count(of_node);
+	CDBG("%s gpio count %d\n", __func__, gpio_array_size);
+
+	if (gpio_array_size) {
+		gpio_array = kzalloc(sizeof(uint16_t) * gpio_array_size,
+			GFP_KERNEL);
+		if (!gpio_array) {
+			pr_err("%s failed %d\n", __func__, __LINE__);
+			goto ERROR3;
+		}
+		for (i = 0; i < gpio_array_size; i++) {
+			gpio_array[i] = of_get_gpio(of_node, i);
+			CDBG("%s gpio_array[%d] = %d\n", __func__, i,
+				gpio_array[i]);
+		}
+
+		rc = msm_camera_get_dt_gpio_req_tbl(of_node, gconf,
+			gpio_array, gpio_array_size);
+		if (rc < 0) {
+			pr_err("%s failed %d\n", __func__, __LINE__);
+			goto ERROR4;
+		}
+
+		rc = msm_camera_init_gpio_pin_tbl(of_node, gconf,
+			gpio_array, gpio_array_size);
+		if (rc < 0) {
+			pr_err("%s failed %d\n", __func__, __LINE__);
+			goto ERROR4;
+		}
+		kfree(gpio_array);
 	}
 
+	return rc;
+ERROR4:
+	kfree(gpio_array);
+ERROR3:
+	kfree(power_info->gpio_conf);
+ERROR2:
+	kfree(power_info->cam_vreg);
+ERROR1:
+	kfree(power_info->power_setting);
+	return rc;
+}
+
+static int msm_eeprom_mm_dts(struct msm_eeprom_board_info *eb_info,
+				struct device_node *of_node)
+{
+	int rc = 0;
+	struct msm_eeprom_mm_t *mm_data = &eb_info->mm_data;
+
+	mm_data->mm_support =
+		of_property_read_bool(of_node,"qcom,mm-data-support");
+	if (!mm_data->mm_support)
+		return -EINVAL;
+	mm_data->mm_compression =
+		of_property_read_bool(of_node,"qcom,mm-data-compressed");
+	if (!mm_data->mm_compression)
+		pr_err("No MM compression data\n");
+
+	rc = of_property_read_u32(of_node, "qcom,mm-data-offset",
+				  &mm_data->mm_offset);
+	if (rc < 0)
+		pr_err("No MM offset data\n");
+
+	rc = of_property_read_u32(of_node, "qcom,mm-data-size",
+				  &mm_data->mm_size);
+	if (rc < 0)
+		pr_err("No MM size data\n");
+
+	CDBG("mm_support: mm_compr %d, mm_offset %d, mm_size %d\n",
+		mm_data->mm_compression,
+		mm_data->mm_offset,
+		mm_data->mm_size);
 	return 0;
 }
 
@@ -614,7 +724,7 @@
 	struct msm_camera_power_ctrl_t *power_info = NULL;
 	int rc = 0;
 
-	e_ctrl = kzalloc(sizeof(struct msm_eeprom_ctrl_t), GFP_KERNEL);
+	e_ctrl = kzalloc(sizeof(*e_ctrl), GFP_KERNEL);
 	if (!e_ctrl) {
 		pr_err("%s:%d kzalloc failed\n", __func__, __LINE__);
 		return -ENOMEM;
@@ -624,7 +734,7 @@
 	client = &e_ctrl->i2c_client;
 	e_ctrl->is_supported = 0;
 
-	spi_client = kzalloc(sizeof(spi_client), GFP_KERNEL);
+	spi_client = kzalloc(sizeof(*spi_client), GFP_KERNEL);
 	if (!spi_client) {
 		pr_err("%s:%d kzalloc failed\n", __func__, __LINE__);
 		kfree(e_ctrl);
@@ -634,7 +744,7 @@
 	rc = of_property_read_u32(spi->dev.of_node, "cell-index",
 				  &e_ctrl->subdev_id);
 	CDBG("cell-index %d, rc %d\n", e_ctrl->subdev_id, rc);
-	if (rc) {
+	if (rc < 0) {
 		pr_err("failed rc %d\n", rc);
 		return rc;
 	}
@@ -645,7 +755,7 @@
 	client->i2c_func_tbl = &msm_eeprom_spi_func_tbl;
 	client->addr_type = MSM_CAMERA_I2C_3B_ADDR;
 
-	eb_info = kzalloc(sizeof(eb_info), GFP_KERNEL);
+	eb_info = kzalloc(sizeof(*eb_info), GFP_KERNEL);
 	if (!eb_info)
 		goto spi_free;
 	e_ctrl->eboard_info = eb_info;
@@ -657,6 +767,12 @@
 		pr_err("%s failed %d\n", __func__, __LINE__);
 		goto board_free;
 	}
+
+        rc = msm_eeprom_mm_dts(e_ctrl->eboard_info, spi->dev.of_node);
+	if (rc < 0) {
+		pr_err("%s MM data miss:%d\n", __func__, __LINE__);
+	}
+
 	power_info = &eb_info->power_info;
 
 	power_info->clk_info = cam_8974_clk_info;
@@ -664,48 +780,56 @@
 	power_info->dev = &spi->dev;
 
 	rc = msm_eeprom_get_dt_data(e_ctrl);
-	if (rc)
+	if (rc < 0)
 		goto board_free;
 
 	/* set spi instruction info */
 	spi_client->retry_delay = 1;
 	spi_client->retries = 0;
 
-	if (msm_eeprom_spi_parse_of(spi_client)) {
+	rc = msm_eeprom_spi_parse_of(spi_client);
+	if (rc < 0) {
 		dev_err(&spi->dev,
 			"%s: Error parsing device properties\n", __func__);
 		goto board_free;
 	}
 
-	rc = msm_eeprom_alloc_memory_map(e_ctrl, spi->dev.of_node);
-	if (rc)
-		goto board_free;
+	/* prepare memory buffer */
+	rc = msm_eeprom_parse_memory_map(spi->dev.of_node,
+					 &e_ctrl->cal_data);
+	if (rc < 0)
+		CDBG("%s: no cal memory map\n", __func__);
 
+	/* power up eeprom for reading */
 	rc = msm_camera_power_up(power_info, e_ctrl->eeprom_device_type,
 		&e_ctrl->i2c_client);
-	if (rc) {
+	if (rc < 0) {
 		pr_err("failed rc %d\n", rc);
-		goto memmap_free;
+		goto caldata_free;
 	}
 
 	/* check eeprom id */
-	rc = msm_eeprom_check_id(e_ctrl);
-	if (rc) {
+	rc = msm_eeprom_match_id(e_ctrl);
+	if (rc < 0) {
 		CDBG("%s: eeprom not matching %d\n", __func__, rc);
 		goto power_down;
 	}
 	/* read eeprom */
-	rc = read_eeprom_memory(e_ctrl);
-	if (rc) {
-		dev_err(&spi->dev, "%s: read eeprom memory failed\n", __func__);
-		goto power_down;
+	if (e_ctrl->cal_data.map) {
+		rc = read_eeprom_memory(e_ctrl, &e_ctrl->cal_data);
+		if (rc < 0) {
+			pr_err("%s: read cal data failed\n", __func__);
+			goto power_down;
+		}
+		e_ctrl->is_supported |= msm_eeprom_match_crc(
+						&e_ctrl->cal_data);
 	}
 
 	rc = msm_camera_power_down(power_info, e_ctrl->eeprom_device_type,
 		&e_ctrl->i2c_client);
-	if (rc) {
+	if (rc < 0) {
 		pr_err("failed rc %d\n", rc);
-		goto memmap_free;
+		goto caldata_free;
 	}
 
 	/* initiazlie subdev */
@@ -719,21 +843,23 @@
 	e_ctrl->msm_sd.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV;
 	e_ctrl->msm_sd.sd.entity.group_id = MSM_CAMERA_SUBDEV_EEPROM;
 	msm_sd_register(&e_ctrl->msm_sd);
-	e_ctrl->is_supported = 1;
-	CDBG("%s success result=%d X\n", __func__, rc);
+	e_ctrl->is_supported = (e_ctrl->is_supported << 1) | 1;
+	CDBG("%s success result=%d supported=%x X\n", __func__, rc,
+	     e_ctrl->is_supported);
 
 	return 0;
 
 power_down:
 	msm_camera_power_down(power_info, e_ctrl->eeprom_device_type,
 		&e_ctrl->i2c_client);
-memmap_free:
-	kfree(e_ctrl->eboard_info->eeprom_map);
-	kfree(e_ctrl->memory_data);
+caldata_free:
+	kfree(e_ctrl->cal_data.mapdata);
+	kfree(e_ctrl->cal_data.map);
 board_free:
 	kfree(e_ctrl->eboard_info);
 spi_free:
 	kfree(spi_client);
+	kfree(e_ctrl);
 	return rc;
 }
 
@@ -751,14 +877,14 @@
 	cpha = (spi->mode & SPI_CPHA) ? 1 : 0;
 	cpol = (spi->mode & SPI_CPOL) ? 1 : 0;
 	cs_high = (spi->mode & SPI_CS_HIGH) ? 1 : 0;
-	dev_info(&spi->dev, "irq[%d] cs[%x] CPHA[%x] CPOL[%x] CS_HIGH[%x]\n",
-			irq, cs, cpha, cpol, cs_high);
-	dev_info(&spi->dev, "max_speed[%u]\n", spi->max_speed_hz);
+	CDBG("%s: irq[%d] cs[%x] CPHA[%x] CPOL[%x] CS_HIGH[%x]\n",
+			__func__, irq, cs, cpha, cpol, cs_high);
+	CDBG("%s: max_speed[%u]\n", __func__, spi->max_speed_hz);
 
 	return msm_eeprom_spi_setup(spi);
 }
 
-static int32_t msm_eeprom_spi_remove(struct spi_device *sdev)
+static int msm_eeprom_spi_remove(struct spi_device *sdev)
 {
 	struct v4l2_subdev *sd = spi_get_drvdata(sdev);
 	struct msm_eeprom_ctrl_t  *e_ctrl;
@@ -774,20 +900,20 @@
 	}
 
 	kfree(e_ctrl->i2c_client.spi_client);
-	kfree(e_ctrl->memory_data);
+	kfree(e_ctrl->cal_data.mapdata);
+	kfree(e_ctrl->cal_data.map);
 	if (e_ctrl->eboard_info) {
 		kfree(e_ctrl->eboard_info->power_info.gpio_conf);
-		kfree(e_ctrl->eboard_info->eeprom_map);
+		kfree(e_ctrl->eboard_info);
 	}
-	kfree(e_ctrl->eboard_info);
 	kfree(e_ctrl);
 	return 0;
 }
 
-static int32_t msm_eeprom_platform_probe(struct platform_device *pdev)
+static int msm_eeprom_platform_probe(struct platform_device *pdev)
 {
-	int32_t rc = 0;
-	int32_t j = 0;
+	int rc = 0;
+	int j = 0;
 	uint32_t temp;
 
 	struct msm_camera_cci_client *cci_client = NULL;
@@ -798,7 +924,7 @@
 
 	CDBG("%s E\n", __func__);
 
-	e_ctrl = kzalloc(sizeof(struct msm_eeprom_ctrl_t), GFP_KERNEL);
+	e_ctrl = kzalloc(sizeof(*e_ctrl), GFP_KERNEL);
 	if (!e_ctrl) {
 		pr_err("%s:%d kzalloc failed\n", __func__, __LINE__);
 		return -ENOMEM;
@@ -884,12 +1010,16 @@
 		goto board_free;
 	}
 
+        rc = msm_eeprom_mm_dts(e_ctrl->eboard_info, of_node);
+	if (rc < 0) {
+		pr_err("%s MM data miss:%d\n", __func__, __LINE__);
+	}
 	rc = msm_eeprom_get_dt_data(e_ctrl);
 	if (rc)
 		goto board_free;
 
-	rc = msm_eeprom_alloc_memory_map(e_ctrl, of_node);
-	if (rc)
+	rc = msm_eeprom_parse_memory_map(of_node, &e_ctrl->cal_data);
+	if (rc < 0)
 		goto board_free;
 
 	rc = msm_camera_power_up(power_info, e_ctrl->eeprom_device_type,
@@ -898,14 +1028,16 @@
 		pr_err("failed rc %d\n", rc);
 		goto memdata_free;
 	}
-	rc = read_eeprom_memory(e_ctrl);
+	rc = read_eeprom_memory(e_ctrl, &e_ctrl->cal_data);
 	if (rc < 0) {
 		pr_err("%s read_eeprom_memory failed\n", __func__);
 		goto power_down;
 	}
-		pr_err("%s line %d\n", __func__, __LINE__);
-	for (j = 0; j < e_ctrl->num_bytes; j++)
-		CDBG("memory_data[%d] = 0x%X\n", j, e_ctrl->memory_data[j]);
+	for (j = 0; j < e_ctrl->cal_data.num_data; j++)
+		CDBG("memory_data[%d] = 0x%X\n", j,
+		     e_ctrl->cal_data.mapdata[j]);
+
+	e_ctrl->is_supported |= msm_eeprom_match_crc(&e_ctrl->cal_data);
 
 	rc = msm_camera_power_down(power_info, e_ctrl->eeprom_device_type,
 		&e_ctrl->i2c_client);
@@ -926,8 +1058,7 @@
 	e_ctrl->msm_sd.sd.entity.group_id = MSM_CAMERA_SUBDEV_EEPROM;
 	msm_sd_register(&e_ctrl->msm_sd);
 
-
-	e_ctrl->is_supported = 1;
+	e_ctrl->is_supported = (e_ctrl->is_supported << 1) | 1;
 	CDBG("%s X\n", __func__);
 	return rc;
 
@@ -935,8 +1066,8 @@
 	msm_camera_power_down(power_info, e_ctrl->eeprom_device_type,
 		&e_ctrl->i2c_client);
 memdata_free:
-	kfree(e_ctrl->memory_data);
-	kfree(eb_info->eeprom_map);
+	kfree(e_ctrl->cal_data.mapdata);
+	kfree(e_ctrl->cal_data.map);
 board_free:
 	kfree(e_ctrl->eboard_info);
 cciclient_free:
@@ -945,7 +1076,7 @@
 	return rc;
 }
 
-static int32_t msm_eeprom_platform_remove(struct platform_device *pdev)
+static int msm_eeprom_platform_remove(struct platform_device *pdev)
 {
 	struct v4l2_subdev *sd = platform_get_drvdata(pdev);
 	struct msm_eeprom_ctrl_t  *e_ctrl;
@@ -961,12 +1092,12 @@
 	}
 
 	kfree(e_ctrl->i2c_client.cci_client);
-	kfree(e_ctrl->memory_data);
+	kfree(e_ctrl->cal_data.mapdata);
+	kfree(e_ctrl->cal_data.map);
 	if (e_ctrl->eboard_info) {
 		kfree(e_ctrl->eboard_info->power_info.gpio_conf);
-		kfree(e_ctrl->eboard_info->eeprom_map);
+		kfree(e_ctrl->eboard_info);
 	}
-	kfree(e_ctrl->eboard_info);
 	kfree(e_ctrl);
 	return 0;
 }
@@ -1013,7 +1144,7 @@
 
 static int __init msm_eeprom_init_module(void)
 {
-	int32_t rc = 0;
+	int rc = 0;
 	CDBG("%s E\n", __func__);
 	rc = platform_driver_probe(&msm_eeprom_platform_driver,
 		msm_eeprom_platform_probe);
diff --git a/drivers/media/platform/msm/camera_v2/sensor/eeprom/msm_eeprom.h b/drivers/media/platform/msm/camera_v2/sensor/eeprom/msm_eeprom.h
index cebe585..e978824 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/eeprom/msm_eeprom.h
+++ b/drivers/media/platform/msm/camera_v2/sensor/eeprom/msm_eeprom.h
@@ -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
@@ -27,6 +27,8 @@
 #define DEFINE_MSM_MUTEX(mutexname) \
 	static struct mutex mutexname = __MUTEX_INITIALIZER(mutexname)
 
+#define PROPERTY_MAXSIZE 32
+
 struct msm_eeprom_ctrl_t {
 	struct platform_device *pdev;
 	struct mutex *eeprom_mutex;
@@ -38,8 +40,7 @@
 	enum cci_i2c_master_t cci_master;
 
 	struct msm_camera_i2c_client i2c_client;
-	uint32_t num_bytes;
-	uint8_t *memory_data;
+	struct msm_eeprom_memory_block_t cal_data;
 	uint8_t is_supported;
 	struct msm_eeprom_board_info *eboard_info;
 	uint32_t subdev_id;
diff --git a/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_flash.c b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_flash.c
index 2de17c9..149d00c 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_flash.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_flash.c
@@ -46,7 +46,7 @@
 		*(int *)argp = MSM_CAMERA_LED_RELEASE;
 		return fctrl->func_tbl->flash_led_config(fctrl, argp);
 	default:
-		pr_err("invalid cmd %d\n", cmd);
+		pr_err_ratelimited("invalid cmd %d\n", cmd);
 		return -ENOIOCTLCMD;
 	}
 }
diff --git a/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_flash.h b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_flash.h
index a4d7f15..87b65ca 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_flash.h
+++ b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_flash.h
@@ -15,6 +15,7 @@
 
 #include <linux/leds.h>
 #include <linux/platform_device.h>
+#include <linux/ratelimit.h>
 #include <media/v4l2-subdev.h>
 #include <media/msm_cam_sensor.h>
 #include <mach/camera2.h>
diff --git a/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_i2c_trigger.c b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_i2c_trigger.c
index 9caa270..9cfab8f 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_i2c_trigger.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_i2c_trigger.c
@@ -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
@@ -95,27 +95,30 @@
 {
 	int rc = 0;
 	struct msm_camera_sensor_board_info *flashdata = NULL;
+	struct msm_camera_power_ctrl_t *power_info = NULL;
 	CDBG("%s:%d called\n", __func__, __LINE__);
 
 	flashdata = fctrl->flashdata;
-	if (flashdata->gpio_conf->cam_gpiomux_conf_tbl != NULL) {
+	power_info = &flashdata->power_info;
+	if (power_info->gpio_conf->cam_gpiomux_conf_tbl != NULL) {
 		pr_err("%s:%d mux install\n", __func__, __LINE__);
 		msm_gpiomux_install(
 			(struct msm_gpiomux_config *)
-			flashdata->gpio_conf->cam_gpiomux_conf_tbl,
-			flashdata->gpio_conf->cam_gpiomux_conf_tbl_size);
+			power_info->gpio_conf->cam_gpiomux_conf_tbl,
+			power_info->gpio_conf->cam_gpiomux_conf_tbl_size);
 	}
 
 	rc = msm_camera_request_gpio_table(
-		flashdata->gpio_conf->cam_gpio_req_tbl,
-		flashdata->gpio_conf->cam_gpio_req_tbl_size, 1);
+		power_info->gpio_conf->cam_gpio_req_tbl,
+		power_info->gpio_conf->cam_gpio_req_tbl_size, 1);
 	if (rc < 0) {
 		pr_err("%s: request gpio failed\n", __func__);
 		return rc;
 	}
 	msleep(20);
 	gpio_set_value_cansleep(
-		flashdata->gpio_conf->gpio_num_info->gpio_num[0],
+		power_info->gpio_conf->gpio_num_info->
+		gpio_num[SENSOR_GPIO_FL_EN],
 		GPIO_OUT_HIGH);
 
 	if (fctrl->flash_i2c_client && fctrl->reg_setting) {
@@ -133,22 +136,26 @@
 {
 	int rc = 0;
 	struct msm_camera_sensor_board_info *flashdata = NULL;
+	struct msm_camera_power_ctrl_t *power_info = NULL;
 
 	flashdata = fctrl->flashdata;
+	power_info = &flashdata->power_info;
 	CDBG("%s:%d called\n", __func__, __LINE__);
 	if (!fctrl) {
 		pr_err("%s:%d fctrl NULL\n", __func__, __LINE__);
 		return -EINVAL;
 	}
 	gpio_set_value_cansleep(
-		flashdata->gpio_conf->gpio_num_info->gpio_num[0],
+		power_info->gpio_conf->gpio_num_info->
+		gpio_num[SENSOR_GPIO_FL_EN],
 		GPIO_OUT_LOW);
 	gpio_set_value_cansleep(
-		flashdata->gpio_conf->gpio_num_info->gpio_num[1],
+		power_info->gpio_conf->gpio_num_info->
+		gpio_num[SENSOR_GPIO_FL_NOW],
 		GPIO_OUT_LOW);
 	rc = msm_camera_request_gpio_table(
-		flashdata->gpio_conf->cam_gpio_req_tbl,
-		flashdata->gpio_conf->cam_gpio_req_tbl_size, 0);
+		power_info->gpio_conf->cam_gpio_req_tbl,
+		power_info->gpio_conf->cam_gpio_req_tbl_size, 0);
 	if (rc < 0) {
 		pr_err("%s: request gpio failed\n", __func__);
 		return rc;
@@ -160,8 +167,10 @@
 {
 	int rc = 0;
 	struct msm_camera_sensor_board_info *flashdata = NULL;
+	struct msm_camera_power_ctrl_t *power_info = NULL;
 
 	flashdata = fctrl->flashdata;
+	power_info = &flashdata->power_info;
 	CDBG("%s:%d called\n", __func__, __LINE__);
 	if (!fctrl) {
 		pr_err("%s:%d fctrl NULL\n", __func__, __LINE__);
@@ -175,7 +184,8 @@
 			pr_err("%s:%d failed\n", __func__, __LINE__);
 	}
 	gpio_set_value_cansleep(
-		flashdata->gpio_conf->gpio_num_info->gpio_num[1],
+		power_info->gpio_conf->gpio_num_info->
+		gpio_num[SENSOR_GPIO_FL_NOW],
 		GPIO_OUT_LOW);
 
 	return rc;
@@ -185,15 +195,19 @@
 {
 	int rc = 0;
 	struct msm_camera_sensor_board_info *flashdata = NULL;
+	struct msm_camera_power_ctrl_t *power_info = NULL;
 	CDBG("%s:%d called\n", __func__, __LINE__);
 
 	flashdata = fctrl->flashdata;
+	power_info = &flashdata->power_info;
 	gpio_set_value_cansleep(
-		flashdata->gpio_conf->gpio_num_info->gpio_num[0],
+		power_info->gpio_conf->gpio_num_info->
+		gpio_num[SENSOR_GPIO_FL_EN],
 		GPIO_OUT_HIGH);
 
 	gpio_set_value_cansleep(
-		flashdata->gpio_conf->gpio_num_info->gpio_num[1],
+		power_info->gpio_conf->gpio_num_info->
+		gpio_num[SENSOR_GPIO_FL_NOW],
 		GPIO_OUT_HIGH);
 
 
@@ -212,15 +226,19 @@
 {
 	int rc = 0;
 	struct msm_camera_sensor_board_info *flashdata = NULL;
+	struct msm_camera_power_ctrl_t *power_info = NULL;
 	CDBG("%s:%d called\n", __func__, __LINE__);
 
 	flashdata = fctrl->flashdata;
+	power_info = &flashdata->power_info;
 	gpio_set_value_cansleep(
-		flashdata->gpio_conf->gpio_num_info->gpio_num[0],
+		power_info->gpio_conf->gpio_num_info->
+		gpio_num[SENSOR_GPIO_FL_EN],
 		GPIO_OUT_HIGH);
 
 	gpio_set_value_cansleep(
-		flashdata->gpio_conf->gpio_num_info->gpio_num[1],
+		power_info->gpio_conf->gpio_num_info->
+		gpio_num[SENSOR_GPIO_FL_NOW],
 		GPIO_OUT_HIGH);
 
 	if (fctrl->flash_i2c_client && fctrl->reg_setting) {
@@ -234,61 +252,6 @@
 	return rc;
 }
 
-static int32_t msm_flash_init_gpio_pin_tbl(struct device_node *of_node,
-	struct msm_camera_gpio_conf *gconf, uint16_t *gpio_array,
-	uint16_t gpio_array_size)
-{
-	int32_t rc = 0;
-	int32_t val = 0;
-
-	gconf->gpio_num_info = kzalloc(sizeof(struct msm_camera_gpio_num_info),
-		GFP_KERNEL);
-	if (!gconf->gpio_num_info) {
-		pr_err("%s failed %d\n", __func__, __LINE__);
-		rc = -ENOMEM;
-		return rc;
-	}
-
-	rc = of_property_read_u32(of_node, "qcom,gpio-flash-en", &val);
-	if (rc < 0) {
-		pr_err("%s:%d read qcom,gpio-flash-en failed rc %d\n",
-			__func__, __LINE__, rc);
-		goto ERROR;
-	} else if (val >= gpio_array_size) {
-		pr_err("%s:%d qcom,gpio-flash-en invalid %d\n",
-			__func__, __LINE__, val);
-		goto ERROR;
-	}
-	/*index 0 is for qcom,gpio-flash-en */
-	gconf->gpio_num_info->gpio_num[0] =
-		gpio_array[val];
-	CDBG("%s qcom,gpio-flash-en %d\n", __func__,
-		gconf->gpio_num_info->gpio_num[0]);
-
-	rc = of_property_read_u32(of_node, "qcom,gpio-flash-now", &val);
-	if (rc < 0) {
-		pr_err("%s:%d read qcom,gpio-flash-now failed rc %d\n",
-			__func__, __LINE__, rc);
-		goto ERROR;
-	} else if (val >= gpio_array_size) {
-		pr_err("%s:%d qcom,gpio-flash-now invalid %d\n",
-			__func__, __LINE__, val);
-		goto ERROR;
-	}
-	/*index 1 is for qcom,gpio-flash-now */
-	gconf->gpio_num_info->gpio_num[1] =
-		gpio_array[val];
-	CDBG("%s qcom,gpio-flash-now %d\n", __func__,
-		gconf->gpio_num_info->gpio_num[1]);
-
-	return rc;
-
-ERROR:
-	kfree(gconf->gpio_num_info);
-	gconf->gpio_num_info = NULL;
-	return rc;
-}
-
 static int32_t msm_led_get_dt_data(struct device_node *of_node,
 		struct msm_led_flash_ctrl_t *fctrl)
 {
@@ -296,6 +259,7 @@
 	struct msm_camera_gpio_conf *gconf = NULL;
 	struct device_node *flash_src_node = NULL;
 	struct msm_camera_sensor_board_info *flashdata = NULL;
+	struct msm_camera_power_ctrl_t *power_info = NULL;
 	uint32_t count = 0;
 	uint16_t *gpio_array = NULL;
 	uint16_t gpio_array_size = 0;
@@ -317,13 +281,7 @@
 	}
 
 	flashdata = fctrl->flashdata;
-
-	flashdata->sensor_init_params = kzalloc(sizeof(
-		struct msm_sensor_init_params), GFP_KERNEL);
-	if (!flashdata->sensor_init_params) {
-		pr_err("%s failed %d\n", __func__, __LINE__);
-		return -ENOMEM;
-	}
+	power_info = &flashdata->power_info;
 
 	rc = of_property_read_u32(of_node, "cell-index", &fctrl->subdev_id);
 	if (rc < 0) {
@@ -389,15 +347,15 @@
 		}
 
 	} else { /*Handle LED Flash Ctrl by GPIO*/
-		flashdata->gpio_conf =
+		power_info->gpio_conf =
 			 kzalloc(sizeof(struct msm_camera_gpio_conf),
 				 GFP_KERNEL);
-		if (!flashdata->gpio_conf) {
+		if (!power_info->gpio_conf) {
 			pr_err("%s failed %d\n", __func__, __LINE__);
 			rc = -ENOMEM;
 			return rc;
 		}
-		gconf = flashdata->gpio_conf;
+		gconf = power_info->gpio_conf;
 
 		gpio_array_size = of_gpio_count(of_node);
 		CDBG("%s gpio count %d\n", __func__, gpio_array_size);
@@ -416,21 +374,21 @@
 					gpio_array[i]);
 			}
 
-			rc = msm_sensor_get_dt_gpio_req_tbl(of_node, gconf,
+			rc = msm_camera_get_dt_gpio_req_tbl(of_node, gconf,
 				gpio_array, gpio_array_size);
 			if (rc < 0) {
 				pr_err("%s failed %d\n", __func__, __LINE__);
 				goto ERROR4;
 			}
 
-			rc = msm_sensor_get_dt_gpio_set_tbl(of_node, gconf,
+			rc = msm_camera_get_dt_gpio_set_tbl(of_node, gconf,
 				gpio_array, gpio_array_size);
 			if (rc < 0) {
 				pr_err("%s failed %d\n", __func__, __LINE__);
 				goto ERROR5;
 			}
 
-			rc = msm_flash_init_gpio_pin_tbl(of_node, gconf,
+			rc = msm_camera_init_gpio_pin_tbl(of_node, gconf,
 				gpio_array, gpio_array_size);
 			if (rc < 0) {
 				pr_err("%s failed %d\n", __func__, __LINE__);
@@ -462,7 +420,7 @@
 ERROR9:
 		kfree(fctrl->flashdata->slave_info);
 ERROR8:
-		kfree(fctrl->flashdata->gpio_conf->gpio_num_info);
+		kfree(fctrl->flashdata->power_info.gpio_conf->gpio_num_info);
 ERROR6:
 		kfree(gconf->cam_gpio_set_tbl);
 ERROR5:
diff --git a/drivers/media/platform/msm/camera_v2/sensor/gc0339.c b/drivers/media/platform/msm/camera_v2/sensor/gc0339.c
index 8288ad0..36f3b61 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/gc0339.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/gc0339.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
@@ -120,21 +120,23 @@
 	struct msm_sensor_power_setting_array *power_setting_array = NULL;
 	struct msm_sensor_power_setting *power_setting = NULL;
 	struct msm_camera_sensor_board_info *data = s_ctrl->sensordata;
+	struct msm_camera_power_ctrl_t *power_info = &data->power_info;
+	struct msm_camera_gpio_conf *gpio_conf = power_info->gpio_conf;
 
 	CDBG("%s:%d\n", __func__, __LINE__);
 	power_setting_array = &s_ctrl->power_setting_array;
 
-	if (data->gpio_conf->cam_gpiomux_conf_tbl != NULL) {
+	if (gpio_conf->cam_gpiomux_conf_tbl != NULL) {
 		pr_err("%s:%d mux install\n", __func__, __LINE__);
 		msm_gpiomux_install(
 			(struct msm_gpiomux_config *)
-			data->gpio_conf->cam_gpiomux_conf_tbl,
-			data->gpio_conf->cam_gpiomux_conf_tbl_size);
+			gpio_conf->cam_gpiomux_conf_tbl,
+			gpio_conf->cam_gpiomux_conf_tbl_size);
 	}
 
 	rc = msm_camera_request_gpio_table(
-		data->gpio_conf->cam_gpio_req_tbl,
-		data->gpio_conf->cam_gpio_req_tbl_size, 1);
+		gpio_conf->cam_gpio_req_tbl,
+		gpio_conf->cam_gpio_req_tbl_size, 1);
 	if (rc < 0) {
 		pr_err("%s: request gpio failed\n", __func__);
 		return rc;
@@ -145,20 +147,21 @@
 		CDBG("%s type %d\n", __func__, power_setting->seq_type);
 		switch (power_setting->seq_type) {
 		case SENSOR_CLK:
-			if (power_setting->seq_val >= s_ctrl->clk_info_size) {
+			if (power_setting->seq_val >=
+					power_info->clk_info_size) {
 				pr_err("%s clk index %d >= max %d\n", __func__,
 					power_setting->seq_val,
-					s_ctrl->clk_info_size);
+					power_info->clk_info_size);
 				goto power_up_failed;
 			}
 			if (power_setting->config_val)
-				s_ctrl->clk_info[power_setting->seq_val].
+				power_info->clk_info[power_setting->seq_val].
 					clk_rate = power_setting->config_val;
 
-			rc = msm_cam_clk_enable(s_ctrl->dev,
-				&s_ctrl->clk_info[0],
+			rc = msm_cam_clk_enable(power_info->dev,
+				&power_info->clk_info[0],
 				(struct clk **)&power_setting->data[0],
-				s_ctrl->clk_info_size,
+				power_info->clk_info_size,
 				1);
 			if (rc < 0) {
 				pr_err("%s: clk enable failed\n",
@@ -168,19 +171,19 @@
 			break;
 		case SENSOR_GPIO:
 			if (power_setting->seq_val >= SENSOR_GPIO_MAX ||
-				!data->gpio_conf->gpio_num_info) {
+				!gpio_conf->gpio_num_info) {
 				pr_err("%s gpio index %d >= max %d\n", __func__,
 					power_setting->seq_val,
 					SENSOR_GPIO_MAX);
 				goto power_up_failed;
 			}
 			pr_debug("%s:%d gpio set val %d\n", __func__, __LINE__,
-				data->gpio_conf->gpio_num_info->gpio_num
+				gpio_conf->gpio_num_info->gpio_num
 				[power_setting->seq_val]);
-			if (data->gpio_conf->gpio_num_info->gpio_num
+			if (gpio_conf->gpio_num_info->gpio_num
 				[power_setting->seq_val])
 				gpio_set_value_cansleep(
-					data->gpio_conf->gpio_num_info->gpio_num
+					gpio_conf->gpio_num_info->gpio_num
 					[power_setting->seq_val],
 					power_setting->config_val);
 			break;
@@ -191,8 +194,8 @@
 					SENSOR_GPIO_MAX);
 				goto power_up_failed;
 			}
-			msm_camera_config_single_vreg(s_ctrl->dev,
-				&data->cam_vreg[power_setting->seq_val],
+			msm_camera_config_single_vreg(power_info->dev,
+				&power_info->cam_vreg[power_setting->seq_val],
 				(struct regulator **)&power_setting->data[0],
 				1);
 			break;
@@ -247,23 +250,23 @@
 		CDBG("%s type %d\n", __func__, power_setting->seq_type);
 		switch (power_setting->seq_type) {
 		case SENSOR_CLK:
-			msm_cam_clk_enable(s_ctrl->dev,
-				&s_ctrl->clk_info[0],
+			msm_cam_clk_enable(power_info->dev,
+				&power_info->clk_info[0],
 				(struct clk **)&power_setting->data[0],
-				s_ctrl->clk_info_size,
+				power_info->clk_info_size,
 				0);
 			break;
 		case SENSOR_GPIO:
-			if (data->gpio_conf->gpio_num_info->gpio_num
+			if (gpio_conf->gpio_num_info->gpio_num
 				[power_setting->seq_val])
 				gpio_set_value_cansleep(
-					data->gpio_conf->gpio_num_info->gpio_num
+					gpio_conf->gpio_num_info->gpio_num
 					[power_setting->seq_val],
 					GPIOF_OUT_INIT_LOW);
 			break;
 		case SENSOR_VREG:
-			msm_camera_config_single_vreg(s_ctrl->dev,
-				&data->cam_vreg[power_setting->seq_val],
+			msm_camera_config_single_vreg(power_info->dev,
+				&power_info->cam_vreg[power_setting->seq_val],
 				(struct regulator **)&power_setting->data[0],
 				0);
 			break;
@@ -280,8 +283,8 @@
 		}
 	}
 	msm_camera_request_gpio_table(
-		data->gpio_conf->cam_gpio_req_tbl,
-		data->gpio_conf->cam_gpio_req_tbl_size, 0);
+		gpio_conf->cam_gpio_req_tbl,
+		gpio_conf->cam_gpio_req_tbl_size, 0);
 	return rc;
 }
 
@@ -291,6 +294,8 @@
 	struct msm_sensor_power_setting_array *power_setting_array = NULL;
 	struct msm_sensor_power_setting *power_setting = NULL;
 	struct msm_camera_sensor_board_info *data = s_ctrl->sensordata;
+	struct msm_camera_power_ctrl_t *power_info = &data->power_info;
+	struct msm_camera_gpio_conf *gpio_conf = power_info->gpio_conf;
 
 	CDBG("%s:%d\n", __func__, __LINE__);
 	power_setting_array = &s_ctrl->power_setting_array;
@@ -311,24 +316,24 @@
 		CDBG("%s type %d\n", __func__, power_setting->seq_type);
 		switch (power_setting->seq_type) {
 		case SENSOR_CLK:
-			msm_cam_clk_enable(s_ctrl->dev,
-				&s_ctrl->clk_info[0],
+			msm_cam_clk_enable(power_info->dev,
+				&power_info->clk_info[0],
 				(struct clk **)&power_setting->data[0],
-				s_ctrl->clk_info_size,
+				power_info->clk_info_size,
 				0);
 			break;
 		case SENSOR_GPIO:
 			if (power_setting->seq_val >= SENSOR_GPIO_MAX ||
-				!data->gpio_conf->gpio_num_info) {
+				!gpio_conf->gpio_num_info) {
 				pr_err("%s gpio index %d >= max %d\n", __func__,
 					power_setting->seq_val,
 					SENSOR_GPIO_MAX);
 				continue;
 			}
-			if (data->gpio_conf->gpio_num_info->gpio_num
+			if (gpio_conf->gpio_num_info->gpio_num
 				[power_setting->seq_val])
 				gpio_set_value_cansleep(
-					data->gpio_conf->gpio_num_info->gpio_num
+					gpio_conf->gpio_num_info->gpio_num
 					[power_setting->seq_val],
 					GPIOF_OUT_INIT_LOW);
 			break;
@@ -339,8 +344,8 @@
 					SENSOR_GPIO_MAX);
 				continue;
 			}
-			msm_camera_config_single_vreg(s_ctrl->dev,
-				&data->cam_vreg[power_setting->seq_val],
+			msm_camera_config_single_vreg(power_info->dev,
+				&power_info->cam_vreg[power_setting->seq_val],
 				(struct regulator **)&power_setting->data[0],
 				0);
 			break;
@@ -357,8 +362,8 @@
 		}
 	}
 	msm_camera_request_gpio_table(
-		data->gpio_conf->cam_gpio_req_tbl,
-		data->gpio_conf->cam_gpio_req_tbl_size, 0);
+		gpio_conf->cam_gpio_req_tbl,
+		gpio_conf->cam_gpio_req_tbl_size, 0);
 	CDBG("%s exit\n", __func__);
 	return 0;
 }
@@ -402,6 +407,10 @@
 		for (i = 0; i < SUB_MODULE_MAX; i++)
 			cdata->cfg.sensor_info.subdev_id[i] =
 				s_ctrl->sensordata->sensor_info->subdev_id[i];
+		cdata->cfg.sensor_info.is_mount_angle_valid =
+			s_ctrl->sensordata->sensor_info->is_mount_angle_valid;
+		cdata->cfg.sensor_info.sensor_mount_angle =
+			s_ctrl->sensordata->sensor_info->sensor_mount_angle;
 		CDBG("%s:%d sensor name %s\n", __func__, __LINE__,
 			cdata->cfg.sensor_info.sensor_name);
 		CDBG("%s:%d session id %d\n", __func__, __LINE__,
@@ -409,11 +418,18 @@
 		for (i = 0; i < SUB_MODULE_MAX; i++)
 			CDBG("%s:%d subdev_id[%d] %d\n", __func__, __LINE__, i,
 				cdata->cfg.sensor_info.subdev_id[i]);
+		CDBG("%s:%d mount angle valid %d value %d\n", __func__,
+			__LINE__, cdata->cfg.sensor_info.is_mount_angle_valid,
+			cdata->cfg.sensor_info.sensor_mount_angle);
 
 		break;
 	case CFG_GET_SENSOR_INIT_PARAMS:
-		cdata->cfg.sensor_init_params =
-			*s_ctrl->sensordata->sensor_init_params;
+		cdata->cfg.sensor_init_params.modes_supported =
+			s_ctrl->sensordata->sensor_info->modes_supported;
+		cdata->cfg.sensor_init_params.position =
+			s_ctrl->sensordata->sensor_info->position;
+		cdata->cfg.sensor_init_params.sensor_mount_angle =
+			s_ctrl->sensordata->sensor_info->sensor_mount_angle;
 		CDBG("%s:%d init params mode %d pos %d mount %d\n", __func__,
 			__LINE__,
 			cdata->cfg.sensor_init_params.modes_supported,
@@ -462,7 +478,6 @@
 			rc = -EFAULT;
 			break;
 		}
-		s_ctrl->free_power_setting = true;
 		CDBG("%s sensor id %x\n", __func__,
 			sensor_slave_info.slave_addr);
 		CDBG("%s sensor addr type %d\n", __func__,
diff --git a/drivers/media/platform/msm/camera_v2/sensor/hi256.c b/drivers/media/platform/msm/camera_v2/sensor/hi256.c
index a10d60e..c7e0cb5 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/hi256.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/hi256.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
@@ -1781,6 +1781,10 @@
 		for (i = 0; i < SUB_MODULE_MAX; i++)
 			cdata->cfg.sensor_info.subdev_id[i] =
 				s_ctrl->sensordata->sensor_info->subdev_id[i];
+		cdata->cfg.sensor_info.is_mount_angle_valid =
+			s_ctrl->sensordata->sensor_info->is_mount_angle_valid;
+		cdata->cfg.sensor_info.sensor_mount_angle =
+			s_ctrl->sensordata->sensor_info->sensor_mount_angle;
 		CDBG("%s:%d sensor name %s\n", __func__, __LINE__,
 			cdata->cfg.sensor_info.sensor_name);
 		CDBG("%s:%d session id %d\n", __func__, __LINE__,
@@ -1788,6 +1792,10 @@
 		for (i = 0; i < SUB_MODULE_MAX; i++)
 			CDBG("%s:%d subdev_id[%d] %d\n", __func__, __LINE__, i,
 				cdata->cfg.sensor_info.subdev_id[i]);
+		CDBG("%s:%d mount angle valid %d value %d\n", __func__,
+			__LINE__, cdata->cfg.sensor_info.is_mount_angle_valid,
+			cdata->cfg.sensor_info.sensor_mount_angle);
+
 		break;
 	case CFG_SET_INIT_SETTING:
 		CDBG("init setting");
@@ -1823,8 +1831,12 @@
 			ARRAY_SIZE(hi256_start_settings));
 		break;
 	case CFG_GET_SENSOR_INIT_PARAMS:
-		cdata->cfg.sensor_init_params =
-			*s_ctrl->sensordata->sensor_init_params;
+		cdata->cfg.sensor_init_params.modes_supported =
+			s_ctrl->sensordata->sensor_info->modes_supported;
+		cdata->cfg.sensor_init_params.position =
+			s_ctrl->sensordata->sensor_info->position;
+		cdata->cfg.sensor_init_params.sensor_mount_angle =
+			s_ctrl->sensordata->sensor_info->sensor_mount_angle;
 		CDBG("%s:%d init params mode %d pos %d mount %d\n", __func__,
 			__LINE__,
 			cdata->cfg.sensor_init_params.modes_supported,
@@ -1874,7 +1886,6 @@
 			rc = -EFAULT;
 			break;
 		}
-		s_ctrl->free_power_setting = true;
 		CDBG("%s sensor id %x\n", __func__,
 			sensor_slave_info.slave_addr);
 		CDBG("%s sensor addr type %d\n", __func__,
diff --git a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_dt_util.c b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_dt_util.c
index 336c922..cc301ae 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_dt_util.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_dt_util.c
@@ -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
@@ -16,6 +16,7 @@
 #include "msm_camera_i2c_mux.h"
 #include "msm_cci.h"
 
+/*#define CONFIG_MSM_CAMERA_DT_DEBUG*/
 #undef CDBG
 #ifdef CONFIG_MSM_CAMERA_DT_DEBUG
 #define CDBG(fmt, args...) pr_err(fmt, ##args)
@@ -23,10 +24,330 @@
 #define CDBG(fmt, args...) do { } while (0)
 #endif
 
+int msm_camera_fill_vreg_params(struct camera_vreg_t *cam_vreg,
+	int num_vreg, struct msm_sensor_power_setting *power_setting,
+	uint16_t power_setting_size)
+{
+	uint16_t i = 0;
+	int      j = 0;
+
+	/* Validate input parameters */
+	if (!cam_vreg || !power_setting) {
+		pr_err("%s:%d failed: cam_vreg %p power_setting %p", __func__,
+			__LINE__,  cam_vreg, power_setting);
+		return -EINVAL;
+	}
+
+	/* Validate size of num_vreg */
+	if (num_vreg <= 0) {
+		pr_err("failed: num_vreg %d", num_vreg);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < power_setting_size; i++) {
+		if (power_setting[i].seq_type != SENSOR_VREG)
+			continue;
+
+		switch (power_setting[i].seq_val) {
+		case CAM_VDIG:
+			for (j = 0; j < num_vreg; j++) {
+				if (!strcmp(cam_vreg[j].reg_name, "cam_vdig")) {
+					pr_err("%s:%d i %d j %d cam_vdig\n",
+						__func__, __LINE__, i, j);
+					power_setting[i].seq_val = j;
+					break;
+				}
+			}
+			break;
+
+		case CAM_VIO:
+			for (j = 0; j < num_vreg; j++) {
+				if (!strcmp(cam_vreg[j].reg_name, "cam_vio")) {
+					pr_err("%s:%d i %d j %d cam_vio\n",
+						__func__, __LINE__, i, j);
+					power_setting[i].seq_val = j;
+					break;
+				}
+			}
+			break;
+
+		case CAM_VANA:
+			for (j = 0; j < num_vreg; j++) {
+				if (!strcmp(cam_vreg[j].reg_name, "cam_vana")) {
+					pr_err("%s:%d i %d j %d cam_vana\n",
+						__func__, __LINE__, i, j);
+					power_setting[i].seq_val = j;
+					break;
+				}
+			}
+			break;
+
+		case CAM_VAF:
+			for (j = 0; j < num_vreg; j++) {
+				if (!strcmp(cam_vreg[j].reg_name, "cam_vaf")) {
+					pr_err("%s:%d i %d j %d cam_vaf\n",
+						__func__, __LINE__, i, j);
+					power_setting[i].seq_val = j;
+					break;
+				}
+			}
+			break;
+
+		default:
+			pr_err("%s:%d invalid seq_val %d\n", __func__,
+				__LINE__, power_setting[i].seq_val);
+			break;
+		}
+	}
+
+	return 0;
+}
+
+int msm_sensor_get_sub_module_index(struct device_node *of_node,
+				    struct  msm_sensor_info_t **s_info)
+{
+	int rc = 0, i = 0;
+	uint32_t val = 0, count = 0;
+	uint32_t *val_array = NULL;
+	struct device_node *src_node = NULL;
+	struct msm_sensor_info_t *sensor_info;
+
+	sensor_info = kzalloc(sizeof(*sensor_info), GFP_KERNEL);
+	if (!sensor_info) {
+		pr_err("%s:%d failed\n", __func__, __LINE__);
+		return -ENOMEM;
+	}
+	for (i = 0; i < SUB_MODULE_MAX; i++)
+		sensor_info->subdev_id[i] = -1;
+
+	src_node = of_parse_phandle(of_node, "qcom,actuator-src", 0);
+	if (!src_node) {
+		CDBG("%s:%d src_node NULL\n", __func__, __LINE__);
+	} else {
+		rc = of_property_read_u32(src_node, "cell-index", &val);
+		CDBG("%s qcom,actuator cell index %d, rc %d\n", __func__,
+			val, rc);
+		if (rc < 0) {
+			pr_err("%s failed %d\n", __func__, __LINE__);
+			goto ERROR;
+		}
+		sensor_info->subdev_id[SUB_MODULE_ACTUATOR] = val;
+		of_node_put(src_node);
+		src_node = NULL;
+	}
+
+	src_node = of_parse_phandle(of_node, "qcom,eeprom-src", 0);
+	if (!src_node) {
+		CDBG("%s:%d eeprom src_node NULL\n", __func__, __LINE__);
+	} else {
+		rc = of_property_read_u32(src_node, "cell-index", &val);
+		CDBG("%s qcom,eeprom cell index %d, rc %d\n", __func__,
+			val, rc);
+		if (rc < 0) {
+			pr_err("%s failed %d\n", __func__, __LINE__);
+			goto ERROR;
+		}
+		sensor_info->subdev_id[SUB_MODULE_EEPROM] = val;
+		of_node_put(src_node);
+		src_node = NULL;
+	}
+
+	if (of_property_read_bool(of_node, "qcom,eeprom-sd-index") ==
+		true) {
+		rc = of_property_read_u32(of_node, "qcom,eeprom-sd-index",
+			&val);
+		CDBG("%s qcom,eeprom-sd-index %d, rc %d\n", __func__, val, rc);
+		if (rc < 0) {
+			pr_err("%s:%d failed rc %d\n", __func__, __LINE__, rc);
+			goto ERROR;
+		}
+		sensor_info->subdev_id[SUB_MODULE_EEPROM] = val;
+	}
+
+	src_node = of_parse_phandle(of_node, "qcom,led-flash-src", 0);
+	if (!src_node) {
+		CDBG("%s:%d src_node NULL\n", __func__, __LINE__);
+	} else {
+		rc = of_property_read_u32(src_node, "cell-index", &val);
+		CDBG("%s qcom,led flash cell index %d, rc %d\n", __func__,
+			val, rc);
+		if (rc < 0) {
+			pr_err("%s:%d failed %d\n", __func__, __LINE__, rc);
+			goto ERROR;
+		}
+		sensor_info->subdev_id[SUB_MODULE_LED_FLASH] = val;
+		of_node_put(src_node);
+		src_node = NULL;
+	}
+
+	if (of_property_read_bool(of_node, "qcom,strobe-flash-sd-index") ==
+		true) {
+		rc = of_property_read_u32(of_node, "qcom,strobe-flash-sd-index",
+			&val);
+		CDBG("%s qcom,strobe-flash-sd-index %d, rc %d\n", __func__,
+			val, rc);
+		if (rc < 0) {
+			pr_err("%s:%d failed rc %d\n", __func__, __LINE__, rc);
+			goto ERROR;
+		}
+		sensor_info->subdev_id[SUB_MODULE_STROBE_FLASH] = val;
+	}
+
+	if (of_get_property(of_node, "qcom,csiphy-sd-index", &count)) {
+		count /= sizeof(uint32_t);
+		if (count > 2) {
+			pr_err("%s qcom,csiphy-sd-index count %d > 2\n",
+				__func__, count);
+			goto ERROR;
+		}
+		val_array = kzalloc(sizeof(uint32_t) * count, GFP_KERNEL);
+		if (!val_array) {
+			pr_err("%s failed %d\n", __func__, __LINE__);
+			rc = -ENOMEM;
+			goto ERROR;
+		}
+
+		rc = of_property_read_u32_array(of_node, "qcom,csiphy-sd-index",
+			val_array, count);
+		if (rc < 0) {
+			pr_err("%s failed %d\n", __func__, __LINE__);
+			kfree(val_array);
+			goto ERROR;
+		}
+		for (i = 0; i < count; i++) {
+			sensor_info->subdev_id[SUB_MODULE_CSIPHY + i] =
+								val_array[i];
+			CDBG("%s csiphy_core[%d] = %d\n",
+				__func__, i, val_array[i]);
+		}
+		kfree(val_array);
+	} else {
+		pr_err("%s:%d qcom,csiphy-sd-index not present\n", __func__,
+			__LINE__);
+		rc = -EINVAL;
+		goto ERROR;
+	}
+
+	if (of_get_property(of_node, "qcom,csid-sd-index", &count)) {
+		count /= sizeof(uint32_t);
+		if (count > 2) {
+			pr_err("%s qcom,csid-sd-index count %d > 2\n",
+				__func__, count);
+			rc = -EINVAL;
+			goto ERROR;
+		}
+		val_array = kzalloc(sizeof(uint32_t) * count, GFP_KERNEL);
+		if (!val_array) {
+			pr_err("%s failed %d\n", __func__, __LINE__);
+			rc = -ENOMEM;
+			goto ERROR;
+		}
+
+		rc = of_property_read_u32_array(of_node, "qcom,csid-sd-index",
+			val_array, count);
+		if (rc < 0) {
+			pr_err("%s failed %d\n", __func__, __LINE__);
+			kfree(val_array);
+			goto ERROR;
+		}
+		for (i = 0; i < count; i++) {
+			sensor_info->subdev_id
+				[SUB_MODULE_CSID + i] = val_array[i];
+			CDBG("%s csid_core[%d] = %d\n",
+				__func__, i, val_array[i]);
+		}
+		kfree(val_array);
+	} else {
+		pr_err("%s:%d qcom,csid-sd-index not present\n", __func__,
+			__LINE__);
+		rc = -EINVAL;
+		goto ERROR;
+	}
+
+	*s_info = sensor_info;
+	return rc;
+ERROR:
+	kfree(sensor_info);
+	return rc;
+}
+
+int msm_sensor_get_dt_actuator_data(struct device_node *of_node,
+				    struct msm_actuator_info **act_info)
+{
+	int rc = 0;
+	uint32_t val = 0;
+	struct msm_actuator_info *actuator_info;
+
+	rc = of_property_read_u32(of_node, "qcom,actuator-cam-name", &val);
+	CDBG("%s qcom,actuator-cam-name %d, rc %d\n", __func__, val, rc);
+	if (rc < 0)
+		return 0;
+
+	actuator_info = kzalloc(sizeof(*actuator_info), GFP_KERNEL);
+	if (!actuator_info) {
+		pr_err("%s failed %d\n", __func__, __LINE__);
+		rc = -ENOMEM;
+		goto ERROR;
+	}
+
+	actuator_info->cam_name = val;
+
+	rc = of_property_read_u32(of_node, "qcom,actuator-vcm-pwd", &val);
+	CDBG("%s qcom,actuator-vcm-pwd %d, rc %d\n", __func__, val, rc);
+	if (!rc)
+		actuator_info->vcm_pwd = val;
+
+	rc = of_property_read_u32(of_node, "qcom,actuator-vcm-enable", &val);
+	CDBG("%s qcom,actuator-vcm-enable %d, rc %d\n", __func__, val, rc);
+	if (!rc)
+		actuator_info->vcm_enable = val;
+
+	*act_info = actuator_info;
+	return 0;
+ERROR:
+	kfree(actuator_info);
+	return rc;
+}
+
+int msm_sensor_get_dt_csi_data(struct device_node *of_node,
+	struct msm_camera_csi_lane_params **csi_lane_params)
+{
+	int rc = 0;
+	uint32_t val = 0;
+	struct msm_camera_csi_lane_params *clp;
+
+	clp = kzalloc(sizeof(*clp), GFP_KERNEL);
+	if (!clp) {
+		pr_err("%s failed %d\n", __func__, __LINE__);
+		return -ENOMEM;
+	}
+	*csi_lane_params = clp;
+
+	rc = of_property_read_u32(of_node, "qcom,csi-lane-assign", &val);
+	CDBG("%s qcom,csi-lane-assign %x, rc %d\n", __func__, val, rc);
+	if (rc < 0) {
+		pr_err("%s failed %d\n", __func__, __LINE__);
+		goto ERROR;
+	}
+	clp->csi_lane_assign = val;
+
+	rc = of_property_read_u32(of_node, "qcom,csi-lane-mask", &val);
+	CDBG("%s qcom,csi-lane-mask %x, rc %d\n", __func__, val, rc);
+	if (rc < 0) {
+		pr_err("%s failed %d\n", __func__, __LINE__);
+		goto ERROR;
+	}
+	clp->csi_lane_mask = val;
+
+	return rc;
+ERROR:
+	kfree(clp);
+	return rc;
+}
+
 int msm_camera_get_dt_power_setting_data(struct device_node *of_node,
 	struct camera_vreg_t *cam_vreg, int num_vreg,
-	struct msm_sensor_power_setting **power_setting,
-	uint16_t *power_setting_size)
+	struct msm_camera_power_ctrl_t *power_info)
 {
 	int rc = 0, i, j;
 	int count = 0;
@@ -34,11 +355,19 @@
 	uint32_t *array = NULL;
 	struct msm_sensor_power_setting *ps;
 
-	if (!power_setting || !power_setting_size)
+	struct msm_sensor_power_setting *power_setting;
+	uint16_t *power_setting_size, size = 0;
+	bool need_reverse = 0;
+
+	if (!power_info)
 		return -EINVAL;
 
+	power_setting = power_info->power_setting;
+	power_setting_size = &power_info->power_setting_size;
+
 	count = of_property_count_strings(of_node, "qcom,cam-power-seq-type");
 	*power_setting_size = count;
+
 	CDBG("%s qcom,cam-power-seq-type count %d\n", __func__, count);
 
 	if (count <= 0)
@@ -49,7 +378,8 @@
 		pr_err("%s failed %d\n", __func__, __LINE__);
 		return -ENOMEM;
 	}
-	*power_setting = ps;
+	power_setting = ps;
+	power_info->power_setting = ps;
 
 	for (i = 0; i < count; i++) {
 		rc = of_property_read_string_index(of_node,
@@ -179,8 +509,40 @@
 			i, ps[i].delay);
 	}
 	kfree(array);
-	return rc;
 
+	size = *power_setting_size;
+
+	if (NULL != ps && 0 != size)
+		need_reverse = 1;
+
+	power_info->power_down_setting =
+		kzalloc(sizeof(*ps) * size, GFP_KERNEL);
+
+	if (!power_info->power_down_setting) {
+		pr_err("%s failed %d\n", __func__, __LINE__);
+		rc = -ENOMEM;
+		goto ERROR1;
+	}
+
+	memcpy(power_info->power_down_setting,
+		ps, sizeof(*ps) * size);
+
+	power_info->power_down_setting_size = size;
+
+	if (need_reverse) {
+		int c, end = size - 1;
+		struct msm_sensor_power_setting power_down_setting_t;
+		for (c = 0; c < size/2; c++) {
+			power_down_setting_t =
+				power_info->power_down_setting[c];
+			power_info->power_down_setting[c] =
+				power_info->power_down_setting[end];
+			power_info->power_down_setting[end] =
+				power_down_setting_t;
+			end--;
+		}
+	}
+	return rc;
 ERROR2:
 	kfree(array);
 ERROR1:
@@ -273,7 +635,91 @@
 	return rc;
 }
 
-int32_t msm_camera_init_gpio_pin_tbl(struct device_node *of_node,
+int msm_camera_get_dt_gpio_set_tbl(struct device_node *of_node,
+	struct msm_camera_gpio_conf *gconf, uint16_t *gpio_array,
+	uint16_t gpio_array_size)
+{
+	int rc = 0, i = 0;
+	uint32_t count = 0;
+	uint32_t *val_array = NULL;
+
+	if (!of_get_property(of_node, "qcom,gpio-set-tbl-num", &count))
+		return 0;
+
+	count /= sizeof(uint32_t);
+	if (!count) {
+		pr_err("%s qcom,gpio-set-tbl-num 0\n", __func__);
+		return 0;
+	}
+
+	val_array = kzalloc(sizeof(uint32_t) * count, GFP_KERNEL);
+	if (!val_array) {
+		pr_err("%s failed %d\n", __func__, __LINE__);
+		return -ENOMEM;
+	}
+
+	gconf->cam_gpio_set_tbl = kzalloc(sizeof(struct msm_gpio_set_tbl) *
+		count, GFP_KERNEL);
+	if (!gconf->cam_gpio_set_tbl) {
+		pr_err("%s failed %d\n", __func__, __LINE__);
+		rc = -ENOMEM;
+		goto ERROR1;
+	}
+	gconf->cam_gpio_set_tbl_size = count;
+
+	rc = of_property_read_u32_array(of_node, "qcom,gpio-set-tbl-num",
+		val_array, count);
+	if (rc < 0) {
+		pr_err("%s failed %d\n", __func__, __LINE__);
+		goto ERROR2;
+	}
+	for (i = 0; i < count; i++) {
+		if (val_array[i] >= gpio_array_size) {
+			pr_err("%s gpio set tbl index %d invalid\n",
+				__func__, val_array[i]);
+			return -EINVAL;
+		}
+		gconf->cam_gpio_set_tbl[i].gpio = gpio_array[val_array[i]];
+		CDBG("%s cam_gpio_set_tbl[%d].gpio = %d\n", __func__, i,
+			gconf->cam_gpio_set_tbl[i].gpio);
+	}
+
+	rc = of_property_read_u32_array(of_node, "qcom,gpio-set-tbl-flags",
+		val_array, count);
+	if (rc < 0) {
+		pr_err("%s failed %d\n", __func__, __LINE__);
+		goto ERROR2;
+	}
+	for (i = 0; i < count; i++) {
+		gconf->cam_gpio_set_tbl[i].flags = val_array[i];
+		CDBG("%s cam_gpio_set_tbl[%d].flags = %ld\n", __func__, i,
+			gconf->cam_gpio_set_tbl[i].flags);
+	}
+
+	rc = of_property_read_u32_array(of_node, "qcom,gpio-set-tbl-delay",
+		val_array, count);
+	if (rc < 0) {
+		pr_err("%s failed %d\n", __func__, __LINE__);
+		goto ERROR2;
+	}
+	for (i = 0; i < count; i++) {
+		gconf->cam_gpio_set_tbl[i].delay = val_array[i];
+		CDBG("%s cam_gpio_set_tbl[%d].delay = %d\n", __func__, i,
+			gconf->cam_gpio_set_tbl[i].delay);
+	}
+
+	kfree(val_array);
+	return rc;
+
+ERROR2:
+	kfree(gconf->cam_gpio_set_tbl);
+ERROR1:
+	kfree(val_array);
+	gconf->cam_gpio_set_tbl_size = 0;
+	return rc;
+}
+
+int msm_camera_init_gpio_pin_tbl(struct device_node *of_node,
 	struct msm_camera_gpio_conf *gconf, uint16_t *gpio_array,
 	uint16_t gpio_array_size)
 {
@@ -300,6 +746,7 @@
 		}
 		gconf->gpio_num_info->gpio_num[SENSOR_GPIO_VDIG] =
 			gpio_array[val];
+		gconf->gpio_num_info->valid[SENSOR_GPIO_VDIG] = 1;
 		CDBG("%s qcom,gpio-reset %d\n", __func__,
 			gconf->gpio_num_info->gpio_num[SENSOR_GPIO_VDIG]);
 	}
@@ -317,6 +764,7 @@
 		}
 		gconf->gpio_num_info->gpio_num[SENSOR_GPIO_RESET] =
 			gpio_array[val];
+		gconf->gpio_num_info->valid[SENSOR_GPIO_RESET] = 1;
 		CDBG("%s qcom,gpio-reset %d\n", __func__,
 			gconf->gpio_num_info->gpio_num[SENSOR_GPIO_RESET]);
 	}
@@ -334,9 +782,47 @@
 		}
 		gconf->gpio_num_info->gpio_num[SENSOR_GPIO_STANDBY] =
 			gpio_array[val];
+		gconf->gpio_num_info->valid[SENSOR_GPIO_STANDBY] = 1;
 		CDBG("%s qcom,gpio-reset %d\n", __func__,
 			gconf->gpio_num_info->gpio_num[SENSOR_GPIO_STANDBY]);
 	}
+
+	if (of_property_read_bool(of_node, "qcom,gpio-flash-en") == true) {
+		rc = of_property_read_u32(of_node, "qcom,gpio-flash-en", &val);
+		if (rc < 0) {
+			pr_err("%s:%d read qcom,gpio-flash-en failed rc %d\n",
+				__func__, __LINE__, rc);
+			goto ERROR;
+		} else if (val >= gpio_array_size) {
+			pr_err("%s:%d qcom,gpio-flash-en invalid %d\n",
+				__func__, __LINE__, val);
+			goto ERROR;
+		}
+		gconf->gpio_num_info->gpio_num[SENSOR_GPIO_FL_EN] =
+			gpio_array[val];
+		gconf->gpio_num_info->valid[SENSOR_GPIO_FL_EN] = 1;
+		CDBG("%s qcom,gpio-flash-en %d\n", __func__,
+			gconf->gpio_num_info->gpio_num[SENSOR_GPIO_FL_EN]);
+	}
+
+	if (of_property_read_bool(of_node, "qcom,gpio-flash-now") == true) {
+		rc = of_property_read_u32(of_node, "qcom,gpio-flash-now", &val);
+		if (rc < 0) {
+			pr_err("%s:%d read qcom,gpio-flash-now failed rc %d\n",
+				__func__, __LINE__, rc);
+			goto ERROR;
+		} else if (val >= gpio_array_size) {
+			pr_err("%s:%d qcom,gpio-flash-now invalid %d\n",
+				__func__, __LINE__, val);
+			goto ERROR;
+		}
+		gconf->gpio_num_info->gpio_num[SENSOR_GPIO_FL_NOW] =
+			gpio_array[val];
+		gconf->gpio_num_info->valid[SENSOR_GPIO_FL_NOW] = 1;
+		CDBG("%s qcom,gpio-flash-now %d\n", __func__,
+			gconf->gpio_num_info->gpio_num[SENSOR_GPIO_FL_NOW]);
+	}
+
 	return rc;
 
 ERROR:
@@ -529,6 +1015,9 @@
 					SENSOR_GPIO_MAX);
 				goto power_up_failed;
 			}
+			if (!ctrl->gpio_conf->gpio_num_info->valid
+				[power_setting->seq_val])
+				continue;
 			CDBG("%s:%d gpio set val %d\n", __func__, __LINE__,
 				ctrl->gpio_conf->gpio_num_info->gpio_num
 				[power_setting->seq_val]);
@@ -589,6 +1078,7 @@
 		power_setting = &ctrl->power_setting[index];
 		CDBG("%s type %d\n", __func__, power_setting->seq_type);
 		switch (power_setting->seq_type) {
+
 		case SENSOR_CLK:
 			msm_cam_clk_enable(ctrl->dev,
 				&ctrl->clk_info[0],
@@ -597,6 +1087,9 @@
 				0);
 			break;
 		case SENSOR_GPIO:
+			if (!ctrl->gpio_conf->gpio_num_info->valid
+				[power_setting->seq_val])
+				continue;
 			gpio_set_value_cansleep(
 				ctrl->gpio_conf->gpio_num_info->gpio_num
 				[power_setting->seq_val], GPIOF_OUT_INIT_LOW);
@@ -629,12 +1122,34 @@
 	return rc;
 }
 
+static struct msm_sensor_power_setting*
+msm_camera_get_power_settings(struct msm_camera_power_ctrl_t *ctrl,
+				enum msm_sensor_power_seq_type_t seq_type,
+				uint16_t seq_val)
+{
+	struct msm_sensor_power_setting *power_setting, *ps = NULL;
+	int idx;
+
+	for (idx = 0; idx < ctrl->power_setting_size; idx++) {
+		power_setting = &ctrl->power_setting[idx];
+		if (power_setting->seq_type == seq_type &&
+			power_setting->seq_val ==  seq_val) {
+			ps = power_setting;
+			return ps;
+		}
+
+	}
+	return ps;
+}
+
 int msm_camera_power_down(struct msm_camera_power_ctrl_t *ctrl,
 	enum msm_camera_device_type_t device_type,
 	struct msm_camera_i2c_client *sensor_i2c_client)
 {
 	int index = 0;
-	struct msm_sensor_power_setting *power_setting = NULL;
+	struct msm_sensor_power_setting *pd = NULL;
+	struct msm_sensor_power_setting *ps;
+
 
 	CDBG("%s:%d\n", __func__, __LINE__);
 	if (!ctrl || !sensor_i2c_client) {
@@ -647,43 +1162,64 @@
 		sensor_i2c_client->i2c_func_tbl->i2c_util(
 			sensor_i2c_client, MSM_CCI_RELEASE);
 
-	for (index = (ctrl->power_setting_size - 1); index >= 0; index--) {
+	for (index = 0; index < ctrl->power_down_setting_size; index++) {
 		CDBG("%s index %d\n", __func__, index);
-		power_setting = &ctrl->power_setting[index];
-		CDBG("%s type %d\n", __func__, power_setting->seq_type);
-		switch (power_setting->seq_type) {
+		pd = &ctrl->power_down_setting[index];
+		ps = NULL;
+		CDBG("%s type %d\n", __func__, pd->seq_type);
+		switch (pd->seq_type) {
 		case SENSOR_CLK:
-			msm_cam_clk_enable(ctrl->dev,
-				&ctrl->clk_info[0],
-				(struct clk **)&power_setting->data[0],
-				ctrl->clk_info_size,
-				0);
-			break;
+
+			ps = msm_camera_get_power_settings(ctrl,
+						pd->seq_type,
+						pd->seq_val);
+			if (ps)
+				msm_cam_clk_enable(ctrl->dev,
+					&ctrl->clk_info[0],
+					(struct clk **)&ps->data[0],
+					ctrl->clk_info_size,
+					0);
+			else
+				pr_err("%s error in power up/down seq data\n",
+								__func__);
+				break;
 		case SENSOR_GPIO:
-			if (power_setting->seq_val >= SENSOR_GPIO_MAX ||
+			if (pd->seq_val >= SENSOR_GPIO_MAX ||
 				!ctrl->gpio_conf->gpio_num_info) {
 				pr_err("%s gpio index %d >= max %d\n", __func__,
-					power_setting->seq_val,
+					pd->seq_val,
 					SENSOR_GPIO_MAX);
 				continue;
 			}
+			if (!ctrl->gpio_conf->gpio_num_info->valid
+				[pd->seq_val])
+				continue;
 			gpio_set_value_cansleep(
 				ctrl->gpio_conf->gpio_num_info->gpio_num
-				[power_setting->seq_val],
+				[pd->seq_val],
 				ctrl->gpio_conf->gpio_num_info->gpio_num
-				[power_setting->config_val]);
+				[pd->config_val]);
 			break;
 		case SENSOR_VREG:
-			if (power_setting->seq_val >= CAM_VREG_MAX) {
+			if (pd->seq_val >= CAM_VREG_MAX) {
 				pr_err("%s vreg index %d >= max %d\n", __func__,
-					power_setting->seq_val,
+					pd->seq_val,
 					SENSOR_GPIO_MAX);
 				continue;
 			}
-			msm_camera_config_single_vreg(ctrl->dev,
-				&ctrl->cam_vreg[power_setting->seq_val],
-				(struct regulator **)&power_setting->data[0],
-				0);
+
+			ps = msm_camera_get_power_settings(ctrl,
+						pd->seq_type,
+						pd->seq_val);
+
+			if (ps)
+				msm_camera_config_single_vreg(ctrl->dev,
+					&ctrl->cam_vreg[pd->seq_val],
+					(struct regulator **)&ps->data[0],
+					0);
+			else
+				pr_err("%s error in power up/down seq data\n",
+								__func__);
 			break;
 		case SENSOR_I2C_MUX:
 			if (ctrl->i2c_conf && ctrl->i2c_conf->use_i2c_mux)
@@ -691,14 +1227,14 @@
 			break;
 		default:
 			pr_err("%s error power seq type %d\n", __func__,
-				power_setting->seq_type);
+				pd->seq_type);
 			break;
 		}
-		if (power_setting->delay > 20) {
-			msleep(power_setting->delay);
-		} else if (power_setting->delay) {
-			usleep_range(power_setting->delay * 1000,
-				(power_setting->delay * 1000) + 1000);
+		if (pd->delay > 20) {
+			msleep(pd->delay);
+		} else if (pd->delay) {
+			usleep_range(pd->delay * 1000,
+				(pd->delay * 1000) + 1000);
 		}
 	}
 	msm_camera_request_gpio_table(
diff --git a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_dt_util.h b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_dt_util.h
index fee2a4c..d7f8507 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_dt_util.h
+++ b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_dt_util.h
@@ -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
@@ -18,28 +18,44 @@
 #include <linux/of.h>
 #include "msm_camera_i2c.h"
 
-int32_t msm_camera_get_dt_power_setting_data(struct device_node *of_node,
+int msm_sensor_get_sub_module_index(struct device_node *of_node,
+	struct  msm_sensor_info_t **s_info);
+
+int msm_sensor_get_dt_actuator_data(struct device_node *of_node,
+	struct msm_actuator_info **act_info);
+
+int msm_sensor_get_dt_csi_data(struct device_node *of_node,
+	struct msm_camera_csi_lane_params **csi_lane_params);
+
+int msm_camera_get_dt_power_setting_data(struct device_node *of_node,
 	struct camera_vreg_t *cam_vreg, int num_vreg,
-	struct msm_sensor_power_setting **power_setting,
-	uint16_t *power_setting_size);
+	struct msm_camera_power_ctrl_t *power_info);
 
-int32_t msm_camera_get_dt_gpio_req_tbl(struct device_node *of_node,
+int msm_camera_get_dt_gpio_req_tbl(struct device_node *of_node,
 	struct msm_camera_gpio_conf *gconf, uint16_t *gpio_array,
 	uint16_t gpio_array_size);
 
-int32_t msm_camera_init_gpio_pin_tbl(struct device_node *of_node,
+int msm_camera_get_dt_gpio_set_tbl(struct device_node *of_node,
 	struct msm_camera_gpio_conf *gconf, uint16_t *gpio_array,
 	uint16_t gpio_array_size);
 
-int32_t msm_camera_get_dt_vreg_data(struct device_node *of_node,
+int msm_camera_init_gpio_pin_tbl(struct device_node *of_node,
+	struct msm_camera_gpio_conf *gconf, uint16_t *gpio_array,
+	uint16_t gpio_array_size);
+
+int msm_camera_get_dt_vreg_data(struct device_node *of_node,
 	struct camera_vreg_t **cam_vreg, int *num_vreg);
 
-int32_t msm_camera_power_up(struct msm_camera_power_ctrl_t *ctrl,
+int msm_camera_power_up(struct msm_camera_power_ctrl_t *ctrl,
 	enum msm_camera_device_type_t device_type,
 	struct msm_camera_i2c_client *sensor_i2c_client);
 
-int32_t msm_camera_power_down(struct msm_camera_power_ctrl_t *ctrl,
+int msm_camera_power_down(struct msm_camera_power_ctrl_t *ctrl,
 	enum msm_camera_device_type_t device_type,
 	struct msm_camera_i2c_client *sensor_i2c_client);
 
+int msm_camera_fill_vreg_params(struct camera_vreg_t *cam_vreg,
+	int num_vreg, struct msm_sensor_power_setting *power_setting,
+	uint16_t power_setting_size);
+
 #endif
diff --git a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_i2c.h b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_i2c.h
index 763c131..1bceb51 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_i2c.h
+++ b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_i2c.h
@@ -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
@@ -117,4 +117,8 @@
 	struct msm_camera_i2c_reg_conf *reg_conf_tbl, uint16_t size,
 	enum msm_camera_i2c_data_type data_type);
 
+int32_t msm_camera_qup_i2c_poll(struct msm_camera_i2c_client *client,
+	uint32_t addr, uint16_t data,
+	enum msm_camera_i2c_data_type data_type);
+
 #endif
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.c b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.c
old mode 100644
new mode 100755
index 03145c8..279a7dd
--- a/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.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
@@ -20,6 +20,7 @@
 #include <mach/rpm-regulator-smd.h>
 #include <linux/regulator/consumer.h>
 
+/*#define CONFIG_MSMB_CAMERA_DEBUG*/
 #undef CDBG
 #ifdef CONFIG_MSMB_CAMERA_DEBUG
 #define CDBG(fmt, args...) pr_err(fmt, ##args)
@@ -27,674 +28,76 @@
 #define CDBG(fmt, args...) do { } while (0)
 #endif
 
-static int32_t msm_sensor_enable_i2c_mux(struct msm_camera_i2c_conf *i2c_conf)
+static int32_t msm_camera_get_power_settimgs_from_sensor_lib(
+	struct msm_camera_power_ctrl_t *power_info,
+	struct msm_sensor_power_setting_array *power_setting_array)
 {
-	struct v4l2_subdev *i2c_mux_sd =
-		dev_get_drvdata(&i2c_conf->mux_dev->dev);
-	v4l2_subdev_call(i2c_mux_sd, core, ioctl,
-		VIDIOC_MSM_I2C_MUX_INIT, NULL);
-	v4l2_subdev_call(i2c_mux_sd, core, ioctl,
-		VIDIOC_MSM_I2C_MUX_CFG, (void *)&i2c_conf->i2c_mux_mode);
-	return 0;
-}
+	int32_t rc = 0;
+	uint32_t size;
+	struct msm_sensor_power_setting *ps;
+	bool need_reverse = 0;
 
-static int32_t msm_sensor_disable_i2c_mux(struct msm_camera_i2c_conf *i2c_conf)
-{
-	struct v4l2_subdev *i2c_mux_sd =
-		dev_get_drvdata(&i2c_conf->mux_dev->dev);
-	v4l2_subdev_call(i2c_mux_sd, core, ioctl,
-				VIDIOC_MSM_I2C_MUX_RELEASE, NULL);
-	return 0;
-}
+	if ((NULL == power_info->power_setting) ||
+		(0 == power_info->power_setting_size)) {
 
-static int32_t msm_sensor_get_sub_module_index(struct device_node *of_node,
-	struct  msm_camera_sensor_board_info *sensordata)
-{
-	int32_t rc = 0, i = 0;
-	uint32_t val = 0, count = 0;
-	uint32_t *val_array = NULL;
-	struct device_node *src_node = NULL;
-
-	sensordata->sensor_info = kzalloc(sizeof(struct msm_sensor_info_t),
-		GFP_KERNEL);
-	if (!sensordata->sensor_info) {
-		pr_err("%s:%d failed\n", __func__, __LINE__);
-		return -ENOMEM;
-	}
-	for (i = 0; i < SUB_MODULE_MAX; i++)
-		sensordata->sensor_info->subdev_id[i] = -1;
-
-	src_node = of_parse_phandle(of_node, "qcom,actuator-src", 0);
-	if (!src_node) {
-		CDBG("%s:%d src_node NULL\n", __func__, __LINE__);
-	} else {
-		rc = of_property_read_u32(src_node, "cell-index", &val);
-		CDBG("%s qcom,actuator cell index %d, rc %d\n", __func__,
-			val, rc);
-		if (rc < 0) {
+		ps = power_setting_array->power_setting;
+		size = power_setting_array->size;
+		if ((NULL == ps) || (0 == size)) {
 			pr_err("%s failed %d\n", __func__, __LINE__);
-			goto ERROR;
-		}
-		sensordata->sensor_info->
-			subdev_id[SUB_MODULE_ACTUATOR] = val;
-		of_node_put(src_node);
-		src_node = NULL;
-	}
-
-	src_node = of_parse_phandle(of_node, "qcom,eeprom-src", 0);
-	if (!src_node) {
-		CDBG("%s:%d eeprom src_node NULL\n", __func__, __LINE__);
-	} else {
-		rc = of_property_read_u32(src_node, "cell-index", &val);
-		CDBG("%s qcom,eeprom cell index %d, rc %d\n", __func__,
-			val, rc);
-		if (rc < 0) {
-			pr_err("%s failed %d\n", __func__, __LINE__);
-			goto ERROR;
-		}
-		sensordata->sensor_info->
-			subdev_id[SUB_MODULE_EEPROM] = val;
-		of_node_put(src_node);
-		src_node = NULL;
-	}
-
-	if (of_property_read_bool(of_node, "qcom,eeprom-sd-index") ==
-		true) {
-		rc = of_property_read_u32(of_node, "qcom,eeprom-sd-index",
-			&val);
-		CDBG("%s qcom,eeprom-sd-index %d, rc %d\n", __func__, val, rc);
-		if (rc < 0) {
-			pr_err("%s:%d failed rc %d\n", __func__, __LINE__, rc);
-			goto ERROR;
-		}
-		sensordata->sensor_info->subdev_id[SUB_MODULE_EEPROM] = val;
-	}
-
-	src_node = of_parse_phandle(of_node, "qcom,led-flash-src", 0);
-	if (!src_node) {
-		CDBG("%s:%d src_node NULL\n", __func__, __LINE__);
-	} else {
-		rc = of_property_read_u32(src_node, "cell-index", &val);
-		CDBG("%s qcom,led flash cell index %d, rc %d\n", __func__,
-			val, rc);
-		if (rc < 0) {
-			pr_err("%s:%d failed %d\n", __func__, __LINE__, rc);
-			goto ERROR;
-		}
-		sensordata->sensor_info->
-			subdev_id[SUB_MODULE_LED_FLASH] = val;
-		of_node_put(src_node);
-		src_node = NULL;
-	}
-
-	if (of_property_read_bool(of_node, "qcom,strobe-flash-sd-index") ==
-		true) {
-		rc = of_property_read_u32(of_node, "qcom,strobe-flash-sd-index",
-			&val);
-		CDBG("%s qcom,strobe-flash-sd-index %d, rc %d\n", __func__,
-			val, rc);
-		if (rc < 0) {
-			pr_err("%s:%d failed rc %d\n", __func__, __LINE__, rc);
-			goto ERROR;
-		}
-		sensordata->sensor_info->subdev_id[SUB_MODULE_STROBE_FLASH] =
-			val;
-	}
-
-	if (of_get_property(of_node, "qcom,csiphy-sd-index", &count)) {
-		count /= sizeof(uint32_t);
-		if (count > 2) {
-			pr_err("%s qcom,csiphy-sd-index count %d > 2\n",
-				__func__, count);
-			goto ERROR;
-		}
-		val_array = kzalloc(sizeof(uint32_t) * count, GFP_KERNEL);
-		if (!val_array) {
-			pr_err("%s failed %d\n", __func__, __LINE__);
-			rc = -ENOMEM;
-			goto ERROR;
-		}
-
-		rc = of_property_read_u32_array(of_node, "qcom,csiphy-sd-index",
-			val_array, count);
-		if (rc < 0) {
-			pr_err("%s failed %d\n", __func__, __LINE__);
-			kfree(val_array);
-			goto ERROR;
-		}
-		for (i = 0; i < count; i++) {
-			sensordata->sensor_info->subdev_id
-				[SUB_MODULE_CSIPHY + i] = val_array[i];
-			CDBG("%s csiphy_core[%d] = %d\n",
-				__func__, i, val_array[i]);
-		}
-		kfree(val_array);
-	} else {
-		pr_err("%s:%d qcom,csiphy-sd-index not present\n", __func__,
-			__LINE__);
-		rc = -EINVAL;
-		goto ERROR;
-	}
-
-	if (of_get_property(of_node, "qcom,csid-sd-index", &count)) {
-		count /= sizeof(uint32_t);
-		if (count > 2) {
-			pr_err("%s qcom,csid-sd-index count %d > 2\n",
-				__func__, count);
 			rc = -EINVAL;
-			goto ERROR;
+			goto FAILED_1;
 		}
-		val_array = kzalloc(sizeof(uint32_t) * count, GFP_KERNEL);
-		if (!val_array) {
+
+		power_info->power_setting =
+		kzalloc(sizeof(*ps) * size, GFP_KERNEL);
+		if (!power_info->power_setting) {
 			pr_err("%s failed %d\n", __func__, __LINE__);
 			rc = -ENOMEM;
-			goto ERROR;
+			goto FAILED_1;
 		}
-
-		rc = of_property_read_u32_array(of_node, "qcom,csid-sd-index",
-			val_array, count);
-		if (rc < 0) {
-			pr_err("%s failed %d\n", __func__, __LINE__);
-			kfree(val_array);
-			goto ERROR;
-		}
-		for (i = 0; i < count; i++) {
-			sensordata->sensor_info->subdev_id
-				[SUB_MODULE_CSID + i] = val_array[i];
-			CDBG("%s csid_core[%d] = %d\n",
-				__func__, i, val_array[i]);
-		}
-		kfree(val_array);
-	} else {
-		pr_err("%s:%d qcom,csid-sd-index not present\n", __func__,
-			__LINE__);
-		rc = -EINVAL;
-		goto ERROR;
+		memcpy(power_info->power_setting,
+			power_setting_array->power_setting,
+			sizeof(*ps) * size);
+		power_info->power_setting_size = size;
 	}
-	return rc;
-ERROR:
-	kfree(sensordata->sensor_info);
-	sensordata->sensor_info = NULL;
-	return rc;
-}
 
-static int32_t msm_sensor_get_dt_csi_data(struct device_node *of_node,
-	struct  msm_camera_sensor_board_info *sensordata)
-{
-	int32_t rc = 0;
-	uint32_t val = 0;
+	ps = power_setting_array->power_down_setting;
+	size = power_setting_array->size_down;
+	if (NULL == ps || 0 == size) {
+		ps = power_info->power_setting;
+		size = power_info->power_setting_size;
+		need_reverse = 1;
+	}
 
-	sensordata->csi_lane_params = kzalloc(
-		sizeof(struct msm_camera_csi_lane_params), GFP_KERNEL);
-	if (!sensordata->csi_lane_params) {
+	power_info->power_down_setting =
+	kzalloc(sizeof(*ps) * size, GFP_KERNEL);
+	if (!power_info->power_down_setting) {
 		pr_err("%s failed %d\n", __func__, __LINE__);
-		rc = -ENOMEM;
-		goto ERROR1;
+		goto FREE_UP;
 	}
+	memcpy(power_info->power_down_setting,
+		ps,
+		sizeof(*ps) * size);
+	power_info->power_down_setting_size = size;
 
-	rc = of_property_read_u32(of_node, "qcom,csi-lane-assign", &val);
-	CDBG("%s qcom,csi-lane-assign %x, rc %d\n", __func__, val, rc);
-	if (rc < 0) {
-		pr_err("%s failed %d\n", __func__, __LINE__);
-		goto ERROR2;
-	}
-	sensordata->csi_lane_params->csi_lane_assign = val;
-
-	rc = of_property_read_u32(of_node, "qcom,csi-lane-mask", &val);
-	CDBG("%s qcom,csi-lane-mask %x, rc %d\n", __func__, val, rc);
-	if (rc < 0) {
-		pr_err("%s failed %d\n", __func__, __LINE__);
-		goto ERROR2;
-	}
-	sensordata->csi_lane_params->csi_lane_mask = val;
-
-	return rc;
-ERROR2:
-	kfree(sensordata->csi_lane_params);
-ERROR1:
-	return rc;
-}
-
-static int32_t msm_sensor_get_dt_vreg_data(struct device_node *of_node,
-	struct msm_camera_sensor_board_info *sensordata)
-{
-	int32_t rc = 0, i = 0;
-	uint32_t count = 0;
-	uint32_t *vreg_array = NULL;
-
-	count = of_property_count_strings(of_node, "qcom,cam-vreg-name");
-	CDBG("%s qcom,cam-vreg-name count %d\n", __func__, count);
-
-	if (!count)
-		return 0;
-
-	sensordata->cam_vreg = kzalloc(sizeof(struct camera_vreg_t) * count,
-		GFP_KERNEL);
-	if (!sensordata->cam_vreg) {
-		pr_err("%s failed %d\n", __func__, __LINE__);
-		return -ENOMEM;
-	}
-
-	sensordata->num_vreg = count;
-	for (i = 0; i < count; i++) {
-		rc = of_property_read_string_index(of_node,
-			"qcom,cam-vreg-name", i,
-			&sensordata->cam_vreg[i].reg_name);
-		CDBG("%s reg_name[%d] = %s\n", __func__, i,
-			sensordata->cam_vreg[i].reg_name);
-		if (rc < 0) {
-			pr_err("%s failed %d\n", __func__, __LINE__);
-			goto ERROR1;
+	if (need_reverse) {
+		int c, end = size - 1;
+		struct msm_sensor_power_setting power_down_setting_t;
+		for (c = 0; c < size/2; c++) {
+			power_down_setting_t =
+				power_info->power_down_setting[c];
+			power_info->power_down_setting[c] =
+				power_info->power_down_setting[end];
+			power_info->power_down_setting[end] =
+				power_down_setting_t;
+			end--;
 		}
 	}
 
-	vreg_array = kzalloc(sizeof(uint32_t) * count, GFP_KERNEL);
-	if (!vreg_array) {
-		pr_err("%s failed %d\n", __func__, __LINE__);
-		rc = -ENOMEM;
-		goto ERROR1;
-	}
-
-	rc = of_property_read_u32_array(of_node, "qcom,cam-vreg-type",
-		vreg_array, count);
-	if (rc < 0) {
-		pr_err("%s failed %d\n", __func__, __LINE__);
-		goto ERROR2;
-	}
-	for (i = 0; i < count; i++) {
-		sensordata->cam_vreg[i].type = vreg_array[i];
-		CDBG("%s cam_vreg[%d].type = %d\n", __func__, i,
-			sensordata->cam_vreg[i].type);
-	}
-
-	rc = of_property_read_u32_array(of_node, "qcom,cam-vreg-min-voltage",
-		vreg_array, count);
-	if (rc < 0) {
-		pr_err("%s failed %d\n", __func__, __LINE__);
-		goto ERROR2;
-	}
-	for (i = 0; i < count; i++) {
-		sensordata->cam_vreg[i].min_voltage = vreg_array[i];
-		CDBG("%s cam_vreg[%d].min_voltage = %d\n", __func__,
-			i, sensordata->cam_vreg[i].min_voltage);
-	}
-
-	rc = of_property_read_u32_array(of_node, "qcom,cam-vreg-max-voltage",
-		vreg_array, count);
-	if (rc < 0) {
-		pr_err("%s failed %d\n", __func__, __LINE__);
-		goto ERROR2;
-	}
-	for (i = 0; i < count; i++) {
-		sensordata->cam_vreg[i].max_voltage = vreg_array[i];
-		CDBG("%s cam_vreg[%d].max_voltage = %d\n", __func__,
-			i, sensordata->cam_vreg[i].max_voltage);
-	}
-
-	rc = of_property_read_u32_array(of_node, "qcom,cam-vreg-op-mode",
-		vreg_array, count);
-	if (rc < 0) {
-		pr_err("%s failed %d\n", __func__, __LINE__);
-		goto ERROR2;
-	}
-	for (i = 0; i < count; i++) {
-		sensordata->cam_vreg[i].op_mode = vreg_array[i];
-		CDBG("%s cam_vreg[%d].op_mode = %d\n", __func__, i,
-			sensordata->cam_vreg[i].op_mode);
-	}
-
-	kfree(vreg_array);
-	return rc;
-ERROR2:
-	kfree(vreg_array);
-ERROR1:
-	kfree(sensordata->cam_vreg);
-	sensordata->num_vreg = 0;
-	return rc;
-}
-
-int32_t msm_sensor_get_dt_gpio_req_tbl(struct device_node *of_node,
-	struct msm_camera_gpio_conf *gconf, uint16_t *gpio_array,
-	uint16_t gpio_array_size)
-{
-	int32_t rc = 0, i = 0;
-	uint32_t count = 0;
-	uint32_t *val_array = NULL;
-
-	if (!of_get_property(of_node, "qcom,gpio-req-tbl-num", &count))
-		return 0;
-
-	count /= sizeof(uint32_t);
-	if (!count) {
-		pr_err("%s qcom,gpio-req-tbl-num 0\n", __func__);
-		return 0;
-	}
-
-	val_array = kzalloc(sizeof(uint32_t) * count, GFP_KERNEL);
-	if (!val_array) {
-		pr_err("%s failed %d\n", __func__, __LINE__);
-		return -ENOMEM;
-	}
-
-	gconf->cam_gpio_req_tbl = kzalloc(sizeof(struct gpio) * count,
-		GFP_KERNEL);
-	if (!gconf->cam_gpio_req_tbl) {
-		pr_err("%s failed %d\n", __func__, __LINE__);
-		rc = -ENOMEM;
-		goto ERROR1;
-	}
-	gconf->cam_gpio_req_tbl_size = count;
-
-	rc = of_property_read_u32_array(of_node, "qcom,gpio-req-tbl-num",
-		val_array, count);
-	if (rc < 0) {
-		pr_err("%s failed %d\n", __func__, __LINE__);
-		goto ERROR2;
-	}
-	for (i = 0; i < count; i++) {
-		if (val_array[i] >= gpio_array_size) {
-			pr_err("%s gpio req tbl index %d invalid\n",
-				__func__, val_array[i]);
-			return -EINVAL;
-		}
-		gconf->cam_gpio_req_tbl[i].gpio = gpio_array[val_array[i]];
-		CDBG("%s cam_gpio_req_tbl[%d].gpio = %d\n", __func__, i,
-			gconf->cam_gpio_req_tbl[i].gpio);
-	}
-
-	rc = of_property_read_u32_array(of_node, "qcom,gpio-req-tbl-flags",
-		val_array, count);
-	if (rc < 0) {
-		pr_err("%s failed %d\n", __func__, __LINE__);
-		goto ERROR2;
-	}
-	for (i = 0; i < count; i++) {
-		gconf->cam_gpio_req_tbl[i].flags = val_array[i];
-		CDBG("%s cam_gpio_req_tbl[%d].flags = %ld\n", __func__, i,
-			gconf->cam_gpio_req_tbl[i].flags);
-	}
-
-	for (i = 0; i < count; i++) {
-		rc = of_property_read_string_index(of_node,
-			"qcom,gpio-req-tbl-label", i,
-			&gconf->cam_gpio_req_tbl[i].label);
-		CDBG("%s cam_gpio_req_tbl[%d].label = %s\n", __func__, i,
-			gconf->cam_gpio_req_tbl[i].label);
-		if (rc < 0) {
-			pr_err("%s failed %d\n", __func__, __LINE__);
-			goto ERROR2;
-		}
-	}
-
-	kfree(val_array);
-	return rc;
-
-ERROR2:
-	kfree(gconf->cam_gpio_req_tbl);
-ERROR1:
-	kfree(val_array);
-	gconf->cam_gpio_req_tbl_size = 0;
-	return rc;
-}
-
-int32_t msm_sensor_get_dt_gpio_set_tbl(struct device_node *of_node,
-	struct msm_camera_gpio_conf *gconf, uint16_t *gpio_array,
-	uint16_t gpio_array_size)
-{
-	int32_t rc = 0, i = 0;
-	uint32_t count = 0;
-	uint32_t *val_array = NULL;
-
-	if (!of_get_property(of_node, "qcom,gpio-set-tbl-num", &count))
-		return 0;
-
-	count /= sizeof(uint32_t);
-	if (!count) {
-		pr_err("%s qcom,gpio-set-tbl-num 0\n", __func__);
-		return 0;
-	}
-
-	val_array = kzalloc(sizeof(uint32_t) * count, GFP_KERNEL);
-	if (!val_array) {
-		pr_err("%s failed %d\n", __func__, __LINE__);
-		return -ENOMEM;
-	}
-
-	gconf->cam_gpio_set_tbl = kzalloc(sizeof(struct msm_gpio_set_tbl) *
-		count, GFP_KERNEL);
-	if (!gconf->cam_gpio_set_tbl) {
-		pr_err("%s failed %d\n", __func__, __LINE__);
-		rc = -ENOMEM;
-		goto ERROR1;
-	}
-	gconf->cam_gpio_set_tbl_size = count;
-
-	rc = of_property_read_u32_array(of_node, "qcom,gpio-set-tbl-num",
-		val_array, count);
-	if (rc < 0) {
-		pr_err("%s failed %d\n", __func__, __LINE__);
-		goto ERROR2;
-	}
-	for (i = 0; i < count; i++) {
-		if (val_array[i] >= gpio_array_size) {
-			pr_err("%s gpio set tbl index %d invalid\n",
-				__func__, val_array[i]);
-			return -EINVAL;
-		}
-		gconf->cam_gpio_set_tbl[i].gpio = gpio_array[val_array[i]];
-		CDBG("%s cam_gpio_set_tbl[%d].gpio = %d\n", __func__, i,
-			gconf->cam_gpio_set_tbl[i].gpio);
-	}
-
-	rc = of_property_read_u32_array(of_node, "qcom,gpio-set-tbl-flags",
-		val_array, count);
-	if (rc < 0) {
-		pr_err("%s failed %d\n", __func__, __LINE__);
-		goto ERROR2;
-	}
-	for (i = 0; i < count; i++) {
-		gconf->cam_gpio_set_tbl[i].flags = val_array[i];
-		CDBG("%s cam_gpio_set_tbl[%d].flags = %ld\n", __func__, i,
-			gconf->cam_gpio_set_tbl[i].flags);
-	}
-
-	rc = of_property_read_u32_array(of_node, "qcom,gpio-set-tbl-delay",
-		val_array, count);
-	if (rc < 0) {
-		pr_err("%s failed %d\n", __func__, __LINE__);
-		goto ERROR2;
-	}
-	for (i = 0; i < count; i++) {
-		gconf->cam_gpio_set_tbl[i].delay = val_array[i];
-		CDBG("%s cam_gpio_set_tbl[%d].delay = %d\n", __func__, i,
-			gconf->cam_gpio_set_tbl[i].delay);
-	}
-
-	kfree(val_array);
-	return rc;
-
-ERROR2:
-	kfree(gconf->cam_gpio_set_tbl);
-ERROR1:
-	kfree(val_array);
-	gconf->cam_gpio_set_tbl_size = 0;
-	return rc;
-}
-
-int32_t msm_sensor_init_gpio_pin_tbl(struct device_node *of_node,
-	struct msm_camera_gpio_conf *gconf, uint16_t *gpio_array,
-	uint16_t gpio_array_size)
-{
-	int32_t rc = 0;
-	int32_t val = 0;
-
-	gconf->gpio_num_info = kzalloc(sizeof(struct msm_camera_gpio_num_info),
-		GFP_KERNEL);
-	if (!gconf->gpio_num_info) {
-		pr_err("%s failed %d\n", __func__, __LINE__);
-		rc = -ENOMEM;
-		return rc;
-	}
-
-	if (of_property_read_bool(of_node, "qcom,gpio-reset") == true) {
-		rc = of_property_read_u32(of_node, "qcom,gpio-reset", &val);
-		if (rc < 0) {
-			pr_err("%s:%d read qcom,gpio-reset failed rc %d\n",
-				__func__, __LINE__, rc);
-			goto ERROR;
-		} else if (val >= gpio_array_size) {
-			pr_err("%s:%d qcom,gpio-reset invalid %d\n",
-				__func__, __LINE__, val);
-			goto ERROR;
-		}
-		gconf->gpio_num_info->gpio_num[SENSOR_GPIO_RESET] =
-			gpio_array[val];
-		CDBG("%s qcom,gpio-reset %d\n", __func__,
-			gconf->gpio_num_info->gpio_num[SENSOR_GPIO_RESET]);
-	}
-
-	if (of_property_read_bool(of_node, "qcom,gpio-standby") == true) {
-		rc = of_property_read_u32(of_node, "qcom,gpio-standby", &val);
-		if (rc < 0) {
-			pr_err("%s:%d read qcom,gpio-standby failed rc %d\n",
-				__func__, __LINE__, rc);
-			goto ERROR;
-		} else if (val >= gpio_array_size) {
-			pr_err("%s:%d qcom,gpio-standby invalid %d\n",
-				__func__, __LINE__, val);
-			goto ERROR;
-		}
-		gconf->gpio_num_info->gpio_num[SENSOR_GPIO_STANDBY] =
-			gpio_array[val];
-		CDBG("%s qcom,gpio-reset %d\n", __func__,
-			gconf->gpio_num_info->gpio_num[SENSOR_GPIO_STANDBY]);
-	}
-
-	rc = of_property_read_u32(of_node, "qcom,gpio-vio", &val);
-	if (!rc) {
-		if (val >= gpio_array_size) {
-			pr_err("%s:%d qcom,gpio-vio invalid %d\n",
-				__func__, __LINE__, val);
-			goto ERROR;
-		}
-		gconf->gpio_num_info->gpio_num[SENSOR_GPIO_VIO] =
-			gpio_array[val];
-		CDBG("%s qcom,gpio-vio %d\n", __func__,
-			gconf->gpio_num_info->gpio_num[SENSOR_GPIO_VIO]);
-	} else if (rc != -EINVAL) {
-		pr_err("%s:%d read qcom,gpio-vio failed rc %d\n",
-			__func__, __LINE__, rc);
-		goto ERROR;
-	}
-
-	rc = of_property_read_u32(of_node, "qcom,gpio-vana", &val);
-	if (!rc) {
-		if (val >= gpio_array_size) {
-			pr_err("%s:%d qcom,gpio-vana invalid %d\n",
-				__func__, __LINE__, val);
-			goto ERROR;
-		}
-		gconf->gpio_num_info->gpio_num[SENSOR_GPIO_VANA] =
-			gpio_array[val];
-		CDBG("%s qcom,gpio-vana %d\n", __func__,
-			gconf->gpio_num_info->gpio_num[SENSOR_GPIO_VANA]);
-	} else if (rc != -EINVAL) {
-		pr_err("%s:%d read qcom,gpio-vana failed rc %d\n",
-			__func__, __LINE__, rc);
-		goto ERROR;
-	}
-
-	rc = of_property_read_u32(of_node, "qcom,gpio-vdig", &val);
-	if (!rc) {
-		if (val >= gpio_array_size) {
-			pr_err("%s:%d qcom,gpio-vdig invalid %d\n",
-				__func__, __LINE__, val);
-			goto ERROR;
-		}
-		gconf->gpio_num_info->gpio_num[SENSOR_GPIO_VDIG] =
-			gpio_array[val];
-		CDBG("%s qcom,gpio-vdig %d\n", __func__,
-			gconf->gpio_num_info->gpio_num[SENSOR_GPIO_VDIG]);
-	} else if (rc != -EINVAL) {
-		pr_err("%s:%d read qcom,gpio-vdig failed rc %d\n",
-			__func__, __LINE__, rc);
-		goto ERROR;
-	}
-
-	rc = of_property_read_u32(of_node, "qcom,gpio-vaf", &val);
-	if (!rc) {
-		if (val >= gpio_array_size) {
-			pr_err("%s:%d qcom,gpio-vaf invalid %d\n",
-				__func__, __LINE__, val);
-			goto ERROR;
-		}
-		gconf->gpio_num_info->gpio_num[SENSOR_GPIO_VAF] =
-			gpio_array[val];
-		CDBG("%s qcom,gpio-vaf %d\n", __func__,
-			gconf->gpio_num_info->gpio_num[SENSOR_GPIO_VAF]);
-	} else if (rc != -EINVAL) {
-		pr_err("%s:%d read qcom,gpio-vaf failed rc %d\n",
-			__func__, __LINE__, rc);
-		goto ERROR;
-	}
-
-	rc = of_property_read_u32(of_node, "qcom,gpio-af-pwdm", &val);
-	if (!rc) {
-		if (val >= gpio_array_size) {
-			pr_err("%s:%d qcom,gpio-af-pwdm invalid %d\n",
-				__func__, __LINE__, val);
-			goto ERROR;
-		}
-		gconf->gpio_num_info->gpio_num[SENSOR_GPIO_AF_PWDM] =
-			gpio_array[val];
-		CDBG("%s qcom,gpio-af-pwdm %d\n", __func__,
-			gconf->gpio_num_info->gpio_num[SENSOR_GPIO_AF_PWDM]);
-	} else if (rc != -EINVAL) {
-		pr_err("%s:%d read qcom,gpio-af-pwdm failed rc %d\n",
-			__func__, __LINE__, rc);
-		goto ERROR;
-	}
-	return 0;
-
-ERROR:
-	kfree(gconf->gpio_num_info);
-	gconf->gpio_num_info = NULL;
-	return rc;
-}
-
-static int32_t msm_sensor_get_dt_actuator_data(struct device_node *of_node,
-	struct  msm_camera_sensor_board_info *sensordata)
-{
-	int32_t rc = 0;
-	uint32_t val = 0;
-
-	rc = of_property_read_u32(of_node, "qcom,actuator-cam-name", &val);
-	CDBG("%s qcom,actuator-cam-name %d, rc %d\n", __func__, val, rc);
-	if (rc < 0)
-		return 0;
-
-	sensordata->actuator_info = kzalloc(sizeof(struct msm_actuator_info),
-		GFP_KERNEL);
-	if (!sensordata->actuator_info) {
-		pr_err("%s failed %d\n", __func__, __LINE__);
-		rc = -ENOMEM;
-		goto ERROR;
-	}
-
-	sensordata->actuator_info->cam_name = val;
-
-	rc = of_property_read_u32(of_node, "qcom,actuator-vcm-pwd", &val);
-	CDBG("%s qcom,actuator-vcm-pwd %d, rc %d\n", __func__, val, rc);
-	if (!rc)
-		sensordata->actuator_info->vcm_pwd = val;
-
-	rc = of_property_read_u32(of_node, "qcom,actuator-vcm-enable", &val);
-	CDBG("%s qcom,actuator-vcm-enable %d, rc %d\n", __func__, val, rc);
-	if (!rc)
-		sensordata->actuator_info->vcm_enable = val;
-
 	return 0;
-ERROR:
+FREE_UP:
+	kfree(power_info->power_setting);
+FAILED_1:
 	return rc;
 }
 
@@ -718,48 +121,13 @@
 
 	sensordata = s_ctrl->sensordata;
 
-	sensordata->sensor_init_params = kzalloc(sizeof(
-		struct msm_sensor_init_params), GFP_KERNEL);
-	if (!sensordata->sensor_init_params) {
-		pr_err("%s failed %d\n", __func__, __LINE__);
-		return -ENOMEM;
-	}
-
 	rc = of_property_read_string(of_node, "qcom,sensor-name",
 		&sensordata->sensor_name);
 	CDBG("%s qcom,sensor-name %s, rc %d\n", __func__,
 		sensordata->sensor_name, rc);
 	if (rc < 0) {
 		pr_err("%s failed %d\n", __func__, __LINE__);
-		goto ERROR1;
-	}
-
-	rc = of_property_read_u32(of_node, "qcom,sensor-mode",
-		&sensordata->sensor_init_params->modes_supported);
-	CDBG("%s qcom,sensor-mode %d, rc %d\n", __func__,
-		sensordata->sensor_init_params->modes_supported, rc);
-	if (rc < 0) {
-		pr_err("%s failed %d\n", __func__, __LINE__);
-		goto ERROR1;
-	}
-
-	rc = of_property_read_u32(of_node, "qcom,sensor-position",
-		&sensordata->sensor_init_params->position);
-	CDBG("%s qcom,sensor-position %d, rc %d\n", __func__,
-		sensordata->sensor_init_params->position, rc);
-	if (rc < 0) {
-		pr_err("%s failed %d\n", __func__, __LINE__);
-		goto ERROR1;
-	}
-
-	rc = of_property_read_u32(of_node, "qcom,mount-angle",
-		&sensordata->sensor_init_params->sensor_mount_angle);
-	CDBG("%s qcom,mount-angle %d, rc %d\n", __func__,
-		sensordata->sensor_init_params->sensor_mount_angle, rc);
-	if (rc < 0) {
-		/* Set default mount angle */
-		sensordata->sensor_init_params->sensor_mount_angle = 0;
-		rc = 0;
+		goto FREE_SENSORDATA;
 	}
 
 	rc = of_property_read_u32(of_node, "qcom,cci-master",
@@ -772,32 +140,88 @@
 		rc = 0;
 	}
 
-	rc = msm_sensor_get_sub_module_index(of_node, sensordata);
+	rc = msm_sensor_get_sub_module_index(of_node, &sensordata->sensor_info);
 	if (rc < 0) {
 		pr_err("%s failed %d\n", __func__, __LINE__);
-		goto ERROR1;
+		goto FREE_SENSORDATA;
 	}
 
-	rc = msm_sensor_get_dt_csi_data(of_node, sensordata);
+	/* Get sensor mount angle */
+	rc = of_property_read_u32(of_node, "qcom,mount-angle",
+		&sensordata->sensor_info->sensor_mount_angle);
+	CDBG("%s qcom,mount-angle %d, rc %d\n", __func__,
+		sensordata->sensor_info->sensor_mount_angle, rc);
+	if (rc < 0) {
+		/* Invalidate mount angle flag */
+		pr_err("%s Default sensor mount angle %d\n",
+					__func__, __LINE__);
+		sensordata->sensor_info->is_mount_angle_valid = 0;
+		sensordata->sensor_info->sensor_mount_angle = 0;
+		rc = 0;
+	} else {
+		sensordata->sensor_info->is_mount_angle_valid = 1;
+	}
+
+	rc = of_property_read_u32(of_node, "qcom,sensor-position",
+		&sensordata->sensor_info->position);
+	CDBG("%s qcom,sensor-position %d, rc %d\n", __func__,
+		sensordata->sensor_info->position, rc);
+	if (rc < 0) {
+		pr_err("%s Default sensor position %d\n", __func__, __LINE__);
+		sensordata->sensor_info->position = 0;
+		rc = 0;
+	}
+
+	rc = of_property_read_u32(of_node, "qcom,sensor-mode",
+		&sensordata->sensor_info->modes_supported);
+	CDBG("%s qcom,sensor-mode %d, rc %d\n", __func__,
+		sensordata->sensor_info->modes_supported, rc);
+	if (rc < 0) {
+		pr_err("%s Default sensor mode %d\n", __func__, __LINE__);
+		sensordata->sensor_info->modes_supported = 0;
+		rc = 0;
+	}
+
+	rc = msm_sensor_get_dt_csi_data(of_node, &sensordata->csi_lane_params);
 	if (rc < 0) {
 		pr_err("%s failed %d\n", __func__, __LINE__);
-		goto ERROR1;
+		goto FREE_SENSOR_INFO;
 	}
 
-	rc = msm_sensor_get_dt_vreg_data(of_node, sensordata);
+	rc = msm_camera_get_dt_vreg_data(of_node,
+			&sensordata->power_info.cam_vreg,
+			&sensordata->power_info.num_vreg);
+	if (rc < 0)
+		goto FREE_CSI;
+
+	rc = msm_camera_get_dt_power_setting_data(of_node,
+			sensordata->power_info.cam_vreg,
+			sensordata->power_info.num_vreg,
+			&sensordata->power_info);
+
+
 	if (rc < 0) {
 		pr_err("%s failed %d\n", __func__, __LINE__);
-		goto ERROR2;
+		goto FREE_VREG;
 	}
 
-	sensordata->gpio_conf = kzalloc(sizeof(struct msm_camera_gpio_conf),
-		GFP_KERNEL);
-	if (!sensordata->gpio_conf) {
+
+	rc = msm_camera_get_power_settimgs_from_sensor_lib(
+			&sensordata->power_info,
+			&s_ctrl->power_setting_array);
+	if (rc < 0) {
+		pr_err("%s failed %d\n", __func__, __LINE__);
+		goto FREE_VREG;
+	}
+
+	sensordata->power_info.gpio_conf = kzalloc(
+			sizeof(struct msm_camera_gpio_conf), GFP_KERNEL);
+	if (!sensordata->power_info.gpio_conf) {
 		pr_err("%s failed %d\n", __func__, __LINE__);
 		rc = -ENOMEM;
-		goto ERROR3;
+		goto FREE_PS;
 	}
-	gconf = sensordata->gpio_conf;
+	gconf = sensordata->power_info.gpio_conf;
 
 	gpio_array_size = of_gpio_count(of_node);
 	CDBG("%s gpio count %d\n", __func__, gpio_array_size);
@@ -807,7 +231,7 @@
 			GFP_KERNEL);
 		if (!gpio_array) {
 			pr_err("%s failed %d\n", __func__, __LINE__);
-			goto ERROR4;
+			goto FREE_GPIO_CONF;
 		}
 		for (i = 0; i < gpio_array_size; i++) {
 			gpio_array[i] = of_get_gpio(of_node, i);
@@ -815,31 +239,32 @@
 				gpio_array[i]);
 		}
 
-		rc = msm_sensor_get_dt_gpio_req_tbl(of_node, gconf,
+		rc = msm_camera_get_dt_gpio_req_tbl(of_node, gconf,
 			gpio_array, gpio_array_size);
 		if (rc < 0) {
 			pr_err("%s failed %d\n", __func__, __LINE__);
-			goto ERROR4;
+			goto FREE_GPIO_CONF;
 		}
 
-		rc = msm_sensor_get_dt_gpio_set_tbl(of_node, gconf,
+		rc = msm_camera_get_dt_gpio_set_tbl(of_node, gconf,
 			gpio_array, gpio_array_size);
 		if (rc < 0) {
 			pr_err("%s failed %d\n", __func__, __LINE__);
-			goto ERROR5;
+			goto FREE_GPIO_REQ_TBL;
 		}
 
-		rc = msm_sensor_init_gpio_pin_tbl(of_node, gconf,
+		rc = msm_camera_init_gpio_pin_tbl(of_node, gconf,
 			gpio_array, gpio_array_size);
 		if (rc < 0) {
 			pr_err("%s failed %d\n", __func__, __LINE__);
-			goto ERROR6;
+			goto FREE_GPIO_SET_TBL;
 		}
 	}
-	rc = msm_sensor_get_dt_actuator_data(of_node, sensordata);
+	rc = msm_sensor_get_dt_actuator_data(of_node,
+					     &sensordata->actuator_info);
 	if (rc < 0) {
 		pr_err("%s failed %d\n", __func__, __LINE__);
-		goto ERROR7;
+		goto FREE_GPIO_PIN_TBL;
 	}
 
 	sensordata->slave_info = kzalloc(sizeof(struct msm_camera_slave_info),
@@ -847,19 +272,23 @@
 	if (!sensordata->slave_info) {
 		pr_err("%s failed %d\n", __func__, __LINE__);
 		rc = -ENOMEM;
-		goto ERROR8;
+		goto FREE_ACTUATOR_INFO;
 	}
 
 	rc = of_property_read_u32_array(of_node, "qcom,slave-id",
 		id_info, 3);
 	if (rc < 0) {
 		pr_err("%s failed %d\n", __func__, __LINE__);
-		goto ERROR9;
+		goto FREE_SLAVE_INFO;
 	}
 
 	sensordata->slave_info->sensor_slave_addr = id_info[0];
 	sensordata->slave_info->sensor_id_reg_addr = id_info[1];
 	sensordata->slave_info->sensor_id = id_info[2];
+	CDBG("%s:%d slave addr %x sensor reg %x id %x\n", __func__, __LINE__,
+		sensordata->slave_info->sensor_slave_addr,
+		sensordata->slave_info->sensor_id_reg_addr,
+		sensordata->slave_info->sensor_id);
 
 	/*Optional property, don't return error if absent */
 	ret = of_property_read_string(of_node, "qcom,vdd-cx-name",
@@ -871,23 +300,28 @@
 
 	return rc;
 
-ERROR9:
+FREE_SLAVE_INFO:
 	kfree(s_ctrl->sensordata->slave_info);
-ERROR8:
+FREE_ACTUATOR_INFO:
 	kfree(s_ctrl->sensordata->actuator_info);
-ERROR7:
-	kfree(s_ctrl->sensordata->gpio_conf->gpio_num_info);
-ERROR6:
-	kfree(s_ctrl->sensordata->gpio_conf->cam_gpio_set_tbl);
-ERROR5:
-	kfree(s_ctrl->sensordata->gpio_conf->cam_gpio_req_tbl);
-ERROR4:
-	kfree(s_ctrl->sensordata->gpio_conf);
-ERROR3:
-	kfree(s_ctrl->sensordata->cam_vreg);
-ERROR2:
+FREE_GPIO_PIN_TBL:
+	kfree(s_ctrl->sensordata->power_info.gpio_conf->gpio_num_info);
+FREE_GPIO_SET_TBL:
+	kfree(s_ctrl->sensordata->power_info.gpio_conf->cam_gpio_set_tbl);
+FREE_GPIO_REQ_TBL:
+	kfree(s_ctrl->sensordata->power_info.gpio_conf->cam_gpio_req_tbl);
+FREE_GPIO_CONF:
+	kfree(s_ctrl->sensordata->power_info.gpio_conf);
+FREE_PS:
+	kfree(s_ctrl->sensordata->power_info.power_setting);
+	kfree(s_ctrl->sensordata->power_info.power_down_setting);
+FREE_VREG:
+	kfree(s_ctrl->sensordata->power_info.cam_vreg);
+FREE_CSI:
 	kfree(s_ctrl->sensordata->csi_lane_params);
-ERROR1:
+FREE_SENSOR_INFO:
+	kfree(s_ctrl->sensordata->sensor_info);
+FREE_SENSORDATA:
 	kfree(s_ctrl->sensordata);
 	kfree(gpio_array);
 	return rc;
@@ -930,20 +364,21 @@
 
 int32_t msm_sensor_free_sensor_data(struct msm_sensor_ctrl_t *s_ctrl)
 {
-	if (!s_ctrl->pdev)
+	if (!s_ctrl->pdev && !s_ctrl->sensor_i2c_client->client)
 		return 0;
 	kfree(s_ctrl->sensordata->slave_info);
+	kfree(s_ctrl->sensordata->cam_slave_info);
 	kfree(s_ctrl->sensordata->actuator_info);
-	kfree(s_ctrl->sensordata->gpio_conf->gpio_num_info);
-	kfree(s_ctrl->sensordata->gpio_conf->cam_gpio_set_tbl);
-	kfree(s_ctrl->sensordata->gpio_conf->cam_gpio_req_tbl);
-	kfree(s_ctrl->sensordata->gpio_conf);
-	kfree(s_ctrl->sensordata->cam_vreg);
+	kfree(s_ctrl->sensordata->power_info.gpio_conf->gpio_num_info);
+	kfree(s_ctrl->sensordata->power_info.gpio_conf->cam_gpio_set_tbl);
+	kfree(s_ctrl->sensordata->power_info.gpio_conf->cam_gpio_req_tbl);
+	kfree(s_ctrl->sensordata->power_info.gpio_conf);
+	kfree(s_ctrl->sensordata->power_info.cam_vreg);
+	kfree(s_ctrl->sensordata->power_info.power_setting);
 	kfree(s_ctrl->sensordata->csi_lane_params);
 	kfree(s_ctrl->sensordata->sensor_info);
-	kfree(s_ctrl->sensordata->sensor_init_params);
+	kfree(s_ctrl->sensordata->power_info.clk_info);
 	kfree(s_ctrl->sensordata);
-	kfree(s_ctrl->clk_info);
 	return 0;
 }
 
@@ -961,268 +396,105 @@
 	[SENSOR_CAM_CLK] = {"cam_clk", 0},
 };
 
-int32_t msm_sensor_power_up(struct msm_sensor_ctrl_t *s_ctrl)
+int msm_sensor_power_down(struct msm_sensor_ctrl_t *s_ctrl)
 {
-	int32_t rc = 0, index = 0;
-	struct msm_sensor_power_setting_array *power_setting_array = NULL;
-	struct msm_sensor_power_setting *power_setting = NULL;
-	struct msm_camera_sensor_board_info *data = s_ctrl->sensordata;
-	s_ctrl->stop_setting_valid = 0;
+	struct msm_camera_power_ctrl_t *power_info;
+	enum msm_camera_device_type_t sensor_device_type;
+	struct msm_camera_i2c_client *sensor_i2c_client;
 
-	CDBG("%s:%d\n", __func__, __LINE__);
-	power_setting_array = &s_ctrl->power_setting_array;
-
-	if (data->gpio_conf->cam_gpiomux_conf_tbl != NULL) {
-		pr_err("%s:%d mux install\n", __func__, __LINE__);
-		msm_gpiomux_install(
-			(struct msm_gpiomux_config *)
-			data->gpio_conf->cam_gpiomux_conf_tbl,
-			data->gpio_conf->cam_gpiomux_conf_tbl_size);
+	if (!s_ctrl) {
+		pr_err("%s:%d failed: s_ctrl %p\n",
+			__func__, __LINE__, s_ctrl);
+		return -EINVAL;
 	}
 
-	rc = msm_camera_request_gpio_table(
-		data->gpio_conf->cam_gpio_req_tbl,
-		data->gpio_conf->cam_gpio_req_tbl_size, 1);
-	if (rc < 0) {
-		pr_err("%s: request gpio failed\n", __func__);
+	power_info = &s_ctrl->sensordata->power_info;
+	sensor_device_type = s_ctrl->sensor_device_type;
+	sensor_i2c_client = s_ctrl->sensor_i2c_client;
+
+	if (!power_info || !sensor_i2c_client) {
+		pr_err("%s:%d failed: power_info %p sensor_i2c_client %p\n",
+			__func__, __LINE__, power_info, sensor_i2c_client);
+		return -EINVAL;
+	}
+	return msm_camera_power_down(power_info, sensor_device_type,
+		sensor_i2c_client);
+}
+
+int msm_sensor_power_up(struct msm_sensor_ctrl_t *s_ctrl)
+{
+	int rc;
+	struct msm_camera_power_ctrl_t *power_info;
+	struct msm_camera_i2c_client *sensor_i2c_client;
+	struct msm_camera_slave_info *slave_info;
+	const char *sensor_name;
+
+	if (!s_ctrl) {
+		pr_err("%s:%d failed: %p\n",
+			__func__, __LINE__, s_ctrl);
+		return -EINVAL;
+	}
+
+	power_info = &s_ctrl->sensordata->power_info;
+	sensor_i2c_client = s_ctrl->sensor_i2c_client;
+	slave_info = s_ctrl->sensordata->slave_info;
+	sensor_name = s_ctrl->sensordata->sensor_name;
+
+	if (!power_info || !sensor_i2c_client || !slave_info ||
+		!sensor_name) {
+		pr_err("%s:%d failed: %p %p %p %p\n",
+			__func__, __LINE__, power_info,
+			sensor_i2c_client, slave_info, sensor_name);
+		return -EINVAL;
+	}
+
+	rc = msm_camera_power_up(power_info, s_ctrl->sensor_device_type,
+		sensor_i2c_client);
+	if (rc < 0)
 		return rc;
-	}
-	for (index = 0; index < power_setting_array->size; index++) {
-		CDBG("%s index %d\n", __func__, index);
-		power_setting = &power_setting_array->power_setting[index];
-		CDBG("%s type %d\n", __func__, power_setting->seq_type);
-		switch (power_setting->seq_type) {
-		case SENSOR_CLK:
-			if (power_setting->seq_val >= s_ctrl->clk_info_size) {
-				pr_err("%s clk index %d >= max %d\n", __func__,
-					power_setting->seq_val,
-					s_ctrl->clk_info_size);
-				goto power_up_failed;
-			}
-			if (power_setting->config_val)
-				s_ctrl->clk_info[power_setting->seq_val].
-					clk_rate = power_setting->config_val;
+	rc = msm_sensor_check_id(s_ctrl);
+	if (rc < 0)
+		msm_camera_power_down(power_info, s_ctrl->sensor_device_type,
+					sensor_i2c_client);
 
-			rc = msm_cam_clk_enable(s_ctrl->dev,
-				&s_ctrl->clk_info[0],
-				(struct clk **)&power_setting->data[0],
-				s_ctrl->clk_info_size,
-				1);
-			if (rc < 0) {
-				pr_err("%s: clk enable failed\n",
-					__func__);
-				goto power_up_failed;
-			}
-			break;
-		case SENSOR_GPIO:
-			if (power_setting->seq_val >= SENSOR_GPIO_MAX ||
-				!data->gpio_conf->gpio_num_info) {
-				pr_err("%s gpio index %d >= max %d\n", __func__,
-					power_setting->seq_val,
-					SENSOR_GPIO_MAX);
-				goto power_up_failed;
-			}
-			pr_debug("%s:%d gpio set val %d\n", __func__, __LINE__,
-				data->gpio_conf->gpio_num_info->gpio_num
-				[power_setting->seq_val]);
-			gpio_set_value_cansleep(
-				data->gpio_conf->gpio_num_info->gpio_num
-				[power_setting->seq_val],
-				power_setting->config_val);
-			break;
-		case SENSOR_VREG:
-			if (power_setting->seq_val >= CAM_VREG_MAX) {
-				pr_err("%s vreg index %d >= max %d\n", __func__,
-					power_setting->seq_val,
-					SENSOR_GPIO_MAX);
-				goto power_up_failed;
-			}
-			msm_camera_config_single_vreg(s_ctrl->dev,
-				&data->cam_vreg[power_setting->seq_val],
-				(struct regulator **)&power_setting->data[0],
-				1);
-			break;
-		case SENSOR_I2C_MUX:
-			if (data->i2c_conf && data->i2c_conf->use_i2c_mux)
-				msm_sensor_enable_i2c_mux(data->i2c_conf);
-			break;
-		default:
-			pr_err("%s error power seq type %d\n", __func__,
-				power_setting->seq_type);
-			break;
-		}
-		if (power_setting->delay > 20) {
-			msleep(power_setting->delay);
-		} else if (power_setting->delay) {
-			usleep_range(power_setting->delay * 1000,
-				(power_setting->delay * 1000) + 1000);
-		}
-	}
-
-	if (s_ctrl->sensor_device_type == MSM_CAMERA_PLATFORM_DEVICE) {
-		rc = s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_util(
-			s_ctrl->sensor_i2c_client, MSM_CCI_INIT);
-		if (rc < 0) {
-			pr_err("%s cci_init failed\n", __func__);
-			goto power_up_failed;
-		}
-	}
-
-	if (s_ctrl->func_tbl->sensor_match_id)
-		rc = s_ctrl->func_tbl->sensor_match_id(s_ctrl);
-	else
-		rc = msm_sensor_match_id(s_ctrl);
-	if (rc < 0) {
-		pr_err("%s:%d match id failed rc %d\n", __func__, __LINE__, rc);
-		goto power_up_failed;
-	}
-
-	CDBG("%s exit\n", __func__);
-	return 0;
-power_up_failed:
-	pr_err("%s:%d failed\n", __func__, __LINE__);
-	if (s_ctrl->sensor_device_type == MSM_CAMERA_PLATFORM_DEVICE) {
-		s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_util(
-			s_ctrl->sensor_i2c_client, MSM_CCI_RELEASE);
-	}
-
-	for (index--; index >= 0; index--) {
-		CDBG("%s index %d\n", __func__, index);
-		power_setting = &power_setting_array->power_setting[index];
-		CDBG("%s type %d\n", __func__, power_setting->seq_type);
-		switch (power_setting->seq_type) {
-		case SENSOR_CLK:
-			msm_cam_clk_enable(s_ctrl->dev,
-				&s_ctrl->clk_info[0],
-				(struct clk **)&power_setting->data[0],
-				s_ctrl->clk_info_size,
-				0);
-			break;
-		case SENSOR_GPIO:
-			gpio_set_value_cansleep(
-				data->gpio_conf->gpio_num_info->gpio_num
-				[power_setting->seq_val], GPIOF_OUT_INIT_LOW);
-			break;
-		case SENSOR_VREG:
-			msm_camera_config_single_vreg(s_ctrl->dev,
-				&data->cam_vreg[power_setting->seq_val],
-				(struct regulator **)&power_setting->data[0],
-				0);
-			break;
-		case SENSOR_I2C_MUX:
-			if (data->i2c_conf && data->i2c_conf->use_i2c_mux)
-				msm_sensor_disable_i2c_mux(data->i2c_conf);
-			break;
-		default:
-			pr_err("%s error power seq type %d\n", __func__,
-				power_setting->seq_type);
-			break;
-		}
-		if (power_setting->delay > 20) {
-			msleep(power_setting->delay);
-		} else if (power_setting->delay) {
-			usleep_range(power_setting->delay * 1000,
-				(power_setting->delay * 1000) + 1000);
-		}
-	}
-	msm_camera_request_gpio_table(
-		data->gpio_conf->cam_gpio_req_tbl,
-		data->gpio_conf->cam_gpio_req_tbl_size, 0);
 	return rc;
 }
 
-int32_t msm_sensor_power_down(struct msm_sensor_ctrl_t *s_ctrl)
+int msm_sensor_match_id(struct msm_sensor_ctrl_t *s_ctrl)
 {
-	int32_t index = 0;
-	struct msm_sensor_power_setting_array *power_setting_array = NULL;
-	struct msm_sensor_power_setting *power_setting = NULL;
-	struct msm_camera_sensor_board_info *data = s_ctrl->sensordata;
-	s_ctrl->stop_setting_valid = 0;
-
-	CDBG("%s:%d\n", __func__, __LINE__);
-	power_setting_array = &s_ctrl->power_setting_array;
-
-	if (s_ctrl->sensor_device_type == MSM_CAMERA_PLATFORM_DEVICE) {
-		s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_util(
-			s_ctrl->sensor_i2c_client, MSM_CCI_RELEASE);
-	}
-
-	for (index = (power_setting_array->size - 1); index >= 0; index--) {
-		CDBG("%s index %d\n", __func__, index);
-		power_setting = &power_setting_array->power_setting[index];
-		CDBG("%s type %d\n", __func__, power_setting->seq_type);
-		switch (power_setting->seq_type) {
-		case SENSOR_CLK:
-			msm_cam_clk_enable(s_ctrl->dev,
-				&s_ctrl->clk_info[0],
-				(struct clk **)&power_setting->data[0],
-				s_ctrl->clk_info_size,
-				0);
-			break;
-		case SENSOR_GPIO:
-			if (power_setting->seq_val >= SENSOR_GPIO_MAX ||
-				!data->gpio_conf->gpio_num_info) {
-				pr_err("%s gpio index %d >= max %d\n", __func__,
-					power_setting->seq_val,
-					SENSOR_GPIO_MAX);
-				continue;
-			}
-			gpio_set_value_cansleep(
-				data->gpio_conf->gpio_num_info->gpio_num
-				[power_setting->seq_val], GPIOF_OUT_INIT_LOW);
-			break;
-		case SENSOR_VREG:
-			if (power_setting->seq_val >= CAM_VREG_MAX) {
-				pr_err("%s vreg index %d >= max %d\n", __func__,
-					power_setting->seq_val,
-					SENSOR_GPIO_MAX);
-				continue;
-			}
-			msm_camera_config_single_vreg(s_ctrl->dev,
-				&data->cam_vreg[power_setting->seq_val],
-				(struct regulator **)&power_setting->data[0],
-				0);
-			break;
-		case SENSOR_I2C_MUX:
-			if (data->i2c_conf && data->i2c_conf->use_i2c_mux)
-				msm_sensor_disable_i2c_mux(data->i2c_conf);
-			break;
-		default:
-			pr_err("%s error power seq type %d\n", __func__,
-				power_setting->seq_type);
-			break;
-		}
-		if (power_setting->delay > 20) {
-			msleep(power_setting->delay);
-		} else if (power_setting->delay) {
-			usleep_range(power_setting->delay * 1000,
-				(power_setting->delay * 1000) + 1000);
-		}
-	}
-	msm_camera_request_gpio_table(
-		data->gpio_conf->cam_gpio_req_tbl,
-		data->gpio_conf->cam_gpio_req_tbl_size, 0);
-	CDBG("%s exit\n", __func__);
-	return 0;
-}
-
-int32_t msm_sensor_match_id(struct msm_sensor_ctrl_t *s_ctrl)
-{
-	int32_t rc = 0;
+	int rc = 0;
 	uint16_t chipid = 0;
-	rc = s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_read(
-			s_ctrl->sensor_i2c_client,
-			s_ctrl->sensordata->slave_info->sensor_id_reg_addr,
-			&chipid, MSM_CAMERA_I2C_WORD_DATA);
+	struct msm_camera_i2c_client *sensor_i2c_client;
+	struct msm_camera_slave_info *slave_info;
+	const char *sensor_name;
+
+	if (!s_ctrl) {
+		pr_err("%s:%d failed: %p\n",
+			__func__, __LINE__, s_ctrl);
+		return -EINVAL;
+	}
+	sensor_i2c_client = s_ctrl->sensor_i2c_client;
+	slave_info = s_ctrl->sensordata->slave_info;
+	sensor_name = s_ctrl->sensordata->sensor_name;
+
+	if (!sensor_i2c_client || !slave_info || !sensor_name) {
+		pr_err("%s:%d failed: %p %p %p\n",
+			__func__, __LINE__, sensor_i2c_client, slave_info,
+			sensor_name);
+		return -EINVAL;
+	}
+
+	rc = sensor_i2c_client->i2c_func_tbl->i2c_read(
+		sensor_i2c_client, slave_info->sensor_id_reg_addr,
+		&chipid, MSM_CAMERA_I2C_WORD_DATA);
 	if (rc < 0) {
-		pr_err("%s: %s: read id failed\n", __func__,
-			s_ctrl->sensordata->sensor_name);
+		pr_err("%s: %s: read id failed\n", __func__, sensor_name);
 		return rc;
 	}
 
 	CDBG("%s: read id: %x expected id %x:\n", __func__, chipid,
-		s_ctrl->sensordata->slave_info->sensor_id);
-	if (chipid != s_ctrl->sensordata->slave_info->sensor_id) {
+		slave_info->sensor_id);
+	if (chipid != slave_info->sensor_id) {
 		pr_err("msm_sensor_match_id chip id doesnot match\n");
 		return -ENODEV;
 	}
@@ -1281,12 +553,11 @@
 	}
 }
 
-int32_t msm_sensor_config(struct msm_sensor_ctrl_t *s_ctrl,
-	void __user *argp)
+int msm_sensor_config(struct msm_sensor_ctrl_t *s_ctrl, void __user *argp)
 {
 	struct sensorb_cfg_data *cdata = (struct sensorb_cfg_data *)argp;
 	long rc = 0;
-	int32_t i = 0;
+	int i = 0;
 	mutex_lock(s_ctrl->msm_sensor_mutex);
 	CDBG("%s:%d %s cfgtype = %d\n", __func__, __LINE__,
 		s_ctrl->sensordata->sensor_name, cdata->cfgtype);
@@ -1300,6 +571,14 @@
 		for (i = 0; i < SUB_MODULE_MAX; i++)
 			cdata->cfg.sensor_info.subdev_id[i] =
 				s_ctrl->sensordata->sensor_info->subdev_id[i];
+		cdata->cfg.sensor_info.is_mount_angle_valid =
+			s_ctrl->sensordata->sensor_info->is_mount_angle_valid;
+		cdata->cfg.sensor_info.sensor_mount_angle =
+			s_ctrl->sensordata->sensor_info->sensor_mount_angle;
+		cdata->cfg.sensor_info.position =
+			s_ctrl->sensordata->sensor_info->position;
+		cdata->cfg.sensor_info.modes_supported =
+			s_ctrl->sensordata->sensor_info->modes_supported;
 		CDBG("%s:%d sensor name %s\n", __func__, __LINE__,
 			cdata->cfg.sensor_info.sensor_name);
 		CDBG("%s:%d session id %d\n", __func__, __LINE__,
@@ -1307,11 +586,18 @@
 		for (i = 0; i < SUB_MODULE_MAX; i++)
 			CDBG("%s:%d subdev_id[%d] %d\n", __func__, __LINE__, i,
 				cdata->cfg.sensor_info.subdev_id[i]);
+		CDBG("%s:%d mount angle valid %d value %d\n", __func__,
+			__LINE__, cdata->cfg.sensor_info.is_mount_angle_valid,
+			cdata->cfg.sensor_info.sensor_mount_angle);
 
 		break;
 	case CFG_GET_SENSOR_INIT_PARAMS:
-		cdata->cfg.sensor_init_params =
-			*s_ctrl->sensordata->sensor_init_params;
+		cdata->cfg.sensor_init_params.modes_supported =
+			s_ctrl->sensordata->sensor_info->modes_supported;
+		cdata->cfg.sensor_init_params.position =
+			s_ctrl->sensordata->sensor_info->position;
+		cdata->cfg.sensor_init_params.sensor_mount_angle =
+			s_ctrl->sensordata->sensor_info->sensor_mount_angle;
 		CDBG("%s:%d init params mode %d pos %d mount %d\n", __func__,
 			__LINE__,
 			cdata->cfg.sensor_init_params.modes_supported,
@@ -1320,11 +606,12 @@
 		break;
 	case CFG_SET_SLAVE_INFO: {
 		struct msm_camera_sensor_slave_info sensor_slave_info;
-		struct msm_sensor_power_setting_array *power_setting_array;
-		int slave_index = 0;
+		struct msm_camera_power_ctrl_t *p_ctrl;
+		uint16_t size;
+		int s_index = 0;
 		if (copy_from_user(&sensor_slave_info,
-			(void *)cdata->cfg.setting,
-			sizeof(struct msm_camera_sensor_slave_info))) {
+				(void *)cdata->cfg.setting,
+				sizeof(sensor_slave_info))) {
 			pr_err("%s:%d failed\n", __func__, __LINE__);
 			rc = -EFAULT;
 			break;
@@ -1338,37 +625,34 @@
 		/* Update sensor address type */
 		s_ctrl->sensor_i2c_client->addr_type =
 			sensor_slave_info.addr_type;
+		p_ctrl = &s_ctrl->sensordata->power_info;
 
-		/* Update power up / down sequence */
-		s_ctrl->power_setting_array =
-			sensor_slave_info.power_setting_array;
-		power_setting_array = &s_ctrl->power_setting_array;
-
-		if (!power_setting_array->size) {
-			pr_err("%s:%d failed\n", __func__, __LINE__);
-			rc = -EFAULT;
-			break;
+		/* Update power up sequence */
+		size = sensor_slave_info.power_setting_array.size;
+		if (p_ctrl->power_setting_size < size) {
+			struct msm_sensor_power_setting *tmp;
+			tmp = kmalloc(sizeof(*tmp) * size, GFP_KERNEL);
+			if (!tmp) {
+				pr_err("%s: failed to alloc mem\n", __func__);
+				rc = -ENOMEM;
+				break;
+			}
+			kfree(p_ctrl->power_setting);
+			p_ctrl->power_setting = tmp;
 		}
+		p_ctrl->power_setting_size = size;
 
-		power_setting_array->power_setting = kzalloc(
-			power_setting_array->size *
-			sizeof(struct msm_sensor_power_setting), GFP_KERNEL);
-		if (!power_setting_array->power_setting) {
-			pr_err("%s:%d failed\n", __func__, __LINE__);
-			rc = -ENOMEM;
-			break;
-		}
-		if (copy_from_user(power_setting_array->power_setting,
-			(void *)
+
+		rc = copy_from_user(p_ctrl->power_setting, (void *)
 			sensor_slave_info.power_setting_array.power_setting,
-			power_setting_array->size *
-			sizeof(struct msm_sensor_power_setting))) {
+			size * sizeof(struct msm_sensor_power_setting));
+		if (rc) {
 			pr_err("%s:%d failed\n", __func__, __LINE__);
-			kfree(power_setting_array->power_setting);
+			kfree(sensor_slave_info.power_setting_array.
+				power_setting);
 			rc = -EFAULT;
 			break;
 		}
-		s_ctrl->free_power_setting = true;
 		CDBG("%s sensor id %x\n", __func__,
 			sensor_slave_info.slave_addr);
 		CDBG("%s sensor addr type %d\n", __func__,
@@ -1377,19 +661,62 @@
 			sensor_slave_info.sensor_id_info.sensor_id_reg_addr);
 		CDBG("%s sensor id %x\n", __func__,
 			sensor_slave_info.sensor_id_info.sensor_id);
-		for (slave_index = 0; slave_index <
-			power_setting_array->size; slave_index++) {
-			CDBG("%s i %d power setting %d %d %ld %d\n", __func__,
-				slave_index,
-				power_setting_array->power_setting[slave_index].
-				seq_type,
-				power_setting_array->power_setting[slave_index].
-				seq_val,
-				power_setting_array->power_setting[slave_index].
-				config_val,
-				power_setting_array->power_setting[slave_index].
-				delay);
+		for (s_index = 0; s_index <
+			p_ctrl->power_setting_size; s_index++) {
+			CDBG("%s i %d power up setting %d %d %ld %d\n",
+				__func__,
+				s_index,
+				p_ctrl->power_setting[s_index].seq_type,
+				p_ctrl->power_setting[s_index].seq_val,
+				p_ctrl->power_setting[s_index].config_val,
+				p_ctrl->power_setting[s_index].delay);
 		}
+
+		/* Update power down sequence */
+		if (!sensor_slave_info.power_setting_array.power_down_setting ||
+			0 == size) {
+			pr_err("%s: Missing dedicated power down sequence\n",
+				__func__);
+			break;
+		}
+		size = sensor_slave_info.power_setting_array.size_down;
+
+		if (p_ctrl->power_down_setting_size < size) {
+			struct msm_sensor_power_setting *tmp;
+			tmp = kmalloc(sizeof(*tmp) * size, GFP_KERNEL);
+			if (!tmp) {
+				pr_err("%s: failed to alloc mem\n", __func__);
+				rc = -ENOMEM;
+				break;
+			}
+			kfree(p_ctrl->power_down_setting);
+			p_ctrl->power_down_setting = tmp;
+		}
+		p_ctrl->power_down_setting_size = size;
+
+
+		rc = copy_from_user(p_ctrl->power_down_setting, (void *)
+			sensor_slave_info.power_setting_array.
+			power_down_setting,
+			size * sizeof(struct msm_sensor_power_setting));
+		if (rc) {
+			pr_err("%s:%d failed\n", __func__, __LINE__);
+			kfree(sensor_slave_info.power_setting_array.
+				power_down_setting);
+			rc = -EFAULT;
+			break;
+		}
+		for (s_index = 0; s_index <
+			p_ctrl->power_down_setting_size; s_index++) {
+			CDBG("%s i %d power DOWN setting %d %d %ld %d\n",
+				__func__,
+				s_index,
+				p_ctrl->power_down_setting[s_index].seq_type,
+				p_ctrl->power_down_setting[s_index].seq_val,
+				p_ctrl->power_down_setting[s_index].config_val,
+				p_ctrl->power_down_setting[s_index].delay);
+		}
+
 		break;
 	}
 	case CFG_WRITE_I2C_ARRAY: {
@@ -1653,8 +980,7 @@
 			if (s_ctrl->sensordata->misc_regulator)
 				msm_sensor_misc_regulator(s_ctrl, 0);
 
-			rc = s_ctrl->func_tbl->sensor_power_down(
-				s_ctrl);
+			rc = s_ctrl->func_tbl->sensor_power_down(s_ctrl);
 			if (rc < 0) {
 				pr_err("%s:%d failed rc %ld\n", __func__,
 					__LINE__, rc);
@@ -1679,7 +1005,7 @@
 			rc = -EFAULT;
 			break;
 		}
-		s_ctrl->stop_setting_valid = 1;
+
 		reg_setting = stop_setting->reg_setting;
 
 		if (!stop_setting->size) {
@@ -1717,7 +1043,20 @@
 	return rc;
 }
 
-static int32_t msm_sensor_power(struct v4l2_subdev *sd, int on)
+int msm_sensor_check_id(struct msm_sensor_ctrl_t *s_ctrl)
+{
+	int rc;
+
+	if (s_ctrl->func_tbl->sensor_match_id)
+		rc = s_ctrl->func_tbl->sensor_match_id(s_ctrl);
+	else
+		rc = msm_sensor_match_id(s_ctrl);
+	if (rc < 0)
+		pr_err("%s:%d match id failed rc %d\n", __func__, __LINE__, rc);
+	return rc;
+}
+
+static int msm_sensor_power(struct v4l2_subdev *sd, int on)
 {
 	int rc = 0;
 	struct msm_sensor_ctrl_t *s_ctrl = get_sctrl(sd);
@@ -1726,15 +1065,11 @@
 		s_ctrl->func_tbl->sensor_power_down(s_ctrl);
 		s_ctrl->sensor_state = MSM_SENSOR_POWER_DOWN;
 	}
-	if (s_ctrl->free_power_setting == true) {
-		kfree(s_ctrl->power_setting_array.power_setting);
-		s_ctrl->free_power_setting = false;
-	}
 	mutex_unlock(s_ctrl->msm_sensor_mutex);
 	return rc;
 }
 
-static int32_t msm_sensor_v4l2_enum_fmt(struct v4l2_subdev *sd,
+static int msm_sensor_v4l2_enum_fmt(struct v4l2_subdev *sd,
 	unsigned int index, enum v4l2_mbus_pixelcode *code)
 {
 	struct msm_sensor_ctrl_t *s_ctrl = get_sctrl(sd);
@@ -1792,7 +1127,7 @@
 
 int32_t msm_sensor_platform_probe(struct platform_device *pdev, void *data)
 {
-	int32_t rc = 0;
+	int rc = 0;
 	struct msm_sensor_ctrl_t *s_ctrl =
 		(struct msm_sensor_ctrl_t *)data;
 	struct msm_camera_cci_client *cci_client = NULL;
@@ -1800,7 +1135,6 @@
 	unsigned long mount_pos;
 
 	s_ctrl->pdev = pdev;
-	s_ctrl->dev = &pdev->dev;
 	CDBG("%s called data %p\n", __func__, data);
 	CDBG("%s pdev name %s\n", __func__, pdev->id_entry->name);
 	if (pdev->dev.of_node) {
@@ -1810,6 +1144,7 @@
 			return rc;
 		}
 	}
+	s_ctrl->sensordata->power_info.dev = &pdev->dev;
 	s_ctrl->sensor_device_type = MSM_CAMERA_PLATFORM_DEVICE;
 	s_ctrl->sensor_i2c_client->cci_client = kzalloc(sizeof(
 		struct msm_camera_cci_client), GFP_KERNEL);
@@ -1832,20 +1167,22 @@
 			&msm_sensor_cci_func_tbl;
 	if (!s_ctrl->sensor_v4l2_subdev_ops)
 		s_ctrl->sensor_v4l2_subdev_ops = &msm_sensor_subdev_ops;
-	s_ctrl->clk_info = kzalloc(sizeof(cam_8974_clk_info),
-		GFP_KERNEL);
-	if (!s_ctrl->clk_info) {
+	s_ctrl->sensordata->power_info.clk_info =
+		kzalloc(sizeof(cam_8974_clk_info), GFP_KERNEL);
+	if (!s_ctrl->sensordata->power_info.clk_info) {
 		pr_err("%s:%d failed nomem\n", __func__, __LINE__);
 		kfree(cci_client);
 		return -ENOMEM;
 	}
-	memcpy(s_ctrl->clk_info, cam_8974_clk_info, sizeof(cam_8974_clk_info));
-	s_ctrl->clk_info_size = ARRAY_SIZE(cam_8974_clk_info);
+	memcpy(s_ctrl->sensordata->power_info.clk_info, cam_8974_clk_info,
+		sizeof(cam_8974_clk_info));
+	s_ctrl->sensordata->power_info.clk_info_size =
+		ARRAY_SIZE(cam_8974_clk_info);
 	rc = s_ctrl->func_tbl->sensor_power_up(s_ctrl);
 	if (rc < 0) {
 		pr_err("%s %s power up failed\n", __func__,
 			s_ctrl->sensordata->sensor_name);
-		kfree(s_ctrl->clk_info);
+		kfree(s_ctrl->sensordata->power_info.clk_info);
 		kfree(cci_client);
 		return rc;
 	}
@@ -1864,11 +1201,11 @@
 	s_ctrl->msm_sd.sd.entity.group_id = MSM_CAMERA_SUBDEV_SENSOR;
 	s_ctrl->msm_sd.sd.entity.name =
 		s_ctrl->msm_sd.sd.name;
-	mount_pos = s_ctrl->sensordata->sensor_init_params->position;
-	mount_pos = mount_pos << 8;
+
+	mount_pos = s_ctrl->sensordata->sensor_info->position << 16;
 	mount_pos = mount_pos |
-	(s_ctrl->sensordata->sensor_init_params->sensor_mount_angle / 90);
-	s_ctrl->msm_sd.sd.entity.flags = mount_pos;
+	((s_ctrl->sensordata->sensor_info->sensor_mount_angle / 90) << 8);
+	s_ctrl->msm_sd.sd.entity.flags = mount_pos | MEDIA_ENT_FL_DEFAULT;
 
 	rc = camera_init_v4l2(&s_ctrl->pdev->dev, &session_id);
 	CDBG("%s rc %d session_id %d\n", __func__, rc, session_id);
@@ -1882,7 +1219,7 @@
 	return rc;
 }
 
-int32_t msm_sensor_i2c_probe(struct i2c_client *client,
+int msm_sensor_i2c_probe(struct i2c_client *client,
 	const struct i2c_device_id *id, struct msm_sensor_ctrl_t *s_ctrl)
 {
 	int rc = 0;
@@ -1923,7 +1260,7 @@
 
 	if (s_ctrl->sensor_i2c_client != NULL) {
 		s_ctrl->sensor_i2c_client->client = client;
-		s_ctrl->dev = &client->dev;
+		s_ctrl->sensordata->power_info.dev = &client->dev;
 		if (s_ctrl->sensordata->slave_info->sensor_slave_addr)
 			s_ctrl->sensor_i2c_client->client->addr =
 				s_ctrl->sensordata->slave_info->
@@ -1944,31 +1281,33 @@
 		s_ctrl->sensor_v4l2_subdev_ops = &msm_sensor_subdev_ops;
 
 	if (!client->dev.of_node) {
-		s_ctrl->clk_info = kzalloc(sizeof(cam_8960_clk_info),
-			GFP_KERNEL);
-		if (!s_ctrl->clk_info) {
+		s_ctrl->sensordata->power_info.clk_info =
+			kzalloc(sizeof(cam_8960_clk_info), GFP_KERNEL);
+		if (!s_ctrl->sensordata->power_info.clk_info) {
 			pr_err("%s:%d failed nomem\n", __func__, __LINE__);
 			return -ENOMEM;
 		}
-		memcpy(s_ctrl->clk_info, cam_8960_clk_info,
-			sizeof(cam_8960_clk_info));
-		s_ctrl->clk_info_size = ARRAY_SIZE(cam_8960_clk_info);
+		memcpy(s_ctrl->sensordata->power_info.clk_info,
+			cam_8960_clk_info, sizeof(cam_8960_clk_info));
+		s_ctrl->sensordata->power_info.clk_info_size =
+			ARRAY_SIZE(cam_8960_clk_info);
 	} else {
-		s_ctrl->clk_info = kzalloc(sizeof(cam_8610_clk_info),
-			GFP_KERNEL);
-		if (!s_ctrl->clk_info) {
+		s_ctrl->sensordata->power_info.clk_info =
+			kzalloc(sizeof(cam_8610_clk_info), GFP_KERNEL);
+		if (!s_ctrl->sensordata->power_info.clk_info) {
 			pr_err("%s:%d failed nomem\n", __func__, __LINE__);
 			return -ENOMEM;
 		}
-		memcpy(s_ctrl->clk_info, cam_8610_clk_info,
-			sizeof(cam_8610_clk_info));
-		s_ctrl->clk_info_size = ARRAY_SIZE(cam_8610_clk_info);
+		memcpy(s_ctrl->sensordata->power_info.clk_info,
+			cam_8610_clk_info, sizeof(cam_8610_clk_info));
+		s_ctrl->sensordata->power_info.clk_info_size =
+			ARRAY_SIZE(cam_8610_clk_info);
 	}
 
 	rc = s_ctrl->func_tbl->sensor_power_up(s_ctrl);
 	if (rc < 0) {
 		pr_err("%s %s power up failed\n", __func__, client->name);
-		kfree(s_ctrl->clk_info);
+		kfree(s_ctrl->sensordata->power_info.clk_info);
 		return rc;
 	}
 
@@ -1985,11 +1324,10 @@
 	s_ctrl->msm_sd.sd.entity.name =
 		s_ctrl->msm_sd.sd.name;
 
-	mount_pos = s_ctrl->sensordata->sensor_init_params->position;
-	mount_pos = mount_pos << 8;
+	mount_pos = s_ctrl->sensordata->sensor_info->position << 16;
 	mount_pos = mount_pos |
-	(s_ctrl->sensordata->sensor_init_params->sensor_mount_angle / 90);
-	s_ctrl->msm_sd.sd.entity.flags = mount_pos;
+	((s_ctrl->sensordata->sensor_info->sensor_mount_angle / 90) << 8);
+	s_ctrl->msm_sd.sd.entity.flags = mount_pos | MEDIA_ENT_FL_DEFAULT;
 
 	rc = camera_init_v4l2(&s_ctrl->sensor_i2c_client->client->dev,
 		&session_id);
@@ -2002,3 +1340,77 @@
 	s_ctrl->func_tbl->sensor_power_down(s_ctrl);
 	return rc;
 }
+
+int32_t msm_sensor_init_default_params(struct msm_sensor_ctrl_t *s_ctrl)
+{
+	int32_t                       rc = -ENOMEM;
+	struct msm_camera_cci_client *cci_client = NULL;
+	struct msm_cam_clk_info      *clk_info = NULL;
+
+	/* Validate input parameters */
+	if (!s_ctrl) {
+		pr_err("%s:%d failed: invalid params s_ctrl %p\n", __func__,
+			__LINE__, s_ctrl);
+		return -EINVAL;
+	}
+
+	if (!s_ctrl->sensor_i2c_client) {
+		pr_err("%s:%d failed: invalid params sensor_i2c_client %p\n",
+			__func__, __LINE__, s_ctrl->sensor_i2c_client);
+		return -EINVAL;
+	}
+
+	/* Initialize cci_client */
+	s_ctrl->sensor_i2c_client->cci_client = kzalloc(sizeof(
+		struct msm_camera_cci_client), GFP_KERNEL);
+	if (!s_ctrl->sensor_i2c_client->cci_client) {
+		pr_err("%s:%d failed: no memory cci_client %p\n", __func__,
+			__LINE__, s_ctrl->sensor_i2c_client->cci_client);
+		return -ENOMEM;
+	}
+
+	if (s_ctrl->sensor_device_type == MSM_CAMERA_PLATFORM_DEVICE) {
+		cci_client = s_ctrl->sensor_i2c_client->cci_client;
+
+		/* Get CCI subdev */
+		cci_client->cci_subdev = msm_cci_get_subdev();
+
+		/* Update CCI / I2C function table */
+		if (!s_ctrl->sensor_i2c_client->i2c_func_tbl)
+			s_ctrl->sensor_i2c_client->i2c_func_tbl =
+				&msm_sensor_cci_func_tbl;
+	} else {
+		if (!s_ctrl->sensor_i2c_client->i2c_func_tbl) {
+			CDBG("%s:%d\n", __func__, __LINE__);
+			s_ctrl->sensor_i2c_client->i2c_func_tbl =
+				&msm_sensor_qup_func_tbl;
+		}
+	}
+
+	/* Update function table driven by ioctl */
+	if (!s_ctrl->func_tbl)
+		s_ctrl->func_tbl = &msm_sensor_func_tbl;
+
+	/* Update v4l2 subdev ops table */
+	if (!s_ctrl->sensor_v4l2_subdev_ops)
+		s_ctrl->sensor_v4l2_subdev_ops = &msm_sensor_subdev_ops;
+
+	/* Initialize clock info */
+	clk_info = kzalloc(sizeof(cam_8974_clk_info), GFP_KERNEL);
+	if (!clk_info) {
+		pr_err("%s:%d failed no memory clk_info %p\n", __func__,
+			__LINE__, clk_info);
+		rc = -ENOMEM;
+		goto FREE_CCI_CLIENT;
+	}
+	memcpy(clk_info, cam_8974_clk_info, sizeof(cam_8974_clk_info));
+	s_ctrl->sensordata->power_info.clk_info = clk_info;
+	s_ctrl->sensordata->power_info.clk_info_size =
+		ARRAY_SIZE(cam_8974_clk_info);
+
+	return 0;
+
+FREE_CCI_CLIENT:
+	kfree(cci_client);
+	return rc;
+}
diff --git a/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.h b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.h
index a53d448..0f77567 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.h
+++ b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.h
@@ -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
@@ -30,6 +30,7 @@
 #include <media/msm_cam_sensor.h>
 #include <media/v4l2-subdev.h>
 #include "msm_camera_i2c.h"
+#include "msm_camera_dt_util.h"
 #include "msm_sd.h"
 
 #define DEFINE_MSM_MUTEX(mutexname) \
@@ -44,53 +45,57 @@
 
 struct msm_sensor_fn_t {
 	int (*sensor_config) (struct msm_sensor_ctrl_t *, void __user *);
-	int (*sensor_power_down)
-		(struct msm_sensor_ctrl_t *);
+	int (*sensor_power_down) (struct msm_sensor_ctrl_t *);
 	int (*sensor_power_up) (struct msm_sensor_ctrl_t *);
-	int32_t (*sensor_match_id)(struct msm_sensor_ctrl_t *s_ctrl);
+	int (*sensor_match_id) (struct msm_sensor_ctrl_t *);
 };
 
+
 struct msm_sensor_ctrl_t {
 	struct platform_device *pdev;
-	enum msm_camera_device_type_t sensor_device_type;
-	enum cci_i2c_master_t cci_i2c_master;
-	struct msm_camera_sensor_board_info *sensordata;
-	struct msm_sensor_power_setting_array power_setting_array;
 	struct mutex *msm_sensor_mutex;
 
-	struct msm_camera_i2c_client *sensor_i2c_client;
-	struct device *dev;
-
+	enum msm_camera_device_type_t sensor_device_type;
+	struct msm_camera_sensor_board_info *sensordata;
+	struct msm_sensor_power_setting_array power_setting_array;
+	struct msm_sensor_packed_cfg_t *cfg_override;
 	struct msm_sd_subdev msm_sd;
+	enum cci_i2c_master_t cci_i2c_master;
+
+	struct msm_camera_i2c_client *sensor_i2c_client;
 	struct v4l2_subdev_info *sensor_v4l2_subdev_info;
 	uint8_t sensor_v4l2_subdev_info_size;
 	struct v4l2_subdev_ops *sensor_v4l2_subdev_ops;
 	struct msm_sensor_fn_t *func_tbl;
 	struct msm_camera_i2c_reg_setting stop_setting;
-	bool stop_setting_valid;
-	bool free_power_setting;
-	struct msm_cam_clk_info *clk_info;
-	uint16_t clk_info_size;
 	void *misc_regulator;
 	enum msm_sensor_state_t sensor_state;
+	uint8_t is_probe_succeed;
+	uint32_t id;
+	struct device_node *of_node;
 };
 
-int32_t msm_sensor_config(struct msm_sensor_ctrl_t *s_ctrl,
-			void __user *argp);
+int msm_sensor_config(struct msm_sensor_ctrl_t *s_ctrl, void __user *argp);
 
-int32_t msm_sensor_power_up(struct msm_sensor_ctrl_t *s_ctrl);
+int msm_sensor_power_up(struct msm_sensor_ctrl_t *s_ctrl);
 
-int32_t msm_sensor_power_down(struct msm_sensor_ctrl_t *s_ctrl);
+int msm_sensor_power_down(struct msm_sensor_ctrl_t *s_ctrl);
 
-int32_t msm_sensor_match_id(struct msm_sensor_ctrl_t *s_ctrl);
+int msm_sensor_check_id(struct msm_sensor_ctrl_t *s_ctrl);
+
+int msm_sensor_match_id(struct msm_sensor_ctrl_t *s_ctrl);
 
 int32_t msm_sensor_platform_probe(struct platform_device *pdev,
 	void *data);
 
-int32_t msm_sensor_i2c_probe(struct i2c_client *client,
+int msm_sensor_update_cfg(struct msm_sensor_ctrl_t *s_ctrl);
+
+int msm_sensor_i2c_probe(struct i2c_client *client,
 	const struct i2c_device_id *id, struct msm_sensor_ctrl_t *s_ctrl);
 
-int32_t msm_sensor_free_sensor_data(struct msm_sensor_ctrl_t *s_ctrl);
+int msm_sensor_free_sensor_data(struct msm_sensor_ctrl_t *s_ctrl);
+
+int32_t msm_sensor_init_default_params(struct msm_sensor_ctrl_t *s_ctrl);
 
 int32_t msm_sensor_get_dt_gpio_req_tbl(struct device_node *of_node,
 	struct msm_camera_gpio_conf *gconf, uint16_t *gpio_array,
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
new file mode 100644
index 0000000..d8b90dd
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor_driver.c
@@ -0,0 +1,1038 @@
+/* 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.
+ */
+
+#define SENSOR_DRIVER_I2C "camera"
+/* Header file declaration */
+#include "msm_sensor.h"
+#include "msm_sd.h"
+#include "camera.h"
+#include "msm_cci.h"
+#include "msm_camera_dt_util.h"
+
+/* Logging macro */
+/*#define MSM_SENSOR_DRIVER_DEBUG*/
+#undef CDBG
+#ifdef MSM_SENSOR_DRIVER_DEBUG
+#define CDBG(fmt, args...) pr_err(fmt, ##args)
+#else
+#define CDBG(fmt, args...) pr_debug(fmt, ##args)
+#endif
+
+#define	SENSOR_MAX_MOUNTANGLE (360)
+
+/* Static declaration */
+static struct msm_sensor_ctrl_t *g_sctrl[MAX_CAMERAS];
+
+static int msm_sensor_platform_remove(struct platform_device *pdev)
+{
+	struct msm_sensor_ctrl_t  *s_ctrl;
+
+	pr_err("%s: sensor FREE\n", __func__);
+
+	s_ctrl = g_sctrl[pdev->id];
+	if (!s_ctrl) {
+		pr_err("%s: sensor device is NULL\n", __func__);
+		return 0;
+	}
+
+	msm_sensor_free_sensor_data(s_ctrl);
+	kfree(s_ctrl->msm_sensor_mutex);
+	kfree(s_ctrl->sensor_i2c_client);
+	kfree(s_ctrl);
+	g_sctrl[pdev->id] = NULL;
+
+	return 0;
+}
+
+
+static const struct of_device_id msm_sensor_driver_dt_match[] = {
+	{.compatible = "qcom,camera"},
+	{}
+};
+
+MODULE_DEVICE_TABLE(of, msm_sensor_driver_dt_match);
+
+static struct platform_driver msm_sensor_platform_driver = {
+	.driver = {
+		.name = "qcom,camera",
+		.owner = THIS_MODULE,
+		.of_match_table = msm_sensor_driver_dt_match,
+	},
+	.remove = msm_sensor_platform_remove,
+};
+
+static struct v4l2_subdev_info msm_sensor_driver_subdev_info[] = {
+	{
+		.code = V4L2_MBUS_FMT_SBGGR10_1X10,
+		.colorspace = V4L2_COLORSPACE_JPEG,
+		.fmt = 1,
+		.order = 0,
+	},
+};
+
+static int32_t msm_sensor_driver_create_i2c_v4l_subdev
+			(struct msm_sensor_ctrl_t *s_ctrl)
+{
+	int32_t rc = 0;
+	uint32_t session_id = 0;
+	struct i2c_client *client = s_ctrl->sensor_i2c_client->client;
+
+	CDBG("%s %s I2c probe succeeded\n", __func__, client->name);
+	rc = camera_init_v4l2(&client->dev, &session_id);
+	if (rc < 0) {
+		pr_err("failed: camera_init_i2c_v4l2 rc %d", rc);
+		return rc;
+	}
+	CDBG("%s rc %d session_id %d\n", __func__, rc, session_id);
+	snprintf(s_ctrl->msm_sd.sd.name,
+		sizeof(s_ctrl->msm_sd.sd.name), "%s",
+		s_ctrl->sensordata->sensor_name);
+	v4l2_i2c_subdev_init(&s_ctrl->msm_sd.sd, client,
+		s_ctrl->sensor_v4l2_subdev_ops);
+	v4l2_set_subdevdata(&s_ctrl->msm_sd.sd, client);
+	s_ctrl->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+	media_entity_init(&s_ctrl->msm_sd.sd.entity, 0, NULL, 0);
+	s_ctrl->msm_sd.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV;
+	s_ctrl->msm_sd.sd.entity.group_id = MSM_CAMERA_SUBDEV_SENSOR;
+	s_ctrl->msm_sd.sd.entity.name =	s_ctrl->msm_sd.sd.name;
+	s_ctrl->sensordata->sensor_info->session_id = session_id;
+	s_ctrl->msm_sd.close_seq = MSM_SD_CLOSE_2ND_CATEGORY | 0x3;
+	msm_sd_register(&s_ctrl->msm_sd);
+	CDBG("%s:%d\n", __func__, __LINE__);
+	return rc;
+}
+
+static int32_t msm_sensor_driver_create_v4l_subdev
+			(struct msm_sensor_ctrl_t *s_ctrl)
+{
+	int32_t rc = 0;
+	uint32_t session_id = 0;
+
+	rc = camera_init_v4l2(&s_ctrl->pdev->dev, &session_id);
+	if (rc < 0) {
+		pr_err("failed: camera_init_v4l2 rc %d", rc);
+		return rc;
+	}
+	CDBG("rc %d session_id %d", rc, session_id);
+	s_ctrl->sensordata->sensor_info->session_id = session_id;
+
+	/* Create /dev/v4l-subdevX device */
+	v4l2_subdev_init(&s_ctrl->msm_sd.sd, s_ctrl->sensor_v4l2_subdev_ops);
+	snprintf(s_ctrl->msm_sd.sd.name, sizeof(s_ctrl->msm_sd.sd.name), "%s",
+		s_ctrl->sensordata->sensor_name);
+	v4l2_set_subdevdata(&s_ctrl->msm_sd.sd, s_ctrl->pdev);
+	s_ctrl->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+	media_entity_init(&s_ctrl->msm_sd.sd.entity, 0, NULL, 0);
+	s_ctrl->msm_sd.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV;
+	s_ctrl->msm_sd.sd.entity.group_id = MSM_CAMERA_SUBDEV_SENSOR;
+	s_ctrl->msm_sd.sd.entity.name = s_ctrl->msm_sd.sd.name;
+	s_ctrl->msm_sd.close_seq = MSM_SD_CLOSE_2ND_CATEGORY | 0x3;
+	msm_sd_register(&s_ctrl->msm_sd);
+	return rc;
+}
+
+static int32_t msm_sensor_fill_eeprom_subdevid_by_name(
+				struct msm_sensor_ctrl_t *s_ctrl)
+{
+	int32_t rc = 0;
+	const char *eeprom_name;
+	struct device_node *src_node = NULL;
+	uint32_t val = 0, count = 0, eeprom_name_len;
+	int i;
+	int32_t *eeprom_subdev_id;
+	struct  msm_sensor_info_t *sensor_info;
+	struct device_node *of_node = s_ctrl->of_node;
+	const void *p;
+
+	if (!s_ctrl->sensordata->eeprom_name || !of_node)
+		return -EINVAL;
+
+	eeprom_name_len = strlen(s_ctrl->sensordata->eeprom_name);
+	if (eeprom_name_len >= MAX_SENSOR_NAME)
+		return -EINVAL;
+
+	sensor_info = s_ctrl->sensordata->sensor_info;
+	eeprom_subdev_id = &sensor_info->subdev_id[SUB_MODULE_EEPROM];
+	/*
+	 * string for eeprom name is valid, set sudev id to -1
+	 *  and try to found new id
+	 */
+	*eeprom_subdev_id = -1;
+
+	if (0 == eeprom_name_len)
+		return 0;
+
+	CDBG("Try to find eeprom subdev for %s\n",
+			s_ctrl->sensordata->eeprom_name);
+	p = of_get_property(of_node, "qcom,eeprom-src", &count);
+	if (!p || !count)
+		return 0;
+
+	count /= sizeof(uint32_t);
+	for (i = 0; i < count; i++) {
+		eeprom_name = NULL;
+		src_node = of_parse_phandle(of_node, "qcom,eeprom-src", i);
+		if (!src_node) {
+			pr_err("eeprom src node NULL\n");
+			continue;
+		}
+		rc = of_property_read_string(src_node, "qcom,eeprom-name",
+			&eeprom_name);
+		if (rc < 0) {
+			pr_err("failed\n");
+			of_node_put(src_node);
+			continue;
+		}
+		if (strcmp(eeprom_name, s_ctrl->sensordata->eeprom_name))
+			continue;
+
+		rc = of_property_read_u32(src_node, "cell-index", &val);
+
+		CDBG("%s qcom,eeprom cell index %d, rc %d\n", __func__,
+			val, rc);
+		if (rc < 0) {
+			pr_err("failed\n");
+			of_node_put(src_node);
+			continue;
+		}
+
+		*eeprom_subdev_id = val;
+		CDBG("Done. Eeprom subdevice id is %d\n", val);
+		of_node_put(src_node);
+		src_node = NULL;
+		break;
+	}
+
+	return rc;
+}
+
+static int32_t msm_sensor_fill_actuator_subdevid_by_name(
+				struct msm_sensor_ctrl_t *s_ctrl)
+{
+	int32_t rc = 0;
+	struct device_node *src_node = NULL;
+	uint32_t val = 0, actuator_name_len;
+	int32_t *actuator_subdev_id;
+	struct  msm_sensor_info_t *sensor_info;
+	struct device_node *of_node = s_ctrl->of_node;
+
+	if (!s_ctrl->sensordata->actuator_name || !of_node)
+		return -EINVAL;
+
+	actuator_name_len = strlen(s_ctrl->sensordata->actuator_name);
+	if (actuator_name_len >= MAX_SENSOR_NAME)
+		return -EINVAL;
+
+	sensor_info = s_ctrl->sensordata->sensor_info;
+	actuator_subdev_id = &sensor_info->subdev_id[SUB_MODULE_ACTUATOR];
+	/*
+	 * string for actuator name is valid, set sudev id to -1
+	 * and try to found new id
+	 */
+	*actuator_subdev_id = -1;
+
+	if (0 == actuator_name_len)
+		return 0;
+
+	src_node = of_parse_phandle(of_node, "qcom,actuator-src", 0);
+	if (!src_node) {
+		CDBG("%s:%d src_node NULL\n", __func__, __LINE__);
+	} else {
+		rc = of_property_read_u32(src_node, "cell-index", &val);
+		CDBG("%s qcom,actuator cell index %d, rc %d\n", __func__,
+			val, rc);
+		if (rc < 0) {
+			pr_err("%s failed %d\n", __func__, __LINE__);
+			return -EINVAL;
+		}
+		*actuator_subdev_id = val;
+		of_node_put(src_node);
+		src_node = NULL;
+	}
+
+	return rc;
+}
+
+static int32_t msm_sensor_fill_slave_info_init_params(
+	struct msm_camera_sensor_slave_info *slave_info,
+	struct msm_sensor_info_t *sensor_info)
+{
+	struct msm_sensor_init_params *sensor_init_params;
+	if (!slave_info ||  !sensor_info)
+		return -EINVAL;
+
+	if (!slave_info->is_init_params_valid)
+		return 0;
+
+	sensor_init_params = &slave_info->sensor_init_params;
+	if (INVALID_CAMERA_B != sensor_init_params->position)
+		sensor_info->position =
+			sensor_init_params->position;
+
+	if (SENSOR_MAX_MOUNTANGLE > sensor_init_params->sensor_mount_angle) {
+		sensor_info->sensor_mount_angle =
+			sensor_init_params->sensor_mount_angle;
+		sensor_info->is_mount_angle_valid = 1;
+	}
+
+	if (CAMERA_MODE_INVALID != sensor_init_params->modes_supported)
+		sensor_info->modes_supported =
+			sensor_init_params->modes_supported;
+
+	return 0;
+}
+
+
+static int32_t msm_sensor_validate_slave_info(
+	struct msm_sensor_info_t *sensor_info)
+{
+	if (INVALID_CAMERA_B == sensor_info->position) {
+		sensor_info->position = BACK_CAMERA_B;
+		pr_err("%s Set dafault sensor position%d\n",
+			__func__, __LINE__);
+	}
+	if (CAMERA_MODE_INVALID == sensor_info->modes_supported) {
+		sensor_info->modes_supported = CAMERA_MODE_2D_B;
+		pr_err("%s Set dafault sensor modes_supported%d\n",
+			__func__, __LINE__);
+	}
+	if (SENSOR_MAX_MOUNTANGLE < sensor_info->sensor_mount_angle) {
+		sensor_info->sensor_mount_angle = 0;
+		pr_err("%s Set dafault sensor mount angle%d\n",
+			__func__, __LINE__);
+		sensor_info->is_mount_angle_valid = 1;
+	}
+	return 0;
+}
+
+/* static function definition */
+int32_t msm_sensor_driver_probe(void *setting)
+{
+	int32_t                              rc = 0;
+	uint16_t                             i = 0, size = 0, size_down = 0;
+	struct msm_sensor_ctrl_t            *s_ctrl = NULL;
+	struct msm_camera_cci_client        *cci_client = NULL;
+	struct msm_camera_sensor_slave_info *slave_info = NULL;
+	struct msm_sensor_power_setting     *power_setting = NULL;
+	struct msm_sensor_power_setting     *power_down_setting = NULL;
+	struct msm_camera_slave_info        *camera_info = NULL;
+	struct msm_camera_power_ctrl_t      *power_info = NULL;
+	int c, end;
+	struct msm_sensor_power_setting     power_down_setting_t;
+	unsigned long mount_pos = 0;
+
+	/* Validate input parameters */
+	if (!setting) {
+		pr_err("failed: slave_info %p", setting);
+		return -EINVAL;
+	}
+
+	/* Allocate memory for slave info */
+	slave_info = kzalloc(sizeof(*slave_info), GFP_KERNEL);
+	if (!slave_info) {
+		pr_err("failed: no memory slave_info %p", slave_info);
+		return -ENOMEM;
+	}
+
+	if (copy_from_user(slave_info, (void *)setting, sizeof(*slave_info))) {
+		pr_err("failed: copy_from_user");
+		rc = -EFAULT;
+		goto FREE_SLAVE_INFO;
+	}
+
+	/* Print slave info */
+	CDBG("camera id %d", slave_info->camera_id);
+	CDBG("slave_addr %x", slave_info->slave_addr);
+	CDBG("addr_type %d", slave_info->addr_type);
+	CDBG("sensor_id_reg_addr %x",
+		slave_info->sensor_id_info.sensor_id_reg_addr);
+	CDBG("sensor_id %x", slave_info->sensor_id_info.sensor_id);
+	CDBG("size %d", slave_info->power_setting_array.size);
+	CDBG("size down %d", slave_info->power_setting_array.size_down);
+
+	if (slave_info->is_init_params_valid) {
+		CDBG("position %d",
+			slave_info->sensor_init_params.position);
+		CDBG("mount %d",
+			slave_info->sensor_init_params.sensor_mount_angle);
+	}
+
+	/* Validate camera id */
+	if (slave_info->camera_id >= MAX_CAMERAS) {
+		pr_err("failed: invalid camera id %d max %d",
+			slave_info->camera_id, MAX_CAMERAS);
+		rc = -EINVAL;
+		goto FREE_POWER_SETTING;
+	}
+
+	/* Extract s_ctrl from camera id */
+	s_ctrl = g_sctrl[slave_info->camera_id];
+	if (!s_ctrl) {
+		pr_err("failed: s_ctrl %p for camera_id %d", s_ctrl,
+			slave_info->camera_id);
+		rc = -EINVAL;
+		goto FREE_POWER_SETTING;
+	}
+
+	CDBG("s_ctrl[%d] %p", slave_info->camera_id, s_ctrl);
+
+	if (s_ctrl->is_probe_succeed == 1) {
+		/*
+		 * Different sensor on this camera slot has been connected
+		 * and probe already succeeded for that sensor. Ignore this
+		 * probe
+		 */
+		pr_err("slot %d has some other sensor", slave_info->camera_id);
+		kfree(slave_info);
+		return 0;
+	}
+
+	size = slave_info->power_setting_array.size;
+	/* Allocate memory for power up setting */
+	power_setting = kzalloc(sizeof(*power_setting) * size, GFP_KERNEL);
+	if (!power_setting) {
+		pr_err("failed: no memory power_setting %p", power_setting);
+		rc = -ENOMEM;
+		goto FREE_SLAVE_INFO;
+	}
+
+	if (copy_from_user(power_setting,
+		(void *)slave_info->power_setting_array.power_setting,
+		sizeof(*power_setting) * size)) {
+		pr_err("failed: copy_from_user");
+		rc = -EFAULT;
+		goto FREE_POWER_SETTING;
+	}
+
+	/* Print power setting */
+	for (i = 0; i < size; i++) {
+		CDBG("UP seq_type %d seq_val %d config_val %ld delay %d",
+			power_setting[i].seq_type, power_setting[i].seq_val,
+			power_setting[i].config_val, power_setting[i].delay);
+	}
+	/*DOWN*/
+	size_down = slave_info->power_setting_array.size_down;
+	if (!size_down)
+		size_down = size;
+	/* Allocate memory for power down setting */
+	power_down_setting =
+		kzalloc(sizeof(*power_setting) * size_down, GFP_KERNEL);
+	if (!power_down_setting) {
+		pr_err("failed: no memory power_setting %p",
+						power_down_setting);
+		rc = -ENOMEM;
+		goto FREE_POWER_SETTING;
+	}
+
+	if (slave_info->power_setting_array.power_down_setting) {
+		if (copy_from_user(power_down_setting,
+			(void *)slave_info->power_setting_array.
+						power_down_setting,
+			sizeof(*power_down_setting) * size_down)) {
+			pr_err("failed: copy_from_user");
+			rc = -EFAULT;
+			goto FREE_POWER_DOWN_SETTING;
+		}
+	} else {
+		pr_err("failed: no power_down_setting");
+		if (copy_from_user(power_down_setting,
+			(void *)slave_info->power_setting_array.
+						power_setting,
+			sizeof(*power_down_setting) * size_down)) {
+			pr_err("failed: copy_from_user");
+			rc = -EFAULT;
+			goto FREE_POWER_DOWN_SETTING;
+		}
+
+		/*reverce*/
+		end = size_down - 1;
+		for (c = 0; c < size_down/2; c++) {
+			power_down_setting_t = power_down_setting[c];
+			power_down_setting[c] = power_down_setting[end];
+			power_down_setting[end] = power_down_setting_t;
+			end--;
+		}
+
+	}
+
+	/* Print power setting */
+	for (i = 0; i < size_down; i++) {
+		CDBG("DOWN seq_type %d seq_val %d config_val %ld delay %d",
+			power_down_setting[i].seq_type,
+			power_down_setting[i].seq_val,
+			power_down_setting[i].config_val,
+			power_down_setting[i].delay);
+	}
+
+	camera_info = kzalloc(sizeof(struct msm_camera_slave_info), GFP_KERNEL);
+	if (!camera_info) {
+		pr_err("failed: no memory slave_info %p", camera_info);
+		goto FREE_POWER_DOWN_SETTING;
+
+	}
+
+	/* Fill power up setting and power up setting size */
+	power_info = &s_ctrl->sensordata->power_info;
+	power_info->power_setting = power_setting;
+	power_info->power_setting_size = size;
+	power_info->power_down_setting = power_down_setting;
+	power_info->power_down_setting_size = size_down;
+
+	s_ctrl->sensordata->slave_info = camera_info;
+
+	/* Fill sensor slave info */
+	camera_info->sensor_slave_addr = slave_info->slave_addr;
+	camera_info->sensor_id_reg_addr =
+		slave_info->sensor_id_info.sensor_id_reg_addr;
+	camera_info->sensor_id = slave_info->sensor_id_info.sensor_id;
+
+	/* Fill CCI master, slave address and CCI default params */
+	if (!s_ctrl->sensor_i2c_client) {
+		pr_err("failed: sensor_i2c_client %p",
+			s_ctrl->sensor_i2c_client);
+		rc = -EINVAL;
+		goto FREE_CAMERA_INFO;
+	}
+	/* Fill sensor address type */
+	s_ctrl->sensor_i2c_client->addr_type = slave_info->addr_type;
+	if (s_ctrl->sensor_i2c_client->client)
+		s_ctrl->sensor_i2c_client->client->addr =
+			camera_info->sensor_slave_addr;
+
+	cci_client = s_ctrl->sensor_i2c_client->cci_client;
+	if (!cci_client) {
+		pr_err("failed: cci_client %p", cci_client);
+		goto FREE_CAMERA_INFO;
+	}
+	cci_client->cci_i2c_master = s_ctrl->cci_i2c_master;
+	cci_client->sid = slave_info->slave_addr >> 1;
+	cci_client->retries = 3;
+	cci_client->id_map = 0;
+
+	/* Parse and fill vreg params for powerup settings */
+	rc = msm_camera_fill_vreg_params(
+		power_info->cam_vreg,
+		power_info->num_vreg,
+		power_info->power_setting,
+		power_info->power_setting_size);
+	if (rc < 0) {
+		pr_err("failed: msm_camera_get_dt_power_setting_data rc %d",
+			rc);
+		goto FREE_CAMERA_INFO;
+	}
+
+	/* Parse and fill vreg params for powerdown settings*/
+	rc = msm_camera_fill_vreg_params(
+		power_info->cam_vreg,
+		power_info->num_vreg,
+		power_info->power_down_setting,
+		power_info->power_down_setting_size);
+	if (rc < 0) {
+		pr_err("failed: msm_camera_fill_vreg_params for PDOWN rc %d",
+			rc);
+		goto FREE_CAMERA_INFO;
+	}
+
+	/*
+	 *  Update sensor, actuator and eeprom name in
+	 *  sensor control structure.
+	 */
+	s_ctrl->sensordata->sensor_name = slave_info->sensor_name;
+	s_ctrl->sensordata->eeprom_name = slave_info->eeprom_name;
+	s_ctrl->sensordata->actuator_name = slave_info->actuator_name;
+
+	/*
+	 * Update eeporm subdevice Id by input eeprom name
+	 */
+	rc = msm_sensor_fill_eeprom_subdevid_by_name(s_ctrl);
+	if (rc < 0) {
+		pr_err("%s failed %d\n", __func__, __LINE__);
+		goto FREE_POWER_SETTING;
+	}
+	/*
+	 * Update actuator subdevice Id by input actuator name
+	 */
+	rc = msm_sensor_fill_actuator_subdevid_by_name(s_ctrl);
+	if (rc < 0) {
+		pr_err("%s failed %d\n", __func__, __LINE__);
+		goto FREE_POWER_SETTING;
+	}
+
+	/* Power up and probe sensor */
+	rc = s_ctrl->func_tbl->sensor_power_up(s_ctrl);
+	if (rc < 0) {
+		pr_err("%s power up failed", slave_info->sensor_name);
+		goto FREE_CAMERA_INFO;
+	}
+
+	pr_err("%s probe succeeded", slave_info->sensor_name);
+
+	/*
+	  Set probe succeeded flag to 1 so that no other camera shall
+	 * probed on this slot
+	 */
+	s_ctrl->is_probe_succeed = 1;
+
+	/*
+	 * Create /dev/videoX node, comment for now until dummy /dev/videoX
+	 * node is created and used by HAL
+	 */
+
+	if (s_ctrl->sensor_device_type == MSM_CAMERA_PLATFORM_DEVICE)
+		rc = msm_sensor_driver_create_v4l_subdev(s_ctrl);
+	else
+		rc = msm_sensor_driver_create_i2c_v4l_subdev(s_ctrl);
+	if (rc < 0) {
+		pr_err("failed: camera creat v4l2 rc %d", rc);
+		goto CAMERA_POWER_DOWN;
+	}
+
+	/* Power down */
+	s_ctrl->func_tbl->sensor_power_down(s_ctrl);
+
+	rc = msm_sensor_fill_slave_info_init_params(
+		slave_info,
+		s_ctrl->sensordata->sensor_info);
+	if (rc < 0) {
+		pr_err("%s Fill slave info failed", slave_info->sensor_name);
+		goto FREE_CAMERA_INFO;
+	}
+	rc = msm_sensor_validate_slave_info(s_ctrl->sensordata->sensor_info);
+	if (rc < 0) {
+		pr_err("%s Validate slave info failed",
+			slave_info->sensor_name);
+		goto FREE_CAMERA_INFO;
+	}
+	/* Update sensor mount angle and position in media entity flag */
+	mount_pos = s_ctrl->sensordata->sensor_info->position << 16;
+	mount_pos = mount_pos | ((s_ctrl->sensordata->sensor_info->
+		sensor_mount_angle / 90) << 8);
+	s_ctrl->msm_sd.sd.entity.flags = mount_pos | MEDIA_ENT_FL_DEFAULT;
+
+	/*Save sensor info*/
+	s_ctrl->sensordata->cam_slave_info = slave_info;
+
+	return rc;
+
+CAMERA_POWER_DOWN:
+	s_ctrl->func_tbl->sensor_power_down(s_ctrl);
+FREE_CAMERA_INFO:
+	kfree(camera_info);
+FREE_POWER_DOWN_SETTING:
+	kfree(power_down_setting);
+FREE_POWER_SETTING:
+	kfree(power_setting);
+FREE_SLAVE_INFO:
+	kfree(slave_info);
+	return rc;
+}
+
+static int32_t msm_sensor_driver_get_gpio_data(
+	struct msm_camera_sensor_board_info *sensordata,
+	struct device_node *of_node)
+{
+	int32_t                      rc = 0, i = 0;
+	struct msm_camera_gpio_conf *gconf = NULL;
+	uint16_t                    *gpio_array = NULL;
+	uint16_t                     gpio_array_size = 0;
+
+	/* Validate input paramters */
+	if (!sensordata || !of_node) {
+		pr_err("failed: invalid params sensordata %p of_node %p",
+			sensordata, of_node);
+		return -EINVAL;
+	}
+
+	sensordata->power_info.gpio_conf = kzalloc(
+			sizeof(struct msm_camera_gpio_conf), GFP_KERNEL);
+	if (!sensordata->power_info.gpio_conf) {
+		pr_err("failed");
+		return -ENOMEM;
+	}
+	gconf = sensordata->power_info.gpio_conf;
+
+	gpio_array_size = of_gpio_count(of_node);
+	CDBG("gpio count %d", gpio_array_size);
+	if (!gpio_array_size)
+		return 0;
+
+	gpio_array = kzalloc(sizeof(uint16_t) * gpio_array_size, GFP_KERNEL);
+	if (!gpio_array) {
+		pr_err("failed");
+		goto FREE_GPIO_CONF;
+	}
+	for (i = 0; i < gpio_array_size; i++) {
+		gpio_array[i] = of_get_gpio(of_node, i);
+		CDBG("gpio_array[%d] = %d", i, gpio_array[i]);
+	}
+
+	rc = msm_camera_get_dt_gpio_req_tbl(of_node, gconf, gpio_array,
+		gpio_array_size);
+	if (rc < 0) {
+		pr_err("failed");
+		goto FREE_GPIO_CONF;
+	}
+
+	rc = msm_camera_init_gpio_pin_tbl(of_node, gconf, gpio_array,
+		gpio_array_size);
+	if (rc < 0) {
+		pr_err("failed");
+		goto FREE_GPIO_REQ_TBL;
+	}
+
+	kfree(gpio_array);
+	return rc;
+
+FREE_GPIO_REQ_TBL:
+	kfree(sensordata->power_info.gpio_conf->cam_gpio_req_tbl);
+FREE_GPIO_CONF:
+	kfree(sensordata->power_info.gpio_conf);
+	kfree(gpio_array);
+	return rc;
+}
+
+static int32_t msm_sensor_driver_get_dt_data(struct msm_sensor_ctrl_t *s_ctrl)
+{
+	int32_t                              rc = 0;
+	struct msm_camera_sensor_board_info *sensordata = NULL;
+	struct device_node                  *of_node = s_ctrl->of_node;
+	uint32_t cell_id;
+
+	s_ctrl->sensordata = kzalloc(sizeof(*sensordata), GFP_KERNEL);
+	if (!s_ctrl->sensordata) {
+		pr_err("failed: no memory");
+		return -ENOMEM;
+	}
+
+	sensordata = s_ctrl->sensordata;
+
+	/*
+	 * Read cell index - this cell index will be the camera slot where
+	 * this camera will be mounted
+	 */
+	rc = of_property_read_u32(of_node, "cell-index", &cell_id);
+	if (rc < 0) {
+		pr_err("failed: cell-index rc %d", rc);
+		goto FREE_SENSOR_DATA;
+	}
+	s_ctrl->id = cell_id;
+
+	/* Validate cell_id */
+	if (cell_id >= MAX_CAMERAS) {
+		pr_err("failed: invalid cell_id %d", cell_id);
+		rc = -EINVAL;
+		goto FREE_SENSOR_DATA;
+	}
+
+	/* Check whether g_sctrl is already filled for this cell_id */
+	if (g_sctrl[cell_id]) {
+		pr_err("failed: sctrl already filled for cell_id %d", cell_id);
+		rc = -EINVAL;
+		goto FREE_SENSOR_DATA;
+	}
+
+	/* Read subdev info */
+	rc = msm_sensor_get_sub_module_index(of_node, &sensordata->sensor_info);
+	if (rc < 0) {
+		pr_err("failed");
+		goto FREE_SENSOR_DATA;
+	}
+
+	/* Read vreg information */
+	rc = msm_camera_get_dt_vreg_data(of_node,
+		&sensordata->power_info.cam_vreg,
+		&sensordata->power_info.num_vreg);
+	if (rc < 0) {
+		pr_err("failed: msm_camera_get_dt_vreg_data rc %d", rc);
+		goto FREE_SUB_MODULE_DATA;
+	}
+
+	/* Read gpio information */
+	rc = msm_sensor_driver_get_gpio_data(sensordata, of_node);
+	if (rc < 0) {
+		pr_err("failed: msm_sensor_driver_get_gpio_data rc %d", rc);
+		goto FREE_VREG_DATA;
+	}
+
+	/* Get CCI master */
+	rc = of_property_read_u32(of_node, "qcom,cci-master",
+		&s_ctrl->cci_i2c_master);
+	CDBG("qcom,cci-master %d, rc %d", s_ctrl->cci_i2c_master, rc);
+	if (rc < 0) {
+		/* Set default master 0 */
+		s_ctrl->cci_i2c_master = MASTER_0;
+		rc = 0;
+	}
+
+	/* Get mount angle */
+
+	rc = of_property_read_u32(of_node, "qcom,mount-angle",
+		&sensordata->sensor_info->sensor_mount_angle);
+	CDBG("%s qcom,mount-angle %d, rc %d\n", __func__,
+		sensordata->sensor_info->sensor_mount_angle, rc);
+	if (rc < 0) {
+		/* Invalidate mount angle flag */
+		sensordata->sensor_info->is_mount_angle_valid = 0;
+		sensordata->sensor_info->sensor_mount_angle = 0;
+		rc = 0;
+	} else {
+		sensordata->sensor_info->is_mount_angle_valid = 1;
+	}
+
+	rc = of_property_read_u32(of_node, "qcom,sensor-position",
+		&sensordata->sensor_info->position);
+	if (rc < 0) {
+		pr_err("%s:%d Invalid sensor position\n", __func__, __LINE__);
+		sensordata->sensor_info->position = INVALID_CAMERA_B;
+	}
+
+	rc = of_property_read_u32(of_node, "qcom,sensor-mode",
+		&sensordata->sensor_info->modes_supported);
+	if (rc < 0) {
+		pr_err("%s:%d Invalid sensor mode supported\n",
+			__func__, __LINE__);
+		sensordata->sensor_info->modes_supported = CAMERA_MODE_INVALID;
+		rc = 0;
+	}
+
+	/* Get vdd-cx regulator */
+	/*Optional property, don't return error if absent */
+	of_property_read_string(of_node, "qcom,vdd-cx-name",
+		&sensordata->misc_regulator);
+	CDBG("qcom,misc_regulator %s", sensordata->misc_regulator);
+
+	return rc;
+
+FREE_VREG_DATA:
+	kfree(sensordata->power_info.cam_vreg);
+FREE_SUB_MODULE_DATA:
+	kfree(sensordata->sensor_info);
+FREE_SENSOR_DATA:
+	kfree(sensordata);
+	return rc;
+}
+
+static int32_t msm_sensor_driver_parse(struct msm_sensor_ctrl_t *s_ctrl)
+{
+	int32_t                   rc = 0;
+
+	CDBG("Enter");
+	/* Validate input parameters */
+
+
+	/* Allocate memory for sensor_i2c_client */
+	s_ctrl->sensor_i2c_client = kzalloc(sizeof(*s_ctrl->sensor_i2c_client),
+		GFP_KERNEL);
+	if (!s_ctrl->sensor_i2c_client) {
+		pr_err("failed: no memory sensor_i2c_client %p",
+			s_ctrl->sensor_i2c_client);
+		return -ENOMEM;
+	}
+
+	/* Allocate memory for mutex */
+	s_ctrl->msm_sensor_mutex = kzalloc(sizeof(*s_ctrl->msm_sensor_mutex),
+		GFP_KERNEL);
+	if (!s_ctrl->msm_sensor_mutex) {
+		pr_err("failed: no memory msm_sensor_mutex %p",
+			s_ctrl->msm_sensor_mutex);
+		goto FREE_SENSOR_I2C_CLIENT;
+	}
+
+	/* Parse dt information and store in sensor control structure */
+	rc = msm_sensor_driver_get_dt_data(s_ctrl);
+	if (rc < 0) {
+		pr_err("failed: rc %d", rc);
+		goto FREE_MUTEX;
+	}
+
+	/* Initialize mutex */
+	mutex_init(s_ctrl->msm_sensor_mutex);
+
+	/* Initilize v4l2 subdev info */
+	s_ctrl->sensor_v4l2_subdev_info = msm_sensor_driver_subdev_info;
+	s_ctrl->sensor_v4l2_subdev_info_size =
+		ARRAY_SIZE(msm_sensor_driver_subdev_info);
+
+	/* Initialize default parameters */
+	rc = msm_sensor_init_default_params(s_ctrl);
+	if (rc < 0) {
+		pr_err("failed: msm_sensor_init_default_params rc %d", rc);
+		goto FREE_DT_DATA;
+	}
+
+	/* Store sensor control structure in static database */
+	g_sctrl[s_ctrl->id] = s_ctrl;
+	pr_err("g_sctrl[%d] %p", s_ctrl->id, g_sctrl[s_ctrl->id]);
+
+	return rc;
+
+FREE_DT_DATA:
+	kfree(s_ctrl->sensordata->power_info.gpio_conf->gpio_num_info);
+	kfree(s_ctrl->sensordata->power_info.gpio_conf->cam_gpio_req_tbl);
+	kfree(s_ctrl->sensordata->power_info.gpio_conf);
+	kfree(s_ctrl->sensordata->power_info.cam_vreg);
+	kfree(s_ctrl->sensordata);
+FREE_MUTEX:
+	kfree(s_ctrl->msm_sensor_mutex);
+FREE_SENSOR_I2C_CLIENT:
+	kfree(s_ctrl->sensor_i2c_client);
+	return rc;
+}
+
+static int32_t msm_sensor_driver_platform_probe(struct platform_device *pdev)
+{
+	int32_t rc = 0;
+	struct msm_sensor_ctrl_t *s_ctrl = NULL;
+
+
+	/* Create sensor control structure */
+	s_ctrl = kzalloc(sizeof(*s_ctrl), GFP_KERNEL);
+	if (!s_ctrl) {
+		pr_err("failed: no memory s_ctrl %p", s_ctrl);
+		return -ENOMEM;
+	}
+
+	platform_set_drvdata(pdev, s_ctrl);
+
+	/* Initialize sensor device type */
+	s_ctrl->sensor_device_type = MSM_CAMERA_PLATFORM_DEVICE;
+	s_ctrl->of_node = pdev->dev.of_node;
+
+	rc = msm_sensor_driver_parse(s_ctrl);
+	if (rc < 0) {
+		pr_err("failed: msm_sensor_driver_parse rc %d", rc);
+		goto FREE_S_CTRL;
+	}
+
+	/* Fill platform device */
+	pdev->id = s_ctrl->id;
+	s_ctrl->pdev = pdev;
+
+	/* Fill device in power info */
+	s_ctrl->sensordata->power_info.dev = &pdev->dev;
+
+	return rc;
+FREE_S_CTRL:
+	kfree(s_ctrl);
+	return rc;
+}
+
+static int32_t msm_sensor_driver_i2c_probe(struct i2c_client *client,
+	const struct i2c_device_id *id)
+{
+	int32_t rc = 0;
+	struct msm_sensor_ctrl_t *s_ctrl;
+
+	CDBG("\n\nEnter: msm_sensor_driver_i2c_probe");
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+		pr_err("%s %s i2c_check_functionality failed\n",
+			__func__, client->name);
+		rc = -EFAULT;
+		return rc;
+	}
+
+	/* Create sensor control structure */
+	s_ctrl = kzalloc(sizeof(*s_ctrl), GFP_KERNEL);
+	if (!s_ctrl) {
+		pr_err("failed: no memory s_ctrl %p", s_ctrl);
+		return -ENOMEM;
+	}
+
+	i2c_set_clientdata(client, s_ctrl);
+
+	/* Initialize sensor device type */
+	s_ctrl->sensor_device_type = MSM_CAMERA_I2C_DEVICE;
+	s_ctrl->of_node = client->dev.of_node;
+
+	rc = msm_sensor_driver_parse(s_ctrl);
+	if (rc < 0) {
+		pr_err("failed: msm_sensor_driver_parse rc %d", rc);
+		goto FREE_S_CTRL;
+	}
+
+	if (s_ctrl->sensor_i2c_client != NULL) {
+		s_ctrl->sensor_i2c_client->client = client;
+		s_ctrl->sensordata->power_info.dev = &client->dev;
+
+	}
+
+	return rc;
+FREE_S_CTRL:
+	kfree(s_ctrl);
+	return rc;
+}
+
+static int msm_sensor_driver_i2c_remove(struct i2c_client *client)
+{
+	struct msm_sensor_ctrl_t  *s_ctrl = i2c_get_clientdata(client);
+
+	pr_err("%s: sensor FREE\n", __func__);
+
+	if (!s_ctrl) {
+		pr_err("%s: sensor device is NULL\n", __func__);
+		return 0;
+	}
+
+	g_sctrl[s_ctrl->id] = NULL;
+	msm_sensor_free_sensor_data(s_ctrl);
+	kfree(s_ctrl->msm_sensor_mutex);
+	kfree(s_ctrl->sensor_i2c_client);
+	kfree(s_ctrl);
+
+	return 0;
+}
+
+static const struct i2c_device_id i2c_id[] = {
+	{SENSOR_DRIVER_I2C, (kernel_ulong_t)NULL},
+	{ }
+};
+
+static struct i2c_driver msm_sensor_driver_i2c = {
+	.id_table = i2c_id,
+	.probe  = msm_sensor_driver_i2c_probe,
+	.remove = msm_sensor_driver_i2c_remove,
+	.driver = {
+		.name = SENSOR_DRIVER_I2C,
+	},
+};
+
+static int __init msm_sensor_driver_init(void)
+{
+	int32_t rc = 0;
+
+	CDBG("Enter");
+	rc = platform_driver_probe(&msm_sensor_platform_driver,
+		msm_sensor_driver_platform_probe);
+	if (!rc) {
+		CDBG("probe success");
+		return rc;
+	} else {
+		CDBG("probe i2c");
+		rc = i2c_add_driver(&msm_sensor_driver_i2c);
+	}
+
+	return rc;
+}
+
+
+static void __exit msm_sensor_driver_exit(void)
+{
+	CDBG("Enter");
+	platform_driver_unregister(&msm_sensor_platform_driver);
+	i2c_del_driver(&msm_sensor_driver_i2c);
+	return;
+}
+
+module_init(msm_sensor_driver_init);
+module_exit(msm_sensor_driver_exit);
+MODULE_DESCRIPTION("msm_sensor_driver");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/boot/dts/msm8926-qrd.dts b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor_driver.h
similarity index 63%
copy from arch/arm/boot/dts/msm8926-qrd.dts
copy to drivers/media/platform/msm/camera_v2/sensor/msm_sensor_driver.h
index 8ee8828..0394387 100644
--- a/arch/arm/boot/dts/msm8926-qrd.dts
+++ b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor_driver.h
@@ -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
@@ -10,12 +10,11 @@
  * GNU General Public License for more details.
  */
 
-/dts-v1/;
-/include/ "msm8926.dtsi"
-/include/ "msm8226-qrd.dtsi"
+#ifndef MSM_SENSOR_DRIVER_H
+#define MSM_SENSOR_DRIVER_H
 
-/ {
-	model = "Qualcomm MSM 8926 QRD";
-	compatible = "qcom,msm8926-qrd", "qcom,msm8926", "qcom,qrd";
-	qcom,board-id = <11 0>;
-};
+#include "msm_sensor.h"
+
+int32_t msm_sensor_driver_probe(void *setting);
+
+#endif
diff --git a/drivers/media/platform/msm/camera_v2/sensor/msm_sensor_init.c b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor_init.c
new file mode 100644
index 0000000..bc96eb8
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor_init.c
@@ -0,0 +1,177 @@
+/* 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.
+ */
+
+#define pr_fmt(fmt) "MSM-SENSOR-INIT %s:%d " fmt "\n", __func__, __LINE__
+
+/* Header files */
+#include <mach/gpiomux.h>
+#include "msm_sensor_init.h"
+#include "msm_sensor_driver.h"
+#include "msm_sensor.h"
+#include "msm_sd.h"
+
+/* Logging macro */
+/*#define CONFIG_MSMB_CAMERA_DEBUG*/
+#undef CDBG
+#ifdef CONFIG_MSMB_CAMERA_DEBUG
+#define CDBG(fmt, args...) pr_err(fmt, ##args)
+#else
+#define CDBG(fmt, args...) do { } while (0)
+#endif
+
+static struct msm_sensor_init_t *s_init;
+
+/* Static function declaration */
+static long msm_sensor_init_subdev_ioctl(struct v4l2_subdev *sd,
+	unsigned int cmd, void *arg);
+
+/* Static structure declaration */
+static struct v4l2_subdev_core_ops msm_sensor_init_subdev_core_ops = {
+	.ioctl = msm_sensor_init_subdev_ioctl,
+};
+
+static struct v4l2_subdev_ops msm_sensor_init_subdev_ops = {
+	.core = &msm_sensor_init_subdev_core_ops,
+};
+
+static const struct v4l2_subdev_internal_ops msm_sensor_init_internal_ops;
+
+static int msm_sensor_wait_for_probe_done(struct msm_sensor_init_t *s_init)
+{
+	int rc;
+
+	if (s_init->module_init_status == 1) {
+		pr_err("msm_cam_get_module_init_status -2\n");
+		return 0;
+	}
+
+	while (1) {
+		rc = wait_event_interruptible(s_init->state_wait,
+			(s_init->module_init_status == 1));
+		if (rc == -ETIMEDOUT)
+			continue;
+		else if (rc == 0)
+			break;
+	}
+	return 0;
+}
+
+/* Static function definition */
+static long msm_sensor_driver_cmd(struct msm_sensor_init_t *s_init, void *arg)
+{
+	int32_t                      rc = 0;
+	struct sensor_init_cfg_data *cfg = (struct sensor_init_cfg_data *)arg;
+
+	/* Validate input parameters */
+	if (!s_init || !cfg) {
+		pr_err("failed: s_init %p cfg %p", s_init, cfg);
+		return -EINVAL;
+	}
+
+	switch (cfg->cfgtype) {
+	case CFG_SINIT_PROBE:
+		mutex_lock(&s_init->imutex);
+		s_init->module_init_status = 0;
+		rc = msm_sensor_driver_probe(cfg->cfg.setting);
+		mutex_unlock(&s_init->imutex);
+		if (rc < 0)
+			pr_err("failed: msm_sensor_driver_probe rc %d", rc);
+		break;
+
+	case CFG_SINIT_PROBE_DONE:
+		s_init->module_init_status = 1;
+		wake_up(&s_init->state_wait);
+		break;
+
+	case CFG_SINIT_PROBE_WAIT_DONE:
+		msm_sensor_wait_for_probe_done(s_init);
+		break;
+
+	default:
+		pr_err("default");
+		break;
+	}
+
+	return rc;
+}
+
+static long msm_sensor_init_subdev_ioctl(struct v4l2_subdev *sd,
+	unsigned int cmd, void *arg)
+{
+	int32_t rc = 0;
+	struct msm_sensor_init_t *s_init = v4l2_get_subdevdata(sd);
+	CDBG("Enter");
+
+	/* Validate input parameters */
+	if (!s_init) {
+		pr_err("failed: s_init %p", s_init);
+		return -EINVAL;
+	}
+
+	switch (cmd) {
+	case VIDIOC_MSM_SENSOR_INIT_CFG:
+		rc = msm_sensor_driver_cmd(s_init, arg);
+		break;
+
+	default:
+		pr_err("default");
+		break;
+	}
+
+	return 0;
+}
+
+static int __init msm_sensor_init_module(void)
+{
+	/* Allocate memory for msm_sensor_init control structure */
+	s_init = kzalloc(sizeof(struct msm_sensor_init_t), GFP_KERNEL);
+	if (!s_init) {
+		pr_err("failed: no memory s_init %p", NULL);
+		return -ENOMEM;
+	}
+
+	pr_err("MSM_SENSOR_INIT_MODULE %p", NULL);
+
+	/* Initialize mutex */
+	mutex_init(&s_init->imutex);
+
+	/* Create /dev/v4l-subdevX for msm_sensor_init */
+	v4l2_subdev_init(&s_init->msm_sd.sd, &msm_sensor_init_subdev_ops);
+	snprintf(s_init->msm_sd.sd.name, sizeof(s_init->msm_sd.sd.name), "%s",
+		"msm_sensor_init");
+	v4l2_set_subdevdata(&s_init->msm_sd.sd, s_init);
+	s_init->msm_sd.sd.internal_ops = &msm_sensor_init_internal_ops;
+	s_init->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+	media_entity_init(&s_init->msm_sd.sd.entity, 0, NULL, 0);
+	s_init->msm_sd.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV;
+	s_init->msm_sd.sd.entity.group_id = MSM_CAMERA_SUBDEV_SENSOR_INIT;
+	s_init->msm_sd.sd.entity.name = s_init->msm_sd.sd.name;
+	s_init->msm_sd.close_seq = MSM_SD_CLOSE_2ND_CATEGORY | 0x6;
+	msm_sd_register(&s_init->msm_sd);
+
+	init_waitqueue_head(&s_init->state_wait);
+
+	return 0;
+}
+
+static void __exit msm_sensor_exit_module(void)
+{
+	msm_sd_unregister(&s_init->msm_sd);
+	mutex_destroy(&s_init->imutex);
+	kfree(s_init);
+	return;
+}
+
+module_init(msm_sensor_init_module);
+module_exit(msm_sensor_exit_module);
+MODULE_DESCRIPTION("msm_sensor_init");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/boot/dts/msm8926-1080p-mtp.dts b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor_init.h
similarity index 60%
copy from arch/arm/boot/dts/msm8926-1080p-mtp.dts
copy to drivers/media/platform/msm/camera_v2/sensor/msm_sensor_init.h
index c1217a2..256b0a1 100644
--- a/arch/arm/boot/dts/msm8926-1080p-mtp.dts
+++ b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor_init.h
@@ -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
@@ -10,14 +10,16 @@
  * GNU General Public License for more details.
  */
 
+#ifndef MSM_SENSOR_INIT_H
+#define MSM_SENSOR_INIT_H
 
-/dts-v1/;
-/include/ "msm8926.dtsi"
-/include/ "msm8226-1080p-mtp.dtsi"
-/include/ "msm8226-camera-sensor-mtp.dtsi"
+#include "msm_sensor.h"
 
-/ {
-	model = "Qualcomm MSM 8926 MTP";
-	compatible = "qcom,msm8926-mtp", "qcom,msm8926", "qcom,mtp";
-	qcom,board-id = <8 2>;
+struct msm_sensor_init_t {
+	struct mutex imutex;
+	struct msm_sd_subdev msm_sd;
+	int module_init_status;
+	wait_queue_head_t state_wait;
 };
+
+#endif
diff --git a/drivers/media/platform/msm/camera_v2/sensor/mt9m114.c b/drivers/media/platform/msm/camera_v2/sensor/mt9m114.c
index de4fcd0..1d58490 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/mt9m114.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/mt9m114.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
@@ -1191,6 +1191,10 @@
 		for (i = 0; i < SUB_MODULE_MAX; i++)
 			cdata->cfg.sensor_info.subdev_id[i] =
 				s_ctrl->sensordata->sensor_info->subdev_id[i];
+		cdata->cfg.sensor_info.is_mount_angle_valid =
+			s_ctrl->sensordata->sensor_info->is_mount_angle_valid;
+		cdata->cfg.sensor_info.sensor_mount_angle =
+			s_ctrl->sensordata->sensor_info->sensor_mount_angle;
 		CDBG("%s:%d sensor name %s\n", __func__, __LINE__,
 			cdata->cfg.sensor_info.sensor_name);
 		CDBG("%s:%d session id %d\n", __func__, __LINE__,
@@ -1198,6 +1202,9 @@
 		for (i = 0; i < SUB_MODULE_MAX; i++)
 			CDBG("%s:%d subdev_id[%d] %d\n", __func__, __LINE__, i,
 				cdata->cfg.sensor_info.subdev_id[i]);
+		CDBG("%s:%d mount angle valid %d value %d\n", __func__,
+			__LINE__, cdata->cfg.sensor_info.is_mount_angle_valid,
+			cdata->cfg.sensor_info.sensor_mount_angle);
 
 		break;
 	case CFG_SET_INIT_SETTING:
@@ -1233,8 +1240,12 @@
 			MSM_CAMERA_I2C_WORD_DATA);
 		break;
 	case CFG_GET_SENSOR_INIT_PARAMS:
-		cdata->cfg.sensor_init_params =
-			*s_ctrl->sensordata->sensor_init_params;
+		cdata->cfg.sensor_init_params.modes_supported =
+			s_ctrl->sensordata->sensor_info->modes_supported;
+		cdata->cfg.sensor_init_params.position =
+			s_ctrl->sensordata->sensor_info->position;
+		cdata->cfg.sensor_init_params.sensor_mount_angle =
+			s_ctrl->sensordata->sensor_info->sensor_mount_angle;
 		CDBG("%s:%d init params mode %d pos %d mount %d\n", __func__,
 			__LINE__,
 			cdata->cfg.sensor_init_params.modes_supported,
@@ -1243,11 +1254,12 @@
 		break;
 	case CFG_SET_SLAVE_INFO: {
 		struct msm_camera_sensor_slave_info sensor_slave_info;
-		struct msm_sensor_power_setting_array *power_setting_array;
+		struct msm_camera_power_ctrl_t *p_ctrl;
+		uint16_t size;
 		int slave_index = 0;
 		if (copy_from_user(&sensor_slave_info,
-		    (void *)cdata->cfg.setting,
-		    sizeof(struct msm_camera_sensor_slave_info))) {
+			(void *)cdata->cfg.setting,
+			sizeof(struct msm_camera_sensor_slave_info))) {
 			pr_err("%s:%d failed\n", __func__, __LINE__);
 			rc = -EFAULT;
 			break;
@@ -1263,27 +1275,30 @@
 			sensor_slave_info.addr_type;
 
 		/* Update power up / down sequence */
-		s_ctrl->power_setting_array =
-			sensor_slave_info.power_setting_array;
-		power_setting_array = &s_ctrl->power_setting_array;
-		power_setting_array->power_setting = kzalloc(
-			power_setting_array->size *
-			sizeof(struct msm_sensor_power_setting), GFP_KERNEL);
-		if (!power_setting_array->power_setting) {
-			pr_err("%s:%d failed\n", __func__, __LINE__);
-			rc = -ENOMEM;
-			break;
+		p_ctrl = &s_ctrl->sensordata->power_info;
+		size = sensor_slave_info.power_setting_array.size;
+		if (p_ctrl->power_setting_size < size) {
+			struct msm_sensor_power_setting *tmp;
+			tmp = kmalloc(sizeof(struct msm_sensor_power_setting)
+				      * size, GFP_KERNEL);
+			if (!tmp) {
+				pr_err("%s: failed to alloc mem\n", __func__);
+				rc = -ENOMEM;
+				break;
+			}
+			kfree(p_ctrl->power_setting);
+			p_ctrl->power_setting = tmp;
 		}
-		if (copy_from_user(power_setting_array->power_setting,
-		    (void *)sensor_slave_info.power_setting_array.power_setting,
-		    power_setting_array->size *
-		    sizeof(struct msm_sensor_power_setting))) {
-			kfree(power_setting_array->power_setting);
+		p_ctrl->power_setting_size = size;
+
+		rc = copy_from_user(p_ctrl->power_setting, (void *)
+			sensor_slave_info.power_setting_array.power_setting,
+			size * sizeof(struct msm_sensor_power_setting));
+		if (rc) {
 			pr_err("%s:%d failed\n", __func__, __LINE__);
 			rc = -EFAULT;
 			break;
 		}
-		s_ctrl->free_power_setting = true;
 		CDBG("%s sensor id %x\n", __func__,
 			sensor_slave_info.slave_addr);
 		CDBG("%s sensor addr type %d\n", __func__,
@@ -1293,19 +1308,14 @@
 		CDBG("%s sensor id %x\n", __func__,
 			sensor_slave_info.sensor_id_info.sensor_id);
 		for (slave_index = 0; slave_index <
-			power_setting_array->size; slave_index++) {
+			p_ctrl->power_setting_size; slave_index++) {
 			CDBG("%s i %d power setting %d %d %ld %d\n", __func__,
 				slave_index,
-				power_setting_array->power_setting[slave_index].
-				seq_type,
-				power_setting_array->power_setting[slave_index].
-				seq_val,
-				power_setting_array->power_setting[slave_index].
-				config_val,
-				power_setting_array->power_setting[slave_index].
-				delay);
+				p_ctrl->power_setting[slave_index].seq_type,
+				p_ctrl->power_setting[slave_index].seq_val,
+				p_ctrl->power_setting[slave_index].config_val,
+				p_ctrl->power_setting[slave_index].delay);
 		}
-		kfree(power_setting_array->power_setting);
 		break;
 	}
 	case CFG_WRITE_I2C_ARRAY: {
@@ -1388,8 +1398,7 @@
 
 	case CFG_POWER_DOWN:
 		if (s_ctrl->func_tbl->sensor_power_down)
-			rc = s_ctrl->func_tbl->sensor_power_down(
-				s_ctrl);
+			rc = s_ctrl->func_tbl->sensor_power_down(s_ctrl);
 		else
 			rc = -EFAULT;
 		break;
diff --git a/drivers/media/platform/msm/camera_v2/sensor/sp1628.c b/drivers/media/platform/msm/camera_v2/sensor/sp1628.c
index 9a422c0..d4e4cdf 100755
--- a/drivers/media/platform/msm/camera_v2/sensor/sp1628.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/sp1628.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
@@ -637,6 +637,10 @@
 		for (i = 0; i < SUB_MODULE_MAX; i++)
 			cdata->cfg.sensor_info.subdev_id[i] =
 				s_ctrl->sensordata->sensor_info->subdev_id[i];
+		cdata->cfg.sensor_info.is_mount_angle_valid =
+			s_ctrl->sensordata->sensor_info->is_mount_angle_valid;
+		cdata->cfg.sensor_info.sensor_mount_angle =
+			s_ctrl->sensordata->sensor_info->sensor_mount_angle;
 		CDBG("%s:%d sensor name %s\n", __func__, __LINE__,
 			cdata->cfg.sensor_info.sensor_name);
 		CDBG("%s:%d session id %d\n", __func__, __LINE__,
@@ -644,6 +648,9 @@
 		for (i = 0; i < SUB_MODULE_MAX; i++)
 			CDBG("%s:%d subdev_id[%d] %d\n", __func__, __LINE__, i,
 				cdata->cfg.sensor_info.subdev_id[i]);
+		CDBG("%s:%d mount angle valid %d value %d\n", __func__,
+			__LINE__, cdata->cfg.sensor_info.is_mount_angle_valid,
+			cdata->cfg.sensor_info.sensor_mount_angle);
 
 		break;
 	case CFG_SET_INIT_SETTING:
@@ -674,8 +681,12 @@
 			MSM_CAMERA_I2C_BYTE_DATA);
 		break;
 	case CFG_GET_SENSOR_INIT_PARAMS:
-		cdata->cfg.sensor_init_params =
-			*s_ctrl->sensordata->sensor_init_params;
+		cdata->cfg.sensor_init_params.modes_supported =
+			s_ctrl->sensordata->sensor_info->modes_supported;
+		cdata->cfg.sensor_init_params.position =
+			s_ctrl->sensordata->sensor_info->position;
+		cdata->cfg.sensor_init_params.sensor_mount_angle =
+			s_ctrl->sensordata->sensor_info->sensor_mount_angle;
 		CDBG("%s:%d init params mode %d pos %d mount %d\n", __func__,
 			__LINE__,
 			cdata->cfg.sensor_init_params.modes_supported,
@@ -724,7 +735,6 @@
 			rc = -EFAULT;
 			break;
 		}
-		s_ctrl->free_power_setting = true;
 		CDBG("%s sensor id %x\n", __func__,
 			sensor_slave_info.slave_addr);
 		CDBG("%s sensor addr type %d\n", __func__,
diff --git a/drivers/media/platform/msm/vidc/hfi_packetization.c b/drivers/media/platform/msm/vidc/hfi_packetization.c
index 4da0f6f..a563f68 100644
--- a/drivers/media/platform/msm/vidc/hfi_packetization.c
+++ b/drivers/media/platform/msm/vidc/hfi_packetization.c
@@ -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
@@ -342,12 +342,6 @@
 	case HAL_EXTRADATA_RECOVERY_POINT_SEI:
 		ret = HFI_PROPERTY_PARAM_VDEC_RECOVERY_POINT_SEI_EXTRADATA;
 		break;
-	case HAL_EXTRADATA_CLOSED_CAPTION_UD:
-		ret = HFI_PROPERTY_PARAM_VDEC_CLOSED_CAPTION_EXTRADATA;
-		break;
-	case HAL_EXTRADATA_AFD_UD:
-		ret = HFI_PROPERTY_PARAM_VDEC_AFD_EXTRADATA;
-		break;
 	case HAL_EXTRADATA_MULTISLICE_INFO:
 		ret = HFI_PROPERTY_PARAM_VENC_MULTI_SLICE_INFO;
 		break;
@@ -360,6 +354,21 @@
 	case HAL_EXTRADATA_MPEG2_SEQDISP:
 		ret = HFI_PROPERTY_PARAM_VDEC_MPEG2_SEQDISP_EXTRADATA;
 		break;
+	case HAL_EXTRADATA_FRAME_QP:
+		ret = HFI_PROPERTY_PARAM_VDEC_FRAME_QP_EXTRADATA;
+		break;
+	case HAL_EXTRADATA_FRAME_BITS_INFO:
+		ret = HFI_PROPERTY_PARAM_VDEC_FRAME_BITS_INFO_EXTRADATA;
+		break;
+	case HAL_EXTRADATA_LTR_INFO:
+		ret = HFI_PROPERTY_PARAM_VENC_LTR_INFO;
+		break;
+	case HAL_EXTRADATA_METADATA_MBI:
+		ret = HFI_PROPERTY_PARAM_VENC_MBI_DUMPING;
+		break;
+	case HAL_EXTRADATA_STREAM_USERDATA:
+		ret = HFI_PROPERTY_PARAM_VDEC_STREAM_USERDATA_EXTRADATA;
+		break;
 	default:
 		dprintk(VIDC_WARN, "Extradata index not found: %d\n", index);
 		break;
@@ -389,6 +398,28 @@
 	return buf_mode;
 }
 
+static u32 get_hfi_ltr_mode(enum ltr_mode ltr_mode_type)
+{
+	u32 ltrmode;
+	switch (ltr_mode_type) {
+	case HAL_LTR_MODE_DISABLE:
+		ltrmode = HFI_LTR_MODE_DISABLE;
+		break;
+	case HAL_LTR_MODE_MANUAL:
+		ltrmode = HFI_LTR_MODE_MANUAL;
+		break;
+	case HAL_LTR_MODE_PERIODIC:
+		ltrmode = HFI_LTR_MODE_PERIODIC;
+		break;
+	default:
+		dprintk(VIDC_ERR, "Invalid ltr mode :0x%x\n",
+			ltr_mode_type);
+		ltrmode = HFI_LTR_MODE_DISABLE;
+		break;
+	}
+	return ltrmode;
+}
+
 int create_pkt_cmd_session_set_buffers(
 		struct hfi_cmd_session_set_buffers_packet *pkt,
 		u32 session_id,
@@ -1405,6 +1436,76 @@
 		pkt->size += sizeof(u32) + sizeof(struct hfi_enable);
 		break;
 	}
+	case HAL_PARAM_VENC_LTRMODE:
+	{
+		struct hfi_ltrmode *hfi;
+		struct hal_ltrmode *hal = pdata;
+		pkt->rg_property_data[0] =
+			HFI_PROPERTY_PARAM_VENC_LTRMODE;
+		hfi = (struct hfi_ltrmode *) &pkt->rg_property_data[1];
+		hfi->ltrmode = get_hfi_ltr_mode(hal->ltrmode);
+		hfi->ltrcount = hal->ltrcount;
+		hfi->trustmode = hal->trustmode;
+		pkt->size += sizeof(u32) + sizeof(struct hfi_ltrmode);
+		pr_err("SET LTR\n");
+		break;
+	}
+	case HAL_CONFIG_VENC_USELTRFRAME:
+	{
+		struct hfi_ltruse *hfi;
+		struct hal_ltruse *hal = pdata;
+		pkt->rg_property_data[0] =
+			HFI_PROPERTY_CONFIG_VENC_USELTRFRAME;
+		hfi = (struct hfi_ltruse *) &pkt->rg_property_data[1];
+		hfi->frames = hal->frames;
+		hfi->refltr = hal->refltr;
+		hfi->useconstrnt = hal->useconstrnt;
+		pkt->size += sizeof(u32) + sizeof(struct hfi_ltruse);
+		pr_err("USE LTR\n");
+		break;
+	}
+	case HAL_CONFIG_VENC_MARKLTRFRAME:
+	{
+		struct hfi_ltrmark *hfi;
+		struct hal_ltrmark *hal = pdata;
+		pkt->rg_property_data[0] =
+			HFI_PROPERTY_CONFIG_VENC_MARKLTRFRAME;
+		hfi = (struct hfi_ltrmark *) &pkt->rg_property_data[1];
+		hfi->markframe = hal->markframe;
+		pkt->size += sizeof(u32) + sizeof(struct hfi_ltrmark);
+		pr_err("MARK LTR\n");
+		break;
+	}
+	case HAL_PARAM_VENC_HIER_P_MAX_ENH_LAYERS:
+	{
+		pkt->rg_property_data[0] =
+			HFI_PROPERTY_PARAM_VENC_HIER_P_MAX_NUM_ENH_LAYER;
+		pkt->rg_property_data[1] = *(u32 *)pdata;
+		pkt->size += sizeof(u32) * 2;
+		break;
+	}
+	case HAL_CONFIG_VENC_HIER_P_NUM_FRAMES:
+	{
+		pkt->rg_property_data[0] =
+			HFI_PROPERTY_CONFIG_VENC_HIER_P_ENH_LAYER;
+		pkt->rg_property_data[1] = *(u32 *)pdata;
+		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:
@@ -1432,7 +1533,7 @@
 	case HAL_CONFIG_VENC_TIMESTAMP_SCALE:
 	case HAL_PARAM_VENC_LOW_LATENCY:
 	default:
-		dprintk(VIDC_ERR, "DEFAULT: Calling 0x%x", ptype);
+		dprintk(VIDC_ERR, "DEFAULT: Calling 0x%x\n", ptype);
 		rc = -ENOTSUPP;
 		break;
 	}
diff --git a/drivers/media/platform/msm/vidc/hfi_response_handler.c b/drivers/media/platform/msm/vidc/hfi_response_handler.c
index 3fd5d3a..c6fb382 100644
--- a/drivers/media/platform/msm/vidc/hfi_response_handler.c
+++ b/drivers/media/platform/msm/vidc/hfi_response_handler.c
@@ -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
@@ -49,7 +49,7 @@
 		vidc_err = VIDC_ERR_NOT_SUPPORTED;
 		break;
 	case HFI_ERR_SYS_MAX_SESSIONS_REACHED:
-		vidc_err = VIDC_ERR_MAX_CLIENT;
+		vidc_err = VIDC_ERR_MAX_CLIENTS;
 		break;
 	case HFI_ERR_SYS_SESSION_IN_USE:
 		vidc_err = VIDC_ERR_CLIENT_PRESENT;
@@ -75,6 +75,8 @@
 		vidc_err = VIDC_ERR_FAIL;
 		break;
 	}
+	if (vidc_err != HFI_ERR_NONE)
+		dprintk(VIDC_ERR, "HFI Error: %d\n", vidc_err);
 	return vidc_err;
 }
 
@@ -108,7 +110,8 @@
 	struct hfi_frame_size frame_sz;
 	u8 *data_ptr;
 	int prop_id;
-	dprintk(VIDC_DBG, "RECEIVED:EVENT_NOTIFY");
+	dprintk(VIDC_DBG, "RECEIVED: EVENT_NOTIFY[%u]: %d, 0x%x\n",
+		pkt->session_id, pkt->event_data1, pkt->event_data2);
 	if (sizeof(struct hfi_msg_event_notify_packet)
 		> pkt->size) {
 		dprintk(VIDC_ERR, "hal_process_session_init_done:bad_pkt_size");
@@ -248,25 +251,33 @@
 		hfi_process_sys_error(callback, device_id);
 		break;
 	case HFI_EVENT_SESSION_ERROR:
-		dprintk(VIDC_INFO, "HFI_EVENT_SESSION_ERROR");
+		dprintk(VIDC_INFO,
+			"HFI_EVENT_SESSION_ERROR[%u]\n", pkt->session_id);
 		if (!validate_session_pkt(sessions, sess, session_lock))
 			hfi_process_session_error(callback, device_id, pkt);
 		break;
 	case HFI_EVENT_SESSION_SEQUENCE_CHANGED:
-		dprintk(VIDC_INFO, "HFI_EVENT_SESSION_SEQUENCE_CHANGED");
+		dprintk(VIDC_INFO, "HFI_EVENT_SESSION_SEQUENCE_CHANGED[%u]\n",
+			pkt->session_id);
 		if (!validate_session_pkt(sessions, sess, session_lock))
 			hfi_process_sess_evt_seq_changed(callback,
 				device_id, pkt);
 		break;
 	case HFI_EVENT_SESSION_PROPERTY_CHANGED:
-		dprintk(VIDC_INFO, "HFI_EVENT_SESSION_PROPERTY_CHANGED");
+		dprintk(VIDC_INFO, "HFI_EVENT_SESSION_PROPERTY_CHANGED[%u]\n",
+			pkt->session_id);
 		break;
 	case HFI_EVENT_RELEASE_BUFFER_REFERENCE:
-		dprintk(VIDC_INFO, "HFI_EVENT_RELEASE_BUFFER_REFERENCE\n");
-		hfi_process_evt_release_buffer_ref(callback, device_id, pkt);
+		dprintk(VIDC_INFO, "HFI_EVENT_RELEASE_BUFFER_REFERENCE[%u]\n",
+			pkt->session_id);
+		if (!validate_session_pkt(sessions, sess, session_lock))
+			hfi_process_evt_release_buffer_ref(callback,
+				device_id, pkt);
 		break;
 	default:
-		dprintk(VIDC_WARN, "hal_process_event_notify:unkown_event_id");
+		dprintk(VIDC_WARN,
+			"hal_process_event_notify: unknown_event_id[%u]\n",
+			pkt->session_id);
 		break;
 	}
 }
@@ -386,6 +397,10 @@
 		struct vidc_hal_session_init_done *sess_init_done)
 {
 	struct hal_capability_supported *out = NULL;
+	if (!in) {
+		dprintk(VIDC_ERR, "Invalid input for supported capabilties\n");
+		return;
+	}
 	switch (in->capability_type) {
 	case HFI_CAPABILITY_FRAME_WIDTH:
 		out = &sess_init_done->width;
@@ -418,9 +433,17 @@
 	case HFI_CAPABILITY_BITRATE:
 		out = &sess_init_done->bitrate;
 		break;
+
+	case HFI_CAPABILITY_ENC_LTR_COUNT:
+		out = &sess_init_done->ltr_count;
+		break;
+
+	case HFI_CAPABILITY_HIER_P_NUM_ENH_LAYERS:
+		out = &sess_init_done->hier_p;
+		break;
 	}
 
-	if (in && out) {
+	if (out) {
 		out->capability_type =
 			(enum hal_capability)in->capability_type;
 		out->min = in->min;
@@ -744,7 +767,8 @@
 	struct msm_vidc_cb_cmd_done cmd_done;
 	struct buffer_requirements buff_req;
 
-	dprintk(VIDC_DBG, "Received SESSION_PROPERTY_INFO");
+	dprintk(VIDC_DBG, "Received SESSION_PROPERTY_INFO[%u]\n",
+		pkt->session_id);
 
 	if (pkt->size < sizeof(struct hfi_msg_session_property_info_packet)) {
 		dprintk(VIDC_ERR, "hal_process_session_prop_info:bad_pkt_size");
@@ -786,7 +810,8 @@
 	struct msm_vidc_cb_cmd_done cmd_done;
 	struct vidc_hal_session_init_done session_init_done;
 	struct hal_session *sess_close = NULL;
-	dprintk(VIDC_DBG, "RECEIVED:SESSION_INIT_DONE");
+	dprintk(VIDC_DBG, "RECEIVED: SESSION_INIT_DONE[%u]\n",
+		pkt->session_id);
 	if (sizeof(struct hfi_msg_sys_session_init_done_packet)
 		> pkt->size) {
 		dprintk(VIDC_ERR, "hal_process_session_init_done:bad_pkt_size");
@@ -825,7 +850,8 @@
 		struct hfi_msg_session_load_resources_done_packet *pkt)
 {
 	struct msm_vidc_cb_cmd_done cmd_done;
-	dprintk(VIDC_DBG, "RECEIVED:SESSION_LOAD_RESOURCES_DONE");
+	dprintk(VIDC_DBG, "RECEIVED: SESSION_LOAD_RESOURCES_DONE[%u]\n",
+		pkt->session_id);
 
 	if (sizeof(struct hfi_msg_session_load_resources_done_packet) !=
 		pkt->size) {
@@ -851,7 +877,8 @@
 {
 	struct msm_vidc_cb_cmd_done cmd_done;
 
-	dprintk(VIDC_DBG, "RECEIVED:SESSION_FLUSH_DONE");
+	dprintk(VIDC_DBG, "RECEIVED: SESSION_FLUSH_DONE[%u]\n",
+		pkt->session_id);
 
 	if (sizeof(struct hfi_msg_session_flush_done_packet) != pkt->size) {
 		dprintk(VIDC_ERR, "hal_process_session_flush_done: "
@@ -875,7 +902,8 @@
 {
 	struct msm_vidc_cb_data_done data_done;
 
-	dprintk(VIDC_DBG, "RECEIVED:SESSION_ETB_DONE");
+	dprintk(VIDC_DBG, "RECEIVED: SESSION_ETB_DONE[%u]\n",
+		pkt->session_id);
 
 	if (!pkt || pkt->size <
 		sizeof(struct hfi_msg_session_empty_buffer_done_packet)) {
@@ -916,7 +944,8 @@
 
 	session = (struct hal_session *)
 		((struct hal_session *)	pack->session_id)->session_id;
-	dprintk(VIDC_DBG, "RECEIVED:SESSION_FTB_DONE");
+	dprintk(VIDC_DBG, "RECEIVED: SESSION_FTB_DONE[%u]\n",
+		pack->session_id);
 
 	memset(&data_done, 0, sizeof(struct msm_vidc_cb_data_done));
 
@@ -1014,7 +1043,8 @@
 {
 	struct msm_vidc_cb_cmd_done cmd_done;
 
-	dprintk(VIDC_DBG, "RECEIVED:SESSION_START_DONE");
+	dprintk(VIDC_DBG, "RECEIVED: SESSION_START_DONE[%u]\n",
+		pkt->session_id);
 
 	if (!pkt || pkt->size !=
 		sizeof(struct hfi_msg_session_start_done_packet)) {
@@ -1039,7 +1069,8 @@
 {
 	struct msm_vidc_cb_cmd_done cmd_done;
 
-	dprintk(VIDC_DBG, "RECEIVED:SESSION_STOP_DONE");
+	dprintk(VIDC_DBG, "RECEIVED: SESSION_STOP_DONE[%u]\n",
+		pkt->session_id);
 
 	if (!pkt || pkt->size !=
 		sizeof(struct hfi_msg_session_stop_done_packet)) {
@@ -1064,7 +1095,8 @@
 {
 	struct msm_vidc_cb_cmd_done cmd_done;
 
-	dprintk(VIDC_DBG, "RECEIVED:SESSION_RELEASE_RESOURCES_DONE");
+	dprintk(VIDC_DBG, "RECEIVED: SESSION_RELEASE_RESOURCES_DONE[%u]\n",
+		pkt->session_id);
 
 	if (!pkt || pkt->size !=
 		sizeof(struct hfi_msg_session_release_resources_done_packet)) {
@@ -1088,6 +1120,8 @@
 		struct hfi_msg_session_release_buffers_done_packet *pkt)
 {
 	struct msm_vidc_cb_cmd_done cmd_done;
+	dprintk(VIDC_DBG, "RECEIVED:SESSION_RELEASE_BUFFER_DONE[%u]\n",
+		pkt->session_id);
 	if (!pkt || pkt->size !=
 		sizeof(struct
 			   hfi_msg_session_release_buffers_done_packet)) {
@@ -1115,7 +1149,8 @@
 {
 	struct msm_vidc_cb_cmd_done cmd_done;
 
-	dprintk(VIDC_DBG, "RECEIVED:SESSION_END_DONE");
+	dprintk(VIDC_DBG, "RECEIVED: SESSION_END_DONE[%u]\n",
+		pkt->session_id);
 
 	if (!pkt || pkt->size !=
 		sizeof(struct hfi_msg_sys_session_end_done_packet)) {
@@ -1140,8 +1175,8 @@
 {
 	struct msm_vidc_cb_cmd_done cmd_done;
 
-	dprintk(VIDC_DBG, "RECEIVED:SESSION_ABORT_DONE");
-
+	dprintk(VIDC_DBG, "RECEIVED: SESSION_ABORT_DONE[%u]\n",
+		pkt->session_id);
 	if (!pkt || pkt->size !=
 		sizeof(struct hfi_msg_sys_session_abort_done_packet)) {
 		dprintk(VIDC_ERR, "%s: bad packet/packet size: %d",
@@ -1170,6 +1205,8 @@
 		dprintk(VIDC_ERR, "bad packet/packet size: %d", pkt->size);
 		return;
 	}
+	dprintk(VIDC_DBG, "RECEIVED:SESSION_GET_SEQ_HDR_DONE[%u]\n",
+		pkt->session_id);
 	memset(&data_done, 0, sizeof(struct msm_vidc_cb_data_done));
 	data_done.device_id = device_id;
 	data_done.size = sizeof(struct msm_vidc_cb_data_done);
diff --git a/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c b/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c
index 468ba74..c638415 100644
--- a/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c
+++ b/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c
@@ -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
@@ -120,6 +120,13 @@
 	return msm_vidc_g_ctrl((void *)vidc_inst, a);
 }
 
+int msm_v4l2_s_ext_ctrl(struct file *file, void *fh,
+					struct v4l2_ext_controls *a)
+{
+	struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh);
+	return msm_vidc_s_ext_ctrl((void *)vidc_inst, a);
+}
+
 int msm_v4l2_reqbufs(struct file *file, void *fh,
 				struct v4l2_requestbuffers *b)
 {
@@ -242,6 +249,7 @@
 	.vidioc_streamoff = msm_v4l2_streamoff,
 	.vidioc_s_ctrl = msm_v4l2_s_ctrl,
 	.vidioc_g_ctrl = msm_v4l2_g_ctrl,
+	.vidioc_s_ext_ctrls = msm_v4l2_s_ext_ctrl,
 	.vidioc_subscribe_event = msm_v4l2_subscribe_event,
 	.vidioc_unsubscribe_event = msm_v4l2_unsubscribe_event,
 	.vidioc_decoder_cmd = msm_v4l2_decoder_cmd,
@@ -311,7 +319,6 @@
 	}
 
 	INIT_LIST_HEAD(&core->instances);
-	mutex_init(&core->sync_lock);
 	mutex_init(&core->lock);
 
 	core->state = VIDC_CORE_UNINIT;
@@ -389,18 +396,22 @@
 	rc = msm_vidc_initialize_core(pdev, core);
 	if (rc) {
 		dprintk(VIDC_ERR, "Failed to init core\n");
-		goto err_v4l2_register;
+		goto err_core_init;
 	}
 	rc = device_create_file(&pdev->dev, &dev_attr_pwr_collapse_delay);
 	if (rc) {
 		dprintk(VIDC_ERR,
 				"Failed to create pwr_collapse_delay sysfs node");
-		goto err_v4l2_register;
+		goto err_core_init;
 	}
 	if (core->hfi_type == VIDC_HFI_Q6) {
 		dprintk(VIDC_ERR, "Q6 hfi device probe called\n");
 		nr += MSM_VIDC_MAX_DEVICES;
+		core->id = MSM_VIDC_CORE_Q6;
+	} else {
+		core->id = MSM_VIDC_CORE_VENUS;
 	}
+
 	rc = v4l2_device_register(&pdev->dev, &core->v4l2_dev);
 	if (rc) {
 		dprintk(VIDC_ERR, "Failed to register v4l2 device\n");
@@ -453,16 +464,20 @@
 				vidc_driver->num_cores);
 		goto err_cores_exceeded;
 	}
-	core->id = vidc_driver->num_cores++;
+	vidc_driver->num_cores++;
 	mutex_unlock(&vidc_driver->lock);
 
 	core->device = vidc_hfi_initialize(core->hfi_type, core->id,
 				&core->resources, &handle_cmd_response);
-	if (!core->device) {
-		dprintk(VIDC_ERR, "Failed to create HFI device\n");
+	if (IS_ERR_OR_NULL(core->device)) {
 		mutex_lock(&vidc_driver->lock);
 		vidc_driver->num_cores--;
 		mutex_unlock(&vidc_driver->lock);
+		rc = PTR_ERR(core->device);
+		if (rc != -EPROBE_DEFER)
+			dprintk(VIDC_ERR, "Failed to create HFI device\n");
+		else
+			dprintk(VIDC_DBG, "msm_vidc: request probe defer\n");
 		goto err_cores_exceeded;
 	}
 
@@ -487,6 +502,8 @@
 err_dec_register:
 	v4l2_device_unregister(&core->v4l2_dev);
 err_v4l2_register:
+	device_remove_file(&pdev->dev, &dev_attr_pwr_collapse_delay);
+err_core_init:
 	kfree(core);
 err_no_mem:
 	return rc;
@@ -523,6 +540,7 @@
 }
 static const struct of_device_id msm_vidc_dt_match[] = {
 	{.compatible = "qcom,msm-vidc"},
+	{}
 };
 
 MODULE_DEVICE_TABLE(of, msm_vidc_dt_match);
diff --git a/drivers/media/platform/msm/vidc/msm_vdec.c b/drivers/media/platform/msm/vidc/msm_vdec.c
index 9dd4e93..f84a806 100644
--- a/drivers/media/platform/msm/vidc/msm_vdec.c
+++ b/drivers/media/platform/msm/vidc/msm_vdec.c
@@ -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
@@ -21,16 +21,12 @@
 
 #define MSM_VDEC_DVC_NAME "msm_vdec_8974"
 #define MIN_NUM_OUTPUT_BUFFERS 4
-#define MAX_NUM_OUTPUT_BUFFERS 6
-#define DEFAULT_CONCEAL_COLOR 0x0
+#define MAX_NUM_OUTPUT_BUFFERS VIDEO_MAX_FRAME
+#define DEFAULT_VIDEO_CONCEAL_COLOR_BLACK 0x8080
 
-#define TZ_INFO_GET_FEATURE_VERSION_ID 0x3
 #define TZ_DYNAMIC_BUFFER_FEATURE_ID 12
 #define TZ_FEATURE_VERSION(major, minor, patch) \
 	(((major & 0x3FF) << 22) | ((minor & 0x3FF) << 12) | (patch & 0xFFF))
-struct tz_get_feature_version {
-	u32 feature_id;
-};
 
 enum msm_vdec_ctrl_cluster {
 	MSM_VDEC_CTRL_CLUSTER_MAX = 1 << 0,
@@ -106,7 +102,6 @@
 		),
 		.qmenu = mpeg_video_stream_format,
 		.step = 0,
-		.cluster = 0,
 	},
 	{
 		.id = V4L2_CID_MPEG_VIDC_VIDEO_OUTPUT_ORDER,
@@ -121,7 +116,6 @@
 			),
 		.qmenu = mpeg_video_output_order,
 		.step = 0,
-		.cluster = 0,
 	},
 	{
 		.id = V4L2_CID_MPEG_VIDC_VIDEO_ENABLE_PICTURE_TYPE,
@@ -133,7 +127,6 @@
 		.step = 1,
 		.menu_skip_mask = 0,
 		.qmenu = NULL,
-		.cluster = 0,
 	},
 	{
 		.id = V4L2_CID_MPEG_VIDC_VIDEO_KEEP_ASPECT_RATIO,
@@ -145,7 +138,6 @@
 		.step = 1,
 		.menu_skip_mask = 0,
 		.qmenu = NULL,
-		.cluster = 0,
 	},
 	{
 		.id = V4L2_CID_MPEG_VIDC_VIDEO_POST_LOOP_DEBLOCKER_MODE,
@@ -157,7 +149,6 @@
 		.step = 1,
 		.menu_skip_mask = 0,
 		.qmenu = NULL,
-		.cluster = 0,
 	},
 	{
 		.id = V4L2_CID_MPEG_VIDC_VIDEO_DIVX_FORMAT,
@@ -173,7 +164,6 @@
 			),
 		.qmenu = mpeg_video_vidc_divx_format,
 		.step = 0,
-		.cluster = 0,
 	},
 	{
 		.id = V4L2_CID_MPEG_VIDC_VIDEO_MB_ERROR_MAP_REPORTING,
@@ -185,7 +175,6 @@
 		.step = 1,
 		.menu_skip_mask = 0,
 		.qmenu = NULL,
-		.cluster = 0,
 	},
 	{
 		.id = V4L2_CID_MPEG_VIDC_VIDEO_CONTINUE_DATA_TRANSFER,
@@ -197,7 +186,6 @@
 		.step = 1,
 		.menu_skip_mask = 0,
 		.qmenu = NULL,
-		.cluster = 0,
 	},
 	{
 		.id = V4L2_CID_MPEG_VIDC_VIDEO_SYNC_FRAME_DECODE,
@@ -217,14 +205,13 @@
 		.step = 0,
 		.menu_skip_mask = 0,
 		.qmenu = NULL,
-		.cluster = 0,
 	},
 	{
 		.id = V4L2_CID_MPEG_VIDC_VIDEO_EXTRADATA,
 		.name = "Extradata Type",
 		.type = V4L2_CTRL_TYPE_MENU,
 		.minimum = V4L2_MPEG_VIDC_EXTRADATA_NONE,
-		.maximum = V4L2_MPEG_VIDC_EXTRADATA_MPEG2_SEQDISP,
+		.maximum = V4L2_MPEG_VIDC_EXTRADATA_STREAM_USERDATA,
 		.default_value = V4L2_MPEG_VIDC_EXTRADATA_NONE,
 		.menu_skip_mask = ~(
 			(1 << V4L2_MPEG_VIDC_EXTRADATA_NONE) |
@@ -237,15 +224,16 @@
 			(1 << V4L2_MPEG_VIDC_EXTRADATA_FRAME_RATE) |
 			(1 << V4L2_MPEG_VIDC_EXTRADATA_PANSCAN_WINDOW) |
 			(1 << V4L2_MPEG_VIDC_EXTRADATA_RECOVERY_POINT_SEI) |
-			(1 << V4L2_MPEG_VIDC_EXTRADATA_CLOSED_CAPTION_UD) |
-			(1 << V4L2_MPEG_VIDC_EXTRADATA_AFD_UD) |
 			(1 << V4L2_MPEG_VIDC_EXTRADATA_MULTISLICE_INFO) |
 			(1 << V4L2_MPEG_VIDC_EXTRADATA_NUM_CONCEALED_MB) |
 			(1 << V4L2_MPEG_VIDC_EXTRADATA_METADATA_FILLER) |
 			(1 << V4L2_MPEG_VIDC_INDEX_EXTRADATA_INPUT_CROP) |
 			(1 << V4L2_MPEG_VIDC_INDEX_EXTRADATA_DIGITAL_ZOOM) |
 			(1 << V4L2_MPEG_VIDC_INDEX_EXTRADATA_ASPECT_RATIO) |
-			(1 << V4L2_MPEG_VIDC_EXTRADATA_MPEG2_SEQDISP)
+			(1 << V4L2_MPEG_VIDC_EXTRADATA_MPEG2_SEQDISP) |
+			(1 << V4L2_MPEG_VIDC_EXTRADATA_FRAME_QP) |
+			(1 << V4L2_MPEG_VIDC_EXTRADATA_FRAME_BITS_INFO) |
+			(1 << V4L2_MPEG_VIDC_EXTRADATA_STREAM_USERDATA)
 			),
 		.qmenu = mpeg_video_vidc_extradata,
 		.step = 0,
@@ -277,7 +265,6 @@
 			),
 		.qmenu = mpeg_vidc_video_alloc_mode_type,
 		.step = 0,
-		.cluster = 0,
 	},
 	{
 		.id = V4L2_CID_MPEG_VIDC_VIDEO_ALLOC_MODE_OUTPUT,
@@ -293,7 +280,6 @@
 			),
 		.qmenu = mpeg_vidc_video_alloc_mode_type,
 		.step = 0,
-		.cluster = 0,
 	},
 	{
 		.id = V4L2_CID_MPEG_VIDC_VIDEO_FRAME_ASSEMBLY,
@@ -305,7 +291,6 @@
 		.step = 1,
 		.menu_skip_mask = 0,
 		.qmenu = NULL,
-		.cluster = 0,
 	},
 	{
 		.id = V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_MODE,
@@ -321,7 +306,15 @@
 		.menu_skip_mask = 0,
 		.step = 1,
 		.qmenu = NULL,
-		.cluster = 0,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_CONCEAL_COLOR,
+		.name = "Picture concealed color",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 0x0,
+		.maximum = 0xffffff,
+		.default_value = DEFAULT_VIDEO_CONCEAL_COLOR_BLACK,
+		.step = 1,
 	},
 };
 
@@ -568,15 +561,7 @@
 				core);
 		goto exit;
 	}
-	if (!inst->in_reconfig) {
-		rc = msm_comm_try_state(inst, MSM_VIDC_RELEASE_RESOURCES_DONE);
-		if (rc) {
-			dprintk(VIDC_ERR,
-				"Failed to move inst: %p to relase res done\n",
-				inst);
-			goto exit;
-		}
-	}
+
 	switch (b->type) {
 	case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
 		break;
@@ -679,7 +664,7 @@
 	rc = vb2_reqbufs(&q->vb2_bufq, b);
 	mutex_unlock(&q->lock);
 	if (rc)
-		dprintk(VIDC_ERR, "Failed to get reqbufs, %d\n", rc);
+		dprintk(VIDC_DBG, "Failed to get reqbufs, %d\n", rc);
 	return rc;
 }
 
@@ -693,11 +678,20 @@
 	int rc = 0;
 	int i;
 	struct hal_buffer_requirements *buff_req_buffer;
+
 	if (!inst || !f || !inst->core || !inst->core->device) {
 		dprintk(VIDC_ERR,
 			"Invalid input, inst = %p, format = %p\n", inst, f);
 		return -EINVAL;
 	}
+
+	rc = msm_comm_try_get_bufreqs(inst);
+	if (rc) {
+		dprintk(VIDC_ERR, "Getting buffer requirements failed: %d\n",
+				rc);
+		return rc;
+	}
+
 	hdev = inst->core->device;
 	if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
 		fmt = inst->fmts[CAPTURE_PORT];
@@ -807,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",
@@ -856,9 +870,8 @@
 		dprintk(VIDC_PROF, "reported fps changed for %p: %d->%d\n",
 				inst, inst->prop.fps, fps);
 		inst->prop.fps = fps;
-		mutex_lock(&inst->core->sync_lock);
+
 		msm_comm_scale_clocks_and_bus(inst);
-		mutex_unlock(&inst->core->sync_lock);
 	}
 exit:
 	return rc;
@@ -971,11 +984,17 @@
 			rc = -EINVAL;
 			goto err_invalid_fmt;
 		}
+		rc = msm_comm_try_state(inst, MSM_VIDC_CORE_INIT_DONE);
+		if (rc) {
+			dprintk(VIDC_ERR, "Failed to initialize instance\n");
+			goto err_invalid_fmt;
+		}
 		if (!(get_hal_codec_type(fmt->fourcc) &
 			inst->core->dec_codec_supported)) {
 			dprintk(VIDC_ERR,
-				"Codec(0x%x) not supported\n",
-				get_hal_codec_type(fmt->fourcc));
+				"Codec(0x%x) is not present in the supported codecs list(0x%x)\n",
+				get_hal_codec_type(fmt->fourcc),
+				inst->core->dec_codec_supported);
 			rc = -EINVAL;
 			goto err_invalid_fmt;
 		}
@@ -1170,64 +1189,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;
@@ -1266,9 +1227,8 @@
 			goto fail_start;
 		}
 	}
-	mutex_lock(&inst->core->sync_lock);
+
 	msm_comm_scale_clocks_and_bus(inst);
-	mutex_unlock(&inst->core->sync_lock);
 
 	rc = msm_comm_try_state(inst, MSM_VIDC_START_DONE);
 	if (rc) {
@@ -1278,7 +1238,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);
@@ -1319,7 +1279,6 @@
 {
 	struct msm_vidc_inst *inst;
 	int rc = 0;
-	int pdata = DEFAULT_CONCEAL_COLOR;
 	struct hfi_device *hdev;
 	if (!q || !q->drv_priv) {
 		dprintk(VIDC_ERR, "Invalid input, q = %p\n", q);
@@ -1337,10 +1296,6 @@
 	case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
 		if (inst->bufq[CAPTURE_PORT].vb2_bufq.streaming)
 			rc = start_streaming(inst);
-		rc = call_hfi_op(hdev, session_set_property,
-			(void *) inst->session,
-			HAL_PARAM_VDEC_CONCEAL_COLOR,
-			(void *) &pdata);
 		break;
 	case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
 		if (inst->bufq[OUTPUT_PORT].vb2_bufq.streaming)
@@ -1380,9 +1335,7 @@
 		break;
 	}
 
-	mutex_lock(&inst->core->sync_lock);
 	msm_comm_scale_clocks_and_bus(inst);
-	mutex_unlock(&inst->core->sync_lock);
 
 	if (rc)
 		dprintk(VIDC_ERR,
@@ -1410,7 +1363,19 @@
 	}
 	switch (dec->cmd) {
 	case V4L2_DEC_QCOM_CMD_FLUSH:
+		if (core->state != VIDC_CORE_INVALID &&
+			inst->state ==  MSM_VIDC_CORE_INVALID) {
+			rc = msm_comm_recover_from_session_error(inst);
+			if (rc)
+				dprintk(VIDC_ERR,
+					"Failed to recover from session_error: %d\n",
+					rc);
+		}
 		rc = msm_comm_flush(inst, dec->flags);
+		if (rc) {
+			dprintk(VIDC_ERR,
+					"Failed to flush buffers: %d\n", rc);
+		}
 		break;
 	case V4L2_DEC_CMD_STOP:
 		if (core->state != VIDC_CORE_INVALID &&
@@ -1512,17 +1477,16 @@
 static int check_tz_dynamic_buffer_support(void)
 {
 	int rc = 0;
-	struct tz_get_feature_version tz_feature_id;
-	unsigned int resp = 0;
+	int version = scm_get_feat_version(TZ_DYNAMIC_BUFFER_FEATURE_ID);
 
-	tz_feature_id.feature_id = TZ_DYNAMIC_BUFFER_FEATURE_ID;
-	rc = scm_call(SCM_SVC_INFO,
-		  TZ_INFO_GET_FEATURE_VERSION_ID, &tz_feature_id,
-		  sizeof(tz_feature_id), &resp, sizeof(resp));
-	if ((rc) || (resp != TZ_FEATURE_VERSION(1, 1, 0))) {
+	/*
+	 * if the version is < 1.1.0 then dynamic buffer allocation is
+	 * not supported
+	 */
+	if (version < TZ_FEATURE_VERSION(1, 1, 0)) {
 		dprintk(VIDC_DBG,
-			"Dyamic buffer mode not supported, failed to get tz feature version id : %u, rc : %d, response : %u\n",
-			tz_feature_id.feature_id, rc, resp);
+			"Dynamic buffer mode not supported, tz version is : %u vs required : %u\n",
+			version, TZ_FEATURE_VERSION(1, 1, 0));
 		rc = -ENOTSUPP;
 	}
 	return rc;
@@ -1732,6 +1696,11 @@
 			break;
 		}
 		break;
+	case V4L2_CID_MPEG_VIDC_VIDEO_CONCEAL_COLOR:
+		property_id = HAL_PARAM_VDEC_CONCEAL_COLOR;
+		property_val = ctrl->val;
+		pdata = &property_val;
+		break;
 	default:
 		break;
 	}
@@ -1805,21 +1774,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;
@@ -1830,6 +1796,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);
 
@@ -1883,7 +1862,7 @@
 		}
 
 
-		msm_vdec_ctrls[idx].priv = ctrl;
+		inst->ctrls[idx] = ctrl;
 	}
 	ret_val = inst->ctrl_handler.error;
 	if (ret_val)
@@ -1891,41 +1870,29 @@
 			"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);
+	if (!inst) {
+		dprintk(VIDC_ERR, "%s invalid parameters\n", __func__);
+		return -EINVAL;
 	}
+
+	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 c0bf32c..d9d65a7 100644
--- a/drivers/media/platform/msm/vidc/msm_venc.c
+++ b/drivers/media/platform/msm/vidc/msm_venc.c
@@ -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
@@ -37,6 +37,8 @@
 #define B_FRAME_QP 30
 #define MAX_INTRA_REFRESH_MBS 300
 #define MAX_NUM_B_FRAMES 4
+#define MAX_LTR_FRAME_COUNT 10
+
 #define L_MODE V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED_AT_SLICE_BOUNDARY
 #define CODING V4L2_MPEG_VIDEO_MPEG4_PROFILE_ADVANCED_CODING_EFFICIENCY
 
@@ -114,6 +116,8 @@
 	"Extradata input crop",
 	"Extradata digital zoom",
 	"Extradata aspect ratio",
+	"Extradata LTR",
+	"Extradata macroblock metadata",
 };
 
 static const char *const perf_level[] = {
@@ -122,6 +126,14 @@
 	"Turbo"
 };
 
+static const char *const intra_refresh_modes[] = {
+	"None",
+	"Cyclic",
+	"Adaptive",
+	"Cyclic Adaptive",
+	"Random"
+};
+
 enum msm_venc_ctrl_cluster {
 	MSM_VENC_CTRL_CLUSTER_QP = 1 << 0,
 	MSM_VENC_CTRL_CLUSTER_INTRA_PERIOD = 1 << 1,
@@ -135,7 +147,8 @@
 	MSM_VENC_CTRL_CLUSTER_TIMING = 1 << 9,
 	MSM_VENC_CTRL_CLUSTER_VP8_PROFILE_LEVEL = 1 << 10,
 	MSM_VENC_CTRL_CLUSTER_DEINTERLACE = 1 << 11,
-	MSM_VENC_CTRL_CLUSTER_MAX = 1 << 12,
+	MSM_VENC_CTRL_CLUSTER_USE_LTRFRAME = 1 << 12,
+	MSM_VENC_CTRL_CLUSTER_MAX = 1 << 13,
 };
 
 static struct msm_vidc_ctrl msm_venc_ctrls[] = {
@@ -149,7 +162,6 @@
 		.step = 1,
 		.menu_skip_mask = 0,
 		.qmenu = NULL,
-		.cluster = 0,
 	},
 	{
 		.id = V4L2_CID_MPEG_VIDEO_H264_I_PERIOD,
@@ -161,19 +173,17 @@
 		.step = 1,
 		.menu_skip_mask = 0,
 		.qmenu = NULL,
-		.cluster = MSM_VENC_CTRL_CLUSTER_INTRA_PERIOD,
 	},
 	{
 		.id = V4L2_CID_MPEG_VIDC_VIDEO_NUM_P_FRAMES,
 		.name = "Intra Period for P frames",
 		.type = V4L2_CTRL_TYPE_INTEGER,
 		.minimum = 0,
-		.maximum = 10*DEFAULT_FRAME_RATE,
+		.maximum = INT_MAX,
 		.default_value = 2*DEFAULT_FRAME_RATE-1,
 		.step = 1,
 		.menu_skip_mask = 0,
 		.qmenu = NULL,
-		.cluster = MSM_VENC_CTRL_CLUSTER_INTRA_PERIOD,
 	},
 	{
 		.id = V4L2_CID_MPEG_VIDC_VIDEO_NUM_B_FRAMES,
@@ -185,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,
@@ -197,7 +206,6 @@
 		.step = 0,
 		.menu_skip_mask = 0,
 		.qmenu = NULL,
-		.cluster = 0,
 	},
 	{
 		.id = V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL,
@@ -215,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,
@@ -231,7 +237,6 @@
 		(1 << V4L2_MPEG_VIDEO_BITRATE_MODE_CBR)
 		),
 		.qmenu = NULL,
-		.cluster = MSM_VENC_CTRL_CLUSTER_BITRATE,
 	},
 	{
 		.id = V4L2_CID_MPEG_VIDEO_BITRATE,
@@ -243,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,
@@ -255,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,
@@ -269,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,
@@ -285,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,
@@ -296,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,
@@ -307,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,
@@ -318,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,
@@ -329,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,
@@ -350,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,
@@ -369,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,
@@ -384,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,
@@ -401,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,
@@ -413,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,
@@ -425,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,
@@ -437,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,
@@ -449,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,
@@ -461,7 +450,24 @@
 		.step = 1,
 		.menu_skip_mask = 0,
 		.qmenu = NULL,
-		.cluster = MSM_VENC_CTRL_CLUSTER_QP,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_VP8_MIN_QP,
+		.name = "VP8 Minimum QP",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 1,
+		.maximum = 128,
+		.default_value = 1,
+		.step = 1,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_VP8_MAX_QP,
+		.name = "VP8 Maximum QP",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 1,
+		.maximum = 128,
+		.default_value = 128,
+		.step = 1,
 	},
 	{
 		.id = V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE,
@@ -477,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,
@@ -489,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,
@@ -501,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,
@@ -513,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,
@@ -525,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,
@@ -542,7 +543,7 @@
 		(1 << V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_CYCLIC_ADAPTIVE) |
 		(1 << V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_RANDOM)
 		),
-		.cluster = MSM_VENC_CTRL_CLUSTER_INTRA_REFRESH,
+		.qmenu = intra_refresh_modes,
 	},
 	{
 		.id = V4L2_CID_MPEG_VIDC_VIDEO_AIR_MBS,
@@ -554,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,
@@ -566,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,
@@ -578,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,
@@ -590,7 +588,6 @@
 		.step = 1,
 		.menu_skip_mask = 0,
 		.qmenu = NULL,
-		.cluster = 0,
 	},
 	{
 		.id = V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA,
@@ -602,7 +599,6 @@
 		.step = 1,
 		.menu_skip_mask = 0,
 		.qmenu = NULL,
-		.cluster = 0,
 	},
 	{
 		.id = V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE,
@@ -617,7 +613,6 @@
 		(1 << V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED) |
 		(1 << L_MODE)
 		),
-		.cluster = 0,
 	},
 	{
 		.id = V4L2_CID_MPEG_VIDEO_HEADER_MODE,
@@ -632,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,
@@ -644,14 +638,13 @@
 		.step = 0,
 		.menu_skip_mask = 0,
 		.qmenu = NULL,
-		.cluster = 0,
 	},
 	{
 		.id = V4L2_CID_MPEG_VIDC_VIDEO_EXTRADATA,
 		.name = "Extradata Type",
 		.type = V4L2_CTRL_TYPE_MENU,
 		.minimum = V4L2_MPEG_VIDC_EXTRADATA_NONE,
-		.maximum = V4L2_MPEG_VIDC_INDEX_EXTRADATA_ASPECT_RATIO,
+		.maximum = V4L2_MPEG_VIDC_EXTRADATA_METADATA_MBI,
 		.default_value = V4L2_MPEG_VIDC_EXTRADATA_NONE,
 		.menu_skip_mask = ~(
 			(1 << V4L2_MPEG_VIDC_EXTRADATA_NONE) |
@@ -664,14 +657,14 @@
 			(1 << V4L2_MPEG_VIDC_EXTRADATA_FRAME_RATE) |
 			(1 << V4L2_MPEG_VIDC_EXTRADATA_PANSCAN_WINDOW) |
 			(1 << V4L2_MPEG_VIDC_EXTRADATA_RECOVERY_POINT_SEI) |
-			(1 << V4L2_MPEG_VIDC_EXTRADATA_CLOSED_CAPTION_UD) |
-			(1 << V4L2_MPEG_VIDC_EXTRADATA_AFD_UD) |
 			(1 << V4L2_MPEG_VIDC_EXTRADATA_MULTISLICE_INFO) |
 			(1 << V4L2_MPEG_VIDC_EXTRADATA_NUM_CONCEALED_MB) |
 			(1 << V4L2_MPEG_VIDC_EXTRADATA_METADATA_FILLER) |
 			(1 << V4L2_MPEG_VIDC_INDEX_EXTRADATA_INPUT_CROP) |
 			(1 << V4L2_MPEG_VIDC_INDEX_EXTRADATA_DIGITAL_ZOOM) |
-			(1 << V4L2_MPEG_VIDC_INDEX_EXTRADATA_ASPECT_RATIO)
+			(1 << V4L2_MPEG_VIDC_INDEX_EXTRADATA_ASPECT_RATIO) |
+			(1 << V4L2_MPEG_VIDC_EXTRADATA_LTR) |
+			(1 << V4L2_MPEG_VIDC_EXTRADATA_METADATA_MBI)
 			),
 		.qmenu = mpeg_video_vidc_extradata,
 		.step = 0,
@@ -684,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,
@@ -718,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,
@@ -728,7 +719,95 @@
 		.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,
+		.name = "H264 Use LTR",
+		.type = V4L2_CTRL_TYPE_BUTTON,
+		.minimum = 0,
+		.maximum = (MAX_LTR_FRAME_COUNT - 1),
+		.default_value = 0,
+		.step = 1,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_LTRCOUNT,
+		.name = "Ltr Count",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 0,
+		.maximum = MAX_LTR_FRAME_COUNT,
+		.default_value = 0,
+		.step = 1,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_LTRMODE,
+		.name = "Ltr Mode",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = V4L2_MPEG_VIDC_VIDEO_LTR_MODE_DISABLE,
+		.maximum = V4L2_MPEG_VIDC_VIDEO_LTR_MODE_PERIODIC,
+		.default_value = V4L2_MPEG_VIDC_VIDEO_LTR_MODE_DISABLE,
+		.step = 1,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_MARKLTRFRAME,
+		.name = "H264 Mark LTR",
+		.type = V4L2_CTRL_TYPE_BUTTON,
+		.minimum = 0,
+		.maximum = (MAX_LTR_FRAME_COUNT - 1),
+		.default_value = 0,
+		.step = 1,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_HIER_P_NUM_LAYERS,
+		.name = "Set Hier P num layers",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 0,
+		.maximum = 3,
+		.default_value = 0,
+		.step = 1,
+		.qmenu = NULL,
+	},
+	{
+		.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,
 	}
 };
 
@@ -828,36 +907,64 @@
 	}
 	hdev = inst->core->device;
 
+	rc = msm_comm_try_state(inst, MSM_VIDC_OPEN_DONE);
+	if (rc) {
+		dprintk(VIDC_ERR, "Failed to open instance\n");
+		return rc;
+	}
+
+	rc = msm_comm_try_get_bufreqs(inst);
+	if (rc) {
+		dprintk(VIDC_ERR,
+				"Failed to get buffer requirements: %d\n", rc);
+		return rc;
+	}
+
 	switch (q->type) {
 	case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
 		*num_planes = 1;
+
 		buff_req = get_buff_req_buffer(inst, HAL_BUFFER_OUTPUT);
 		if (buff_req) {
 			*num_buffers = buff_req->buffer_count_actual =
 			max(*num_buffers, buff_req->buffer_count_actual);
 		}
-		if (*num_buffers < MIN_NUM_CAPTURE_BUFFERS)
-			*num_buffers = MIN_NUM_CAPTURE_BUFFERS;
 
-		if (*num_buffers > VIDEO_MAX_FRAME) {
-			dprintk(VIDC_ERR,
-				"Changing buffers requested, from %d to max"\
-				" supported (%d) best effort encoding\n",
-				*num_buffers, VIDEO_MAX_FRAME);
-			*num_buffers = VIDEO_MAX_FRAME;
+		if (*num_buffers < MIN_NUM_CAPTURE_BUFFERS ||
+				*num_buffers > VIDEO_MAX_FRAME) {
+			int temp = *num_buffers;
+
+			*num_buffers = clamp_val(*num_buffers,
+					MIN_NUM_CAPTURE_BUFFERS,
+					VIDEO_MAX_FRAME);
+			dprintk(VIDC_INFO,
+				"Changing buffer count on CAPTURE_MPLANE from %d to %d for best effort encoding\n",
+				temp, *num_buffers);
 		}
+
 		ctrl = v4l2_ctrl_find(&inst->ctrl_handler,
 				V4L2_CID_MPEG_VIDC_VIDEO_EXTRADATA);
 		if (ctrl)
 			extradata = v4l2_ctrl_g_ctrl(ctrl);
-		if (extradata)
+		if (extradata != V4L2_MPEG_VIDC_EXTRADATA_NONE)
 			*num_planes = *num_planes + 1;
 		inst->fmts[CAPTURE_PORT]->num_planes = *num_planes;
+
 		for (i = 0; i < *num_planes; i++) {
+			int extra_idx = EXTRADATA_IDX(*num_planes);
+
 			sizes[i] = inst->fmts[CAPTURE_PORT]->get_frame_size(
 					i, inst->prop.height[CAPTURE_PORT],
 					inst->prop.width[CAPTURE_PORT]);
+
+			if (extra_idx && i == extra_idx &&
+					extra_idx < VIDEO_MAX_PLANES) {
+				buff_req = get_buff_req_buffer(inst,
+						HAL_BUFFER_EXTRADATA_OUTPUT);
+				sizes[i] = buff_req->buffer_size;
+			}
 		}
+
 		property_id = HAL_PARAM_BUFFER_COUNT_ACTUAL;
 		new_buf_count.buffer_type = HAL_BUFFER_OUTPUT;
 		new_buf_count.buffer_count_actual = *num_buffers;
@@ -865,26 +972,18 @@
 			property_id, &new_buf_count);
 		break;
 	case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
-		rc = msm_comm_try_state(inst, MSM_VIDC_OPEN_DONE);
-		if (rc) {
-			dprintk(VIDC_ERR, "Failed to open instance\n");
-			break;
-		}
-		rc = msm_comm_try_get_bufreqs(inst);
-		if (rc) {
-			dprintk(VIDC_ERR,
-				"Failed to get buffer requirements: %d\n", rc);
-			break;
-		}
 		*num_planes = 1;
+
 		mutex_lock(&inst->lock);
 		*num_buffers = inst->buff_req.buffer[0].buffer_count_actual =
 			max(*num_buffers, inst->buff_req.buffer[0].
 				buffer_count_actual);
 		mutex_unlock(&inst->lock);
+
 		property_id = HAL_PARAM_BUFFER_COUNT_ACTUAL;
 		new_buf_count.buffer_type = HAL_BUFFER_INPUT;
 		new_buf_count.buffer_count_actual = *num_buffers;
+
 		rc = call_hfi_op(hdev, session_set_property, inst->session,
 					property_id, &new_buf_count);
 		dprintk(VIDC_DBG, "size = %d, alignment = %d, count = %d\n",
@@ -896,6 +995,7 @@
 					i, inst->prop.height[OUTPUT_PORT],
 					inst->prop.width[OUTPUT_PORT]);
 		}
+
 		break;
 	default:
 		dprintk(VIDC_ERR, "Invalid q type = %d\n", q->type);
@@ -905,11 +1005,53 @@
 	return rc;
 }
 
+static int msm_venc_enable_hier_p(struct msm_vidc_inst *inst)
+{
+	int num_enh_layers = 0;
+	u32 property_id = 0;
+	struct hfi_device *hdev = NULL;
+	int rc = 0;
+
+	if (!inst || !inst->core || !inst->core->device) {
+		dprintk(VIDC_ERR, "%s invalid parameters\n", __func__);
+		return -EINVAL;
+	}
+
+	if (inst->fmts[CAPTURE_PORT]->fourcc != V4L2_PIX_FMT_VP8)
+		return 0;
+
+	num_enh_layers = inst->capability.hier_p.max - 1;
+	if (!num_enh_layers)
+		return 0;
+
+	hdev = inst->core->device;
+	property_id = HAL_PARAM_VENC_HIER_P_MAX_ENH_LAYERS;
+
+	rc = call_hfi_op(hdev, session_set_property,
+			(void *)inst->session, property_id,
+			(void *)&num_enh_layers);
+	if (rc) {
+		dprintk(VIDC_ERR,
+			"%s: failed with error = %d\n", __func__, rc);
+	}
+	return rc;
+}
+
 static inline int start_streaming(struct msm_vidc_inst *inst)
 {
 	int rc = 0;
 	struct vb2_buf_entry *temp;
 	struct list_head *ptr, *next;
+
+	if (!inst || !inst->core || !inst->core->device) {
+		dprintk(VIDC_ERR, "%s invalid parameters\n", __func__);
+		return -EINVAL;
+	}
+
+	rc = msm_venc_enable_hier_p(inst);
+	if (rc)
+		return rc;
+
 	if (inst->capability.pixelprocess_capabilities &
 		HAL_VIDEO_ENCODER_SCALING_CAPABILITY)
 		rc = msm_comm_check_scaling_supported(inst);
@@ -934,9 +1076,7 @@
 		goto fail_start;
 	}
 
-	mutex_lock(&inst->core->sync_lock);
 	msm_comm_scale_clocks_and_bus(inst);
-	mutex_unlock(&inst->core->sync_lock);
 
 	rc = msm_comm_try_state(inst, MSM_VIDC_START_DONE);
 	if (rc) {
@@ -1013,9 +1153,7 @@
 		break;
 	}
 
-	mutex_lock(&inst->core->sync_lock);
 	msm_comm_scale_clocks_and_bus(inst);
-	mutex_unlock(&inst->core->sync_lock);
 
 	if (rc)
 		dprintk(VIDC_ERR,
@@ -1273,6 +1411,9 @@
 	struct v4l2_ctrl *temp_ctrl = NULL;
 	struct hfi_device *hdev;
 	struct hal_extradata_enable extra;
+	struct hal_ltruse useltr;
+	struct hal_ltrmark markltr;
+	u32 hier_p_layers;
 
 	if (!inst || !inst->core || !inst->core->device) {
 		dprintk(VIDC_ERR, "%s invalid parameters", __func__);
@@ -1683,6 +1824,26 @@
 		pdata = &qp_range;
 		break;
 	}
+	case V4L2_CID_MPEG_VIDC_VIDEO_VP8_MIN_QP: {
+		struct v4l2_ctrl *qp_max;
+		qp_max = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_VP8_MAX_QP);
+		property_id = HAL_PARAM_VENC_SESSION_QP_RANGE;
+		qp_range.layer_id = 0;
+		qp_range.max_qp = qp_max->val;
+		qp_range.min_qp = ctrl->val;
+		pdata = &qp_range;
+		break;
+	}
+	case V4L2_CID_MPEG_VIDC_VIDEO_VP8_MAX_QP: {
+		struct v4l2_ctrl *qp_min;
+		qp_min = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_VP8_MIN_QP);
+		property_id = HAL_PARAM_VENC_SESSION_QP_RANGE;
+		qp_range.layer_id = 0;
+		qp_range.max_qp = ctrl->val;
+		qp_range.min_qp = qp_min->val;
+		pdata = &qp_range;
+		break;
+	}
 	case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE: {
 		int temp = 0;
 
@@ -1970,7 +2131,33 @@
 		pdata = &enable;
 		break;
 	}
+	case V4L2_CID_MPEG_VIDC_VIDEO_USELTRFRAME:
+		property_id = HAL_CONFIG_VENC_USELTRFRAME;
+		useltr.refltr = ctrl->val;
+		useltr.useconstrnt = false;
+		useltr.frames = 0;
+		pdata = &useltr;
+		break;
+	case V4L2_CID_MPEG_VIDC_VIDEO_MARKLTRFRAME:
+		property_id = HAL_CONFIG_VENC_MARKLTRFRAME;
+		markltr.markframe = ctrl->val;
+		pdata = &markltr;
+		break;
+	case V4L2_CID_MPEG_VIDC_VIDEO_HIER_P_NUM_LAYERS:
+		property_id = HAL_CONFIG_VENC_HIER_P_NUM_FRAMES;
+		hier_p_layers = ctrl->val;
+		if (hier_p_layers > (inst->capability.hier_p.max - 1)) {
+			dprintk(VIDC_ERR,
+				"Error setting hier p num layers = %d max supported by f/w = %d\n",
+				hier_p_layers,
+				inst->capability.hier_p.max - 1);
+			rc = -ENOTSUPP;
+			break;
+		}
+		pdata = &hier_p_layers;
+		break;
 	default:
+		dprintk(VIDC_ERR, "Unsupported index: %x\n", ctrl->id);
 		rc = -ENOTSUPP;
 		break;
 	}
@@ -1987,6 +2174,92 @@
 	return rc;
 }
 
+static int try_set_ext_ctrl(struct msm_vidc_inst *inst,
+	struct v4l2_ext_controls *ctrl)
+{
+	int rc = 0, i;
+	struct v4l2_ext_control *control;
+	struct hfi_device *hdev;
+	struct hal_ltrmode ltrmode;
+	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;
+	}
+
+	hdev = inst->core->device;
+	cap = &inst->capability;
+
+	control = ctrl->controls;
+	for (i = 0; i < ctrl->count; i++) {
+		switch (control[i].id) {
+		case V4L2_CID_MPEG_VIDC_VIDEO_LTRMODE:
+			ltrmode.ltrmode = control[i].value;
+			ltrmode.trustmode = 1;
+			property_id = HAL_PARAM_VENC_LTRMODE;
+			pdata = &ltrmode;
+			break;
+		case V4L2_CID_MPEG_VIDC_VIDEO_LTRCOUNT:
+			ltrmode.ltrcount =  control[i].value;
+			if (ltrmode.ltrcount > cap->ltr_count.max) {
+				dprintk(VIDC_ERR,
+						"Invalid LTR count %d. Supported max: %d\n",
+						ltrmode.ltrcount,
+						cap->ltr_count.max);
+				/*
+				 * FIXME: Return an error (-EINVALID)
+				 * here once VP8 supports LTR count
+				 * capability
+				 */
+				ltrmode.ltrcount = 1;
+			}
+			ltrmode.trustmode = 1;
+			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);
+			rc = -ENOTSUPP;
+			break;
+		}
+		if (rc)
+			break;
+	}
+
+	if (!rc && property_id) {
+		dprintk(VIDC_DBG, "Control: HAL property=%x\n", property_id);
+		rc = call_hfi_op(hdev, session_set_property,
+				(void *)inst->session, property_id, pdata);
+	}
+	pr_err("Returning from %s\n", __func__);
+	return rc;
+}
+
 static int msm_venc_op_s_ctrl(struct v4l2_ctrl *ctrl)
 {
 
@@ -2072,6 +2345,22 @@
 	return v4l2_g_ctrl(&inst->ctrl_handler, ctrl);
 }
 
+int msm_venc_s_ext_ctrl(struct msm_vidc_inst *inst,
+	struct v4l2_ext_controls *ctrl)
+{
+	int rc = 0;
+	if (ctrl->ctrl_class != V4L2_CTRL_CLASS_MPEG) {
+		dprintk(VIDC_ERR, "Invalid Class set for extended control\n");
+		return -EINVAL;
+	}
+	rc = try_set_ext_ctrl(inst, ctrl);
+	if (rc) {
+		dprintk(VIDC_ERR, "Error setting extended control\n");
+		return rc;
+	}
+	return rc;
+}
+
 int msm_venc_cmd(struct msm_vidc_inst *inst, struct v4l2_encoder_cmd *enc)
 {
 	int rc = 0;
@@ -2219,9 +2508,8 @@
 			dprintk(VIDC_WARN,
 				"Failed to set frame rate %d\n", rc);
 		}
-		mutex_lock(&inst->core->sync_lock);
+
 		msm_comm_scale_clocks_and_bus(inst);
-		mutex_unlock(&inst->core->sync_lock);
 	}
 exit:
 	return rc;
@@ -2371,6 +2659,14 @@
 			"Invalid input, inst = %p, format = %p\n", inst, f);
 		return -EINVAL;
 	}
+
+	rc = msm_comm_try_get_bufreqs(inst);
+	if (rc) {
+		dprintk(VIDC_WARN, "Getting new buffer requirements failed: %d\n",
+				rc);
+		return rc;
+	}
+
 	if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
 		fmt = inst->fmts[CAPTURE_PORT];
 		height = inst->prop.height[CAPTURE_PORT];
@@ -2400,8 +2696,16 @@
 				buff_req_buffer->buffer_size : 0;
 		}
 		for (i = 0; i < fmt->num_planes; ++i) {
-			inst->bufq[CAPTURE_PORT].vb2_bufq.plane_sizes[i] =
-			f->fmt.pix_mp.plane_fmt[i].sizeimage;
+			if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+				inst->bufq[OUTPUT_PORT].vb2_bufq.
+				plane_sizes[i] =
+				f->fmt.pix_mp.plane_fmt[i].sizeimage;
+			} else if (f->type ==
+				V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+				inst->bufq[CAPTURE_PORT].vb2_bufq.
+				plane_sizes[i] =
+				f->fmt.pix_mp.plane_fmt[i].sizeimage;
+			}
 		}
 	} else {
 		dprintk(VIDC_ERR,
@@ -2431,7 +2735,7 @@
 	rc = vb2_reqbufs(&q->vb2_bufq, b);
 	mutex_unlock(&q->lock);
 	if (rc)
-		dprintk(VIDC_ERR, "Failed to get reqbufs, %d\n", rc);
+		dprintk(VIDC_DBG, "Failed to get reqbufs, %d\n", rc);
 	return rc;
 }
 
@@ -2638,21 +2942,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;
@@ -2660,10 +2961,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",
@@ -2713,7 +3027,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)
@@ -2721,41 +3036,29 @@
 			"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);
+	if (!inst) {
+		dprintk(VIDC_ERR, "%s invalid parameters\n", __func__);
+		return -EINVAL;
 	}
+
+	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.h b/drivers/media/platform/msm/vidc/msm_venc.h
index 9020167..5965d39 100644
--- a/drivers/media/platform/msm/vidc/msm_venc.h
+++ b/drivers/media/platform/msm/vidc/msm_venc.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, 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
@@ -25,6 +25,7 @@
 int msm_venc_g_fmt(void *instance, struct v4l2_format *f);
 int msm_venc_s_ctrl(void *instance, struct v4l2_control *a);
 int msm_venc_g_ctrl(void *instance, struct v4l2_control *a);
+int msm_venc_s_ext_ctrl(void *instance, struct v4l2_ext_controls *a);
 int msm_venc_reqbufs(void *instance, struct v4l2_requestbuffers *b);
 int msm_venc_prepare_buf(struct msm_vidc_inst *inst, struct v4l2_buffer *b);
 int msm_venc_release_buf(struct msm_vidc_inst *inst, struct v4l2_buffer *b);
diff --git a/drivers/media/platform/msm/vidc/msm_vidc.c b/drivers/media/platform/msm/vidc/msm_vidc.c
index 9da1220..cfc2eb8 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc.c
@@ -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
@@ -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;
 }
@@ -185,6 +194,15 @@
 		return msm_venc_g_ctrl(instance, control);
 	return -EINVAL;
 }
+int msm_vidc_s_ext_ctrl(void *instance, struct v4l2_ext_controls *control)
+{
+	struct msm_vidc_inst *inst = instance;
+	if (!inst || !control)
+		return -EINVAL;
+	if (inst->session_type == MSM_VIDC_ENCODER)
+		return msm_venc_s_ext_ctrl(instance, control);
+	return -EINVAL;
+}
 int msm_vidc_reqbufs(void *instance, struct v4l2_requestbuffers *b)
 {
 	struct msm_vidc_inst *inst = instance;
@@ -246,38 +264,38 @@
 	return ret;
 }
 
-struct buffer_info *get_same_fd_buffer(struct msm_vidc_inst *inst,
-			struct list_head *list, int fd, int *plane)
+struct msm_smem *get_same_fd_buffer(struct msm_vidc_inst *inst,
+			struct list_head *list, int fd)
 {
 	struct buffer_info *temp;
-	struct buffer_info *ret = NULL;
+	struct msm_smem *same_fd_handle = NULL;
+
 	int i;
 	if (fd == 0)
 		return NULL;
-	if (!list || fd < 0 || !plane) {
+	if (!list || fd < 0) {
 		dprintk(VIDC_ERR, "Invalid input\n");
 		goto err_invalid_input;
 	}
-	*plane = 0;
 	mutex_lock(&inst->lock);
 	list_for_each_entry(temp, list, list) {
 		for (i = 0; (i < temp->num_planes)
 			&& (i < VIDEO_MAX_PLANES); i++) {
-			if (temp && temp->fd[i] == fd)  {
+			if (temp && (temp->fd[i] == fd) &&
+				temp->handle[i] && temp->mapped[i])  {
 				temp->same_fd_ref[i]++;
 				dprintk(VIDC_INFO,
 				"Found same fd buffer\n");
-				ret = temp;
-				*plane = i;
+				same_fd_handle = temp->handle[i];
 				break;
 			}
 		}
-		if (ret)
+		if (same_fd_handle)
 			break;
 	}
 	mutex_unlock(&inst->lock);
 err_invalid_input:
-	return ret;
+	return same_fd_handle;
 }
 
 struct buffer_info *device_to_uvaddr(struct msm_vidc_inst *inst,
@@ -324,7 +342,6 @@
 	binfo->num_planes = b->length;
 	binfo->memory = b->memory;
 	binfo->v4l2_index = b->index;
-	binfo->dequeued = false;
 	binfo->timestamp.tv_sec = b->timestamp.tv_sec;
 	binfo->timestamp.tv_usec = b->timestamp.tv_usec;
 	dprintk(VIDC_DBG, "%s: fd[%d] = %d b->index = %d",
@@ -341,6 +358,7 @@
 	b->index = binfo->v4l2_index;
 	b->timestamp.tv_sec = binfo->timestamp.tv_sec;
 	b->timestamp.tv_usec = binfo->timestamp.tv_usec;
+	binfo->dequeued = false;
 	for (i = 0; i < binfo->num_planes; ++i) {
 		b->m.planes[i].reserved[0] = binfo->fd[i];
 		b->m.planes[i].reserved[1] = binfo->buff_off[i];
@@ -423,6 +441,7 @@
 	struct buffer_info *temp = NULL;
 	int plane = 0;
 	int i = 0, rc = 0;
+	struct msm_smem *same_fd_handle = NULL;
 
 	if (!b || !inst) {
 		dprintk(VIDC_ERR, "%s: invalid input\n", __func__);
@@ -480,16 +499,17 @@
 		if (rc < 0)
 			goto exit;
 
-		temp = get_same_fd_buffer(inst, &inst->registered_bufs,
-					b->m.planes[i].reserved[0], &plane);
+		same_fd_handle = get_same_fd_buffer(inst,
+					&inst->registered_bufs,
+					b->m.planes[i].reserved[0]);
 
 		populate_buf_info(binfo, b, i);
-		if (temp) {
+		if (same_fd_handle) {
 			binfo->device_addr[i] =
-			temp->handle[plane]->device_addr + binfo->buff_off[i];
+			same_fd_handle->device_addr + binfo->buff_off[i];
 			b->m.planes[i].m.userptr = binfo->device_addr[i];
 			binfo->mapped[i] = false;
-			binfo->handle[i] = temp->handle[i];
+			binfo->handle[i] = same_fd_handle;
 		} else {
 			if (inst->map_output_buffer) {
 				binfo->handle[i] =
@@ -514,7 +534,7 @@
 		if ((i == 0) && is_dynamic_output_buffer_mode(b, inst)) {
 			rc = buf_ref_get(inst, binfo);
 			if (rc < 0)
-				return rc;
+				goto exit;
 		}
 		dprintk(VIDC_DBG,
 			"%s: [MAP] binfo = %p, handle[%d] = %p, device_addr = 0x%x, fd = %d, offset = %d, mapped = %d\n",
@@ -672,7 +692,8 @@
 				return -EINVAL;
 			}
 		} else
-			dprintk(VIDC_ERR, "%s: WARN: NULL handle", __func__);
+			dprintk(VIDC_DBG, "%s: NULL handle for plane %d\n",
+					__func__, i);
 	}
 	return 0;
 }
@@ -716,7 +737,29 @@
 	if (!inst)
 		return -EINVAL;
 
+	if (!inst->in_reconfig) {
+		rc = msm_comm_try_state(inst, MSM_VIDC_RELEASE_RESOURCES_DONE);
+		if (rc) {
+			dprintk(VIDC_ERR,
+					"Failed to move inst: %p to release res done\n",
+					inst);
+		}
+	}
+
+	/*
+	* In dynamic buffer mode, driver needs to release resources,
+	* but not call release buffers on firmware, as the buffers
+	* were never registered with firmware.
+	*/
+	if ((buffer_type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) &&
+		(inst->buffer_mode_set[CAPTURE_PORT] ==
+				HAL_BUFFER_MODE_DYNAMIC)) {
+		goto free_and_unmap;
+	}
+
 	list_for_each_safe(ptr, next, &inst->registered_bufs) {
+		bool release_buf = false;
+		mutex_lock(&inst->lock);
 		bi = list_entry(ptr, struct buffer_info, list);
 		if (bi->type == buffer_type) {
 			buffer_info.type = bi->type;
@@ -734,19 +777,30 @@
 					buffer_info.m.planes[i].length);
 			}
 			buffer_info.length = bi->num_planes;
-			if (inst->session_type == MSM_VIDC_DECODER)
-				rc = msm_vdec_release_buf(instance,
-					&buffer_info);
-			if (inst->session_type == MSM_VIDC_ENCODER)
-				rc = msm_venc_release_buf(instance,
-					&buffer_info);
-			if (rc)
-				dprintk(VIDC_ERR,
-					"Failed Release buffer: %d, %d, %d\n",
-					buffer_info.m.planes[0].reserved[0],
-					buffer_info.m.planes[0].reserved[1],
-					buffer_info.m.planes[0].length);
+			release_buf = true;
+		}
+		mutex_unlock(&inst->lock);
+		if (!release_buf)
+			continue;
+		if (inst->session_type == MSM_VIDC_DECODER)
+			rc = msm_vdec_release_buf(instance,
+				&buffer_info);
+		if (inst->session_type == MSM_VIDC_ENCODER)
+			rc = msm_venc_release_buf(instance,
+				&buffer_info);
+		if (rc)
+			dprintk(VIDC_ERR,
+				"Failed Release buffer: %d, %d, %d\n",
+				buffer_info.m.planes[0].reserved[0],
+				buffer_info.m.planes[0].reserved[1],
+				buffer_info.m.planes[0].length);
+	}
 
+free_and_unmap:
+	mutex_lock(&inst->lock);
+	list_for_each_safe(ptr, next, &inst->registered_bufs) {
+		bi = list_entry(ptr, struct buffer_info, list);
+		if (bi->type == buffer_type) {
 			list_del(&bi->list);
 			for (i = 0; i < bi->num_planes; i++) {
 				if (bi->handle[i] && bi->mapped[i]) {
@@ -762,12 +816,17 @@
 			kfree(bi);
 		}
 	}
+	mutex_unlock(&inst->lock);
 	return rc;
 }
 
 int msm_vidc_encoder_cmd(void *instance, struct v4l2_encoder_cmd *enc)
 {
 	struct msm_vidc_inst *inst = instance;
+	if (!inst || !inst->core || !enc) {
+		dprintk(VIDC_ERR, "%s invalid params\n", __func__);
+		return -EINVAL;
+	}
 	if (inst->session_type == MSM_VIDC_ENCODER)
 		return msm_venc_cmd(instance, enc);
 	return -EINVAL;
@@ -776,6 +835,10 @@
 int msm_vidc_decoder_cmd(void *instance, struct v4l2_decoder_cmd *dec)
 {
 	struct msm_vidc_inst *inst = instance;
+	if (!inst || !inst->core || !dec) {
+		dprintk(VIDC_ERR, "%s invalid params\n", __func__);
+		return -EINVAL;
+	}
 	if (inst->session_type == MSM_VIDC_DECODER)
 		return msm_vdec_cmd(instance, dec);
 	return -EINVAL;
@@ -916,6 +979,13 @@
 		}
 	}
 
+	if (!buffer_info && inst->map_output_buffer) {
+		dprintk(VIDC_ERR,
+			"%s: error - no buffer info found in registered list\n",
+			__func__);
+		return -EINVAL;
+	}
+
 	if (is_dynamic_output_buffer_mode(b, inst)) {
 		mutex_lock(&inst->lock);
 		buffer_info->dequeued = true;
@@ -1076,8 +1146,6 @@
 {
 	int rc = 0;
 	struct msm_vidc_inst *vidc_inst = (struct msm_vidc_inst *)inst;
-	spin_lock_init(&pvdev->fh_lock);
-	INIT_LIST_HEAD(&pvdev->fh_list);
 
 	v4l2_fh_init(&vidc_inst->event_handler, pvdev);
 	v4l2_fh_add(&vidc_inst->event_handler);
@@ -1158,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);
@@ -1209,9 +1276,9 @@
 
 	setup_event_queue(inst, &core->vdev[session_type].vdev);
 
-	mutex_lock(&core->sync_lock);
+	mutex_lock(&core->lock);
 	list_add_tail(&inst->list, &core->instances);
-	mutex_unlock(&core->sync_lock);
+	mutex_unlock(&core->lock);
 	return inst;
 fail_init:
 	vb2_queue_release(&inst->bufq[OUTPUT_PORT].vb2_bufq);
@@ -1234,7 +1301,6 @@
 {
 	struct list_head *ptr, *next;
 	struct vb2_buf_entry *entry;
-	struct internal_buf *buf;
 	if (inst) {
 		mutex_lock(&inst->lock);
 		if (!list_empty(&inst->pendingq)) {
@@ -1246,37 +1312,28 @@
 			}
 		}
 		if (!list_empty(&inst->internalbufs)) {
-			list_for_each_safe(ptr, next, &inst->internalbufs) {
-				buf = list_entry(ptr, struct internal_buf,
-						list);
-				list_del(&buf->list);
-				mutex_unlock(&inst->lock);
-				msm_comm_smem_free(inst, buf->handle);
-				kfree(buf);
-				mutex_lock(&inst->lock);
-			}
+			mutex_unlock(&inst->lock);
+			if (msm_comm_release_scratch_buffers(inst))
+				dprintk(VIDC_ERR,
+					"Failed to release scratch buffers\n");
+
+			mutex_lock(&inst->lock);
 		}
 		if (!list_empty(&inst->persistbufs)) {
-			list_for_each_safe(ptr, next, &inst->persistbufs) {
-				buf = list_entry(ptr, struct internal_buf,
-						list);
-				list_del(&buf->list);
-				mutex_unlock(&inst->lock);
-				msm_comm_smem_free(inst, buf->handle);
-				kfree(buf);
-				mutex_lock(&inst->lock);
-			}
+			mutex_unlock(&inst->lock);
+			if (msm_comm_release_persist_buffers(inst))
+				dprintk(VIDC_ERR,
+					"Failed to release persist buffers\n");
+
+			mutex_lock(&inst->lock);
 		}
 		if (!list_empty(&inst->outputbufs)) {
-			list_for_each_safe(ptr, next, &inst->outputbufs) {
-				buf = list_entry(ptr, struct internal_buf,
-						list);
-				list_del(&buf->list);
-				mutex_unlock(&inst->lock);
-				msm_comm_smem_free(inst, buf->handle);
-				kfree(buf);
-				mutex_lock(&inst->lock);
-			}
+			mutex_unlock(&inst->lock);
+			if (msm_comm_release_output_buffers(inst))
+				dprintk(VIDC_ERR,
+					"Failed to release output buffers\n");
+
+			mutex_lock(&inst->lock);
 		}
 		if (inst->extradata_handle) {
 			mutex_unlock(&inst->lock);
@@ -1284,7 +1341,6 @@
 			mutex_lock(&inst->lock);
 		}
 		mutex_unlock(&inst->lock);
-		msm_smem_delete_client(inst->mem_client);
 		debugfs_remove_recursive(inst->debugfs_root);
 	}
 }
@@ -1302,6 +1358,7 @@
 	if (!inst)
 		return -EINVAL;
 
+	v4l2_fh_del(&inst->event_handler);
 	list_for_each_safe(ptr, next, &inst->registered_bufs) {
 		bi = list_entry(ptr, struct buffer_info, list);
 		if (bi->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
@@ -1316,13 +1373,13 @@
 	}
 
 	core = inst->core;
-	mutex_lock(&core->sync_lock);
+	mutex_lock(&core->lock);
 	list_for_each_safe(ptr, next, &core->instances) {
 		temp = list_entry(ptr, struct msm_vidc_inst, list);
 		if (temp == inst)
 			list_del(&inst->list);
 	}
-	mutex_unlock(&core->sync_lock);
+	mutex_unlock(&core->lock);
 
 	if (inst->session_type == MSM_VIDC_DECODER)
 		msm_vdec_ctrl_deinit(inst);
@@ -1341,7 +1398,9 @@
 	for (i = 0; i < MAX_PORT_NUM; i++)
 		vb2_queue_release(&inst->bufq[i].vb2_bufq);
 
+	msm_smem_delete_client(inst->mem_client);
 	pr_info(VIDC_DBG_TAG "Closed video instance: %p\n", VIDC_INFO, inst);
 	kfree(inst);
+
 	return 0;
 }
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c
index 7588994..7429466 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c
@@ -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,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>
 
@@ -50,9 +51,10 @@
 		enum session_type type)
 {
 	struct msm_vidc_inst *inst = NULL;
+	bool wants_turbo = false;
 
+	mutex_lock(&core->lock);
 	list_for_each_entry(inst, &core->instances, list) {
-		bool wants_turbo = false;
 
 		mutex_lock(&inst->lock);
 		if (inst->session_type == type &&
@@ -63,10 +65,12 @@
 		mutex_unlock(&inst->lock);
 
 		if (wants_turbo)
-			return true;
+			break;
 	}
 
-	return false;
+	mutex_unlock(&core->lock);
+
+	return wants_turbo;
 }
 
 static bool is_thumbnail_session(struct msm_vidc_inst *inst)
@@ -116,6 +120,7 @@
 		dprintk(VIDC_ERR, "Invalid args: %p\n", core);
 		return -EINVAL;
 	}
+	mutex_lock(&core->lock);
 	list_for_each_entry(inst, &core->instances, list) {
 		mutex_lock(&inst->lock);
 		if (inst->session_type == type &&
@@ -127,6 +132,7 @@
 		}
 		mutex_unlock(&inst->lock);
 	}
+	mutex_unlock(&core->lock);
 	return num_mbs_per_sec;
 }
 
@@ -390,7 +396,9 @@
 		&inst->completions[SESSION_MSG_INDEX(cmd)],
 		msecs_to_jiffies(msm_vidc_hw_rsp_timeout));
 	if (!rc) {
-		dprintk(VIDC_ERR, "Wait interrupted or timeout: %d\n", rc);
+		dprintk(VIDC_ERR,
+			"%s: Wait interrupted or timeout[%u]: %d\n",
+			__func__, (u32)inst->session, SESSION_MSG_INDEX(cmd));
 		msm_comm_recover_from_session_error(inst);
 		rc = -EIO;
 	} else {
@@ -438,6 +446,21 @@
 	mutex_unlock(&inst->lock);
 }
 
+static void msm_comm_generate_max_clients_error(struct msm_vidc_inst *inst)
+{
+	if (!inst) {
+		dprintk(VIDC_ERR, "%s: invalid input parameters\n", __func__);
+		return;
+	}
+	mutex_lock(&inst->sync_lock);
+	inst->session = NULL;
+	inst->state = MSM_VIDC_CORE_INVALID;
+	msm_vidc_queue_v4l2_event(inst, V4L2_EVENT_MSM_VIDC_MAX_CLIENTS);
+	dprintk(VIDC_WARN,
+			"%s: Too many clients\n", __func__);
+	mutex_unlock(&inst->sync_lock);
+}
+
 static void handle_session_init_done(enum command_response cmd, void *data)
 {
 	struct msm_vidc_cb_cmd_done *response = data;
@@ -463,6 +486,9 @@
 				session_init_done->frame_rate;
 			inst->capability.scale_x = session_init_done->scale_x;
 			inst->capability.scale_y = session_init_done->scale_y;
+			inst->capability.ltr_count =
+				session_init_done->ltr_count;
+			inst->capability.hier_p = session_init_done->hier_p;
 			inst->capability.pixelprocess_capabilities =
 				call_hfi_op(hdev, get_core_capabilities);
 			inst->capability.capability_set = true;
@@ -472,7 +498,10 @@
 			dprintk(VIDC_ERR,
 				"Session init response from FW : 0x%x",
 				response->status);
-			msm_comm_generate_session_error(inst);
+			if (response->status == VIDC_ERR_MAX_CLIENTS)
+				msm_comm_generate_max_clients_error(inst);
+			else
+				msm_comm_generate_session_error(inst);
 		}
 		signal_session_msg_receipt(cmd, inst);
 	} else {
@@ -519,6 +548,14 @@
 					event_notify->packet_buffer,
 					event_notify->exra_data_buffer);
 
+				if (inst->state == MSM_VIDC_CORE_INVALID ||
+					inst->core->state ==
+						VIDC_CORE_INVALID) {
+					dprintk(VIDC_DBG,
+						"Event release buf ref received in invalid state - discard\n");
+					return;
+				}
+
 				/*
 				* Get the buffer_info entry for the
 				* device address.
@@ -575,10 +612,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] =
@@ -699,8 +742,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;
 		}
@@ -714,16 +757,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);
@@ -752,95 +850,127 @@
 			"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->lock);
+	/*
+	* Restart the firmware to bring out of bad state.
+	*/
+	if ((core->state == VIDC_CORE_INVALID) &&
+		hdev->resurrect_fw) {
+		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;
+	} else {
+		dprintk(VIDC_DBG,
+			"fw unloaded after sys error, no need to resurrect\n");
+	}
+	mutex_unlock(&core->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.
+	*/
+	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);
+	mutex_unlock(&core->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)
@@ -1109,6 +1239,7 @@
 	struct vidc_hal_fbd *fill_buf_done;
 	enum hal_buffer buffer_type;
 	int64_t time_usec = 0;
+	int extra_idx = 0;
 
 	if (!response) {
 		dprintk(VIDC_ERR, "Invalid response from vidc_hal\n");
@@ -1155,6 +1286,15 @@
 				ns_to_timeval(time_usec * NSEC_PER_USEC);
 		}
 		vb->v4l2_buf.flags = 0;
+		extra_idx =
+			EXTRADATA_IDX(inst->fmts[CAPTURE_PORT]->num_planes);
+		if (extra_idx && (extra_idx < VIDEO_MAX_PLANES)) {
+			vb->v4l2_planes[extra_idx].m.userptr =
+				(unsigned long)fill_buf_done->extra_data_buffer;
+			vb->v4l2_planes[extra_idx].bytesused =
+				vb->v4l2_planes[extra_idx].length;
+			vb->v4l2_planes[extra_idx].data_offset = 0;
+		}
 
 		handle_dynamic_buffer(inst, (u32)fill_buf_done->packet_buffer1,
 					fill_buf_done->flags1);
@@ -1174,6 +1314,8 @@
 			vb->v4l2_buf.flags |= V4L2_QCOM_BUF_DATA_CORRUPT;
 		if (fill_buf_done->flags1 & HAL_BUFFERFLAG_DROP_FRAME)
 			vb->v4l2_buf.flags |= V4L2_QCOM_BUF_DROP_FRAME;
+		if (fill_buf_done->flags1 & HAL_BUFFERFLAG_MBAFF)
+			vb->v4l2_buf.flags |= V4L2_MSM_BUF_FLAG_MBAFF;
 		switch (fill_buf_done->picture_type) {
 		case HAL_PICTURE_IDR:
 			vb->v4l2_buf.flags |= V4L2_QCOM_BUF_FLAG_IDRFRAME;
@@ -1209,6 +1351,13 @@
 		fill_buf_done->start_y_coord, fill_buf_done->frame_width,
 		fill_buf_done->frame_height, fill_buf_done->picture_type);
 
+		if (extra_idx && (extra_idx < VIDEO_MAX_PLANES)) {
+			dprintk(VIDC_DBG,
+			"extradata: userptr = %p;  bytesused = %d; length = %d\n",
+			(u8 *)vb->v4l2_planes[extra_idx].m.userptr,
+			vb->v4l2_planes[extra_idx].bytesused,
+			vb->v4l2_planes[extra_idx].length);
+		}
 		mutex_lock(&inst->bufq[CAPTURE_PORT].lock);
 		vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
 		mutex_unlock(&inst->bufq[CAPTURE_PORT].lock);
@@ -1328,7 +1477,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);
@@ -1444,7 +1593,8 @@
 		&core->completions[SYS_MSG_INDEX(RELEASE_RESOURCE_DONE)],
 		msecs_to_jiffies(msm_vidc_hw_rsp_timeout));
 	if (!rc) {
-		dprintk(VIDC_ERR, "Wait interrupted or timeout: %d\n", rc);
+		dprintk(VIDC_ERR, "%s: Wait interrupted or timeout: %d\n",
+			__func__, SYS_MSG_INDEX(RELEASE_RESOURCE_DONE));
 		rc = -EIO;
 	}
 release_ocmem_failed:
@@ -1455,7 +1605,7 @@
 {
 	struct msm_vidc_core *core = inst->core;
 	int rc = 0;
-	mutex_lock(&core->sync_lock);
+	mutex_lock(&core->lock);
 	if (core->state >= VIDC_CORE_INIT_DONE) {
 		dprintk(VIDC_INFO, "Video core: %d is already in state: %d\n",
 				core->id, core->state);
@@ -1466,20 +1616,19 @@
 		&core->completions[SYS_MSG_INDEX(SYS_INIT_DONE)],
 		msecs_to_jiffies(msm_vidc_hw_rsp_timeout));
 	if (!rc) {
-		dprintk(VIDC_ERR, "Wait interrupted or timeout: %d\n", rc);
+		dprintk(VIDC_ERR, "%s: Wait interrupted or timeout: %d\n",
+			__func__, SYS_MSG_INDEX(SYS_INIT_DONE));
 		rc = -EIO;
 		goto exit;
 	} else {
-		mutex_lock(&core->lock);
 		core->state = VIDC_CORE_INIT_DONE;
-		mutex_unlock(&core->lock);
 	}
 	dprintk(VIDC_DBG, "SYS_INIT_DONE!!!\n");
 core_already_inited:
 	change_inst_state(inst, MSM_VIDC_CORE_INIT_DONE);
 	rc = 0;
 exit:
-	mutex_unlock(&core->sync_lock);
+	mutex_unlock(&core->lock);
 	return rc;
 }
 
@@ -1493,12 +1642,13 @@
 		return -EINVAL;
 	hdev = core->device;
 
-	mutex_lock(&core->sync_lock);
+	mutex_lock(&core->lock);
 	if (core->state >= VIDC_CORE_INIT) {
 		dprintk(VIDC_INFO, "Video core: %d is already in state: %d\n",
 				core->id, core->state);
 		goto core_already_inited;
 	}
+	mutex_unlock(&core->lock);
 
 	rc = msm_comm_scale_bus(core, inst->session_type, DDR_MEM);
 	if (rc) {
@@ -1506,36 +1656,46 @@
 		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;
+	mutex_lock(&core->lock);
+	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;
+		}
+		core->state = VIDC_CORE_LOADED;
 	}
+	mutex_unlock(&core->lock);
+
 	rc = msm_comm_scale_clocks(core);
 	if (rc) {
 		dprintk(VIDC_ERR, "Failed to scale clocks: %d\n", rc);
 		goto fail_core_init;
 	}
 
-	init_completion(&core->completions[SYS_MSG_INDEX(SYS_INIT_DONE)]);
-	rc = call_hfi_op(hdev, core_init, hdev->hfi_device_data);
-	if (rc) {
-		dprintk(VIDC_ERR, "Failed to init core, id = %d\n", core->id);
-		goto fail_core_init;
-	}
 	mutex_lock(&core->lock);
-	core->state = VIDC_CORE_INIT;
-	mutex_unlock(&core->lock);
+	if (core->state == VIDC_CORE_LOADED) {
+		init_completion(&core->completions
+			[SYS_MSG_INDEX(SYS_INIT_DONE)]);
+		rc = call_hfi_op(hdev, core_init, hdev->hfi_device_data);
+		if (rc) {
+			dprintk(VIDC_ERR, "Failed to init core, id = %d\n",
+					core->id);
+			goto fail_core_init;
+		}
+		core->state = VIDC_CORE_INIT;
+	}
+
 core_already_inited:
 	change_inst_state(inst, MSM_VIDC_CORE_INIT);
-	mutex_unlock(&core->sync_lock);
+	mutex_unlock(&core->lock);
 	return rc;
 fail_core_init:
 	call_hfi_op(hdev, unload_fw, hdev->hfi_device_data);
 fail_load_fw:
 	msm_comm_unvote_buses(core, DDR_MEM);
 fail_scale_bus:
-	mutex_unlock(&core->sync_lock);
+	mutex_unlock(&core->lock);
 	return rc;
 }
 
@@ -1553,39 +1713,49 @@
 	core = inst->core;
 	hdev = core->device;
 
-	mutex_lock(&core->sync_lock);
+	mutex_lock(&core->lock);
 	if (core->state == VIDC_CORE_UNINIT) {
 		dprintk(VIDC_INFO, "Video core: %d is already in state: %d\n",
 				core->id, core->state);
 		goto core_already_uninited;
 	}
+	mutex_unlock(&core->lock);
+
 	msm_comm_scale_clocks_and_bus(inst);
+
+	mutex_lock(&core->lock);
 	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);
+		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;
+			}
 		}
-		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;
-		mutex_unlock(&core->lock);
+
 		call_hfi_op(hdev, unload_fw, hdev->hfi_device_data);
 		if (core->resources.has_ocmem)
 			msm_comm_unvote_buses(core, DDR_MEM|OCMEM_MEM);
 		else
 			msm_comm_unvote_buses(core, DDR_MEM);
 	}
+
 core_already_uninited:
 	change_inst_state(inst, MSM_VIDC_CORE_UNINIT);
 exit:
-	mutex_unlock(&core->sync_lock);
+	mutex_unlock(&core->lock);
 	return rc;
 }
 
@@ -1714,6 +1884,8 @@
 	struct msm_vidc_inst *temp;
 	dprintk(VIDC_ERR, "Running instances:\n");
 	dprintk(VIDC_ERR, "%4s|%4s|%4s|%4s\n", "type", "w", "h", "fps");
+
+	mutex_lock(&core->lock);
 	list_for_each_entry(temp, &core->instances, list) {
 		mutex_lock(&temp->lock);
 		if (temp->state >= MSM_VIDC_OPEN_DONE &&
@@ -1726,6 +1898,7 @@
 		}
 		mutex_unlock(&temp->lock);
 	}
+	mutex_unlock(&core->lock);
 }
 
 static int msm_vidc_load_resources(int flipped_state,
@@ -1741,17 +1914,21 @@
 		dprintk(VIDC_ERR, "%s invalid parameters", __func__);
 		return -EINVAL;
 	}
-	if (inst->state == MSM_VIDC_CORE_INVALID ||
-			inst->core->state == VIDC_CORE_INVALID) {
+
+	if (inst->core->state == VIDC_CORE_INVALID) {
 		dprintk(VIDC_ERR,
-				"Core is in bad state can't do load res");
+				"Core is in bad state can't do load res\n");
 		return -EINVAL;
 	}
 
-	mutex_lock(&inst->core->sync_lock);
+	if (inst->state == MSM_VIDC_CORE_INVALID) {
+		dprintk(VIDC_ERR,
+				"Instance is in invalid state can't do load res\n");
+		return -EINVAL;
+	}
+
 	num_mbs_per_sec = msm_comm_get_load(inst->core, MSM_VIDC_DECODER);
 	num_mbs_per_sec += msm_comm_get_load(inst->core, MSM_VIDC_ENCODER);
-	mutex_unlock(&inst->core->sync_lock);
 
 	if (num_mbs_per_sec > inst->core->resources.max_load) {
 		dprintk(VIDC_ERR, "HW is overloaded, needed: %d max: %d\n",
@@ -1759,7 +1936,7 @@
 		msm_vidc_print_running_insts(inst->core);
 		inst->state = MSM_VIDC_CORE_INVALID;
 		msm_comm_recover_from_session_error(inst);
-		return -ENOMEM;
+		return -EBUSY;
 	}
 
 	hdev = inst->core->device;
@@ -1775,16 +1952,14 @@
 			inst->prop.width[OUTPUT_PORT]);
 		ocmem_sz = get_ocmem_requirement(
 			height, width);
-		mutex_lock(&inst->core->sync_lock);
 		rc = msm_comm_scale_bus(inst->core, inst->session_type,
 					OCMEM_MEM);
-		mutex_unlock(&inst->core->sync_lock);
 		if (!rc) {
-			mutex_lock(&inst->core->sync_lock);
+			mutex_lock(&inst->core->lock);
 			rc = call_hfi_op(hdev, alloc_ocmem,
 					hdev->hfi_device_data,
 					ocmem_sz);
-			mutex_unlock(&inst->core->sync_lock);
+			mutex_unlock(&inst->core->lock);
 			if (rc) {
 				dprintk(VIDC_WARN,
 				"Failed to allocate OCMEM. Performance will be impacted\n");
@@ -2396,13 +2571,6 @@
 			mutex_unlock(&inst->sync_lock);
 	} else {
 		int64_t time_usec = timeval_to_ns(&vb->v4l2_buf.timestamp);
-
-		rc = msm_vidc_check_session_supported(inst);
-		if (rc) {
-			dprintk(VIDC_ERR,
-				"%s: session not supported\n", __func__);
-			goto err_no_mem;
-		}
 		do_div(time_usec, NSEC_PER_USEC);
 		memset(&frame_data, 0 , sizeof(struct vidc_frame_data));
 		frame_data.alloc_len = vb->v4l2_planes[0].length;
@@ -2546,7 +2714,9 @@
 		msecs_to_jiffies(msm_vidc_hw_rsp_timeout));
 	if (!rc) {
 		dprintk(VIDC_ERR,
-			"Wait interrupted or timeout: %d\n", rc);
+			"%s: Wait interrupted or timeout[%u]: %d\n",
+			__func__, (u32)inst->session,
+			SESSION_MSG_INDEX(SESSION_PROPERTY_INFO));
 		inst->state = MSM_VIDC_CORE_INVALID;
 		msm_comm_recover_from_session_error(inst);
 		rc = -EIO;
@@ -2952,9 +3122,6 @@
 				dprintk(VIDC_DBG,
 					"released buffer held in driver before issuing flush: 0x%x fd[0]: %d\n",
 					binfo->device_addr[0], binfo->fd[0]);
-				/*delete this buffer info from registered list*/
-				list_del(&binfo->list);
-				kfree(binfo);
 				/*send event to client*/
 				v4l2_event_queue_fh(&inst->event_handler,
 					&buf_event);
@@ -2999,6 +3166,9 @@
 		dprintk(VIDC_INFO, "Input only flush not supported\n");
 		return 0;
 	}
+	mutex_lock(&inst->sync_lock);
+	msm_comm_flush_dynamic_buffers(inst);
+	mutex_unlock(&inst->sync_lock);
 	if (inst->state == MSM_VIDC_CORE_INVALID ||
 			core->state == VIDC_CORE_INVALID) {
 		dprintk(VIDC_ERR,
@@ -3009,7 +3179,6 @@
 	}
 
 	mutex_lock(&inst->sync_lock);
-	msm_comm_flush_dynamic_buffers(inst);
 	if (inst->in_reconfig && !ip_flush && op_flush) {
 		if (!list_empty(&inst->pendingq)) {
 			/*Execution can never reach here since port reconfig
@@ -3093,12 +3262,6 @@
 	case V4L2_MPEG_VIDC_EXTRADATA_RECOVERY_POINT_SEI:
 		ret = HAL_EXTRADATA_RECOVERY_POINT_SEI;
 		break;
-	case V4L2_MPEG_VIDC_EXTRADATA_CLOSED_CAPTION_UD:
-		ret = HAL_EXTRADATA_CLOSED_CAPTION_UD;
-		break;
-	case V4L2_MPEG_VIDC_EXTRADATA_AFD_UD:
-		ret = HAL_EXTRADATA_AFD_UD;
-		break;
 	case V4L2_MPEG_VIDC_EXTRADATA_MULTISLICE_INFO:
 		ret = HAL_EXTRADATA_MULTISLICE_INFO;
 		break;
@@ -3114,6 +3277,21 @@
 	case V4L2_MPEG_VIDC_EXTRADATA_MPEG2_SEQDISP:
 		ret = HAL_EXTRADATA_MPEG2_SEQDISP;
 		break;
+	case V4L2_MPEG_VIDC_EXTRADATA_FRAME_QP:
+		ret = HAL_EXTRADATA_FRAME_QP;
+		break;
+	case V4L2_MPEG_VIDC_EXTRADATA_FRAME_BITS_INFO:
+		ret = HAL_EXTRADATA_FRAME_BITS_INFO;
+		break;
+	case V4L2_MPEG_VIDC_EXTRADATA_LTR:
+		ret = HAL_EXTRADATA_LTR_INFO;
+		break;
+	case V4L2_MPEG_VIDC_EXTRADATA_METADATA_MBI:
+		ret = HAL_EXTRADATA_METADATA_MBI;
+		break;
+	case V4L2_MPEG_VIDC_EXTRADATA_STREAM_USERDATA:
+		ret = HAL_EXTRADATA_STREAM_USERDATA;
+		break;
 	default:
 		dprintk(VIDC_WARN, "Extradata not found: %d\n", index);
 		break;
@@ -3177,20 +3355,16 @@
 	int num_mbs_per_sec = 0;
 
 	if (inst->state == MSM_VIDC_OPEN_DONE) {
-		mutex_lock(&inst->core->sync_lock);
 		num_mbs_per_sec = msm_comm_get_load(inst->core,
 			MSM_VIDC_DECODER);
 		num_mbs_per_sec += msm_comm_get_load(inst->core,
 			MSM_VIDC_ENCODER);
-		mutex_unlock(&inst->core->sync_lock);
 		if (num_mbs_per_sec > inst->core->resources.max_load) {
 			dprintk(VIDC_ERR,
 				"H/w is overloaded. needed: %d max: %d\n",
 				num_mbs_per_sec,
 				inst->core->resources.max_load);
-			mutex_lock(&inst->sync_lock);
 			msm_vidc_print_running_insts(inst->core);
-			mutex_unlock(&inst->sync_lock);
 			return -EINVAL;
 		}
 	}
@@ -3277,16 +3451,36 @@
 
 	rc = msm_vidc_load_supported(inst);
 	if (!rc && inst->capability.capability_set) {
-		rc = call_hfi_op(hdev, capability_check,
-			inst->fmts[OUTPUT_PORT]->fourcc,
-			inst->prop.width[CAPTURE_PORT], &capability->width.max,
-			&capability->height.max);
+		if (inst->prop.width[CAPTURE_PORT] < capability->width.min ||
+			inst->prop.height[CAPTURE_PORT] <
+			capability->height.min) {
+			dprintk(VIDC_ERR,
+				"Unsupported WxH = (%u)x(%u), min supported is - (%u)x(%u)\n",
+				inst->prop.width[CAPTURE_PORT],
+				inst->prop.height[CAPTURE_PORT],
+				capability->width.min,
+				capability->height.min);
+			rc = -ENOTSUPP;
+		}
+		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);
+				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);
@@ -3297,7 +3491,10 @@
 		mutex_lock(&inst->sync_lock);
 		inst->state = MSM_VIDC_CORE_INVALID;
 		mutex_unlock(&inst->sync_lock);
-		msm_vidc_queue_v4l2_event(inst, V4L2_EVENT_MSM_VIDC_SYS_ERROR);
+		msm_vidc_queue_v4l2_event(inst,
+					V4L2_EVENT_MSM_VIDC_HW_OVERLOAD);
+		dprintk(VIDC_WARN,
+			"%s: Hardware is overloaded\n", __func__);
 		wake_up(&inst->kernel_event_queue);
 	}
 	return rc;
@@ -3348,8 +3545,9 @@
 		&inst->completions[SESSION_MSG_INDEX(SESSION_ABORT_DONE)],
 		msecs_to_jiffies(msm_vidc_hw_rsp_timeout));
 	if (!rc) {
-		dprintk(VIDC_ERR, "%s: Wait interrupted or timeout: %d\n",
-			__func__, rc);
+		dprintk(VIDC_ERR, "%s: Wait interrupted or timeout[%u]: %d\n",
+			__func__, (u32)inst->session,
+			SESSION_MSG_INDEX(SESSION_ABORT_DONE));
 		msm_comm_generate_sys_error(inst);
 	} else
 		change_inst_state(inst, MSM_VIDC_CLOSE_DONE);
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.h b/drivers/media/platform/msm/vidc/msm_vidc_common.h
index e2f7b61..da71424 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.h
@@ -32,11 +32,13 @@
 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);
 int msm_comm_release_scratch_buffers(struct msm_vidc_inst *inst);
 int msm_comm_release_persist_buffers(struct msm_vidc_inst *inst);
+int msm_comm_release_output_buffers(struct msm_vidc_inst *inst);
 int msm_comm_force_cleanup(struct msm_vidc_inst *inst);
 enum hal_extradata_id msm_comm_get_hal_extradata_index(
 	enum v4l2_mpeg_vidc_extradata index);
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_internal.h b/drivers/media/platform/msm/vidc/msm_vidc_internal.h
index e4f920f..1677e57 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_internal.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_internal.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
@@ -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
@@ -190,13 +191,15 @@
 	u32 pixelprocess_capabilities;
 	struct hal_capability_supported scale_x;
 	struct hal_capability_supported scale_y;
+	struct hal_capability_supported ltr_count;
+	struct hal_capability_supported hier_p;
 	u32 capability_set;
 	enum buffer_mode_type buffer_mode[MAX_PORT_NUM];
 };
 
 struct msm_vidc_core {
 	struct list_head list;
-	struct mutex sync_lock, lock;
+	struct mutex lock;
 	int id;
 	void *device;
 	struct msm_video_device vdev[MSM_VIDC_MAX_DEVICES];
@@ -229,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;
@@ -248,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;
@@ -267,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 8e91f34..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;
 	}
 
@@ -210,8 +210,9 @@
 		iommu_map = &iommu_group_set->iommu_maps[i];
 		iommu_map->group = iommu_group_find(iommu_map->name);
 		if (!iommu_map->group) {
-			dprintk(VIDC_ERR, "Failed to find group :%s\n",
+			dprintk(VIDC_DBG, "Failed to find group :%s\n",
 					iommu_map->name);
+			rc = -EPROBE_DEFER;
 			goto fail_group;
 		}
 		domain = iommu_group_get_iommudata(iommu_map->group);
@@ -219,6 +220,7 @@
 			dprintk(VIDC_ERR,
 					"Failed to get domain data for group %p",
 					iommu_map->group);
+			rc = -EINVAL;
 			goto fail_group;
 		}
 		iommu_map->domain = msm_find_domain_no(domain);
@@ -226,6 +228,7 @@
 			dprintk(VIDC_ERR,
 					"Failed to get domain index for domain %p",
 					domain);
+			rc = -EINVAL;
 			goto fail_group;
 		}
 	}
@@ -239,7 +242,7 @@
 		iommu_map->group = NULL;
 		iommu_map->domain = -1;
 	}
-	return -EINVAL;
+	return rc;
 }
 
 static void q6_hfi_deregister_iommu_domains(struct q6_hfi_device *device)
@@ -275,8 +278,12 @@
 
 	device->res = res;
 	rc = q6_hfi_register_iommu_domains(device);
-	if (rc)
-		dprintk(VIDC_ERR, "Failed to register iommu domains: %d\n", rc);
+	if (rc) {
+		if (rc != -EPROBE_DEFER) {
+			dprintk(VIDC_ERR,
+				"Failed to register iommu domains: %d\n", rc);
+		}
+	}
 
 	return rc;
 }
@@ -351,14 +358,15 @@
 
 	rc = q6_hfi_init_resources(device, res);
 	if (rc) {
-		dprintk(VIDC_ERR, "Failed to init resources: %d\n", rc);
+		if (rc != -EPROBE_DEFER)
+			dprintk(VIDC_ERR, "Failed to init resources: %d\n", rc);
 		goto err_fail_init_res;
 	}
 	return device;
 
 err_fail_init_res:
 	q6_hfi_delete_device(device);
-	return NULL;
+	return ERR_PTR(rc);
 }
 
 void q6_hfi_delete_device(void *device)
@@ -546,6 +554,10 @@
 
 	new_session = (struct hal_session *)
 		kzalloc(sizeof(struct hal_session), GFP_KERNEL);
+	if (!new_session) {
+		dprintk(VIDC_ERR, "new session fail: Out of memory\n");
+		return NULL;
+	}
 	new_session->session_id = (u32) session_id;
 	if (session_type == 1)
 		new_session->is_decoder = 0;
@@ -1379,6 +1391,12 @@
 	}
 	hdev->hfi_device_data = q6_hfi_get_device(device_id, res, callback);
 
+	if (IS_ERR_OR_NULL(hdev->hfi_device_data)) {
+		rc = PTR_ERR(hdev->hfi_device_data);
+		rc = !rc ? -EINVAL : rc;
+		goto err_hfi_init;
+	}
+
 	q6_init_hfi_callbacks(hdev);
 
 err_hfi_init:
diff --git a/drivers/media/platform/msm/vidc/venus_hfi.c b/drivers/media/platform/msm/vidc/venus_hfi.c
index 2596a30..448fe3b 100644
--- a/drivers/media/platform/msm/vidc/venus_hfi.c
+++ b/drivers/media/platform/msm/vidc/venus_hfi.c
@@ -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
@@ -80,11 +80,31 @@
 	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);
+
 static void venus_hfi_dump_packet(u8 *packet)
 {
 	u32 c = 0, packet_size = *(u32 *)packet;
@@ -474,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;
@@ -514,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;
@@ -524,6 +544,25 @@
 	return rc;
 }
 
+static void venus_hfi_set_registers(struct venus_hfi_device *device)
+{
+	struct reg_set *reg_set;
+	int i;
+
+	if (!device->res) {
+		dprintk(VIDC_ERR,
+			"device resources null, cannot set registers\n");
+		return;
+	}
+
+	reg_set = &device->res->reg_set;
+	for (i = 0; i < reg_set->count; i++) {
+		venus_hfi_write_register(device,
+				reg_set->reg_tbl[i].reg,
+				reg_set->reg_tbl[i].value, 0);
+	}
+}
+
 static int venus_hfi_core_start_cpu(struct venus_hfi_device *device)
 {
 	u32 ctrl_status = 0, count = 0, rc = 0;
@@ -786,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};
@@ -820,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;
@@ -832,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;
 	}
@@ -847,41 +1083,54 @@
 			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:
 	for (i--; i >= 0; i--) {
 		cl = &device->resources.clock[i];
+		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;
+	int i, rc = 0;
 	struct venus_core_clock *cl;
 
 	if (!device) {
 		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;
 	}
 
+	/* We get better power savings if we lower the venus core clock to the
+	 * lowest level before disabling it. */
+	rc = clk_set_rate(device->resources.clock[VCODEC_CLK].clk,
+			venus_hfi_get_clock_rate(
+			&device->resources.clock[VCODEC_CLK], 0));
+	if (rc)
+		dprintk(VIDC_WARN, "Failed to set clock rate to min: %d\n", rc);
+
 	for (i = 0; i <= device->clk_gating_level; i++) {
 		cl = &device->resources.clock[i];
+		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)
 {
@@ -891,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);
@@ -908,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;
 }
 
@@ -935,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) {
@@ -947,8 +1200,9 @@
 	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:
 	return rc;
 }
@@ -982,25 +1236,67 @@
 		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;
 	}
 
+
+	/*
+	 * Re-program all of the registers that get reset as a result of
+	 * regulator_disable() and _enable()
+	 */
+	venus_hfi_set_registers(device);
+
+	venus_hfi_write_register(device, VIDC_UC_REGION_ADDR,
+			(u32)device->iface_q_table.align_device_addr, 0);
+	venus_hfi_write_register(device,
+			VIDC_UC_REGION_SIZE, SHARED_QSIZE, 0);
+	venus_hfi_write_register(device, VIDC_CPU_CS_SCIACMDARG2,
+		(u32)device->iface_q_table.align_device_addr,
+		device->iface_q_table.align_virtual_addr);
+
+	if (!IS_ERR_OR_NULL(device->sfr.align_device_addr))
+		venus_hfi_write_register(device, VIDC_SFR_ADDR,
+				(u32)device->sfr.align_device_addr, 0);
+	if (!IS_ERR_OR_NULL(device->qdss.align_device_addr))
+		venus_hfi_write_register(device, VIDC_MMAP_ADDR,
+				(u32)device->qdss.align_device_addr, 0);
+
+	/* Reboot the firmware */
 	rc = venus_hfi_tzbsp_set_video_state(TZBSP_VIDEO_STATE_RESUME);
 	if (rc) {
 		dprintk(VIDC_ERR, "Failed to resume video core %d\n", rc);
 		goto err_set_video_state;
 	}
+
+	/* Wait for boot completion */
 	rc = venus_hfi_reset_core(device);
 	if (rc) {
 		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:
@@ -1026,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;
 }
 
@@ -1044,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;
 	}
@@ -1066,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;
 }
@@ -1104,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)
@@ -1142,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;
 }
 
@@ -1163,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);
@@ -1207,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");
@@ -1292,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;
 
@@ -1484,25 +1817,6 @@
 	return -ENOMEM;
 }
 
-static void venus_hfi_set_registers(struct venus_hfi_device *device)
-{
-	struct reg_set *reg_set;
-	int i;
-
-	if (!device->res) {
-		dprintk(VIDC_ERR,
-			"device resources null, cannot set registers\n");
-		return;
-	}
-
-	reg_set = &device->res->reg_set;
-	for (i = 0; i < reg_set->count; i++) {
-		venus_hfi_write_register(device,
-				reg_set->reg_tbl[i].reg,
-				reg_set->reg_tbl[i].value, 0);
-	}
-}
-
 static int venus_hfi_sys_set_debug(struct venus_hfi_device *device, int debug)
 {
 	u8 packet[VIDC_IFACEQ_VAR_SMALL_PKT_SIZE];
@@ -1546,11 +1860,10 @@
 		return -ENODEV;
 	}
 
+	VENUS_SET_STATE(dev, VENUS_STATE_INIT);
+
 	dev->intr_status = 0;
 	INIT_LIST_HEAD(&dev->sess_head);
-	mutex_init(&dev->read_lock);
-	mutex_init(&dev->write_lock);
-	mutex_init(&dev->session_lock);
 	venus_hfi_set_registers(dev);
 
 	if (!dev->hal_client) {
@@ -1601,6 +1914,7 @@
 
 	return rc;
 err_core_init:
+	VENUS_SET_STATE(dev, VENUS_STATE_DEINIT);
 	disable_irq_nosync(dev->hal_data->irq);
 	return rc;
 }
@@ -1615,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);
@@ -1631,19 +1946,31 @@
 		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;
 }
 
-static int venus_hfi_is_cmd_pending(struct venus_hfi_device *dev)
+static int venus_hfi_get_q_size(struct venus_hfi_device *dev,
+	unsigned int q_index)
 {
 	struct hfi_queue_header *queue;
 	struct vidc_iface_q_info *q_info;
 	u32 write_ptr, read_ptr;
 	u32 rc = 0;
-	q_info = &dev->iface_queues[VIDC_IFACEQ_CMDQ_IDX];
-	if (!q_info)
+	if (q_index >= VIDC_IFACEQ_NUMQ) {
+		dprintk(VIDC_ERR, "Invalid q index: %d\n", q_index);
+		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");
+		return -ENOENT;
+	}
 	queue = (struct hfi_queue_header *) q_info->q_hdr;
 	if (!queue) {
 		dprintk(VIDC_ERR, "queue not present");
@@ -1661,21 +1988,24 @@
 		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;
 	}
 	/*SYS Idle should be last message so mask any further interrupts
 	 * until clocks are enabled again.*/
-	venus_hfi_write_register(device,
-			VIDC_WRAPPER_INTR_MASK,
-			VIDC_WRAPPER_INTR_MASK_A2HVCODEC_BMSK | VIDC_WRAPPER_INTR_MASK_A2HCPU_BMSK, 0);
+	if (!venus_hfi_get_q_size(device, VIDC_IFACEQ_MSGQ_IDX)) {
+		venus_hfi_write_register(device,
+				VIDC_WRAPPER_INTR_MASK,
+				VIDC_WRAPPER_INTR_MASK_A2HVCODEC_BMSK |
+				VIDC_WRAPPER_INTR_MASK_A2HCPU_BMSK, 0);
+	}
 	venus_hfi_clk_disable(device);
 	if (!queue_delayed_work(device->venus_pm_workq, &venus_hfi_pm_work,
 			msecs_to_jiffies(msm_vidc_pwr_collapse_delay)))
 		dprintk(VIDC_DBG, "PM work already scheduled\n");
 already_disabled:
-	device->clocks_enabled = 0;
+	device->clk_state = DISABLED_PREPARED;
 }
 
 static void venus_hfi_core_clear_interrupt(struct venus_hfi_device *device)
@@ -1721,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;
@@ -2004,6 +2277,10 @@
 
 	new_session = (struct hal_session *)
 		kzalloc(sizeof(struct hal_session), GFP_KERNEL);
+	if (!new_session) {
+		dprintk(VIDC_ERR, "new session fail: Out of memory\n");
+		return NULL;
+	}
 	new_session->session_id = (u32) session_id;
 	if (session_type == 1)
 		new_session->is_decoder = 0;
@@ -2461,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)
 {
@@ -2468,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;
@@ -2512,7 +2853,7 @@
 	}
 	mutex_lock(&device->write_lock);
 	mutex_lock(&device->clk_pwr_lock);
-	rc = venus_hfi_is_cmd_pending(device);
+	rc = venus_hfi_get_q_size(device, VIDC_IFACEQ_CMDQ_IDX);
 	ctrl_status = venus_hfi_read_register(
 		device,
 		VIDC_CPU_CS_SCIACMDARG0);
@@ -2573,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");
@@ -2766,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;
@@ -2774,16 +3126,21 @@
 		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;
 			cl = &device->resources.clock[i];
+			usleep(100);
 			clk_disable(cl->clk);
 		}
 	} else {
 		for (i = device->clk_gating_level + 1;
 			i < VCODEC_MAX_CLKS; i++) {
 			cl = &device->resources.clock[i];
+			usleep(100);
 			clk_disable(cl->clk);
 		}
 	}
@@ -2793,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;
@@ -2806,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;
@@ -2819,18 +3181,19 @@
 			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--) {
 		cl = &device->resources.clock[i];
+		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)
 {
@@ -2848,8 +3211,9 @@
 		iommu_map = &iommu_group_set->iommu_maps[i];
 		iommu_map->group = iommu_group_find(iommu_map->name);
 		if (!iommu_map->group) {
-			dprintk(VIDC_ERR, "Failed to find group :%s\n",
+			dprintk(VIDC_DBG, "Failed to find group :%s\n",
 				iommu_map->name);
+			rc = -EPROBE_DEFER;
 			goto fail_group;
 		}
 		domain = iommu_group_get_iommudata(iommu_map->group);
@@ -2857,6 +3221,7 @@
 			dprintk(VIDC_ERR,
 				"Failed to get domain data for group %p",
 				iommu_map->group);
+			rc = -EINVAL;
 			goto fail_group;
 		}
 		iommu_map->domain = msm_find_domain_no(domain);
@@ -2864,6 +3229,7 @@
 			dprintk(VIDC_ERR,
 				"Failed to get domain index for domain %p",
 				domain);
+			rc = -EINVAL;
 			goto fail_group;
 		}
 	}
@@ -2877,7 +3243,7 @@
 		iommu_map->group = NULL;
 		iommu_map->domain = -1;
 	}
-	return -EINVAL;
+	return rc;
 }
 
 static void venus_hfi_deregister_iommu_domains(struct venus_hfi_device *device)
@@ -2974,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)
 {
@@ -3044,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;
 		}
@@ -3070,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;
-		}
-		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)
@@ -3164,7 +3423,10 @@
 
 	rc = venus_hfi_register_iommu_domains(device, res);
 	if (rc) {
-		dprintk(VIDC_ERR, "Failed to register iommu domains: %d\n", rc);
+		if (rc != -EPROBE_DEFER) {
+			dprintk(VIDC_ERR,
+				"Failed to register iommu domains: %d\n", rc);
+		}
 		goto err_register_iommu_domain;
 	}
 
@@ -3266,7 +3528,6 @@
 			__func__, device);
 		return -EINVAL;
 	}
-	mutex_init(&device->clk_pwr_lock);
 	device->clk_gating_level = VCODEC_CLK;
 	rc = venus_hfi_iommu_attach(device);
 	if (rc) {
@@ -3291,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");
@@ -3310,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:
@@ -3346,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;
@@ -3406,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;
@@ -3430,61 +3739,11 @@
 
 int venus_hfi_get_core_capabilities(void)
 {
-	int i = 0, rc = 0, j = 0, venus_version_length = 0;
-	u32 smem_block_size = 0;
-	u8 *smem_table_ptr;
-	char version[256];
-	const u32 version_string_size = 128;
-	char venus_version[] = "VIDEO.VE.1.4";
-	u8 version_info[256];
-	const u32 smem_image_index_venus = 14 * 128;
-	/* Venus version is stored at 14th entry in smem table */
-
-	smem_table_ptr = smem_get_entry(SMEM_IMAGE_VERSION_TABLE,
-			&smem_block_size);
-	if (smem_table_ptr &&
-			((smem_image_index_venus + version_string_size) <=
-			smem_block_size))
-		memcpy(version_info, smem_table_ptr + smem_image_index_venus,
-				version_string_size);
-
-	while (version_info[i++] != 'V' && i < version_string_size)
-		;
-
-	venus_version_length = strlen(venus_version);
-	for (i--, j = 0; i < version_string_size && j < venus_version_length;
-		i++)
-		version[j++] = version_info[i];
-	version[venus_version_length] = '\0';
-	dprintk(VIDC_DBG, "F/W version retrieved : %s\n", version);
-
-	if (strcmp((const char *)version, (const char *)venus_version) == 0)
-		rc = HAL_VIDEO_ENCODER_ROTATION_CAPABILITY |
-			HAL_VIDEO_ENCODER_SCALING_CAPABILITY |
-			HAL_VIDEO_ENCODER_DEINTERLACE_CAPABILITY |
-			HAL_VIDEO_DECODER_MULTI_STREAM_CAPABILITY;
-	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;
-	}
+	rc = HAL_VIDEO_ENCODER_ROTATION_CAPABILITY |
+		HAL_VIDEO_ENCODER_SCALING_CAPABILITY |
+		HAL_VIDEO_ENCODER_DEINTERLACE_CAPABILITY |
+		HAL_VIDEO_DECODER_MULTI_STREAM_CAPABILITY;
 	return rc;
 }
 
@@ -3495,7 +3754,7 @@
 	struct venus_hfi_device *hdevice = NULL;
 	int rc = 0;
 
-	if (device_id || !res || !callback) {
+	if (!res || !callback) {
 		dprintk(VIDC_ERR, "Invalid Paramters");
 		return NULL;
 	}
@@ -3515,9 +3774,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(
@@ -3533,6 +3792,11 @@
 		goto error_createq_pm;
 	}
 
+	mutex_init(&hdevice->read_lock);
+	mutex_init(&hdevice->write_lock);
+	mutex_init(&hdevice->session_lock);
+	mutex_init(&hdevice->clk_pwr_lock);
+
 	if (hal_ctxt.dev_count == 0)
 		INIT_LIST_HEAD(&hal_ctxt.dev_head);
 
@@ -3570,14 +3834,15 @@
 
 	rc = venus_hfi_init_resources(device, res);
 	if (rc) {
-		dprintk(VIDC_ERR, "Failed to init resources: %d\n", rc);
+		if (rc != -EPROBE_DEFER)
+			dprintk(VIDC_ERR, "Failed to init resources: %d\n", rc);
 		goto err_fail_init_res;
 	}
 	return device;
 
 err_fail_init_res:
 	venus_hfi_delete_device(device);
-	return NULL;
+	return ERR_PTR(rc);
 }
 
 void venus_hfi_delete_device(void *device)
@@ -3639,10 +3904,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;
 }
@@ -3661,6 +3926,12 @@
 	}
 	hdev->hfi_device_data = venus_hfi_get_device(device_id, res, callback);
 
+	if (IS_ERR_OR_NULL(hdev->hfi_device_data)) {
+		rc = PTR_ERR(hdev->hfi_device_data);
+		rc = !rc ? -EINVAL : rc;
+		goto err_venus_hfi_init;
+	}
+
 	venus_init_hfi_callbacks(hdev);
 
 err_venus_hfi_init:
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.c b/drivers/media/platform/msm/vidc/vidc_hfi.c
index 46293a6..ef0de37 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi.c
+++ b/drivers/media/platform/msm/vidc/vidc_hfi.c
@@ -44,7 +44,8 @@
 	}
 
 	if (rc) {
-		dprintk(VIDC_ERR, "%s device init failed rc = %d",
+		if (rc != -EPROBE_DEFER)
+			dprintk(VIDC_ERR, "%s device init failed rc = %d",
 				__func__, rc);
 		goto err_hfi_init;
 	}
@@ -53,7 +54,7 @@
 
 err_hfi_init:
 	kfree(hdev);
-	return NULL;
+	return ERR_PTR(rc);
 }
 
 void vidc_hfi_deinitialize(enum msm_vidc_hfi_type hfi_type,
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi.h b/drivers/media/platform/msm/vidc/vidc_hfi.h
index 70b93ff0..5566338 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi.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
@@ -19,6 +19,7 @@
 
 #define HFI_EVENT_SESSION_SEQUENCE_CHANGED (HFI_OX_BASE + 0x3)
 #define HFI_EVENT_SESSION_PROPERTY_CHANGED (HFI_OX_BASE + 0x4)
+#define HFI_EVENT_SESSION_LTRUSE_FAILED (HFI_OX_BASE + 0x5)
 #define HFI_EVENT_RELEASE_BUFFER_REFERENCE (HFI_OX_BASE + 0x6)
 
 #define HFI_EVENT_DATA_SEQUENCE_CHANGED_SUFFICIENT_BUFFER_RESOURCES	\
@@ -78,12 +79,14 @@
 #define HFI_EXTRADATA_FRAME_RATE			0x00000007
 #define HFI_EXTRADATA_PANSCAN_WINDOW		0x00000008
 #define HFI_EXTRADATA_RECOVERY_POINT_SEI	0x00000009
-#define HFI_EXTRADATA_CLOSED_CAPTION_UD		0x0000000A
-#define HFI_EXTRADATA_AFD_UD			0x0000000B
 #define HFI_EXTRADATA_MPEG2_SEQDISP		0x0000000D
+#define HFI_EXTRADATA_STREAM_USERDATA		0x0000000E
+#define HFI_EXTRADATA_FRAME_QP			0x0000000F
+#define HFI_EXTRADATA_FRAME_BITS_INFO		0x00000010
 #define HFI_EXTRADATA_MULTISLICE_INFO		0x7F100000
 #define HFI_EXTRADATA_NUM_CONCEALED_MB		0x7F100001
 #define HFI_EXTRADATA_INDEX					0x7F100002
+#define HFI_EXTRADATA_METADATA_LTR			0x7F100004
 #define HFI_EXTRADATA_METADATA_FILLER		0x7FE00002
 
 #define HFI_INDEX_EXTRADATA_INPUT_CROP		0x0700000E
@@ -186,10 +189,6 @@
 
 #define HFI_PROPERTY_PARAM_VDEC_FRAME_ASSEMBLY		\
 	(HFI_PROPERTY_PARAM_VDEC_OX_START + 0x00E)
-#define HFI_PROPERTY_PARAM_VDEC_CLOSED_CAPTION_EXTRADATA	\
-	(HFI_PROPERTY_PARAM_VDEC_OX_START + 0x00F)
-#define HFI_PROPERTY_PARAM_VDEC_AFD_EXTRADATA		\
-	(HFI_PROPERTY_PARAM_VDEC_OX_START + 0x010)
 #define HFI_PROPERTY_PARAM_VDEC_VC1_FRAMEDISP_EXTRADATA		\
 	(HFI_PROPERTY_PARAM_VDEC_OX_START + 0x011)
 #define HFI_PROPERTY_PARAM_VDEC_VC1_SEQDISP_EXTRADATA		\
@@ -202,6 +201,12 @@
 	(HFI_PROPERTY_PARAM_VDEC_OX_START + 0x015)
 #define HFI_PROPERTY_PARAM_VDEC_MPEG2_SEQDISP_EXTRADATA \
 	(HFI_PROPERTY_PARAM_VDEC_OX_START + 0x016)
+#define HFI_PROPERTY_PARAM_VDEC_STREAM_USERDATA_EXTRADATA \
+	(HFI_PROPERTY_PARAM_VDEC_OX_START + 0x017)
+#define HFI_PROPERTY_PARAM_VDEC_FRAME_QP_EXTRADATA \
+	(HFI_PROPERTY_PARAM_VDEC_OX_START + 0x018)
+#define HFI_PROPERTY_PARAM_VDEC_FRAME_BITS_INFO_EXTRADATA \
+	(HFI_PROPERTY_PARAM_VDEC_OX_START + 0x019)
 
 #define HFI_PROPERTY_CONFIG_VDEC_OX_START				\
 	(HFI_DOMAIN_BASE_VDEC + HFI_ARCH_OX_OFFSET + 0x0000)
@@ -218,6 +223,10 @@
 	(HFI_PROPERTY_PARAM_VENC_OX_START + 0x001)
 #define  HFI_PROPERTY_PARAM_VENC_H264_IDR_S3D_FRAME_PACKING_NAL \
 	(HFI_PROPERTY_PARAM_VENC_OX_START + 0x002)
+#define  HFI_PROPERTY_PARAM_VENC_LTR_INFO			\
+	(HFI_PROPERTY_PARAM_VENC_OX_START + 0x003)
+#define  HFI_PROPERTY_PARAM_VENC_MBI_DUMPING				\
+	(HFI_PROPERTY_PARAM_VENC_OX_START + 0x005)
 
 #define HFI_PROPERTY_CONFIG_VENC_OX_START				\
 	(HFI_DOMAIN_BASE_VENC + HFI_ARCH_OX_OFFSET + 0x6000)
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_api.h b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
index 846171e..38c5bdb 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi_api.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi_api.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
@@ -44,6 +44,7 @@
 #define HAL_BUFFERFLAG_READONLY         0x00000200
 #define HAL_BUFFERFLAG_ENDOFSUBFRAME    0x00000400
 #define HAL_BUFFERFLAG_EOSEQ            0x00200000
+#define HAL_BUFFERFLAG_MBAFF            0x08000000
 #define HAL_BUFFERFLAG_DROP_FRAME       0x20000000
 
 
@@ -62,7 +63,7 @@
 	VIDC_ERR_BAD_HANDLE,
 	VIDC_ERR_NOT_SUPPORTED,
 	VIDC_ERR_BAD_STATE,
-	VIDC_ERR_MAX_CLIENT,
+	VIDC_ERR_MAX_CLIENTS,
 	VIDC_ERR_IFRAME_EXPECTED,
 	VIDC_ERR_HW_FATAL,
 	VIDC_ERR_BITSTREAM_ERR,
@@ -90,14 +91,17 @@
 	HAL_EXTRADATA_FRAME_RATE,
 	HAL_EXTRADATA_PANSCAN_WINDOW,
 	HAL_EXTRADATA_RECOVERY_POINT_SEI,
-	HAL_EXTRADATA_CLOSED_CAPTION_UD,
-	HAL_EXTRADATA_AFD_UD,
 	HAL_EXTRADATA_MULTISLICE_INFO,
 	HAL_EXTRADATA_INDEX,
 	HAL_EXTRADATA_NUM_CONCEALED_MB,
 	HAL_EXTRADATA_METADATA_FILLER,
 	HAL_EXTRADATA_ASPECT_RATIO,
-	HAL_EXTRADATA_MPEG2_SEQDISP
+	HAL_EXTRADATA_MPEG2_SEQDISP,
+	HAL_EXTRADATA_FRAME_QP,
+	HAL_EXTRADATA_FRAME_BITS_INFO,
+	HAL_EXTRADATA_LTR_INFO,
+	HAL_EXTRADATA_METADATA_MBI,
+	HAL_EXTRADATA_STREAM_USERDATA,
 };
 
 enum hal_property {
@@ -177,6 +181,13 @@
 	HAL_PARAM_BUFFER_ALLOC_MODE,
 	HAL_PARAM_VDEC_FRAME_ASSEMBLY,
 	HAL_PARAM_VDEC_CONCEAL_COLOR,
+	HAL_PARAM_VENC_LTRMODE,
+	HAL_CONFIG_VENC_MARKLTRFRAME,
+	HAL_CONFIG_VENC_USELTRFRAME,
+	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 {
@@ -622,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;
@@ -896,6 +914,27 @@
 	enum buffer_mode_type buffer_mode;
 };
 
+enum ltr_mode {
+	HAL_LTR_MODE_DISABLE,
+	HAL_LTR_MODE_MANUAL,
+	HAL_LTR_MODE_PERIODIC,
+};
+
+struct hal_ltrmode {
+	enum ltr_mode ltrmode;
+	u32 ltrcount;
+	u32 trustmode;
+};
+
+struct hal_ltruse {
+	u32 refltr;
+	u32 useconstrnt;
+	u32 frames;
+};
+
+struct hal_ltrmark {
+	u32 markframe;
+};
 /* HAL Response */
 
 enum command_response {
@@ -1032,6 +1071,8 @@
 	struct hal_capability_supported scale_x;
 	struct hal_capability_supported scale_y;
 	struct hal_capability_supported bitrate;
+	struct hal_capability_supported ltr_count;
+	struct hal_capability_supported hier_p;
 	struct hal_uncompressed_format_supported uncomp_format;
 	struct hal_interlace_format_supported HAL_format;
 	struct hal_nal_stream_format_supported nal_stream_format;
@@ -1122,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 1916e9f..7c62e77 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi_helper.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi_helper.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
@@ -305,11 +305,9 @@
 	(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x018)
 #define HFI_PROPERTY_PARAM_VENC_MULTIREF_P				\
 	(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x019)
-#define HFI_PROPERTY_PARAM_VENC_HIER_P_NUM_ENH_LAYER	\
-	(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x01A)
 #define HFI_PROPERTY_PARAM_VENC_H264_NAL_SVC_EXT		\
 	(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x01B)
-#define HFI_PROPERTY_PARAM_VENC_H264_LTRMODE		\
+#define HFI_PROPERTY_PARAM_VENC_LTRMODE		\
 	 (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x01C)
 #define HFI_PROPERTY_PARAM_VENC_VIDEO_FULL_RANGE	\
 	(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x01D)
@@ -319,6 +317,10 @@
 	(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x01F)
 #define  HFI_PROPERTY_PARAM_VENC_MAX_NUM_B_FRAMES \
 	(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				\
@@ -338,7 +340,14 @@
 	(HFI_DOMAIN_BASE_VPE + HFI_ARCH_COMMON_OFFSET + 0x7000)
 #define  HFI_PROPERTY_CONFIG_VENC_SYNC_FRAME_SEQUENCE_HEADER	\
 	(HFI_PROPERTY_CONFIG_VENC_COMMON_START + 0x008)
-
+#define  HFI_PROPERTY_CONFIG_VENC_MARKLTRFRAME			\
+	(HFI_PROPERTY_CONFIG_VENC_COMMON_START + 0x009)
+#define  HFI_PROPERTY_CONFIG_VENC_USELTRFRAME			\
+	(HFI_PROPERTY_CONFIG_VENC_COMMON_START + 0x00A)
+#define  HFI_PROPERTY_CONFIG_VENC_HIER_P_ENH_LAYER		\
+	(HFI_PROPERTY_CONFIG_VENC_COMMON_START + 0x00B)
+#define  HFI_PROPERTY_CONFIG_VENC_LTRPERIOD			\
+	(HFI_PROPERTY_CONFIG_VENC_COMMON_START + 0x00C)
 #define HFI_PROPERTY_CONFIG_VPE_COMMON_START				\
 	(HFI_DOMAIN_BASE_VPE + HFI_ARCH_COMMON_OFFSET + 0x8000)
 #define HFI_PROPERTY_CONFIG_VPE_DEINTERLACE				\
@@ -361,6 +370,7 @@
 #define HFI_CAPABILITY_BITRATE				(HFI_COMMON_BASE + 0x8)
 #define  HFI_CAPABILITY_BFRAME				(HFI_COMMON_BASE + 0x9)
 #define  HFI_CAPABILITY_HIER_P_NUM_ENH_LAYERS   (HFI_COMMON_BASE + 0x10)
+#define  HFI_CAPABILITY_ENC_LTR_COUNT      (HFI_COMMON_BASE + 0x11)
 
 struct hfi_capability_supported {
 	u32 capability_type;
@@ -525,12 +535,39 @@
 	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;
 	u32 layer_id;
 };
 
+#define HFI_LTR_MODE_DISABLE	0x0
+#define HFI_LTR_MODE_MANUAL		0x1
+#define HFI_LTR_MODE_PERIODIC	0x2
+
+struct hfi_ltrmode {
+	u32 ltrmode;
+	u32 ltrcount;
+	u32 trustmode;
+};
+
+struct hfi_ltruse {
+	u32 refltr;
+	u32 useconstrnt;
+	u32 frames;
+};
+
+struct hfi_ltrmark {
+	u32 markframe;
+};
+
 struct hfi_frame_size {
 	u32 buffer_type;
 	u32 width;
diff --git a/drivers/media/platform/msm/wfd/enc-venus-subdev.c b/drivers/media/platform/msm/wfd/enc-venus-subdev.c
index 9cd199b..40d1b2c 100644
--- a/drivers/media/platform/msm/wfd/enc-venus-subdev.c
+++ b/drivers/media/platform/msm/wfd/enc-venus-subdev.c
@@ -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,6 +14,7 @@
 #include <linux/bitmap.h>
 #include <linux/completion.h>
 #include <linux/ion.h>
+#include <linux/jiffies.h>
 #include <linux/kthread.h>
 #include <linux/list.h>
 #include <linux/mutex.h>
@@ -28,6 +29,7 @@
 
 #define BUF_TYPE_OUTPUT V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE
 #define BUF_TYPE_INPUT V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE
+#define TIMEOUT msecs_to_jiffies(100)
 
 static struct ion_client *venc_ion_client;
 static long venc_secure(struct v4l2_subdev *sd);
@@ -377,7 +379,8 @@
 		goto vidc_wq_create_fail;
 	}
 
-	inst->vidc_context = msm_vidc_open(MSM_VIDC_CORE_0, MSM_VIDC_ENCODER);
+	inst->vidc_context = msm_vidc_open(MSM_VIDC_CORE_VENUS,
+				MSM_VIDC_ENCODER);
 	if (!inst->vidc_context) {
 		WFD_MSG_ERR("Failed to create vidc context\n");
 		rc = -ENXIO;
@@ -1026,10 +1029,18 @@
 		index = next_free_index(&inst->free_output_indices);
 		mutex_unlock(&inst->lock);
 
-		if (index < 0)
-			wait_for_completion(&inst->dq_complete);
-		else
+		if (index < 0) {
+			rc = wait_for_completion_timeout(&inst->dq_complete,
+					TIMEOUT);
+			if (!rc) {
+				WFD_MSG_ERR(
+					"Timed out waiting for an output buffer\n");
+				rc = -ETIMEDOUT;
+				goto err_fill_buf;
+			}
+		} else {
 			break;
+		}
 	}
 
 	buffer = (struct v4l2_buffer) {
@@ -1049,6 +1060,7 @@
 		mutex_unlock(&inst->lock);
 	}
 
+err_fill_buf:
 	return rc;
 }
 
@@ -1152,10 +1164,18 @@
 		index = next_free_index(&inst->free_input_indices);
 		mutex_unlock(&inst->lock);
 
-		if (index < 0)
-			wait_for_completion(&inst->dq_complete);
-		else
+		if (index < 0) {
+			rc = wait_for_completion_timeout(&inst->dq_complete,
+					TIMEOUT);
+			if (!rc) {
+				WFD_MSG_ERR(
+					"Timed out waiting for an input buffer\n");
+				rc = -ETIMEDOUT;
+				goto err_encode_frame;
+			}
+		} else {
 			break;
+		}
 	}
 
 	buffer = (struct v4l2_buffer) {
@@ -1175,6 +1195,7 @@
 		mark_index_busy(&inst->free_input_indices, index);
 		mutex_unlock(&inst->lock);
 	}
+err_encode_frame:
 	return rc;
 }
 
diff --git a/drivers/media/platform/msm/wfd/mdp-5-subdev.c b/drivers/media/platform/msm/wfd/mdp-5-subdev.c
index 97204ae..a28cb1a 100644
--- a/drivers/media/platform/msm/wfd/mdp-5-subdev.c
+++ b/drivers/media/platform/msm/wfd/mdp-5-subdev.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
@@ -208,6 +208,7 @@
 		return -EINVAL;
 	}
 
+	msm_fb_writeback_iommu_ref(inst->mdp, true);
 	if (inst->secure) {
 		rc = msm_ion_secure_buffer(mmap->ion_client,
 			mregion->ion_handle, VIDEO_PIXEL, 0);
@@ -231,12 +232,15 @@
 				!inst->secure ? "non" : "", rc);
 		goto iommu_fail;
 	}
+	msm_fb_writeback_iommu_ref(inst->mdp, false);
 
 	return 0;
 iommu_fail:
 	if (inst->secure)
 		msm_ion_unsecure_buffer(mmap->ion_client, mregion->ion_handle);
 secure_fail:
+	msm_fb_writeback_iommu_ref(inst->mdp, false);
+
 	return rc;
 }
 
@@ -251,10 +255,10 @@
 		WFD_MSG_ERR("Invalid argument\n");
 		return -EINVAL;
 	}
-
 	inst = mmap->cookie;
 	mregion = mmap->mregion;
 
+	msm_fb_writeback_iommu_ref(inst->mdp, true);
 	domain = msm_fb_get_iommu_domain(inst->mdp,
 			inst->secure ? MDP_IOMMU_DOMAIN_CP :
 					MDP_IOMMU_DOMAIN_NS);
@@ -264,6 +268,7 @@
 
 	if (inst->secure)
 		msm_ion_unsecure_buffer(mmap->ion_client, mregion->ion_handle);
+	msm_fb_writeback_iommu_ref(inst->mdp, false);
 
 	return 0;
 }
diff --git a/drivers/media/platform/msm/wfd/vsg-subdev.c b/drivers/media/platform/msm/wfd/vsg-subdev.c
index c20250e..960e45c 100644
--- a/drivers/media/platform/msm/wfd/vsg-subdev.c
+++ b/drivers/media/platform/msm/wfd/vsg-subdev.c
@@ -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
@@ -23,12 +23,8 @@
 #define DEFAULT_MAX_FRAME_INTERVAL (1*NSEC_PER_SEC)
 #define DEFAULT_MODE ((enum vsg_modes)VSG_MODE_CFR)
 #define MAX_BUFS_BUSY_WITH_ENC 5
+#define TICKS_PER_TIMEOUT 2
 
-static void vsg_reset_timer(struct hrtimer *timer, ktime_t time)
-{
-	hrtimer_forward_now(timer, time);
-	hrtimer_restart(timer);
-}
 
 static int vsg_release_input_buffer(struct vsg_context *context,
 		struct vsg_buf_info *buf)
@@ -120,9 +116,10 @@
 	INIT_LIST_HEAD(&buf_info->node);
 
 	ktime_get_ts(&buf_info->time);
-	vsg_reset_timer(&context->threshold_timer, ns_to_ktime(
-				context->max_frame_interval));
-
+	if (work->work_delayed) {
+		buf_info->time = timespec_sub(buf_info->time,
+					context->delayed_frame_interval);
+	}
 	temp = NULL;
 	list_for_each_entry(temp, &context->busy_queue.node, node) {
 		if (mdp_buf_info_equals(&temp->mdp_buf_info,
@@ -233,6 +230,7 @@
 
 		INIT_WORK(&new_work->work, vsg_work_func);
 		new_work->context = context;
+		new_work->work_delayed = work->work_delayed;
 		queue_work(context->work_queue, &new_work->work);
 	}
 
@@ -245,25 +243,43 @@
 {
 	struct vsg_context *context = NULL;
 	struct vsg_work *task = NULL;
-
-	task = kzalloc(sizeof(*task), GFP_ATOMIC);
+	int64_t max_frame_interval = 0;
 	context = container_of(timer, struct vsg_context,
 			threshold_timer);
+
+	if (!context) {
+		WFD_MSG_ERR("Context not proper in %s", __func__);
+		goto threshold_err_no_context;
+	}
+	max_frame_interval = context->max_frame_interval;
+	if (list_empty(&context->free_queue.node) && !context->vsync_wait) {
+		context->vsync_wait = true;
+		max_frame_interval = context->max_frame_interval /
+					TICKS_PER_TIMEOUT;
+		goto restart_timer;
+	} else if (context->vsync_wait) {
+			max_frame_interval = context->max_frame_interval /
+						TICKS_PER_TIMEOUT;
+		context->vsync_wait = false;
+	}
+
+	task = kzalloc(sizeof(*task), GFP_ATOMIC);
 	if (!task) {
 		WFD_MSG_ERR("Out of memory in %s", __func__);
 		goto threshold_err_bad_param;
-	} else if (!context) {
-		WFD_MSG_ERR("Context not proper in %s", __func__);
-		goto threshold_err_no_context;
 	}
 
 	INIT_WORK(&task->work, vsg_timer_helper_func);
 	task->context = context;
+	task->work_delayed = false;
+	if (max_frame_interval < context->max_frame_interval)
+		task->work_delayed = true;
 
 	queue_work(context->work_queue, &task->work);
+restart_timer:
 threshold_err_bad_param:
 	hrtimer_forward_now(&context->threshold_timer, ns_to_ktime(
-				context->max_frame_interval));
+				max_frame_interval));
 	return HRTIMER_RESTART;
 threshold_err_no_context:
 	return HRTIMER_NORESTART;
@@ -298,6 +314,7 @@
 	context->last_buffer = NULL;
 	context->mode = DEFAULT_MODE;
 	context->state = VSG_STATE_NONE;
+	context->vsync_wait = false;
 	mutex_init(&context->mutex);
 
 	sd->dev_priv = context;
@@ -320,6 +337,7 @@
 static int vsg_start(struct v4l2_subdev *sd)
 {
 	struct vsg_context *context = NULL;
+	int rc = 0;
 
 	if (!sd) {
 		WFD_MSG_ERR("ERROR, invalid arguments into %s\n", __func__);
@@ -328,18 +346,24 @@
 
 	context = (struct vsg_context *)sd->dev_priv;
 
+	mutex_lock(&context->mutex);
 	if (context->state == VSG_STATE_STARTED) {
 		WFD_MSG_ERR("VSG not stopped, start not allowed\n");
-		return -EINPROGRESS;
+		rc = -EINPROGRESS;
+		goto err_bad_state;
 	} else if (context->state == VSG_STATE_ERROR) {
 		WFD_MSG_ERR("VSG in error state, not allowed to restart\n");
-		return -ENOTRECOVERABLE;
+		rc = -ENOTRECOVERABLE;
+		goto err_bad_state;
 	}
 
 	context->state = VSG_STATE_STARTED;
 	hrtimer_start(&context->threshold_timer, ns_to_ktime(context->
 			max_frame_interval), HRTIMER_MODE_REL);
-	return 0;
+
+err_bad_state:
+	mutex_unlock(&context->mutex);
+	return rc;
 }
 
 static int vsg_stop(struct v4l2_subdev *sd)
@@ -444,7 +468,7 @@
 			 * otherwise, diff between two consecutive frames might
 			 * be less than max_frame_interval (for just one sample)
 			 */
-			vsg_reset_timer(&context->threshold_timer,
+			hrtimer_forward_now(&context->threshold_timer,
 				ns_to_ktime(context->max_frame_interval));
 		}
 	}
@@ -568,7 +592,8 @@
 				context->max_frame_interval, interval);
 		context->max_frame_interval = interval;
 	}
-
+	context->delayed_frame_interval =
+		ns_to_timespec(context->frame_interval / TICKS_PER_TIMEOUT);
 	mutex_unlock(&context->mutex);
 	return 0;
 }
diff --git a/drivers/media/platform/msm/wfd/vsg-subdev.h b/drivers/media/platform/msm/wfd/vsg-subdev.h
index 3347e5b..bbaced1 100644
--- a/drivers/media/platform/msm/wfd/vsg-subdev.h
+++ b/drivers/media/platform/msm/wfd/vsg-subdev.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, 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
@@ -56,7 +56,7 @@
 };
 
 struct vsg_context {
-	struct vsg_buf_info	free_queue, busy_queue;
+	struct vsg_buf_info free_queue, busy_queue;
 	struct vsg_msg_ops vmops;
 	/* All time related values below in nanosecs */
 	int64_t frame_interval, max_frame_interval, frame_interval_variance;
@@ -66,11 +66,14 @@
 	struct vsg_buf_info *last_buffer;
 	int mode;
 	int state;
+	bool vsync_wait;
+	struct timespec delayed_frame_interval;
 };
 
 struct vsg_work {
 	struct vsg_context *context;
 	struct work_struct work;
+	bool work_delayed;
 };
 
 struct vsg_encode_work {
diff --git a/drivers/media/radio/radio-iris.c b/drivers/media/radio/radio-iris.c
index 5dde469..07d3fde 100644
--- a/drivers/media/radio/radio-iris.c
+++ b/drivers/media/radio/radio-iris.c
@@ -499,7 +499,7 @@
 	struct kfifo *data_b;
 	unsigned char evt = event;
 
-	if (radio == NULL) {
+	if (unlikely(radio == NULL)) {
 		FMDERR(":radio is null");
 		return;
 	}
@@ -511,9 +511,14 @@
 
 static int hci_send_frame(struct sk_buff *skb)
 {
-	struct radio_hci_dev *hdev = (struct radio_hci_dev *) skb->dev;
+	struct radio_hci_dev *hdev;
 
-	if (!hdev) {
+	if (unlikely(skb == NULL)) {
+		FMDERR("%s, socket buffer is null\n", __func__);
+		return -EINVAL;
+	}
+	hdev = (struct radio_hci_dev *) skb->dev;
+	if (unlikely(!hdev)) {
 		kfree_skb(skb);
 		return -ENODEV;
 	}
@@ -528,6 +533,11 @@
 {
 	struct radio_hci_dev *hdev = (struct radio_hci_dev *) arg;
 	struct sk_buff *skb;
+
+	if (unlikely(hdev == NULL)) {
+		FMDERR("%s, HCI Device is null\n", __func__);
+		return;
+	}
 	if (!(atomic_read(&hdev->cmd_cnt))
 		&& time_after(jiffies, hdev->cmd_last_tx + HZ)) {
 		FMDERR("%s command tx timeout", hdev->name);
@@ -555,6 +565,10 @@
 	struct radio_hci_dev *hdev = (struct radio_hci_dev *) arg;
 	struct sk_buff *skb;
 
+	if (unlikely(hdev == NULL)) {
+		FMDERR("%s, HCI Device is null\n", __func__);
+		return;
+	}
 	read_lock(&hci_task_lock);
 
 	skb = skb_dequeue(&hdev->rx_q);
@@ -618,8 +632,14 @@
 
 int radio_hci_recv_frame(struct sk_buff *skb)
 {
-	struct radio_hci_dev *hdev = (struct radio_hci_dev *) skb->dev;
-	if (!hdev) {
+	struct radio_hci_dev *hdev;
+
+	if (unlikely(skb == NULL)) {
+		FMDERR("%s, socket buffer is null\n", __func__);
+		return -EINVAL;
+	}
+	hdev = (struct radio_hci_dev *) skb->dev;
+	if (unlikely(!hdev)) {
 		FMDERR("%s hdev is null while receiving frame", hdev->name);
 		kfree_skb(skb);
 		return -ENXIO;
@@ -641,6 +661,10 @@
 	struct sk_buff *skb;
 	int ret = 0;
 
+	if (unlikely(hdev == NULL)) {
+		FMDERR("%s, hci device is null\n", __func__);
+		return -EINVAL;
+	}
 	skb = alloc_skb(len, GFP_ATOMIC);
 	if (!skb) {
 		FMDERR("%s no memory for command", hdev->name);
@@ -679,7 +703,7 @@
 	struct iris_device *radio = video_get_drvdata(video_get_dev());
 	__u16 opcode = 0;
 
-	if (radio == NULL) {
+	if (unlikely(radio == NULL)) {
 		FMDERR(":radio is null");
 		return -EINVAL;
 	}
@@ -746,6 +770,10 @@
 	struct hci_fm_recv_conf_req *recv_conf_req =
 		(struct hci_fm_recv_conf_req *) param;
 
+	if (recv_conf_req == NULL) {
+		FMDERR("%s, recv conf is null\n", __func__);
+		return -EINVAL;
+	}
 	opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
 		HCI_OCF_FM_SET_RECV_CONF_REQ);
 	return radio_hci_send_cmd(hdev, opcode, sizeof((*recv_conf_req)),
@@ -760,6 +788,11 @@
 	struct hci_fm_trans_conf_req_struct *trans_conf_req =
 		(struct hci_fm_trans_conf_req_struct *) param;
 
+	if (trans_conf_req == NULL) {
+		FMDERR("%s, tx conf is null\n", __func__);
+		return -EINVAL;
+	}
+
 	opcode = hci_opcode_pack(HCI_OGF_FM_TRANS_CTRL_CMD_REQ,
 		HCI_OCF_FM_SET_TRANS_CONF_REQ);
 	return radio_hci_send_cmd(hdev, opcode, sizeof((*trans_conf_req)),
@@ -783,6 +816,10 @@
 	struct hci_fm_mute_mode_req *mute_mode_req =
 		(struct hci_fm_mute_mode_req *) param;
 
+	if (mute_mode_req == NULL) {
+		FMDERR("%s, mute mode is null\n", __func__);
+		return -EINVAL;
+	}
 	opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
 		HCI_OCF_FM_SET_MUTE_MODE_REQ);
 	return radio_hci_send_cmd(hdev, opcode, sizeof((*mute_mode_req)),
@@ -797,6 +834,10 @@
 	struct hci_fm_tx_ps *tx_ps_req =
 		(struct hci_fm_tx_ps *) param;
 
+	if (tx_ps_req == NULL) {
+		FMDERR("%s, tx ps req is null\n", __func__);
+		return -EINVAL;
+	}
 	opcode = hci_opcode_pack(HCI_OGF_FM_TRANS_CTRL_CMD_REQ,
 		HCI_OCF_FM_RDS_PS_REQ);
 
@@ -811,6 +852,10 @@
 	struct hci_fm_tx_rt *tx_rt_req =
 		(struct hci_fm_tx_rt *) param;
 
+	if (tx_rt_req == NULL) {
+		FMDERR("%s, tx rt req is null\n", __func__);
+		return -EINVAL;
+	}
 	opcode = hci_opcode_pack(HCI_OGF_FM_TRANS_CTRL_CMD_REQ,
 		HCI_OCF_FM_RDS_RT_REQ);
 
@@ -824,6 +869,11 @@
 	__u16 opcode = 0;
 	struct hci_fm_stereo_mode_req *stereo_mode_req =
 		(struct hci_fm_stereo_mode_req *) param;
+
+	if (stereo_mode_req == NULL) {
+		FMDERR("%s, stere mode req is null\n", __func__);
+		return -EINVAL;
+	}
 	opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
 		HCI_OCF_FM_SET_STEREO_MODE_REQ);
 	return radio_hci_send_cmd(hdev, opcode, sizeof((*stereo_mode_req)),
@@ -913,6 +963,10 @@
 	struct hci_fm_search_station_req *srch_stations =
 		(struct hci_fm_search_station_req *) param;
 
+	if (srch_stations == NULL) {
+		FMDERR("%s, search station param is null\n", __func__);
+		return -EINVAL;
+	}
 	opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
 		HCI_OCF_FM_SEARCH_STATIONS);
 	return radio_hci_send_cmd(hdev, opcode, sizeof((*srch_stations)),
@@ -926,6 +980,10 @@
 	struct hci_fm_search_rds_station_req *srch_stations =
 		(struct hci_fm_search_rds_station_req *) param;
 
+	if (srch_stations == NULL) {
+		FMDERR("%s, rds stations param is null\n", __func__);
+		return -EINVAL;
+	}
 	opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
 		HCI_OCF_FM_SEARCH_RDS_STATIONS);
 	return radio_hci_send_cmd(hdev, opcode, sizeof((*srch_stations)),
@@ -939,6 +997,10 @@
 	struct hci_fm_search_station_list_req *srch_list =
 		(struct hci_fm_search_station_list_req *) param;
 
+	if (srch_list == NULL) {
+		FMDERR("%s, search list param is null\n", __func__);
+		return -EINVAL;
+	}
 	opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
 		HCI_OCF_FM_SEARCH_STATIONS_LIST);
 	return radio_hci_send_cmd(hdev, opcode, sizeof((*srch_list)),
@@ -963,6 +1025,10 @@
 	struct hci_fm_rds_grp_req *fm_grp_mask =
 		(struct hci_fm_rds_grp_req *)param;
 
+	if (fm_grp_mask == NULL) {
+		FMDERR("%s, grp mask param is null\n", __func__);
+		return -EINVAL;
+	}
 	opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
 		HCI_OCF_FM_RDS_GRP);
 	return radio_hci_send_cmd(hdev, opcode, sizeof(*fm_grp_mask),
@@ -1001,6 +1067,10 @@
 	struct hci_fm_def_data_rd_req *def_data_rd =
 		(struct hci_fm_def_data_rd_req *) param;
 
+	if (def_data_rd == NULL) {
+		FMDERR("%s, def data read param is null\n", __func__);
+		return -EINVAL;
+	}
 	opcode = hci_opcode_pack(HCI_OGF_FM_COMMON_CTRL_CMD_REQ,
 		HCI_OCF_FM_DEFAULT_DATA_READ);
 	return radio_hci_send_cmd(hdev, opcode, sizeof((*def_data_rd)),
@@ -1014,6 +1084,10 @@
 	struct hci_fm_def_data_wr_req *def_data_wr =
 		(struct hci_fm_def_data_wr_req *) param;
 
+	if (def_data_wr == NULL) {
+		FMDERR("%s, def data write param is null\n", __func__);
+		return -EINVAL;
+	}
 	opcode = hci_opcode_pack(HCI_OGF_FM_COMMON_CTRL_CMD_REQ,
 		HCI_OCF_FM_DEFAULT_DATA_WRITE);
 
@@ -1083,6 +1157,10 @@
 	__u16 opcode = 0;
 	struct hci_fm_riva_data *peek_data = (struct hci_fm_riva_data *)param;
 
+	if (peek_data == NULL) {
+		FMDERR("%s, peek data param is null\n", __func__);
+		return -EINVAL;
+	}
 	opcode = hci_opcode_pack(HCI_OGF_FM_DIAGNOSTIC_CMD_REQ,
 		HCI_OCF_FM_PEEK_DATA);
 	return radio_hci_send_cmd(hdev, opcode, sizeof((*peek_data)),
@@ -1094,6 +1172,10 @@
 	__u16 opcode = 0;
 	struct hci_fm_riva_poke *poke_data = (struct hci_fm_riva_poke *) param;
 
+	if (poke_data == NULL) {
+		FMDERR("%s, poke data param is null\n", __func__);
+		return -EINVAL;
+	}
 	opcode = hci_opcode_pack(HCI_OGF_FM_DIAGNOSTIC_CMD_REQ,
 		HCI_OCF_FM_POKE_DATA);
 	return radio_hci_send_cmd(hdev, opcode, sizeof((*poke_data)),
@@ -1106,6 +1188,10 @@
 	__u16 opcode = 0;
 	struct hci_fm_ssbi_peek *ssbi_peek = (struct hci_fm_ssbi_peek *) param;
 
+	if (ssbi_peek == NULL) {
+		FMDERR("%s, ssbi peek param is null\n", __func__);
+		return -EINVAL;
+	}
 	opcode = hci_opcode_pack(HCI_OGF_FM_DIAGNOSTIC_CMD_REQ,
 		HCI_OCF_FM_SSBI_PEEK_REG);
 	return radio_hci_send_cmd(hdev, opcode, sizeof((*ssbi_peek)),
@@ -1118,6 +1204,10 @@
 	__u16 opcode = 0;
 	struct hci_fm_ssbi_req *ssbi_poke = (struct hci_fm_ssbi_req *) param;
 
+	if (ssbi_poke == NULL) {
+		FMDERR("%s, ssbi poke param is null\n", __func__);
+		return -EINVAL;
+	}
 	opcode = hci_opcode_pack(HCI_OGF_FM_DIAGNOSTIC_CMD_REQ,
 		HCI_OCF_FM_SSBI_POKE_REG);
 	return radio_hci_send_cmd(hdev, opcode, sizeof((*ssbi_poke)),
@@ -1139,7 +1229,13 @@
 {
 	struct hci_fm_ch_det_threshold *ch_det_th =
 			 (struct hci_fm_ch_det_threshold *) param;
-	u16 opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
+	u16 opcode;
+
+	if (ch_det_th == NULL) {
+		FMDERR("%s, channel det thrshld is null\n", __func__);
+		return -EINVAL;
+	}
+	opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ,
 		HCI_OCF_FM_SET_CH_DET_THRESHOLD);
 	return radio_hci_send_cmd(hdev, opcode, sizeof((*ch_det_th)),
 		ch_det_th);
@@ -1183,9 +1279,13 @@
 			unsigned long param, __u32 timeout)
 {
 	int err = 0;
-
 	DECLARE_WAITQUEUE(wait, current);
 
+	if (unlikely(hdev == NULL)) {
+		FMDERR("%s, hci dev is null\n", __func__);
+		return -EINVAL;
+	}
+
 	mutex_lock(&iris_fm);
 	hdev->req_status = HCI_REQ_PEND;
 
@@ -1208,11 +1308,6 @@
 	case HCI_REQ_STATUS:
 		err = radio_hci_err(hdev->req_result);
 		break;
-
-	case HCI_REQ_CANCELED:
-		err = -hdev->req_result;
-		break;
-
 	default:
 		err = -ETIMEDOUT;
 		break;
@@ -1239,7 +1334,13 @@
 static inline int hci_conf_event_mask(__u8 *arg,
 		struct radio_hci_dev *hdev)
 {
-	u8 event_mask = *arg;
+	u8 event_mask;
+
+	if (arg == NULL) {
+		FMDERR("%s, arg is null\n", __func__);
+		return -EINVAL;
+	}
+	event_mask = *arg;
 	return  radio_hci_request(hdev, hci_fm_set_event_mask,
 				event_mask, RADIO_HCI_TIMEOUT);
 }
@@ -1270,8 +1371,13 @@
 static int hci_fm_tune_station(__u32 *arg, struct radio_hci_dev *hdev)
 {
 	int ret = 0;
-	__u32 tune_freq = *arg;
+	__u32 tune_freq;
 
+	if (arg == NULL) {
+		FMDERR("%s, arg is null\n", __func__);
+		return -EINVAL;
+	}
+	tune_freq = *arg;
 	ret = radio_hci_request(hdev, hci_fm_tune_station_req, tune_freq,
 		RADIO_HCI_TIMEOUT);
 
@@ -1305,8 +1411,13 @@
 static int hci_fm_set_antenna(__u8 *arg, struct radio_hci_dev *hdev)
 {
 	int ret = 0;
-	__u8 antenna = *arg;
+	__u8 antenna;
 
+	if (arg == NULL) {
+		FMDERR("%s, arg is null\n", __func__);
+		return -EINVAL;
+	}
+	antenna = *arg;
 	ret = radio_hci_request(hdev, hci_fm_set_antenna_req, antenna,
 		RADIO_HCI_TIMEOUT);
 
@@ -1317,8 +1428,13 @@
 	struct radio_hci_dev *hdev)
 {
 	int ret = 0;
-	__u8 sig_threshold = *arg;
+	__u8 sig_threshold;
 
+	if (arg == NULL) {
+		FMDERR("%s, arg is null\n", __func__);
+		return -EINVAL;
+	}
+	sig_threshold = *arg;
 	ret = radio_hci_request(hdev, hci_fm_set_sig_threshold_req,
 		sig_threshold, RADIO_HCI_TIMEOUT);
 
@@ -1377,8 +1493,13 @@
 static int hci_fm_rds_grps_process(__u32 *arg, struct radio_hci_dev *hdev)
 {
 	int ret = 0;
-	__u32 fm_grps_process = *arg;
+	__u32 fm_grps_process;
 
+	if (arg == NULL) {
+		FMDERR("%s, arg is null\n", __func__);
+		return -EINVAL;
+	}
+	fm_grps_process = *arg;
 	ret = radio_hci_request(hdev, hci_fm_rds_grp_process_req,
 		fm_grps_process, RADIO_HCI_TIMEOUT);
 
@@ -1410,8 +1531,13 @@
 int hci_fm_do_calibration(__u8 *arg, struct radio_hci_dev *hdev)
 {
 	int ret = 0;
-	__u8 mode = *arg;
+	__u8 mode;
 
+	if (arg == NULL) {
+		FMDERR("%s, arg is null\n", __func__);
+		return -EINVAL;
+	}
+	mode = *arg;
 	ret = radio_hci_request(hdev, hci_fm_do_calibration_req, mode,
 		RADIO_HCI_TIMEOUT);
 
@@ -1421,7 +1547,13 @@
 static int hci_read_grp_counters(__u8 *arg, struct radio_hci_dev *hdev)
 {
 	int ret = 0;
-	__u8 reset_counters = *arg;
+	__u8 reset_counters;
+
+	if (arg == NULL) {
+		FMDERR("%s, arg is null\n", __func__);
+		return -EINVAL;
+	}
+	reset_counters = *arg;
 	ret = radio_hci_request(hdev, hci_read_grp_counters_req,
 		reset_counters, RADIO_HCI_TIMEOUT);
 
@@ -1431,7 +1563,14 @@
 static int hci_set_notch_filter(__u8 *arg, struct radio_hci_dev *hdev)
 {
 	int ret = 0;
-	__u8 notch_filter = *arg;
+	__u8 notch_filter;
+
+	if (arg == NULL) {
+		FMDERR("%s, arg is null\n", __func__);
+		return -EINVAL;
+	}
+
+	notch_filter = *arg;
 	ret = radio_hci_request(hdev, hci_set_notch_filter_req,
 		notch_filter, RADIO_HCI_TIMEOUT);
 
@@ -1505,8 +1644,8 @@
 
 	opcode = hci_opcode_pack(HCI_OGF_FM_COMMON_CTRL_CMD_REQ,
 		HCI_OCF_FM_SET_CALIBRATION);
-	return radio_hci_send_cmd(hdev, opcode, sizeof(*cal_req),
-		cal_req);
+	return radio_hci_send_cmd(hdev, opcode,
+		sizeof(hci_fm_set_cal_req_proc), cal_req);
 }
 
 static int hci_fm_do_cal_req(struct radio_hci_dev *hdev,
@@ -1623,6 +1762,11 @@
 
 static void radio_hci_req_complete(struct radio_hci_dev *hdev, int result)
 {
+
+	if (unlikely(hdev == NULL)) {
+		FMDERR("%s, hci device is null\n", __func__);
+		return;
+	}
 	hdev->req_result = result;
 	hdev->req_status = HCI_REQ_DONE;
 	wake_up_interruptible(&hdev->req_wait_q);
@@ -1630,6 +1774,10 @@
 
 static void radio_hci_status_complete(struct radio_hci_dev *hdev, int result)
 {
+	if (unlikely(hdev == NULL)) {
+		FMDERR("%s, hci device is null\n", __func__);
+		return;
+	}
 	hdev->req_result = result;
 	hdev->req_status = HCI_REQ_STATUS;
 	wake_up_interruptible(&hdev->req_wait_q);
@@ -1637,10 +1785,13 @@
 
 static void hci_cc_rsp(struct radio_hci_dev *hdev, struct sk_buff *skb)
 {
-	__u8 status = *((__u8 *) skb->data);
+	__u8 status;
 
-	if (status)
+	if (unlikely(skb == NULL)) {
+		FMDERR("%s, socket buffer is null\n", __func__);
 		return;
+	}
+	status = *((__u8 *) skb->data);
 
 	radio_hci_req_complete(hdev, status);
 }
@@ -1648,14 +1799,20 @@
 static void hci_cc_fm_disable_rsp(struct radio_hci_dev *hdev,
 	struct sk_buff *skb)
 {
-	__u8 status = *((__u8 *) skb->data);
+	__u8 status;
 	struct iris_device *radio = video_get_drvdata(video_get_dev());
 
-	if (radio == NULL) {
-                FMDERR(":radio is null");
-                return;
-        }
+	if (unlikely(radio == NULL)) {
+		FMDERR(":radio is null");
+		return;
+	}
 
+	if (unlikely(skb == NULL)) {
+		FMDERR("%s, socket buffer is null\n", __func__);
+		return;
+	}
+
+	status = *((__u8 *) skb->data);
 	if ((radio->mode == FM_TURNING_OFF) && (status == 0)) {
 		iris_q_event(radio, IRIS_EVT_RADIO_DISABLED);
 		radio_hci_req_complete(hdev, status);
@@ -1665,66 +1822,76 @@
 	} else if ((radio->mode == FM_RECV) || (radio->mode == FM_TRANS)) {
 		iris_q_event(radio, IRIS_EVT_RADIO_DISABLED);
 		radio->mode = FM_OFF;
+	} else if ((radio->mode == FM_TURNING_OFF) && (status != 0)) {
+		radio_hci_req_complete(hdev, status);
 	}
 }
 
 static void hci_cc_conf_rsp(struct radio_hci_dev *hdev, struct sk_buff *skb)
 {
-	struct hci_fm_conf_rsp  *rsp = (void *)skb->data;
+	struct hci_fm_conf_rsp  *rsp;
 	struct iris_device *radio = video_get_drvdata(video_get_dev());
 
-	if (radio == NULL) {
+	if (unlikely(radio == NULL)) {
 		FMDERR(":radio is null");
 		return;
 	}
-	if (rsp->status)
+	if (unlikely(skb == NULL)) {
+		FMDERR("%s, socket buffer is null\n", __func__);
 		return;
-
-	radio->recv_conf = rsp->recv_conf_rsp;
+	}
+	rsp = (struct hci_fm_conf_rsp *)skb->data;
+	if (!rsp->status)
+		radio->recv_conf = rsp->recv_conf_rsp;
 	radio_hci_req_complete(hdev, rsp->status);
 }
 
 static void hci_cc_fm_trans_get_conf_rsp(struct radio_hci_dev *hdev,
 		struct sk_buff *skb)
 {
-	struct hci_fm_get_trans_conf_rsp  *rsp = (void *)skb->data;
+	struct hci_fm_get_trans_conf_rsp  *rsp;
 	struct iris_device *radio = video_get_drvdata(video_get_dev());
 
-	if (radio == NULL) {
+	if (unlikely(radio == NULL)) {
 		FMDERR(":radio is null");
 		return;
 	}
-
-	if (rsp->status)
+	if (unlikely(skb == NULL)) {
+		FMDERR("%s, socket buffer is null\n", __func__);
 		return;
-	memcpy((void *)&radio->trans_conf,  (void*)&rsp->trans_conf_rsp,
+	}
+
+	rsp = (struct hci_fm_get_trans_conf_rsp *)skb->data;
+	if (!rsp->status)
+		memcpy((void *)&radio->trans_conf,
+			(void *)&rsp->trans_conf_rsp,
 			sizeof(rsp->trans_conf_rsp));
+
 	radio_hci_req_complete(hdev, rsp->status);
 }
 
 static void hci_cc_fm_enable_rsp(struct radio_hci_dev *hdev,
 	struct sk_buff *skb)
 {
-	struct hci_fm_conf_rsp  *rsp = (void *)skb->data;
+	struct hci_fm_conf_rsp  *rsp;
 	struct iris_device *radio = video_get_drvdata(video_get_dev());
 
-	if (radio == NULL) {
+	if (unlikely(radio == NULL)) {
 		FMDERR(":radio is null");
 		return;
 	}
 
+	if (unlikely(skb == NULL)) {
+		FMDERR("%s, socket buffer is null\n", __func__);
+		return;
+	}
+
+	rsp = (struct hci_fm_conf_rsp *)skb->data;
 	if (rsp->status) {
 		radio_hci_req_complete(hdev, rsp->status);
 		return;
 	}
 
-	if (radio->mode == FM_RECV_TURNING_ON) {
-		radio->mode = FM_RECV;
-		iris_q_event(radio, IRIS_EVT_RADIO_READY);
-	} else if (radio->mode == FM_TRANS_TURNING_ON) {
-		radio->mode = FM_TRANS;
-		iris_q_event(radio, IRIS_EVT_RADIO_READY);
-	}
 	radio_hci_req_complete(hdev, rsp->status);
 }
 
@@ -1732,18 +1899,21 @@
 static void hci_cc_fm_trans_set_conf_rsp(struct radio_hci_dev *hdev,
 	struct sk_buff *skb)
 {
-	struct hci_fm_conf_rsp  *rsp = (void *)skb->data;
+	struct hci_fm_conf_rsp  *rsp;
 	struct iris_device *radio = video_get_drvdata(video_get_dev());
 
-	if (radio == NULL) {
+	if (unlikely(radio == NULL)) {
 		FMDERR(":radio is null");
 		return;
 	}
 
-	if (rsp->status)
+	if (unlikely(skb == NULL)) {
+		FMDERR("%s, socket buffer is null\n", __func__);
 		return;
-
-	iris_q_event(radio, HCI_EV_CMD_COMPLETE);
+	}
+	rsp = (struct hci_fm_conf_rsp  *)skb->data;
+	if (!rsp->status)
+		iris_q_event(radio, HCI_EV_CMD_COMPLETE);
 
 	radio_hci_req_complete(hdev, rsp->status);
 }
@@ -1752,31 +1922,41 @@
 static void hci_cc_sig_threshold_rsp(struct radio_hci_dev *hdev,
 		struct sk_buff *skb)
 {
-	struct hci_fm_sig_threshold_rsp  *rsp = (void *)skb->data;
+	struct hci_fm_sig_threshold_rsp  *rsp;
 	struct iris_device *radio = video_get_drvdata(video_get_dev());
 
-	if (radio == NULL) {
+	if (unlikely(radio == NULL)) {
 		FMDERR(":radio is null");
 		return;
 	}
-
-	if (rsp->status)
+	if (unlikely(skb == NULL)) {
+		FMDERR("%s, socket buffer is null\n", __func__);
 		return;
+	}
 
-	memcpy(&radio->sig_th, rsp, sizeof(struct hci_fm_sig_threshold_rsp));
+	rsp = (struct hci_fm_sig_threshold_rsp  *)skb->data;
+	if (!rsp->status)
+		memcpy(&radio->sig_th, rsp,
+			sizeof(struct hci_fm_sig_threshold_rsp));
+
 	radio_hci_req_complete(hdev, rsp->status);
 }
 
 static void hci_cc_station_rsp(struct radio_hci_dev *hdev, struct sk_buff *skb)
 {
 	struct iris_device *radio = video_get_drvdata(video_get_dev());
-	struct hci_fm_station_rsp *rsp = (void *)skb->data;
+	struct hci_fm_station_rsp *rsp;
 
-	if (radio == NULL) {
+	if (unlikely(radio == NULL)) {
 		FMDERR(":radio is null");
 		return;
 	}
+	if (unlikely(skb == NULL)) {
+		FMDERR("%s, socket buffer is null\n", __func__);
+		return;
+	}
 
+	rsp = (struct hci_fm_station_rsp *)skb->data;
 	radio->fm_st_rsp = *(rsp);
 
 	/* Tune is always succesful */
@@ -1785,31 +1965,41 @@
 
 static void hci_cc_prg_srv_rsp(struct radio_hci_dev *hdev, struct sk_buff *skb)
 {
-	struct hci_fm_prgm_srv_rsp  *rsp = (void *)skb->data;
+	struct hci_fm_prgm_srv_rsp  *rsp;
 
-	if (rsp->status)
+	if (unlikely(skb == NULL)) {
+		FMDERR("%s, socket buffer is null\n", __func__);
 		return;
+	}
+
+	rsp = (struct hci_fm_prgm_srv_rsp  *)skb->data;
 
 	radio_hci_req_complete(hdev, rsp->status);
 }
 
 static void hci_cc_rd_txt_rsp(struct radio_hci_dev *hdev, struct sk_buff *skb)
 {
-	struct hci_fm_radio_txt_rsp  *rsp = (void *)skb->data;
+	struct hci_fm_radio_txt_rsp  *rsp;
 
-	if (rsp->status)
+	if (unlikely(skb == NULL)) {
+		FMDERR("%s, socket buffer is null\n", __func__);
 		return;
+	}
 
+	rsp = (struct hci_fm_radio_txt_rsp  *)skb->data;
 	radio_hci_req_complete(hdev, rsp->status);
 }
 
 static void hci_cc_af_list_rsp(struct radio_hci_dev *hdev, struct sk_buff *skb)
 {
-	struct hci_fm_af_list_rsp  *rsp = (void *)skb->data;
+	struct hci_fm_af_list_rsp  *rsp;
 
-	if (rsp->status)
+	if (unlikely(skb == NULL)) {
+		FMDERR("%s, socket buffer is null\n", __func__);
 		return;
+	}
 
+	rsp = (struct hci_fm_af_list_rsp  *)skb->data;
 	radio_hci_req_complete(hdev, rsp->status);
 }
 
@@ -1817,20 +2007,25 @@
 	struct sk_buff *skb)
 {
 	struct v4l2_capability *v4l_cap;
-	struct hci_fm_feature_list_rsp  *rsp = (void *)skb->data;
+	struct hci_fm_feature_list_rsp  *rsp;
 	struct iris_device *radio = video_get_drvdata(video_get_dev());
 
-	if (radio == NULL) {
+	if (unlikely(radio == NULL)) {
 		FMDERR(":radio is null");
 		return;
 	}
 
+	if (unlikely(skb == NULL)) {
+		FMDERR("%s, socket buffer is null\n", __func__);
+		return;
+	}
+
+	rsp = (struct hci_fm_feature_list_rsp  *)skb->data;
 	v4l_cap = &radio->g_cap;
 
-	if (rsp->status)
-		return;
-	v4l_cap->capabilities = (rsp->feature_mask & 0x000002) |
-		(rsp->feature_mask & 0x000001);
+	if (!rsp->status)
+		v4l_cap->capabilities = (rsp->feature_mask & 0x000002) |
+						(rsp->feature_mask & 0x000001);
 
 	radio_hci_req_complete(hdev, rsp->status);
 }
@@ -1839,17 +2034,20 @@
 	struct sk_buff *skb)
 {
 	struct iris_device *radio = video_get_drvdata(video_get_dev());
-	struct hci_fm_dbg_param_rsp *rsp = (void *)skb->data;
+	struct hci_fm_dbg_param_rsp *rsp;
 
-	if (radio == NULL) {
+	if (unlikely(radio == NULL)) {
 		FMDERR(":radio is null");
 		return;
 	}
 
-	radio->st_dbg_param = *(rsp);
-	if (radio->st_dbg_param.status)
+	if (unlikely(skb == NULL)) {
+		FMDERR("%s, socket buffer is null\n", __func__);
 		return;
+	}
 
+	rsp = (struct hci_fm_dbg_param_rsp *)skb->data;
+	radio->st_dbg_param = *(rsp);
 	radio_hci_req_complete(hdev, radio->st_dbg_param.status);
 }
 
@@ -1858,7 +2056,7 @@
 {
 	struct kfifo *data_b;
 
-	if (radio == NULL) {
+	if (unlikely(radio == NULL)) {
 		FMDERR(":radio is null");
 		return;
 	}
@@ -1871,46 +2069,55 @@
 		struct sk_buff *skb)
 {
 	struct iris_device *radio = video_get_drvdata(video_get_dev());
-	__u8 status = *((__u8 *) skb->data);
+	__u8 status;
 	int len;
 	char *data;
 
-	if (status)
-		return;
-	len = skb->data[RIVA_PEEK_LEN_OFSET] + RIVA_PEEK_PARAM;
-	data = kmalloc(len, GFP_ATOMIC);
-
-	if (!data) {
-		FMDERR("Memory allocation failed");
+	if (unlikely(skb == NULL)) {
+		FMDERR("%s, socket buffer is null\n", __func__);
 		return;
 	}
+	status = *((__u8 *) skb->data);
+	if (!status) {
+		len = skb->data[RIVA_PEEK_LEN_OFSET] + RIVA_PEEK_PARAM;
+		data = kmalloc(len, GFP_ATOMIC);
 
-	memcpy(data, &skb->data[PEEK_DATA_OFSET], len);
-	iris_q_evt_data(radio, data, len, IRIS_BUF_PEEK);
+		if (data != NULL) {
+			memcpy(data, &skb->data[PEEK_DATA_OFSET], len);
+			iris_q_evt_data(radio, data, len, IRIS_BUF_PEEK);
+			kfree(data);
+		} else {
+			FMDERR("Memory allocation failed");
+		}
+	}
+
 	radio_hci_req_complete(hdev, status);
-	kfree(data);
-
 }
 
 static void hci_cc_riva_read_default_rsp(struct radio_hci_dev *hdev,
 		struct sk_buff *skb)
 {
 	struct iris_device *radio = video_get_drvdata(video_get_dev());
-	__u8 status = *((__u8 *) skb->data);
+	__u8 status;
 	__u8 len;
 
-        if (radio == NULL) {
-                FMDERR(":radio is null");
-                return;
-        }
-
-	if (status)
+	if (unlikely(radio == NULL)) {
+		FMDERR(":radio is null");
 		return;
-	len = skb->data[1];
-
-	memset(&radio->default_data, 0 , sizeof(struct hci_fm_data_rd_rsp));
-	memcpy(&radio->default_data, &skb->data[0], len+2);
-	iris_q_evt_data(radio, &skb->data[0], len+2, IRIS_BUF_RD_DEFAULT);
+	}
+	if (unlikely(skb == NULL)) {
+		FMDERR("%s, socket buffer is null\n", __func__);
+		return;
+	}
+	status = *((__u8 *) skb->data);
+	if (!status) {
+		len = skb->data[1];
+		memset(&radio->default_data, 0,
+			sizeof(struct hci_fm_data_rd_rsp));
+		memcpy(&radio->default_data, &skb->data[0], len+2);
+		iris_q_evt_data(radio, &skb->data[0], len+2,
+				IRIS_BUF_RD_DEFAULT);
+	}
 	radio_hci_req_complete(hdev, status);
 }
 
@@ -1918,41 +2125,53 @@
 		struct sk_buff *skb)
 {
 	struct iris_device *radio = video_get_drvdata(video_get_dev());
-	__u8 status = *((__u8 *) skb->data);
+	__u8 status;
 	char *data;
 
-	if (status)
-		return;
-	data = kmalloc(SSBI_PEEK_LEN, GFP_ATOMIC);
-	if (!data) {
-		FMDERR("Memory allocation failed");
+	if (unlikely(skb == NULL)) {
+		FMDERR("%s, socket buffer is null\n", __func__);
 		return;
 	}
+	status = *((__u8 *) skb->data);
+	if (!status) {
+		data = kmalloc(SSBI_PEEK_LEN, GFP_ATOMIC);
+		if (data != NULL) {
+			data[0] = skb->data[PEEK_DATA_OFSET];
+			iris_q_evt_data(radio, data, SSBI_PEEK_LEN,
+					IRIS_BUF_SSBI_PEEK);
+			kfree(data);
+		} else {
+			FMDERR("Memory allocation failed");
+		}
+	}
 
-	data[0] = skb->data[PEEK_DATA_OFSET];
-	iris_q_evt_data(radio, data, SSBI_PEEK_LEN, IRIS_BUF_SSBI_PEEK);
 	radio_hci_req_complete(hdev, status);
-	kfree(data);
 }
 
 static void hci_cc_rds_grp_cntrs_rsp(struct radio_hci_dev *hdev,
 		struct sk_buff *skb)
 {
 	struct iris_device *radio = video_get_drvdata(video_get_dev());
-	__u8 status = *((__u8 *) skb->data);
+	__u8 status;
 	char *data;
-	if (status)
-		return;
-	data = kmalloc(RDS_GRP_CNTR_LEN, GFP_ATOMIC);
-	if (!data) {
-		FMDERR("memory allocation failed");
+
+	if (unlikely(skb == NULL)) {
+		FMDERR("%s, socket buffer is null\n", __func__);
 		return;
 	}
-	memcpy(data, &skb->data[1], RDS_GRP_CNTR_LEN);
-	iris_q_evt_data(radio, data, RDS_GRP_CNTR_LEN, IRIS_BUF_RDS_CNTRS);
+	status = *((__u8 *) skb->data);
+	if (!status) {
+		data = kmalloc(RDS_GRP_CNTR_LEN, GFP_ATOMIC);
+		if (data != NULL) {
+			memcpy(data, &skb->data[1], RDS_GRP_CNTR_LEN);
+			iris_q_evt_data(radio, data, RDS_GRP_CNTR_LEN,
+						IRIS_BUF_RDS_CNTRS);
+			kfree(data);
+		} else {
+			FMDERR("memory allocation failed");
+		}
+	}
 	radio_hci_req_complete(hdev, status);
-	kfree(data);
-
 }
 
 static void hci_cc_do_calibration_rsp(struct radio_hci_dev *hdev,
@@ -1960,22 +2179,23 @@
 {
 	struct iris_device *radio = video_get_drvdata(video_get_dev());
 	static struct hci_cc_do_calibration_rsp rsp ;
+
+	if (unlikely(skb == NULL)) {
+		FMDERR("%s, socket buffer is null\n", __func__);
+		return;
+	}
+
 	rsp.status = skb->data[0];
 	rsp.mode = skb->data[CALIB_MODE_OFSET];
 
-	if (rsp.status) {
-		FMDERR("status = %d", rsp.status);
-		return;
-	}
-	if (rsp.mode == PROCS_CALIB_MODE) {
-		memcpy(&rsp.data[0], &skb->data[CALIB_DATA_OFSET],
+	if (!rsp.status) {
+		if (rsp.mode == PROCS_CALIB_MODE) {
+			memcpy(&rsp.data[0], &skb->data[CALIB_DATA_OFSET],
 				PROCS_CALIB_SIZE);
-	iris_q_evt_data(radio, rsp.data, PROCS_CALIB_SIZE,
+			iris_q_evt_data(radio, rsp.data, PROCS_CALIB_SIZE,
 					IRIS_BUF_CAL_DATA);
-	} else {
-		return;
+		}
 	}
-
 	radio_hci_req_complete(hdev, rsp.status);
 }
 
@@ -1983,27 +2203,37 @@
 		struct sk_buff *skb)
 {
 	struct iris_device *radio = video_get_drvdata(video_get_dev());
-	u8  status = skb->data[0];
+	u8  status;
 
-	if (radio == NULL) {
+	if (unlikely(radio == NULL)) {
 		FMDERR(":radio is null");
 		return;
 	}
-	if (status) {
-		FMDERR("status = %d", status);
+	if (unlikely(skb == NULL)) {
+		FMDERR("%s, socket buffer is null\n", __func__);
 		return;
 	}
-	memcpy(&radio->ch_det_threshold, &skb->data[1],
-		sizeof(struct hci_fm_ch_det_threshold));
+	status = skb->data[0];
+	if (!status)
+		memcpy(&radio->ch_det_threshold, &skb->data[1],
+			sizeof(struct hci_fm_ch_det_threshold));
+
 	radio_hci_req_complete(hdev, status);
 }
 
 static inline void hci_cmd_complete_event(struct radio_hci_dev *hdev,
 		struct sk_buff *skb)
 {
-	struct hci_ev_cmd_complete *cmd_compl_ev = (void *) skb->data;
+	struct hci_ev_cmd_complete *cmd_compl_ev;
 	__u16 opcode;
 
+
+	if (unlikely(skb == NULL)) {
+		FMDERR("%s, socket buffer is null\n", __func__);
+		return;
+	}
+
+	cmd_compl_ev = (struct hci_ev_cmd_complete *)skb->data;
 	skb_pull(skb, sizeof(*cmd_compl_ev));
 
 	opcode = __le16_to_cpu(cmd_compl_ev->cmd_opcode);
@@ -2122,7 +2352,7 @@
 	int i;
 	struct iris_device *radio = video_get_drvdata(video_get_dev());
 
-	if (radio == NULL) {
+	if (unlikely(radio == NULL)) {
 		FMDERR(":radio is null");
 		return;
 	}
@@ -2154,6 +2384,7 @@
 		struct sk_buff *skb)
 {
 	struct iris_device *radio = video_get_drvdata(video_get_dev());
+	radio->search_on = 0;
 	iris_q_event(radio, IRIS_EVT_SEEK_COMPLETE);
 }
 
@@ -2168,10 +2399,15 @@
 	int abs_freq;
 	int len;
 
-	if (radio == NULL) {
+	if (unlikely(radio == NULL)) {
 		FMDERR(":radio is null");
 		return;
 	}
+
+	if (unlikely(skb == NULL)) {
+		FMDERR("%s, socket buffer is null\n", __func__);
+		return;
+	}
 	ev = kmalloc(sizeof(*ev), GFP_ATOMIC);
 	if (!ev) {
 		FMDERR("Memory allocation failed");
@@ -2210,7 +2446,13 @@
 		struct sk_buff *skb)
 {
 	struct iris_device *radio = video_get_drvdata(video_get_dev());
-	__u8 st_status = *((__u8 *) skb->data);
+	__u8 st_status;
+
+	if (unlikely(skb == NULL)) {
+		FMDERR("%s, socket buffer is null\n", __func__);
+		return;
+	}
+	st_status = *((__u8 *) skb->data);
 	if (st_status)
 		iris_q_event(radio, IRIS_EVT_STEREO);
 	else
@@ -2230,10 +2472,16 @@
 	radio = video_get_drvdata(video_get_dev());
 	index = RDSGRP_DATA_OFFSET;
 
-	if (radio == NULL) {
+	if (unlikely(radio == NULL)) {
 		FMDERR(":radio is null");
 		return;
 	}
+
+	if (unlikely(skb == NULL)) {
+		FMDERR("%s, socket buffer is null\n", __func__);
+		return;
+	}
+
 	for (blocknum = 0; blocknum < RDS_BLOCKS_NUM; blocknum++) {
 		temp.rdsBlk[blocknum].rdsLsb =
 			(skb->data[index]);
@@ -2304,6 +2552,10 @@
 	unsigned short int info_byte = 0;
 	unsigned short int byte_pair_index;
 
+	if (rds_buf == NULL) {
+		FMDERR("%s, rds buffer is null\n", __func__);
+		return;
+	}
 	byte_pair_index = AGT(rds_buf->rdsBlk[1].rdsLsb);
 	if (byte_pair_index == 0) {
 		c_byt_pair_index = 0;
@@ -2486,6 +2738,10 @@
 	int len = 0;
 	char *data;
 
+	if (unlikely(skb == NULL)) {
+		FMDERR("%s, socket buffer is null\n", __func__);
+		return;
+	}
 	iris_q_event(radio, IRIS_EVT_NEW_RT_RDS);
 
 	while ((skb->data[len+RDS_OFFSET] != 0x0d) && (len < MAX_RT_LENGTH))
@@ -2516,6 +2772,10 @@
 	struct iris_device *radio = video_get_drvdata(video_get_dev());
 	struct hci_ev_af_list ev;
 
+	if (unlikely(skb == NULL)) {
+		FMDERR("%s, socket buffer is null\n", __func__);
+		return;
+	}
 	ev.tune_freq = *((int *) &skb->data[0]);
 	ev.pi_code = *((__le16 *) &skb->data[PI_CODE_OFFSET]);
 	ev.af_size = skb->data[AF_SIZE_OFFSET];
@@ -2534,7 +2794,14 @@
 	struct sk_buff *skb)
 {
 	struct iris_device *radio = video_get_drvdata(video_get_dev());
-	__u8 rds_status = skb->data[0];
+	__u8 rds_status;
+
+	if (unlikely(skb == NULL)) {
+		FMDERR("%s, socket buffer is null\n", __func__);
+		return;
+	}
+
+	rds_status = skb->data[0];
 
 	if (rds_status)
 		iris_q_event(radio, IRIS_EVT_RDS_AVAIL);
@@ -2546,7 +2813,13 @@
 	struct sk_buff *skb)
 {
 	struct iris_device *radio = video_get_drvdata(video_get_dev());
-	u8 serv_avble = skb->data[0];
+	u8 serv_avble;
+
+	if (unlikely(skb == NULL)) {
+		FMDERR("%s, socket buffer is null\n", __func__);
+		return;
+	}
+	serv_avble = skb->data[0];
 	if (serv_avble)
 		iris_q_event(radio, IRIS_EVT_ABOVE_TH);
 	else
@@ -2641,13 +2914,15 @@
 {
 	int retval = 0;
 	enum search_t srch;
+	int saved_val;
 
-	if (radio == NULL) {
+	if (unlikely(radio == NULL)) {
 		FMDERR(":radio is null");
 		return -EINVAL;
 	}
 
 	srch = radio->g_search_mode & SRCH_MODE;
+	saved_val = radio->search_on;
 	radio->search_on = on;
 	if (on) {
 		switch (srch) {
@@ -2682,6 +2957,8 @@
 		retval = hci_cmd(HCI_FM_CANCEL_SEARCH_CMD, radio->fm_hdev);
 	}
 
+	if (retval < 0)
+		radio->search_on = saved_val;
 	return retval;
 }
 
@@ -2691,7 +2968,7 @@
 	int rds_grps_proc = 0x00;
 	int retval = 0;
 
-	if (radio == NULL) {
+	if (unlikely(radio == NULL)) {
 		FMDERR(":radio is null");
 		return -EINVAL;
 	}
@@ -2734,18 +3011,22 @@
 static int iris_recv_set_region(struct iris_device *radio, int req_region)
 {
 	int retval;
+	int saved_val;
 
-	if (radio == NULL) {
+	if (unlikely(radio == NULL)) {
 		FMDERR(":radio is null");
 		return -EINVAL;
 	}
-
+	saved_val = radio->region;
 	radio->region = req_region;
 
 	retval = hci_set_fm_recv_conf(
 			&radio->recv_conf,
 			radio->fm_hdev);
 
+	if (retval < 0)
+		radio->region = saved_val;
+
 	return retval;
 }
 
@@ -2753,16 +3034,22 @@
 static int iris_trans_set_region(struct iris_device *radio, int req_region)
 {
 	int retval;
+	int saved_val;
 
-	if (radio == NULL) {
+	if (unlikely(radio == NULL)) {
 		FMDERR(":radio is null");
 		return -EINVAL;
 	}
+
+	saved_val = radio->region;
 	radio->region = req_region;
 
 	retval = hci_set_fm_trans_conf(
 			&radio->trans_conf,
 				radio->fm_hdev);
+
+	if (retval < 0)
+		radio->region = saved_val;
 	return retval;
 }
 
@@ -2772,7 +3059,7 @@
 
 	int retval;
 
-	if (radio == NULL) {
+	if (unlikely(radio == NULL)) {
 		FMDERR(":radio is null");
 		return -EINVAL;
 	}
@@ -2789,6 +3076,10 @@
 	unsigned char i;
 	int retval = -EINVAL;
 
+	if (unlikely(qc == NULL)) {
+		FMDERR("%s, query ctrl is null\n", __func__);
+		return retval;
+	}
 	for (i = 0; i < ARRAY_SIZE(iris_v4l2_queryctrl); i++) {
 		if (qc->id && qc->id == iris_v4l2_queryctrl[i].id) {
 			memcpy(qc, &(iris_v4l2_queryctrl[i]), sizeof(*qc));
@@ -2805,7 +3096,7 @@
 	char cal_mode = 0x00;
 	int retval = 0x00;
 
-	if (radio == NULL) {
+	if (unlikely(radio == NULL)) {
 		FMDERR(":radio is null");
 		return -EINVAL;
 	}
@@ -2844,28 +3135,46 @@
 	struct hci_fm_def_data_rd_req rd;
 	int lsb, msb;
 
-	if (radio == NULL) {
+	if (unlikely(radio == NULL)) {
 		FMDERR(":radio is null");
-		return -EINVAL;
+		retval = -EINVAL;
+		goto END;
 	}
 
+	if (unlikely(ctrl == NULL)) {
+		FMDERR("%s, v4l2 ctrl is null\n", __func__);
+		retval = -EINVAL;
+		goto END;
+	}
 	switch (ctrl->id) {
 	case V4L2_CID_AUDIO_VOLUME:
 		break;
 	case V4L2_CID_AUDIO_MUTE:
-		ctrl->value = radio->mute_mode.hard_mute;
+		if (is_valid_hard_mute(radio->mute_mode.hard_mute))
+			ctrl->value = radio->mute_mode.hard_mute;
+		else
+			retval = -EINVAL;
 		break;
 	case V4L2_CID_PRIVATE_IRIS_SRCHMODE:
-		ctrl->value = radio->g_search_mode;
+		if (is_valid_srch_mode(radio->g_search_mode))
+			ctrl->value = radio->g_search_mode;
+		else
+			retval = -EINVAL;
 		break;
 	case V4L2_CID_PRIVATE_IRIS_SCANDWELL:
-		ctrl->value = radio->g_scan_time;
+		if (is_valid_scan_dwell_prd(radio->g_scan_time))
+			ctrl->value = radio->g_scan_time;
+		else
+			retval = -EINVAL;
 		break;
 	case V4L2_CID_PRIVATE_IRIS_SRCHON:
 		ctrl->value = radio->search_on;
 		break;
 	case V4L2_CID_PRIVATE_IRIS_STATE:
-		ctrl->value = radio->mode;
+		if (is_valid_fm_state(radio->mode))
+			ctrl->value = radio->mode;
+		else
+			retval = -EINVAL;
 		break;
 	case V4L2_CID_PRIVATE_IRIS_IOVERC:
 		retval = hci_cmd(HCI_FM_STATION_DBG_PARAM_CMD, radio->fm_hdev);
@@ -2875,68 +3184,115 @@
 		break;
 	case V4L2_CID_PRIVATE_IRIS_INTDET:
 		retval = hci_cmd(HCI_FM_STATION_DBG_PARAM_CMD, radio->fm_hdev);
-		if (retval < 0)
-			return retval;
-		ctrl->value = radio->st_dbg_param.in_det_out;
+		if (retval == 0)
+			ctrl->value = radio->st_dbg_param.in_det_out;
+		else
+			retval = -EINVAL;
 		break;
 	case V4L2_CID_PRIVATE_IRIS_REGION:
 		ctrl->value = radio->region;
 		break;
 	case V4L2_CID_PRIVATE_IRIS_SIGNAL_TH:
 		retval = hci_cmd(HCI_FM_GET_SIGNAL_TH_CMD, radio->fm_hdev);
-		if (retval < 0) {
-			FMDERR("Error in get signal threshold %d\n", retval);
-			return retval;
-		}
-		ctrl->value = radio->sig_th.sig_threshold;
+		if ((retval == 0) &&
+			is_valid_sig_th(radio->sig_th.sig_threshold))
+			ctrl->value = radio->sig_th.sig_threshold;
+		else
+			retval = -EINVAL;
 		break;
 	case V4L2_CID_PRIVATE_IRIS_SRCH_PTY:
-		ctrl->value = radio->srch_rds.srch_pty;
+		if (is_valid_pty(radio->srch_rds.srch_pty))
+			ctrl->value = radio->srch_rds.srch_pty;
+		else
+			retval = -EINVAL;
 		break;
 	case V4L2_CID_PRIVATE_IRIS_SRCH_PI:
-		ctrl->value = radio->srch_rds.srch_pi;
+		if (is_valid_pi(radio->srch_rds.srch_pi))
+			ctrl->value = radio->srch_rds.srch_pi;
+		else
+			retval = -EINVAL;
 		break;
 	case V4L2_CID_PRIVATE_IRIS_SRCH_CNT:
-		ctrl->value = radio->srch_st_result.num_stations_found;
+		if (is_valid_srch_station_cnt(
+			radio->srch_st_result.num_stations_found))
+			ctrl->value = radio->srch_st_result.num_stations_found;
+		else
+			retval = -EINVAL;
 		break;
 	case V4L2_CID_PRIVATE_IRIS_EMPHASIS:
 		if (radio->mode == FM_RECV) {
-			ctrl->value = radio->recv_conf.emphasis;
+			retval = hci_cmd(HCI_FM_GET_RECV_CONF_CMD,
+						radio->fm_hdev);
+			if ((retval == 0) &&
+				is_valid_emphasis(radio->recv_conf.emphasis))
+				ctrl->value = radio->recv_conf.emphasis;
+			else
+				retval = -EINVAL;
 		} else if (radio->mode == FM_TRANS) {
-			ctrl->value = radio->trans_conf.emphasis;
+			retval =  hci_cmd(HCI_FM_GET_TX_CONFIG,
+						radio->fm_hdev);
+			if ((retval == 0) &&
+				is_valid_emphasis(radio->trans_conf.emphasis))
+				ctrl->value = radio->trans_conf.emphasis;
+			else
+				retval = -EINVAL;
 		} else {
-			FMDERR("Error in radio mode"
-				" %d\n", retval);
-			return -EINVAL;
+			retval = -EINVAL;
+			FMDERR("Error in radio mode"" %d\n", retval);
 		}
 		break;
 	case V4L2_CID_PRIVATE_IRIS_RDS_STD:
 		if (radio->mode == FM_RECV) {
-			ctrl->value = radio->recv_conf.rds_std;
+			retval = hci_cmd(HCI_FM_GET_RECV_CONF_CMD,
+						radio->fm_hdev);
+			if ((retval == 0) &&
+				is_valid_rds_std(radio->recv_conf.rds_std))
+				ctrl->value = radio->recv_conf.rds_std;
+			else
+				retval = -EINVAL;
 		} else if (radio->mode == FM_TRANS) {
-			ctrl->value = radio->trans_conf.rds_std;
+			retval =  hci_cmd(HCI_FM_GET_TX_CONFIG,
+						radio->fm_hdev);
+			if ((retval == 0) &&
+				is_valid_rds_std(radio->trans_conf.rds_std))
+				ctrl->value = radio->trans_conf.rds_std;
+			else
+				retval = -EINVAL;
 		} else {
+			retval = -EINVAL;
 			FMDERR("Error in radio mode"
 				" %d\n", retval);
-			return -EINVAL;
 		}
 		break;
 	case V4L2_CID_PRIVATE_IRIS_SPACING:
 		if (radio->mode == FM_RECV) {
-			ctrl->value = radio->recv_conf.ch_spacing;
+			retval = hci_cmd(HCI_FM_GET_RECV_CONF_CMD,
+						radio->fm_hdev);
+			if ((retval == 0) &&
+				is_valid_chan_spacing(
+						radio->recv_conf.ch_spacing))
+				ctrl->value = radio->recv_conf.ch_spacing;
+			else
+				retval = -EINVAL;
 		} else {
+			retval = -EINVAL;
 			FMDERR("Error in radio mode"
 				" %d\n", retval);
-			return -EINVAL;
 		}
 		break;
 	case V4L2_CID_PRIVATE_IRIS_RDSON:
 		if (radio->mode == FM_RECV) {
-			ctrl->value = radio->recv_conf.rds_std;
+			retval = hci_cmd(HCI_FM_GET_RECV_CONF_CMD,
+						radio->fm_hdev);
+			if ((retval == 0) &&
+				is_valid_rds_std(radio->recv_conf.rds_std))
+				ctrl->value = radio->recv_conf.rds_std;
+			else
+				retval = -EINVAL;
 		} else {
+			retval = -EINVAL;
 			FMDERR("Error in radio mode"
 				" %d\n", retval);
-			return -EINVAL;
 		}
 		break;
 	case V4L2_CID_PRIVATE_IRIS_RDSGROUP_MASK:
@@ -2956,7 +3312,12 @@
 		ctrl->value = radio->g_antenna;
 		break;
 	case V4L2_CID_PRIVATE_IRIS_SOFT_MUTE:
-		ctrl->value = radio->mute_mode.soft_mute;
+		retval = hci_cmd(HCI_FM_STATION_DBG_PARAM_CMD, radio->fm_hdev);
+		if ((retval == 0) &&
+			is_valid_soft_mute(radio->mute_mode.soft_mute))
+			ctrl->value = radio->mute_mode.soft_mute;
+		else
+			retval = -EINVAL;
 		break;
 	case V4L2_CID_PRIVATE_IRIS_DO_CALIBRATION:
 		retval = iris_do_calibration(radio);
@@ -2965,47 +3326,30 @@
 		if (radio->mode == FM_RECV) {
 			retval = hci_cmd(HCI_FM_GET_STATION_PARAM_CMD,
 						 radio->fm_hdev);
-			if (retval < 0) {
-				FMDERR("Get SINR Failed");
-				return retval;
-			}
-			ctrl->value = radio->fm_st_rsp.station_rsp.sinr;
-
+			if (retval == 0)
+				ctrl->value = radio->fm_st_rsp.station_rsp.sinr;
 		} else
 			retval = -EINVAL;
 		break;
 	case V4L2_CID_PRIVATE_INTF_HIGH_THRESHOLD:
 		retval = hci_cmd(HCI_FM_GET_DET_CH_TH_CMD, radio->fm_hdev);
-		if (retval < 0) {
-			FMDERR("Get High det threshold failed %x", retval);
-			return retval;
-		}
-		ctrl->value = radio->ch_det_threshold.high_th;
+		if (retval == 0)
+			ctrl->value = radio->ch_det_threshold.high_th;
 		break;
 	case V4L2_CID_PRIVATE_INTF_LOW_THRESHOLD:
 		retval = hci_cmd(HCI_FM_GET_DET_CH_TH_CMD, radio->fm_hdev);
-		if (retval < 0) {
-			FMDERR("Get Low det threshold failed %x", retval);
-			return retval;
-		}
-		ctrl->value = radio->ch_det_threshold.low_th;
+		if (retval == 0)
+			ctrl->value = radio->ch_det_threshold.low_th;
 		break;
 	case V4L2_CID_PRIVATE_SINR_THRESHOLD:
 		retval = hci_cmd(HCI_FM_GET_DET_CH_TH_CMD, radio->fm_hdev);
-		if (retval < 0) {
-			FMDERR("Get SINR threshold failed %x", retval);
-			return retval;
-		}
-		ctrl->value = radio->ch_det_threshold.sinr;
+		if (retval == 0)
+			ctrl->value = radio->ch_det_threshold.sinr;
 		break;
 	case V4L2_CID_PRIVATE_SINR_SAMPLES:
 		retval = hci_cmd(HCI_FM_GET_DET_CH_TH_CMD, radio->fm_hdev);
-		if (retval < 0) {
-			FMDERR("Get SINR samples failed %x", retval);
-			return retval;
-		}
-
-		ctrl->value = radio->ch_det_threshold.sinr_samples;
+		if (retval == 0)
+			ctrl->value = radio->ch_det_threshold.sinr_samples;
 		break;
 	case V4L2_CID_PRIVATE_VALID_CHANNEL:
 		ctrl->value = radio->is_station_valid;
@@ -3017,13 +3361,11 @@
 		rd.param = 0;
 
 		retval = hci_def_data_read(&rd, radio->fm_hdev);
-		if (retval < 0) {
-			FMDERR("Get AF Jump Threshold failed %x", retval);
-			return retval;
+		if (retval == 0) {
+			lsb = radio->default_data.data[AF_RMSSI_TH_LSB_OFFSET];
+			msb = radio->default_data.data[AF_RMSSI_TH_MSB_OFFSET];
+			ctrl->value = ((msb << 8) | lsb);
 		}
-		lsb = radio->default_data.data[AF_RMSSI_TH_LSB_OFFSET];
-		msb = radio->default_data.data[AF_RMSSI_TH_MSB_OFFSET];
-		ctrl->value = ((msb << 8) | lsb);
 		break;
 	case V4L2_CID_PRIVATE_AF_RMSSI_SAMPLES:
 		rd.mode = FM_RDS_CNFG_MODE;
@@ -3032,11 +3374,9 @@
 		rd.param = 0;
 
 		retval = hci_def_data_read(&rd, radio->fm_hdev);
-		if (retval < 0) {
-			FMDERR("Get AF jump rmssi samples failed %x", retval);
-			return retval;
-		}
-		ctrl->value = radio->default_data.data[AF_RMSSI_SAMPLES_OFFSET];
+		if (retval == 0)
+			ctrl->value =
+			radio->default_data.data[AF_RMSSI_SAMPLES_OFFSET];
 		break;
 	case V4L2_CID_PRIVATE_GOOD_CH_RMSSI_TH:
 		rd.mode = FM_RX_CONFG_MODE;
@@ -3045,13 +3385,12 @@
 		rd.param = 0;
 
 		retval = hci_def_data_read(&rd, radio->fm_hdev);
-		if (retval < 0) {
-			FMDERR("get good channel rmssi th failed %x", retval);
-			return retval;
+		if (retval == 0) {
+			ctrl->value =
+			radio->default_data.data[GD_CH_RMSSI_TH_OFFSET];
+			if (ctrl->value > MAX_GD_CH_RMSSI_TH)
+				ctrl->value -= 256;
 		}
-		ctrl->value = radio->default_data.data[GD_CH_RMSSI_TH_OFFSET];
-		if (ctrl->value > MAX_GD_CH_RMSSI_TH)
-			ctrl->value -= 256;
 		break;
 	case V4L2_CID_PRIVATE_SRCHALGOTYPE:
 		rd.mode = FM_RX_CONFG_MODE;
@@ -3060,11 +3399,9 @@
 		rd.param = 0;
 
 		retval = hci_def_data_read(&rd, radio->fm_hdev);
-		if (retval < 0) {
-			FMDERR("get search algo type failed %x", retval);
-			return retval;
-		}
-		ctrl->value = radio->default_data.data[SRCH_ALGO_TYPE_OFFSET];
+		if (retval == 0)
+			ctrl->value =
+			radio->default_data.data[SRCH_ALGO_TYPE_OFFSET];
 		break;
 	case V4L2_CID_PRIVATE_SINRFIRSTSTAGE:
 		rd.mode = FM_RX_CONFG_MODE;
@@ -3073,13 +3410,12 @@
 		rd.param = 0;
 
 		retval = hci_def_data_read(&rd, radio->fm_hdev);
-		if (retval < 0) {
-			FMDERR("default data read failed %x", retval);
-			return retval;
+		if (retval == 0) {
+			ctrl->value =
+			radio->default_data.data[SINRFIRSTSTAGE_OFFSET];
+			if (ctrl->value > MAX_SINR_FIRSTSTAGE)
+				ctrl->value -= 256;
 		}
-		ctrl->value = radio->default_data.data[SINRFIRSTSTAGE_OFFSET];
-		if (ctrl->value > MAX_SINR_FIRSTSTAGE)
-			ctrl->value -= 256;
 		break;
 	case V4L2_CID_PRIVATE_RMSSIFIRSTSTAGE:
 		rd.mode = FM_RX_CONFG_MODE;
@@ -3088,13 +3424,12 @@
 		rd.param = 0;
 
 		retval = hci_def_data_read(&rd, radio->fm_hdev);
-		if (retval < 0) {
-			FMDERR("default data read failed %x", retval);
-			return retval;
+		if (retval == 0) {
+			ctrl->value =
+			radio->default_data.data[RMSSIFIRSTSTAGE_OFFSET];
+			if (ctrl->value > MAX_RMSSI_FIRSTSTAGE)
+				ctrl->value -= 256;
 		}
-		ctrl->value = radio->default_data.data[RMSSIFIRSTSTAGE_OFFSET];
-		if (ctrl->value > MAX_RMSSI_FIRSTSTAGE)
-			ctrl->value -= 256;
 		break;
 	case V4L2_CID_PRIVATE_CF0TH12:
 		rd.mode = FM_RX_CONFG_MODE;
@@ -3103,26 +3438,31 @@
 		rd.param = 0;
 
 		retval = hci_def_data_read(&rd, radio->fm_hdev);
-		if (retval < 0) {
-			FMDERR("default data read failed %x", retval);
-			return retval;
+		if (retval == 0) {
+			ctrl->value =
+			radio->default_data.data[CF0TH12_BYTE1_OFFSET];
+			cf0 = radio->default_data.data[CF0TH12_BYTE2_OFFSET];
+			ctrl->value |= (cf0 << 8);
+			cf0 = radio->default_data.data[CF0TH12_BYTE3_OFFSET];
+			ctrl->value |= (cf0 << 16);
+			cf0 = radio->default_data.data[CF0TH12_BYTE4_OFFSET];
+			if (cf0 > 127)
+				cf0 -= 256;
+			ctrl->value |= (cf0 << 24);
 		}
-		ctrl->value = radio->default_data.data[CF0TH12_BYTE1_OFFSET];
-		cf0 = radio->default_data.data[CF0TH12_BYTE2_OFFSET];
-		ctrl->value |= (cf0 << 8);
-		cf0 = radio->default_data.data[CF0TH12_BYTE3_OFFSET];
-		ctrl->value |= (cf0 << 16);
-		cf0 = radio->default_data.data[CF0TH12_BYTE4_OFFSET];
-		if (cf0 > 127)
-			cf0 -= 256;
-		ctrl->value |= (cf0 << 24);
 		break;
 	default:
 		retval = -EINVAL;
+		break;
 	}
+
+END:
+	if (retval > 0)
+		retval = -EINVAL;
 	if (retval < 0)
 		FMDERR("get control failed with %d, id: %d\n",
 			retval, ctrl->id);
+
 	return retval;
 }
 
@@ -3134,24 +3474,38 @@
 	struct iris_device *radio = video_get_drvdata(video_devdata(file));
 	struct hci_fm_def_data_rd_req default_data_rd;
 
-	if (radio == NULL) {
+	if (unlikely(radio == NULL)) {
 		FMDERR(":radio is null");
-		return -EINVAL;
+		retval = -EINVAL;
+		goto END;
 	}
 
+	if (unlikely((ctrl == NULL)) || unlikely((ctrl->count == 0))
+		|| unlikely((ctrl->controls == NULL))) {
+		FMDERR("%s, invalid v4l2 ctrl\n", __func__);
+		retval = -EINVAL;
+		goto END;
+	}
 	switch ((ctrl->controls[0]).id) {
 	case V4L2_CID_PRIVATE_IRIS_READ_DEFAULT:
 		data = (ctrl->controls[0]).string;
 		memset(&default_data_rd, 0, sizeof(default_data_rd));
 		if (copy_from_user(&default_data_rd.mode, data,
-					sizeof(default_data_rd)))
-			return -EFAULT;
+					sizeof(default_data_rd))) {
+			retval = -EFAULT;
+			goto END;
+		}
 		retval = hci_def_data_read(&default_data_rd, radio->fm_hdev);
 		break;
 	default:
 		retval = -EINVAL;
+		break;
 	}
 
+END:
+	if (retval > 0)
+		retval = -EINVAL;
+
 	return retval;
 }
 
@@ -3168,10 +3522,17 @@
 	struct iris_device *radio = video_get_drvdata(video_devdata(file));
 	char *data = NULL;
 
-	if ((ctrl == NULL) || (ctrl->controls == NULL)
-		|| (ctrl->count == 0)) {
+	if (unlikely(radio == NULL)) {
+		FMDERR(":radio is null");
 		retval = -EINVAL;
-		return retval;
+		goto END;
+	}
+
+	if (unlikely((ctrl == NULL)) || unlikely((ctrl->count == 0))
+		|| unlikely((ctrl->controls == NULL))) {
+		FMDERR("%s, invalid v4l2 ctrl\n", __func__);
+		retval = -EINVAL;
+		goto END;
 	}
 
 	switch ((ctrl->controls[0]).id) {
@@ -3185,16 +3546,23 @@
 		data = (ctrl->controls[0]).string;
 
 		if (copy_from_user(tx_ps.ps_data,
-				data, bytes_to_copy))
-				return -EFAULT;
-		tx_ps.ps_control =  0x01;
-		tx_ps.pi = radio->pi;
-		tx_ps.pty = radio->pty;
-		tx_ps.ps_repeatcount = radio->ps_repeatcount;
-		tx_ps.ps_num = (bytes_to_copy / PS_STRING_LEN);
+				data, bytes_to_copy)) {
+			FMDERR("%s: copy from user for tx ps name failed\n",
+				__func__);
+			retval = -EFAULT;
+			goto END;
+		} else {
+			tx_ps.ps_control =  0x01;
+			tx_ps.pi = radio->pi;
+			tx_ps.pty = radio->pty;
+			tx_ps.ps_repeatcount = radio->ps_repeatcount;
+			tx_ps.ps_num = (bytes_to_copy / PS_STRING_LEN);
 
-		retval = radio_hci_request(radio->fm_hdev, hci_trans_ps_req,
-				(unsigned long)&tx_ps, RADIO_HCI_TIMEOUT);
+			retval = radio_hci_request(radio->fm_hdev,
+							hci_trans_ps_req,
+							(unsigned long)&tx_ps,
+							RADIO_HCI_TIMEOUT);
+		}
 		break;
 	case V4L2_CID_RDS_TX_RADIO_TEXT:
 		bytes_to_copy =
@@ -3204,16 +3572,22 @@
 		memset(tx_rt.rt_data, 0, MAX_RT_LENGTH);
 
 		if (copy_from_user(tx_rt.rt_data,
-				data, bytes_to_copy))
-				return -EFAULT;
+				data, bytes_to_copy)) {
+			FMDERR("%s: copy from user for tx rt failed\n",
+				 __func__);
+			retval = -EFAULT;
+			goto END;
+		} else {
+			tx_rt.rt_control = 0x01;
+			tx_rt.pi = radio->pi;
+			tx_rt.pty = radio->pty;
+			tx_rt.rt_len = bytes_to_copy;
 
-		tx_rt.rt_control =  0x01;
-		tx_rt.pi = radio->pi;
-		tx_rt.pty = radio->pty;
-		tx_rt.rt_len = bytes_to_copy;
-
-		retval = radio_hci_request(radio->fm_hdev, hci_trans_rt_req,
-				(unsigned long)&tx_rt, RADIO_HCI_TIMEOUT);
+			retval = radio_hci_request(radio->fm_hdev,
+							hci_trans_rt_req,
+							(unsigned long)&tx_rt,
+							RADIO_HCI_TIMEOUT);
+		}
 		break;
 	case V4L2_CID_PRIVATE_IRIS_WRITE_DEFAULT:
 		data = (ctrl->controls[0]).string;
@@ -3228,7 +3602,8 @@
 		 */
 		if (ctrl->controls[0].size > (DEFAULT_DATA_SIZE + 2)) {
 			pr_err("%s: Default data buffer overflow!\n", __func__);
-			return -EINVAL;
+			retval = -EINVAL;
+			goto END;
 		}
 
 		/* copy only 'size' bytes of data as requested by user */
@@ -3237,7 +3612,8 @@
 		if (retval > 0) {
 			pr_err("%s: Failed to copy %d bytes of default data"
 				" passed by user\n", __func__, retval);
-			return -EFAULT;
+			retval = -EFAULT;
+			goto END;
 		}
 		FMDBG("%s: XFR Mode\t: 0x%x\n", __func__, default_data.mode);
 		FMDBG("%s: XFR Data Length\t: %d\n", __func__,
@@ -3252,7 +3628,8 @@
 		if (default_data.length != (ctrl->controls[0].size - 2)) {
 			pr_err("%s: Invalid 'length' parameter passed for "
 				"actual xfr data\n", __func__);
-			return -EINVAL;
+			retval = -EINVAL;
+			goto END;
 		}
 		retval = hci_def_data_write(&default_data, radio->fm_hdev);
 		break;
@@ -3261,24 +3638,32 @@
 		bytes_to_copy = (ctrl->controls[0]).size;
 		if (bytes_to_copy < PROCS_CALIB_SIZE) {
 			FMDERR("data is less than required size");
-			return -EFAULT;
+			retval = -EFAULT;
+			goto END;
 		}
 		memset(proc_cal_req.data, 0, PROCS_CALIB_SIZE);
 		proc_cal_req.mode = PROCS_CALIB_MODE;
 		if (copy_from_user(&proc_cal_req.data[0],
-				data, sizeof(proc_cal_req.data)))
-				return -EFAULT;
+				data, sizeof(proc_cal_req.data))) {
+			retval = -EFAULT;
+			goto END;
+		}
 		retval = radio_hci_request(radio->fm_hdev,
 				hci_fm_set_cal_req_proc,
 				(unsigned long)&proc_cal_req,
 				 RADIO_HCI_TIMEOUT);
-		if (retval < 0)
-			FMDERR("Set Process calibration failed %d", retval);
 		break;
 	default:
 		FMDBG("Shouldn't reach here\n");
 		retval = -1;
+		goto END;
+		break;
 	}
+
+END:
+	if (retval > 0)
+		retval = -EINVAL;
+
 	return retval;
 }
 
@@ -3289,6 +3674,7 @@
 	int retval = 0;
 	unsigned int rds_grps_proc = 0;
 	__u8 temp_val = 0;
+	int saved_val;
 	unsigned long arg = 0;
 	struct hci_fm_tx_ps tx_ps = {0};
 	struct hci_fm_tx_rt tx_rt = {0};
@@ -3297,37 +3683,70 @@
 	char sinr_th, sinr;
 	__u8 intf_det_low_th, intf_det_high_th, intf_det_out;
 
-	if (radio == NULL) {
+	if (unlikely(radio == NULL)) {
 		FMDERR(":radio is null");
-		return -EINVAL;
+		retval = -EINVAL;
+		goto END;
 	}
 
+	if (unlikely(ctrl == NULL)) {
+		FMDERR("%s, v4l2 ctrl is null\n", __func__);
+		retval = -EINVAL;
+		goto END;
+	}
 	switch (ctrl->id) {
 	case V4L2_CID_PRIVATE_IRIS_TX_TONE:
+		if (!is_valid_tone(ctrl->value)) {
+			retval = -EINVAL;
+			FMDERR("%s: tone value is not valid\n", __func__);
+			goto END;
+		}
+		saved_val = radio->tone_freq;
 		radio->tone_freq = ctrl->value;
 		retval = radio_hci_request(radio->fm_hdev,
 				hci_fm_tone_generator, arg,
 				msecs_to_jiffies(RADIO_HCI_TIMEOUT));
-		if (retval < 0)
+		if (retval < 0) {
 			FMDERR("Error while setting the tone %d", retval);
+			radio->tone_freq = saved_val;
+		}
 		break;
 	case V4L2_CID_AUDIO_VOLUME:
 		break;
 	case V4L2_CID_AUDIO_MUTE:
+		if (!is_valid_hard_mute(ctrl->value)) {
+			retval = -EINVAL;
+			FMDERR("%s: hard mute value is not valid\n", __func__);
+			goto END;
+		}
+		saved_val = radio->mute_mode.hard_mute;
 		radio->mute_mode.hard_mute = ctrl->value;
-		radio->mute_mode.soft_mute = IOC_SFT_MUTE;
 		retval = hci_set_fm_mute_mode(
 				&radio->mute_mode,
 				radio->fm_hdev);
-		if (retval < 0)
+		if (retval < 0) {
 			FMDERR("Error while set FM hard mute"" %d\n",
-			retval);
+				retval);
+			radio->mute_mode.hard_mute = saved_val;
+		}
 		break;
 	case V4L2_CID_PRIVATE_IRIS_SRCHMODE:
-		radio->g_search_mode = ctrl->value;
+		if (is_valid_srch_mode(ctrl->value)) {
+			radio->g_search_mode = ctrl->value;
+		} else {
+			FMDERR("%s: srch mode is not valid\n", __func__);
+			retval = -EINVAL;
+			goto END;
+		}
 		break;
 	case V4L2_CID_PRIVATE_IRIS_SCANDWELL:
-		radio->g_scan_time = ctrl->value;
+		if (is_valid_scan_dwell_prd(ctrl->value)) {
+			radio->g_scan_time = ctrl->value;
+		} else {
+			FMDERR("%s: scandwell period is not valid\n", __func__);
+			retval = -EINVAL;
+			goto END;
+		}
 		break;
 	case V4L2_CID_PRIVATE_IRIS_SRCHON:
 		iris_search(radio, ctrl->value, SRCH_DIR_UP);
@@ -3335,8 +3754,12 @@
 	case V4L2_CID_PRIVATE_IRIS_STATE:
 		switch (ctrl->value) {
 		case FM_RECV:
-			if (is_enable_rx_possible(radio) != 0)
-				return -EINVAL;
+			if (is_enable_rx_possible(radio) != 0) {
+				FMDERR("%s: fm is not in proper state\n",
+					 __func__);
+				retval = -EINVAL;
+				goto END;
+			}
 			radio->mode = FM_RECV_TURNING_ON;
 			retval = hci_cmd(HCI_FM_ENABLE_RECV_CMD,
 							 radio->fm_hdev);
@@ -3344,14 +3767,28 @@
 				FMDERR("Error while enabling RECV FM"
 							" %d\n", retval);
 				radio->mode = FM_OFF;
-				return retval;
+				goto END;
 			} else {
-				initialise_recv(radio);
+				retval = initialise_recv(radio);
+				if (retval < 0) {
+					FMDERR("Error while initialising"\
+						"radio %d\n", retval);
+					hci_cmd(HCI_FM_DISABLE_RECV_CMD,
+							radio->fm_hdev);
+					radio->mode = FM_OFF;
+					goto END;
+				}
+			}
+			if (radio->mode == FM_RECV_TURNING_ON) {
+				radio->mode = FM_RECV;
+				iris_q_event(radio, IRIS_EVT_RADIO_READY);
 			}
 			break;
 		case FM_TRANS:
-			if (is_enable_tx_possible(radio) != 0)
-				return -EINVAL;
+			if (is_enable_tx_possible(radio) != 0) {
+				retval = -EINVAL;
+				goto END;
+			}
 			radio->mode = FM_TRANS_TURNING_ON;
 			retval = hci_cmd(HCI_FM_ENABLE_TRANS_CMD,
 							 radio->fm_hdev);
@@ -3359,9 +3796,21 @@
 				FMDERR("Error while enabling TRANS FM"
 							" %d\n", retval);
 				radio->mode = FM_OFF;
-				return retval;
+				goto END;
 			} else {
-				initialise_trans(radio);
+				retval = initialise_trans(radio);
+				if (retval < 0) {
+					FMDERR("Error while initialising"\
+							"radio %d\n", retval);
+					hci_cmd(HCI_FM_DISABLE_TRANS_CMD,
+								radio->fm_hdev);
+					radio->mode = FM_OFF;
+					goto END;
+				}
+			}
+			if (radio->mode == FM_TRANS_TURNING_ON) {
+				radio->mode = FM_TRANS;
+				iris_q_event(radio, IRIS_EVT_RADIO_READY);
 			}
 			break;
 		case FM_OFF:
@@ -3375,7 +3824,7 @@
 					FMDERR("Err on disable recv FM"
 						   " %d\n", retval);
 					radio->mode = FM_RECV;
-					return retval;
+					goto END;
 				}
 				break;
 			case FM_TRANS:
@@ -3387,7 +3836,7 @@
 					FMDERR("Err disabling trans FM"
 						" %d\n", retval);
 					radio->mode = FM_TRANS;
-					return retval;
+					goto END;
 				}
 				break;
 			default:
@@ -3402,136 +3851,236 @@
 		if (radio->mode == FM_RECV) {
 			retval = iris_recv_set_region(radio, ctrl->value);
 		} else {
-			if (radio->mode == FM_TRANS)
+			if (radio->mode == FM_TRANS) {
 				retval = iris_trans_set_region(radio,
 						ctrl->value);
-			else
+			} else {
+				FMDERR("%s: fm is not in proper state\n",
+					__func__);
 				retval = -EINVAL;
+				goto END;
+			}
 		}
 		break;
 	case V4L2_CID_PRIVATE_IRIS_SIGNAL_TH:
+		if (!is_valid_sig_th(ctrl->value)) {
+			retval = -EINVAL;
+			FMDERR("%s: sig threshold is not valid\n", __func__);
+			goto END;
+		}
 		temp_val = ctrl->value;
 		retval = hci_fm_set_signal_threshold(
 				&temp_val,
 				radio->fm_hdev);
 		if (retval < 0) {
 			FMDERR("Error while setting signal threshold\n");
-			break;
+			goto END;
 		}
 		break;
 	case V4L2_CID_PRIVATE_IRIS_SRCH_PTY:
-		radio->srch_rds.srch_pty = ctrl->value;
-		radio->srch_st_list.srch_pty = ctrl->value;
+		if (is_valid_pty(ctrl->value)) {
+			radio->srch_rds.srch_pty = ctrl->value;
+			radio->srch_st_list.srch_pty = ctrl->value;
+		} else {
+			FMDERR("%s: pty is not valid\n", __func__);
+			retval = -EINVAL;
+			goto END;
+		}
 		break;
 	case V4L2_CID_PRIVATE_IRIS_SRCH_PI:
-		radio->srch_rds.srch_pi = ctrl->value;
+		if (is_valid_pi(ctrl->value)) {
+			radio->srch_rds.srch_pi = ctrl->value;
+		} else {
+			retval = -EINVAL;
+			FMDERR("%s: Pi is not valid\n", __func__);
+			goto END;
+		}
 		break;
 	case V4L2_CID_PRIVATE_IRIS_SRCH_CNT:
-		radio->srch_st_list.srch_list_max = ctrl->value;
+		if (is_valid_srch_station_cnt(ctrl->value)) {
+			radio->srch_st_list.srch_list_max = ctrl->value;
+		} else {
+			retval = -EINVAL;
+			FMDERR("%s: srch station count is not valid\n",
+				__func__);
+			goto END;
+		}
 		break;
 	case V4L2_CID_PRIVATE_IRIS_SPACING:
+		if (!is_valid_chan_spacing(ctrl->value)) {
+			retval = -EINVAL;
+			FMDERR("%s: channel spacing is not valid\n", __func__);
+			goto END;
+		}
 		if (radio->mode == FM_RECV) {
+			saved_val = radio->recv_conf.ch_spacing;
 			radio->recv_conf.ch_spacing = ctrl->value;
 			retval = hci_set_fm_recv_conf(
 					&radio->recv_conf,
 						radio->fm_hdev);
-			if (retval < 0)
+			if (retval < 0) {
 				FMDERR("Error in setting channel spacing");
+				radio->recv_conf.ch_spacing = saved_val;
+				goto END;
+			}
 		}
 		break;
 	case V4L2_CID_PRIVATE_IRIS_EMPHASIS:
+		if (!is_valid_emphasis(ctrl->value)) {
+			retval = -EINVAL;
+			FMDERR("%s, emphasis is not valid\n", __func__);
+			goto END;
+		}
 		switch (radio->mode) {
 		case FM_RECV:
+			saved_val = radio->recv_conf.emphasis;
 			radio->recv_conf.emphasis = ctrl->value;
 			retval = hci_set_fm_recv_conf(
 					&radio->recv_conf,
 						radio->fm_hdev);
-			if (retval < 0)
+			if (retval < 0) {
 				FMDERR("Error in setting emphasis");
+				radio->recv_conf.emphasis = saved_val;
+				goto END;
+			}
 			break;
 		case FM_TRANS:
+			saved_val = radio->trans_conf.emphasis;
 			radio->trans_conf.emphasis = ctrl->value;
 			retval = hci_set_fm_trans_conf(
 					&radio->trans_conf,
 						radio->fm_hdev);
-			if (retval < 0)
+			if (retval < 0) {
 				FMDERR("Error in setting emphasis");
+				radio->trans_conf.emphasis = saved_val;
+				goto END;
+			}
 			break;
 		default:
 			retval = -EINVAL;
+			FMDERR("%s, FM is not in proper state\n", __func__);
+			goto END;
+			break;
 		}
 		break;
 	case V4L2_CID_PRIVATE_IRIS_RDS_STD:
+		if (!is_valid_rds_std(ctrl->value)) {
+			retval = -EINVAL;
+			FMDERR("%s: rds std is not valid\n", __func__);
+			goto END;
+		}
 		switch (radio->mode) {
 		case FM_RECV:
+			saved_val = radio->recv_conf.rds_std;
 			radio->recv_conf.rds_std = ctrl->value;
 			retval = hci_set_fm_recv_conf(
 					&radio->recv_conf,
 						radio->fm_hdev);
-			if (retval < 0)
+			if (retval < 0) {
 				FMDERR("Error in rds_std");
+				radio->recv_conf.rds_std = saved_val;
+				goto END;
+			}
 			break;
 		case FM_TRANS:
+			saved_val = radio->trans_conf.rds_std;
 			radio->trans_conf.rds_std = ctrl->value;
 			retval = hci_set_fm_trans_conf(
 					&radio->trans_conf,
 						radio->fm_hdev);
-			if (retval < 0)
+			if (retval < 0) {
 				FMDERR("Error in rds_Std");
+				radio->trans_conf.rds_std = saved_val;
+				goto END;
+			}
 			break;
 		default:
 			retval = -EINVAL;
+			FMDERR("%s: fm is not in proper state\n", __func__);
+			goto END;
+			break;
 		}
 		break;
 	case V4L2_CID_PRIVATE_IRIS_RDSON:
+		if (!is_valid_rds_std(ctrl->value)) {
+			retval = -EINVAL;
+			FMDERR("%s: rds std is not valid\n", __func__);
+			goto END;
+		}
 		switch (radio->mode) {
 		case FM_RECV:
+			saved_val = radio->recv_conf.rds_std;
 			radio->recv_conf.rds_std = ctrl->value;
 			retval = hci_set_fm_recv_conf(
 					&radio->recv_conf,
 						radio->fm_hdev);
-			if (retval < 0)
+			if (retval < 0) {
 				FMDERR("Error in rds_std");
+				radio->recv_conf.rds_std = saved_val;
+				goto END;
+			}
 			break;
 		case FM_TRANS:
+			saved_val = radio->trans_conf.rds_std;
 			radio->trans_conf.rds_std = ctrl->value;
 			retval = hci_set_fm_trans_conf(
 					&radio->trans_conf,
 						radio->fm_hdev);
-			if (retval < 0)
+			if (retval < 0) {
 				FMDERR("Error in rds_Std");
+				radio->trans_conf.rds_std = saved_val;
+				goto END;
+			}
 			break;
 		default:
 			retval = -EINVAL;
+			FMDERR("%s: fm is not in proper state\n", __func__);
+			goto END;
+			break;
 		}
 		break;
 	case V4L2_CID_PRIVATE_IRIS_RDSGROUP_MASK:
+		saved_val = radio->rds_grp.rds_grp_enable_mask;
 		grp_mask = (grp_mask | oda_agt | ctrl->value);
 		radio->rds_grp.rds_grp_enable_mask = grp_mask;
 		radio->rds_grp.rds_buf_size = 1;
 		radio->rds_grp.en_rds_change_filter = 0;
 		retval = hci_fm_rds_grp(&radio->rds_grp, radio->fm_hdev);
-		if (retval < 0)
+		if (retval < 0) {
 			FMDERR("error in setting group mask\n");
+			radio->rds_grp.rds_grp_enable_mask = saved_val;
+			goto END;
+		}
 		break;
 	case V4L2_CID_PRIVATE_IRIS_RDSGROUP_PROC:
+		saved_val = radio->g_rds_grp_proc_ps;
 		rds_grps_proc = radio->g_rds_grp_proc_ps | ctrl->value;
 		radio->g_rds_grp_proc_ps = (rds_grps_proc >> RDS_CONFIG_OFFSET);
 		retval = hci_fm_rds_grps_process(
 				&radio->g_rds_grp_proc_ps,
 				radio->fm_hdev);
+		if (retval < 0) {
+			radio->g_rds_grp_proc_ps = saved_val;
+			goto END;
+		}
 		break;
 	case V4L2_CID_PRIVATE_IRIS_RDSD_BUF:
 		radio->rds_grp.rds_buf_size = ctrl->value;
 		break;
 	case V4L2_CID_PRIVATE_IRIS_PSALL:
+		saved_val = radio->g_rds_grp_proc_ps;
 		rds_grps_proc = (ctrl->value << RDS_CONFIG_OFFSET);
 		radio->g_rds_grp_proc_ps |= rds_grps_proc;
 		retval = hci_fm_rds_grps_process(
 				&radio->g_rds_grp_proc_ps,
 				radio->fm_hdev);
+		if (retval < 0) {
+			radio->g_rds_grp_proc_ps = saved_val;
+			goto END;
+		}
 		break;
 	case V4L2_CID_PRIVATE_IRIS_AF_JUMP:
+		saved_val = radio->g_rds_grp_proc_ps;
 		/*Clear the current AF jump settings*/
 		radio->g_rds_grp_proc_ps &= ~(1 << RDS_AF_JUMP_OFFSET);
 		radio->af_jump_bit = ctrl->value;
@@ -3541,24 +4090,45 @@
 		retval = hci_fm_rds_grps_process(
 				&radio->g_rds_grp_proc_ps,
 				radio->fm_hdev);
+		if (retval < 0) {
+			radio->g_rds_grp_proc_ps = saved_val;
+			goto END;
+		}
 		break;
 	case V4L2_CID_PRIVATE_IRIS_LP_MODE:
 		set_low_power_mode(radio, ctrl->value);
 		break;
 	case V4L2_CID_PRIVATE_IRIS_ANTENNA:
+		if (!is_valid_antenna(ctrl->value)) {
+			retval = -EINVAL;
+			FMDERR("%s: antenna type is not valid\n", __func__);
+			goto END;
+		}
 		temp_val = ctrl->value;
 		retval = hci_fm_set_antenna(&temp_val, radio->fm_hdev);
 		if (retval < 0) {
 			FMDERR("Set Antenna failed retval = %x", retval);
-			return retval;
+			goto END;
 		}
 		radio->g_antenna =  ctrl->value;
 		break;
 	case V4L2_CID_RDS_TX_PTY:
-		radio->pty = ctrl->value;
+		if (is_valid_pty(ctrl->value)) {
+			radio->pty = ctrl->value;
+		} else {
+			retval = -EINVAL;
+			FMDERR("%s: pty is not valid\n", __func__);
+			goto END;
+		}
 		break;
 	case V4L2_CID_RDS_TX_PI:
-		radio->pi = ctrl->value;
+		if (is_valid_pi(ctrl->value)) {
+			radio->pi = ctrl->value;
+		} else {
+			retval = -EINVAL;
+			FMDERR("%s: pi is not valid\n", __func__);
+			goto END;
+		}
 		break;
 	case V4L2_CID_PRIVATE_IRIS_STOP_RDS_TX_PS_NAME:
 		tx_ps.ps_control =  0x00;
@@ -3571,7 +4141,13 @@
 				(unsigned long)&tx_rt, RADIO_HCI_TIMEOUT);
 		break;
 	case V4L2_CID_PRIVATE_IRIS_TX_SETPSREPEATCOUNT:
-		radio->ps_repeatcount = ctrl->value;
+		if (is_valid_ps_repeat_cnt(ctrl->value)) {
+			radio->ps_repeatcount = ctrl->value;
+		} else {
+			retval = -EINVAL;
+			FMDERR("%s: ps repeat count is not valid\n", __func__);
+			goto END;
+		}
 		break;
 	case V4L2_CID_TUNE_POWER_LEVEL:
 		if (ctrl->value > FM_TX_PWR_LVL_MAX)
@@ -3586,8 +4162,8 @@
 		retval = hci_def_data_read(&rd, radio->fm_hdev);
 		if (retval < 0) {
 			FMDERR("Default data read failed for PHY_CFG %d\n",
-			retval);
-			break;
+				retval);
+			goto END;
 		}
 		memset(&wrd, 0, sizeof(wrd));
 		wrd.mode = FM_TX_PHY_CFG_MODE;
@@ -3599,40 +4175,58 @@
 		retval = hci_def_data_write(&wrd, radio->fm_hdev);
 		if (retval < 0)
 			FMDERR("Default write failed for PHY_TXGAIN %d\n",
-			retval);
+				retval);
 		break;
 	case V4L2_CID_PRIVATE_IRIS_SOFT_MUTE:
+		if (!is_valid_soft_mute(ctrl->value)) {
+			retval = -EINVAL;
+			FMDERR("%s: soft mute is not valid\n", __func__);
+			goto END;
+		}
+		saved_val = radio->mute_mode.soft_mute;
 		radio->mute_mode.soft_mute = ctrl->value;
 		retval = hci_set_fm_mute_mode(
 				&radio->mute_mode,
 				radio->fm_hdev);
-		if (retval < 0)
+		if (retval < 0) {
 			FMDERR("Error while setting FM soft mute"" %d\n",
-			retval);
+				retval);
+			radio->mute_mode.soft_mute = saved_val;
+			goto END;
+		}
 		break;
 	case V4L2_CID_PRIVATE_IRIS_RIVA_ACCS_ADDR:
 		radio->riva_data_req.cmd_params.start_addr = ctrl->value;
 		break;
 	case V4L2_CID_PRIVATE_IRIS_RIVA_ACCS_LEN:
-		if ((ctrl->value > 0) &&
-			(ctrl->value <= MAX_RIVA_PEEK_RSP_SIZE)) {
+		if (is_valid_peek_len(ctrl->value)) {
 			radio->riva_data_req.cmd_params.length = ctrl->value;
 		} else {
-			FMDERR("Length %d is more than the buffer size %d\n",
-			ctrl->value, MAX_RIVA_PEEK_RSP_SIZE);
 			retval = -EINVAL;
+			FMDERR("%s: riva access len is not valid\n", __func__);
+			goto END;
 		}
 		break;
 	case V4L2_CID_PRIVATE_IRIS_RIVA_POKE:
-		if (radio->riva_data_req.cmd_params.length <= MAX_RIVA_PEEK_RSP_SIZE) {
-			memcpy(radio->riva_data_req.data, (void *)ctrl->value,
-						radio->riva_data_req.cmd_params.length);
-			radio->riva_data_req.cmd_params.subopcode = RIVA_POKE_OPCODE;
-			retval = hci_poke_data(&radio->riva_data_req , radio->fm_hdev);
+		if (radio->riva_data_req.cmd_params.length <=
+		    MAX_RIVA_PEEK_RSP_SIZE) {
+			retval = copy_from_user(
+					radio->riva_data_req.data,
+					(void *)ctrl->value,
+					radio->riva_data_req.cmd_params.length);
+			if (retval != 0) {
+				retval = -retval;
+				goto END;
+			}
+			radio->riva_data_req.cmd_params.subopcode =
+						RIVA_POKE_OPCODE;
+			retval = hci_poke_data(
+					&radio->riva_data_req,
+					radio->fm_hdev);
 		} else {
-			FMDERR("Can not copy into driver's buffer. Length %d is more than"
-			 "the buffer size %d\n", ctrl->value, MAX_RIVA_PEEK_RSP_SIZE);
+			FMDERR("Can not copy into driver's buffer.\n");
 			retval = -EINVAL;
+			goto END;
 		}
 		break;
 	case V4L2_CID_PRIVATE_IRIS_SSBI_ACCS_ADDR:
@@ -3653,80 +4247,133 @@
 		hci_ssbi_peek_reg(&radio->ssbi_peek_reg, radio->fm_hdev);
 		break;
 	case V4L2_CID_PRIVATE_IRIS_RDS_GRP_COUNTERS:
-		temp_val = ctrl->value;
-		hci_read_grp_counters(&temp_val, radio->fm_hdev);
+		if (is_valid_reset_cntr(ctrl->value)) {
+			temp_val = ctrl->value;
+			hci_read_grp_counters(&temp_val, radio->fm_hdev);
+		} else {
+			FMDERR("%s: reset counter value is not valid\n",
+				__func__);
+			retval = -EINVAL;
+			goto END;
+		}
 		break;
 	case V4L2_CID_PRIVATE_IRIS_HLSI:
+		if (!is_valid_hlsi(ctrl->value)) {
+			FMDERR("%s: hlsi value is not valid\n", __func__);
+			retval = -EINVAL;
+			goto END;
+		}
 		retval = hci_cmd(HCI_FM_GET_RECV_CONF_CMD,
 						radio->fm_hdev);
 		if (retval)
-			break;
+			goto END;
+		saved_val = radio->recv_conf.hlsi;
 		radio->recv_conf.hlsi = ctrl->value;
 		retval = hci_set_fm_recv_conf(
 					&radio->recv_conf,
 						radio->fm_hdev);
+		if (retval < 0)
+			radio->recv_conf.hlsi = saved_val;
 		break;
 	case V4L2_CID_PRIVATE_IRIS_SET_NOTCH_FILTER:
-		temp_val = ctrl->value;
-		retval = hci_set_notch_filter(&temp_val, radio->fm_hdev);
+		if (is_valid_notch_filter(ctrl->value)) {
+			temp_val = ctrl->value;
+			retval = hci_set_notch_filter(&temp_val,
+							radio->fm_hdev);
+		} else {
+			FMDERR("%s: notch filter is not valid\n", __func__);
+			retval = -EINVAL;
+			goto END;
+		}
 		break;
 	case V4L2_CID_PRIVATE_INTF_HIGH_THRESHOLD:
+		if (!is_valid_intf_det_hgh_th(ctrl->value)) {
+			FMDERR("%s: intf high threshold is not valid\n",
+				__func__);
+			retval = -EINVAL;
+			goto END;
+		}
 		retval = hci_cmd(HCI_FM_GET_DET_CH_TH_CMD, radio->fm_hdev);
 		if (retval < 0) {
 			FMDERR("Failed to get chnl det thresholds  %d", retval);
-			return retval;
+			goto END;
 		}
+		saved_val = radio->ch_det_threshold.high_th;
 		radio->ch_det_threshold.high_th = ctrl->value;
 		retval = hci_set_ch_det_thresholds_req(&radio->ch_det_threshold,
 							 radio->fm_hdev);
 		if (retval < 0) {
 			FMDERR("Failed to set High det threshold %d ", retval);
-			return retval;
+			radio->ch_det_threshold.high_th = saved_val;
+			goto END;
 		}
 		break;
 
 	case V4L2_CID_PRIVATE_INTF_LOW_THRESHOLD:
+		if (!is_valid_intf_det_low_th(ctrl->value)) {
+			FMDERR("%s: intf det low threshold is not valid\n",
+				__func__);
+			retval = -EINVAL;
+			goto END;
+		}
 		retval = hci_cmd(HCI_FM_GET_DET_CH_TH_CMD, radio->fm_hdev);
 		if (retval < 0) {
 			FMDERR("Failed to get chnl det thresholds  %d", retval);
-			return retval;
+			goto END;
 		}
+		saved_val = radio->ch_det_threshold.low_th;
 		radio->ch_det_threshold.low_th = ctrl->value;
 		retval = hci_set_ch_det_thresholds_req(&radio->ch_det_threshold,
 							 radio->fm_hdev);
 		if (retval < 0) {
 			FMDERR("Failed to Set Low det threshold %d", retval);
-			return retval;
+			radio->ch_det_threshold.low_th = saved_val;
+			goto END;
 		}
 		break;
 
 	case V4L2_CID_PRIVATE_SINR_THRESHOLD:
+		if (!is_valid_sinr_th(ctrl->value)) {
+			FMDERR("%s: sinr threshold is not valid\n", __func__);
+			retval = -EINVAL;
+			goto END;
+		}
 		retval = hci_cmd(HCI_FM_GET_DET_CH_TH_CMD, radio->fm_hdev);
 		if (retval < 0) {
 			FMDERR("Failed to get chnl det thresholds  %d", retval);
-			return retval;
+			goto END;
 		}
+		saved_val = radio->ch_det_threshold.sinr;
 		radio->ch_det_threshold.sinr = ctrl->value;
 		retval = hci_set_ch_det_thresholds_req(&radio->ch_det_threshold,
 							 radio->fm_hdev);
 		if (retval < 0) {
 			FMDERR("Failed to set SINR threshold %d", retval);
-			return retval;
+			radio->ch_det_threshold.sinr = saved_val;
+			goto END;
 		}
 		break;
 
 	case V4L2_CID_PRIVATE_SINR_SAMPLES:
+		if (!is_valid_sinr_samples(ctrl->value)) {
+			FMDERR("%s: sinr samples count is not valid\n",
+				__func__);
+			retval = -EINVAL;
+			goto END;
+		}
 		retval = hci_cmd(HCI_FM_GET_DET_CH_TH_CMD, radio->fm_hdev);
 		if (retval < 0) {
 			FMDERR("Failed to get chnl det thresholds  %d", retval);
-			return retval;
+			goto END;
 		}
+		saved_val = radio->ch_det_threshold.sinr_samples;
 		radio->ch_det_threshold.sinr_samples = ctrl->value;
 		retval = hci_set_ch_det_thresholds_req(&radio->ch_det_threshold,
 							 radio->fm_hdev);
 	       if (retval < 0) {
 			FMDERR("Failed to set SINR samples  %d", retval);
-			return retval;
+			radio->ch_det_threshold.sinr_samples = saved_val;
+			goto END;
 		}
 		break;
 
@@ -3773,18 +4420,23 @@
 		if (retval < 0) {
 			FMDERR("%s: Failed to determine channel's validity\n",
 				__func__);
-			return retval;
+			goto END;
 		} else {
 			sinr_th = radio->ch_det_threshold.sinr;
 			intf_det_low_th = radio->ch_det_threshold.low_th;
 			intf_det_high_th = radio->ch_det_threshold.high_th;
 		}
-
+		if (!is_valid_sinr_th(sinr_th) ||
+			!is_valid_intf_det_low_th(intf_det_low_th) ||
+			!is_valid_intf_det_hgh_th(intf_det_high_th)) {
+			retval = -EINVAL;
+			goto END;
+		}
 		retval = hci_cmd(HCI_FM_GET_STATION_PARAM_CMD, radio->fm_hdev);
 		if (retval < 0) {
 			FMDERR("%s: Failed to determine channel's validity\n",
 				__func__);
-			return retval;
+			goto END;
 		} else
 			sinr = radio->fm_st_rsp.station_rsp.sinr;
 
@@ -3792,7 +4444,7 @@
 		if (retval < 0) {
 			FMDERR("%s: Failed to determine channel's validity\n",
 				 __func__);
-			return retval;
+			goto END;
 		} else
 			intf_det_out = radio->st_dbg_param.in_det_out;
 
@@ -3811,7 +4463,7 @@
 		retval = hci_def_data_read(&rd, radio->fm_hdev);
 		if (retval < 0) {
 			FMDERR("default data read failed %x", retval);
-			return retval;
+			goto END;
 		}
 		wrd.mode = FM_RDS_CNFG_MODE;
 		wrd.length = FM_RDS_CNFG_LEN;
@@ -3832,7 +4484,7 @@
 		retval = hci_def_data_read(&rd, radio->fm_hdev);
 		if (retval < 0) {
 			FMDERR("default data read failed %x", retval);
-			return retval;
+			goto END;
 		}
 		wrd.mode = FM_RDS_CNFG_MODE;
 		wrd.length = FM_RDS_CNFG_LEN;
@@ -3852,7 +4504,7 @@
 		retval = hci_def_data_read(&rd, radio->fm_hdev);
 		if (retval < 0) {
 			FMDERR("default data read failed %x", retval);
-			return retval;
+			goto END;
 		}
 		wrd.mode = FM_RX_CONFG_MODE;
 		wrd.length = FM_RX_CNFG_LEN;
@@ -3872,7 +4524,7 @@
 		retval = hci_def_data_read(&rd, radio->fm_hdev);
 		if (retval < 0) {
 			FMDERR("default data read failed %x", retval);
-			return retval;
+			goto END;
 		}
 		wrd.mode = FM_RX_CONFG_MODE;
 		wrd.length = FM_RX_CNFG_LEN;
@@ -3892,7 +4544,7 @@
 		retval = hci_def_data_read(&rd, radio->fm_hdev);
 		if (retval < 0) {
 			FMDERR("default data read failed %x", retval);
-			return retval;
+			goto END;
 		}
 		wrd.mode = FM_RX_CONFG_MODE;
 		wrd.length = FM_RX_CNFG_LEN;
@@ -3912,7 +4564,7 @@
 		retval = hci_def_data_read(&rd, radio->fm_hdev);
 		if (retval < 0) {
 			FMDERR("default data read failed %x", retval);
-			return retval;
+			goto END;
 		}
 		wrd.mode = FM_RX_CONFG_MODE;
 		wrd.length = FM_RX_CNFG_LEN;
@@ -3932,7 +4584,7 @@
 		retval = hci_def_data_read(&rd, radio->fm_hdev);
 		if (retval < 0) {
 			FMDERR("default data read failed %x", retval);
-			return retval;
+			goto END;
 		}
 		wrd.mode = FM_RX_CONFG_MODE;
 		wrd.length = FM_RX_CNFG_LEN;
@@ -3955,7 +4607,7 @@
 		retval = hci_def_data_read(&rd, radio->fm_hdev);
 		if (retval < 0) {
 			FMDERR("default data read failed for PS0 %x", retval);
-			return retval;
+			goto END;
 		}
 		wrd.mode = RDS_PS0_XFR_MODE;
 		wrd.length = RDS_PS0_LEN;
@@ -3969,7 +4621,13 @@
 		break;
 	default:
 		retval = -EINVAL;
+		break;
 	}
+
+END:
+	if (retval > 0)
+		retval = -EINVAL;
+
 	return retval;
 }
 
@@ -3984,7 +4642,7 @@
 	/* Pass the mode of SPUR_CLK */
 	default_data.mode = CKK_SPUR;
 
-	if (radio == NULL) {
+	if (unlikely(radio == NULL)) {
 		FMDERR(":radio is null");
 		return -EINVAL;
 	}
@@ -4058,10 +4716,14 @@
 	int retval;
 	struct iris_device *radio = video_get_drvdata(video_devdata(file));
 
-	if (radio == NULL) {
+	if (unlikely(radio == NULL)) {
 		FMDERR(":radio is null");
 		return -EINVAL;
 	}
+	if (unlikely(tuner == NULL)) {
+		FMDERR("%s, tuner is null\n", __func__);
+		return -EINVAL;
+	}
 	if (tuner->index > 0) {
 		FMDERR("Invalid Tuner Index");
 		return -EINVAL;
@@ -4106,11 +4768,16 @@
 	struct iris_device *radio = video_get_drvdata(video_devdata(file));
 	int retval = 0;
 
-	if (radio == NULL) {
+	if (unlikely(radio == NULL)) {
 		FMDERR(":radio is null");
 		return -EINVAL;
 	}
 
+	if (unlikely(tuner == NULL)) {
+		FMDERR("%s, tuner is null\n", __func__);
+		return -EINVAL;
+	}
+
 	if (tuner->index > 0)
 		return -EINVAL;
 
@@ -4160,9 +4827,15 @@
 {
 	struct iris_device  *radio = video_get_drvdata(video_devdata(file));
 	int retval = -1;
-	freq->frequency = freq->frequency / TUNE_PARAM;
+	u32 f;
 
-	if (radio == NULL) {
+	if (unlikely(freq == NULL)) {
+		FMDERR("%s, v4l2 freq is null\n", __func__);
+		return -EINVAL;
+	}
+	f = (freq->frequency / TUNE_PARAM);
+
+	if (unlikely(radio == NULL)) {
 		FMDERR(":radio is null");
 		return -EINVAL;
 	}
@@ -4182,7 +4855,7 @@
 				radio->fm_hdev);
 	}
 
-	retval = iris_set_freq(radio, freq->frequency);
+	retval = iris_set_freq(radio, f);
 
 	if (radio->mode == FM_TRANS
 		 && radio->trans_conf.rds_std == 2
@@ -4281,6 +4954,11 @@
 {
 	struct iris_device *radio = video_get_drvdata(video_devdata(file));
 	int dir;
+
+	if (unlikely(seek == NULL)) {
+		FMDERR("%s, v4l2_hw_freq_seek is null\n", __func__);
+		return -EINVAL;
+	}
 	if (seek->seek_upward)
 		dir = SRCH_DIR_UP;
 	else
@@ -4294,10 +4972,14 @@
 	struct iris_device *radio;
 	radio = video_get_drvdata(video_devdata(file));
 
-	if (radio == NULL) {
+	if (unlikely(radio == NULL)) {
 		FMDERR(":radio is null");
 		return -EINVAL;
 	}
+	if (unlikely(capability == NULL)) {
+		FMDERR("%s, capability struct is null\n", __func__);
+		return -EINVAL;
+	}
 	strlcpy(capability->driver, DRIVER_NAME, sizeof(capability->driver));
 	strlcpy(capability->card, DRIVER_CARD, sizeof(capability->card));
 
@@ -4313,7 +4995,7 @@
 {
 	int retval;
 
-	if (radio == NULL) {
+	if (unlikely(radio == NULL)) {
 		FMDERR(":radio is null");
 		return -EINVAL;
 	}
@@ -4357,7 +5039,7 @@
 
 	int retval;
 
-	if (radio == NULL) {
+	if (unlikely(radio == NULL)) {
 		FMDERR(":radio is null");
 		return -EINVAL;
 	}
@@ -4373,7 +5055,7 @@
 {
 	int retval = 1;
 
-	if (radio == NULL) {
+	if (unlikely(radio == NULL)) {
 		FMDERR(":radio is null");
 		return -EINVAL;
 	}
diff --git a/drivers/media/video/v4l2-ioctl.c b/drivers/media/video/v4l2-ioctl.c
index 5b2ec1f..ca28003 100644
--- a/drivers/media/video/v4l2-ioctl.c
+++ b/drivers/media/video/v4l2-ioctl.c
@@ -2348,6 +2348,7 @@
 	int ret = 0;
 
 	switch (cmd) {
+	case VIDIOC_PREPARE_BUF:
 	case VIDIOC_QUERYBUF:
 	case VIDIOC_QBUF:
 	case VIDIOC_DQBUF: {
diff --git a/drivers/media/video/videobuf2-core.c b/drivers/media/video/videobuf2-core.c
index 668cc73..6cea218 100644
--- a/drivers/media/video/videobuf2-core.c
+++ b/drivers/media/video/videobuf2-core.c
@@ -513,13 +513,6 @@
 		return -EINVAL;
 	}
 
-	/*
-	 * If the same number of buffers and memory access method is requested
-	 * then return immediately.
-	 */
-	if (q->memory == req->memory && req->count == q->num_buffers)
-		return 0;
-
 	if (req->count == 0 || q->num_buffers != 0 || q->memory != req->memory) {
 		/*
 		 * We already have buffers allocated, so first check if they
@@ -1104,9 +1097,13 @@
 	 * consistent after getting driver's lock back.
 	 */
 	if (q->memory == V4L2_MEMORY_USERPTR) {
-		mmap_sem = &current->active_mm->mmap_sem;
+		bool mm_exists = !!current->mm;
+
+		mmap_sem = mm_exists ? &current->mm->mmap_sem : NULL;
 		call_qop(q, wait_prepare, q);
-		down_read(mmap_sem);
+		/* kthreads have no userspace, hence no pages to lock */
+		if (mmap_sem)
+			down_read(mmap_sem);
 		call_qop(q, wait_finish, q);
 	}
 
diff --git a/drivers/mfd/wcd9xxx-core-resource.c b/drivers/mfd/wcd9xxx-core-resource.c
index 1791d72..1d0f894 100644
--- a/drivers/mfd/wcd9xxx-core-resource.c
+++ b/drivers/mfd/wcd9xxx-core-resource.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
@@ -55,6 +55,8 @@
 	int (*codec_read)(struct wcd9xxx_core_resource*, unsigned short),
 	int (*codec_write)(struct wcd9xxx_core_resource*, unsigned short, u8),
 	int (*codec_bulk_read) (struct wcd9xxx_core_resource*, unsigned short,
+							int, u8*),
+	int (*codec_bulk_write) (struct wcd9xxx_core_resource*, unsigned short,
 							int, u8*))
 {
 	mutex_init(&wcd9xxx_core_res->pm_lock);
@@ -68,6 +70,7 @@
 	wcd9xxx_core_res->codec_reg_read = codec_read;
 	wcd9xxx_core_res->codec_reg_write = codec_write;
 	wcd9xxx_core_res->codec_bulk_read = codec_bulk_read;
+	wcd9xxx_core_res->codec_bulk_write = codec_bulk_write;
 	wcd9xxx_core_res->num_irqs = num_irqs;
 	wcd9xxx_core_res->num_irq_regs = num_irq_regs;
 
diff --git a/drivers/mfd/wcd9xxx-core.c b/drivers/mfd/wcd9xxx-core.c
index 907ce7c..156ce24 100644
--- a/drivers/mfd/wcd9xxx-core.c
+++ b/drivers/mfd/wcd9xxx-core.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
@@ -555,7 +555,6 @@
 	{WCD9XXX_IRQ_EAR_PA_OCPL_FAULT, false},
 	{WCD9XXX_IRQ_HPH_L_PA_STARTUP, false},
 	{WCD9XXX_IRQ_HPH_R_PA_STARTUP, false},
-	{WCD9320_IRQ_EAR_PA_STARTUP, false},
 	{WCD9XXX_IRQ_RESERVED_0, false},
 	{WCD9XXX_IRQ_RESERVED_1, false},
 	{WCD9XXX_IRQ_MAD_AUDIO, false},
@@ -605,7 +604,7 @@
 				wcd9xxx->codec_type->num_irqs,
 				wcd9xxx_num_irq_regs(wcd9xxx),
 				wcd9xxx_reg_read, wcd9xxx_reg_write,
-				wcd9xxx_bulk_read);
+				wcd9xxx_bulk_read, wcd9xxx_bulk_write);
 
 	if (wcd9xxx_core_irq_init(&wcd9xxx->core_res))
 		goto err;
@@ -1673,10 +1672,8 @@
 		wcd9xxx->slim_device_bootup = false;
 		return 0;
 	}
-	ret = wcd9xxx_reset(wcd9xxx);
-	if (ret)
-		pr_err("%s: Resetting Codec failed\n", __func__);
 
+	dev_info(wcd9xxx->dev, "%s: codec bring up\n", __func__);
 	wcd9xxx_bring_up(wcd9xxx);
 	ret = wcd9xxx_irq_init(wcd9xxx_res);
 	if (ret) {
@@ -1688,6 +1685,25 @@
 	return ret;
 }
 
+static int wcd9xxx_slim_device_reset(struct slim_device *sldev)
+{
+	int ret;
+	struct wcd9xxx *wcd9xxx = slim_get_devicedata(sldev);
+	if (!wcd9xxx) {
+		pr_err("%s: wcd9xxx is NULL\n", __func__);
+		return -EINVAL;
+	}
+
+	dev_info(wcd9xxx->dev, "%s: device reset\n", __func__);
+	if (wcd9xxx->slim_device_bootup)
+		return 0;
+	ret = wcd9xxx_reset(wcd9xxx);
+	if (ret)
+		dev_err(wcd9xxx->dev, "%s: Resetting Codec failed\n", __func__);
+
+	return ret;
+}
+
 static int wcd9xxx_slim_device_up(struct slim_device *sldev)
 {
 	struct wcd9xxx *wcd9xxx = slim_get_devicedata(sldev);
@@ -1695,7 +1711,7 @@
 		pr_err("%s: wcd9xxx is NULL\n", __func__);
 		return -EINVAL;
 	}
-	dev_dbg(wcd9xxx->dev, "%s: device up\n", __func__);
+	dev_info(wcd9xxx->dev, "%s: slim device up\n", __func__);
 	return wcd9xxx_device_up(wcd9xxx);
 }
 
@@ -1826,6 +1842,7 @@
 	.resume = wcd9xxx_slim_resume,
 	.suspend = wcd9xxx_slim_suspend,
 	.device_up = wcd9xxx_slim_device_up,
+	.reset_device = wcd9xxx_slim_device_reset,
 	.device_down = wcd9xxx_slim_device_down,
 };
 
@@ -1845,6 +1862,7 @@
 	.resume = wcd9xxx_slim_resume,
 	.suspend = wcd9xxx_slim_suspend,
 	.device_up = wcd9xxx_slim_device_up,
+	.reset_device = wcd9xxx_slim_device_reset,
 	.device_down = wcd9xxx_slim_device_down,
 };
 
diff --git a/drivers/mfd/wcd9xxx-irq.c b/drivers/mfd/wcd9xxx-irq.c
index 9209f0b..d9cf60a 100644
--- a/drivers/mfd/wcd9xxx-irq.c
+++ b/drivers/mfd/wcd9xxx-irq.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
@@ -316,10 +316,12 @@
 		}
 
 		memset(status, 0xff, num_irq_regs);
-		wcd9xxx_bulk_write(wcd9xxx_res, WCD9XXX_A_INTR_CLEAR0,
-				   num_irq_regs, status);
+
+		ret = wcd9xxx_res->codec_bulk_write(wcd9xxx_res,
+				WCD9XXX_A_INTR_CLEAR0,
+				num_irq_regs, status);
 		if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_I2C)
-			wcd9xxx_reg_write(wcd9xxx_res,
+			wcd9xxx_res->codec_reg_write(wcd9xxx_res,
 					WCD9XXX_A_INTR_MODE, 0x02);
 	}
 	wcd9xxx_unlock_sleep(wcd9xxx_res);
@@ -613,6 +615,10 @@
 static int virq_to_phyirq(struct wcd9xxx_core_resource *wcd9xxx_res, int virq)
 {
 	struct irq_data *irq_data = irq_get_irq_data(virq);
+	if (unlikely(!irq_data)) {
+		pr_err("%s: irq_data is NULL", __func__);
+		return -EINVAL;
+	}
 	return irq_data->hwirq;
 }
 
@@ -662,6 +668,10 @@
 	} else {
 		dev_dbg(&pdev->dev, "%s: virq = %d\n", __func__, irq);
 		domain = irq_find_host(pdev->dev.of_node);
+		if (unlikely(!domain)) {
+			pr_err("%s: domain is NULL", __func__);
+			return -EINVAL;
+		}
 		data = (struct wcd9xxx_irq_drv_data *)domain->host_data;
 		data->irq = irq;
 		wmb();
@@ -677,6 +687,10 @@
 	struct wcd9xxx_irq_drv_data *data;
 
 	domain = irq_find_host(pdev->dev.of_node);
+	if (unlikely(!domain)) {
+		pr_err("%s: domain is NULL", __func__);
+		return -EINVAL;
+	}
 	data = (struct wcd9xxx_irq_drv_data *)domain->host_data;
 	data->irq = 0;
 	wmb();
diff --git a/drivers/mfd/wcd9xxx-slimslave.c b/drivers/mfd/wcd9xxx-slimslave.c
index 81262b58..4f42181 100644
--- a/drivers/mfd/wcd9xxx-slimslave.c
+++ b/drivers/mfd/wcd9xxx-slimslave.c
@@ -499,7 +499,8 @@
 
 /* This function is called with mutex acquired */
 int wcd9xxx_tx_vport_validation(u32 vtable, u32 port_id,
-				struct wcd9xxx_codec_dai_data *codec_dai)
+				struct wcd9xxx_codec_dai_data *codec_dai,
+				u32 num_codec_dais)
 {
 	struct wcd9xxx_ch *ch;
 	int ret = 0;
@@ -508,18 +509,25 @@
 	pr_debug("%s: vtable 0x%x port_id %u size %d\n", __func__,
 		 vtable, port_id, size);
 	for_each_set_bit(index, (unsigned long *)&vtable, size) {
-		list_for_each_entry(ch,
-				    &codec_dai[index].wcd9xxx_ch_list,
-				    list) {
-			pr_debug("%s: index %u ch->port %u vtable 0x%x\n",
-				 __func__, index, ch->port, vtable);
-			if (ch->port == port_id) {
-				pr_err("%s: TX%u is used by AIF%u_CAP Mixer\n",
-					__func__, port_id + 1,
-					(index + 1)/2);
-				ret = -EINVAL;
-				break;
+		if (index < num_codec_dais) {
+			list_for_each_entry(ch,
+					&codec_dai[index].wcd9xxx_ch_list,
+					list) {
+				pr_debug("%s: index %u ch->port %u vtable 0x%x\n",
+						__func__, index, ch->port,
+						vtable);
+				if (ch->port == port_id) {
+					pr_err("%s: TX%u is used by AIF%u_CAP Mixer\n",
+							__func__, port_id + 1,
+							(index + 1)/2);
+					ret = -EINVAL;
+					break;
+				}
 			}
+		} else {
+			pr_err("%s: Invalid index %d of codec dai",
+					__func__, index);
+			ret = -EINVAL;
 		}
 		if (ret)
 			break;
diff --git a/drivers/misc/isa1200.c b/drivers/misc/isa1200.c
index 8090b95..d7fa87b 100644
--- a/drivers/misc/isa1200.c
+++ b/drivers/misc/isa1200.c
@@ -3,7 +3,7 @@
  *
  *  Copyright (C) 2009 Samsung Electronics
  *  Kyungmin Park <kyungmin.park@samsung.com>
- *  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 as
@@ -318,7 +318,7 @@
 
 	value |= (haptic->pdata->mode_ctrl << 3) |
 		(haptic->pdata->overdrive_high << 5) |
-		(haptic->pdata->overdrive_en << 5) |
+		(haptic->pdata->overdrive_en << 6) |
 		(haptic->pdata->chip_en << 7);
 
 	rc = isa1200_write_reg(client, ISA1200_HCTRL0, value);
diff --git a/drivers/misc/qfp_fuse.c b/drivers/misc/qfp_fuse.c
index 3a088dc..f271f96 100644
--- a/drivers/misc/qfp_fuse.c
+++ b/drivers/misc/qfp_fuse.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, 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
@@ -28,7 +28,7 @@
 /*
  * Time QFPROM requires to reliably burn a fuse.
  */
-#define QFPROM_BLOW_TIMEOUT_US      10
+#define QFPROM_BLOW_TIMEOUT_US      20
 #define QFPROM_BLOW_TIMER_OFFSET    0x2038
 /*
  * Denotes number of cycles required to blow the fuse.
@@ -42,6 +42,10 @@
 #define QFP_FUSE_READY              0x01
 #define QFP_FUSE_OFF                0x00
 
+#define QFP_FUSE_BUF_SIZE           64
+#define UINT32_MAX                  (0xFFFFFFFFU)
+
+
 struct qfp_priv_t {
 	uint32_t base;
 	uint32_t end;
@@ -53,6 +57,23 @@
 /* We need only one instance of this for the driver */
 static struct qfp_priv_t *qfp_priv;
 
+static inline bool is_usr_req_valid(const struct qfp_fuse_req *req)
+{
+	uint32_t size = qfp_priv->end - qfp_priv->base;
+	uint32_t req_size;
+
+	if (req->size >= (UINT32_MAX / sizeof(uint32_t)))
+		return false;
+	req_size = req->size * sizeof(uint32_t);
+	if ((req_size == 0) || (req_size > size))
+		return false;
+	if (req->offset >= size)
+		return false;
+	if ((req->offset + req_size) > size)
+		return false;
+
+	return true;
+}
 
 static int qfp_fuse_open(struct inode *inode, struct file *filp)
 {
@@ -177,7 +198,9 @@
 {
 	int err = 0;
 	struct qfp_fuse_req req;
-	u32 *buf = NULL;
+	u32 fuse_buf[QFP_FUSE_BUF_SIZE];
+	u32 *buf = fuse_buf;
+	u32 *ptr = NULL;
 	int i;
 
 	/* Verify user arguments. */
@@ -199,25 +222,21 @@
 		}
 
 		/* Check for limits */
-		if (!req.size) {
-			pr_err("Request size zero.\n");
-			err = -EFAULT;
+		if (is_usr_req_valid(&req) == false) {
+			pr_err("Invalid request\n");
+			err = -EINVAL;
 			break;
 		}
 
-		if (qfp_priv->base + req.offset + (req.size - 1) * 4 >
-				qfp_priv->end) {
-			pr_err("Req size exceeds QFPROM addr space\n");
-			err = -EFAULT;
-			break;
-		}
-
-		/* Allocate memory for buffer */
-		buf = kzalloc(req.size * 4, GFP_KERNEL);
-		if (buf == NULL) {
-			pr_alert("No memory for data\n");
-			err = -ENOMEM;
-			break;
+		if (req.size > QFP_FUSE_BUF_SIZE) {
+			/* Allocate memory for buffer */
+			ptr = kzalloc(req.size * 4, GFP_KERNEL);
+			if (ptr == NULL) {
+				pr_alert("No memory for data\n");
+				err = -ENOMEM;
+				break;
+			}
+			buf = ptr;
 		}
 
 		if (mutex_lock_interruptible(&qfp_priv->lock)) {
@@ -251,24 +270,21 @@
 			break;
 		}
 		/* Check for limits */
-		if (!req.size) {
-			pr_err("Request size zero.\n");
-			err = -EFAULT;
-			break;
-		}
-		if (qfp_priv->base + req.offset + (req.size - 1) * 4 >
-				qfp_priv->end) {
-			pr_err("Req size exceeds QFPROM space\n");
-			err = -EFAULT;
+		if (is_usr_req_valid(&req) == false) {
+			pr_err("Invalid request\n");
+			err = -EINVAL;
 			break;
 		}
 
-		/* Allocate memory for buffer */
-		buf = kzalloc(4 * (req.size), GFP_KERNEL);
-		if (buf == NULL) {
-			pr_alert("No memory for data\n");
-			err = -ENOMEM;
-			break;
+		if (req.size > QFP_FUSE_BUF_SIZE) {
+			/* Allocate memory for buffer */
+			ptr = kzalloc(req.size * 4, GFP_KERNEL);
+			if (ptr == NULL) {
+				pr_alert("No memory for data\n");
+				err = -ENOMEM;
+				break;
+			}
+			buf = ptr;
 		}
 
 		/* Copy user data to local buffer */
@@ -296,7 +312,7 @@
 		pr_err("Invalid ioctl command.\n");
 		return -ENOTTY;
 	}
-	kfree(buf);
+	kfree(ptr);
 	return err;
 }
 
diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c
index 0bc18fb..23edc8a 100644
--- a/drivers/misc/qseecom.c
+++ b/drivers/misc/qseecom.c
@@ -1,6 +1,6 @@
 /*Qualcomm Secure Execution Environment Communicator (QSEECOM) driver
  *
- * 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
@@ -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
@@ -71,6 +71,9 @@
 
 #define RPMB_SERVICE			0x2000
 
+#define QSEECOM_SEND_CMD_CRYPTO_TIMEOUT	2000
+#define QSEECOM_LOAD_APP_CRYPTO_TIMEOUT	2000
+
 enum qseecom_clk_definitions {
 	CLK_DFAB = 0,
 	CLK_SFPB,
@@ -99,7 +102,7 @@
 struct qseecom_registered_listener_list {
 	struct list_head                 list;
 	struct qseecom_register_listener_req svc;
-	u8  *sb_reg_req;
+	uint32_t user_virt_sb_base;
 	u8 *sb_virt;
 	s32 sb_phys;
 	size_t sb_length;
@@ -124,6 +127,7 @@
 	uint32_t  qsee_ce_hw_instance;
 	uint32_t  hlos_ce_hw_instance;
 	uint32_t  disk_encrypt_pipe;
+	uint32_t  file_encrypt_pipe;
 };
 
 struct qseecom_clk {
@@ -153,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;
@@ -161,7 +166,16 @@
 	uint32_t qsee_perf_client;
 	struct qseecom_clk qsee;
 	struct qseecom_clk ce_drv;
+
+	bool support_bus_scaling;
+	bool support_fde;
+	bool support_pfe;
+	uint32_t  cumulative_mode;
+	enum qseecom_bandwidth_request_mode  current_mode;
+	struct timer_list bw_scale_down_timer;
+	struct work_struct bw_inactive_req_ws;
 	struct cdev cdev;
+	bool timer_running;
 };
 
 struct qseecom_client_handle {
@@ -191,6 +205,7 @@
 	atomic_t          ioctl_count;
 	bool  perf_enabled;
 	bool  fast_load_enabled;
+	enum qseecom_bandwidth_request_mode mode;
 };
 
 enum qseecom_set_clear_key_flag {
@@ -212,6 +227,24 @@
 	uint32_t len;
 };
 
+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 */
 static int qsee_vote_for_clock(struct qseecom_dev_handle *, int32_t);
 static void qsee_disable_clock_vote(struct qseecom_dev_handle *, int32_t);
@@ -272,14 +305,18 @@
 	/* Get the handle of the shared fd */
 	svc->ihandle = ion_import_dma_buf(qseecom.ion_clnt,
 					listener->ifd_data_fd);
-	if (svc->ihandle == NULL) {
+	if (IS_ERR_OR_NULL(svc->ihandle)) {
 		pr_err("Ion client could not retrieve the handle\n");
 		return -ENOMEM;
 	}
 
 	/* 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;
@@ -319,6 +356,10 @@
 		pr_err("copy_from_user failed\n");
 		return ret;
 	}
+	if (!access_ok(VERIFY_WRITE, (void __user *)rcvd_lstnr.virt_sb_base,
+			rcvd_lstnr.sb_size))
+		return -EFAULT;
+
 	data->listener.id = 0;
 	if (!__qseecom_is_svc_unique(data, &rcvd_lstnr)) {
 		pr_err("Service is not unique and is already registered\n");
@@ -336,6 +377,7 @@
 
 	new_entry->svc.listener_id = rcvd_lstnr.listener_id;
 	new_entry->sb_length = rcvd_lstnr.sb_size;
+	new_entry->user_virt_sb_base = rcvd_lstnr.virt_sb_base;
 	if (__qseecom_set_sb_memory(new_entry, data, &rcvd_lstnr)) {
 		pr_err("qseecom_set_sb_memoryfailed\n");
 		kzfree(new_entry);
@@ -428,6 +470,208 @@
 	return ret;
 }
 
+static int __qseecom_set_msm_bus_request(uint32_t mode)
+{
+	int ret = 0;
+	struct qseecom_clk *qclk;
+
+	qclk = &qseecom.qsee;
+	if (qclk->ce_core_src_clk != NULL) {
+		if (mode == INACTIVE) {
+			__qseecom_disable_clk(CLK_QSEE);
+		} else {
+			ret = __qseecom_enable_clk(CLK_QSEE);
+			if (ret)
+				pr_err("CLK enabling failed (%d) MODE (%d)\n",
+							ret, mode);
+		}
+	}
+
+	if ((!ret) && (qseecom.current_mode != mode)) {
+		ret = msm_bus_scale_client_update_request(
+					qseecom.qsee_perf_client, mode);
+		if (ret) {
+			pr_err("Bandwidth req failed(%d) MODE (%d)\n",
+							ret, mode);
+			if (qclk->ce_core_src_clk != NULL) {
+				if (mode == INACTIVE)
+					__qseecom_enable_clk(CLK_QSEE);
+				else
+					__qseecom_disable_clk(CLK_QSEE);
+			}
+		}
+		qseecom.current_mode = mode;
+	}
+	return ret;
+}
+
+static void qseecom_bw_inactive_req_work(struct work_struct *work)
+{
+	mutex_lock(&app_access_lock);
+	mutex_lock(&qsee_bw_mutex);
+	__qseecom_set_msm_bus_request(INACTIVE);
+	pr_debug("current_mode = %d, cumulative_mode = %d\n",
+				qseecom.current_mode, qseecom.cumulative_mode);
+	qseecom.timer_running = false;
+	mutex_unlock(&qsee_bw_mutex);
+	mutex_unlock(&app_access_lock);
+	return;
+}
+
+static void qseecom_scale_bus_bandwidth_timer_callback(unsigned long data)
+{
+	schedule_work(&qseecom.bw_inactive_req_ws);
+	return;
+}
+
+static int __qseecom_decrease_clk_ref_count(enum qseecom_ce_hw_instance ce)
+{
+	struct qseecom_clk *qclk;
+	int ret = 0;
+	mutex_lock(&clk_access_lock);
+	if (ce == CLK_QSEE)
+		qclk = &qseecom.qsee;
+	else
+		qclk = &qseecom.ce_drv;
+
+	if (qclk->clk_access_cnt > 2) {
+		pr_err("Invalid clock ref count %d\n", qclk->clk_access_cnt);
+		ret = -EINVAL;
+		goto err_dec_ref_cnt;
+	}
+	if (qclk->clk_access_cnt == 2)
+		qclk->clk_access_cnt--;
+
+err_dec_ref_cnt:
+	mutex_unlock(&clk_access_lock);
+	return ret;
+}
+
+
+static int qseecom_scale_bus_bandwidth_timer(uint32_t mode)
+{
+	int32_t ret = 0;
+	int32_t request_mode = INACTIVE;
+
+	mutex_lock(&qsee_bw_mutex);
+	if (mode == 0) {
+		if (qseecom.cumulative_mode > MEDIUM)
+			request_mode = HIGH;
+		else
+			request_mode = qseecom.cumulative_mode;
+	} else {
+		request_mode = mode;
+	}
+
+	ret = __qseecom_set_msm_bus_request(request_mode);
+	if (ret) {
+		pr_err("set msm bus request failed (%d),request_mode (%d)\n",
+			ret, request_mode);
+		goto err_scale_timer;
+	}
+
+	if (qseecom.timer_running) {
+		ret = __qseecom_decrease_clk_ref_count(CLK_QSEE);
+		if (ret) {
+			pr_err("Failed to decrease clk ref count.\n");
+			goto err_scale_timer;
+		}
+		del_timer_sync(&(qseecom.bw_scale_down_timer));
+		qseecom.timer_running = false;
+	}
+err_scale_timer:
+	mutex_unlock(&qsee_bw_mutex);
+	return ret;
+}
+
+
+static int qseecom_unregister_bus_bandwidth_needs(
+					struct qseecom_dev_handle *data)
+{
+	int32_t ret = 0;
+
+	qseecom.cumulative_mode -= data->mode;
+	data->mode = INACTIVE;
+
+	return ret;
+}
+
+static int __qseecom_register_bus_bandwidth_needs(
+			struct qseecom_dev_handle *data, uint32_t request_mode)
+{
+	int32_t ret = 0;
+
+	if (data->mode == INACTIVE) {
+		qseecom.cumulative_mode += request_mode;
+		data->mode = request_mode;
+	} else {
+		if (data->mode != request_mode) {
+			qseecom.cumulative_mode -= data->mode;
+			qseecom.cumulative_mode += request_mode;
+			data->mode = request_mode;
+		}
+	}
+	return ret;
+}
+
+static int qseecom_scale_bus_bandwidth(struct qseecom_dev_handle *data,
+						void __user *argp)
+{
+	int32_t ret = 0;
+	int32_t req_mode;
+
+	ret = copy_from_user(&req_mode, argp, sizeof(req_mode));
+	if (ret) {
+		pr_err("copy_from_user failed\n");
+		return ret;
+	}
+	if (req_mode > HIGH) {
+		pr_err("Invalid bandwidth mode (%d)\n", req_mode);
+		return ret;
+	}
+	mutex_lock(&qsee_bw_mutex);
+	ret = __qseecom_register_bus_bandwidth_needs(data, req_mode);
+	mutex_unlock(&qsee_bw_mutex);
+
+	return ret;
+}
+
+static void __qseecom_add_bw_scale_down_timer(uint32_t duration)
+{
+	mutex_lock(&qsee_bw_mutex);
+	qseecom.bw_scale_down_timer.expires = jiffies +
+		msecs_to_jiffies(duration);
+	mod_timer(&(qseecom.bw_scale_down_timer),
+		qseecom.bw_scale_down_timer.expires);
+	qseecom.timer_running = true;
+	mutex_unlock(&qsee_bw_mutex);
+}
+
+static void __qseecom_disable_clk_scale_down(struct qseecom_dev_handle *data)
+{
+	if (!qseecom.support_bus_scaling)
+		qsee_disable_clock_vote(data, CLK_SFPB);
+	else
+		__qseecom_add_bw_scale_down_timer(
+			QSEECOM_LOAD_APP_CRYPTO_TIMEOUT);
+	return;
+}
+
+static int __qseecom_enable_clk_scale_up(struct qseecom_dev_handle *data)
+{
+	int ret = 0;
+	if (qseecom.support_bus_scaling) {
+		ret = qseecom_scale_bus_bandwidth_timer(MEDIUM);
+		if (ret)
+			pr_err("Failed to set bw MEDIUM.\n");
+	} else {
+		ret = qsee_vote_for_clock(data, CLK_SFPB);
+		if (ret)
+			pr_err("Fail vote for clk SFPB ret %d\n", ret);
+	}
+	return ret;
+}
+
 static int qseecom_set_client_mem_param(struct qseecom_dev_handle *data,
 						void __user *argp)
 {
@@ -446,6 +690,10 @@
 			req.ifd_data_fd, req.sb_len, req.virt_sb_base);
 		return -EFAULT;
 	}
+	if (!access_ok(VERIFY_WRITE, (void __user *)req.virt_sb_base,
+			req.sb_len))
+		return -EFAULT;
+
 	/* Get the handle of the shared fd */
 	data->client.ihandle = ion_import_dma_buf(qseecom.ion_clnt,
 						req.ifd_data_fd);
@@ -455,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);
@@ -613,7 +867,7 @@
 	u32 app_id = 0;
 	struct ion_handle *ihandle;	/* Ion handle */
 	struct qseecom_load_img_req load_img_req;
-	int32_t ret;
+	int32_t ret = 0;
 	ion_phys_addr_t pa = 0;
 	uint32_t len;
 	struct qseecom_command_scm_resp resp;
@@ -627,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 = qsee_vote_for_clock(data, CLK_SFPB);
+	ret = __qseecom_enable_clk_scale_up(data);
 	if (ret)
-		pr_warning("Unable to vote for SFPB clock");
+		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) {
-		qsee_disable_clock_vote(data, CLK_SFPB);
-		return ret;
-	}
+	if (ret < 0)
+		goto loadapp_err;
 
 	app_id = ret;
 	if (app_id) {
@@ -663,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");
-			qsee_disable_clock_vote(data, CLK_SFPB);
-			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,
@@ -688,16 +955,16 @@
 			pr_err("scm_call to load app failed\n");
 			if (!IS_ERR_OR_NULL(ihandle))
 				ion_free(qseecom.ion_clnt, ihandle);
-			qsee_disable_clock_vote(data, CLK_SFPB);
-			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);
-			qsee_disable_clock_vote(data, CLK_SFPB);
-			return -EFAULT;
+			ret = -EFAULT;
+			goto loadapp_err;
 		}
 
 		if (resp.result == QSEOS_RESULT_INCOMPLETE) {
@@ -707,8 +974,8 @@
 					ret);
 				if (!IS_ERR_OR_NULL(ihandle))
 					ion_free(qseecom.ion_clnt, ihandle);
-				qsee_disable_clock_vote(data, CLK_SFPB);
-				return ret;
+				ret = -EFAULT;
+				goto loadapp_err;
 			}
 		}
 
@@ -717,8 +984,8 @@
 				resp.result);
 			if (!IS_ERR_OR_NULL(ihandle))
 				ion_free(qseecom.ion_clnt, ihandle);
-			qsee_disable_clock_vote(data, CLK_SFPB);
-			return -EFAULT;
+			ret = -EFAULT;
+			goto loadapp_err;
 		}
 
 		app_id = resp.data;
@@ -726,8 +993,8 @@
 		entry = kmalloc(sizeof(*entry), GFP_KERNEL);
 		if (!entry) {
 			pr_err("kmalloc failed\n");
-			qsee_disable_clock_vote(data, CLK_SFPB);
-			return -ENOMEM;
+			ret = -ENOMEM;
+			goto loadapp_err;
 		}
 		entry->app_id = app_id;
 		entry->ref_cnt = 1;
@@ -749,11 +1016,18 @@
 	if (copy_to_user(argp, &load_img_req, sizeof(load_img_req))) {
 		pr_err("copy_to_user failed\n");
 		kzfree(entry);
-		qsee_disable_clock_vote(data, CLK_SFPB);
-		return -EFAULT;
+		ret = -EFAULT;
 	}
-	qsee_disable_clock_vote(data, CLK_SFPB);
-	return 0;
+
+loadapp_err:
+	__qseecom_disable_clk_scale_down(data);
+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)
@@ -782,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;
@@ -794,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;
+					}
 				}
 			}
 		}
@@ -812,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;
 		}
 	}
@@ -836,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);
@@ -845,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;
 			}
 		}
@@ -861,6 +1142,13 @@
 	return data->client.sb_phys + (virt - data->client.user_virt_sb_base);
 }
 
+static uint32_t __qseecom_uvirt_to_kvirt(struct qseecom_dev_handle *data,
+						uint32_t virt)
+{
+	return (uint32_t)data->client.sb_virt +
+				(virt - data->client.user_virt_sb_base);
+}
+
 int __qseecom_process_rpmb_svc_cmd(struct qseecom_dev_handle *data_ptr,
 		struct qseecom_send_svc_cmd_req *req_ptr,
 		struct qseecom_client_send_service_ireq *send_svc_ireq_ptr)
@@ -879,16 +1167,13 @@
 		return -EINVAL;
 	}
 
-	if (((uint32_t)req_ptr->cmd_req_buf <
-			data_ptr->client.user_virt_sb_base)
-			|| ((uint32_t)req_ptr->cmd_req_buf >=
-			(data_ptr->client.user_virt_sb_base +
-			data_ptr->client.sb_length))) {
-		pr_err("cmd buffer address not within shared bufffer\n");
+	/* Clients need to ensure req_buf is at base offset of shared buffer */
+	if ((uint32_t)req_ptr->cmd_req_buf !=
+			data_ptr->client.user_virt_sb_base) {
+		pr_err("cmd buf not pointing to base offset of shared buffer\n");
 		return -EINVAL;
 	}
 
-
 	if (((uint32_t)req_ptr->resp_buf < data_ptr->client.user_virt_sb_base)
 			|| ((uint32_t)req_ptr->resp_buf >=
 			(data_ptr->client.user_virt_sb_base +
@@ -907,8 +1192,6 @@
 					(uint32_t)req_ptr->resp_buf));
 	send_svc_ireq_ptr->rsp_len = req_ptr->resp_len;
 
-	pr_debug("CMD ID (%x), KEY_TYPE (%d)\n", send_svc_ireq_ptr->qsee_cmd_id,
-	((struct qseecom_rpmb_provision_key *)req_ptr->cmd_req_buf)->key_type);
 	return ret;
 }
 
@@ -933,6 +1216,23 @@
 		return -EINVAL;
 	}
 
+	if (data->client.sb_virt == NULL) {
+		pr_err("sb_virt null\n");
+		return -EINVAL;
+	}
+
+	if (data->client.user_virt_sb_base == 0) {
+		pr_err("user_virt_sb_base is null\n");
+		return -EINVAL;
+	}
+
+	if (data->client.sb_length == 0) {
+		pr_err("sb_length is 0\n");
+		return -EINVAL;
+	}
+
+	data->type = QSEECOM_SECURE_SERVICE;
+
 	switch (req.cmd_id) {
 	case QSEOS_RPMB_PROVISION_KEY_COMMAND:
 	case QSEOS_RPMB_ERASE_COMMAND:
@@ -945,15 +1245,24 @@
 		return -EINVAL;
 	}
 
-	ret = qsee_vote_for_clock(data, CLK_DFAB);
-	if (ret) {
-		pr_err("Failed to vote for DFAB clock%d\n", ret);
-		return ret;
-	}
-	ret = qsee_vote_for_clock(data, CLK_SFPB);
-	if (ret) {
-		pr_err("Failed to vote for SFPB clock%d\n", ret);
-		goto exit_reset_dfab_freq;
+	if (qseecom.support_bus_scaling) {
+		ret = qseecom_scale_bus_bandwidth_timer(HIGH);
+		if (ret) {
+			pr_err("Fail to set bw HIGH\n");
+			return ret;
+		}
+	} else {
+		ret = qsee_vote_for_clock(data, CLK_DFAB);
+		if (ret) {
+			pr_err("Failed to vote for DFAB clock%d\n", ret);
+			return ret;
+		}
+		ret = qsee_vote_for_clock(data, CLK_SFPB);
+		if (ret) {
+			qsee_disable_clock_vote(data, CLK_DFAB);
+			pr_err("Failed to vote for SFPB clock%d\n", ret);
+			goto exit;
+		}
 	}
 
 	msm_ion_do_cache_op(qseecom.ion_clnt, data->client.ihandle,
@@ -967,7 +1276,14 @@
 				ION_IOC_INV_CACHES);
 	if (ret) {
 		pr_err("qseecom_scm_call failed with err: %d\n", ret);
-		goto exit_reset_sdfab_freq;
+		if (!qseecom.support_bus_scaling) {
+			qsee_disable_clock_vote(data, CLK_DFAB);
+			qsee_disable_clock_vote(data, CLK_SFPB);
+		} else {
+			__qseecom_add_bw_scale_down_timer(
+				QSEECOM_SEND_CMD_CRYPTO_TIMEOUT);
+		}
+		goto exit;
 	}
 
 	switch (resp.result) {
@@ -990,10 +1306,15 @@
 		ret = -EINVAL;
 		break;
 	}
-exit_reset_sdfab_freq:
-	qsee_disable_clock_vote(data, CLK_SFPB);
-exit_reset_dfab_freq:
-	qsee_disable_clock_vote(data, CLK_DFAB);
+	if (!qseecom.support_bus_scaling) {
+		qsee_disable_clock_vote(data, CLK_DFAB);
+		qsee_disable_clock_vote(data, CLK_SFPB);
+	} else {
+		__qseecom_add_bw_scale_down_timer(
+			QSEECOM_SEND_CMD_CRYPTO_TIMEOUT);
+	}
+
+exit:
 	return ret;
 }
 
@@ -1105,26 +1426,6 @@
 	return ret;
 }
 
-static int qseecom_unprotect_buffer(void __user *argp)
-{
-	int ret = 0;
-	struct ion_handle *ihandle;
-	int32_t ion_fd;
-
-	ret = copy_from_user(&ion_fd, argp, sizeof(ion_fd));
-	if (ret) {
-		pr_err("copy_from_user failed");
-		return ret;
-	}
-
-	ihandle = ion_import_dma_buf(qseecom.ion_clnt, ion_fd);
-
-	ret = msm_ion_unsecure_buffer(qseecom.ion_clnt, ihandle);
-	if (ret)
-		return -EINVAL;
-	return 0;
-}
-
 static int __qseecom_update_cmd_buf(void *msg, bool cleanup,
 					struct qseecom_dev_handle *data,
 					bool listener_svc)
@@ -1173,21 +1474,6 @@
 				pr_err("Ion client can't retrieve the handle\n");
 				return -ENOMEM;
 			}
-			switch (lstnr_resp->protection_mode) {
-			case QSEOS_PROTECT_BUFFER:
-				 ret = msm_ion_secure_buffer(qseecom.ion_clnt,
-								ihandle,
-								VIDEO_PIXEL,
-								0);
-				break;
-			case QSEOS_UNPROTECT_PROTECTED_BUFFER:
-				ret = msm_ion_unsecure_buffer(qseecom.ion_clnt,
-								ihandle);
-				break;
-			case QSEOS_UNPROTECTED_BUFFER:
-			default:
-				break;
-			}
 			field = lstnr_resp->resp_buf_ptr +
 				lstnr_resp->ifd_data[i].cmd_buf_offset;
 		} else {
@@ -1269,6 +1555,31 @@
 		pr_err("copy_from_user failed\n");
 		return ret;
 	}
+
+	if (req.cmd_req_buf == NULL || req.resp_buf == NULL) {
+		pr_err("cmd buffer or response buffer is null\n");
+		return -EINVAL;
+	}
+	if (((uint32_t)req.cmd_req_buf < data->client.user_virt_sb_base) ||
+		((uint32_t)req.cmd_req_buf >= (data->client.user_virt_sb_base +
+					data->client.sb_length))) {
+		pr_err("cmd buffer address not within shared bufffer\n");
+		return -EINVAL;
+	}
+
+	if (((uint32_t)req.resp_buf < data->client.user_virt_sb_base)  ||
+		((uint32_t)req.resp_buf >= (data->client.user_virt_sb_base +
+					data->client.sb_length))){
+		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;
@@ -1282,6 +1593,11 @@
 			return -EINVAL;
 		}
 	}
+	req.cmd_req_buf = (void *)__qseecom_uvirt_to_kvirt(data,
+						(uint32_t)req.cmd_req_buf);
+	req.resp_buf = (void *)__qseecom_uvirt_to_kvirt(data,
+						(uint32_t)req.resp_buf);
+
 	ret = __qseecom_update_cmd_buf(&req, false, data, false);
 	if (ret)
 		return ret;
@@ -1318,7 +1634,7 @@
 		if (wait_event_freezable(this_lstnr->rcv_req_wq,
 				__qseecom_listener_has_rcvd_req(data,
 				this_lstnr))) {
-			pr_warning("Interrupted: exiting Listener Service = %d\n",
+			pr_debug("Interrupted: exiting Listener Service = %d\n",
 						(uint32_t)data->listener.id);
 			/* woken up for different reason */
 			return -ERESTARTSYS;
@@ -1476,11 +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);
-	ret = qsee_vote_for_clock(data, CLK_SFPB);
+
+	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);
-		pr_warning("Unable to vote for SFPB clock");
-		return -EIO;
+		ret = -EIO;
+		goto loadfw_err;
 	}
 
 	__cpuc_flush_dcache_area((void *)img_data, fw_size);
@@ -1491,8 +1818,8 @@
 	kzfree(img_data);
 	if (ret) {
 		pr_err("scm_call to load failed : ret %d\n", ret);
-		qsee_disable_clock_vote(data, CLK_SFPB);
-		return -EIO;
+		ret = -EIO;
+		goto loadfw_err;
 	}
 
 	switch (resp.result) {
@@ -1514,40 +1841,76 @@
 		ret = -EINVAL;
 		break;
 	}
-	qsee_disable_clock_vote(data, CLK_SFPB);
 
+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 = qsee_vote_for_clock(data, CLK_SFPB);
+	ret = __qseecom_enable_clk_scale_up(data);
 	if (ret) {
-		pr_err("Unable to vote for SFPB clock: ret = %d", ret);
-		kzfree(img_data);
-		return -EIO;
+		ret = -EIO;
+		goto exit_unregister_bus_bw_need;
 	}
 
 	__cpuc_flush_dcache_area((void *)img_data, fw_size);
@@ -1558,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);
-	qsee_disable_clock_vote(data, CLK_SFPB);
+
+	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;
 }
 
@@ -1614,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;
 }
 
@@ -1729,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);
@@ -1790,11 +2186,25 @@
 	if (!found_handle)
 		pr_err("Unable to find the handle, exiting\n");
 	else
-		ret = qseecom_unload_app(data);
-	if (data->fast_load_enabled == true)
-		qsee_disable_clock_vote(data, CLK_SFPB);
-	if (data->perf_enabled == true)
-		qsee_disable_clock_vote(data, CLK_DFAB);
+		ret = qseecom_unload_app(data, false);
+
+	if (qseecom.support_bus_scaling) {
+		mutex_lock(&qsee_bw_mutex);
+		if (data->mode != INACTIVE) {
+			qseecom_unregister_bus_bandwidth_needs(data);
+			if (qseecom.cumulative_mode == INACTIVE) {
+				ret = __qseecom_set_msm_bus_request(INACTIVE);
+				if (ret)
+					pr_err("Fail to scale down bus\n");
+			}
+		}
+		mutex_unlock(&qsee_bw_mutex);
+	} else {
+		if (data->fast_load_enabled == true)
+			qsee_disable_clock_vote(data, CLK_SFPB);
+		if (data->perf_enabled == true)
+			qsee_disable_clock_vote(data, CLK_DFAB);
+	}
 	if (ret == 0) {
 		kzfree(data);
 		kzfree(*handle);
@@ -1825,8 +2235,19 @@
 
 	mutex_lock(&app_access_lock);
 	atomic_inc(&data->ioctl_count);
-
+	if (qseecom.support_bus_scaling) {
+		ret = qseecom_scale_bus_bandwidth_timer(INACTIVE);
+		if (ret) {
+			pr_err("Failed to set bw.\n");
+			atomic_dec(&data->ioctl_count);
+			mutex_unlock(&app_access_lock);
+			return ret;
+		}
+	}
 	ret = __qseecom_send_cmd(data, &req);
+	if (qseecom.support_bus_scaling)
+		__qseecom_add_bw_scale_down_timer(
+			QSEECOM_SEND_CMD_CRYPTO_TIMEOUT);
 
 	atomic_dec(&data->ioctl_count);
 	mutex_unlock(&app_access_lock);
@@ -1848,17 +2269,34 @@
 		return -EINVAL;
 	}
 	if (high) {
-		ret = qsee_vote_for_clock(handle->dev, CLK_DFAB);
-		if (ret)
-			pr_err("Failed to vote for DFAB clock%d\n", ret);
-		ret = qsee_vote_for_clock(handle->dev, CLK_SFPB);
-		if (ret) {
-			pr_err("Failed to vote for SFPB clock%d\n", ret);
-			qsee_disable_clock_vote(handle->dev, CLK_DFAB);
+		if (qseecom.support_bus_scaling) {
+			mutex_lock(&qsee_bw_mutex);
+			__qseecom_register_bus_bandwidth_needs(handle->dev,
+									HIGH);
+			mutex_unlock(&qsee_bw_mutex);
+			if (ret)
+				pr_err("Failed to scale bus (med) %d\n", ret);
+		} else {
+			ret = qsee_vote_for_clock(handle->dev, CLK_DFAB);
+			if (ret)
+				pr_err("Failed to vote for DFAB clock%d\n",
+									ret);
+			ret = qsee_vote_for_clock(handle->dev, CLK_SFPB);
+			if (ret) {
+				pr_err("Failed to vote for SFPB clock%d\n",
+									ret);
+				qsee_disable_clock_vote(handle->dev, CLK_DFAB);
+			}
 		}
 	} else {
-		qsee_disable_clock_vote(handle->dev, CLK_DFAB);
-		qsee_disable_clock_vote(handle->dev, CLK_SFPB);
+		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;
 }
@@ -1877,11 +2315,20 @@
 {
 	struct qseecom_send_modfd_listener_resp resp;
 	int i;
+	struct qseecom_registered_listener_list *this_lstnr = NULL;
 
 	if (copy_from_user(&resp, argp, sizeof(resp))) {
 		pr_err("copy_from_user failed");
 		return -EINVAL;
 	}
+	this_lstnr = __qseecom_find_svc(data->listener.id);
+	if (this_lstnr == NULL)
+		return -EINVAL;
+
+	if (resp.resp_buf_ptr == NULL) {
+		pr_err("Invalid resp_buf_ptr\n");
+		return -EINVAL;
+	}
 	/* validate offsets */
 	for (i = 0; i < MAX_ION_FD; i++) {
 		if (resp.ifd_data[i].cmd_buf_offset >= resp.resp_len) {
@@ -1890,6 +2337,17 @@
 			return -EINVAL;
 		}
 	}
+
+	if (((uint32_t)resp.resp_buf_ptr <
+			this_lstnr->user_virt_sb_base)
+			|| ((uint32_t)resp.resp_buf_ptr >=
+			(this_lstnr->user_virt_sb_base +
+			this_lstnr->sb_length))) {
+		pr_err("resp_buf_ptr address not within shared buffer\n");
+		return -EINVAL;
+	}
+	resp.resp_buf_ptr = (uint32_t)this_lstnr->sb_virt +
+		(resp.resp_buf_ptr - this_lstnr->user_virt_sb_base);
 	__qseecom_update_cmd_buf(&resp, false, data, true);
 	qseecom.send_resp_flag = 1;
 	wake_up_interruptible(&qseecom.send_resp_wq);
@@ -2185,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;
@@ -2202,12 +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 = qsee_vote_for_clock(data, CLK_SFPB);
+	ret = __qseecom_enable_clk_scale_up(data);
 	if (ret) {
-		pr_err("Unable to vote for SFPB clock: ret = %d", 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);
@@ -2243,7 +2714,15 @@
 	}
 
 exit_disable_clock:
-	qsee_disable_clock_vote(data, CLK_SFPB);
+	__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;
@@ -2379,16 +2858,28 @@
 	int ret;
 	switch (usage) {
 	case QSEOS_KM_USAGE_DISK_ENCRYPTION:
-		if (qseecom.ce_info.disk_encrypt_pipe == 0xFF ||
-			qseecom.ce_info.hlos_ce_hw_instance == 0xFF) {
-			pr_err("nfo unavailable: disk encr pipe %d ce_hw %d\n",
-				qseecom.ce_info.disk_encrypt_pipe,
-				qseecom.ce_info.hlos_ce_hw_instance);
-			ret = -EINVAL;
-		} else {
+		if (qseecom.support_fde) {
 			*pipe = qseecom.ce_info.disk_encrypt_pipe;
 			*ce_hw = qseecom.ce_info.hlos_ce_hw_instance;
 			ret = 0;
+
+		} else {
+			pr_err("info unavailable: disk encr pipe %d ce_hw %d\n",
+				qseecom.ce_info.disk_encrypt_pipe,
+				qseecom.ce_info.hlos_ce_hw_instance);
+			ret = -EINVAL;
+		}
+		break;
+	case QSEOS_KM_USAGE_FILE_ENCRYPTION:
+		if (qseecom.support_pfe) {
+			*pipe = qseecom.ce_info.file_encrypt_pipe;
+			*ce_hw = qseecom.ce_info.hlos_ce_hw_instance;
+			ret = 0;
+		} else {
+			pr_err("info unavailable: file encr pipe %d ce_hw %d\n",
+				qseecom.ce_info.file_encrypt_pipe,
+				qseecom.ce_info.hlos_ce_hw_instance);
+			ret = -EINVAL;
 		}
 		break;
 	default:
@@ -2400,43 +2891,38 @@
 
 static int __qseecom_generate_and_save_key(struct qseecom_dev_handle *data,
 			enum qseecom_key_management_usage_type usage,
-			uint8_t *key_id, uint32_t flags)
+			struct qseecom_key_generate_ireq *ireq)
 {
-	struct qseecom_key_generate_ireq ireq;
 	struct qseecom_command_scm_resp resp;
 	int ret;
 
-	if (usage != QSEOS_KM_USAGE_DISK_ENCRYPTION) {
+	if (usage < QSEOS_KM_USAGE_DISK_ENCRYPTION ||
+		usage >= QSEOS_KM_USAGE_MAX) {
 		pr_err("Error:: unsupported usage %d\n", usage);
 		return -EFAULT;
 	}
-
-	memcpy(ireq.key_id, key_id, QSEECOM_KEY_ID_SIZE);
-	ireq.flags = flags;
-	ireq.qsee_command_id = QSEOS_GENERATE_KEY;
-
 	__qseecom_enable_clk(CLK_QSEE);
 
 	ret = scm_call(SCM_SVC_TZSCHEDULER, 1,
-				&ireq, sizeof(struct qseecom_key_generate_ireq),
+				ireq, sizeof(struct qseecom_key_generate_ireq),
 				&resp, sizeof(resp));
 	if (ret) {
 		pr_err("scm call to generate key failed : %d\n", ret);
 		__qseecom_disable_clk(CLK_QSEE);
-		return ret;
+		return -EFAULT;
 	}
 
 	switch (resp.result) {
 	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",
@@ -2456,9 +2942,8 @@
 
 static int __qseecom_delete_saved_key(struct qseecom_dev_handle *data,
 			enum qseecom_key_management_usage_type usage,
-			uint8_t *key_id, uint32_t flags)
+			struct qseecom_key_delete_ireq *ireq)
 {
-	struct qseecom_key_delete_ireq ireq;
 	struct qseecom_command_scm_resp resp;
 	int ret;
 
@@ -2467,19 +2952,15 @@
 		return -EFAULT;
 	}
 
-	memcpy(ireq.key_id, key_id, QSEECOM_KEY_ID_SIZE);
-	ireq.flags = flags;
-	ireq.qsee_command_id = QSEOS_DELETE_KEY;
-
 	__qseecom_enable_clk(CLK_QSEE);
 
 	ret = scm_call(SCM_SVC_TZSCHEDULER, 1,
-				&ireq, sizeof(struct qseecom_key_delete_ireq),
+				ireq, sizeof(struct qseecom_key_delete_ireq),
 				&resp, sizeof(struct qseecom_command_scm_resp));
 	if (ret) {
 		pr_err("scm call to delete key failed : %d\n", ret);
 		__qseecom_disable_clk(CLK_QSEE);
-		return ret;
+		return -EFAULT;
 	}
 
 	switch (resp.result) {
@@ -2487,9 +2968,18 @@
 		break;
 	case QSEOS_RESULT_INCOMPLETE:
 		ret = __qseecom_process_incomplete_cmd(data, &resp);
-		if (ret)
+		if (ret) {
 			pr_err("process_incomplete_cmd FAILED, resp.result %d\n",
 					resp.result);
+			if (resp.result == QSEOS_RESULT_FAIL_MAX_ATTEMPT) {
+				pr_debug("Max attempts to input password reached.\n");
+				ret = -ERANGE;
+			}
+		}
+		break;
+	case QSEOS_RESULT_FAIL_MAX_ATTEMPT:
+		pr_debug("Max attempts to input password reached.\n");
+		ret = -ERANGE;
 		break;
 	case QSEOS_RESULT_FAILURE:
 	default:
@@ -2504,13 +2994,13 @@
 
 static int __qseecom_set_clear_ce_key(struct qseecom_dev_handle *data,
 			enum qseecom_key_management_usage_type usage,
-			struct qseecom_set_key_parameter *set_key_para)
+			struct qseecom_key_select_ireq *ireq)
 {
-	struct qseecom_key_select_ireq ireq;
 	struct qseecom_command_scm_resp resp;
 	int ret;
 
-	if (usage != QSEOS_KM_USAGE_DISK_ENCRYPTION) {
+	if (usage < QSEOS_KM_USAGE_DISK_ENCRYPTION ||
+		usage >= QSEOS_KM_USAGE_MAX) {
 			pr_err("Error:: unsupported usage %d\n", usage);
 			return -EFAULT;
 	}
@@ -2519,31 +3009,72 @@
 	if (qseecom.qsee.instance != qseecom.ce_drv.instance)
 		__qseecom_enable_clk(CLK_CE_DRV);
 
-	memcpy(ireq.key_id, set_key_para->key_id, QSEECOM_KEY_ID_SIZE);
-	ireq.qsee_command_id = QSEOS_SET_KEY;
-	ireq.ce = set_key_para->ce_hw;
-	ireq.pipe = set_key_para->pipe;
-	ireq.flags = set_key_para->flags;
-
-	/* set both PIPE_ENC and PIPE_ENC_XTS*/
-	ireq.pipe_type = QSEOS_PIPE_ENC|QSEOS_PIPE_ENC_XTS;
-
-	if (set_key_para->set_clear_key_flag ==
-			QSEECOM_SET_CE_KEY_CMD)
-		memcpy((void *)ireq.hash, (void *)set_key_para->hash32,
-				QSEECOM_HASH_SIZE);
-	else
-		memset((void *)ireq.hash, 0, QSEECOM_HASH_SIZE);
-
 	ret = scm_call(SCM_SVC_TZSCHEDULER, 1,
-				&ireq, sizeof(struct qseecom_key_select_ireq),
+				ireq, sizeof(struct qseecom_key_select_ireq),
 				&resp, sizeof(struct qseecom_command_scm_resp));
 	if (ret) {
 		pr_err("scm call to set QSEOS_PIPE_ENC key failed : %d\n", ret);
 		__qseecom_disable_clk(CLK_QSEE);
 		if (qseecom.qsee.instance != qseecom.ce_drv.instance)
 			__qseecom_disable_clk(CLK_CE_DRV);
-		return ret;
+		return -EFAULT;
+	}
+
+	switch (resp.result) {
+	case QSEOS_RESULT_SUCCESS:
+		break;
+	case QSEOS_RESULT_INCOMPLETE:
+		ret = __qseecom_process_incomplete_cmd(data, &resp);
+		if (ret) {
+			pr_err("process_incomplete_cmd FAILED, resp.result %d\n",
+					resp.result);
+			if (resp.result == QSEOS_RESULT_FAIL_MAX_ATTEMPT) {
+				pr_debug("Max attempts to input password reached.\n");
+				ret = -ERANGE;
+			}
+		}
+		break;
+	case QSEOS_RESULT_FAIL_MAX_ATTEMPT:
+		pr_debug("Max attempts to input password reached.\n");
+		ret = -ERANGE;
+		break;
+	case QSEOS_RESULT_FAILURE:
+	default:
+		pr_err("Set key scm call failed resp.result %d\n", resp.result);
+		ret = -EINVAL;
+		break;
+	}
+
+	__qseecom_disable_clk(CLK_QSEE);
+	if (qseecom.qsee.instance != qseecom.ce_drv.instance)
+		__qseecom_disable_clk(CLK_CE_DRV);
+
+	return ret;
+}
+
+static int __qseecom_update_current_key_user_info(
+			struct qseecom_dev_handle *data,
+			enum qseecom_key_management_usage_type usage,
+			struct qseecom_key_userinfo_update_ireq *ireq)
+{
+	struct qseecom_command_scm_resp resp;
+	int ret;
+
+	if (usage < QSEOS_KM_USAGE_DISK_ENCRYPTION ||
+		usage >= QSEOS_KM_USAGE_MAX) {
+			pr_err("Error:: unsupported usage %d\n", usage);
+			return -EFAULT;
+	}
+
+	__qseecom_enable_clk(CLK_QSEE);
+
+	ret = scm_call(SCM_SVC_TZSCHEDULER, 1,
+		ireq, sizeof(struct qseecom_key_userinfo_update_ireq),
+		&resp, sizeof(struct qseecom_command_scm_resp));
+	if (ret) {
+		pr_err("scm call to update key userinfo failed : %d\n", ret);
+		__qseecom_disable_clk(CLK_QSEE);
+		return -EFAULT;
 	}
 
 	switch (resp.result) {
@@ -2563,9 +3094,6 @@
 	}
 
 	__qseecom_disable_clk(CLK_QSEE);
-	if (qseecom.qsee.instance != qseecom.ce_drv.instance)
-		__qseecom_disable_clk(CLK_CE_DRV);
-
 	return ret;
 }
 
@@ -2574,11 +3102,11 @@
 {
 	uint32_t ce_hw = 0;
 	uint32_t pipe = 0;
-	uint8_t key_id[QSEECOM_KEY_ID_SIZE] = {0};
 	int ret = 0;
 	uint32_t flags = 0;
-	struct qseecom_set_key_parameter set_key_para;
 	struct qseecom_create_key_req create_key_req;
+	struct qseecom_key_generate_ireq generate_key_ireq;
+	struct qseecom_key_select_ireq set_key_ireq;
 
 	ret = copy_from_user(&create_key_req, argp, sizeof(create_key_req));
 	if (ret) {
@@ -2586,7 +3114,8 @@
 		return ret;
 	}
 
-	if (create_key_req.usage != QSEOS_KM_USAGE_DISK_ENCRYPTION) {
+	if (create_key_req.usage < QSEOS_KM_USAGE_DISK_ENCRYPTION ||
+		create_key_req.usage >= QSEOS_KM_USAGE_MAX) {
 		pr_err("Error:: unsupported usage %d\n", create_key_req.usage);
 		return -EFAULT;
 	}
@@ -2597,27 +3126,44 @@
 		return -EINVAL;
 	}
 
+	generate_key_ireq.flags = flags;
+	generate_key_ireq.qsee_command_id = QSEOS_GENERATE_KEY;
+	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].desc,
+			QSEECOM_KEY_ID_SIZE);
+	memcpy((void *)generate_key_ireq.hash32,
+			(void *)create_key_req.hash32, QSEECOM_HASH_SIZE);
+
 	ret = __qseecom_generate_and_save_key(data, create_key_req.usage,
-								key_id, flags);
+					&generate_key_ireq);
 	if (ret) {
 		pr_err("Failed to generate key on storage: %d\n", ret);
-		return -EFAULT;
+		return ret;
 	}
 
-	set_key_para.ce_hw = ce_hw;
-	set_key_para.pipe = pipe;
-	memcpy(set_key_para.key_id, key_id, QSEECOM_KEY_ID_SIZE);
-	set_key_para.flags = flags;
-	set_key_para.set_clear_key_flag = QSEECOM_SET_CE_KEY_CMD;
-	memcpy((void *)set_key_para.hash32, (void *)create_key_req.hash32,
+	set_key_ireq.qsee_command_id = QSEOS_SET_KEY;
+	set_key_ireq.ce = ce_hw;
+	set_key_ireq.pipe = pipe;
+	set_key_ireq.flags = flags;
+
+	/* set both PIPE_ENC and PIPE_ENC_XTS*/
+	set_key_ireq.pipe_type = QSEOS_PIPE_ENC|QSEOS_PIPE_ENC_XTS;
+	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].desc,
+		QSEECOM_KEY_ID_SIZE);
+	memcpy((void *)set_key_ireq.hash32, (void *)create_key_req.hash32,
 				QSEECOM_HASH_SIZE);
 
 	ret = __qseecom_set_clear_ce_key(data, create_key_req.usage,
-								&set_key_para);
+								&set_key_ireq);
 	if (ret) {
 		pr_err("Failed to create key: pipe %d, ce %d: %d\n",
 			pipe, ce_hw, ret);
-		return -EFAULT;
+		return ret;
 	}
 
 	return ret;
@@ -2628,12 +3174,12 @@
 {
 	uint32_t ce_hw = 0;
 	uint32_t pipe = 0;
-	uint8_t key_id[QSEECOM_KEY_ID_SIZE] = {0};
 	int ret = 0;
 	uint32_t flags = 0;
 	int i;
 	struct qseecom_wipe_key_req wipe_key_req;
-	struct qseecom_set_key_parameter clear_key_para;
+	struct qseecom_key_delete_ireq delete_key_ireq;
+	struct qseecom_key_select_ireq clear_key_ireq;
 
 	ret = copy_from_user(&wipe_key_req, argp, sizeof(wipe_key_req));
 	if (ret) {
@@ -2641,7 +3187,8 @@
 		return ret;
 	}
 
-	if (wipe_key_req.usage != QSEOS_KM_USAGE_DISK_ENCRYPTION) {
+	if (wipe_key_req.usage < QSEOS_KM_USAGE_DISK_ENCRYPTION ||
+		wipe_key_req.usage >= QSEOS_KM_USAGE_MAX) {
 		pr_err("Error:: unsupported usage %d\n", wipe_key_req.usage);
 		return -EFAULT;
 	}
@@ -2652,22 +3199,35 @@
 		return -EINVAL;
 	}
 
-	ret = __qseecom_delete_saved_key(data, wipe_key_req.usage, key_id,
-									flags);
-	if (ret) {
-		pr_err("Failed to delete key from ssd storage: %d\n", ret);
-		return -EFAULT;
+	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);
+
+		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;
+		}
 	}
 
-	/* an invalid key_id 0xff is used to indicate clear key*/
+	clear_key_ireq.qsee_command_id = QSEOS_SET_KEY;
+	clear_key_ireq.ce = ce_hw;
+	clear_key_ireq.pipe = pipe;
+	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_para.key_id[i] = 0xff;
-	clear_key_para.ce_hw = ce_hw;
-	clear_key_para.pipe = pipe;
-	clear_key_para.flags = flags;
-	clear_key_para.set_clear_key_flag = QSEECOM_CLEAR_CE_KEY_CMD;
+		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,
-							&clear_key_para);
+							&clear_key_ireq);
 	if (ret) {
 		pr_err("Failed to wipe key: pipe %d, ce %d: %d\n",
 			pipe, ce_hw, ret);
@@ -2677,6 +3237,49 @@
 	return ret;
 }
 
+static int qseecom_update_key_user_info(struct qseecom_dev_handle *data,
+			void __user *argp)
+{
+	int ret = 0;
+	uint32_t flags = 0;
+	struct qseecom_update_key_userinfo_req update_key_req;
+	struct qseecom_key_userinfo_update_ireq ireq;
+
+	ret = copy_from_user(&update_key_req, argp, sizeof(update_key_req));
+	if (ret) {
+		pr_err("copy_from_user failed\n");
+		return ret;
+	}
+
+	if (update_key_req.usage < QSEOS_KM_USAGE_DISK_ENCRYPTION ||
+		update_key_req.usage >= QSEOS_KM_USAGE_MAX) {
+		pr_err("Error:: unsupported usage %d\n", update_key_req.usage);
+		return -EFAULT;
+	}
+
+	ireq.qsee_command_id = QSEOS_UPDATE_KEY_USERINFO;
+	ireq.flags = flags;
+	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((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,
+		(void *)update_key_req.new_hash32, QSEECOM_HASH_SIZE);
+
+	ret = __qseecom_update_current_key_user_info(data, update_key_req.usage,
+						&ireq);
+	if (ret) {
+		pr_err("Failed to update key info: %d\n", ret);
+		return ret;
+	}
+	return ret;
+
+}
+
 static int qseecom_is_es_activated(void __user *argp)
 {
 	struct qseecom_is_es_activated_req req;
@@ -2794,6 +3397,7 @@
 		break;
 	}
 	case QSEECOM_IOCTL_SEND_CMD_REQ: {
+		pr_debug("qseecom.current_mode %d\n", qseecom.current_mode);
 		if ((data->client.app_id == 0) ||
 			(data->type != QSEECOM_CLIENT_APP)) {
 			pr_err("send cmd req: invalid handle (%d) app_id(%d)\n",
@@ -2803,8 +3407,27 @@
 		}
 		/* 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");
+				ret = -EINVAL;
+				mutex_unlock(&app_access_lock);
+				break;
+			}
+		}
 		atomic_inc(&data->ioctl_count);
 		ret = qseecom_send_cmd(data, argp);
+		if (qseecom.support_bus_scaling)
+			__qseecom_add_bw_scale_down_timer(
+				QSEECOM_SEND_CMD_CRYPTO_TIMEOUT);
 		atomic_dec(&data->ioctl_count);
 		wake_up_all(&data->abort_wq);
 		mutex_unlock(&app_access_lock);
@@ -2813,6 +3436,7 @@
 		break;
 	}
 	case QSEECOM_IOCTL_SEND_MODFD_CMD_REQ: {
+		pr_debug("qseecom.current_mode %d\n", qseecom.current_mode);
 		if ((data->client.app_id == 0) ||
 			(data->type != QSEECOM_CLIENT_APP)) {
 			pr_err("send mdfd cmd: invalid handle (%d) appid(%d)\n",
@@ -2822,8 +3446,26 @@
 		}
 		/* 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");
+				mutex_unlock(&app_access_lock);
+				ret = -EINVAL;
+				break;
+			}
+		}
 		atomic_inc(&data->ioctl_count);
 		ret = qseecom_send_modfd_cmd(data, argp);
+		if (qseecom.support_bus_scaling)
+			__qseecom_add_bw_scale_down_timer(
+				QSEECOM_SEND_CMD_CRYPTO_TIMEOUT);
 		atomic_dec(&data->ioctl_count);
 		wake_up_all(&data->abort_wq);
 		mutex_unlock(&app_access_lock);
@@ -2843,7 +3485,7 @@
 		ret = qseecom_receive_req(data);
 		atomic_dec(&data->ioctl_count);
 		wake_up_all(&data->abort_wq);
-		if (ret)
+		if (ret && (ret != -ERESTARTSYS))
 			pr_err("failed qseecom_receive_req: %d\n", ret);
 		break;
 	}
@@ -2872,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)
@@ -2917,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)
@@ -2948,12 +3591,18 @@
 			break;
 		}
 		atomic_inc(&data->ioctl_count);
-		ret = qsee_vote_for_clock(data, CLK_DFAB);
-		if (ret)
-			pr_err("Failed to vote for DFAB clock%d\n", ret);
-		ret = qsee_vote_for_clock(data, CLK_SFPB);
-		if (ret)
-			pr_err("Failed to vote for SFPB clock%d\n", ret);
+		if (qseecom.support_bus_scaling) {
+			mutex_lock(&qsee_bw_mutex);
+			__qseecom_register_bus_bandwidth_needs(data, HIGH);
+			mutex_unlock(&qsee_bw_mutex);
+		} else {
+			ret = qsee_vote_for_clock(data, CLK_DFAB);
+			if (ret)
+				pr_err("Fail to vote for DFAB clock%d\n", ret);
+			ret = qsee_vote_for_clock(data, CLK_SFPB);
+			if (ret)
+				pr_err("Fail to vote for SFPB clock%d\n", ret);
+		}
 		atomic_dec(&data->ioctl_count);
 		break;
 	}
@@ -2973,8 +3622,28 @@
 			break;
 		}
 		atomic_inc(&data->ioctl_count);
+		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;
+	}
+
+	case QSEECOM_IOCTL_SET_BUS_SCALING_REQ: {
+		if ((data->client.app_id == 0) ||
+			(data->type != QSEECOM_CLIENT_APP)) {
+			pr_err("set bus scale: invalid handle (%d) appid(%d)\n",
+					data->type, data->client.app_id);
+			ret = -EINVAL;
+			break;
+		}
+		atomic_inc(&data->ioctl_count);
+		ret = qseecom_scale_bus_bandwidth(data, argp);
 		atomic_dec(&data->ioctl_count);
 		break;
 	}
@@ -3015,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);
@@ -3044,6 +3714,8 @@
 		break;
 	}
 	case QSEECOM_IOCTL_CREATE_KEY_REQ: {
+		if (!(qseecom.support_pfe || qseecom.support_fde))
+			pr_err("Features requiring key init not supported\n");
 		if (data->type != QSEECOM_GENERIC) {
 			pr_err("create key req: invalid handle (%d)\n",
 								data->type);
@@ -3056,17 +3728,17 @@
 			return -EINVAL;
 		}
 		data->released = true;
-		mutex_lock(&app_access_lock);
 		atomic_inc(&data->ioctl_count);
 		ret = qseecom_create_key(data, argp);
 		if (ret)
 			pr_err("failed to create encryption key: %d\n", ret);
 
 		atomic_dec(&data->ioctl_count);
-		mutex_unlock(&app_access_lock);
 		break;
 	}
 	case QSEECOM_IOCTL_WIPE_KEY_REQ: {
+		if (!(qseecom.support_pfe || qseecom.support_fde))
+			pr_err("Features requiring key init not supported\n");
 		if (data->type != QSEECOM_GENERIC) {
 			pr_err("wipe key req: invalid handle (%d)\n",
 								data->type);
@@ -3079,13 +3751,33 @@
 			return -EINVAL;
 		}
 		data->released = true;
-		mutex_lock(&app_access_lock);
 		atomic_inc(&data->ioctl_count);
 		ret = qseecom_wipe_key(data, argp);
 		if (ret)
 			pr_err("failed to wipe encryption key: %d\n", ret);
 		atomic_dec(&data->ioctl_count);
-		mutex_unlock(&app_access_lock);
+		break;
+	}
+	case QSEECOM_IOCTL_UPDATE_KEY_USER_INFO_REQ: {
+		if (!(qseecom.support_pfe || qseecom.support_fde))
+			pr_err("Features requiring key init not supported\n");
+		if (data->type != QSEECOM_GENERIC) {
+			pr_err("update key req: invalid handle (%d)\n",
+								data->type);
+			ret = -EINVAL;
+			break;
+		}
+		if (qseecom.qsee_version < QSEE_VERSION_05) {
+			pr_err("Update Key feature unsupported in qsee ver %u\n",
+				qseecom.qsee_version);
+			return -EINVAL;
+		}
+		data->released = true;
+		atomic_inc(&data->ioctl_count);
+		ret = qseecom_update_key_user_info(data, argp);
+		if (ret)
+			pr_err("failed to update key user info: %d\n", ret);
+		atomic_dec(&data->ioctl_count);
 		break;
 	}
 	case QSEECOM_IOCTL_SAVE_PARTITION_HASH_REQ: {
@@ -3135,23 +3827,6 @@
 			pr_err("failed qseecom_send_mod_resp: %d\n", ret);
 		break;
 	}
-	case QSEECOM_IOCTL_UNPROTECT_BUF: {
-		if ((data->listener.id == 0) ||
-			(data->type != QSEECOM_LISTENER_SERVICE)) {
-			pr_err("receive req: invalid handle (%d), lid(%d)\n",
-						data->type, data->listener.id);
-			ret = -EINVAL;
-			break;
-		}
-		/* Only one client allowed here at a time */
-		atomic_inc(&data->ioctl_count);
-		ret = qseecom_unprotect_buffer(argp);
-		atomic_dec(&data->ioctl_count);
-		wake_up_all(&data->abort_wq);
-		if (ret)
-			pr_err("failed qseecom_unprotect: %d\n", ret);
-		break;
-	}
 	default:
 		pr_err("Invalid IOCTL: %d\n", cmd);
 		return -EINVAL;
@@ -3173,6 +3848,7 @@
 	data->abort = 0;
 	data->type = QSEECOM_GENERIC;
 	data->released = false;
+	data->mode = INACTIVE;
 	init_waitqueue_head(&data->abort_wq);
 	atomic_set(&data->ioctl_count, 0);
 
@@ -3192,13 +3868,13 @@
 			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;
@@ -3209,11 +3885,23 @@
 		}
 	}
 
-	if (data->fast_load_enabled == true)
-		qsee_disable_clock_vote(data, CLK_SFPB);
-	if (data->perf_enabled == true)
-		qsee_disable_clock_vote(data, CLK_DFAB);
-
+	if (qseecom.support_bus_scaling) {
+		mutex_lock(&qsee_bw_mutex);
+		if (data->mode != INACTIVE) {
+			qseecom_unregister_bus_bandwidth_needs(data);
+			if (qseecom.cumulative_mode == INACTIVE) {
+				ret = __qseecom_set_msm_bus_request(INACTIVE);
+				if (ret)
+					pr_err("Fail to scale down bus\n");
+			}
+		}
+		mutex_unlock(&qsee_bw_mutex);
+	} else {
+		if (data->fast_load_enabled == true)
+			qsee_disable_clock_vote(data, CLK_SFPB);
+		if (data->perf_enabled == true)
+			qsee_disable_clock_vote(data, CLK_DFAB);
+	}
 	kfree(data);
 
 	return ret;
@@ -3356,6 +4044,12 @@
 	qseecom.qsee.ce_core_src_clk = NULL;
 	qseecom.qsee.ce_bus_clk = NULL;
 
+	qseecom.cumulative_mode = 0;
+	qseecom.current_mode = INACTIVE;
+	qseecom.support_bus_scaling = false;
+	qseecom.support_fde = false;
+	qseecom.support_pfe = false;
+
 	qseecom.ce_drv.ce_core_clk = NULL;
 	qseecom.ce_drv.ce_clk = NULL;
 	qseecom.ce_drv.ce_core_src_clk = NULL;
@@ -3435,24 +4129,68 @@
 
 	/* register client for bus scaling */
 	if (pdev->dev.of_node) {
-
-		if (of_property_read_u32((&pdev->dev)->of_node,
+		qseecom.pdev->of_node = pdev->dev.of_node;
+		qseecom.support_bus_scaling =
+				of_property_read_bool((&pdev->dev)->of_node,
+						"qcom,support-bus-scaling");
+		pr_warn("support_bus_scaling=0x%x",
+				qseecom.support_bus_scaling);
+		qseecom.support_fde =
+				of_property_read_bool((&pdev->dev)->of_node,
+						"qcom,support-fde");
+		if (qseecom.support_fde) {
+			if (of_property_read_u32((&pdev->dev)->of_node,
 				"qcom,disk-encrypt-pipe-pair",
 				&qseecom.ce_info.disk_encrypt_pipe)) {
-			pr_err("Fail to get disk-encrypt pipe pair information.\n");
-			qseecom.ce_info.disk_encrypt_pipe = 0xff;
-			rc = -EINVAL;
-			goto exit_destroy_ion_client;
+				pr_err("Fail to get FDE pipe information.\n");
+				rc = -EINVAL;
+				goto exit_destroy_ion_client;
+			} else {
+				pr_warn("disk-encrypt-pipe-pair=0x%x",
+				qseecom.ce_info.disk_encrypt_pipe);
+			}
 		} else {
-			pr_warn("bam_pipe_pair=0x%x",
-			qseecom.ce_info.disk_encrypt_pipe);
+			pr_warn("Device does not support FDE");
+			qseecom.ce_info.disk_encrypt_pipe = 0xff;
+		}
+		qseecom.support_pfe =
+				of_property_read_bool((&pdev->dev)->of_node,
+						"qcom,support-pfe");
+		if (qseecom.support_pfe) {
+			if (of_property_read_u32((&pdev->dev)->of_node,
+				"qcom,file-encrypt-pipe-pair",
+				&qseecom.ce_info.disk_encrypt_pipe)) {
+				pr_err("Fail to get PFE pipe information.\n");
+				rc = -EINVAL;
+				goto exit_destroy_ion_client;
+			} else {
+				pr_warn("file-encrypt-pipe-pair=0x%x",
+				qseecom.ce_info.file_encrypt_pipe);
+			}
+		} else {
+			pr_warn("Device does not support PFE");
+			qseecom.ce_info.file_encrypt_pipe = 0xff;
+		}
+		if (qseecom.support_pfe || qseecom.support_fde) {
+			if (of_property_read_u32((&pdev->dev)->of_node,
+				"qcom,hlos-ce-hw-instance",
+				&qseecom.ce_info.hlos_ce_hw_instance)) {
+				pr_err("Fail: get hlos ce hw instanc info\n");
+				rc = -EINVAL;
+				goto exit_destroy_ion_client;
+			} else {
+				pr_warn("hlos-ce-hw-instance=0x%x",
+				qseecom.ce_info.hlos_ce_hw_instance);
+			}
+		} else {
+			pr_warn("Device does not support PFE/FDE");
+			qseecom.ce_info.hlos_ce_hw_instance = 0xff;
 		}
 
 		if (of_property_read_u32((&pdev->dev)->of_node,
 				"qcom,qsee-ce-hw-instance",
 				&qseecom.ce_info.qsee_ce_hw_instance)) {
 			pr_err("Fail to get qsee ce hw instance information.\n");
-			qseecom.ce_info.qsee_ce_hw_instance = 0xff;
 			rc = -EINVAL;
 			goto exit_destroy_ion_client;
 		} else {
@@ -3460,18 +4198,6 @@
 			qseecom.ce_info.qsee_ce_hw_instance);
 		}
 
-		if (of_property_read_u32((&pdev->dev)->of_node,
-				"qcom,hlos-ce-hw-instance",
-				&qseecom.ce_info.hlos_ce_hw_instance)) {
-			pr_err("Fail to get hlos ce hw instance information.\n");
-			qseecom.ce_info.hlos_ce_hw_instance = 0xff;
-			rc = -EINVAL;
-			goto exit_destroy_ion_client;
-		} else {
-			pr_warn("hlos-ce-hw-instance=0x%x",
-			qseecom.ce_info.hlos_ce_hw_instance);
-		}
-
 		qseecom.qsee.instance = qseecom.ce_info.qsee_ce_hw_instance;
 		qseecom.ce_drv.instance = qseecom.ce_info.hlos_ce_hw_instance;
 
@@ -3479,7 +4205,8 @@
 		if (ret)
 			goto exit_destroy_ion_client;
 
-		if (qseecom.qsee.instance != qseecom.ce_drv.instance) {
+		if ((qseecom.qsee.instance != qseecom.ce_drv.instance) &&
+				(qseecom.support_pfe || qseecom.support_fde)) {
 			ret = __qseecom_init_clk(CLK_CE_DRV);
 			if (ret) {
 				__qseecom_deinit_clk(CLK_QSEE);
@@ -3528,7 +4255,14 @@
 		qseecom_platform_support = (struct msm_bus_scale_pdata *)
 						pdev->dev.platform_data;
 	}
-
+	if (qseecom.support_bus_scaling) {
+		init_timer(&(qseecom.bw_scale_down_timer));
+		INIT_WORK(&qseecom.bw_inactive_req_ws,
+					qseecom_bw_inactive_req_work);
+		qseecom.bw_scale_down_timer.function =
+				qseecom_scale_bus_bandwidth_timer_callback;
+	}
+	qseecom.timer_running = false;
 	qseecom.qsee_perf_client = msm_bus_scale_register_client(
 					qseecom_platform_support);
 
@@ -3570,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);
@@ -3594,10 +4328,16 @@
 	if (pdev->dev.platform_data != NULL)
 		msm_bus_scale_unregister_client(qseecom.qsee_perf_client);
 
+	if (qseecom.support_bus_scaling) {
+		cancel_work_sync(&qseecom.bw_inactive_req_ws);
+		del_timer_sync(&qseecom.bw_scale_down_timer);
+	}
+
 	/* register client for bus scaling */
 	if (pdev->dev.of_node) {
 		__qseecom_deinit_clk(CLK_QSEE);
-		if (qseecom.qsee.instance != qseecom.ce_drv.instance)
+		if ((qseecom.qsee.instance != qseecom.ce_drv.instance) &&
+				(qseecom.support_pfe || qseecom.support_fde))
 			__qseecom_deinit_clk(CLK_CE_DRV);
 	}
 
@@ -3614,6 +4354,113 @@
 	return ret;
 }
 
+static int qseecom_suspend(struct platform_device *pdev, pm_message_t state)
+{
+	int ret = 0;
+	struct qseecom_clk *qclk;
+	qclk = &qseecom.qsee;
+
+	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;
+	}
+
+	if (qclk->clk_access_cnt) {
+		if (qclk->ce_clk != NULL)
+			clk_disable_unprepare(qclk->ce_clk);
+		if (qclk->ce_core_clk != NULL)
+			clk_disable_unprepare(qclk->ce_core_clk);
+		if (qclk->ce_bus_clk != NULL)
+			clk_disable_unprepare(qclk->ce_bus_clk);
+	}
+
+	del_timer_sync(&(qseecom.bw_scale_down_timer));
+	qseecom.timer_running = false;
+
+	mutex_unlock(&clk_access_lock);
+	mutex_unlock(&qsee_bw_mutex);
+
+	return 0;
+}
+
+static int qseecom_resume(struct platform_device *pdev)
+{
+	int mode = 0;
+	int ret = 0;
+	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
+		mode = qseecom.cumulative_mode;
+
+	if (qseecom.cumulative_mode != INACTIVE) {
+		ret = msm_bus_scale_client_update_request(
+			qseecom.qsee_perf_client, mode);
+		if (ret)
+			pr_err("Fail to scale up bus to %d\n", mode);
+		else
+			qseecom.current_mode = mode;
+	}
+
+	if (qclk->clk_access_cnt) {
+
+		ret = clk_prepare_enable(qclk->ce_core_clk);
+		if (ret) {
+			pr_err("Unable to enable/prepare CE core clk\n");
+			qclk->clk_access_cnt = 0;
+			goto err;
+		}
+
+		ret = clk_prepare_enable(qclk->ce_clk);
+		if (ret) {
+			pr_err("Unable to enable/prepare CE iface clk\n");
+			qclk->clk_access_cnt = 0;
+			goto ce_clk_err;
+		}
+
+		ret = clk_prepare_enable(qclk->ce_bus_clk);
+		if (ret) {
+			pr_err("Unable to enable/prepare CE bus clk\n");
+			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);
+		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:
+	clk_disable_unprepare(qclk->ce_clk);
+ce_clk_err:
+	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[] = {
 	{
 		.compatible = "qcom,qseecom",
@@ -3624,6 +4471,8 @@
 static struct platform_driver qseecom_plat_driver = {
 	.probe = qseecom_probe,
 	.remove = qseecom_remove,
+	.suspend = qseecom_suspend,
+	.resume = qseecom_resume,
 	.driver = {
 		.name = "qseecom",
 		.owner = THIS_MODULE,
diff --git a/drivers/misc/smsc_hub.c b/drivers/misc/smsc_hub.c
index 6f98dc7..e89451a 100644
--- a/drivers/misc/smsc_hub.c
+++ b/drivers/misc/smsc_hub.c
@@ -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
@@ -36,6 +36,7 @@
 	struct clk		*ref_clk;
 	struct regulator	*hsic_hub_reg;
 	struct regulator	*int_pad_reg, *hub_vbus_reg;
+	bool enabled;
 };
 static struct hsic_hub *smsc_hub;
 static struct platform_driver smsc_hub_driver;
@@ -191,6 +192,14 @@
 {
 	int ret;
 
+	/*
+	 * xo_clk_gpio controls an external xo clock which feeds
+	 * the hub reference clock. When this gpio is present,
+	 * assume that no other clocks are required.
+	 */
+	if (hub->pdata->xo_clk_gpio)
+		return 0;
+
 	if (!init) {
 		if (!IS_ERR(hub->ref_clk))
 			clk_disable_unprepare(hub->ref_clk);
@@ -257,6 +266,15 @@
 			dev_err(hub->dev, "gpio request failed (CLK GPIO)\n");
 	}
 
+	if (pdata->xo_clk_gpio) {
+		ret = devm_gpio_request(hub->dev, pdata->xo_clk_gpio,
+							 "HSIC_HUB_XO_CLK");
+		if (ret < 0) {
+			dev_err(hub->dev, "gpio request failed(XO CLK GPIO)\n");
+			return ret;
+		}
+	}
+
 	if (pdata->int_gpio) {
 		ret = devm_gpio_request(hub->dev, pdata->int_gpio,
 							 "HSIC_HUB_INT");
@@ -266,7 +284,7 @@
 		}
 
 		/* Enable LDO if required for external pull-up */
-		smsc_hub->int_pad_reg = devm_regulator_get(hub->dev, "hub_int");
+		smsc_hub->int_pad_reg = devm_regulator_get(hub->dev, "hub-int");
 		if (IS_ERR(smsc_hub->int_pad_reg)) {
 			dev_dbg(hub->dev, "unable to get ext hub_int reg\n");
 		} else {
@@ -298,6 +316,9 @@
 {
 	int ret;
 
+	if (!of_get_property(hub->dev->of_node, "ext-hub-vddio-supply", NULL))
+		return 0;
+
 	if (!init) {
 		if (!IS_ERR(smsc_hub->hsic_hub_reg)) {
 			regulator_disable(smsc_hub->hsic_hub_reg);
@@ -308,7 +329,7 @@
 		return 0;
 	}
 
-	smsc_hub->hsic_hub_reg = devm_regulator_get(hub->dev, "EXT_HUB_VDDIO");
+	smsc_hub->hsic_hub_reg = devm_regulator_get(hub->dev, "ext-hub-vddio");
 	if (IS_ERR(smsc_hub->hsic_hub_reg)) {
 		dev_dbg(hub->dev, "unable to get ext hub vddcx\n");
 	} else {
@@ -345,6 +366,124 @@
 
 	return ret;
 }
+
+static int smsc_hub_enable(struct hsic_hub *hub)
+{
+	struct smsc_hub_platform_data *pdata = hub->pdata;
+	struct of_dev_auxdata *hsic_host_auxdata = dev_get_platdata(hub->dev);
+	struct device_node *node = hub->dev->of_node;
+	int ret;
+
+	ret = gpio_direction_output(pdata->xo_clk_gpio, 1);
+	if (ret < 0) {
+		dev_err(hub->dev, "fail to enable xo clk\n");
+		return ret;
+	}
+
+	ret = gpio_direction_output(pdata->hub_reset, 0);
+	if (ret < 0) {
+		dev_err(hub->dev, "fail to assert reset\n");
+		goto disable_xo;
+	}
+	udelay(5);
+	ret = gpio_direction_output(pdata->hub_reset, 1);
+	if (ret < 0) {
+		dev_err(hub->dev, "fail to de-assert reset\n");
+		goto disable_xo;
+	}
+
+	ret = of_platform_populate(node, NULL, hsic_host_auxdata,
+			hub->dev);
+	if (ret < 0) {
+		dev_err(smsc_hub->dev, "fail to add child with %d\n",
+				ret);
+		goto reset;
+	}
+
+	pm_runtime_allow(hub->dev);
+
+	return 0;
+
+reset:
+	gpio_direction_output(pdata->hub_reset, 0);
+disable_xo:
+	gpio_direction_output(pdata->xo_clk_gpio, 0);
+
+	return ret;
+}
+
+static int sms_hub_remove_child(struct device *dev, void *data)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+
+	/*
+	 * Runtime PM is disabled before the driver's remove method
+	 * is called.  So resume the device before unregistering
+	 * the device. Don't worry about the PM usage counter as
+	 * the device will be freed.
+	 */
+	pm_runtime_get_sync(dev);
+	of_device_unregister(pdev);
+
+	return 0;
+}
+
+static int smsc_hub_disable(struct hsic_hub *hub)
+{
+	struct smsc_hub_platform_data *pdata = hub->pdata;
+
+	pm_runtime_forbid(hub->dev);
+	device_for_each_child(hub->dev, NULL, sms_hub_remove_child);
+	gpio_direction_output(pdata->hub_reset, 0);
+	gpio_direction_output(pdata->xo_clk_gpio, 0);
+
+	return 0;
+}
+
+static ssize_t smsc_hub_enable_show(struct device *dev,
+			       struct device_attribute *attr, char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "%s\n", smsc_hub->enabled ?
+						"enabled" : "disabled");
+}
+
+static ssize_t smsc_hub_enable_store(struct device *dev,
+		struct device_attribute *attr, const char
+		*buf, size_t size)
+{
+
+	bool enable;
+	int val;
+	int ret = size;
+
+	if (sscanf(buf, "%d", &val) == 1) {
+		enable = !!val;
+	} else {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	if (smsc_hub->enabled == enable)
+		goto out;
+
+	if (enable)
+		ret = smsc_hub_enable(smsc_hub);
+	else
+		ret = smsc_hub_disable(smsc_hub);
+
+	pr_debug("smsc hub %s status %d\n", enable ?
+			"Enable" : "Disable", ret);
+	if (!ret) {
+		ret = size;
+		smsc_hub->enabled = enable;
+	}
+out:
+	return ret;
+}
+
+static DEVICE_ATTR(enable, S_IRUGO | S_IWUSR, smsc_hub_enable_show,
+			smsc_hub_enable_store);
+
 struct smsc_hub_platform_data *msm_hub_dt_to_pdata(
 				struct platform_device *pdev)
 {
@@ -365,6 +504,8 @@
 		return ERR_PTR(rc);
 	} else {
 		pdata->model_id = temp_val;
+		if (pdata->model_id == 0)
+			return pdata;
 	}
 
 	pdata->hub_reset = of_get_named_gpio(node, "smsc,reset-gpio", 0);
@@ -379,6 +520,10 @@
 	if (pdata->int_gpio < 0)
 		pdata->int_gpio = 0;
 
+	pdata->xo_clk_gpio = of_get_named_gpio(node, "smsc,xo-clk-gpio", 0);
+	if (pdata->xo_clk_gpio < 0)
+		pdata->xo_clk_gpio = 0;
+
 	return pdata;
 }
 
@@ -406,6 +551,12 @@
 		return -ENODEV;
 	}
 
+	if (pdata->model_id == 0) {
+		dev_dbg(&pdev->dev, "standalone HSIC config enabled\n");
+		return of_platform_populate(node, NULL,
+				hsic_host_auxdata, &pdev->dev);
+	}
+
 	if (!pdata->hub_reset)
 		return -EINVAL;
 
@@ -416,11 +567,14 @@
 	smsc_hub->dev = &pdev->dev;
 	smsc_hub->pdata = pdata;
 
-	smsc_hub->hub_vbus_reg = devm_regulator_get(&pdev->dev, "hub_vbus");
-	ret = PTR_ERR(smsc_hub->hub_vbus_reg);
-	if (ret == -EPROBE_DEFER) {
-		dev_dbg(&pdev->dev, "failed to get hub_vbus\n");
-		return ret;
+	if (of_get_property(pdev->dev.of_node, "hub-vbus-supply", NULL)) {
+		smsc_hub->hub_vbus_reg = devm_regulator_get(&pdev->dev,
+				"hub-vbus");
+		ret = PTR_ERR(smsc_hub->hub_vbus_reg);
+		if (ret == -EPROBE_DEFER) {
+			dev_dbg(&pdev->dev, "failed to get hub_vbus\n");
+			return ret;
+		}
 	}
 
 	ret = msm_hsic_hub_init_vdd(smsc_hub, 1);
@@ -439,6 +593,16 @@
 		goto uninit_clock;
 	}
 
+	if (pdata->model_id == SMSC3502_ID) {
+		ret = device_create_file(&pdev->dev, &dev_attr_enable);
+		if (ret < 0) {
+			dev_err(&pdev->dev, "fail to create sysfs file\n");
+			goto uninit_gpio;
+		}
+		pm_runtime_forbid(&pdev->dev);
+		goto done;
+	}
+
 	gpio_direction_output(pdata->hub_reset, 0);
 	/*
 	 * Hub reset should be asserted for minimum 2microsec
@@ -447,7 +611,7 @@
 	udelay(5);
 	gpio_direction_output(pdata->hub_reset, 1);
 
-	if (!IS_ERR(smsc_hub->hub_vbus_reg)) {
+	if (!IS_ERR_OR_NULL(smsc_hub->hub_vbus_reg)) {
 		ret = regulator_enable(smsc_hub->hub_vbus_reg);
 		if (ret) {
 			dev_err(&pdev->dev, "unable to enable hub_vbus\n");
@@ -501,10 +665,13 @@
 		goto uninit_gpio;
 	}
 
+	smsc_hub->enabled = true;
+
 	if (!smsc_hub->client)
 		dev_err(&pdev->dev,
 			"failed to connect to smsc_hub through I2C\n");
 
+done:
 	pm_runtime_set_active(&pdev->dev);
 	pm_runtime_enable(&pdev->dev);
 
@@ -524,7 +691,12 @@
 {
 	const struct smsc_hub_platform_data *pdata;
 
+	if (!smsc_hub)
+		return 0;
+
 	pdata = smsc_hub->pdata;
+	if (pdata->model_id == SMSC3502_ID)
+		device_remove_file(&pdev->dev, &dev_attr_enable);
 	if (smsc_hub->client) {
 		i2c_unregister_device(smsc_hub->client);
 		smsc_hub->client = NULL;
@@ -532,7 +704,7 @@
 	}
 	pm_runtime_disable(&pdev->dev);
 
-	if (!IS_ERR(smsc_hub->hub_vbus_reg))
+	if (!IS_ERR_OR_NULL(smsc_hub->hub_vbus_reg))
 		regulator_disable(smsc_hub->hub_vbus_reg);
 	msm_hsic_hub_init_gpio(smsc_hub, 0);
 	msm_hsic_hub_init_clock(smsc_hub, 0);
@@ -553,13 +725,19 @@
 {
 	int ret = 0;
 
+	if (!smsc_hub || !smsc_hub->enabled)
+		return 0;
+
 	if (smsc_hub->xo_handle) {
 		ret = msm_xo_mode_vote(smsc_hub->xo_handle, MSM_XO_MODE_OFF);
 		if (ret) {
 			pr_err("%s: failed to devote for TCXO\n"
 				"D1 buffer%d\n", __func__, ret);
 		}
+	} else if (smsc_hub->pdata->xo_clk_gpio) {
+		gpio_direction_output(smsc_hub->pdata->xo_clk_gpio, 0);
 	}
+
 	return ret;
 }
 
@@ -567,13 +745,19 @@
 {
 	int ret = 0;
 
+	if (!smsc_hub || !smsc_hub->enabled)
+		return 0;
+
 	if (smsc_hub->xo_handle) {
 		ret = msm_xo_mode_vote(smsc_hub->xo_handle, MSM_XO_MODE_ON);
 		if (ret) {
 			pr_err("%s: failed to vote for TCXO\n"
 				"D1 buffer%d\n", __func__, ret);
 		}
+	} else if (smsc_hub->pdata->xo_clk_gpio) {
+		gpio_direction_output(smsc_hub->pdata->xo_clk_gpio, 1);
 	}
+
 	return ret;
 }
 #endif
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 743668b..0c70746 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -198,9 +198,13 @@
 {
 	int ret;
 	struct mmc_blk_data *md = mmc_blk_get(dev_to_disk(dev));
-	struct mmc_card *card = md->queue.card;
+	struct mmc_card *card;
 	int locked = 0;
 
+	if (!md)
+		return -EINVAL;
+
+	card = md->queue.card;
 	if (card->ext_csd.boot_ro_lock & EXT_CSD_BOOT_WP_B_PERM_WP_EN)
 		locked = 2;
 	else if (card->ext_csd.boot_ro_lock & EXT_CSD_BOOT_WP_B_PWR_WP_EN)
@@ -226,6 +230,8 @@
 		return count;
 
 	md = mmc_blk_get(dev_to_disk(dev));
+	if (!md)
+		return -EINVAL;
 	card = md->queue.card;
 
 	mmc_rpm_hold(card->host, &card->dev);
@@ -265,6 +271,9 @@
 	int ret;
 	struct mmc_blk_data *md = mmc_blk_get(dev_to_disk(dev));
 
+	if (!md)
+		return -EINVAL;
+
 	ret = snprintf(buf, PAGE_SIZE, "%d",
 		       get_disk_ro(dev_to_disk(dev)) ^
 		       md->read_only);
@@ -279,6 +288,10 @@
 	char *end;
 	struct mmc_blk_data *md = mmc_blk_get(dev_to_disk(dev));
 	unsigned long set = simple_strtoul(buf, &end, 0);
+
+	if (!md)
+		return -EINVAL;
+
 	if (end == buf) {
 		ret = -EINVAL;
 		goto out;
@@ -299,6 +312,8 @@
 	int num_wr_reqs_to_start_packing;
 	int ret;
 
+	if (!md)
+		return -EINVAL;
 	num_wr_reqs_to_start_packing = md->queue.num_wr_reqs_to_start_packing;
 
 	ret = snprintf(buf, PAGE_SIZE, "%d\n", num_wr_reqs_to_start_packing);
@@ -314,9 +329,13 @@
 {
 	int value;
 	struct mmc_blk_data *md = mmc_blk_get(dev_to_disk(dev));
-	struct mmc_card *card = md->queue.card;
+	struct mmc_card *card;
 	int ret = count;
 
+	if (!md)
+		return -EINVAL;
+
+	card = md->queue.card;
 	if (!card) {
 		ret = -EINVAL;
 		goto exit;
@@ -348,9 +367,13 @@
 				  struct device_attribute *attr, char *buf)
 {
 	struct mmc_blk_data *md = mmc_blk_get(dev_to_disk(dev));
-	struct mmc_card *card = md->queue.card;
+	struct mmc_card *card;
 	int ret;
 
+	if (!md)
+		return -EINVAL;
+
+	card = md->queue.card;
 	if (!card)
 		ret = -EINVAL;
 	else
@@ -368,10 +391,14 @@
 {
 	int value;
 	struct mmc_blk_data *md = mmc_blk_get(dev_to_disk(dev));
-	struct mmc_card *card = md->queue.card;
+	struct mmc_card *card;
 	unsigned int card_size;
 	int ret = count;
 
+	if (!md)
+		return -EINVAL;
+
+	card = md->queue.card;
 	if (!card) {
 		ret = -EINVAL;
 		goto exit;
@@ -409,6 +436,8 @@
 	struct mmc_blk_data *md = mmc_blk_get(dev_to_disk(dev));
 	int ret;
 
+	if (!md)
+		return -EINVAL;
 	ret = snprintf(buf, PAGE_SIZE, "%d\n", md->queue.no_pack_for_random);
 
 	mmc_blk_put(md);
@@ -422,9 +451,13 @@
 {
 	int value;
 	struct mmc_blk_data *md = mmc_blk_get(dev_to_disk(dev));
-	struct mmc_card *card = md->queue.card;
+	struct mmc_card *card;
 	int ret = count;
 
+	if (!md)
+		return -EINVAL;
+
+	card = md->queue.card;
 	if (!card) {
 		ret = -EINVAL;
 		goto exit;
@@ -772,7 +805,7 @@
 	/* make sure this is a rpmb partition */
 	if ((!md) || (!(md->area_type & MMC_BLK_DATA_AREA_RPMB))) {
 		err = -EINVAL;
-		goto cmd_done;
+		return err;
 	}
 
 	idata = mmc_blk_ioctl_rpmb_copy_from_user(ic_ptr);
@@ -2491,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)
@@ -2605,15 +2650,13 @@
 	struct mmc_host *host = card->host;
 	unsigned long flags;
 
+	if (req && !mq->mqrq_prev->req) {
+		mmc_rpm_hold(host, &card->dev);
 #ifdef CONFIG_MMC_BLOCK_DEFERRED_RESUME
 	if (mmc_bus_needs_resume(card->host)) {
 		mmc_resume_bus(card->host);
-		mmc_blk_set_blksize(md, card);
 	}
 #endif
-
-	if (req && !mq->mqrq_prev->req) {
-		mmc_rpm_hold(host, &card->dev);
 		/* claim host only for the first request */
 		mmc_claim_host(card->host);
 		if (card->ext_csd.bkops_en)
@@ -2670,7 +2713,8 @@
 	 */
 	if ((!req && !(mq->flags & MMC_QUEUE_NEW_REQUEST)) ||
 			((mq->flags & MMC_QUEUE_URGENT_REQUEST) &&
-				!(mq->mqrq_cur->req->cmd_flags & REQ_URGENT))) {
+			 !(mq->mqrq_cur->req->cmd_flags &
+				MMC_REQ_NOREINSERT_MASK))) {
 		if (mmc_card_need_bkops(card))
 			mmc_start_bkops(card, false);
 		/* release host only when there are no more requests */
@@ -3073,6 +3117,8 @@
 		  MMC_QUIRK_SEC_ERASE_TRIM_BROKEN),
 	MMC_FIXUP("VZL00M", CID_MANFID_SAMSUNG, CID_OEMID_ANY, add_quirk_mmc,
 		  MMC_QUIRK_SEC_ERASE_TRIM_BROKEN),
+	MMC_FIXUP(CID_NAME_ANY, CID_MANFID_HYNIX, CID_OEMID_ANY, add_quirk_mmc,
+		  MMC_QUIRK_BROKEN_DATA_TIMEOUT),
 
 	END_FIXUP
 };
@@ -3158,6 +3204,9 @@
 	/* send power off notification */
 	if (mmc_card_mmc(card)) {
 		mmc_rpm_hold(card->host, &card->dev);
+		mmc_claim_host(card->host);
+		mmc_stop_bkops(card);
+		mmc_release_host(card->host);
 		mmc_send_long_pon(card);
 		mmc_rpm_release(card->host, &card->dev);
 	}
@@ -3265,4 +3314,3 @@
 
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("Multimedia Card (MMC) block device driver");
-
diff --git a/drivers/mmc/card/mmc_block_test.c b/drivers/mmc/card/mmc_block_test.c
index 39296ef..5cc2806 100644
--- a/drivers/mmc/card/mmc_block_test.c
+++ b/drivers/mmc/card/mmc_block_test.c
@@ -2285,6 +2285,9 @@
 			       size_t count,
 			       loff_t *offset)
 {
+	if (!access_ok(VERIFY_WRITE, buffer, count))
+		return count;
+
 	memset((void *)buffer, 0, count);
 
 	snprintf(buffer, count,
@@ -2383,6 +2386,9 @@
 			       size_t count,
 			       loff_t *offset)
 {
+	if (!access_ok(VERIFY_WRITE, buffer, count))
+		return count;
+
 	memset((void *)buffer, 0, count);
 
 	snprintf(buffer, count,
@@ -2491,6 +2497,9 @@
 			       size_t count,
 			       loff_t *offset)
 {
+	if (!access_ok(VERIFY_WRITE, buffer, count))
+		return count;
+
 	memset((void *)buffer, 0, count);
 
 	snprintf(buffer, count,
@@ -2605,6 +2614,9 @@
 			       size_t count,
 			       loff_t *offset)
 {
+	if (!access_ok(VERIFY_WRITE, buffer, count))
+		return count;
+
 	memset((void *)buffer, 0, count);
 
 	snprintf(buffer, count,
@@ -2730,6 +2742,9 @@
 			       size_t count,
 			       loff_t *offset)
 {
+	if (!access_ok(VERIFY_WRITE, buffer, count))
+		return count;
+
 	memset((void *)buffer, 0, count);
 
 	snprintf(buffer, count,
@@ -2818,6 +2833,9 @@
 			       size_t count,
 			       loff_t *offset)
 {
+	if (!access_ok(VERIFY_WRITE, buffer, count))
+		return count;
+
 	memset((void *)buffer, 0, count);
 
 	snprintf(buffer, count,
@@ -2978,6 +2996,9 @@
 			       size_t count,
 			       loff_t *offset)
 {
+	if (!access_ok(VERIFY_WRITE, buffer, count))
+		return count;
+
 	memset((void *)buffer, 0, count);
 
 	snprintf(buffer, count,
@@ -3051,6 +3072,9 @@
 			       size_t count,
 			       loff_t *offset)
 {
+	if (!access_ok(VERIFY_WRITE, buffer, count))
+		return count;
+
 	memset((void *)buffer, 0, count);
 
 	snprintf(buffer, count,
diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c
index 8986829..fa3dcdc 100644
--- a/drivers/mmc/card/queue.c
+++ b/drivers/mmc/card/queue.c
@@ -79,7 +79,8 @@
 				continue; /* fetch again */
 			} else if ((mq->flags & MMC_QUEUE_URGENT_REQUEST) &&
 				   (mq->mqrq_cur->req &&
-				!(mq->mqrq_cur->req->cmd_flags & REQ_URGENT))) {
+				!(mq->mqrq_cur->req->cmd_flags &
+				       MMC_REQ_NOREINSERT_MASK))) {
 				/*
 				 * clean current request when urgent request
 				 * processing in progress and current request is
@@ -348,22 +349,43 @@
 #endif
 
 	if (!mqrq_cur->bounce_buf && !mqrq_prev->bounce_buf) {
+		unsigned int max_segs = host->max_segs;
+
 		blk_queue_bounce_limit(mq->queue, limit);
 		blk_queue_max_hw_sectors(mq->queue,
 			min(host->max_blk_count, host->max_req_size / 512));
-		blk_queue_max_segments(mq->queue, host->max_segs);
 		blk_queue_max_segment_size(mq->queue, host->max_seg_size);
+retry:
+		blk_queue_max_segments(mq->queue, host->max_segs);
 
 		mqrq_cur->sg = mmc_alloc_sg(host->max_segs, &ret);
-		if (ret)
+		if (ret == -ENOMEM)
+			goto cur_sg_alloc_failed;
+		else if (ret)
 			goto cleanup_queue;
 
-
 		mqrq_prev->sg = mmc_alloc_sg(host->max_segs, &ret);
-		if (ret)
+		if (ret == -ENOMEM)
+			goto prev_sg_alloc_failed;
+		else if (ret)
 			goto cleanup_queue;
+
+		goto success;
+
+prev_sg_alloc_failed:
+		kfree(mqrq_cur->sg);
+		mqrq_cur->sg = NULL;
+cur_sg_alloc_failed:
+		host->max_segs /= 2;
+		if (host->max_segs) {
+			goto retry;
+		} else {
+			host->max_segs = max_segs;
+			goto cleanup_queue;
+		}
 	}
 
+success:
 	sema_init(&mq->thread_sem, 1);
 
 	mq->thread = kthread_run(mmc_queue_thread, mq, "mmcqd/%d%s",
diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
index b36faff..a6fcec5 100644
--- a/drivers/mmc/core/bus.c
+++ b/drivers/mmc/core/bus.c
@@ -421,10 +421,17 @@
 	else if (!mmc_card_sdio(card) && mmc_use_core_runtime_pm(card->host))
 		pm_runtime_enable(&card->dev);
 
+	if (mmc_card_sdio(card)) {
+		ret = device_init_wakeup(&card->dev, true);
+		if (ret)
+			pr_err("%s: %s: failed to init wakeup: %d\n",
+			       mmc_hostname(card->host), __func__, ret);
+	}
 	ret = device_add(&card->dev);
 	if (ret)
 		return ret;
 
+	device_enable_async_suspend(&card->dev);
 	if (mmc_use_core_runtime_pm(card->host) && !mmc_card_sdio(card)) {
 		card->rpm_attrib.show = show_rpm_delay;
 		card->rpm_attrib.store = store_rpm_delay;
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 a296e48..28012ab 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);
@@ -895,7 +924,8 @@
 			mmc_post_req(host, host->areq->mrq, 0);
 			host->areq = NULL;
 			if (areq) {
-				if (!(areq->cmd_flags & REQ_URGENT)) {
+				if (!(areq->cmd_flags &
+						MMC_REQ_NOREINSERT_MASK)) {
 					areq->reinsert_req(areq);
 					mmc_post_req(host, areq->mrq, 0);
 				} else {
@@ -982,6 +1012,10 @@
  */
 void mmc_wait_for_req(struct mmc_host *host, struct mmc_request *mrq)
 {
+#ifdef CONFIG_MMC_BLOCK_DEFERRED_RESUME
+	if (mmc_bus_needs_resume(host))
+		mmc_resume_bus(host);
+#endif
 	__mmc_start_req(host, mrq);
 	mmc_wait_for_req_done(host, mrq);
 }
@@ -1307,6 +1341,11 @@
 		data->timeout_ns = 4000000000u; /* 4s */
 		data->timeout_clks = 0;
 	}
+	/* Some emmc cards require a longer read/write time */
+	if (card->quirks & MMC_QUIRK_BROKEN_DATA_TIMEOUT) {
+		if (data->timeout_ns <  4000000000u)
+			data->timeout_ns = 4000000000u;	/* 4s */
+	}
 }
 EXPORT_SYMBOL(mmc_set_data_timeout);
 
@@ -2005,9 +2044,6 @@
 		host->bus_ops->resume(host);
 	}
 
-	if (host->bus_ops->detect && !host->bus_dead)
-		host->bus_ops->detect(host);
-
 	mmc_bus_put(host);
 	printk("%s: Deferred resume completed\n", mmc_hostname(host));
 	return 0;
@@ -2819,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)) {
@@ -3141,6 +3178,7 @@
 		return;
 
 	mmc_bus_get(host);
+	mmc_rpm_hold(host, &host->class_dev);
 
 	/*
 	 * if there is a _removable_ card registered, check whether it is
@@ -3173,10 +3211,13 @@
 
 	/* if there still is a card present, stop here */
 	if (host->bus_ops != NULL) {
+		mmc_rpm_release(host, &host->class_dev);
 		mmc_bus_put(host);
 		goto out;
 	}
 
+	mmc_rpm_release(host, &host->class_dev);
+
 	/*
 	 * Only we can add a new handler, so it's safe to
 	 * release the lock here.
@@ -3193,7 +3234,8 @@
 	mmc_release_host(host);
 	mmc_rpm_release(host, &host->class_dev);
  out:
-	if (extend_wakelock)
+	/* only extend the wakelock, if suspend has not started yet */
+	if (extend_wakelock && !host->rescan_disable)
 		wake_lock_timeout(&host->detect_wake_lock, HZ / 2);
 
 	if (host->caps & MMC_CAP_NEEDS_POLL)
@@ -3346,7 +3388,8 @@
 	struct mmc_host *host = card->host;
 	int err = 0, rc;
 
-	if (!(host->caps2 & MMC_CAP2_CACHE_CTRL))
+	if (!(host->caps2 & MMC_CAP2_CACHE_CTRL) ||
+	     (card->quirks & MMC_QUIRK_CACHE_DISABLE))
 		return err;
 
 	if (mmc_card_mmc(card) &&
@@ -3385,7 +3428,8 @@
 	int err = 0, rc;
 
 	if (!(host->caps2 & MMC_CAP2_CACHE_CTRL) ||
-			mmc_card_is_removable(host))
+			mmc_card_is_removable(host) ||
+			(card->quirks & MMC_QUIRK_CACHE_DISABLE))
 		return err;
 
 	if (card && mmc_card_mmc(card) &&
@@ -3576,16 +3620,15 @@
 			spin_unlock_irqrestore(&host->lock, flags);
 			break;
 		}
+
+		/* since its suspending anyway, disable rescan */
+		host->rescan_disable = 1;
 		spin_unlock_irqrestore(&host->lock, flags);
 
 		/* Wait for pending detect work to be completed */
 		if (!(host->caps & MMC_CAP_NEEDS_POLL))
 			flush_work(&host->detect.work);
 
-		spin_lock_irqsave(&host->lock, flags);
-		host->rescan_disable = 1;
-		spin_unlock_irqrestore(&host->lock, flags);
-
 		/*
 		 * In some cases, the detect work might be scheduled
 		 * just before rescan_disable is set to true.
@@ -3593,6 +3636,13 @@
 		 */
 		cancel_delayed_work_sync(&host->detect);
 
+		/*
+		 * It is possible that the wake-lock has been acquired, since
+		 * its being suspended, release the wakelock
+		 */
+		if (wake_lock_active(&host->detect_wake_lock))
+			wake_unlock(&host->detect_wake_lock);
+
 		if (!host->bus_ops || host->bus_ops->suspend)
 			break;
 
diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c
index 903decf..4ec8941 100644
--- a/drivers/mmc/core/debugfs.c
+++ b/drivers/mmc/core/debugfs.c
@@ -15,6 +15,7 @@
 #include <linux/slab.h>
 #include <linux/stat.h>
 #include <linux/fault-inject.h>
+#include <linux/uaccess.h>
 
 #include <linux/mmc/card.h>
 #include <linux/mmc/host.h>
@@ -392,6 +393,9 @@
 	if (!card)
 		return cnt;
 
+	if (!access_ok(VERIFY_WRITE, ubuf, cnt))
+		return cnt;
+
 	if (!card->wr_pack_stats.print_in_read)
 		return 0;
 
@@ -532,6 +536,9 @@
 	if (!card)
 		return cnt;
 
+	if (!access_ok(VERIFY_READ, ubuf, cnt))
+		return cnt;
+
 	sscanf(ubuf, "%d", &value);
 	if (value) {
 		mmc_blk_init_packed_statistics(card);
@@ -571,6 +578,9 @@
 	if (!card)
 		return cnt;
 
+	if (!access_ok(VERIFY_WRITE, ubuf, cnt))
+		return cnt;
+
 	bkops_stats = &card->bkops_info.bkops_stats;
 
 	if (!bkops_stats->print_stats)
@@ -637,6 +647,9 @@
 	if (!card)
 		return cnt;
 
+	if (!access_ok(VERIFY_READ, ubuf, cnt))
+		return cnt;
+
 	bkops_stats = &card->bkops_info.bkops_stats;
 
 	sscanf(ubuf, "%d", &value);
diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c
index c7fa876..c4b9724 100644
--- a/drivers/mmc/core/host.c
+++ b/drivers/mmc/core/host.c
@@ -77,16 +77,40 @@
 {
 	struct mmc_host *host = cls_dev_to_mmc_host(dev);
 	int ret = 0;
+	unsigned long flags;
 
 	if (!mmc_use_core_pm(host))
 		return 0;
 
+	spin_lock_irqsave(&host->clk_lock, flags);
+	/*
+	 * let the driver know that suspend is in progress and must
+	 * be aborted on receiving a sdio card interrupt
+	 */
+	host->dev_status = DEV_SUSPENDING;
+	spin_unlock_irqrestore(&host->clk_lock, flags);
 	if (!pm_runtime_suspended(dev)) {
 		ret = mmc_suspend_host(host);
 		if (ret < 0)
 			pr_err("%s: %s: failed: ret: %d\n", mmc_hostname(host),
 			       __func__, ret);
 	}
+	/*
+	 * If SDIO function driver doesn't want to power off the card,
+	 * atleast turn off clocks to allow deep sleep.
+	 */
+	if (!ret && host->card && mmc_card_sdio(host->card) &&
+	    host->ios.clock) {
+		spin_lock_irqsave(&host->clk_lock, flags);
+		host->clk_old = host->ios.clock;
+		host->ios.clock = 0;
+		host->clk_gated = true;
+		spin_unlock_irqrestore(&host->clk_lock, flags);
+		mmc_set_ios(host);
+	}
+	spin_lock_irqsave(&host->clk_lock, flags);
+	host->dev_status = DEV_SUSPENDED;
+	spin_unlock_irqrestore(&host->clk_lock, flags);
 	return ret;
 }
 
@@ -104,6 +128,7 @@
 			pr_err("%s: %s: failed: ret: %d\n", mmc_hostname(host),
 			       __func__, ret);
 	}
+	host->dev_status = DEV_RESUMED;
 	return ret;
 }
 
@@ -697,6 +722,7 @@
 	if (err)
 		return err;
 
+	device_enable_async_suspend(&host->class_dev);
 	led_trigger_register_simple(dev_name(&host->class_dev), &host->led);
 
 #ifdef CONFIG_DEBUG_FS
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index b295bb8..c1f366e 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -66,6 +66,21 @@
 	MMC_FIXUP_EXT_CSD_REV(CID_NAME_ANY, CID_MANFID_HYNIX,
 			      0x014a, add_quirk, MMC_QUIRK_BROKEN_HPI, 5),
 
+	/* Disable HPI feature for Kingstone card */
+	MMC_FIXUP_EXT_CSD_REV("MMC16G", CID_MANFID_KINGSTON, CID_OEMID_ANY,
+			add_quirk, MMC_QUIRK_BROKEN_HPI, 5),
+
+	/*
+	 * Some Hynix cards exhibit data corruption over reboots if cache is
+	 * enabled. Disable cache for all versions until a class of cards that
+	 * show this behavior is identified.
+	 */
+	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
 };
 
@@ -340,6 +355,8 @@
 	card->ext_csd.raw_card_type = ext_csd[EXT_CSD_CARD_TYPE];
 	mmc_select_card_type(card);
 
+	card->ext_csd.raw_drive_strength = ext_csd[EXT_CSD_DRIVE_STRENGTH];
+
 	card->ext_csd.raw_s_a_timeout = ext_csd[EXT_CSD_S_A_TIMEOUT];
 	card->ext_csd.raw_erase_timeout_mult =
 		ext_csd[EXT_CSD_ERASE_TIMEOUT_MULT];
@@ -1247,8 +1264,7 @@
 		mmc_set_clock(host, (unsigned int) (*freq));
 	}
 
-	if ((mmc_card_hs400(card) || mmc_card_hs200(card))
-		&& card->host->ops->execute_tuning) {
+	if (mmc_card_hs200(card) && card->host->ops->execute_tuning) {
 		/*
 		 * We try to probe host driver for tuning for any
 		 * frequency, it is host driver responsibility to
@@ -1557,7 +1573,8 @@
 	 * If HPI is not supported then cache shouldn't be enabled.
 	 */
 	if ((host->caps2 & MMC_CAP2_CACHE_CTRL) &&
-	    (card->ext_csd.cache_size > 0) && card->ext_csd.hpi_en) {
+	    (card->ext_csd.cache_size > 0) && card->ext_csd.hpi_en &&
+	    ((card->quirks & MMC_QUIRK_CACHE_DISABLE) == 0)) {
 		err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
 				EXT_CSD_CACHE_CTRL, 1,
 				card->ext_csd.generic_cmd6_time);
@@ -1700,11 +1717,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/quirks.c b/drivers/mmc/core/quirks.c
index 4407d91..d517205 100644
--- a/drivers/mmc/core/quirks.c
+++ b/drivers/mmc/core/quirks.c
@@ -50,6 +50,14 @@
 #define SDIO_DEVICE_ID_MSM_QCA_AR6003_2	0x301
 #endif
 
+#ifndef SDIO_DEVICE_ID_MSM_QCA_AR6004_1
+#define SDIO_DEVICE_ID_MSM_QCA_AR6004_1	0x400
+#endif
+
+#ifndef SDIO_DEVICE_ID_MSM_QCA_AR6004_2
+#define SDIO_DEVICE_ID_MSM_QCA_AR6004_2	0x401
+#endif
+
 /*
  * This hook just adds a quirk for all sdio devices
  */
@@ -78,6 +86,12 @@
 	SDIO_FIXUP(SDIO_VENDOR_ID_MSM_QCA, SDIO_DEVICE_ID_MSM_QCA_AR6003_2,
 		   remove_quirk, MMC_QUIRK_BROKEN_CLK_GATING),
 
+	SDIO_FIXUP(SDIO_VENDOR_ID_MSM_QCA, SDIO_DEVICE_ID_MSM_QCA_AR6004_1,
+		   remove_quirk, MMC_QUIRK_BROKEN_CLK_GATING),
+
+	SDIO_FIXUP(SDIO_VENDOR_ID_MSM_QCA, SDIO_DEVICE_ID_MSM_QCA_AR6004_2,
+		   remove_quirk, MMC_QUIRK_BROKEN_CLK_GATING),
+
 	SDIO_FIXUP(SDIO_VENDOR_ID_TI, SDIO_DEVICE_ID_TI_WL1271,
 		   add_quirk, MMC_QUIRK_NONSTD_FUNC_IF),
 
diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
index 3648d88..783f512 100644
--- a/drivers/mmc/core/sd.c
+++ b/drivers/mmc/core/sd.c
@@ -851,6 +851,7 @@
 	   ((*rocr & 0x41000000) == 0x41000000)) {
 		err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180, true);
 		if (err) {
+			mmc_power_cycle(host);
 			ocr &= ~SD_OCR_S18R;
 			goto try_again;
 		}
@@ -1131,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);
 }
 
@@ -1398,7 +1399,11 @@
 	 */
 #ifdef CONFIG_MMC_PARANOID_SD_INIT
 	retries = 5;
-	while (retries) {
+	/*
+	 * Some bad cards may take a long time to init, give preference to
+	 * suspend in those cases.
+	 */
+	while (retries && !host->rescan_disable) {
 		err = mmc_sd_init_card(host, host->ocr, NULL);
 		if (err) {
 			retries--;
@@ -1416,6 +1421,9 @@
 		       mmc_hostname(host), err);
 		goto err;
 	}
+
+	if (host->rescan_disable)
+		goto err;
 #else
 	err = mmc_sd_init_card(host, host->ocr, NULL);
 	if (err)
@@ -1439,9 +1447,9 @@
 	mmc_claim_host(host);
 err:
 	mmc_detach_bus(host);
-
-	pr_err("%s: error %d whilst initialising SD card\n",
-		mmc_hostname(host), err);
+	if (err)
+		pr_err("%s: error %d whilst initialising SD card: rescan: %d\n",
+		       mmc_hostname(host), err, host->rescan_disable);
 
 	return err;
 }
diff --git a/drivers/mmc/core/sdio_irq.c b/drivers/mmc/core/sdio_irq.c
index 3d8ceb4..2b48f77 100644
--- a/drivers/mmc/core/sdio_irq.c
+++ b/drivers/mmc/core/sdio_irq.c
@@ -85,6 +85,7 @@
 	struct sched_param param = { .sched_priority = 1 };
 	unsigned long period, idle_period;
 	int ret;
+	bool ws;
 
 	sched_setscheduler(current, SCHED_FIFO, &param);
 
@@ -118,6 +119,17 @@
 		ret = __mmc_claim_host(host, &host->sdio_irq_thread_abort);
 		if (ret)
 			break;
+		ws = false;
+		/*
+		 * prevent suspend if it has started when scheduled;
+		 * 100 msec (approx. value) should be enough for the system to
+		 * resume and attend to the card's request
+		 */
+		if ((host->dev_status == DEV_SUSPENDING) ||
+		    (host->dev_status == DEV_SUSPENDED)) {
+			pm_wakeup_event(&host->card->dev, 100);
+			ws = true;
+		}
 		ret = process_sdio_pending_irqs(host);
 		host->sdio_irq_pending = false;
 		mmc_release_host(host);
@@ -154,6 +166,12 @@
 			host->ops->enable_sdio_irq(host, 1);
 			mmc_host_clk_release(host);
 		}
+		/*
+		 * function drivers would have processed the event from card
+		 * unless suspended, hence release wake source
+		 */
+		if (ws && (host->dev_status == DEV_RESUMED))
+			pm_relax(&host->card->dev);
 		if (!kthread_should_stop())
 			schedule_timeout(period);
 		set_current_state(TASK_RUNNING);
diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
index 4d3a560..2c96d3c 100644
--- a/drivers/mmc/host/sdhci-msm.c
+++ b/drivers/mmc/host/sdhci-msm.c
@@ -2,7 +2,7 @@
  * drivers/mmc/host/sdhci-msm.c - Qualcomm MSM SDHCI Platform
  * driver source file
  *
- * 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
@@ -31,6 +31,7 @@
 #include <linux/delay.h>
 #include <linux/scatterlist.h>
 #include <linux/slab.h>
+#include <linux/irq.h>
 #include <linux/mmc/mmc.h>
 #include <linux/pm.h>
 #include <linux/pm_runtime.h>
@@ -38,10 +39,18 @@
 #include <linux/dma-mapping.h>
 #include <mach/gpio.h>
 #include <mach/msm_bus.h>
+#include <mach/mpm.h>
 #include <linux/iopoll.h>
 
 #include "sdhci-pltfm.h"
 
+enum sdc_mpm_pin_state {
+	SDC_DAT1_DISABLE,
+	SDC_DAT1_ENABLE,
+	SDC_DAT1_ENWAKE,
+	SDC_DAT1_DISWAKE,
+};
+
 #define SDHCI_VER_100		0x2B
 #define CORE_HC_MODE		0x78
 #define HC_MODE_EN		0x1
@@ -156,6 +165,9 @@
 
 #define INVALID_TUNING_PHASE	-1
 
+#define sdhci_is_valid_mpm_wakeup_int(_h) ((_h)->pdata->mpm_sdiowakeup_int >= 0)
+#define sdhci_is_valid_gpio_wakeup_int(_h) ((_h)->pdata->sdiowakeup_irq >= 0)
+
 static const u32 tuning_block_64[] = {
 	0x00FF0FFF, 0xCCC3CCFF, 0xFFCC3CC3, 0xEFFEFFFE,
 	0xDDFFDFFF, 0xFBFFFBFF, 0xFF7FFFBF, 0xEFBDF777,
@@ -283,6 +295,8 @@
 	struct sdhci_msm_bus_voting_data *voting_data;
 	u32 *sup_clk_table;
 	unsigned char sup_clk_cnt;
+	int mpm_sdiowakeup_int;
+	int sdiowakeup_irq;
 };
 
 struct sdhci_msm_bus_vote {
@@ -318,6 +332,7 @@
 	bool calibration_done;
 	u8 saved_tuning_phase;
 	atomic_t controller_clock;
+	bool is_sdiowakeup_enabled;
 };
 
 enum vdd_io_level {
@@ -861,6 +876,14 @@
 		memset(data_buf, 0, size);
 		mmc_wait_for_req(mmc, &mrq);
 
+		/*
+		 * wait for 146 MCLK cycles for the card to send out the data
+		 * and thus move to TRANS state. As the MCLK would be minimum
+		 * 200MHz when tuning is performed, we need maximum 0.73us
+		 * delay. To be on safer side 1ms delay is given.
+		 */
+		if (cmd.error)
+			usleep_range(1000, 1200);
 		if (!cmd.error && !data.error &&
 			!memcmp(data_buf, tuning_block_pattern, size)) {
 			/* tuning is successful at this tuning point */
@@ -1338,7 +1361,7 @@
 	struct device_node *np = dev->of_node;
 	u32 bus_width = 0;
 	u32 cpu_dma_latency;
-	int len, i;
+	int len, i, mpm_int;
 	int clk_table_len;
 	u32 *clk_table = NULL;
 	enum of_gpio_flags flags = OF_GPIO_ACTIVE_LOW;
@@ -1433,6 +1456,12 @@
 	if (of_get_property(np, "qcom,nonremovable", NULL))
 		pdata->nonremovable = true;
 
+	if (!of_property_read_u32(np, "qcom,dat1-mpm-int",
+				  &mpm_int))
+		pdata->mpm_sdiowakeup_int = mpm_int;
+	else
+		pdata->mpm_sdiowakeup_int = -1;
+
 	return pdata;
 out:
 	return NULL;
@@ -1933,6 +1962,39 @@
 	return ret;
 }
 
+/*
+ * Acquire spin-lock host->lock before calling this function
+ */
+static void sdhci_msm_cfg_sdiowakeup_gpio_irq(struct sdhci_host *host,
+					      bool enable)
+{
+	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+	struct sdhci_msm_host *msm_host = pltfm_host->priv;
+
+	if (enable && !msm_host->is_sdiowakeup_enabled)
+		enable_irq(msm_host->pdata->sdiowakeup_irq);
+	else if (!enable && msm_host->is_sdiowakeup_enabled)
+		disable_irq_nosync(msm_host->pdata->sdiowakeup_irq);
+	else
+		dev_warn(&msm_host->pdev->dev, "%s: wakeup to config: %d curr: %d\n",
+			__func__, enable, msm_host->is_sdiowakeup_enabled);
+	msm_host->is_sdiowakeup_enabled = enable;
+}
+
+static irqreturn_t sdhci_msm_sdiowakeup_irq(int irq, void *data)
+{
+	struct sdhci_host *host = (struct sdhci_host *)data;
+	unsigned long flags;
+
+	pr_debug("%s: irq (%d) received\n", __func__, irq);
+
+	spin_lock_irqsave(&host->lock, flags);
+	sdhci_msm_cfg_sdiowakeup_gpio_irq(host, false);
+	spin_unlock_irqrestore(&host->lock, flags);
+
+	return IRQ_HANDLED;
+}
+
 static irqreturn_t sdhci_msm_pwr_irq(int irq, void *data)
 {
 	struct sdhci_host *host = (struct sdhci_host *)data;
@@ -2355,6 +2417,12 @@
 	bool curr_pwrsave;
 
 	if (!clock) {
+		/*
+		 * disable pwrsave to ensure clock is not auto-gated until
+		 * the rate is >400KHz (initialization complete).
+		 */
+		writel_relaxed(readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC) &
+			~CORE_CLK_PWRSAVE, host->ioaddr + CORE_VENDOR_SPEC);
 		sdhci_msm_prepare_clocks(host, false);
 		host->clock = clock;
 		return;
@@ -2603,6 +2671,38 @@
 	.enable_controller_clock = sdhci_msm_enable_controller_clock,
 };
 
+static int sdhci_msm_cfg_mpm_pin_wakeup(struct sdhci_host *host, unsigned mode)
+{
+	int ret = 0;
+	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+	struct sdhci_msm_host *msm_host = pltfm_host->priv;
+	unsigned int pin = msm_host->pdata->mpm_sdiowakeup_int;
+
+	if (!pin)
+		return 0;
+
+	switch (mode) {
+	case SDC_DAT1_DISABLE:
+		ret = msm_mpm_enable_pin(pin, 0);
+		break;
+	case SDC_DAT1_ENABLE:
+		ret = msm_mpm_set_pin_type(pin, IRQ_TYPE_LEVEL_LOW);
+		if (!ret)
+			ret = msm_mpm_enable_pin(pin, 1);
+		break;
+	case SDC_DAT1_ENWAKE:
+		ret = msm_mpm_set_pin_wake(pin, 1);
+		break;
+	case SDC_DAT1_DISWAKE:
+		ret = msm_mpm_set_pin_wake(pin, 0);
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+	return ret;
+}
+
 static int __devinit sdhci_msm_probe(struct platform_device *pdev)
 {
 	struct sdhci_host *host;
@@ -2613,6 +2713,7 @@
 	u32 vdd_max_current;
 	u16 host_version;
 	u32 pwr, irq_status, irq_ctl;
+	unsigned long flags;
 
 	pr_debug("%s: Enter %s\n", dev_name(&pdev->dev), __func__);
 	msm_host = devm_kzalloc(&pdev->dev, sizeof(struct sdhci_msm_host),
@@ -2761,7 +2862,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);
@@ -2804,7 +2905,6 @@
 	host->quirks |= SDHCI_QUIRK_SINGLE_POWER_WRITE;
 	host->quirks |= SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN;
 	host->quirks2 |= SDHCI_QUIRK2_ALWAYS_USE_BASE_CLOCK;
-	host->quirks2 |= SDHCI_QUIRK2_IGNORE_CMDCRC_FOR_TUNING;
 	host->quirks2 |= SDHCI_QUIRK2_USE_MAX_DISCARD_SIZE;
 	host->quirks2 |= SDHCI_QUIRK2_IGNORE_DATATOUT_FOR_R1BCMD;
 	host->quirks2 |= SDHCI_QUIRK2_BROKEN_PRESET_VALUE;
@@ -2831,6 +2931,8 @@
 		host->quirks2 |= SDHCI_QUIRK2_RDWR_TX_ACTIVE_EOT;
 	}
 
+	host->quirks2 |= SDHCI_QUIRK2_IGN_DATA_END_BIT_ERROR;
+
 	/* Setup PWRCTL irq */
 	msm_host->pwr_irq = platform_get_irq_byname(pdev, "pwr_irq");
 	if (msm_host->pwr_irq < 0) {
@@ -2885,7 +2987,7 @@
 	msm_host->mmc->caps2 |= MMC_CAP2_STOP_REQUEST;
 	msm_host->mmc->caps2 |= MMC_CAP2_ASYNC_SDIO_IRQ_4BIT_MODE;
 	msm_host->mmc->caps2 |= MMC_CAP2_CORE_PM;
-	msm_host->mmc->pm_caps |= MMC_PM_KEEP_POWER;
+	msm_host->mmc->pm_caps |= MMC_PM_KEEP_POWER | MMC_PM_WAKE_SDIO_IRQ;
 
 	if (msm_host->pdata->nonremovable)
 		msm_host->mmc->caps |= MMC_CAP_NONREMOVABLE;
@@ -2911,6 +3013,27 @@
 		dev_err(&pdev->dev, "%s: Failed to set dma mask\n", __func__);
 	}
 
+	msm_host->pdata->sdiowakeup_irq = platform_get_irq_byname(pdev,
+							  "sdiowakeup_irq");
+	if (msm_host->pdata->sdiowakeup_irq >= 0) {
+		msm_host->is_sdiowakeup_enabled = true;
+		ret = request_irq(msm_host->pdata->sdiowakeup_irq,
+				  sdhci_msm_sdiowakeup_irq,
+				  IRQF_SHARED | IRQF_TRIGGER_LOW,
+				  "sdhci-msm sdiowakeup", host);
+		if (ret) {
+			dev_err(&pdev->dev, "%s: request sdiowakeup IRQ %d: failed: %d\n",
+				__func__, msm_host->pdata->sdiowakeup_irq, ret);
+			msm_host->pdata->sdiowakeup_irq = -1;
+			msm_host->is_sdiowakeup_enabled = false;
+			goto free_cd_gpio;
+		} else {
+			spin_lock_irqsave(&host->lock, flags);
+			sdhci_msm_cfg_sdiowakeup_gpio_irq(host, false);
+			spin_unlock_irqrestore(&host->lock, flags);
+		}
+	}
+
 	ret = sdhci_add_host(host);
 	if (ret) {
 		dev_err(&pdev->dev, "Add host failed (%d)\n", ret);
@@ -2944,6 +3067,17 @@
 	else if (mmc_use_core_runtime_pm(host->mmc))
 		pm_runtime_enable(&pdev->dev);
 
+	if (msm_host->pdata->mpm_sdiowakeup_int != -1) {
+		ret = sdhci_msm_cfg_mpm_pin_wakeup(host, SDC_DAT1_ENABLE);
+		if (ret) {
+			pr_err("%s: enabling wakeup: failed: ret: %d\n",
+			       mmc_hostname(host->mmc), ret);
+			ret = 0;
+			msm_host->pdata->mpm_sdiowakeup_int = -1;
+		}
+	}
+
+	device_enable_async_suspend(&pdev->dev);
 	/* Successful initialization */
 	goto out;
 
@@ -2955,6 +3089,8 @@
 free_cd_gpio:
 	if (gpio_is_valid(msm_host->pdata->status_gpio))
 		mmc_cd_gpio_free(msm_host->mmc);
+	if (sdhci_is_valid_gpio_wakeup_int(msm_host))
+		free_irq(msm_host->pdata->sdiowakeup_irq, host);
 vreg_deinit:
 	sdhci_msm_vreg_init(&pdev->dev, msm_host->pdata, false);
 bus_unregister:
@@ -3000,6 +3136,12 @@
 	pm_runtime_disable(&pdev->dev);
 	sdhci_pltfm_free(pdev);
 
+	if (sdhci_is_valid_mpm_wakeup_int(msm_host))
+		sdhci_msm_cfg_mpm_pin_wakeup(host, SDC_DAT1_DISABLE);
+
+	if (sdhci_is_valid_gpio_wakeup_int(msm_host))
+		free_irq(msm_host->pdata->sdiowakeup_irq, host);
+
 	if (gpio_is_valid(msm_host->pdata->status_gpio))
 		mmc_cd_gpio_free(msm_host->mmc);
 
@@ -3015,13 +3157,75 @@
 	return 0;
 }
 
+static int sdhci_msm_cfg_sdio_wakeup(struct sdhci_host *host, bool enable)
+{
+	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+	struct sdhci_msm_host *msm_host = pltfm_host->priv;
+	unsigned long flags;
+	int ret = 0;
+
+	if (!(host->mmc->card && mmc_card_sdio(host->mmc->card) &&
+	      (sdhci_is_valid_mpm_wakeup_int(msm_host) ||
+	      sdhci_is_valid_gpio_wakeup_int(msm_host)) &&
+	      mmc_card_wake_sdio_irq(host->mmc))) {
+		return 1;
+	}
+
+	spin_lock_irqsave(&host->lock, flags);
+	if (enable) {
+		/* configure DAT1 gpio if applicable */
+		if (sdhci_is_valid_gpio_wakeup_int(msm_host)) {
+			ret = enable_irq_wake(msm_host->pdata->sdiowakeup_irq);
+			if (!ret)
+				sdhci_msm_cfg_sdiowakeup_gpio_irq(host, true);
+			goto out;
+		} else {
+			ret = sdhci_msm_cfg_mpm_pin_wakeup(host,
+							   SDC_DAT1_ENWAKE);
+			if (ret)
+				goto out;
+			ret = enable_irq_wake(host->irq);
+			if (ret)
+				sdhci_msm_cfg_mpm_pin_wakeup(host,
+							     SDC_DAT1_DISWAKE);
+		}
+	} else {
+		if (sdhci_is_valid_gpio_wakeup_int(msm_host)) {
+			ret = disable_irq_wake(msm_host->pdata->sdiowakeup_irq);
+			sdhci_msm_cfg_sdiowakeup_gpio_irq(host, false);
+		} else {
+			ret = sdhci_msm_cfg_mpm_pin_wakeup(host,
+							   SDC_DAT1_DISWAKE);
+			if (ret)
+				goto out;
+			ret = disable_irq_wake(host->irq);
+		}
+	}
+out:
+	if (ret)
+		pr_err("%s: %s: %sable wakeup: failed: %d gpio: %d mpm: %d\n",
+		       mmc_hostname(host->mmc), __func__, enable ? "en" : "dis",
+		       ret, msm_host->pdata->sdiowakeup_irq,
+		       msm_host->pdata->mpm_sdiowakeup_int);
+	spin_unlock_irqrestore(&host->lock, flags);
+	return ret;
+}
+
 static int sdhci_msm_runtime_suspend(struct device *dev)
 {
 	struct sdhci_host *host = dev_get_drvdata(dev);
 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
 	struct sdhci_msm_host *msm_host = pltfm_host->priv;
+	int ret;
+
+	ret = sdhci_msm_cfg_sdio_wakeup(host, true);
+	/* pwr_irq is not monitored by mpm on suspend, hence disable it */
+	if (!ret)
+		goto skip_disable_host_irq;
 
 	disable_irq(host->irq);
+
+skip_disable_host_irq:
 	disable_irq(msm_host->pwr_irq);
 
 	/*
@@ -3042,10 +3246,17 @@
 	struct sdhci_host *host = dev_get_drvdata(dev);
 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
 	struct sdhci_msm_host *msm_host = pltfm_host->priv;
+	int ret;
 
-	enable_irq(msm_host->pwr_irq);
+	ret = sdhci_msm_cfg_sdio_wakeup(host, false);
+	if (!ret)
+		goto skip_enable_host_irq;
+
 	enable_irq(host->irq);
 
+skip_enable_host_irq:
+	enable_irq(msm_host->pwr_irq);
+
 	return 0;
 }
 
@@ -3097,6 +3308,26 @@
 out:
 	return ret;
 }
+
+static int sdhci_msm_suspend_noirq(struct device *dev)
+{
+	struct sdhci_host *host = dev_get_drvdata(dev);
+	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+	struct sdhci_msm_host *msm_host = pltfm_host->priv;
+	int ret = 0;
+
+	/*
+	 * ksdioirqd may get scheduled after sdhc suspend, hence retry
+	 * suspend in case the clocks are ON
+	 */
+	if (atomic_read(&msm_host->clks_on)) {
+		pr_warn("%s: %s: clock ON after suspend, aborting suspend\n",
+			mmc_hostname(host->mmc), __func__);
+		ret = -EAGAIN;
+	}
+
+	return ret;
+}
 #endif
 
 #ifdef CONFIG_PM
@@ -3104,6 +3335,7 @@
 	SET_SYSTEM_SLEEP_PM_OPS(sdhci_msm_suspend, sdhci_msm_resume)
 	SET_RUNTIME_PM_OPS(sdhci_msm_runtime_suspend, sdhci_msm_runtime_resume,
 			   NULL)
+	.suspend_noirq = sdhci_msm_suspend_noirq,
 };
 
 #define SDHCI_MSM_PMOPS (&sdhci_msm_pmops)
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 830223d..277aef5 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -32,6 +32,7 @@
 #include "sdhci.h"
 
 #define DRIVER_NAME "sdhci"
+#define SDHCI_SUSPEND_TIMEOUT 300 /* 300 ms */
 
 #define DBG(f, x...) \
 	pr_debug(DRIVER_NAME " [%s()]: " f, __func__,## x)
@@ -68,6 +69,12 @@
 }
 #endif
 
+static inline int sdhci_get_async_int_status(struct sdhci_host *host)
+{
+	return (sdhci_readw(host, SDHCI_HOST_CONTROL2) &
+		 SDHCI_CTRL_ASYNC_INT_ENABLE) >> 14;
+}
+
 static void sdhci_dump_state(struct sdhci_host *host)
 {
 	struct mmc_host *mmc = host->mmc;
@@ -746,12 +753,6 @@
 	if (host->quirks & SDHCI_QUIRK_BROKEN_TIMEOUT_VAL)
 		return 0xE;
 
-	/* During initialization, don't use max timeout as the clock is slow */
-	if ((host->quirks2 & SDHCI_QUIRK2_USE_RESERVED_MAX_TIMEOUT) &&
-		(host->clock > 400000)) {
-		return 0xF;
-	}
-
 	/* Unspecified timeout, assume max */
 	if (!data && !cmd->cmd_timeout_ms)
 		return 0xE;
@@ -1498,6 +1499,7 @@
 	struct sdhci_host *host;
 	bool present;
 	unsigned long flags;
+	u32 tuning_opcode;
 
 	host = mmc_priv(mmc);
 
@@ -1508,7 +1510,8 @@
 		mrq->cmd->error = -EIO;
 		if (mrq->data)
 			mrq->data->error = -EIO;
-		tasklet_schedule(&host->finish_tasklet);
+		mmc_request_done(host->mmc, mrq);
+		sdhci_runtime_pm_put(host);
 		return;
 	}
 
@@ -1552,14 +1555,25 @@
 		 * is no on-going data transfer. If so, we need to execute
 		 * tuning procedure before sending command.
 		 */
-		if ((host->flags & SDHCI_NEEDS_RETUNING) &&
+		if ((mrq->cmd->opcode != MMC_SEND_TUNING_BLOCK) &&
+		    (mrq->cmd->opcode != MMC_SEND_TUNING_BLOCK_HS400) &&
+		    (mrq->cmd->opcode != MMC_SEND_TUNING_BLOCK_HS200) &&
+		    (host->flags & SDHCI_NEEDS_RETUNING) &&
 		    !(present_state & (SDHCI_DOING_WRITE | SDHCI_DOING_READ))) {
-			spin_unlock_irqrestore(&host->lock, flags);
-			sdhci_execute_tuning(mmc, mrq->cmd->opcode);
-			spin_lock_irqsave(&host->lock, flags);
+			if (mmc->card) {
+				/* eMMC uses cmd21 but sd and sdio use cmd19 */
+				tuning_opcode =
+					mmc->card->type == MMC_TYPE_MMC ?
+					MMC_SEND_TUNING_BLOCK_HS200 :
+					MMC_SEND_TUNING_BLOCK;
+				host->mrq = NULL;
+				spin_unlock_irqrestore(&host->lock, flags);
+				sdhci_execute_tuning(mmc, tuning_opcode);
+				spin_lock_irqsave(&host->lock, flags);
 
-			/* Restore original mmc_request structure */
-			host->mrq = mrq;
+				/* Restore original mmc_request structure */
+				host->mrq = mrq;
+			}
 		}
 
 		if (mrq->sbc && !(host->flags & SDHCI_AUTO_CMD23))
@@ -1572,6 +1586,33 @@
 	spin_unlock_irqrestore(&host->lock, flags);
 }
 
+static void sdhci_cfg_async_intr(struct sdhci_host *host, bool enable)
+{
+	if (!host->async_int_supp)
+		return;
+
+	if (enable)
+		sdhci_writew(host,
+			     sdhci_readw(host, SDHCI_HOST_CONTROL2) |
+			     SDHCI_CTRL_ASYNC_INT_ENABLE,
+			     SDHCI_HOST_CONTROL2);
+	else
+		sdhci_writew(host, sdhci_readw(host, SDHCI_HOST_CONTROL2) &
+			     ~SDHCI_CTRL_ASYNC_INT_ENABLE,
+			     SDHCI_HOST_CONTROL2);
+}
+
+static void sdhci_cfg_irq(struct sdhci_host *host, bool enable)
+{
+	if (enable && !host->irq_enabled) {
+		enable_irq(host->irq);
+		host->irq_enabled = true;
+	} else if (!enable && host->irq_enabled) {
+		disable_irq_nosync(host->irq);
+		host->irq_enabled = false;
+	}
+}
+
 static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
 {
 	unsigned long flags;
@@ -1587,9 +1628,26 @@
 		return;
 	}
 
-	if (ios->clock)
+	spin_lock_irqsave(&host->lock, flags);
+	/* lock is being released intermittently below, hence disable irq */
+	sdhci_cfg_irq(host, false);
+	spin_unlock_irqrestore(&host->lock, flags);
+	if (ios->clock) {
 		sdhci_set_clock(host, ios->clock);
-
+		if (host->async_int_supp && sdhci_get_async_int_status(host)) {
+			if (host->disable_sdio_irq_deferred) {
+				pr_debug("%s: %s: disable sdio irq\n",
+					 mmc_hostname(host->mmc), __func__);
+				host->mmc->ops->enable_sdio_irq(host->mmc, 0);
+				host->disable_sdio_irq_deferred = false;
+			}
+			spin_lock_irqsave(&host->lock, flags);
+			sdhci_cfg_async_intr(host, false);
+			spin_unlock_irqrestore(&host->lock, flags);
+			pr_debug("%s: %s: unconfig async intr\n",
+				 mmc_hostname(host->mmc), __func__);
+		}
+	}
 	/*
 	 * The controller clocks may be off during power-up and we may end up
 	 * enabling card clock before giving power to the card. Hence, during
@@ -1615,6 +1673,7 @@
 	}
 	spin_lock_irqsave(&host->lock, flags);
 	if (!host->clock) {
+		sdhci_cfg_irq(host, true);
 		spin_unlock_irqrestore(&host->lock, flags);
 		mutex_unlock(&host->ios_mutex);
 		return;
@@ -1774,9 +1833,18 @@
 		if (host->vmmc && vdd_bit != -1)
 			mmc_regulator_set_ocr(host->mmc, host->vmmc, vdd_bit);
 	}
-	if (!ios->clock)
+	if (!ios->clock) {
+		if (host->async_int_supp && host->mmc->card &&
+		    mmc_card_sdio(host->mmc->card)) {
+			sdhci_cfg_async_intr(host, true);
+			pr_debug("%s: %s: config async intr\n",
+				mmc_hostname(host->mmc), __func__);
+		}
 		sdhci_set_clock(host, ios->clock);
-
+	}
+	spin_lock_irqsave(&host->lock, flags);
+	sdhci_cfg_irq(host, true);
+	spin_unlock_irqrestore(&host->lock, flags);
 	mmiowb();
 	mutex_unlock(&host->ios_mutex);
 }
@@ -1856,6 +1924,14 @@
 	if (host->flags & SDHCI_DEVICE_DEAD)
 		goto out;
 
+	if (!enable && !host->clock) {
+		pr_debug("%s: %s: defered disabling card intr\n",
+			 host->mmc ? mmc_hostname(host->mmc) : "null",
+			 __func__);
+		host->disable_sdio_irq_deferred = true;
+		return;
+	}
+
 	if (enable)
 		host->flags |= SDHCI_SDIO_IRQ_ENABLED;
 	else
@@ -2515,18 +2591,9 @@
 			host->cmd->error = -EILSEQ;
 	}
 
-	if (host->quirks2 & SDHCI_QUIRK2_IGNORE_CMDCRC_FOR_TUNING) {
-		if ((host->cmd->opcode == MMC_SEND_TUNING_BLOCK_HS400) ||
-			(host->cmd->opcode == MMC_SEND_TUNING_BLOCK_HS200) ||
-			(host->cmd->opcode == MMC_SEND_TUNING_BLOCK)) {
-			if (intmask & SDHCI_INT_CRC) {
-				sdhci_reset(host, SDHCI_RESET_CMD);
-				host->cmd->error = 0;
-			}
-		}
-	}
-
 	if (host->cmd->error) {
+		if (host->cmd->error == -EILSEQ)
+			host->flags |= SDHCI_NEEDS_RETUNING;
 		tasklet_schedule(&host->finish_tasklet);
 		return;
 	}
@@ -2553,17 +2620,6 @@
 		 * fall through and take the SDHCI_INT_RESPONSE */
 	}
 
-	if (host->quirks2 & SDHCI_QUIRK2_IGNORE_CMDCRC_FOR_TUNING) {
-		if ((host->cmd->opcode == MMC_SEND_TUNING_BLOCK_HS400) ||
-			(host->cmd->opcode == MMC_SEND_TUNING_BLOCK_HS200) ||
-			(host->cmd->opcode == MMC_SEND_TUNING_BLOCK)) {
-			if (intmask & SDHCI_INT_CRC) {
-				sdhci_finish_command(host);
-				return;
-			}
-		}
-	}
-
 	if (intmask & SDHCI_INT_RESPONSE)
 		sdhci_finish_command(host);
 }
@@ -2649,14 +2705,16 @@
 		host->data->error = -EIO;
 	}
 	if (host->data->error) {
-		if ((intmask & (SDHCI_INT_DATA_CRC | SDHCI_INT_DATA_TIMEOUT)) &&
-		    (host->quirks2 & SDHCI_QUIRK2_IGNORE_CMDCRC_FOR_TUNING)) {
+		if (intmask & (SDHCI_INT_DATA_CRC | SDHCI_INT_DATA_TIMEOUT)) {
 			command = SDHCI_GET_CMD(sdhci_readw(host,
 							    SDHCI_COMMAND));
 			if ((command != MMC_SEND_TUNING_BLOCK_HS400) &&
 			    (command != MMC_SEND_TUNING_BLOCK_HS200) &&
-			    (command != MMC_SEND_TUNING_BLOCK))
+			    (command != MMC_SEND_TUNING_BLOCK)) {
 				pr_msg = true;
+				if (intmask & SDHCI_INT_DATA_CRC)
+					host->flags |= SDHCI_NEEDS_RETUNING;
+			}
 		} else {
 			pr_msg = true;
 		}
@@ -2730,6 +2788,23 @@
 		return IRQ_HANDLED;
 	}
 
+	if (!host->clock && host->mmc->card &&
+	    mmc_card_sdio(host->mmc->card)) {
+		/* SDIO async. interrupt is level-sensitive */
+		sdhci_cfg_irq(host, false);
+		pr_debug("%s: got async-irq: clocks: %d gated: %d host-irq[en:1/dis:0]: %d\n",
+			mmc_hostname(host->mmc), host->clock,
+			host->mmc->clk_gated, host->irq_enabled);
+		spin_unlock(&host->lock);
+		/* prevent suspend till the ksdioirqd runs or resume happens */
+		if ((host->mmc->dev_status == DEV_SUSPENDING) ||
+		    (host->mmc->dev_status == DEV_SUSPENDED))
+			pm_wakeup_event(&host->mmc->card->dev,
+					SDHCI_SUSPEND_TIMEOUT);
+		else
+			mmc_signal_sdio_irq(host->mmc);
+		return IRQ_HANDLED;
+	}
 	intmask = sdhci_readl(host, SDHCI_INT_STATUS);
 
 	if (!intmask || intmask == 0xffffffff) {
@@ -2825,9 +2900,13 @@
 	/*
 	 * We have to delay this as it calls back into the driver.
 	 */
-	if (cardint)
+	if (cardint) {
+		/* clks are on, but suspend may be in progress */
+		if (host->mmc->dev_status == DEV_SUSPENDING)
+			pm_wakeup_event(&host->mmc->card->dev,
+					SDHCI_SUSPEND_TIMEOUT);
 		mmc_signal_sdio_irq(host->mmc);
-
+	}
 	return result;
 }
 
@@ -3477,6 +3556,7 @@
 	if (ret)
 		goto untasklet;
 
+	host->irq_enabled = true;
 	host->vmmc = regulator_get(mmc_dev(mmc), "vmmc");
 	if (IS_ERR(host->vmmc)) {
 		pr_info("%s: no vmmc regulator found\n", mmc_hostname(mmc));
@@ -3520,8 +3600,12 @@
 					mmc_hostname(mmc), ret);
 	}
 
+	if (caps[0] & SDHCI_ASYNC_INTR)
+		host->async_int_supp = true;
 	mmc_add_host(mmc);
 
+	if (host->quirks2 & SDHCI_QUIRK2_IGN_DATA_END_BIT_ERROR)
+		sdhci_clear_set_irqs(host, SDHCI_INT_DATA_END_BIT, 0);
 	pr_info("%s: SDHCI controller on %s [%s] using %s\n",
 		mmc_hostname(mmc), host->hw_name, dev_name(mmc_dev(mmc)),
 		(host->flags & SDHCI_USE_ADMA) ? "ADMA" :
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index db4806d..8c2320b 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -175,6 +175,7 @@
 #define   SDHCI_CTRL_DRV_TYPE_D		0x0030
 #define  SDHCI_CTRL_EXEC_TUNING		0x0040
 #define  SDHCI_CTRL_TUNED_CLK		0x0080
+#define  SDHCI_CTRL_ASYNC_INT_ENABLE	0x4000
 #define  SDHCI_CTRL_PRESET_VAL_ENABLE	0x8000
 
 #define SDHCI_CAPABILITIES	0x40
@@ -195,6 +196,7 @@
 #define  SDHCI_CAN_VDD_300	0x02000000
 #define  SDHCI_CAN_VDD_180	0x04000000
 #define  SDHCI_CAN_64BIT	0x10000000
+#define  SDHCI_ASYNC_INTR	0x20000000
 
 #define  SDHCI_SUPPORT_SDR50	0x00000001
 #define  SDHCI_SUPPORT_SDR104	0x00000002
diff --git a/drivers/mtd/devices/msm_qpic_nand.c b/drivers/mtd/devices/msm_qpic_nand.c
index 7f02187..2e06b42 100644
--- a/drivers/mtd/devices/msm_qpic_nand.c
+++ b/drivers/mtd/devices/msm_qpic_nand.c
@@ -1919,7 +1919,7 @@
 	buf = (uint8_t *)dma_buffer + sizeof(*dma_buffer);
 
 	cmd = dma_buffer->cmd;
-	memset(&data, 0, sizeof(struct msm_nand_erase_reg_data));
+	memset(&data, 0, sizeof(struct msm_nand_blk_isbad_data));
 	data.cfg.cmd = MSM_NAND_CMD_PAGE_READ_ALL;
 	data.cfg.cfg0 = chip->cfg0_raw & ~(7U << CW_PER_PAGE);
 	data.cfg.cfg1 = chip->cfg1_raw;
diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c
index 0fde9fc..40d3d9f 100644
--- a/drivers/mtd/ubi/build.c
+++ b/drivers/mtd/ubi/build.c
@@ -1224,7 +1224,11 @@
 		mtd = open_mtd_device(p->name);
 		if (IS_ERR(mtd)) {
 			err = PTR_ERR(mtd);
-			goto out_detach;
+			ubi_err("cannot open mtd %s, error %d", p->name, err);
+			/* See comment below re-ubi_is_module(). */
+			if (ubi_is_module())
+				goto out_detach;
+			continue;
 		}
 
 		mutex_lock(&ubi_devices_mutex);
diff --git a/drivers/mtd/ubi/wl.c b/drivers/mtd/ubi/wl.c
index 7c1a9bf..444e4ff 100644
--- a/drivers/mtd/ubi/wl.c
+++ b/drivers/mtd/ubi/wl.c
@@ -712,6 +712,9 @@
 		if (!(e2->ec - e1->ec >= UBI_WL_THRESHOLD)) {
 			dbg_wl("no WL needed: min used EC %d, max free EC %d",
 			       e1->ec, e2->ec);
+
+			/* Give the unused PEB back */
+			wl_tree_add(e2, &ubi->free);
 			goto out_cancel;
 		}
 		paranoid_check_in_wl_tree(ubi, e1, &ubi->used);
diff --git a/drivers/net/ethernet/msm/ecm_ipa.c b/drivers/net/ethernet/msm/ecm_ipa.c
index 644a751..cc2ade4 100644
--- a/drivers/net/ethernet/msm/ecm_ipa.c
+++ b/drivers/net/ethernet/msm/ecm_ipa.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
@@ -294,6 +294,7 @@
 	params->ecm_ipa_rx_dp_notify = ecm_ipa_packet_receive_notify;
 	params->ecm_ipa_tx_dp_notify = ecm_ipa_tx_complete_notify;
 	params->private = (void *)ecm_ipa_ctx;
+	params->skip_ep_cfg = false;
 	ecm_ipa_ctx->state = ECM_IPA_INITIALIZED;
 	ECM_IPA_STATE_DEBUG(ecm_ipa_ctx);
 
diff --git a/drivers/net/ethernet/msm/msm_rmnet_bam.c b/drivers/net/ethernet/msm/msm_rmnet_bam.c
index 9f06258..7ec317a 100644
--- a/drivers/net/ethernet/msm/msm_rmnet_bam.c
+++ b/drivers/net/ethernet/msm/msm_rmnet_bam.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
@@ -341,6 +341,8 @@
 	if (bam_ret != 0 && bam_ret != -EAGAIN && bam_ret != -EFAULT) {
 		pr_err("[%s] %s: write returned error %d",
 			dev->name, __func__, bam_ret);
+		if (RMNET_IS_MODE_QOS(opmode))
+			skb_pull(skb, sizeof(struct QMI_QOS_HDR_S));
 		return -EPERM;
 	}
 
diff --git a/drivers/net/usb/rmnet_usb_ctrl.c b/drivers/net/usb/rmnet_usb_ctrl.c
index d1f3748..9682b48 100644
--- a/drivers/net/usb/rmnet_usb_ctrl.c
+++ b/drivers/net/usb/rmnet_usb_ctrl.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
@@ -38,10 +38,6 @@
 #define ACM_CTRL_RI		BIT(2)
 #define ACM_CTRL_CD		BIT(3)
 
-/* polling interval for Interrupt ep */
-#define HS_INTERVAL		7
-#define FS_LS_INTERVAL		3
-
 /*echo modem_wait > /sys/class/hsicctl/hsicctlx/modem_wait*/
 static ssize_t modem_wait_store(struct device *d, struct device_attribute *attr,
 		const char *buf, size_t n)
@@ -941,9 +937,7 @@
 		dev->intf->cur_altsetting->desc.bInterfaceNumber;
 	dev->in_ctlreq->wLength = cpu_to_le16(DEFAULT_READ_URB_LENGTH);
 
-	interval = max((int)int_in->desc.bInterval,
-			(udev->speed == USB_SPEED_HIGH) ? HS_INTERVAL
-							: FS_LS_INTERVAL);
+	interval = int_in->desc.bInterval;
 
 	usb_fill_int_urb(dev->inturb, udev,
 			 dev->int_pipe,
diff --git a/drivers/net/usb/rmnet_usb_data.c b/drivers/net/usb/rmnet_usb_data.c
index f9bb5c8..84b3324 100644
--- a/drivers/net/usb/rmnet_usb_data.c
+++ b/drivers/net/usb/rmnet_usb_data.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
@@ -362,13 +362,10 @@
 	return skb;
 }
 
-static __be16 rmnet_ip_type_trans(struct sk_buff *skb,
-	struct net_device *dev)
+static __be16 rmnet_ip_type_trans(struct sk_buff *skb)
 {
 	__be16	protocol = 0;
 
-	skb->dev = dev;
-
 	switch (skb->data[0] & 0xf0) {
 	case 0x40:
 		protocol = htons(ETH_P_IP);
@@ -404,7 +401,6 @@
 			/*map urb to actual network iface based on mux id*/
 			unet_id = unet_offset + mux_id;
 			skb->dev = unet_list[unet_id]->net;
-			entry->dev = unet_list[unet_id];
 		}
 	}
 
@@ -414,7 +410,7 @@
 static int rmnet_usb_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
 {
 	if (test_bit(RMNET_MODE_LLP_IP, &dev->data[0]))
-		skb->protocol = rmnet_ip_type_trans(skb, dev->net);
+		skb->protocol = rmnet_ip_type_trans(skb);
 	else /*set zero for eth mode*/
 		skb->protocol = 0;
 
@@ -554,8 +550,7 @@
 		break;
 
 	default:
-		dev_err(&unet->intf->dev, "[%s] error: "
-			"rmnet_ioct called for unsupported cmd[%d]",
+		dev_dbg(&unet->intf->dev, "[%s] error: rmnet_ioctl called for unsupported cmd[0x%x]\n",
 			dev->name, cmd);
 		return -EINVAL;
 	}
diff --git a/drivers/net/wireless/wcnss/wcnss_vreg.c b/drivers/net/wireless/wcnss/wcnss_vreg.c
index 4713d29..c066acd 100644
--- a/drivers/net/wireless/wcnss/wcnss_vreg.c
+++ b/drivers/net/wireless/wcnss/wcnss_vreg.c
@@ -51,6 +51,8 @@
 #define WCNSS_PMU_CFG_GC_BUS_MUX_SEL_TOP   BIT(5)
 #define WCNSS_PMU_CFG_IRIS_XO_CFG_STS      BIT(6) /* 1: in progress, 0: done */
 
+#define WCNSS_PMU_CFG_IRIS_RESET           BIT(7)
+#define WCNSS_PMU_CFG_IRIS_RESET_STS       BIT(8) /* 1: in progress, 0: done */
 #define WCNSS_PMU_CFG_IRIS_XO_READ         BIT(9)
 #define WCNSS_PMU_CFG_IRIS_XO_READ_STS     BIT(10)
 
@@ -258,6 +260,19 @@
 
 		writel_relaxed(reg, pmu_conf_reg);
 
+		/* Reset IRIS */
+		reg |= WCNSS_PMU_CFG_IRIS_RESET;
+		writel_relaxed(reg, pmu_conf_reg);
+
+		/* Wait for PMU_CFG.iris_reg_reset_sts */
+		while (readl_relaxed(pmu_conf_reg) &
+				WCNSS_PMU_CFG_IRIS_RESET_STS)
+			cpu_relax();
+
+		/* Reset iris reset bit */
+		reg &= ~WCNSS_PMU_CFG_IRIS_RESET;
+		writel_relaxed(reg, pmu_conf_reg);
+
 		/* Start IRIS XO configuration */
 		reg |= WCNSS_PMU_CFG_IRIS_XO_CFG;
 		writel_relaxed(reg, pmu_conf_reg);
diff --git a/drivers/net/wireless/wcnss/wcnss_wlan.c b/drivers/net/wireless/wcnss/wcnss_wlan.c
index 12c5704..e03d5be 100644
--- a/drivers/net/wireless/wcnss/wcnss_wlan.c
+++ b/drivers/net/wireless/wcnss/wcnss_wlan.c
@@ -36,15 +36,18 @@
 #include <linux/mfd/pm8xxx/misc.h>
 #include <linux/qpnp/qpnp-adc.h>
 
+#include <mach/board.h>
 #include <mach/msm_smd.h>
 #include <mach/msm_iomap.h>
 #include <mach/subsystem_restart.h>
+#include <mach/subsystem_notif.h>
 
 #ifdef CONFIG_WCNSS_MEM_PRE_ALLOC
 #include "wcnss_prealloc.h"
 #endif
 
 #define DEVICE "wcnss_wlan"
+#define CTRL_DEVICE "wcnss_ctrl"
 #define VERSION "1.01"
 #define WCNSS_PIL_DEVICE "wcnss"
 
@@ -143,10 +146,28 @@
 #define MSM_PRONTO_PLL_BASE				0xfb21b1c0
 #define PRONTO_PLL_STATUS_OFFSET		0x1c
 
+#define MSM_PRONTO_MCU_BASE			0xfb080c00
+#define MCU_APB2PHY_STATUS_OFFSET		0xec
+#define MCU_CBR_CCAHB_ERR_OFFSET		0x380
+#define MCU_CBR_CAHB_ERR_OFFSET			0x384
+#define MCU_CBR_CCAHB_TIMEOUT_OFFSET		0x388
+#define MCU_CBR_CAHB_TIMEOUT_OFFSET		0x38c
+#define MCU_DBR_CDAHB_ERR_OFFSET		0x390
+#define MCU_DBR_DAHB_ERR_OFFSET			0x394
+#define MCU_DBR_CDAHB_TIMEOUT_OFFSET		0x398
+#define MCU_DBR_DAHB_TIMEOUT_OFFSET		0x39c
+#define MCU_FDBR_CDAHB_ERR_OFFSET		0x3a0
+#define MCU_FDBR_FDAHB_ERR_OFFSET		0x3a4
+#define MCU_FDBR_CDAHB_TIMEOUT_OFFSET		0x3a8
+#define MCU_FDBR_FDAHB_TIMEOUT_OFFSET		0x3ac
+
 #define MSM_PRONTO_TXP_STATUS           0xfb08040c
 #define MSM_PRONTO_TXP_PHY_ABORT        0xfb080488
 #define MSM_PRONTO_BRDG_ERR_SRC         0xfb080fb0
 
+#define MSM_PRONTO_ALARMS_TXCTL         0xfb0120a8
+#define MSM_PRONTO_ALARMS_TACTL         0xfb012448
+
 #define WCNSS_DEF_WLAN_RX_BUFF_COUNT		1024
 #define WCNSS_VBATT_THRESHOLD		3500000
 #define WCNSS_VBATT_GUARD		200
@@ -157,6 +178,17 @@
 #define WCNSS_MAX_FRAME_SIZE		(4*1024)
 #define WCNSS_VERSION_LEN			30
 #define WCNSS_MAX_BUILD_VER_LEN		256
+#define WCNSS_MAX_CMD_LEN		(128)
+#define WCNSS_MIN_CMD_LEN		(3)
+#define WCNSS_MIN_SERIAL_LEN		(6)
+
+/* control messages from userspace */
+#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"
 
 /* message types */
 #define WCNSS_CTRL_MSG_START	0x01000000
@@ -172,6 +204,9 @@
 #define	WCNSS_BUILD_VER_REQ           (WCNSS_CTRL_MSG_START + 9)
 #define	WCNSS_BUILD_VER_RSP           (WCNSS_CTRL_MSG_START + 10)
 
+/* max 20mhz channel count */
+#define WCNSS_MAX_CH_NUM			45
+#define WCNSS_MAX_PIL_RETRY			3
 
 #define VALID_VERSION(version) \
 	((strncmp(version, "INVALID", WCNSS_VERSION_LEN)) ? 1 : 0)
@@ -207,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"
 
 /*
@@ -344,9 +386,12 @@
 	void __iomem *pronto_ccpu_base;
 	void __iomem *pronto_saw2_base;
 	void __iomem *pronto_pll_base;
+	void __iomem *pronto_mcu_base;
 	void __iomem *wlan_tx_status;
 	void __iomem *wlan_tx_phy_aborts;
 	void __iomem *wlan_brdg_err_source;
+	void __iomem *alarms_txctl;
+	void __iomem *alarms_tactl;
 	void __iomem *fiq_reg;
 	int	nv_downloaded;
 	unsigned char *fw_cal_data;
@@ -361,13 +406,64 @@
 	int	device_opened;
 	int	iris_xo_mode_set;
 	int	fw_vbatt_state;
+	int	ctrl_device_opened;
+	char	wlan_nv_macAddr[WLAN_MAC_ADDR_SIZE];
 	struct mutex dev_lock;
+	struct mutex ctrl_lock;
 	wait_queue_head_t read_wait;
 	struct qpnp_adc_tm_btm_param vbat_monitor_params;
 	struct qpnp_adc_tm_chip *adc_tm_dev;
 	struct mutex vbat_monitor_mutex;
+	u16 unsafe_ch_count;
+	u16 unsafe_ch_list[WCNSS_MAX_CH_NUM];
+	void *wcnss_notif_hdle;
+	u8 is_shutdown;
 } *penv = NULL;
 
+static ssize_t wcnss_wlan_macaddr_store(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count)
+{
+	char macAddr[WLAN_MAC_ADDR_SIZE];
+
+	if (!penv)
+		return -ENODEV;
+
+	pr_debug("%s: Receive MAC Addr From user space: %s\n", __func__, buf);
+
+	if (WLAN_MAC_ADDR_SIZE != sscanf(buf, MAC_ADDRESS_STR,
+		 (int *)&macAddr[0], (int *)&macAddr[1],
+		 (int *)&macAddr[2], (int *)&macAddr[3],
+		 (int *)&macAddr[4], (int *)&macAddr[5])) {
+
+		pr_err("%s: Failed to Copy MAC\n", __func__);
+		return -EINVAL;
+	}
+
+	memcpy(penv->wlan_nv_macAddr, macAddr, sizeof(penv->wlan_nv_macAddr));
+
+	pr_info("%s: Write 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]);
+
+	return count;
+}
+
+static ssize_t wcnss_wlan_macaddr_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	if (!penv)
+		return -ENODEV;
+
+	return scnprintf(buf, PAGE_SIZE, MAC_ADDRESS_STR,
+		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]);
+}
+
+static DEVICE_ATTR(wcnss_mac_addr, S_IRUSR | S_IWUSR,
+	wcnss_wlan_macaddr_show, wcnss_wlan_macaddr_store);
+
 static ssize_t wcnss_serial_number_show(struct device *dev,
 				struct device_attribute *attr, char *buf)
 {
@@ -494,45 +590,47 @@
 
 	reg_addr = penv->msm_wcnss_base + PRONTO_PMU_SPARE_OFFSET;
 	reg = readl_relaxed(reg_addr);
-	pr_info_ratelimited("%s:  PRONTO_PMU_SPARE %08x\n", __func__, reg);
+	pr_err("PRONTO_PMU_SPARE %08x\n", reg);
 
 	reg_addr = penv->msm_wcnss_base + PRONTO_PMU_COM_CPU_CBCR_OFFSET;
 	reg = readl_relaxed(reg_addr);
-	pr_info_ratelimited("%s:  PRONTO_PMU_COM_CPU_CBCR %08x\n",
-						__func__, reg);
+	pr_err("PRONTO_PMU_COM_CPU_CBCR %08x\n", reg);
 
 	reg_addr = penv->msm_wcnss_base + PRONTO_PMU_COM_AHB_CBCR_OFFSET;
 	reg = readl_relaxed(reg_addr);
-	pr_info_ratelimited("%s:  PRONTO_PMU_COM_AHB_CBCR %08x\n",
-						__func__, reg);
+	pr_err("PRONTO_PMU_COM_AHB_CBCR %08x\n", reg);
 
 	reg_addr = penv->msm_wcnss_base + PRONTO_PMU_CFG_OFFSET;
 	reg = readl_relaxed(reg_addr);
-	pr_info_ratelimited("%s:  PRONTO_PMU_CFG %08x\n", __func__, reg);
+	pr_err("PRONTO_PMU_CFG %08x\n", reg);
 
 	reg_addr = penv->msm_wcnss_base + PRONTO_PMU_COM_CSR_OFFSET;
 	reg = readl_relaxed(reg_addr);
-	pr_info_ratelimited("%s:  PRONTO_PMU_COM_CSR %08x\n",
-						__func__, reg);
+	pr_err("PRONTO_PMU_COM_CSR %08x\n", reg);
 
 	reg_addr = penv->msm_wcnss_base + PRONTO_PMU_SOFT_RESET_OFFSET;
 	reg = readl_relaxed(reg_addr);
-	pr_info_ratelimited("%s:  PRONTO_PMU_SOFT_RESET %08x\n",
-						__func__, reg);
+	pr_err("PRONTO_PMU_SOFT_RESET %08x\n", reg);
 
 	reg_addr = penv->pronto_saw2_base + PRONTO_SAW2_SPM_STS_OFFSET;
 	reg = readl_relaxed(reg_addr);
-	pr_info_ratelimited("%s: PRONTO_SAW2_SPM_STS %08x\n", __func__, reg);
+	pr_err("PRONTO_SAW2_SPM_STS %08x\n", reg);
+
+	reg_addr = penv->pronto_pll_base + PRONTO_PLL_STATUS_OFFSET;
+	reg = readl_relaxed(reg_addr);
+	pr_err("PRONTO_PLL_STATUS %08x\n", reg);
+
+	reg_addr = penv->msm_wcnss_base + PRONTO_PMU_CPU_AHB_CMD_RCGR_OFFSET;
+	reg4 = readl_relaxed(reg_addr);
+	pr_err("PMU_CPU_CMD_RCGR %08x\n", reg4);
 
 	reg_addr = penv->msm_wcnss_base + PRONTO_PMU_COM_GDSCR_OFFSET;
 	reg = readl_relaxed(reg_addr);
-	pr_info_ratelimited("%s:  PRONTO_PMU_COM_GDSCR %08x\n",
-						__func__, reg);
+	pr_err("PRONTO_PMU_COM_GDSCR %08x\n", reg);
 	reg >>= 31;
 
 	if (!reg) {
-		pr_info_ratelimited("%s:  Cannot log, Pronto common SS is power collapsed\n",
-				__func__);
+		pr_err("Cannot log, Pronto common SS is power collapsed\n");
 		return;
 	}
 	reg &= ~(PRONTO_PMU_COM_GDSCR_SW_COLLAPSE
@@ -546,35 +644,31 @@
 
 	reg_addr = penv->pronto_a2xb_base + A2XB_CFG_OFFSET;
 	reg = readl_relaxed(reg_addr);
-	pr_info_ratelimited("%s: A2XB_CFG_OFFSET %08x\n", __func__, reg);
+	pr_err("A2XB_CFG_OFFSET %08x\n", reg);
 
 	reg_addr = penv->pronto_a2xb_base + A2XB_INT_SRC_OFFSET;
 	reg = readl_relaxed(reg_addr);
-	pr_info_ratelimited("%s: A2XB_INT_SRC_OFFSET %08x\n", __func__, reg);
+	pr_err("A2XB_INT_SRC_OFFSET %08x\n", reg);
 
 	reg_addr = penv->pronto_a2xb_base + A2XB_ERR_INFO_OFFSET;
 	reg = readl_relaxed(reg_addr);
-	pr_info_ratelimited("%s: A2XB_ERR_INFO_OFFSET %08x\n", __func__, reg);
+	pr_err("A2XB_ERR_INFO_OFFSET %08x\n", reg);
 
 	reg_addr = penv->pronto_ccpu_base + CCU_PRONTO_INVALID_ADDR_OFFSET;
 	reg = readl_relaxed(reg_addr);
-	pr_info_ratelimited("%s: CCU_CCPU_INVALID_ADDR %08x\n", __func__, reg);
+	pr_err("CCU_CCPU_INVALID_ADDR %08x\n", reg);
 
 	reg_addr = penv->pronto_ccpu_base + CCU_PRONTO_LAST_ADDR0_OFFSET;
 	reg = readl_relaxed(reg_addr);
-	pr_info_ratelimited("%s: CCU_CCPU_LAST_ADDR0 %08x\n", __func__, reg);
+	pr_err("CCU_CCPU_LAST_ADDR0 %08x\n", reg);
 
 	reg_addr = penv->pronto_ccpu_base + CCU_PRONTO_LAST_ADDR1_OFFSET;
 	reg = readl_relaxed(reg_addr);
-	pr_info_ratelimited("%s: CCU_CCPU_LAST_ADDR1 %08x\n", __func__, reg);
+	pr_err("CCU_CCPU_LAST_ADDR1 %08x\n", reg);
 
 	reg_addr = penv->pronto_ccpu_base + CCU_PRONTO_LAST_ADDR2_OFFSET;
 	reg = readl_relaxed(reg_addr);
-	pr_info_ratelimited("%s: CCU_CCPU_LAST_ADDR2 %08x\n", __func__, reg);
-
-	reg_addr = penv->pronto_pll_base + PRONTO_PLL_STATUS_OFFSET;
-	reg = readl_relaxed(reg_addr);
-	pr_info_ratelimited("%s: PRONTO_PLL_STATUS %08x\n", __func__, reg);
+	pr_err("CCU_CCPU_LAST_ADDR2 %08x\n", reg);
 
 	tst_addr = penv->pronto_a2xb_base + A2XB_TSTBUS_OFFSET;
 	tst_ctrl_addr = penv->pronto_a2xb_base + A2XB_TSTBUS_CTRL_OFFSET;
@@ -584,24 +678,21 @@
 	reg = reg | WCNSS_TSTBUS_CTRL_EN | WCNSS_TSTBUS_CTRL_RDFIFO;
 	writel_relaxed(reg, tst_ctrl_addr);
 	reg = readl_relaxed(tst_addr);
-	pr_info_ratelimited("%s:  Read data FIFO testbus %08x\n",
-					__func__, reg);
+	pr_err("Read data FIFO testbus %08x\n", reg);
 
 	/*  command FIFO */
 	reg = 0;
 	reg = reg | WCNSS_TSTBUS_CTRL_EN | WCNSS_TSTBUS_CTRL_CMDFIFO;
 	writel_relaxed(reg, tst_ctrl_addr);
 	reg = readl_relaxed(tst_addr);
-	pr_info_ratelimited("%s:  Command FIFO testbus %08x\n",
-					__func__, reg);
+	pr_err("Command FIFO testbus %08x\n", reg);
 
 	/*  write data FIFO */
 	reg = 0;
 	reg = reg | WCNSS_TSTBUS_CTRL_EN | WCNSS_TSTBUS_CTRL_WRFIFO;
 	writel_relaxed(reg, tst_ctrl_addr);
 	reg = readl_relaxed(tst_addr);
-	pr_info_ratelimited("%s:  Rrite data FIFO testbus %08x\n",
-					__func__, reg);
+	pr_err("Rrite data FIFO testbus %08x\n", reg);
 
 	/*   AXIM SEL CFG0 */
 	reg = 0;
@@ -609,8 +700,7 @@
 				WCNSS_TSTBUS_CTRL_AXIM_CFG0;
 	writel_relaxed(reg, tst_ctrl_addr);
 	reg = readl_relaxed(tst_addr);
-	pr_info_ratelimited("%s:  AXIM SEL CFG0 testbus %08x\n",
-					__func__, reg);
+	pr_err("AXIM SEL CFG0 testbus %08x\n", reg);
 
 	/*   AXIM SEL CFG1 */
 	reg = 0;
@@ -618,8 +708,7 @@
 				WCNSS_TSTBUS_CTRL_AXIM_CFG1;
 	writel_relaxed(reg, tst_ctrl_addr);
 	reg = readl_relaxed(tst_addr);
-	pr_info_ratelimited("%s:  AXIM SEL CFG1 testbus %08x\n",
-					__func__, reg);
+	pr_err("AXIM SEL CFG1 testbus %08x\n", reg);
 
 	/*   CTRL SEL CFG0 */
 	reg = 0;
@@ -627,8 +716,7 @@
 		WCNSS_TSTBUS_CTRL_CTRL_CFG0;
 	writel_relaxed(reg, tst_ctrl_addr);
 	reg = readl_relaxed(tst_addr);
-	pr_info_ratelimited("%s:  CTRL SEL CFG0 testbus %08x\n",
-					__func__, reg);
+	pr_err("CTRL SEL CFG0 testbus %08x\n", reg);
 
 	/*   CTRL SEL CFG1 */
 	reg = 0;
@@ -636,7 +724,7 @@
 		WCNSS_TSTBUS_CTRL_CTRL_CFG1;
 	writel_relaxed(reg, tst_ctrl_addr);
 	reg = readl_relaxed(tst_addr);
-	pr_info_ratelimited("%s:  CTRL SEL CFG1 testbus %08x\n", __func__, reg);
+	pr_err("CTRL SEL CFG1 testbus %08x\n", reg);
 
 
 	reg_addr = penv->msm_wcnss_base + PRONTO_PMU_WLAN_BCR_OFFSET;
@@ -647,38 +735,132 @@
 
 	reg_addr = penv->msm_wcnss_base + PRONTO_PMU_WLAN_AHB_CBCR_OFFSET;
 	reg3 = readl_relaxed(reg_addr);
-	pr_info_ratelimited("%s:  PMU_WLAN_AHB_CBCR %08x\n", __func__, reg3);
-
-	reg_addr = penv->msm_wcnss_base + PRONTO_PMU_CPU_AHB_CMD_RCGR_OFFSET;
-	reg4 = readl_relaxed(reg_addr);
-	pr_info_ratelimited("%s:  PMU_CPU_CMD_RCGR %08x\n", __func__, reg4);
+	pr_err("PMU_WLAN_AHB_CBCR %08x\n", reg3);
 
 	if ((reg & PRONTO_PMU_WLAN_BCR_BLK_ARES) ||
 		(reg2 & PRONTO_PMU_WLAN_GDSCR_SW_COLLAPSE) ||
 		(!(reg4 & PRONTO_PMU_CPU_AHB_CMD_RCGR_ROOT_EN)) ||
 		(reg3 & PRONTO_PMU_WLAN_AHB_CBCR_CLK_OFF) ||
 		(!(reg3 & PRONTO_PMU_WLAN_AHB_CBCR_CLK_EN))) {
-		pr_info_ratelimited("%s:  Cannot log, wlan domain is power collapsed\n",
-				__func__);
+		pr_err("Cannot log, wlan domain is power collapsed\n");
 		return;
 	}
 
+	msleep(50);
+
 	reg = readl_relaxed(penv->wlan_tx_phy_aborts);
-	pr_info_ratelimited("%s: WLAN_TX_PHY_ABORTS %08x\n", __func__, reg);
+	pr_err("WLAN_TX_PHY_ABORTS %08x\n", reg);
+
+	reg_addr = penv->pronto_mcu_base + MCU_APB2PHY_STATUS_OFFSET;
+	reg = readl_relaxed(reg_addr);
+	pr_err("MCU_APB2PHY_STATUS %08x\n", reg);
+
+	reg_addr = penv->pronto_mcu_base + MCU_CBR_CCAHB_ERR_OFFSET;
+	reg = readl_relaxed(reg_addr);
+	pr_err("MCU_CBR_CCAHB_ERR %08x\n", reg);
+
+	reg_addr = penv->pronto_mcu_base + MCU_CBR_CAHB_ERR_OFFSET;
+	reg = readl_relaxed(reg_addr);
+	pr_err("MCU_CBR_CAHB_ERR %08x\n", reg);
+
+	reg_addr = penv->pronto_mcu_base + MCU_CBR_CCAHB_TIMEOUT_OFFSET;
+	reg = readl_relaxed(reg_addr);
+	pr_err("MCU_CBR_CCAHB_TIMEOUT %08x\n", reg);
+
+	reg_addr = penv->pronto_mcu_base + MCU_CBR_CAHB_TIMEOUT_OFFSET;
+	reg = readl_relaxed(reg_addr);
+	pr_err("MCU_CBR_CAHB_TIMEOUT %08x\n", reg);
+
+	reg_addr = penv->pronto_mcu_base + MCU_DBR_CDAHB_ERR_OFFSET;
+	reg = readl_relaxed(reg_addr);
+	pr_err("MCU_DBR_CDAHB_ERR %08x\n", reg);
+
+	reg_addr = penv->pronto_mcu_base + MCU_DBR_DAHB_ERR_OFFSET;
+	reg = readl_relaxed(reg_addr);
+	pr_err("MCU_DBR_DAHB_ERR %08x\n", reg);
+
+	reg_addr = penv->pronto_mcu_base + MCU_DBR_CDAHB_TIMEOUT_OFFSET;
+	reg = readl_relaxed(reg_addr);
+	pr_err("MCU_DBR_CDAHB_TIMEOUT %08x\n", reg);
+
+	reg_addr = penv->pronto_mcu_base + MCU_DBR_DAHB_TIMEOUT_OFFSET;
+	reg = readl_relaxed(reg_addr);
+	pr_err("MCU_DBR_DAHB_TIMEOUT %08x\n", reg);
+
+	reg_addr = penv->pronto_mcu_base + MCU_FDBR_CDAHB_ERR_OFFSET;
+	reg = readl_relaxed(reg_addr);
+	pr_err("MCU_FDBR_CDAHB_ERR %08x\n", reg);
+
+	reg_addr = penv->pronto_mcu_base + MCU_FDBR_FDAHB_ERR_OFFSET;
+	reg = readl_relaxed(reg_addr);
+	pr_err("MCU_FDBR_FDAHB_ERR %08x\n", reg);
+
+	reg_addr = penv->pronto_mcu_base + MCU_FDBR_CDAHB_TIMEOUT_OFFSET;
+	reg = readl_relaxed(reg_addr);
+	pr_err("MCU_FDBR_CDAHB_TIMEOUT %08x\n", reg);
+
+	reg_addr = penv->pronto_mcu_base + MCU_FDBR_FDAHB_TIMEOUT_OFFSET;
+	reg = readl_relaxed(reg_addr);
+	pr_err("MCU_FDBR_FDAHB_TIMEOUT %08x\n", reg);
 
 	reg = readl_relaxed(penv->wlan_brdg_err_source);
-	pr_info_ratelimited("%s: WLAN_BRDG_ERR_SOURCE %08x\n", __func__, reg);
+	pr_err("WLAN_BRDG_ERR_SOURCE %08x\n", reg);
 
 	reg = readl_relaxed(penv->wlan_tx_status);
-	pr_info_ratelimited("%s: WLAN_TX_STATUS %08x\n", __func__, reg);
+	pr_err("WLAN_TXP_STATUS %08x\n", reg);
+
+	reg = readl_relaxed(penv->alarms_txctl);
+	pr_err("ALARMS_TXCTL %08x\n", reg);
+
+	reg = readl_relaxed(penv->alarms_tactl);
+	pr_err("ALARMS_TACTL %08x\n", reg);
 }
 EXPORT_SYMBOL(wcnss_pronto_log_debug_regs);
 
 #ifdef CONFIG_WCNSS_REGISTER_DUMP_ON_BITE
+static void wcnss_log_iris_regs(void)
+{
+	int i;
+	u32 reg_val;
+	u32 regs_array[] = {
+		0x04, 0x05, 0x11, 0x1e, 0x40, 0x48,
+		0x49, 0x4b, 0x00, 0x01, 0x4d};
+
+	pr_info("IRIS Registers [address] : value\n");
+
+	for (i = 0; i < ARRAY_SIZE(regs_array); i++) {
+		reg_val = wcnss_rf_read_reg(regs_array[i]);
+		pr_info("[0x%08x] : 0x%08x\n", regs_array[i], reg_val);
+	}
+}
+
 void wcnss_log_debug_regs_on_bite(void)
 {
-	if (wcnss_hardware_type() == WCNSS_PRONTO_HW)
-		wcnss_pronto_log_debug_regs();
+	struct platform_device *pdev = wcnss_get_platform_device();
+	struct clk *measure;
+	struct clk *wcnss_debug_mux;
+	unsigned long clk_rate;
+
+	if (wcnss_hardware_type() != WCNSS_PRONTO_HW)
+		return;
+
+	measure = clk_get(&pdev->dev, "measure");
+	wcnss_debug_mux = clk_get(&pdev->dev, "wcnss_debug");
+
+	if (!IS_ERR(measure) && !IS_ERR(wcnss_debug_mux)) {
+		if (clk_set_parent(measure, wcnss_debug_mux))
+			return;
+
+		clk_rate = clk_get_rate(measure);
+		pr_debug("wcnss: clock frequency is: %luHz\n", clk_rate);
+
+		if (clk_rate) {
+			wcnss_pronto_log_debug_regs();
+		} else {
+			pr_err("clock frequency is zero, cannot access PMU or other registers\n");
+			wcnss_log_iris_regs();
+		}
+	}
 }
 #endif
 
@@ -716,8 +898,14 @@
 	if (ret)
 		goto remove_thermal;
 
+	ret = device_create_file(dev, &dev_attr_wcnss_mac_addr);
+	if (ret)
+		goto remove_version;
+
 	return 0;
 
+remove_version:
+	device_remove_file(dev, &dev_attr_wcnss_version);
 remove_thermal:
 	device_remove_file(dev, &dev_attr_thermal_mitigation);
 remove_serial:
@@ -732,6 +920,7 @@
 		device_remove_file(dev, &dev_attr_serial_number);
 		device_remove_file(dev, &dev_attr_thermal_mitigation);
 		device_remove_file(dev, &dev_attr_wcnss_version);
+		device_remove_file(dev, &dev_attr_wcnss_mac_addr);
 	}
 }
 static void wcnss_smd_notify_event(void *data, unsigned int event)
@@ -949,12 +1138,20 @@
 
 int wcnss_device_ready(void)
 {
-	if (penv && penv->pdev && penv->nv_downloaded)
+	if (penv && penv->pdev && penv->nv_downloaded &&
+	    !wcnss_device_is_shutdown())
 		return 1;
 	return 0;
 }
 EXPORT_SYMBOL(wcnss_device_ready);
 
+int wcnss_device_is_shutdown(void)
+{
+	if (penv && penv->is_shutdown)
+		return 1;
+	return 0;
+}
+EXPORT_SYMBOL(wcnss_device_is_shutdown);
 
 struct resource *wcnss_wlan_get_memory_map(struct device *dev)
 {
@@ -1029,6 +1226,20 @@
 }
 EXPORT_SYMBOL(wcnss_get_serial_number);
 
+int wcnss_get_wlan_mac_address(char mac_addr[WLAN_MAC_ADDR_SIZE])
+{
+	if (!penv)
+		return -ENODEV;
+
+	memcpy(mac_addr, penv->wlan_nv_macAddr, WLAN_MAC_ADDR_SIZE);
+	pr_debug("%s: Get 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]);
+	return 0;
+}
+EXPORT_SYMBOL(wcnss_get_wlan_mac_address);
+
 static int enable_wcnss_suspend_notify;
 
 static int enable_wcnss_suspend_notify_set(const char *val,
@@ -1166,6 +1377,35 @@
 }
 EXPORT_SYMBOL(wcnss_get_wlan_rx_buff_count);
 
+int wcnss_set_wlan_unsafe_channel(u16 *unsafe_ch_list, u16 ch_count)
+{
+	if (penv && unsafe_ch_list &&
+		(ch_count <= WCNSS_MAX_CH_NUM)) {
+		memcpy((char *)penv->unsafe_ch_list,
+			(char *)unsafe_ch_list, ch_count * sizeof(u16));
+		penv->unsafe_ch_count = ch_count;
+		return 0;
+	} else
+		return -ENODEV;
+}
+EXPORT_SYMBOL(wcnss_set_wlan_unsafe_channel);
+
+int wcnss_get_wlan_unsafe_channel(u16 *unsafe_ch_list, u16 buffer_size,
+					u16 *ch_count)
+{
+	if (penv) {
+		if (buffer_size < penv->unsafe_ch_count * sizeof(u16))
+			return -ENODEV;
+		memcpy((char *)unsafe_ch_list,
+			(char *)penv->unsafe_ch_list,
+			penv->unsafe_ch_count * sizeof(u16));
+		*ch_count = penv->unsafe_ch_count;
+		return 0;
+	} else
+		return -ENODEV;
+}
+EXPORT_SYMBOL(wcnss_get_wlan_unsafe_channel);
+
 static int wcnss_smd_tx(void *data, int len)
 {
 	int ret = 0;
@@ -1823,6 +2063,90 @@
 	.notifier_call = wcnss_pm_notify,
 };
 
+static int wcnss_ctrl_open(struct inode *inode, struct file *file)
+{
+	int rc = 0;
+
+	if (!penv || penv->ctrl_device_opened)
+		return -EFAULT;
+
+	penv->ctrl_device_opened = 1;
+
+	return rc;
+}
+
+
+void process_usr_ctrl_cmd(u8 *buf, size_t len)
+{
+	u16 cmd = buf[0] << 8 | buf[1];
+
+	switch (cmd) {
+
+	case WCNSS_USR_SERIAL_NUM:
+		if (WCNSS_MIN_SERIAL_LEN > len) {
+			pr_err("%s: Invalid serial number\n", __func__);
+			return;
+		}
+		penv->serial_number = buf[2] << 24 | buf[3] << 16
+			| buf[4] << 8 | buf[5];
+		break;
+
+	case WCNSS_USR_HAS_CAL_DATA:
+		if (1 < buf[2])
+			pr_err("%s: Invalid data for cal %d\n", __func__,
+				buf[2]);
+		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;
+	}
+}
+
+static ssize_t wcnss_ctrl_write(struct file *fp, const char __user
+			*user_buffer, size_t count, loff_t *position)
+{
+	int rc = 0;
+	u8 buf[WCNSS_MAX_CMD_LEN];
+
+	if (!penv || !penv->ctrl_device_opened || WCNSS_MAX_CMD_LEN < count
+			|| WCNSS_MIN_CMD_LEN > count)
+		return -EFAULT;
+
+	mutex_lock(&penv->ctrl_lock);
+	rc = copy_from_user(buf, user_buffer, count);
+	if (0 == rc)
+		process_usr_ctrl_cmd(buf, count);
+
+	mutex_unlock(&penv->ctrl_lock);
+
+	return rc;
+}
+
+
+static const struct file_operations wcnss_ctrl_fops = {
+	.owner = THIS_MODULE,
+	.open = wcnss_ctrl_open,
+	.write = wcnss_ctrl_write,
+};
+
+static struct miscdevice wcnss_usr_ctrl = {
+	.minor = MISC_DYNAMIC_MINOR,
+	.name = CTRL_DEVICE,
+	.fops = &wcnss_ctrl_fops,
+};
+
 static int
 wcnss_trigger_config(struct platform_device *pdev)
 {
@@ -1831,6 +2155,7 @@
 	unsigned long wcnss_phys_addr;
 	int size = 0;
 	struct resource *res;
+	int pil_retry = 0;
 	int has_pronto_hw = of_property_read_bool(pdev->dev.of_node,
 									"qcom,has-pronto-hw");
 
@@ -2000,6 +2325,25 @@
 			pr_err("%s: ioremap wlan TX STATUS failed\n", __func__);
 			goto fail_ioremap9;
 		}
+		penv->alarms_txctl = ioremap(MSM_PRONTO_ALARMS_TXCTL, SZ_8);
+		if (!penv->alarms_txctl) {
+			ret = -ENOMEM;
+			pr_err("%s: ioremap alarms TXCTL failed\n", __func__);
+			goto fail_ioremap10;
+		}
+		penv->alarms_tactl = ioremap(MSM_PRONTO_ALARMS_TACTL, SZ_8);
+		if (!penv->alarms_tactl) {
+			ret = -ENOMEM;
+			pr_err("%s: ioremap alarms TACTL failed\n", __func__);
+			goto fail_ioremap11;
+		}
+		penv->pronto_mcu_base = ioremap(MSM_PRONTO_MCU_BASE, SZ_1K);
+		if (!penv->pronto_mcu_base) {
+			ret = -ENOMEM;
+			pr_err("%s: ioremap wcnss physical(mcu) failed\n",
+				__func__);
+			goto fail_ioremap12;
+		}
 	}
 	penv->adc_tm_dev = qpnp_get_adc_tm(&penv->pdev->dev, "wcnss");
 	if (IS_ERR(penv->adc_tm_dev)) {
@@ -2010,12 +2354,21 @@
 		penv->fw_vbatt_state = WCNSS_CONFIG_UNSPECIFIED;
 	}
 
-	/* trigger initialization of the WCNSS */
-	penv->pil = subsystem_get(WCNSS_PIL_DEVICE);
-	if (IS_ERR(penv->pil)) {
-		dev_err(&pdev->dev, "Peripheral Loader failed on WCNSS.\n");
-		ret = PTR_ERR(penv->pil);
-		wcnss_pronto_log_debug_regs();
+	do {
+		/* trigger initialization of the WCNSS */
+		penv->pil = subsystem_get(WCNSS_PIL_DEVICE);
+		if (IS_ERR(penv->pil)) {
+			dev_err(&pdev->dev, "Peripheral Loader failed on WCNSS.\n");
+			ret = PTR_ERR(penv->pil);
+			wcnss_pronto_log_debug_regs();
+		}
+	} 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;
 	}
@@ -2025,6 +2378,15 @@
 fail_pil:
 	if (penv->riva_ccu_base)
 		iounmap(penv->riva_ccu_base);
+	if (penv->pronto_mcu_base)
+		iounmap(penv->pronto_mcu_base);
+fail_ioremap12:
+	if (penv->alarms_tactl)
+		iounmap(penv->alarms_tactl);
+fail_ioremap11:
+	if (penv->alarms_txctl)
+		iounmap(penv->alarms_txctl);
+fail_ioremap10:
 	if (penv->wlan_tx_status)
 		iounmap(penv->wlan_tx_status);
 fail_ioremap9:
@@ -2185,6 +2547,21 @@
 }
 
 
+static int wcnss_notif_cb(struct notifier_block *this, unsigned long code,
+				void *ss_handle)
+{
+	pr_debug("%s: wcnss notification event: %lu\n", __func__, code);
+
+	if (SUBSYS_POWERUP_FAILURE == code)
+		wcnss_pronto_log_debug_regs();
+	else if (SUBSYS_BEFORE_SHUTDOWN == code)
+		penv->is_shutdown = 1;
+	else if (SUBSYS_AFTER_POWERUP == code)
+		penv->is_shutdown = 0;
+
+	return NOTIFY_DONE;
+}
+
 static const struct file_operations wcnss_node_fops = {
 	.owner = THIS_MODULE,
 	.open = wcnss_node_open,
@@ -2224,7 +2601,15 @@
 		return -ENOENT;
 	}
 
+	/* register wcnss event notification */
+	penv->wcnss_notif_hdle = subsys_notif_register_notifier("wcnss", &wnb);
+	if (IS_ERR(penv->wcnss_notif_hdle)) {
+		pr_err("wcnss: register event notification failed!\n");
+		return PTR_ERR(penv->wcnss_notif_hdle);
+	}
+
 	mutex_init(&penv->dev_lock);
+	mutex_init(&penv->ctrl_lock);
 	mutex_init(&penv->vbat_monitor_mutex);
 	init_waitqueue_head(&penv->read_wait);
 
@@ -2237,6 +2622,9 @@
 	 * place
 	 */
 	pr_info(DEVICE " probed in built-in mode\n");
+
+	misc_register(&wcnss_usr_ctrl);
+
 	return misc_register(&wcnss_misc);
 
 }
@@ -2244,6 +2632,8 @@
 static int __devexit
 wcnss_wlan_remove(struct platform_device *pdev)
 {
+	if (penv->wcnss_notif_hdle)
+		subsys_notif_unregister_notifier(penv->wcnss_notif_hdle, &wnb);
 	wcnss_remove_sysfs(&pdev->dev);
 	penv = NULL;
 	return 0;
diff --git a/drivers/nfc/nfc-nci.c b/drivers/nfc/nfc-nci.c
index 99e17a6..018c3a6 100644
--- a/drivers/nfc/nfc-nci.c
+++ b/drivers/nfc/nfc-nci.c
@@ -13,6 +13,7 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/fs.h>
+#include <linux/reboot.h>
 #include <linux/slab.h>
 #include <linux/i2c.h>
 #include <linux/irq.h>
@@ -30,10 +31,12 @@
 
 struct qca199x_platform_data {
 	unsigned int irq_gpio;
+	unsigned int	irq_gpio_clk_req;
+	unsigned int	clk_req_irq_num;
 	unsigned int dis_gpio;
-	unsigned int ven_gpio;
+	unsigned int clkreq_gpio;
 	unsigned int reg;
-	const char *clk_src;
+	const char *clk_src_name;
 	unsigned int clk_src_gpio;
 };
 
@@ -44,30 +47,62 @@
 
 MODULE_DEVICE_TABLE(of, msm_match_table);
 
-#define MAX_BUFFER_SIZE		(780)
+#define MAX_BUFFER_SIZE			(780)
+#define PACKET_MAX_LENGTH		(258)
 /* Read data */
 #define PACKET_HEADER_SIZE_NCI	(4)
-#define PACKET_TYPE_NCI		(16)
-#define MAX_PACKET_SIZE		(PACKET_HEADER_SIZE_NCI + 255)
-#define MAX_QCA_REG		(116)
+#define PACKET_TYPE_NCI			(16)
+#define MAX_PACKET_SIZE			(PACKET_HEADER_SIZE_NCI + 255)
+#define MAX_QCA_REG				(116)
+/* will timeout in approx. 100ms as 10us steps */
+#define NFC_RF_CLK_FREQ			(19200000)
+#define NTF_TIMEOUT				(10000)
+#define	CORE_RESET_RSP_GID		(0x60)
+#define	CORE_RESET_OID			(0x00)
+#define CORE_RST_NTF_LENGTH		(0x02)
 
-static int nfc_i2c_write(struct i2c_client *client, u8 *buf, int len);
-static int nfcc_initialise(struct i2c_client *client, unsigned short curr_addr);
+static void clk_req_update(struct work_struct *work);
 
 struct qca199x_dev {
 	wait_queue_head_t read_wq;
-	struct mutex read_mutex;
-	struct i2c_client *client;
-	struct miscdevice qca199x_device;
-	unsigned int irq_gpio;
-	unsigned int dis_gpio;
-	unsigned int ven_gpio;
-	bool irq_enabled;
-	spinlock_t irq_enabled_lock;
-	unsigned int count_irq;
+	struct	mutex		read_mutex;
+	struct	i2c_client	*client;
+	struct	miscdevice	qca199x_device;
+	/* NFC_IRQ new NCI data available */
+	unsigned int		irq_gpio;
+	/* CLK_REQ IRQ to signal the state has changed */
+	unsigned int		irq_gpio_clk_req;
+	/* Actual IRQ no. assigned to CLK_REQ */
+	unsigned int		clk_req_irq_num;
+	unsigned int		dis_gpio;
+	unsigned int		clkreq_gpio;
+	/* NFC_IRQ state */
+	bool			irq_enabled;
+	bool			sent_first_nci_write;
+	spinlock_t		irq_enabled_lock;
+	unsigned int		count_irq;
+	/* CLK_REQ IRQ state */
+	bool			irq_enabled_clk_req;
+	spinlock_t		irq_enabled_lock_clk_req;
+	unsigned int		count_irq_clk_req;
 	enum	nfcc_state	state;
+	/* CLK control */
+	unsigned int		clk_src_gpio;
+	const	char		*clk_src_name;
+	struct	clk		*s_clk;
+	bool			clk_run;
+	struct work_struct	msm_clock_controll_work;
+	struct workqueue_struct *my_wq;
 };
 
+static int nfc_i2c_write(struct i2c_client *client, u8 *buf, int len);
+static int nfcc_hw_check(struct i2c_client *client, unsigned short curr_addr);
+static int nfcc_initialise(struct i2c_client *client, unsigned short curr_addr);
+static int qca199x_clock_select(struct qca199x_dev *qca199x_dev);
+static int qca199x_clock_deselect(struct qca199x_dev *qca199x_dev);
+
+
+
 /*
  * To allow filtering of nfc logging from user. This is set via
  * IOCTL NFC_KERNEL_LOGGING_MODE.
@@ -76,9 +111,13 @@
 /*
  * FTM-RAW-I2C RD/WR MODE
  */
-static struct	devicemode	device_mode;
-static int	ftm_raw_write_mode;
-static int	ftm_werr_code;
+static struct devicemode	device_mode;
+static int					ftm_raw_write_mode;
+static int					ftm_werr_code;
+
+
+unsigned int	disable_ctrl;
+bool		region2_sent;
 
 static void qca199x_init_stat(struct qca199x_dev *qca199x_dev)
 {
@@ -140,6 +179,95 @@
 	return mask;
 }
 
+/* Handlers for CLK_REQ */
+static void qca199x_disable_irq_clk_req(struct qca199x_dev *qca199x_dev)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&qca199x_dev->irq_enabled_lock_clk_req, flags);
+	if (qca199x_dev->irq_enabled_clk_req) {
+		disable_irq_nosync(qca199x_dev->clk_req_irq_num);
+		qca199x_dev->irq_enabled_clk_req = false;
+	}
+	spin_unlock_irqrestore(&qca199x_dev->irq_enabled_lock_clk_req, flags);
+}
+
+
+static void qca199x_enable_irq_clk_req(struct qca199x_dev *qca199x_dev)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&qca199x_dev->irq_enabled_lock_clk_req, flags);
+	if (!qca199x_dev->irq_enabled_clk_req) {
+		qca199x_dev->irq_enabled_clk_req = true;
+		enable_irq(qca199x_dev->clk_req_irq_num);
+	}
+	spin_unlock_irqrestore(&qca199x_dev->irq_enabled_lock_clk_req, flags);
+}
+
+
+static irqreturn_t qca199x_dev_irq_handler_clk_req(int irq, void *dev_id)
+{
+	struct qca199x_dev *qca199x_dev = dev_id;
+	unsigned long flags;
+
+	spin_lock_irqsave(&qca199x_dev->irq_enabled_lock_clk_req, flags);
+	qca199x_dev->count_irq_clk_req++;
+	spin_unlock_irqrestore(&qca199x_dev->irq_enabled_lock_clk_req, flags);
+
+	queue_work(qca199x_dev->my_wq, &qca199x_dev->msm_clock_controll_work);
+
+	return IRQ_HANDLED;
+}
+
+
+static struct gpiomux_setting nfc_clk_on = {
+	.func = GPIOMUX_FUNC_2,
+	.drv  = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+static struct gpiomux_setting nfc_clk_on_suspend = {
+	.func = GPIOMUX_FUNC_2,
+	.drv  = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_DOWN,
+};
+static struct gpiomux_setting nfc_clk_off = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv  = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_DOWN,
+};
+
+static void clk_req_update(struct work_struct *work)
+{
+	struct	i2c_client *client;
+	struct	qca199x_dev *qca199x_dev;
+	int		gpio_clk_req_level = 0;
+
+	qca199x_dev =	container_of(work, struct qca199x_dev,
+			msm_clock_controll_work);
+	client =	qca199x_dev->client;
+
+	/* Read status level of CLK_REQ from NFC Controller, QCA199_x */
+	gpio_clk_req_level = gpio_get_value(qca199x_dev->irq_gpio_clk_req);
+	if (gpio_clk_req_level == 1) {
+		if (qca199x_dev->clk_run == false) {
+			msm_gpiomux_write(qca199x_dev->clk_src_gpio,
+				GPIOMUX_ACTIVE, &nfc_clk_on, NULL);
+			msm_gpiomux_write(qca199x_dev->clk_src_gpio,
+				GPIOMUX_SUSPENDED, &nfc_clk_on_suspend, NULL);
+			qca199x_dev->clk_run = true;
+			}
+	} else{
+		if (qca199x_dev->clk_run == true) {
+			msm_gpiomux_write(qca199x_dev->clk_src_gpio,
+				GPIOMUX_ACTIVE, &nfc_clk_off, NULL);
+			msm_gpiomux_write(qca199x_dev->clk_src_gpio,
+				GPIOMUX_SUSPENDED, &nfc_clk_off, NULL);
+			qca199x_dev->clk_run = false;
+		}
+	}
+}
+
 /*
  * ONLY for FTM-RAW-I2C Mode
  * Required to instigate a read, which comes from DT layer. This means we need
@@ -205,23 +333,33 @@
 	/* NORMAL NCI Behaviour */
 	/* Read the header */
 	ret = i2c_master_recv(qca199x_dev->client, len, PAYLOAD_HEADER_LENGTH);
+	/*
+		We ignore all packets of length PAYLOAD_HEADER_LENGTH
+		or less (i.e <=3). In this case return a total length
+		of ZERO. So ALL PACKETS MUST HAVE A PAYLOAD.
+		If ret < 0 then this is an error code.
+	*/
 	if (ret != PAYLOAD_HEADER_LENGTH) {
-		total = 0;
+		if (ret < 0)
+			total = ret;
+		else
+			total = 0;
 		goto err;
 	}
 	length = len[PAYLOAD_HEADER_LENGTH - 1];
-	if (length == 0)
-		total = 0;
+	if (length == 0) {
+		ret = 0;
+		total = ret;
+		goto err;
+	}
 	/** make sure full packet fits in the buffer **/
 	if ((length > 0) && ((length + PAYLOAD_HEADER_LENGTH) <= count)) {
 		/* Read the packet */
 		ret = i2c_master_recv(qca199x_dev->client, tmp, (length +
 			PAYLOAD_HEADER_LENGTH));
-		if (ret < 0) {
-			total = 0;
+		total = ret;
+		if (ret < 0)
 			goto err;
-		}
-		total = (length + PAYLOAD_HEADER_LENGTH);
 	}
 
 	if (total > 0) {
@@ -232,14 +370,57 @@
 			total = -EFAULT;
 		}
 	}
-	mutex_unlock(&qca199x_dev->read_mutex);
 err:
-	if (ret < 0)
 		mutex_unlock(&qca199x_dev->read_mutex);
 done:
 	return total;
 }
 
+/*
+	Local routine to read from nfcc buffer. This is called to clear any
+	pending receive messages in the nfcc's read buffer, which may be there
+	following a POR. In this way, the upper layers (Device Transport) will
+	associate the next rsp/ntf nci message with the next nci command to the
+	nfcc. Otherwise, the DT may interpret a ntf from the nfcc as being from
+	the nci core reset command when in fact it was already present in the
+	nfcc read buffer following a POR.
+*/
+
+int nfcc_read_buff_svc(struct qca199x_dev *qca199x_dev)
+{
+	unsigned char tmp[PACKET_MAX_LENGTH];
+	unsigned char len[PAYLOAD_HEADER_LENGTH];
+	int total, length, ret;
+	total = 0;
+	length = 0;
+	mutex_lock(&qca199x_dev->read_mutex);
+	memset(tmp, 0, sizeof(tmp));
+	memset(len, 0, sizeof(len));
+
+	/* Read the header */
+	ret = i2c_master_recv(qca199x_dev->client, len, PAYLOAD_HEADER_LENGTH);
+	if (ret < PAYLOAD_HEADER_LENGTH) {
+		total = ret;
+		goto leave;
+	}
+	length = len[PAYLOAD_HEADER_LENGTH - 1];
+	if (length == 0) {
+		ret = PAYLOAD_HEADER_LENGTH;
+		total = ret;
+		goto leave;
+	}
+	/** make sure full packet fits in the buffer **/
+	if ((length > 0) && ((length + PAYLOAD_HEADER_LENGTH) <= PACKET_MAX_LENGTH)) {
+		/* Read the packet */
+		ret = i2c_master_recv(qca199x_dev->client, tmp, (length +
+			PAYLOAD_HEADER_LENGTH));
+		total = ret;
+	}
+leave:
+	mutex_unlock(&qca199x_dev->read_mutex);
+	return total;
+}
+
 static ssize_t nfc_write(struct file *filp, const char __user *buf,
 				size_t count, loff_t *offset)
 {
@@ -247,6 +428,7 @@
 	char tmp[MAX_BUFFER_SIZE];
 	int ret = 0;
 	enum ehandler_mode dmode;
+	int nfcc_buffer = 0;
 
 	if (count > MAX_BUFFER_SIZE) {
 		dev_err(&qca199x_dev->client->dev, "out of memory\n");
@@ -257,10 +439,28 @@
 			"nfc-nci write: failed to copy from user space\n");
 		return -EFAULT;
 	}
+	/*
+		A catch for when the DT is sending the initial NCI write
+		following a hardware POR. In this case we should clear any
+		pending messages in nfcc buffer and open the interrupt gate
+		for new messages coming from the nfcc.
+	*/
+	if ((qca199x_dev->sent_first_nci_write == false) &&
+		 (qca199x_dev->irq_enabled == false)) {
+		/* check rsp/ntf from nfcc read-side buffer */
+		nfcc_buffer = nfcc_read_buff_svc(qca199x_dev);
+		/* There has been an error while reading from nfcc */
+		if (nfcc_buffer < 0) {
+			dev_err(&qca199x_dev->client->dev,
+				"nfc-nci write: error while servicing nfcc read buffer\n");
+		}
+		qca199x_dev->sent_first_nci_write = true;
+		qca199x_enable_irq(qca199x_dev);
+	}
 	mutex_lock(&qca199x_dev->read_mutex);
 	dmode = device_mode.handle_flavour;
 	/* FTM-DIRECT-I2C RD/WR MODE */
-	/* This is a special FTM-i2c mode case,where tester is not using NCI */
+	/* This is a special FTM-i2c mode case, where tester is not using NCI */
 	if ((dmode == UNSOLICITED_FTM_RAW_MODE) ||
 		(dmode == SOLICITED_FTM_RAW_MODE)) {
 		/* Read From Register */
@@ -295,6 +495,12 @@
 	}
 	mutex_unlock(&qca199x_dev->read_mutex);
 
+	/* If we detect a Region2 command prior to power-down */
+	if ((tmp[0] == 0x2F) && (tmp[1] == 0x01) && (tmp[2] == 0x02) &&
+		(tmp[3] == 0x08) && (tmp[4] == 0x00)) {
+		region2_sent = true;
+	}
+
 	return ret;
 }
 
@@ -308,7 +514,14 @@
 
 	filp->private_data = qca199x_dev;
 	qca199x_init_stat(qca199x_dev);
+	/* Enable interrupts from NFCC NFC_INT new NCI data available */
 	qca199x_enable_irq(qca199x_dev);
+
+	if ((!strcmp(qca199x_dev->clk_src_name, "GPCLK")) ||
+		(!strcmp(qca199x_dev->clk_src_name, "GPCLK2"))) {
+		/* Enable interrupts from NFCC CLK_REQ */
+		qca199x_enable_irq_clk_req(qca199x_dev);
+	}
 	dev_dbg(&qca199x_dev->client->dev,
 			"%d,%d\n", imajor(inode), iminor(inode));
 	return ret;
@@ -378,6 +591,9 @@
 	struct qca199x_dev *qca199x_dev = filp->private_data;
 
 	if (arg == 0) {
+		r = qca199x_clock_select(qca199x_dev);
+		if (r < 0)
+			goto err_req;
 		gpio_set_value(qca199x_dev->dis_gpio, 0);
 		r = gpio_direction_output(qca199x_dev->dis_gpio, 1);
 		if (r) {
@@ -389,6 +605,23 @@
 		gpio_set_value(qca199x_dev->dis_gpio, 0);
 		msleep(20);
 	} else if (arg == 1) {
+		/*
+			We are attempting a hardware reset so let us disable
+			interrupts to avoid spurious notifications to upper
+			layers.
+		*/
+		qca199x_disable_irq(qca199x_dev);
+		/* Deselection of clock */
+		r = qca199x_clock_deselect(qca199x_dev);
+		if (r < 0)
+			goto err_req;
+		/*
+			Also, set flag for initial NCI write following reset as
+			may wish to do some house keeping. Ensure no pending
+			messages in NFCC buffers which may be wrongly
+			construed as response to initial message
+		*/
+		qca199x_dev->sent_first_nci_write = false;
 		gpio_set_value(qca199x_dev->dis_gpio, 0);
 		r = gpio_direction_output(qca199x_dev->dis_gpio, 1);
 		if (r) {
@@ -402,10 +635,12 @@
 	} else if (arg == 2) {
 		mutex_lock(&qca199x_dev->read_mutex);
 		r = nfcc_initialise(qca199x_dev->client, 0xE);
+		/* Also reset first NCI write */
+		qca199x_dev->sent_first_nci_write = false;
 		mutex_unlock(&qca199x_dev->read_mutex);
 		if (r) {
 			dev_err(&qca199x_dev->client->dev,
-					"nfc-nci probe: request nfcc initialise failed\n");
+				"nfc_ioctl_power_states: request nfcc initialise failed\n");
 			goto err_req;
 		}
 	} else if (arg == 3) {
@@ -493,7 +728,7 @@
 	int r = 0;
 	unsigned short	slave_addr	=	0xE;
 	unsigned short	curr_addr;
-
+	unsigned char	raw_nci_wake[]			= {0x10, 0x0F};
 	unsigned char raw_chip_version_addr		= 0x00;
 	unsigned char raw_chip_rev_id_addr		= 0x9C;
 	unsigned char raw_chip_version			= 0xFF;
@@ -503,9 +738,22 @@
 
 	platform_data = qca199x_dev->client->dev.platform_data;
 
+	/*
+	 * Always wake up chip when reading 0x9C, otherwise this
+	 * register is not updated
+	 */
+	curr_addr = qca199x_dev->client->addr;
+	qca199x_dev->client->addr = slave_addr;
+	r = nfc_i2c_write(qca199x_dev->client, &raw_nci_wake[0],
+						sizeof(raw_nci_wake));
+	r = sizeof(raw_nci_wake);
+	if (r != sizeof(raw_nci_wake))
+		goto invalid_wake_up;
+	qca199x_dev->state = NFCC_STATE_NORMAL_WAKE;
+
+	/* sleep to ensure the NFCC has time to wake up */
+	usleep(100);
 	if (arg == 0) {
-		curr_addr = qca199x_dev->client->addr;
-		qca199x_dev->client->addr = slave_addr;
 		r = nfc_i2c_write(qca199x_dev->client,
 				&raw_chip_version_addr, 1);
 		if (r < 0)
@@ -514,21 +762,19 @@
 		r = i2c_master_recv(qca199x_dev->client, &raw_chip_version, 1);
 		/* Restore original NFCC slave I2C address */
 		qca199x_dev->client->addr = curr_addr;
-	}
-	if (arg == 1) {
-		curr_addr = qca199x_dev->client->addr;
-		qca199x_dev->client->addr = slave_addr;
+	} else if (arg == 1) {
 		r = nfc_i2c_write(qca199x_dev->client,
 				&raw_chip_rev_id_addr, 1);
 		if (r < 0)
 			goto invalid_wr;
-		usleep(10);
+		usleep(20);
 		r = i2c_master_recv(qca199x_dev->client, &raw_chip_version, 1);
 		/* Restore original NFCC slave I2C address */
 		qca199x_dev->client->addr = curr_addr;
 	}
-
 	return raw_chip_version;
+invalid_wake_up:
+	raw_chip_version = 0xFE;
 invalid_wr:
 	raw_chip_version = 0xFF;
 	dev_err(&qca199x_dev->client->dev,
@@ -536,8 +782,6 @@
 	return raw_chip_version;
 }
 
-
-
 /*
  * Inside nfc_ioctl_kernel_logging
  *
@@ -651,6 +895,33 @@
 	return r;
 }
 
+/* Check for availability of qca199x_ NFC controller hardware */
+static int nfcc_hw_check(struct i2c_client *client, unsigned short curr_addr)
+{
+	int r = 0;
+	unsigned char buf = 0;
+
+	client->addr = curr_addr;
+	/* Set-up Addr 0. No data written */
+	r = i2c_master_send(client, &buf, 1);
+	if (r < 0)
+		goto err_presence_check;
+	buf = 0;
+	/* Read back from Addr 0 */
+	r = i2c_master_recv(client, &buf, 1);
+	if (r < 0)
+		goto err_presence_check;
+
+	r = 0;
+	return r;
+
+err_presence_check:
+	r = -ENXIO;
+	dev_err(&client->dev,
+		"nfc-nci nfcc_presence check - no NFCC available\n");
+	return r;
+}
+/* Initialise qca199x_ NFC controller hardware */
 static int nfcc_initialise(struct i2c_client *client, unsigned short curr_addr)
 {
 	int r = 0;
@@ -664,72 +935,215 @@
 	unsigned char raw_1P8_PAD_CFG_CLK_REQ[]	= {0xA5, 0x1};
 	unsigned char raw_1P8_PAD_CFG_PWR_REQ[]	= {0xA7, 0x1};
 	unsigned char buf = 0;
+	bool core_reset_completed = false;
+	unsigned char rsp[6];
+	int time_taken = 0;
+	int ret = 0;
 
 	client->addr = curr_addr;
 	r = i2c_master_send(client, &buf, 1);
+	if (r < 0)
+		goto err_init;
+
 	buf = 0;
 	r = i2c_master_recv(client, &buf, 1);
-	if (0x10 != (0x10 & buf)) {
-		RAW(s73, 0x02);
+	if (r < 0)
+		goto err_init;
 
-		r = nfc_i2c_write(client, &raw_s73[0], sizeof(raw_s73));
-		usleep(1000);
-		RAW(1p8_CONTROL_011, XTAL_CLOCK | 0x01);
+	RAW(s73, 0x02);
 
-		r = nfc_i2c_write(client, &raw_1p8_CONTROL_011[0],
-						sizeof(raw_1p8_CONTROL_011));
-		usleep(1000);
-		RAW(1P8_CONTROL_010, (0x8));
-		r = nfc_i2c_write(client, &raw_1P8_CONTROL_010[0],
-						sizeof(raw_1P8_CONTROL_010));
+	r = nfc_i2c_write(client, &raw_s73[0], sizeof(raw_s73));
+	if (r < 0)
+		goto err_init;
 
-		usleep(10000);  /* 10ms wait */
-		RAW(1P8_CONTROL_010, (0xC));
-		r = nfc_i2c_write(client, &raw_1P8_CONTROL_010[0],
+	usleep(1000);
+	RAW(1p8_CONTROL_011, XTAL_CLOCK | 0x01);
+
+	r = nfc_i2c_write(client, &raw_1p8_CONTROL_011[0],
+					sizeof(raw_1p8_CONTROL_011));
+	if (r < 0)
+		goto err_init;
+
+	usleep(1000);
+	RAW(1P8_CONTROL_010, (0x8));
+	r = nfc_i2c_write(client, &raw_1P8_CONTROL_010[0],
 					sizeof(raw_1P8_CONTROL_010));
-		usleep(100);  /* 100uS wait */
-		RAW(1P8_X0_0B0, (FREQ_SEL_19));
-		r = nfc_i2c_write(client, &raw_1P8_X0_0B0[0],
-						sizeof(raw_1P8_X0_0B0));
-		usleep(1000);
+	if (r < 0)
+		goto err_init;
 
-		/* PWR_EN = 1 */
-		RAW(1P8_CONTROL_010, (0xd));
-		r = nfc_i2c_write(client, &raw_1P8_CONTROL_010[0],
-						sizeof(raw_1P8_CONTROL_010));
-		usleep(20000);  /* 20ms wait */
-		/* LS_EN = 1 */
-		RAW(1P8_CONTROL_010, 0xF);
-		r = nfc_i2c_write(client, &raw_1P8_CONTROL_010[0],
-						sizeof(raw_1P8_CONTROL_010));
-		usleep(20000);  /* 20ms wait */
+	usleep(10000);  /* 10ms wait */
+	RAW(1P8_CONTROL_010, (0xC));
+	r = nfc_i2c_write(client, &raw_1P8_CONTROL_010[0],
+				sizeof(raw_1P8_CONTROL_010));
+	if (r < 0)
+		goto err_init;
 
-		/* Enable the PMIC clock */
-		RAW(1P8_PAD_CFG_CLK_REQ, (0x1));
-		r = nfc_i2c_write(client, &raw_1P8_PAD_CFG_CLK_REQ[0],
-					  sizeof(raw_1P8_PAD_CFG_CLK_REQ));
-		usleep(1000);
+	usleep(100);  /* 100uS wait */
+	RAW(1P8_X0_0B0, (FREQ_SEL_19));
+	r = nfc_i2c_write(client, &raw_1P8_X0_0B0[0],
+					sizeof(raw_1P8_X0_0B0));
+	if (r < 0)
+		goto err_init;
 
-		RAW(1P8_PAD_CFG_PWR_REQ, (0x1));
-		r = nfc_i2c_write(client, &raw_1P8_PAD_CFG_PWR_REQ[0],
-					  sizeof(raw_1P8_PAD_CFG_PWR_REQ));
-		usleep(1000);
+	usleep(1000);
 
-		RAW(slave2, 0x10);
-		r = nfc_i2c_write(client, &raw_slave2[0], sizeof(raw_slave2));
-		usleep(1000);
+	/* PWR_EN = 1 */
+	RAW(1P8_CONTROL_010, (0xd));
+	r = nfc_i2c_write(client, &raw_1P8_CONTROL_010[0],
+					sizeof(raw_1P8_CONTROL_010));
+	if (r < 0)
+		goto err_init;
 
-		RAW(slave1, NCI_I2C_SLAVE);
-		r = nfc_i2c_write(client, &raw_slave1[0], sizeof(raw_slave1));
-		usleep(1000);
 
-		/* QCA199x NFCC CPU should now boot... */
-		r = i2c_master_recv(client, &raw_slave1_rd, 1);
-		/* Talk on NCI slave address NCI_I2C_SLAVE 0x2C*/
-		client->addr = NCI_I2C_SLAVE;
-		r = 0;
+	usleep(20000);  /* 20ms wait */
+	/* LS_EN = 1 */
+	RAW(1P8_CONTROL_010, 0xF);
+	r = nfc_i2c_write(client, &raw_1P8_CONTROL_010[0],
+					sizeof(raw_1P8_CONTROL_010));
+	if (r < 0)
+		goto err_init;
+
+	usleep(20000);  /* 20ms wait */
+
+	/* Enable the PMIC clock */
+	RAW(1P8_PAD_CFG_CLK_REQ, (0x1));
+	r = nfc_i2c_write(client, &raw_1P8_PAD_CFG_CLK_REQ[0],
+				  sizeof(raw_1P8_PAD_CFG_CLK_REQ));
+	if (r < 0)
+		goto err_init;
+
+	usleep(1000);
+
+	RAW(1P8_PAD_CFG_PWR_REQ, (0x1));
+	r = nfc_i2c_write(client, &raw_1P8_PAD_CFG_PWR_REQ[0],
+				  sizeof(raw_1P8_PAD_CFG_PWR_REQ));
+	if (r < 0)
+		goto err_init;
+
+	usleep(1000);
+
+	RAW(slave2, 0x10);
+	r = nfc_i2c_write(client, &raw_slave2[0], sizeof(raw_slave2));
+	if (r < 0)
+		goto err_init;
+
+	usleep(1000);
+
+	RAW(slave1, NCI_I2C_SLAVE);
+	r = nfc_i2c_write(client, &raw_slave1[0], sizeof(raw_slave1));
+	if (r < 0)
+		goto err_init;
+
+	usleep(1000);
+
+	/* QCA199x NFCC CPU should now boot... */
+	r = i2c_master_recv(client, &raw_slave1_rd, 1);
+	/* Talk on NCI slave address NCI_I2C_SLAVE 0x2C*/
+	client->addr = NCI_I2C_SLAVE;
+
+	/*
+		Start with small delay and then we will poll until we
+		get a core reset notification - This is time for chip
+		& NFCC controller to come-up.
+	*/
+	usleep(1000); /* 1 ms */
+
+	do {
+		ret = i2c_master_recv(client, rsp, 5);
+		/* Found core reset notification */
+		if (((rsp[0] == CORE_RESET_RSP_GID) &&
+			(rsp[1] == CORE_RESET_OID) &&
+			(rsp[2] == CORE_RST_NTF_LENGTH))
+				|| time_taken == NTF_TIMEOUT) {
+			core_reset_completed = true;
+		}
+		usleep(10);  /* 10us sleep before retry */
+		time_taken++;
+	} while (!core_reset_completed);
+	r = 0;
+	return r;
+err_init:
+	r = 1;
+	dev_err(&client->dev,
+		"nfc-nci nfcc_initialise: failed. Check Hardware\n");
+	return r;
+}
+/*
+	Routine to Select clocks
+*/
+static int qca199x_clock_select(struct qca199x_dev *qca199x_dev)
+{
+	int r = 0;
+
+	if (!strcmp(qca199x_dev->clk_src_name, "BBCLK2")) {
+		qca199x_dev->s_clk  =
+			clk_get(&qca199x_dev->client->dev, "ref_clk");
+		if (qca199x_dev->s_clk == NULL)
+			goto err_invalid_dis_gpio;
+	} else if (!strcmp(qca199x_dev->clk_src_name, "RFCLK3")) {
+		qca199x_dev->s_clk  =
+			clk_get(&qca199x_dev->client->dev, "ref_clk_rf");
+		if (qca199x_dev->s_clk == NULL)
+			goto err_invalid_dis_gpio;
+	} else if (!strcmp(qca199x_dev->clk_src_name, "GPCLK")) {
+		if (gpio_is_valid(qca199x_dev->clk_src_gpio)) {
+			qca199x_dev->s_clk  =
+				clk_get(&qca199x_dev->client->dev, "core_clk");
+			if (qca199x_dev->s_clk == NULL)
+				goto err_invalid_dis_gpio;
+		} else {
+			goto err_invalid_dis_gpio;
+		}
+	} else if (!strcmp(qca199x_dev->clk_src_name, "GPCLK2")) {
+		if (gpio_is_valid(qca199x_dev->clk_src_gpio)) {
+			qca199x_dev->s_clk  =
+				clk_get(&qca199x_dev->client->dev, "core_clk_pvt");
+			if (qca199x_dev->s_clk == NULL)
+				goto err_invalid_dis_gpio;
+		} else {
+			goto err_invalid_dis_gpio;
+		}
 	} else {
-		r = 1;
+		qca199x_dev->s_clk = NULL;
+		goto err_invalid_dis_gpio;
+	}
+	if (qca199x_dev->clk_run == false) {
+		/* Set clock rate */
+		if ((!strcmp(qca199x_dev->clk_src_name, "GPCLK")) ||
+			(!strcmp(qca199x_dev->clk_src_name, "GPCLK2"))) {
+			r = clk_set_rate(qca199x_dev->s_clk, NFC_RF_CLK_FREQ);
+			if (r)
+				goto err_invalid_clk;
+		}
+
+		r = clk_prepare_enable(qca199x_dev->s_clk);
+		if (r)
+			goto err_invalid_clk;
+		qca199x_dev->clk_run = true;
+	}
+	r = 0;
+	return r;
+
+err_invalid_clk:
+	r = -1;
+	return r;
+err_invalid_dis_gpio:
+	r = -2;
+	return r;
+}
+/*
+	Routine to De-Select clocks
+*/
+
+static int qca199x_clock_deselect(struct qca199x_dev *qca199x_dev)
+{
+	int r = -1;
+	if (qca199x_dev->s_clk != NULL) {
+		if (qca199x_dev->clk_run == true) {
+			clk_disable_unprepare(qca199x_dev->s_clk);
+			qca199x_dev->clk_run = false;
+		}
+		return 0;
 	}
 	return r;
 }
@@ -743,24 +1157,32 @@
 	if (r)
 		return -EINVAL;
 
-	r = of_property_read_u32(np, "qcom,clk-gpio", &pdata->ven_gpio);
-	if (r)
-		return -EINVAL;
-
 	pdata->dis_gpio = of_get_named_gpio(np, "qcom,dis-gpio", 0);
 	if ((!gpio_is_valid(pdata->dis_gpio)))
 		return -EINVAL;
+	disable_ctrl = pdata->dis_gpio;
 
 	pdata->irq_gpio = of_get_named_gpio(np, "qcom,irq-gpio", 0);
 	if ((!gpio_is_valid(pdata->irq_gpio)))
 		return -EINVAL;
 
-	r = of_property_read_string(np, "qcom,clk-src", &pdata->clk_src);
+	r = of_property_read_string(np, "qcom,clk-src", &pdata->clk_src_name);
 
-	if ((!strcmp(pdata->clk_src, "GPCLK")) ||
-	    (!strcmp(pdata->clk_src, "GPCLK2")))
-		pdata->clk_src_gpio = of_get_named_gpio(np,
-				"qcom,clk-en-gpio", 0);
+	if (strcmp(pdata->clk_src_name, "GPCLK2")) {
+		pdata->clkreq_gpio = of_get_named_gpio(np, "qcom,clk-gpio", 0);
+	}
+
+	if ((!strcmp(pdata->clk_src_name, "GPCLK")) ||
+	    (!strcmp(pdata->clk_src_name, "GPCLK2"))) {
+			pdata->clk_src_gpio = of_get_named_gpio(np,
+					"qcom,clk-src-gpio", 0);
+			if ((!gpio_is_valid(pdata->clk_src_gpio)))
+				return -EINVAL;
+			pdata->irq_gpio_clk_req = of_get_named_gpio(np,
+					"qcom,clk-req-gpio", 0);
+			if ((!gpio_is_valid(pdata->irq_gpio_clk_req)))
+				return -EINVAL;
+	}
 
 	if (r)
 		return -EINVAL;
@@ -772,8 +1194,6 @@
 {
 	int r = 0;
 	int irqn = 0;
-	struct clk *nfc_clk = NULL;
-	struct device_node *node = client->dev.of_node;
 	struct qca199x_platform_data *platform_data;
 	struct qca199x_dev *qca199x_dev;
 
@@ -810,33 +1230,17 @@
 		"nfc-nci probe: failed to allocate memory for module data\n");
 		return -ENOMEM;
 	}
-	if (gpio_is_valid(platform_data->irq_gpio)) {
-		r = gpio_request(platform_data->irq_gpio, "nfc_irq_gpio");
-		if (r) {
-			dev_err(&client->dev, "unable to request gpio [%d]\n",
-				platform_data->irq_gpio);
-			goto err_irq;
-		}
-		r = gpio_direction_input(platform_data->irq_gpio);
-		if (r) {
+	qca199x_dev->client = client;
 
-			dev_err(&client->dev,
-			"unable to set direction for gpio [%d]\n",
-				platform_data->irq_gpio);
-			goto err_irq;
-		}
-		gpio_to_irq(0);
-		irqn = gpio_to_irq(platform_data->irq_gpio);
-		if (irqn < 0) {
-			r = irqn;
-			goto err_irq;
-		}
-		client->irq = irqn;
+	/*
+	 * To be efficient we need to test whether nfcc hardware is physically
+	 * present before attempting further hardware initialisation.
+	 * For this we need to be sure the device is in ULPM state by
+	 * setting disable line low early on.
+	 *
+	 */
 
-	} else {
-		dev_err(&client->dev, "irq gpio not provided\n");
-		goto err_free_dev;
-	}
+
 	if (gpio_is_valid(platform_data->dis_gpio)) {
 		r = gpio_request(platform_data->dis_gpio, "nfc_reset_gpio");
 		if (r) {
@@ -854,73 +1258,129 @@
 		}
 	} else {
 		dev_err(&client->dev, "dis gpio not provided\n");
-		goto err_irq;
+		goto err_free_dev;
 	}
+
+	/* Guarantee that the NFCC starts in a clean state. */
 	gpio_set_value(platform_data->dis_gpio, 1);/* HPD */
-	msleep(20);
+	usleep(200);
 	gpio_set_value(platform_data->dis_gpio, 0);/* ULPM */
-	if (!strcmp(platform_data->clk_src, "BBCLK2")) {
-		nfc_clk  = clk_get(&client->dev, "ref_clk");
-		if (nfc_clk == NULL)
-			goto err_dis_gpio;
-	} else if (!strcmp(platform_data->clk_src, "RFCLK3")) {
-		nfc_clk  = clk_get(&client->dev, "ref_clk_rf");
-		if (nfc_clk == NULL)
-			goto err_dis_gpio;
-	} else if (!strcmp(platform_data->clk_src, "GPCLK")) {
-		if (gpio_is_valid(platform_data->clk_src_gpio)) {
-			nfc_clk  = clk_get(&client->dev, "core_clk");
-			if (nfc_clk == NULL)
-				goto err_dis_gpio;
-		} else {
-			goto err_dis_gpio;
-		}
-	} else if (!strcmp(platform_data->clk_src, "GPCLK2")) {
-		if (gpio_is_valid(platform_data->clk_src_gpio)) {
-			nfc_clk  = clk_get(&client->dev, "core_clk_pvt");
-			if (nfc_clk == NULL)
-				goto err_dis_gpio;
-		} else {
-			goto err_dis_gpio;
-		}
-	} else {
-		nfc_clk = NULL;
+	usleep(200);
+
+	r = nfcc_hw_check(client, platform_data->reg);
+	if (r) {
+		/* We don't think there is hardware but just in case HPD */
+		gpio_set_value(platform_data->dis_gpio, 1);
+		goto err_dis_gpio;
 	}
-	r = clk_prepare_enable(nfc_clk);
-	if (r)
-		goto err_clk;
 
-	platform_data->ven_gpio = of_get_named_gpio(node,
-						"qcom,clk-gpio", 0);
-
-	if (gpio_is_valid(platform_data->ven_gpio)) {
-		r = gpio_request(platform_data->ven_gpio, "nfc_ven_gpio");
+	if (gpio_is_valid(platform_data->irq_gpio)) {
+		r = gpio_request(platform_data->irq_gpio, "nfc_irq_gpio");
 		if (r) {
 			dev_err(&client->dev, "unable to request gpio [%d]\n",
-						platform_data->ven_gpio);
-			goto err_ven_gpio;
+				platform_data->irq_gpio);
+			goto err_dis_gpio;
 		}
-		r = gpio_direction_input(platform_data->ven_gpio);
+		r = gpio_direction_input(platform_data->irq_gpio);
 		if (r) {
 
 			dev_err(&client->dev,
 			"unable to set direction for gpio [%d]\n",
-						platform_data->ven_gpio);
-			goto err_ven_gpio;
+				platform_data->irq_gpio);
+			goto err_irq;
 		}
+		irqn = gpio_to_irq(platform_data->irq_gpio);
+		if (irqn < 0) {
+			r = irqn;
+			goto err_irq;
+		}
+		client->irq = irqn;
+
 	} else {
-		dev_err(&client->dev, "ven gpio not provided\n");
-		goto err_clk;
+		dev_err(&client->dev, "irq gpio not provided\n");
+		goto err_dis_gpio;
+	}
+	/* Interrupt from NFCC CLK_REQ to handle REF_CLK
+		o/p gating/selection */
+	if ((!strcmp(platform_data->clk_src_name, "GPCLK")) ||
+		(!strcmp(platform_data->clk_src_name, "GPCLK2"))) {
+		if (gpio_is_valid(platform_data->irq_gpio_clk_req)) {
+			r = gpio_request(platform_data->irq_gpio_clk_req,
+				"nfc_irq_gpio_clk_en");
+			if (r) {
+				dev_err(&client->dev, "unable to request CLK_EN gpio [%d]\n",
+					platform_data->irq_gpio_clk_req);
+				goto err_irq;
+			}
+			r = gpio_direction_input(
+					platform_data->irq_gpio_clk_req);
+			if (r) {
+				dev_err(&client->dev,
+					"unable to set direction for CLK_EN gpio [%d]\n",
+					platform_data->irq_gpio_clk_req);
+				goto err_irq_clk;
+			}
+			gpio_to_irq(0);
+			irqn = gpio_to_irq(platform_data->irq_gpio_clk_req);
+			if (irqn < 0) {
+				r = irqn;
+				goto err_irq_clk;
+			}
+			platform_data->clk_req_irq_num = irqn;
+		} else {
+			dev_err(&client->dev, "irq CLK_EN gpio not provided\n");
+			goto err_irq;
+		}
+	}
+	/* Get the clock source name and gpio from from Device Tree */
+	qca199x_dev->clk_src_name = platform_data->clk_src_name;
+	qca199x_dev->clk_src_gpio = platform_data->clk_src_gpio;
+	qca199x_dev->clk_run = false;
+	r = qca199x_clock_select(qca199x_dev);
+	if (r != 0) {
+		if (r == -1)
+			goto err_clk;
+		else
+			goto err_irq_clk;
+	}
+
+	if (strcmp(platform_data->clk_src_name, "GPCLK2")) {
+		if (gpio_is_valid(platform_data->clkreq_gpio)) {
+			r = gpio_request(platform_data->clkreq_gpio,
+				"nfc_clkreq_gpio");
+			if (r) {
+				dev_err(&client->dev, "unable to request gpio [%d]\n",
+						platform_data->clkreq_gpio);
+				goto err_clkreq_gpio;
+			}
+			r = gpio_direction_input(platform_data->clkreq_gpio);
+			if (r) {
+				dev_err(&client->dev,
+						"unable to set direction for gpio [%d]\n",
+						platform_data->clkreq_gpio);
+				goto err_clkreq_gpio;
+			}
+		} else {
+			dev_err(&client->dev, "clkreq gpio not provided\n");
+			goto err_clk;
+		}
+		qca199x_dev->clkreq_gpio = platform_data->clkreq_gpio;
 	}
 	qca199x_dev->dis_gpio = platform_data->dis_gpio;
 	qca199x_dev->irq_gpio = platform_data->irq_gpio;
-	qca199x_dev->ven_gpio = platform_data->ven_gpio;
-	qca199x_dev->client = client;
+	if ((!strcmp(platform_data->clk_src_name, "GPCLK")) ||
+		(!strcmp(platform_data->clk_src_name, "GPCLK2"))) {
+			qca199x_dev->irq_gpio_clk_req	=
+						platform_data->irq_gpio_clk_req;
+			qca199x_dev->clk_req_irq_num		=
+						platform_data->clk_req_irq_num;
+	}
 
 	/* init mutex and queues */
 	init_waitqueue_head(&qca199x_dev->read_wq);
 	mutex_init(&qca199x_dev->read_mutex);
 	spin_lock_init(&qca199x_dev->irq_enabled_lock);
+	spin_lock_init(&qca199x_dev->irq_enabled_lock_clk_req);
 
 	qca199x_dev->qca199x_device.minor = MISC_DYNAMIC_MINOR;
 	qca199x_dev->qca199x_device.name = "nfc-nci";
@@ -932,17 +1392,26 @@
 		goto err_misc_register;
 	}
 
-	regulators.regulator = regulator_get(&client->dev, regulators.name);
-	if (IS_ERR(regulators.regulator)) {
-		r = PTR_ERR(regulators.regulator);
-		pr_err("regulator get of %s failed (%d)\n", regulators.name, r);
-	} else {
-		/* Enable the regulator */
-		r = regulator_enable(regulators.regulator);
-		if (r) {
-			pr_err("vreg %s enable failed (%d)\n",
-				regulators.name, r);
-		}
+
+	/*
+	 * Reboot the NFCC now that all resources are ready
+	 *
+	 * The NFCC takes time to transition between power states.
+	 * We wait 20uS for the NFCC to shutdown. (HPD)
+	 * We wait 100uS for the NFCC to boot into ULPM.
+	 */
+	gpio_set_value(platform_data->dis_gpio, 1);/* HPD */
+	msleep(20);
+	gpio_set_value(platform_data->dis_gpio, 0);/* ULPM */
+	msleep(100);
+
+
+	/* Here we perform a second presence check. */
+	r = nfcc_hw_check(client, platform_data->reg);
+	if (r) {
+		/* We don't think there is hardware but just in case HPD */
+		gpio_set_value(platform_data->dis_gpio, 1);
+		goto err_nfcc_not_present;
 	}
 
 	logging_level = 0;
@@ -950,12 +1419,7 @@
 	* for reading.  It is cleared when all data has been read.
 	*/
 	device_mode.handle_flavour = UNSOLICITED_MODE;
-	r = nfcc_initialise(client, platform_data->reg);
-	if (r) {
-		dev_err(&client->dev, "nfc-nci probe: request nfcc initialise failed\n");
-		goto err_nfcc_init_failed;
-	}
-
+	/* NFC_INT IRQ */
 	qca199x_dev->irq_enabled = true;
 	r = request_irq(client->irq, qca199x_dev_irq_handler,
 			  IRQF_TRIGGER_RISING, client->name, qca199x_dev);
@@ -964,35 +1428,69 @@
 		goto err_request_irq_failed;
 	}
 	qca199x_disable_irq(qca199x_dev);
+	/* CLK_REQ IRQ */
+	if ((!strcmp(platform_data->clk_src_name, "GPCLK")) ||
+		(!strcmp(platform_data->clk_src_name, "GPCLK2"))) {
+		r = request_irq(qca199x_dev->clk_req_irq_num,
+				qca199x_dev_irq_handler_clk_req,
+				(IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING),
+						client->name, qca199x_dev);
+		if (r) {
+			dev_err(&client->dev,
+			"nfc-nci probe: request_irq failed. irq no = %d\n, main irq =  %d",
+				qca199x_dev->clk_req_irq_num, client->irq);
+			goto err_request_irq_failed;
+		}
+		qca199x_dev->irq_enabled_clk_req = true;
+		qca199x_disable_irq_clk_req(qca199x_dev);
+
+
+		qca199x_dev->my_wq =
+			create_singlethread_workqueue("qca1990x_CLK_REQ_queue");
+		if (!qca199x_dev->my_wq)
+			goto err_create_workq;
+
+		INIT_WORK(&qca199x_dev->msm_clock_controll_work,
+			clk_req_update);
+	}
 	i2c_set_clientdata(client, qca199x_dev);
+	gpio_set_value(platform_data->dis_gpio, 1);
+
+	/* To keep track if region2 command has been sent to controller */
+	region2_sent = false;
+
 	dev_dbg(&client->dev,
 	"nfc-nci probe: %s, probing qca1990 exited successfully\n",
 		 __func__);
 	return 0;
 
-err_nfcc_init_failed:
+err_create_workq:
+	dev_err(&client->dev,
+	"nfc-nci probe: %s, work_queue creation failure\n",
+		 __func__);
+	free_irq(client->irq, qca199x_dev);
+err_nfcc_not_present:
 err_request_irq_failed:
 	misc_deregister(&qca199x_dev->qca199x_device);
 err_misc_register:
 	mutex_destroy(&qca199x_dev->read_mutex);
-err_ven_gpio:
-	gpio_free(platform_data->ven_gpio);
+err_clkreq_gpio:
+	if (strcmp(platform_data->clk_src_name, "GPCLK2"))
+		gpio_free(platform_data->clkreq_gpio);
 err_clk:
-	clk_disable_unprepare(nfc_clk);
-err_dis_gpio:
-	r = gpio_direction_input(platform_data->dis_gpio);
-	if (r)
-		dev_err(&client->dev, "nfc-nci probe: Unable to set direction\n");
-	if ((!strcmp(platform_data->clk_src, "GPCLK")) ||
-            (!strcmp(platform_data->clk_src, "GPCLK2"))) {
-		r = gpio_direction_input(platform_data->clk_src_gpio);
+		qca199x_clock_deselect(qca199x_dev);
+err_irq_clk:
+	if ((!strcmp(platform_data->clk_src_name, "GPCLK")) ||
+		(!strcmp(platform_data->clk_src_name, "GPCLK2"))) {
+		r = gpio_direction_input(platform_data->irq_gpio_clk_req);
 		if (r)
 			dev_err(&client->dev, "nfc-nci probe: Unable to set direction\n");
-		gpio_free(platform_data->clk_src_gpio);
+		gpio_free(platform_data->irq_gpio_clk_req);
 	}
-	gpio_free(platform_data->dis_gpio);
 err_irq:
 	gpio_free(platform_data->irq_gpio);
+err_dis_gpio:
+	gpio_free(platform_data->dis_gpio);
 err_free_dev:
 	kfree(qca199x_dev);
 	return r;
@@ -1007,8 +1505,13 @@
 	misc_deregister(&qca199x_dev->qca199x_device);
 	mutex_destroy(&qca199x_dev->read_mutex);
 	gpio_free(qca199x_dev->irq_gpio);
+	if ((!strcmp(qca199x_dev->clk_src_name, "GPCLK")) ||
+		(!strcmp(qca199x_dev->clk_src_name, "GPCLK2"))) {
+		gpio_free(qca199x_dev->irq_gpio_clk_req);
+	}
 	gpio_free(qca199x_dev->dis_gpio);
-	gpio_free(qca199x_dev->ven_gpio);
+	if (strcmp(qca199x_dev->clk_src_name, "GPCLK2"))
+		gpio_free(qca199x_dev->clkreq_gpio);
 	kfree(qca199x_dev);
 
 	return 0;
@@ -1030,17 +1533,52 @@
 	},
 };
 
+
+static int nfcc_reboot(struct notifier_block *notifier, unsigned long val,
+		      void *v)
+{
+	/*
+	 * Set DISABLE=1 *ONLY* if the NFC service has been disabled.
+	 * This will put NFCC into HPD(Hard Power Down) state for power
+	 * saving when powering down(Low Batt. or Power off handset)
+	 * If user requires NFC and CE mode when powered down(PD) the
+	 * middleware puts NFCC into region2 prior to PD. In this case
+	 * we DO NOT HPD chip as this will trash Region2 and CE support
+	 * when handset is PD.
+	 */
+	if (region2_sent == false) {
+		/* HPD the NFCC */
+		gpio_set_value(disable_ctrl, 1);
+	}
+	return NOTIFY_OK;
+}
+
+
+static struct notifier_block nfcc_notifier = {
+	.notifier_call	= nfcc_reboot,
+	.next		= NULL,
+	.priority	= 0
+};
+
 /*
  * module load/unload record keeping
  */
 static int __init qca199x_dev_init(void)
 {
+	int ret;
+
+	ret = register_reboot_notifier(&nfcc_notifier);
+	if (ret) {
+		pr_err("cannot register reboot notifier (err=%d)\n", ret);
+		return ret;
+	}
 	return i2c_add_driver(&qca199x);
 }
 module_init(qca199x_dev_init);
 
 static void __exit qca199x_dev_exit(void)
 {
+	unregister_reboot_notifier(&nfcc_notifier);
 	i2c_del_driver(&qca199x);
 }
 module_exit(qca199x_dev_exit);
diff --git a/drivers/nfc/nfc-nci.h b/drivers/nfc/nfc-nci.h
index 9bfb77d..297c152 100644
--- a/drivers/nfc/nfc-nci.h
+++ b/drivers/nfc/nfc-nci.h
@@ -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
@@ -223,9 +223,3 @@
 	unsigned int	reg;
 };
 #endif
-/* enable LDO */
-struct vregs_info {
-	const char * const name;
-	struct regulator *regulator;
-};
-struct vregs_info regulators = {"vlogic", NULL};
diff --git a/drivers/platform/msm/ipa/ipa.c b/drivers/platform/msm/ipa/ipa.c
index 1ef1f1b..c93ec5f 100644
--- a/drivers/platform/msm/ipa/ipa.c
+++ b/drivers/platform/msm/ipa/ipa.c
@@ -205,6 +205,8 @@
 			retval = -EFAULT;
 			break;
 		}
+		/* null terminate the string */
+		nat_mem.dev_name[IPA_RESOURCE_NAME_MAX - 1] = '\0';
 
 		if (allocate_nat_device(&nat_mem)) {
 			retval = -EFAULT;
@@ -542,6 +544,13 @@
 			retval = -EFAULT;
 			break;
 		}
+
+		if (((struct ipa_ioc_query_intf_tx_props *)header)->num_tx_props
+				> IPA_NUM_PROPS_MAX) {
+			retval = -EFAULT;
+			break;
+		}
+
 		pyld_sz = sz + ((struct ipa_ioc_query_intf_tx_props *)
 				header)->num_tx_props *
 			sizeof(struct ipa_ioc_tx_intf_prop);
@@ -570,6 +579,13 @@
 			retval = -EFAULT;
 			break;
 		}
+
+		if (((struct ipa_ioc_query_intf_rx_props *)header)->num_rx_props
+				> IPA_NUM_PROPS_MAX) {
+			retval = -EFAULT;
+			break;
+		}
+
 		pyld_sz = sz + ((struct ipa_ioc_query_intf_rx_props *)
 				header)->num_rx_props *
 			sizeof(struct ipa_ioc_rx_intf_prop);
diff --git a/drivers/platform/msm/ipa/ipa_intf.c b/drivers/platform/msm/ipa/ipa_intf.c
index 5ee1929..ea5c97f 100644
--- a/drivers/platform/msm/ipa/ipa_intf.c
+++ b/drivers/platform/msm/ipa/ipa_intf.c
@@ -60,6 +60,18 @@
 		return -EINVAL;
 	}
 
+	if (tx && tx->num_props > IPA_NUM_PROPS_MAX) {
+		IPAERR("invalid tx num_props=%d max=%d\n", tx->num_props,
+				IPA_NUM_PROPS_MAX);
+		return -EINVAL;
+	}
+
+	if (rx && rx->num_props > IPA_NUM_PROPS_MAX) {
+		IPAERR("invalid rx num_props=%d max=%d\n", rx->num_props,
+				IPA_NUM_PROPS_MAX);
+		return -EINVAL;
+	}
+
 	len = sizeof(struct ipa_intf);
 	intf = kzalloc(len, GFP_KERNEL);
 	if (intf == NULL) {
diff --git a/drivers/platform/msm/ipa/ipa_nat.c b/drivers/platform/msm/ipa/ipa_nat.c
index e2c344f..6ee16fb 100644
--- a/drivers/platform/msm/ipa/ipa_nat.c
+++ b/drivers/platform/msm/ipa/ipa_nat.c
@@ -166,7 +166,7 @@
 
 	nat_ctx->dev =
 	   device_create(nat_ctx->class, NULL, nat_ctx->dev_num, nat_ctx,
-			 mem->dev_name);
+			"%s", mem->dev_name);
 
 	if (IS_ERR(nat_ctx->dev)) {
 		IPAERR("device_create err:%ld\n", PTR_ERR(nat_ctx->dev));
diff --git a/drivers/platform/msm/ipa/teth_bridge.c b/drivers/platform/msm/ipa/teth_bridge.c
index b3a6b17..d08ac64 100644
--- a/drivers/platform/msm/ipa/teth_bridge.c
+++ b/drivers/platform/msm/ipa/teth_bridge.c
@@ -22,7 +22,6 @@
 #include <linux/mutex.h>
 #include <linux/skbuff.h>
 #include <linux/types.h>
-#include <mach/bam_dmux.h>
 #include <mach/ipa.h>
 #include <mach/sps.h>
 #include "ipa_i.h"
@@ -1780,7 +1779,7 @@
 			break;
 		}
 
-		if (caps.num_protocols < teth_ctx->aggr_caps->num_protocols) {
+		if (caps.num_protocols != teth_ctx->aggr_caps->num_protocols) {
 			caps.num_protocols = teth_ctx->aggr_caps->num_protocols;
 			if (copy_to_user((struct teth_aggr_capabilities *)arg,
 					 &caps,
diff --git a/drivers/platform/msm/qpnp-power-on.c b/drivers/platform/msm/qpnp-power-on.c
index b55b66b..1a3baf5 100644
--- a/drivers/platform/msm/qpnp-power-on.c
+++ b/drivers/platform/msm/qpnp-power-on.c
@@ -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
@@ -24,6 +24,13 @@
 #include <linux/log2.h>
 #include <linux/qpnp/power-on.h>
 
+#define PMIC_VER_8941           0x01
+#define PMIC_VERSION_REG        0x0105
+#define PMIC_VERSION_REV4_REG   0x0103
+
+#define PMIC8941_V1_REV4        0x01
+#define PMIC8941_V2_REV4        0x02
+
 /* Common PNP defines */
 #define QPNP_PON_REVISION2(base)		(base + 0x01)
 
@@ -36,6 +43,7 @@
 #define QPNP_PON_REASON1(base)			(base + 0x8)
 #define QPNP_PON_WARM_RESET_REASON1(base)	(base + 0xA)
 #define QPNP_PON_WARM_RESET_REASON2(base)	(base + 0xB)
+#define QPNP_POFF_REASON1(base)			(base + 0xC)
 #define QPNP_PON_KPDPWR_S1_TIMER(base)		(base + 0x40)
 #define QPNP_PON_KPDPWR_S2_TIMER(base)		(base + 0x41)
 #define QPNP_PON_KPDPWR_S2_CNTL(base)		(base + 0x42)
@@ -50,8 +58,17 @@
 #define QPNP_PON_KPDPWR_RESIN_S2_CNTL2(base)	(base + 0x4B)
 #define QPNP_PON_PS_HOLD_RST_CTL(base)		(base + 0x5A)
 #define QPNP_PON_PS_HOLD_RST_CTL2(base)		(base + 0x5B)
-#define QPNP_PON_TRIGGER_EN(base)		(base + 0x80)
+#define QPNP_PON_WD_RST_S2_CTL(base)		(base + 0x56)
+#define QPNP_PON_WD_RST_S2_CTL2(base)		(base + 0x57)
+#define QPNP_PON_S3_SRC(base)			(base + 0x74)
 #define QPNP_PON_S3_DBC_CTL(base)		(base + 0x75)
+#define QPNP_PON_TRIGGER_EN(base)		(base + 0x80)
+
+#define QPNP_PON_S3_SRC_KPDPWR			0
+#define QPNP_PON_S3_SRC_RESIN			1
+#define QPNP_PON_S3_SRC_KPDPWR_OR_RESIN		2
+#define QPNP_PON_S3_SRC_KPDPWR_AND_RESIN	3
+#define QPNP_PON_S3_SRC_MASK			0x3
 
 #define QPNP_PON_WARM_RESET_TFT			BIT(4)
 
@@ -73,6 +90,7 @@
 #define QPNP_PON_RESIN_BARK_N_SET		BIT(4)
 #define QPNP_PON_KPDPWR_RESIN_BARK_N_SET	BIT(5)
 
+#define QPNP_PON_WD_EN			BIT(7)
 #define QPNP_PON_RESET_EN			BIT(7)
 #define QPNP_PON_POWER_OFF_MASK			0xF
 
@@ -83,7 +101,8 @@
 #define QPNP_PON_S3_DBC_DELAY_MASK		0x07
 #define QPNP_PON_RESET_TYPE_MAX			0xF
 #define PON_S1_COUNT_MAX			0xF
-#define PON_REASON_MAX				8
+#define QPNP_PON_MIN_DBC_US			(USEC_PER_SEC / 64)
+#define QPNP_PON_MAX_DBC_US			(USEC_PER_SEC * 2)
 
 #define QPNP_KEY_STATUS_DELAY			msecs_to_jiffies(250)
 #define QPNP_PON_REV_B				0x01
@@ -137,6 +156,26 @@
 	[7] = "Triggered from KPD (power key press)",
 };
 
+static const char * const qpnp_poff_reason[] = {
+	[0] = "Triggered from SOFT (Software)",
+	[1] = "Triggered from PS_HOLD (PS_HOLD/MSM controlled shutdown)",
+	[2] = "Triggered from PMIC_WD (PMIC watchdog)",
+	[3] = "Triggered from GP1 (Keypad_Reset1)",
+	[4] = "Triggered from GP2 (Keypad_Reset2)",
+	[5] = "Triggered from KPDPWR_AND_RESIN"
+		"(Simultaneous power key and reset line)",
+	[6] = "Triggered from RESIN_N (Reset line/Volume Down Key)",
+	[7] = "Triggered from KPDPWR_N (Long Power Key hold)",
+	[8] = "N/A",
+	[9] = "N/A",
+	[10] = "N/A",
+	[11] = "Triggered from CHARGER (Charger ENUM_TIMER, BOOT_DONE)",
+	[12] = "Triggered from TFT (Thermal Fault Tolerance)",
+	[13] = "Triggered from UVLO (Under Voltage Lock Out)",
+	[14] = "Triggered from OTST3 (Overtemp)",
+	[15] = "Triggered from STAGE3 (Stage 3 reset)",
+};
+
 static int
 qpnp_pon_masked_write(struct qpnp_pon *pon, u16 addr, u8 mask, u8 val)
 {
@@ -270,6 +309,32 @@
 EXPORT_SYMBOL(qpnp_pon_is_warm_reset);
 
 /**
+ * qpnp_pon_wd_config - Disable the wd in a warm reset.
+ * @enable: to enable or disable the PON watch dog
+ *
+ * Returns = 0 for operate successfully, < 0 for errors
+ */
+int qpnp_pon_wd_config(bool enable)
+{
+	struct qpnp_pon *pon = sys_reset_dev;
+	int rc = 0;
+
+	if (!pon)
+		return -EPROBE_DEFER;
+
+	rc = qpnp_pon_masked_write(pon, QPNP_PON_WD_RST_S2_CTL2(pon->base),
+			QPNP_PON_WD_EN, enable ? QPNP_PON_WD_EN : 0);
+	if (rc)
+		dev_err(&pon->spmi->dev,
+				"Unable to write to addr=%x, rc(%d)\n",
+				QPNP_PON_WD_RST_S2_CTL2(pon->base), rc);
+
+	return rc;
+}
+EXPORT_SYMBOL(qpnp_pon_wd_config);
+
+
+/**
  * qpnp_pon_trigger_config - Configures (enable/disable) the PON trigger source
  * @pon_src: PON source to be configured
  * @enable: to enable or disable the PON trigger
@@ -718,6 +783,8 @@
 	struct device_node *pp = NULL;
 	struct qpnp_pon_config *cfg;
 	u8 pon_ver;
+	u8 pmic_type;
+	u8 revid_rev4;
 
 	/* Check if it is rev B */
 	rc = spmi_ext_register_readl(pon->spmi->ctrl, pon->spmi->sid,
@@ -800,6 +867,38 @@
 
 			cfg->use_bark = of_property_read_bool(pp,
 							"qcom,use-bark");
+
+			rc = spmi_ext_register_readl(pon->spmi->ctrl,
+					pon->spmi->sid, PMIC_VERSION_REG,
+						&pmic_type, 1);
+
+			if (rc) {
+				dev_err(&pon->spmi->dev,
+				"Unable to read PMIC type\n");
+				return rc;
+			}
+
+			if (pmic_type == PMIC_VER_8941) {
+
+				rc = spmi_ext_register_readl(pon->spmi->ctrl,
+					pon->spmi->sid, PMIC_VERSION_REV4_REG,
+							&revid_rev4, 1);
+
+				if (rc) {
+					dev_err(&pon->spmi->dev,
+					"Unable to read PMIC revision ID\n");
+					return rc;
+				}
+
+				/*PM8941 V3 does not have harware bug. Hence
+				bark is not required from PMIC versions 3.0*/
+				if (!(revid_rev4 == PMIC8941_V1_REV4 ||
+					revid_rev4 == PMIC8941_V2_REV4)) {
+					cfg->support_reset = false;
+					cfg->use_bark = false;
+				}
+			}
+
 			if (cfg->use_bark) {
 				cfg->bark_irq = spmi_get_irq_byname(pon->spmi,
 							NULL, "resin-bark");
@@ -961,7 +1060,17 @@
 					"Unable to config pon reset\n");
 				goto unreg_input_dev;
 			}
+		} else {
+			/* disable S2 reset */
+			rc = qpnp_pon_masked_write(pon, cfg->s2_cntl2_addr,
+						QPNP_PON_S2_CNTL_EN, 0);
+			if (rc) {
+				dev_err(&pon->spmi->dev,
+					"Unable to disable S2 reset\n");
+				goto unreg_input_dev;
+			}
 		}
+
 		rc = qpnp_pon_request_irqs(pon, cfg);
 		if (rc) {
 			dev_err(&pon->spmi->dev, "Unable to request-irq's\n");
@@ -989,7 +1098,10 @@
 	struct device_node *itr = NULL;
 	u32 delay = 0, s3_debounce = 0;
 	int rc, sys_reset, index;
-	u8 pon_sts = 0;
+	u8 pon_sts = 0, buf[2];
+	const char *s3_src;
+	u8 s3_src_reg;
+	u16 poff_sts = 0;
 
 	pon = devm_kzalloc(&spmi->dev, sizeof(struct qpnp_pon),
 							GFP_KERNEL);
@@ -1037,14 +1149,39 @@
 		dev_err(&pon->spmi->dev, "Unable to read PON_RESASON1 reg\n");
 		return rc;
 	}
-	index = ffs(pon_sts);
-	if ((index > PON_REASON_MAX) || (index < 0))
-		index = 0;
 
+	boot_reason = ffs(pon_sts);
+	index = ffs(pon_sts) - 1;
 	cold_boot = !qpnp_pon_is_warm_reset();
-	pr_info("PMIC@SID%d Power-on reason: %s and '%s' boot\n",
-		pon->spmi->sid, index ? qpnp_pon_reason[index - 1] :
-		"Unknown", cold_boot ? "cold" : "warm");
+	if (index >= ARRAY_SIZE(qpnp_pon_reason) || index < 0)
+		dev_info(&pon->spmi->dev,
+			"PMIC@SID%d Power-on reason: Unknown and '%s' boot\n",
+			pon->spmi->sid, cold_boot ? "cold" : "warm");
+	else
+		dev_info(&pon->spmi->dev,
+			"PMIC@SID%d Power-on reason: %s and '%s' boot\n",
+			pon->spmi->sid, qpnp_pon_reason[index],
+			cold_boot ? "cold" : "warm");
+
+	/* POFF reason */
+	rc = spmi_ext_register_readl(pon->spmi->ctrl, pon->spmi->sid,
+				QPNP_POFF_REASON1(pon->base),
+				buf, 2);
+	if (rc) {
+		dev_err(&pon->spmi->dev, "Unable to read POFF_RESASON regs\n");
+		return rc;
+	}
+	poff_sts = buf[0] | (buf[1] << 8);
+	index = ffs(poff_sts) - 1;
+	if (index >= ARRAY_SIZE(qpnp_poff_reason) || index < 0)
+		dev_info(&pon->spmi->dev,
+				"PMIC@SID%d: Unknown power-off reason\n",
+				pon->spmi->sid);
+	else
+		dev_info(&pon->spmi->dev,
+				"PMIC@SID%d: Power-off reason: %s\n",
+				pon->spmi->sid,
+				qpnp_poff_reason[index]);
 
 	rc = of_property_read_u32(pon->spmi->dev.of_node,
 				"qcom,pon-dbc-delay", &delay);
@@ -1090,6 +1227,32 @@
 		}
 	}
 
+	/* program s3 source */
+	s3_src = "kpdpwr-and-resin";
+	rc = of_property_read_string(pon->spmi->dev.of_node,
+				"qcom,s3-src", &s3_src);
+	if (rc && rc != -EINVAL) {
+		dev_err(&pon->spmi->dev, "Unable to read s3 timer\n");
+		return rc;
+	}
+
+	if (!strcmp(s3_src, "kpdpwr"))
+		s3_src_reg = QPNP_PON_S3_SRC_KPDPWR;
+	else if (!strcmp(s3_src, "resin"))
+		s3_src_reg = QPNP_PON_S3_SRC_RESIN;
+	else if (!strcmp(s3_src, "kpdpwr-or-resin"))
+		s3_src_reg = QPNP_PON_S3_SRC_KPDPWR_OR_RESIN;
+	else /* default combination */
+		s3_src_reg = QPNP_PON_S3_SRC_KPDPWR_AND_RESIN;
+
+	rc = qpnp_pon_masked_write(pon, QPNP_PON_S3_SRC(pon->base),
+			QPNP_PON_S3_SRC_MASK, s3_src_reg);
+	if (rc) {
+		dev_err(&spmi->dev,
+			"Unable to program s3 source\n");
+		return rc;
+	}
+
 	dev_set_drvdata(&spmi->dev, pon);
 
 	INIT_DELAYED_WORK(&pon->bark_work, bark_work_func);
diff --git a/drivers/platform/msm/sps/sps.c b/drivers/platform/msm/sps/sps.c
index c621d2a..55a5a2d 100644
--- a/drivers/platform/msm/sps/sps.c
+++ b/drivers/platform/msm/sps/sps.c
@@ -184,6 +184,11 @@
 		return -EFAULT;
 	}
 
+	if (buf_size_kb > (INT_MAX/SZ_1K)) {
+		pr_err("sps:debugfs: buffer size is too large\n");
+		return -EFAULT;
+	}
+
 	new_buf_size = buf_size_kb * SZ_1K;
 
 	if (debugfs_record_enabled) {
@@ -2529,21 +2534,8 @@
 		goto device_create_err;
 	}
 
-	sps->dfab_clk = clk_get(sps->dev, "dfab_clk");
-	if (IS_ERR(sps->dfab_clk)) {
-		if (PTR_ERR(sps->dfab_clk) == -EPROBE_DEFER)
-			ret = -EPROBE_DEFER;
-		else
-			SPS_ERR("sps:fail to get dfab_clk.");
-		goto clk_err;
-	} else {
-		ret = clk_set_rate(sps->dfab_clk, 64000000);
-		if (ret) {
-			SPS_ERR("sps:failed to set dfab_clk rate.");
-			clk_put(sps->dfab_clk);
-			goto clk_err;
-		}
-	}
+	if (pdev->dev.of_node)
+		sps->dev->of_node = pdev->dev.of_node;
 
 	if (!d_type) {
 		sps->pmem_clk = clk_get(sps->dev, "mem_clk");
@@ -2552,36 +2544,58 @@
 				ret = -EPROBE_DEFER;
 			else
 				SPS_ERR("sps:fail to get pmem_clk.");
-			goto clk_err;
+			goto pmem_clk_err;
 		} else {
 			ret = clk_prepare_enable(sps->pmem_clk);
 			if (ret) {
 				SPS_ERR("sps:failed to enable pmem_clk.");
-				goto clk_err;
+				goto pmem_clk_en_err;
 			}
 		}
 	}
 
 #ifdef CONFIG_SPS_SUPPORT_BAMDMA
+	sps->dfab_clk = clk_get(sps->dev, "dfab_clk");
+	if (IS_ERR(sps->dfab_clk)) {
+		if (PTR_ERR(sps->dfab_clk) == -EPROBE_DEFER)
+			ret = -EPROBE_DEFER;
+		else
+			SPS_ERR("sps:fail to get dfab_clk.");
+		goto dfab_clk_err;
+	} else {
+		ret = clk_set_rate(sps->dfab_clk, 64000000);
+		if (ret) {
+			SPS_ERR("sps:failed to set dfab_clk rate.");
+			clk_put(sps->dfab_clk);
+			goto dfab_clk_err;
+		}
+	}
+
 	sps->bamdma_clk = clk_get(sps->dev, "dma_bam_pclk");
 	if (IS_ERR(sps->bamdma_clk)) {
 		if (PTR_ERR(sps->bamdma_clk) == -EPROBE_DEFER)
 			ret = -EPROBE_DEFER;
 		else
 			SPS_ERR("sps:fail to get bamdma_clk.");
-		goto clk_err;
+		clk_put(sps->dfab_clk);
+		goto dfab_clk_err;
 	} else {
 		ret = clk_prepare_enable(sps->bamdma_clk);
 		if (ret) {
 			SPS_ERR("sps:failed to enable bamdma_clk. ret=%d", ret);
-			goto clk_err;
+			clk_put(sps->bamdma_clk);
+			clk_put(sps->dfab_clk);
+			goto dfab_clk_err;
 		}
 	}
 
 	ret = clk_prepare_enable(sps->dfab_clk);
 	if (ret) {
 		SPS_ERR("sps:failed to enable dfab_clk. ret=%d", ret);
-		goto clk_err;
+		clk_disable_unprepare(sps->bamdma_clk);
+		clk_put(sps->bamdma_clk);
+		clk_put(sps->dfab_clk);
+		goto dfab_clk_err;
 	}
 #endif
 	ret = sps_device_init();
@@ -2590,8 +2604,10 @@
 #ifdef CONFIG_SPS_SUPPORT_BAMDMA
 		clk_disable_unprepare(sps->dfab_clk);
 		clk_disable_unprepare(sps->bamdma_clk);
+		clk_put(sps->bamdma_clk);
+		clk_put(sps->dfab_clk);
 #endif
-		goto sps_device_init_err;
+		goto dfab_clk_err;
 	}
 #ifdef CONFIG_SPS_SUPPORT_BAMDMA
 	clk_disable_unprepare(sps->dfab_clk);
@@ -2602,8 +2618,13 @@
 	SPS_INFO("sps:sps is ready.");
 
 	return 0;
-clk_err:
-sps_device_init_err:
+dfab_clk_err:
+	if (!d_type)
+		clk_disable_unprepare(sps->pmem_clk);
+pmem_clk_en_err:
+	if (!d_type)
+		clk_put(sps->pmem_clk);
+pmem_clk_err:
 	device_destroy(sps->dev_class, sps->dev_num);
 device_create_err:
 	unregister_chrdev_region(sps->dev_num, 1);
diff --git a/drivers/platform/msm/sps/sps_bam.c b/drivers/platform/msm/sps/sps_bam.c
index bd4328a..ad5e241 100644
--- a/drivers/platform/msm/sps/sps_bam.c
+++ b/drivers/platform/msm/sps/sps_bam.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
@@ -169,6 +169,7 @@
 	list_for_each_entry(pipe, &dev->pipes_q, list) {
 		/* Check this pipe's bit in the source mask */
 		if (BAM_PIPE_IS_ASSIGNED(pipe)
+				&& (!pipe->disconnecting)
 				&& (source & pipe->pipe_index_mask)) {
 			/* This pipe has an interrupt pending */
 			pipe_handler(dev, pipe);
@@ -585,6 +586,7 @@
 	pipe->mode = -1;
 	pipe->num_descs = 0;
 	pipe->desc_size = 0;
+	pipe->disconnecting = false;
 	memset(&pipe->sys, 0, sizeof(pipe->sys));
 	INIT_LIST_HEAD(&pipe->sys.events_q);
 }
diff --git a/drivers/platform/msm/sps/sps_bam.h b/drivers/platform/msm/sps/sps_bam.h
index da5dafd..a20156b 100644
--- a/drivers/platform/msm/sps/sps_bam.h
+++ b/drivers/platform/msm/sps/sps_bam.h
@@ -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
@@ -185,6 +185,7 @@
 	/* System mode control */
 	struct sps_bam_sys_mode sys;
 
+	bool disconnecting;
 };
 
 /* BAM device descriptor */
diff --git a/drivers/platform/msm/sps/sps_rm.c b/drivers/platform/msm/sps/sps_rm.c
index 7d7e1a6..d8c7a4d 100644
--- a/drivers/platform/msm/sps/sps_rm.c
+++ b/drivers/platform/msm/sps/sps_rm.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
@@ -556,11 +556,8 @@
 {
 	struct sps_connection *map = (void *)pipe->map;
 	struct sps_connect *cfg = &pipe->connect;
-	struct sps_bam *bam = pipe->bam;
-	unsigned long flags;
 
 	mutex_lock(&sps_rm->lock);
-	spin_lock_irqsave(&bam->isr_lock, flags);
 
 	/* Free this connection */
 	if (cfg->mode == SPS_MODE_SRC)
@@ -574,7 +571,6 @@
 
 	sps_rm_remove_ref(map);
 
-	spin_unlock_irqrestore(&bam->isr_lock, flags);
 	mutex_unlock(&sps_rm->lock);
 
 	return 0;
@@ -800,8 +796,9 @@
 			synchronize_irq(bam->props.irq);
 
 		spin_lock_irqsave(&bam->isr_lock, flags);
-		result = sps_bam_pipe_disconnect(pipe->bam, pipe_index);
+		pipe->disconnecting = true;
 		spin_unlock_irqrestore(&bam->isr_lock, flags);
+		result = sps_bam_pipe_disconnect(pipe->bam, pipe_index);
 		if (result) {
 			SPS_ERR("sps:Failed to disconnect BAM 0x%x pipe %d",
 				pipe->bam->props.phys_addr,
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 85a70ea..e227ecd 100644
--- a/drivers/power/qpnp-bms.c
+++ b/drivers/power/qpnp-bms.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
@@ -130,6 +130,7 @@
 struct bms_irq {
 	unsigned int	irq;
 	unsigned long	disabled;
+	bool		ready;
 };
 
 struct bms_wakeup_source {
@@ -280,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;
@@ -393,7 +395,7 @@
 
 static void enable_bms_irq(struct bms_irq *irq)
 {
-	if (__test_and_clear_bit(0, &irq->disabled)) {
+	if (irq->ready && __test_and_clear_bit(0, &irq->disabled)) {
 		enable_irq(irq->irq);
 		pr_debug("enabled irq %d\n", irq->irq);
 	}
@@ -401,12 +403,20 @@
 
 static void disable_bms_irq(struct bms_irq *irq)
 {
-	if (!__test_and_set_bit(0, &irq->disabled)) {
+	if (irq->ready && !__test_and_set_bit(0, &irq->disabled)) {
 		disable_irq(irq->irq);
 		pr_debug("disabled irq %d\n", irq->irq);
 	}
 }
 
+static void disable_bms_irq_nosync(struct bms_irq *irq)
+{
+	if (irq->ready && !__test_and_set_bit(0, &irq->disabled)) {
+		disable_irq_nosync(irq->irq);
+		pr_debug("disabled irq %d\n", irq->irq);
+	}
+}
+
 #define HOLD_OREG_DATA		BIT(0)
 static int lock_output_data(struct qpnp_bms_chip *chip)
 {
@@ -482,7 +492,7 @@
 }
 
 static inline int convert_vbatt_raw_to_uv(struct qpnp_bms_chip *chip,
-					uint16_t reading)
+					uint16_t reading, bool is_pon_ocv)
 {
 	int64_t uv;
 	int rc;
@@ -491,7 +501,7 @@
 	pr_debug("%u raw converted into %lld uv\n", reading, uv);
 	uv = adjust_vbatt_reading(chip, uv);
 	pr_debug("adjusted into %lld uv\n", uv);
-	rc = qpnp_vbat_sns_comp_result(chip->vadc_dev, &uv);
+	rc = qpnp_vbat_sns_comp_result(chip->vadc_dev, &uv, is_pon_ocv);
 	if (rc)
 		pr_debug("could not compensate vbatt\n");
 	pr_debug("compensated into %lld uv\n", uv);
@@ -597,12 +607,14 @@
 	temp_current = div_s64((vsense_uv * 1000000LL),
 				(int)chip->r_sense_uohm);
 
+	*result_ua = temp_current;
 	rc = qpnp_iadc_comp_result(chip->iadc_dev, &temp_current);
 	if (rc)
 		pr_debug("error compensation failed: %d\n", rc);
 
+	pr_debug("%d uA err compensated ibat=%llduA\n",
+			*result_ua, temp_current);
 	*result_ua = temp_current;
-	pr_debug("err compensated ibat=%duA\n", *result_ua);
 	return 0;
 }
 
@@ -688,7 +700,7 @@
 
 static void convert_and_store_ocv(struct qpnp_bms_chip *chip,
 				struct raw_soc_params *raw,
-				int batt_temp)
+				int batt_temp, bool is_pon_ocv)
 {
 	int rc;
 
@@ -700,7 +712,7 @@
 		pr_err("Vadc reference voltage read failed, rc = %d\n", rc);
 	chip->prev_last_good_ocv_raw = raw->last_good_ocv_raw;
 	raw->last_good_ocv_uv = convert_vbatt_raw_to_uv(chip,
-					raw->last_good_ocv_raw);
+					raw->last_good_ocv_raw, is_pon_ocv);
 	chip->last_ocv_uv = raw->last_good_ocv_uv;
 	chip->last_ocv_temp = batt_temp;
 	chip->software_cc_uah = 0;
@@ -740,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;
 	}
 
@@ -755,6 +772,30 @@
 	return POWER_SUPPLY_STATUS_UNKNOWN;
 }
 
+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 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 POWER_SUPPLY_CHARGE_TYPE_NONE;
+}
+
 static bool is_battery_charging(struct qpnp_bms_chip *chip)
 {
 	return get_battery_status(chip) == POWER_SUPPLY_STATUS_CHARGING;
@@ -785,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;
 	}
 
@@ -827,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;
 	}
 
@@ -883,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);
@@ -897,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;
@@ -911,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;
@@ -939,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;
@@ -979,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++;
@@ -1004,28 +1074,27 @@
 			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);
 	mutex_unlock(&chip->bms_output_lock);
 
 	if (chip->prev_last_good_ocv_raw == OCV_RAW_UNINITIALIZED) {
-		convert_and_store_ocv(chip, raw, batt_temp);
+		convert_and_store_ocv(chip, raw, batt_temp, true);
 		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",
@@ -1054,7 +1123,7 @@
 		pr_debug("EOC Battery full ocv_reading = 0x%x\n",
 				chip->ocv_reading_at_100);
 	} else if (chip->prev_last_good_ocv_raw != raw->last_good_ocv_raw) {
-		convert_and_store_ocv(chip, raw, batt_temp);
+		convert_and_store_ocv(chip, raw, batt_temp, false);
 		/* forget the old cc value upon ocv */
 		chip->last_cc_uah = INT_MIN;
 	} else {
@@ -1069,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,
@@ -1077,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. */
@@ -1189,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)
@@ -1244,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;
@@ -1253,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);
@@ -1290,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;
@@ -1313,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;
 
@@ -1329,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)
@@ -1479,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);
 
@@ -1493,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);
 
@@ -1785,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);
 	/*
@@ -1894,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;
@@ -2181,7 +2232,12 @@
 		pr_err("adc vbat failed err = %d\n", rc);
 		return soc;
 	}
-	if (soc == 0 && vbat_uv > chip->v_cutoff_uv) {
+
+	/* only clamp when discharging */
+	if (is_battery_charging(chip))
+		return soc;
+
+	if (soc <= 0 && vbat_uv > chip->v_cutoff_uv) {
 		pr_debug("clamping soc to 1, vbat (%d) > cutoff (%d)\n",
 						vbat_uv, chip->v_cutoff_uv);
 		return 1;
@@ -2394,8 +2450,13 @@
 	}
 	mutex_unlock(&chip->soc_invalidation_mutex);
 
-	pr_debug("SOC before adjustment = %d\n", soc);
-	new_calculated_soc = adjust_soc(chip, &params, soc, batt_temp);
+	if (chip->first_time_calc_soc && !chip->shutdown_soc_invalid) {
+		pr_debug("Skip adjustment when shutdown SOC has been forced\n");
+		new_calculated_soc = soc;
+	} else {
+		pr_debug("SOC before adjustment = %d\n", soc);
+		new_calculated_soc = adjust_soc(chip, &params, soc, batt_temp);
+	}
 
 	/* always clamp soc due to BMS hw/sw immaturities */
 	new_calculated_soc = clamp_soc_based_on_voltage(chip,
@@ -2496,7 +2557,7 @@
 		soc = calculate_soc_from_voltage(chip);
 	} else {
 		if (!chip->batfet_closed)
-			qpnp_iadc_calibrate_for_trim(chip->iadc_dev, true);
+			qpnp_iadc_calibrate_for_trim(chip->iadc_dev, false);
 		rc = qpnp_vadc_read(chip->vadc_dev, LR_MUX1_BATT_THERM,
 								&result);
 		if (rc) {
@@ -2548,7 +2609,7 @@
 		soc = calculate_soc_from_voltage(chip);
 	} else {
 		if (!chip->batfet_closed)
-			qpnp_iadc_calibrate_for_trim(chip->iadc_dev, true);
+			qpnp_iadc_calibrate_for_trim(chip->iadc_dev, false);
 		rc = qpnp_vadc_read(chip->vadc_dev, LR_MUX1_BATT_THERM,
 								&result);
 		if (rc) {
@@ -3104,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);
@@ -3203,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) {
@@ -3273,12 +3335,11 @@
 {
 	bool batfet_closed;
 
-	if (chip->iadc_bms_revision2 > CALIB_WRKARND_DIG_MAJOR_MAX)
-		return;
-
 	batfet_closed = is_batfet_closed(chip);
 	if (chip->batfet_closed != batfet_closed) {
 		chip->batfet_closed = batfet_closed;
+		if (chip->iadc_bms_revision2 > CALIB_WRKARND_DIG_MAJOR_MAX)
+			return;
 		if (batfet_closed == false) {
 			/* batfet opened */
 			schedule_work(&chip->batfet_open_work);
@@ -3335,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,
@@ -3499,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);
@@ -3550,7 +3617,7 @@
 	struct qpnp_bms_chip *chip = _chip;
 
 	pr_debug("sw_cc_thr irq triggered\n");
-	disable_bms_irq(&chip->sw_cc_thr_irq);
+	disable_bms_irq_nosync(&chip->sw_cc_thr_irq);
 	bms_stay_awake(&chip->soc_wake_source);
 	schedule_work(&chip->recalc_work);
 	return IRQ_HANDLED;
@@ -3864,6 +3931,7 @@
 		pr_err("Unable to request " #irq_name " irq: %d\n", rc);\
 		return -ENXIO;						\
 	}								\
+	chip->irq_name##_irq.ready = true;				\
 } while (0)
 
 static int bms_request_irqs(struct qpnp_bms_chip *chip)
@@ -3871,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;
 }
@@ -4273,6 +4343,12 @@
 		goto error_setup;
 	}
 
+	rc = bms_request_irqs(chip);
+	if (rc) {
+		pr_err("error requesting bms irqs, rc = %d\n", rc);
+		goto error_setup;
+	}
+
 	battery_insertion_check(chip);
 	batfet_status_check(chip);
 	battery_status_check(chip);
@@ -4306,12 +4382,6 @@
 		goto unregister_dc;
 	}
 
-	rc = bms_request_irqs(chip);
-	if (rc) {
-		pr_err("error requesting bms irqs, rc = %d\n", rc);
-		goto unregister_dc;
-	}
-
 	pr_info("probe success: soc =%d vbatt = %d ocv = %d r_sense_uohm = %u warm_reset = %d\n",
 			get_prop_bms_capacity(chip), vbatt, chip->last_ocv_uv,
 			chip->r_sense_uohm, warm_reset);
diff --git a/drivers/power/qpnp-charger.c b/drivers/power/qpnp-charger.c
index 6ea4ea6..d5c753f 100644
--- a/drivers/power/qpnp-charger.c
+++ b/drivers/power/qpnp-charger.c
@@ -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
@@ -113,7 +113,11 @@
 #define USB_OCP_THR				0x52
 #define USB_OCP_CLR				0x53
 #define BAT_IF_TEMP_STATUS			0x09
-
+#define BOOST_ILIM				0x78
+#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 */
@@ -160,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 */
@@ -217,6 +222,7 @@
 struct qpnp_chg_irq {
 	int		irq;
 	unsigned long		disabled;
+	unsigned long		wake_enable;
 };
 
 struct qpnp_chg_regulator {
@@ -247,6 +253,7 @@
  * @max_voltage_mv:		the max volts the batt should be charged up to
  * @min_voltage_mv:		min battery voltage before turning the FET on
  * @batt_weak_voltage_mv:	Weak battery voltage threshold
+ * @vbatdet_max_err_mv		resume voltage hysterisis
  * @max_bat_chg_current:	maximum battery charge current in mA
  * @warm_bat_chg_ma:	warm battery maximum charge current in mA
  * @cool_bat_chg_ma:	cool battery maximum charge current in mA
@@ -315,6 +322,8 @@
 	bool				ibat_calibration_enabled;
 	bool				aicl_settled;
 	bool				use_external_rsense;
+	bool				fastchg_on;
+	bool				parallel_ovp_mode;
 	unsigned int			bpd_detection;
 	unsigned int			max_bat_chg_current;
 	unsigned int			warm_bat_chg_ma;
@@ -323,6 +332,7 @@
 	unsigned int			max_voltage_mv;
 	unsigned int			min_voltage_mv;
 	unsigned int			batt_weak_voltage_mv;
+	unsigned int			vbatdet_max_err_mv;
 	int				prev_usb_max_ma;
 	int				set_vddmax_mv;
 	int				delta_vddmax_mv;
@@ -362,6 +372,7 @@
 	struct work_struct		soc_check_work;
 	struct delayed_work		aicl_check_work;
 	struct work_struct		insertion_ocv_work;
+	struct work_struct		ocp_clear_work;
 	struct qpnp_chg_regulator	otg_vreg;
 	struct qpnp_chg_regulator	boost_vreg;
 	struct qpnp_chg_regulator	batfet_vreg;
@@ -379,6 +390,8 @@
 	bool				power_stage_workaround_enable;
 };
 
+static void
+qpnp_chg_set_appropriate_battery_current(struct qpnp_chg_chip *chip);
 
 static struct of_device_id qpnp_charger_match_table[] = {
 	{ .compatible = QPNP_CHARGER_DEV_NAME, },
@@ -529,6 +542,24 @@
 	}
 }
 
+static void
+qpnp_chg_irq_wake_enable(struct qpnp_chg_irq *irq)
+{
+	if (!__test_and_set_bit(0, &irq->wake_enable)) {
+		pr_debug("number = %d\n", irq->irq);
+		enable_irq_wake(irq->irq);
+	}
+}
+
+static void
+qpnp_chg_irq_wake_disable(struct qpnp_chg_irq *irq)
+{
+	if (__test_and_clear_bit(0, &irq->wake_enable)) {
+		pr_debug("number = %d\n", irq->irq);
+		disable_irq_wake(irq->irq);
+	}
+}
+
 #define USB_OTG_EN_BIT	BIT(0)
 static int
 qpnp_chg_is_otg_en_set(struct qpnp_chg_chip *chip)
@@ -620,24 +651,42 @@
 	return (batfet_closed_rt_sts & BAT_FET_ON_IRQ) ? 1 : 0;
 }
 
-#define USB_VALID_BIT	BIT(7)
 static int
 qpnp_chg_is_usb_chg_plugged_in(struct qpnp_chg_chip *chip)
 {
-	u8 usbin_valid_rt_sts;
+	u8 usb_chgpth_rt_sts;
 	int rc;
 
-	rc = qpnp_chg_read(chip, &usbin_valid_rt_sts,
-				 chip->usb_chgpth_base + CHGR_STATUS , 1);
+	rc = qpnp_chg_read(chip, &usb_chgpth_rt_sts,
+				 INT_RT_STS(chip->usb_chgpth_base), 1);
 
 	if (rc) {
 		pr_err("spmi read failed: addr=%03X, rc=%d\n",
-				chip->usb_chgpth_base + CHGR_STATUS, rc);
+				INT_RT_STS(chip->usb_chgpth_base), rc);
 		return rc;
 	}
-	pr_debug("chgr usb sts 0x%x\n", usbin_valid_rt_sts);
+	pr_debug("chgr usb sts 0x%x\n", usb_chgpth_rt_sts);
 
-	return (usbin_valid_rt_sts & USB_VALID_BIT) ? 1 : 0;
+	return (usb_chgpth_rt_sts & USBIN_VALID_IRQ) ? 1 : 0;
+}
+
+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
@@ -656,10 +705,10 @@
 	return !!(buck_sts & IBAT_LOOP_IRQ);
 }
 
-#define USB_VALID_MASK 0xC0
-#define USB_COARSE_DET 0x10
-#define USB_VALID_UVP_VALUE    0x00
-#define USB_VALID_OVP_VALUE    0x40
+#define USB_VALID_MASK		0xC0
+#define USB_VALID_IN_MASK	BIT(7)
+#define USB_COARSE_DET		0x10
+#define USB_VALID_OVP_VALUE	0x40
 static int
 qpnp_chg_check_usb_coarse_det(struct qpnp_chg_chip *chip)
 {
@@ -678,7 +727,8 @@
 static int
 qpnp_chg_check_usbin_health(struct qpnp_chg_chip *chip)
 {
-	u8 usbin_chg_rt_sts, usbin_health = 0;
+	u8 usbin_chg_rt_sts, usb_chgpth_rt_sts;
+	u8 usbin_health = 0;
 	int rc;
 
 	rc = qpnp_chg_read(chip, &usbin_chg_rt_sts,
@@ -690,13 +740,23 @@
 		return rc;
 	}
 
-	pr_debug("chgr usb sts 0x%x\n", usbin_chg_rt_sts);
+	rc = qpnp_chg_read(chip, &usb_chgpth_rt_sts,
+		INT_RT_STS(chip->usb_chgpth_base) , 1);
+
+	if (rc) {
+		pr_err("spmi read failed: addr=%03X, rc=%d\n",
+		INT_RT_STS(chip->usb_chgpth_base), rc);
+		return rc;
+	}
+
+	pr_debug("chgr usb sts 0x%x, chgpth rt sts 0x%x\n",
+				usbin_chg_rt_sts, usb_chgpth_rt_sts);
 	if ((usbin_chg_rt_sts & USB_COARSE_DET) == USB_COARSE_DET) {
 		if ((usbin_chg_rt_sts & USB_VALID_MASK)
 			 == USB_VALID_OVP_VALUE) {
 			usbin_health = USBIN_OVP;
 			pr_err("Over voltage charger inserted\n");
-		} else if ((usbin_chg_rt_sts & USB_VALID_BIT) != 0) {
+		} else if ((usb_chgpth_rt_sts & USBIN_VALID_IRQ) != 0) {
 			usbin_health = USBIN_OK;
 			pr_debug("Valid charger inserted\n");
 		}
@@ -832,13 +892,12 @@
 	int rc = 0;
 	u8 usb_reg = 0, temp = 8;
 
-	if (mA < QPNP_CHG_I_MAX_MIN_100
-			|| mA > QPNP_CHG_I_MAX_MAX_MA) {
+	if (mA < 0 || mA > QPNP_CHG_I_MAX_MAX_MA) {
 		pr_err("bad mA=%d asked to set\n", mA);
 		return -EINVAL;
 	}
 
-	if (mA == QPNP_CHG_I_MAX_MIN_100) {
+	if (mA <= QPNP_CHG_I_MAX_MIN_100) {
 		usb_reg = 0x00;
 		pr_debug("current=%d setting %02x\n", mA, usb_reg);
 		return qpnp_chg_write(chip, &usb_reg,
@@ -882,21 +941,21 @@
 	return rc;
 }
 
-#define QPNP_CHG_VINMIN_MIN_MV		4200
+#define QPNP_CHG_VINMIN_MIN_MV		4000
 #define QPNP_CHG_VINMIN_HIGH_MIN_MV	5600
 #define QPNP_CHG_VINMIN_HIGH_MIN_VAL	0x2B
 #define QPNP_CHG_VINMIN_MAX_MV		9600
 #define QPNP_CHG_VINMIN_STEP_MV		50
 #define QPNP_CHG_VINMIN_STEP_HIGH_MV	200
 #define QPNP_CHG_VINMIN_MASK		0x3F
-#define QPNP_CHG_VINMIN_MIN_VAL	0x10
+#define QPNP_CHG_VINMIN_MIN_VAL	0x0C
 static int
 qpnp_chg_vinmin_set(struct qpnp_chg_chip *chip, int voltage)
 {
 	u8 temp;
 
-	if (voltage < QPNP_CHG_VINMIN_MIN_MV
-			|| voltage > QPNP_CHG_VINMIN_MAX_MV) {
+	if ((voltage < QPNP_CHG_VINMIN_MIN_MV)
+			|| (voltage > QPNP_CHG_VINMIN_MAX_MV)) {
 		pr_err("bad mV=%d asked to set\n", voltage);
 		return -EINVAL;
 	}
@@ -988,10 +1047,69 @@
 	return iusbmax_ma;
 }
 
+#define ILIMIT_OVR_0	0x02
+static int
+override_dcin_ilimit(struct qpnp_chg_chip *chip, bool override)
+{
+	int rc;
+
+	pr_debug("override %d\n", override);
+	rc = qpnp_chg_masked_write(chip,
+			chip->dc_chgpth_base + SEC_ACCESS,
+			0xA5,
+			0xA5, 1);
+	rc |= qpnp_chg_masked_write(chip,
+			chip->dc_chgpth_base + DC_COMP_OVR1,
+			0xFF,
+			override ? ILIMIT_OVR_0 : 0, 1);
+	if (rc) {
+		pr_err("Failed to override dc ilimit rc = %d\n", rc);
+		return rc;
+	}
+
+	return rc;
+}
+
+#define DUAL_PATH_EN	BIT(7)
+static int
+switch_parallel_ovp_mode(struct qpnp_chg_chip *chip, bool enable)
+{
+	int rc = 0;
+
+	if (!chip->usb_chgpth_base || !chip->dc_chgpth_base)
+		return rc;
+
+	pr_debug("enable %d\n", enable);
+	rc = override_dcin_ilimit(chip, 1);
+	udelay(10);
+
+	/* enable/disable dual path mode */
+	rc = qpnp_chg_masked_write(chip,
+			chip->usb_chgpth_base + SEC_ACCESS,
+			0xA5,
+			0xA5, 1);
+	rc |= qpnp_chg_masked_write(chip,
+			chip->usb_chgpth_base + USB_SPARE,
+			0xFF,
+			enable ? DUAL_PATH_EN : 0, 1);
+	if (rc) {
+		pr_err("Failed to turn on usb ovp rc = %d\n", rc);
+		return rc;
+	}
+
+	if (enable)
+		rc = override_dcin_ilimit(chip, 0);
+	return rc;
+}
+
 #define USB_SUSPEND_BIT	BIT(0)
 static int
 qpnp_chg_usb_suspend_enable(struct qpnp_chg_chip *chip, int enable)
 {
+	/* Turn off DC OVP FET when going into USB suspend */
+	if (chip->parallel_ovp_mode && enable)
+		switch_parallel_ovp_mode(chip, 0);
+
 	return qpnp_chg_masked_write(chip,
 			chip->usb_chgpth_base + CHGR_USB_USB_SUSP,
 			USB_SUSPEND_BIT,
@@ -1198,7 +1316,9 @@
 		pr_err("failed to read usb_chgpth_sts rc=%d\n", rc);
 
 	pr_debug("chg_gone triggered\n");
-	if (qpnp_chg_is_usb_chg_plugged_in(chip) && (usb_sts & CHG_GONE_IRQ)) {
+	if ((qpnp_chg_is_usb_chg_plugged_in(chip)
+			|| qpnp_chg_is_dc_chg_plugged_in(chip))
+			&& (usb_sts & CHG_GONE_IRQ)) {
 		qpnp_chg_charge_en(chip, 0);
 		qpnp_chg_force_run_on_batt(chip, 1);
 		schedule_delayed_work(&chip->arb_stop_work,
@@ -1212,10 +1332,36 @@
 qpnp_chg_usb_usb_ocp_irq_handler(int irq, void *_chip)
 {
 	struct qpnp_chg_chip *chip = _chip;
-	int rc;
 
 	pr_debug("usb-ocp triggered\n");
 
+	schedule_work(&chip->ocp_clear_work);
+
+	return IRQ_HANDLED;
+}
+
+#define BOOST_ILIMIT_MIN	0x07
+#define BOOST_ILIMIT_DEF	0x02
+#define BOOST_ILIMT_MASK	0xFF
+static void
+qpnp_chg_ocp_clear_work(struct work_struct *work)
+{
+	int rc;
+	u8 usb_sts;
+	struct qpnp_chg_chip *chip = container_of(work,
+		struct qpnp_chg_chip, ocp_clear_work);
+
+	if (chip->type == SMBBP) {
+		rc = qpnp_chg_masked_write(chip,
+				chip->boost_base + BOOST_ILIM,
+				BOOST_ILIMT_MASK,
+				BOOST_ILIMIT_MIN, 1);
+		if (rc) {
+			pr_err("Failed to turn configure ilim rc = %d\n", rc);
+			return;
+		}
+	}
+
 	rc = qpnp_chg_masked_write(chip,
 			chip->usb_chgpth_base + USB_OCP_CLR,
 			OCP_CLR_BIT,
@@ -1231,7 +1377,29 @@
 	if (rc)
 		pr_err("Failed to turn off usb ovp rc = %d\n", rc);
 
-	return IRQ_HANDLED;
+	if (chip->type == SMBBP) {
+		/* Wait for OCP circuitry to be powered up */
+		msleep(100);
+		rc = qpnp_chg_read(chip, &usb_sts,
+				INT_RT_STS(chip->usb_chgpth_base), 1);
+		if (rc) {
+			pr_err("failed to read interrupt sts %d\n", rc);
+			return;
+		}
+
+		if (usb_sts & COARSE_DET_USB_IRQ) {
+			rc = qpnp_chg_masked_write(chip,
+				chip->boost_base + BOOST_ILIM,
+				BOOST_ILIMT_MASK,
+				BOOST_ILIMIT_DEF, 1);
+			if (rc) {
+				pr_err("Failed to set ilim rc = %d\n", rc);
+				return;
+			}
+		} else {
+			pr_warn_ratelimited("USB short to GND detected!\n");
+		}
+	}
 }
 
 #define QPNP_CHG_VDDMAX_MIN		3400
@@ -1430,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)
 {
@@ -1475,7 +1646,12 @@
 				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;
 			chip->aicl_settled = false;
 		} else {
@@ -1516,15 +1692,38 @@
 	return IRQ_HANDLED;
 }
 
+#define TEST_EN_SMBC_LOOP		0xE5
+#define IBAT_REGULATION_DISABLE		BIT(2)
 static irqreturn_t
 qpnp_chg_bat_if_batt_temp_irq_handler(int irq, void *_chip)
 {
 	struct qpnp_chg_chip *chip = _chip;
-	int batt_temp_good;
+	int batt_temp_good, batt_present, rc;
 
 	batt_temp_good = qpnp_chg_is_batt_temp_ok(chip);
 	pr_debug("batt-temp triggered: %d\n", batt_temp_good);
 
+	batt_present = qpnp_chg_is_batt_present(chip);
+	if (batt_present) {
+		rc = qpnp_chg_masked_write(chip,
+			chip->buck_base + SEC_ACCESS,
+			0xFF,
+			0xA5, 1);
+		if (rc) {
+			pr_err("failed to write SEC_ACCESS rc=%d\n", rc);
+			return rc;
+		}
+
+		rc = qpnp_chg_masked_write(chip,
+			chip->buck_base + TEST_EN_SMBC_LOOP,
+			IBAT_REGULATION_DISABLE,
+			batt_temp_good ? 0 : IBAT_REGULATION_DISABLE, 1);
+		if (rc) {
+			pr_err("failed to write COMP_OVR1 rc=%d\n", rc);
+			return rc;
+		}
+	}
+
 	pr_debug("psy changed batt_psy\n");
 	power_supply_changed(&chip->batt_psy);
 	return IRQ_HANDLED;
@@ -1534,15 +1733,51 @@
 qpnp_chg_bat_if_batt_pres_irq_handler(int irq, void *_chip)
 {
 	struct qpnp_chg_chip *chip = _chip;
-	int batt_present;
+	int batt_present, batt_temp_good, rc;
 
 	batt_present = qpnp_chg_is_batt_present(chip);
 	pr_debug("batt-pres triggered: %d\n", batt_present);
 
 	if (chip->batt_present ^ batt_present) {
 		if (batt_present) {
+			batt_temp_good = qpnp_chg_is_batt_temp_ok(chip);
+			rc = qpnp_chg_masked_write(chip,
+				chip->buck_base + SEC_ACCESS,
+				0xFF,
+				0xA5, 1);
+			if (rc) {
+				pr_err("failed to write SEC_ACCESS: %d\n", rc);
+				return rc;
+			}
+
+			rc = qpnp_chg_masked_write(chip,
+				chip->buck_base + TEST_EN_SMBC_LOOP,
+				IBAT_REGULATION_DISABLE,
+				batt_temp_good
+				? 0 : IBAT_REGULATION_DISABLE, 1);
+			if (rc) {
+				pr_err("failed to write COMP_OVR1 rc=%d\n", rc);
+				return rc;
+			}
 			schedule_work(&chip->insertion_ocv_work);
 		} else {
+			rc = qpnp_chg_masked_write(chip,
+				chip->buck_base + SEC_ACCESS,
+				0xFF,
+				0xA5, 1);
+			if (rc) {
+				pr_err("failed to write SEC_ACCESS: %d\n", rc);
+				return rc;
+			}
+
+			rc = qpnp_chg_masked_write(chip,
+				chip->buck_base + TEST_EN_SMBC_LOOP,
+				IBAT_REGULATION_DISABLE,
+				0, 1);
+			if (rc) {
+				pr_err("failed to write COMP_OVR1 rc=%d\n", rc);
+				return rc;
+			}
 			chip->insertion_ocv_uv = 0;
 			qpnp_chg_charge_en(chip, 0);
 		}
@@ -1592,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");
@@ -1647,41 +1899,96 @@
 	return IRQ_HANDLED;
 }
 
+static int qpnp_chg_is_fastchg_on(struct qpnp_chg_chip *chip)
+{
+	u8 chgr_sts;
+	int rc;
+
+	qpnp_chg_irq_wake_disable(&chip->chg_fastchg);
+
+	rc = qpnp_chg_read(chip, &chgr_sts, INT_RT_STS(chip->chgr_base), 1);
+	if (rc) {
+		pr_err("failed to read interrupt status %d\n", rc);
+		return rc;
+	}
+	pr_debug("chgr_sts 0x%x\n", chgr_sts);
+	return (chgr_sts & FAST_CHG_ON_IRQ) ? 1 : 0;
+}
+
+#define VBATDET_BYPASS	0x01
+static int
+bypass_vbatdet_comp(struct qpnp_chg_chip *chip, bool bypass)
+{
+	int rc;
+
+	pr_debug("bypass %d\n", bypass);
+		rc = qpnp_chg_masked_write(chip,
+			chip->chgr_base + SEC_ACCESS,
+			0xA5,
+			0xA5, 1);
+	rc |= qpnp_chg_masked_write(chip,
+			chip->chgr_base + CHGR_COMP_OVR1,
+			0xFF,
+			bypass ? VBATDET_BYPASS : 0, 1);
+	if (rc) {
+		pr_err("Failed to bypass vbatdet comp rc = %d\n", rc);
+		return rc;
+	}
+
+	return rc;
+}
+
 static irqreturn_t
 qpnp_chg_chgr_chg_fastchg_irq_handler(int irq, void *_chip)
 {
 	struct qpnp_chg_chip *chip = _chip;
-	u8 chgr_sts;
-	int rc;
+	bool fastchg_on = false;
 
-	rc = qpnp_chg_read(chip, &chgr_sts, INT_RT_STS(chip->chgr_base), 1);
-	if (rc)
-		pr_err("failed to read interrupt sts %d\n", rc);
+	fastchg_on = qpnp_chg_is_fastchg_on(chip);
 
-	pr_debug("FAST_CHG IRQ triggered\n");
-	chip->chg_done = false;
-	if (chip->bat_if_base) {
-		pr_debug("psy changed batt_psy\n");
-		power_supply_changed(&chip->batt_psy);
-	}
+	pr_debug("FAST_CHG IRQ triggered, fastchg_on: %d\n", fastchg_on);
 
-	pr_debug("psy changed usb_psy\n");
-	power_supply_changed(chip->usb_psy);
+	if (chip->fastchg_on ^ fastchg_on) {
+		chip->fastchg_on = fastchg_on;
+		if (chip->bat_if_base) {
+			pr_debug("psy changed batt_psy\n");
+			power_supply_changed(&chip->batt_psy);
+		}
 
-	if (chip->dc_chgpth_base) {
-		pr_debug("psy changed dc_psy\n");
-		power_supply_changed(&chip->dc_psy);
-	}
+		pr_debug("psy changed usb_psy\n");
+		power_supply_changed(chip->usb_psy);
 
-	if (chip->resuming_charging) {
-		chip->resuming_charging = false;
-		qpnp_chg_set_appropriate_vbatdet(chip);
-	}
+		if (chip->dc_chgpth_base) {
+			pr_debug("psy changed dc_psy\n");
+			power_supply_changed(&chip->dc_psy);
+		}
 
-	if (!chip->charging_disabled) {
-		schedule_delayed_work(&chip->eoc_work,
-			msecs_to_jiffies(EOC_CHECK_PERIOD_MS));
-		pm_stay_awake(chip->dev);
+		if (fastchg_on) {
+			chip->chg_done = false;
+			bypass_vbatdet_comp(chip, 1);
+			if (chip->bat_is_warm || chip->bat_is_cool) {
+				qpnp_chg_set_appropriate_vddmax(chip);
+				qpnp_chg_set_appropriate_battery_current(chip);
+			}
+
+			if (chip->resuming_charging) {
+				chip->resuming_charging = false;
+				qpnp_chg_set_appropriate_vbatdet(chip);
+			}
+
+			if (!chip->charging_disabled) {
+				schedule_delayed_work(&chip->eoc_work,
+					msecs_to_jiffies(EOC_CHECK_PERIOD_MS));
+				pm_stay_awake(chip->dev);
+			}
+			if (chip->parallel_ovp_mode)
+				switch_parallel_ovp_mode(chip, 1);
+		} else {
+			if (chip->parallel_ovp_mode)
+				switch_parallel_ovp_mode(chip, 0);
+			if (!chip->bat_is_warm && !chip->bat_is_cool)
+				bypass_vbatdet_comp(chip, 0);
+		}
 	}
 
 	qpnp_chg_enable_irq(&chip->chg_vbatdet_lo);
@@ -1757,6 +2064,17 @@
 	if (!qpnp_chg_is_otg_en_set(chip))
 		return 0;
 
+	if (chip->type == SMBBP) {
+		rc = qpnp_chg_masked_write(chip,
+			chip->boost_base + BOOST_ILIM,
+			BOOST_ILIMT_MASK,
+			BOOST_ILIMIT_DEF, 1);
+		if (rc) {
+			pr_err("Failed to set ilim rc = %d\n", rc);
+			return rc;
+		}
+	}
+
 	/* enable usb ovp fet */
 	rc = qpnp_chg_masked_write(chip,
 			chip->usb_chgpth_base + CHGR_USB_USB_OTG_CTL,
@@ -1780,11 +2098,26 @@
 switch_usb_to_host_mode(struct qpnp_chg_chip *chip)
 {
 	int rc;
+	u8 usb_sts;
 
 	pr_debug("switch to host mode\n");
 	if (qpnp_chg_is_otg_en_set(chip))
 		return 0;
 
+	if (chip->parallel_ovp_mode)
+		switch_parallel_ovp_mode(chip, 0);
+
+	if (chip->type == SMBBP) {
+		rc = qpnp_chg_masked_write(chip,
+				chip->boost_base + BOOST_ILIM,
+				BOOST_ILIMT_MASK,
+				BOOST_ILIMIT_MIN, 1);
+		if (rc) {
+			pr_err("Failed to turn configure ilim rc = %d\n", rc);
+			return rc;
+		}
+	}
+
 	if (!qpnp_chg_is_dc_chg_plugged_in(chip)) {
 		rc = qpnp_chg_force_run_on_batt(chip, 1);
 		if (rc) {
@@ -1803,6 +2136,30 @@
 		return rc;
 	}
 
+	if (chip->type == SMBBP) {
+		/* Wait for OCP circuitry to be powered up */
+		msleep(100);
+		rc = qpnp_chg_read(chip, &usb_sts,
+				INT_RT_STS(chip->usb_chgpth_base), 1);
+		if (rc) {
+			pr_err("failed to read interrupt sts %d\n", rc);
+			return rc;
+		}
+
+		if (usb_sts & COARSE_DET_USB_IRQ) {
+			rc = qpnp_chg_masked_write(chip,
+				chip->boost_base + BOOST_ILIM,
+				BOOST_ILIMT_MASK,
+				BOOST_ILIMIT_DEF, 1);
+			if (rc) {
+				pr_err("Failed to set ilim rc = %d\n", rc);
+				return rc;
+			}
+		} else {
+			pr_warn_ratelimited("USB short to GND detected!\n");
+		}
+	}
+
 	return 0;
 }
 
@@ -1854,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,
@@ -1986,6 +2342,24 @@
 	return POWER_SUPPLY_CHARGE_TYPE_NONE;
 }
 
+#define DEFAULT_CAPACITY	50
+static int
+get_batt_capacity(struct qpnp_chg_chip *chip)
+{
+	union power_supply_propval ret = {0,};
+
+	if (chip->fake_battery_soc >= 0)
+		return chip->fake_battery_soc;
+	if (chip->use_default_batt_values || !get_prop_batt_present(chip))
+		return DEFAULT_CAPACITY;
+	if (chip->bms_psy) {
+		chip->bms_psy->get_property(chip->bms_psy,
+				POWER_SUPPLY_PROP_CAPACITY, &ret);
+		return ret.intval;
+	}
+	return DEFAULT_CAPACITY;
+}
+
 static int
 get_prop_batt_status(struct qpnp_chg_chip *chip)
 {
@@ -2009,11 +2383,18 @@
 		return POWER_SUPPLY_CHARGE_TYPE_NONE;
 	}
 
-	if (chgr_sts & TRKL_CHG_ON_IRQ && bat_if_sts & BAT_FET_ON_IRQ)
+	if ((chgr_sts & TRKL_CHG_ON_IRQ) && !(bat_if_sts & BAT_FET_ON_IRQ))
 		return POWER_SUPPLY_STATUS_CHARGING;
 	if (chgr_sts & FAST_CHG_ON_IRQ && bat_if_sts & BAT_FET_ON_IRQ)
 		return POWER_SUPPLY_STATUS_CHARGING;
 
+	/* report full if state of charge is 100 and a charger is connected */
+	if ((qpnp_chg_is_usb_chg_plugged_in(chip) ||
+		qpnp_chg_is_dc_chg_plugged_in(chip))
+			&& get_batt_capacity(chip) == 100) {
+		return POWER_SUPPLY_STATUS_FULL;
+	}
+
 	return POWER_SUPPLY_STATUS_DISCHARGING;
 }
 
@@ -2065,7 +2446,6 @@
 	return 0;
 }
 
-#define DEFAULT_CAPACITY	50
 static int
 get_prop_capacity(struct qpnp_chg_chip *chip)
 {
@@ -2100,6 +2480,7 @@
 				&& soc <= chip->soc_resume_limit) {
 			pr_debug("resuming charging at %d%% soc\n", soc);
 			chip->resuming_charging = true;
+			qpnp_chg_irq_wake_enable(&chip->chg_fastchg);
 			qpnp_chg_set_appropriate_vbatdet(chip);
 			qpnp_chg_charge_en(chip, !chip->charging_disabled);
 		}
@@ -2134,7 +2515,7 @@
 		pr_debug("Unable to read batt temperature rc=%d\n", rc);
 		return 0;
 	}
-	pr_debug("get_bat_temp %d %lld\n",
+	pr_debug("get_bat_temp %d, %lld\n",
 		results.adc_code, results.physical);
 
 	return (int)results.physical;
@@ -2202,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);
 			}
@@ -2476,6 +2865,25 @@
 	return 0;
 }
 
+static void
+qpnp_chg_set_appropriate_battery_current(struct qpnp_chg_chip *chip)
+{
+	unsigned int chg_current = chip->max_bat_chg_current;
+
+	if (chip->bat_is_cool)
+		chg_current = min(chg_current, chip->cool_bat_chg_ma);
+
+	if (chip->bat_is_warm)
+		chg_current = min(chg_current, chip->warm_bat_chg_ma);
+
+	if (chip->therm_lvl_sel != 0 && chip->thermal_mitigation)
+		chg_current = min(chg_current,
+			chip->thermal_mitigation[chip->therm_lvl_sel]);
+
+	pr_debug("setting %d mA\n", chg_current);
+	qpnp_chg_ibatmax_set(chip, chg_current);
+}
+
 static int
 qpnp_chg_vddsafe_set(struct qpnp_chg_chip *chip, int voltage)
 {
@@ -2684,25 +3092,6 @@
 }
 
 static void
-qpnp_chg_set_appropriate_battery_current(struct qpnp_chg_chip *chip)
-{
-	unsigned int chg_current = chip->max_bat_chg_current;
-
-	if (chip->bat_is_cool)
-		chg_current = min(chg_current, chip->cool_bat_chg_ma);
-
-	if (chip->bat_is_warm)
-		chg_current = min(chg_current, chip->warm_bat_chg_ma);
-
-	if (chip->therm_lvl_sel != 0 && chip->thermal_mitigation)
-		chg_current = min(chg_current,
-			chip->thermal_mitigation[chip->therm_lvl_sel]);
-
-	pr_debug("setting %d mA\n", chg_current);
-	qpnp_chg_ibatmax_set(chip, chg_current);
-}
-
-static void
 qpnp_batt_system_temp_level_set(struct qpnp_chg_chip *chip, int lvl_sel)
 {
 	if (lvl_sel >= 0 && lvl_sel < chip->thermal_levels) {
@@ -3104,12 +3493,13 @@
 		vbat_lower_than_vbatdet = !(chg_sts & VBAT_DET_LOW_IRQ);
 		if (vbat_lower_than_vbatdet && vbat_mv <
 				(chip->max_voltage_mv - chip->resume_delta_mv
-				 - VBATDET_MAX_ERR_MV)) {
+				 - chip->vbatdet_max_err_mv)) {
 			vbat_low_count++;
 			pr_debug("woke up too early vbat_mv = %d, max_mv = %d, resume_mv = %d tolerance_mv = %d low_count = %d\n",
 					vbat_mv, chip->max_voltage_mv,
 					chip->resume_delta_mv,
-					VBATDET_MAX_ERR_MV, vbat_low_count);
+					chip->vbatdet_max_err_mv,
+					vbat_low_count);
 			if (vbat_low_count >= CONSECUTIVE_COUNT) {
 				pr_debug("woke up too early stopping\n");
 				qpnp_chg_enable_irq(&chip->chg_vbatdet_lo);
@@ -3230,7 +3620,7 @@
 			state == ADC_TM_WARM_STATE ? "warm" : "cool");
 
 	if (state == ADC_TM_WARM_STATE) {
-		if (temp > chip->warm_bat_decidegc) {
+		if (temp >= chip->warm_bat_decidegc) {
 			/* Normal to warm */
 			bat_warm = true;
 			bat_cool = false;
@@ -3238,7 +3628,7 @@
 				chip->warm_bat_decidegc - HYSTERISIS_DECIDEGC;
 			chip->adc_param.state_request =
 				ADC_TM_COOL_THR_ENABLE;
-		} else if (temp >
+		} else if (temp >=
 				chip->cool_bat_decidegc + HYSTERISIS_DECIDEGC){
 			/* Cool to normal */
 			bat_warm = false;
@@ -3250,7 +3640,7 @@
 					ADC_TM_HIGH_LOW_THR_ENABLE;
 		}
 	} else {
-		if (temp < chip->cool_bat_decidegc) {
+		if (temp <= chip->cool_bat_decidegc) {
 			/* Normal to cool */
 			bat_warm = false;
 			bat_cool = true;
@@ -3258,7 +3648,7 @@
 				chip->cool_bat_decidegc + HYSTERISIS_DECIDEGC;
 			chip->adc_param.state_request =
 				ADC_TM_WARM_THR_ENABLE;
-		} else if (temp <
+		} else if (temp <=
 				chip->warm_bat_decidegc - HYSTERISIS_DECIDEGC){
 			/* Warm to normal */
 			bat_warm = false;
@@ -3275,9 +3665,6 @@
 		chip->bat_is_cool = bat_cool;
 		chip->bat_is_warm = bat_warm;
 
-		if (bat_cool || bat_warm)
-			chip->resuming_charging = false;
-
 		/**
 		 * set appropriate voltages and currents.
 		 *
@@ -3285,9 +3672,25 @@
 		 * driver will not resume with SoC. Only vbatdet is used to
 		 * determine resume of charging.
 		 */
-		qpnp_chg_set_appropriate_vddmax(chip);
-		qpnp_chg_set_appropriate_battery_current(chip);
-		qpnp_chg_set_appropriate_vbatdet(chip);
+		if (bat_cool || bat_warm) {
+			chip->resuming_charging = false;
+			qpnp_chg_set_appropriate_vbatdet(chip);
+
+			/* To avoid ARB, only vbatdet is configured in
+			 * warm/cold zones. Once vbat < vbatdet the
+			 * appropriate vddmax/ibatmax adjustments will
+			 * be made in the fast charge interrupt. */
+			bypass_vbatdet_comp(chip, 1);
+			qpnp_chg_charge_en(chip, !chip->charging_disabled);
+			qpnp_chg_charge_en(chip, chip->charging_disabled);
+			qpnp_chg_charge_en(chip, !chip->charging_disabled);
+		} else {
+			bypass_vbatdet_comp(chip, 0);
+			/* restore normal parameters */
+			qpnp_chg_set_appropriate_vbatdet(chip);
+			qpnp_chg_set_appropriate_vddmax(chip);
+			qpnp_chg_set_appropriate_battery_current(chip);
+		}
 	}
 
 	pr_debug("warm %d, cool %d, low = %d deciDegC, high = %d deciDegC\n",
@@ -3641,13 +4044,19 @@
 		qpnp_batt_system_temp_level_set(chip, val->intval);
 		break;
 	case POWER_SUPPLY_PROP_INPUT_CURRENT_MAX:
-		qpnp_chg_iusbmax_set(chip, val->intval / 1000);
+		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);
@@ -3769,7 +4178,8 @@
 
 			rc |= devm_request_irq(chip->dev, chip->chg_fastchg.irq,
 					qpnp_chg_chgr_chg_fastchg_irq_handler,
-					IRQF_TRIGGER_RISING,
+					IRQF_TRIGGER_RISING |
+					IRQF_TRIGGER_FALLING,
 					"fast-chg-on", chip);
 			if (rc < 0) {
 				pr_err("Can't request %d fast-chg-on: %d\n",
@@ -3798,10 +4208,10 @@
 				return rc;
 			}
 
-			enable_irq_wake(chip->chg_trklchg.irq);
-			enable_irq_wake(chip->chg_failed.irq);
+			qpnp_chg_irq_wake_enable(&chip->chg_trklchg);
+			qpnp_chg_irq_wake_enable(&chip->chg_failed);
 			qpnp_chg_disable_irq(&chip->chg_vbatdet_lo);
-			enable_irq_wake(chip->chg_vbatdet_lo.irq);
+			qpnp_chg_irq_wake_enable(&chip->chg_vbatdet_lo);
 
 			break;
 		case SMBB_BAT_IF_SUBTYPE:
@@ -3824,7 +4234,7 @@
 				return rc;
 			}
 
-			enable_irq_wake(chip->batt_pres.irq);
+			qpnp_chg_irq_wake_enable(&chip->batt_pres);
 
 			chip->batt_temp_ok.irq = spmi_get_irq_byname(spmi,
 						spmi_resource, "bat-temp-ok");
@@ -3841,8 +4251,9 @@
 						chip->batt_temp_ok.irq, rc);
 				return rc;
 			}
+			qpnp_chg_bat_if_batt_temp_irq_handler(0, chip);
 
-			enable_irq_wake(chip->batt_temp_ok.irq);
+			qpnp_chg_irq_wake_enable(&chip->batt_temp_ok);
 
 			break;
 		case SMBB_BUCK_SUBTYPE:
@@ -3924,11 +4335,11 @@
 					return rc;
 				}
 
-				enable_irq_wake(chip->usb_ocp.irq);
+				qpnp_chg_irq_wake_enable(&chip->usb_ocp);
 			}
 
-			enable_irq_wake(chip->usbin_valid.irq);
-			enable_irq_wake(chip->chg_gone.irq);
+			qpnp_chg_irq_wake_enable(&chip->usbin_valid);
+			qpnp_chg_irq_wake_enable(&chip->chg_gone);
 			break;
 		case SMBB_DC_CHGPTH_SUBTYPE:
 			chip->dcin_valid.irq = spmi_get_irq_byname(spmi,
@@ -3947,7 +4358,7 @@
 				return rc;
 			}
 
-			enable_irq_wake(chip->dcin_valid.irq);
+			qpnp_chg_irq_wake_enable(&chip->dcin_valid);
 			break;
 		}
 	}
@@ -4334,6 +4745,7 @@
 	OF_PROP_READ(chip, cold_batt_p, "batt-cold-percentage", rc, 1);
 	OF_PROP_READ(chip, soc_resume_limit, "resume-soc", rc, 1);
 	OF_PROP_READ(chip, batt_weak_voltage_mv, "vbatweak-mv", rc, 1);
+	OF_PROP_READ(chip, vbatdet_max_err_mv, "vbatdet-maxerr-mv", rc, 1);
 
 	if (rc)
 		return rc;
@@ -4352,6 +4764,9 @@
 		}
 	}
 
+	if (!chip->vbatdet_max_err_mv)
+		chip->vbatdet_max_err_mv = VBATDET_MAX_ERR_MV;
+
 	/* Look up JEITA compliance parameters if cool and warm temp provided */
 	if (chip->cool_bat_decidegc || chip->warm_bat_decidegc) {
 		chip->adc_tm_dev = qpnp_get_adc_tm(chip->dev, "chg");
@@ -4410,6 +4825,9 @@
 	chip->ibat_calibration_enabled =
 			of_property_read_bool(chip->spmi->dev.of_node,
 					"qcom,ibat-calibration-enabled");
+	chip->parallel_ovp_mode =
+			of_property_read_bool(chip->spmi->dev.of_node,
+					"qcom,parallel-ovp-mode");
 
 	of_get_property(chip->spmi->dev.of_node, "qcom,thermal-mitigation",
 		&(chip->thermal_levels));
@@ -4472,6 +4890,8 @@
 	INIT_WORK(&chip->reduce_power_stage_work,
 			qpnp_chg_reduce_power_stage_work);
 	mutex_init(&chip->batfet_vreg_lock);
+	INIT_WORK(&chip->ocp_clear_work,
+			qpnp_chg_ocp_clear_work);
 	INIT_WORK(&chip->batfet_lcl_work,
 			qpnp_chg_batfet_lcl_work);
 	INIT_WORK(&chip->insertion_ocv_work,
@@ -4767,6 +5187,14 @@
 	qpnp_chg_force_run_on_batt(chip, chip->charging_disabled);
 	qpnp_chg_set_appropriate_vddmax(chip);
 
+	if (chip->parallel_ovp_mode) {
+		rc = override_dcin_ilimit(chip, 1);
+		if (rc) {
+			pr_err("Override DCIN LLIMIT %d\n", rc);
+			goto unregister_dc_psy;
+		}
+	}
+
 	rc = qpnp_chg_request_irqs(chip);
 	if (rc) {
 		pr_err("failed to request interrupts %d\n", rc);
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 fe5af3a..f721a25 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -102,6 +102,17 @@
 	  This driver supports the voltage regulators of DA9052-BC and
 	  DA9053-AA/Bx PMIC.
 
+config REGULATOR_FAN53555
+	tristate "Fairchild FAN53555 Regulator"
+	depends on I2C
+	select REGMAP_I2C
+	help
+	  This driver supports Fairchild FAN53555 Digitally Programmable
+	  TinyBuck Regulator. The FAN53555 is a step-down switching voltage
+	  regulator that delivers a digitally programmable output from an
+	  input voltage supply of 2.5V to 5.5V. The output voltage is
+	  programmed through an I2C interface.
+
 config REGULATOR_ANATOP
 	tristate "Freescale i.MX on-chip ANATOP LDO regulators"
 	depends on MFD_ANATOP
@@ -129,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 eb07c97..1393f23 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -20,6 +20,7 @@
 obj-$(CONFIG_REGULATOR_DA9052)	+= da9052-regulator.o
 obj-$(CONFIG_REGULATOR_DBX500_PRCMU) += dbx500-prcmu.o
 obj-$(CONFIG_REGULATOR_DB8500_PRCMU) += db8500-prcmu.o
+obj-$(CONFIG_REGULATOR_FAN53555) += fan53555.o
 obj-$(CONFIG_REGULATOR_ISL6271A) += isl6271a-regulator.o
 obj-$(CONFIG_REGULATOR_LP3971) += lp3971.o
 obj-$(CONFIG_REGULATOR_LP3972) += lp3972.o
@@ -33,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/core.c b/drivers/regulator/core.c
index 450c4fb..047bbc4 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -1989,8 +1989,8 @@
 int regulator_set_voltage(struct regulator *regulator, int min_uV, int max_uV)
 {
 	struct regulator_dev *rdev = regulator->rdev;
-	int prev_min_uV, prev_max_uV;
 	int ret = 0;
+	int old_min_uV, old_max_uV;
 
 	mutex_lock(&rdev->mutex);
 
@@ -2013,24 +2013,28 @@
 	if (ret < 0)
 		goto out;
 
-	prev_min_uV = regulator->min_uV;
-	prev_max_uV = regulator->max_uV;
-
+	/* restore original values in case of error */
+	old_min_uV = regulator->min_uV;
+	old_max_uV = regulator->max_uV;
 	regulator->min_uV = min_uV;
 	regulator->max_uV = max_uV;
 
 	ret = regulator_check_consumers(rdev, &min_uV, &max_uV);
-	if (ret < 0) {
-		regulator->min_uV = prev_min_uV;
-		regulator->max_uV = prev_max_uV;
-		goto out;
-	}
+	if (ret < 0)
+		goto out2;
 
 	ret = _regulator_do_set_voltage(rdev, min_uV, max_uV);
+	if (ret < 0)
+		goto out2;
 
 out:
 	mutex_unlock(&rdev->mutex);
 	return ret;
+out2:
+	regulator->min_uV = old_min_uV;
+	regulator->max_uV = old_max_uV;
+	mutex_unlock(&rdev->mutex);
+	return ret;
 }
 EXPORT_SYMBOL_GPL(regulator_set_voltage);
 
diff --git a/drivers/regulator/fan53555.c b/drivers/regulator/fan53555.c
new file mode 100644
index 0000000..6986a52
--- /dev/null
+++ b/drivers/regulator/fan53555.c
@@ -0,0 +1,658 @@
+/*
+ * FAN53555 Fairchild Digitally Programmable TinyBuck Regulator Driver.
+ *
+ * Supported Part Numbers:
+ * FAN53555UC00X/01X/03X/04X/05X
+ *
+ * Copyright (c) 2012 Marvell Technology Ltd.
+ * Yunfan Zhang <yfzhang@marvell.com>
+ *
+ * This package is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+#include <linux/module.h>
+#include <linux/param.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/of_regulator.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/regmap.h>
+#include <linux/regulator/fan53555.h>
+
+/* Voltage setting */
+#define FAN53555_VSEL0		0x00
+#define FAN53555_VSEL1		0x01
+/* Control register */
+#define FAN53555_CONTROL	0x02
+/* IC Type */
+#define FAN53555_ID1		0x03
+/* IC mask version */
+#define FAN53555_ID2		0x04
+/* Monitor register */
+#define FAN53555_MONITOR	0x05
+
+/* VSEL bit definitions */
+#define VSEL_BUCK_EN	(1 << 7)
+#define VSEL_MODE		(1 << 6)
+#define VSEL_NSEL_MASK	0x3F
+#define VSEL_FULL_MASK	0xFF
+/* Chip ID and Verison */
+#define DIE_ID		0x0F	/* ID1 */
+#define DIE_REV		0x0F	/* ID2 */
+#define DIE_13_REV	0x0F	/* DIE Revsion ID of 13 option */
+
+/* Control bit definitions */
+#define CTL_OUTPUT_DISCHG	(1 << 7)
+#define CTL_SLEW_MASK		(0x7 << 4)
+#define CTL_SLEW_SHIFT		4
+#define CTL_RESET			(1 << 2)
+
+#define FAN53555_NVOLTAGES	64	/* Numbers of voltages */
+
+/* IC Type */
+enum {
+	FAN53555_CHIP_ID_00 = 0,
+	FAN53555_CHIP_ID_01,
+	FAN53555_CHIP_ID_02,
+	FAN53555_CHIP_ID_03,
+	FAN53555_CHIP_ID_04,
+	FAN53555_CHIP_ID_05,
+};
+
+static const int slew_rate_plan[] = {
+	64000,
+	32000,
+	16000,
+	8000,
+	4000,
+	2000,
+	1000,
+	500
+};
+
+struct fan53555_device_info {
+	struct regmap *regmap;
+	struct device *dev;
+	struct regulator_desc desc;
+	struct regulator_dev *rdev;
+	struct regulator_init_data *regulator;
+	/* IC Type and Rev */
+	int chip_id;
+	int chip_rev;
+	/* Voltage setting register */
+	unsigned int vol_reg;
+	unsigned int sleep_reg;
+	/* Voltage range and step(linear) */
+	unsigned int vsel_min;
+	unsigned int vsel_step;
+	/* Voltage slew rate limiting */
+	unsigned int slew_rate;
+	/* Sleep voltage cache */
+	unsigned int sleep_vol_cache;
+
+	bool disable_suspend;
+};
+
+static int fan53555_get_voltage(struct regulator_dev *rdev)
+{
+	struct fan53555_device_info *di = rdev_get_drvdata(rdev);
+	unsigned int val;
+	int rc;
+
+	rc = regmap_read(di->regmap, di->vol_reg, &val);
+	if (rc) {
+		dev_err(di->dev, "Unable to get voltage rc(%d)", rc);
+		return rc;
+	}
+
+	return ((val & VSEL_NSEL_MASK) * di->vsel_step) +
+		di->vsel_min;
+}
+
+static int fan53555_set_voltage(struct regulator_dev *rdev,
+			int min_uv, int max_uv, unsigned *selector)
+{
+	struct fan53555_device_info *di = rdev_get_drvdata(rdev);
+	int rc, set_val, cur_uv, new_uv;
+
+	set_val = DIV_ROUND_UP(min_uv - di->vsel_min, di->vsel_step);
+	new_uv = (set_val * di->vsel_step) + di->vsel_min;
+
+	if (new_uv > max_uv || max_uv < di->vsel_min) {
+		dev_err(di->dev, "Unable to set voltage (%d %d)\n",
+			min_uv, max_uv);
+	}
+
+	cur_uv = fan53555_get_voltage(rdev);
+	if (cur_uv < 0)
+		return cur_uv;
+
+	rc = regmap_update_bits(di->regmap, di->vol_reg, VSEL_NSEL_MASK,
+				set_val);
+	if (rc) {
+		dev_err(di->dev, "Unable to set voltage (%d %d)\n",
+			min_uv, max_uv);
+	} else {
+		udelay(DIV_ROUND_UP(abs(new_uv - cur_uv),
+			slew_rate_plan[di->slew_rate]));
+		*selector = set_val;
+	}
+
+	return rc;
+}
+
+static int fan53555_list_voltage(struct regulator_dev *rdev,
+						unsigned selector)
+{
+	struct fan53555_device_info *di = rdev_get_drvdata(rdev);
+
+	if (selector >= di->desc.n_voltages)
+		return 0;
+
+	return selector * di->vsel_step + di->vsel_min;
+}
+
+static int fan53555_set_suspend_voltage(struct regulator_dev *rdev, int uV)
+{
+	struct fan53555_device_info *di = rdev_get_drvdata(rdev);
+	int ret, val;
+
+	if (di->sleep_vol_cache == uV)
+		return 0;
+	ret = fan53555_set_voltage(rdev, uV, uV, &val);
+	if (ret < 0)
+		return -EINVAL;
+	ret = regmap_update_bits(di->regmap, di->sleep_reg,
+					VSEL_NSEL_MASK, val);
+	if (ret < 0)
+		return -EINVAL;
+	/* Cache the sleep voltage setting.
+	 * Might not be the real voltage which is rounded */
+	di->sleep_vol_cache = uV;
+
+	return 0;
+}
+
+static int fan53555_enable(struct regulator_dev *rdev)
+{
+	struct fan53555_device_info *di = rdev_get_drvdata(rdev);
+	int ret;
+
+	ret = regmap_update_bits(di->regmap, di->vol_reg,
+					VSEL_BUCK_EN, VSEL_BUCK_EN);
+	if (ret)
+		dev_err(di->dev, "Unable to enable regulator, ret = %d\n",
+			ret);
+	return ret;
+}
+
+static int fan53555_disable(struct regulator_dev *rdev)
+{
+	struct fan53555_device_info *di = rdev_get_drvdata(rdev);
+	int ret;
+
+	ret = regmap_update_bits(di->regmap, di->vol_reg,
+					VSEL_BUCK_EN, 0);
+	if (ret)
+		dev_err(di->dev, "Unable to set disable regulator, ret = %d\n",
+			ret);
+	return ret;
+}
+
+static int fan53555_is_enabled(struct regulator_dev *rdev)
+{
+	struct fan53555_device_info *di = rdev_get_drvdata(rdev);
+	int ret;
+	u32 val;
+
+	ret = regmap_read(di->regmap, di->vol_reg, &val);
+	if (ret) {
+		dev_err(di->dev, "Unable to get regulator status, ret = %d\n",
+			ret);
+		return ret;
+	} else {
+		return val & VSEL_BUCK_EN;
+	}
+}
+
+static int fan53555_set_mode(struct regulator_dev *rdev, unsigned int mode)
+{
+	struct fan53555_device_info *di = rdev_get_drvdata(rdev);
+
+	switch (mode) {
+	case REGULATOR_MODE_FAST:
+		regmap_update_bits(di->regmap, di->vol_reg,
+				VSEL_MODE, VSEL_MODE);
+		break;
+	case REGULATOR_MODE_NORMAL:
+		regmap_update_bits(di->regmap, di->vol_reg, VSEL_MODE, 0);
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static unsigned int fan53555_get_mode(struct regulator_dev *rdev)
+{
+	struct fan53555_device_info *di = rdev_get_drvdata(rdev);
+	unsigned int val;
+	int ret = 0;
+
+	ret = regmap_read(di->regmap, di->vol_reg, &val);
+	if (ret < 0)
+		return ret;
+	if (val & VSEL_MODE)
+		return REGULATOR_MODE_FAST;
+	else
+		return REGULATOR_MODE_NORMAL;
+}
+
+static struct regulator_ops fan53555_regulator_ops = {
+	.set_voltage = fan53555_set_voltage,
+	.get_voltage = fan53555_get_voltage,
+	.list_voltage = fan53555_list_voltage,
+	.set_suspend_voltage = fan53555_set_suspend_voltage,
+	.enable = fan53555_enable,
+	.disable = fan53555_disable,
+	.is_enabled = fan53555_is_enabled,
+	.set_mode = fan53555_set_mode,
+	.get_mode = fan53555_get_mode,
+};
+
+static struct regulator_ops fan53555_regulator_disable_suspend_ops = {
+	.set_voltage = fan53555_set_voltage,
+	.get_voltage = fan53555_get_voltage,
+	.list_voltage = fan53555_list_voltage,
+	.enable = fan53555_enable,
+	.disable = fan53555_disable,
+	.is_enabled = fan53555_is_enabled,
+	.set_mode = fan53555_set_mode,
+	.get_mode = fan53555_get_mode,
+};
+
+/* For 00,01,03,05 options:
+ * VOUT = 0.60V + NSELx * 10mV, from 0.60 to 1.23V.
+ * For 04 option:
+ * VOUT = 0.603V + NSELx * 12.826mV, from 0.603 to 1.411V.
+ * For 13 option:
+ * 13 option, its DIE ID is 0x00 and DIE_REV is 0x0F.
+ * VOUT = 0.80V + NSELx * 10mV, from 0.80 to 1.43V.
+ * */
+static int fan53555_device_setup(struct fan53555_device_info *di,
+				struct fan53555_platform_data *pdata)
+{
+	unsigned int reg, data, mask;
+
+	/* Setup voltage control register */
+	switch (pdata->sleep_vsel_id) {
+	case FAN53555_VSEL_ID_0:
+		di->sleep_reg = FAN53555_VSEL0;
+		di->vol_reg = FAN53555_VSEL1;
+		break;
+	case FAN53555_VSEL_ID_1:
+		di->sleep_reg = FAN53555_VSEL1;
+		di->vol_reg = FAN53555_VSEL0;
+		break;
+	default:
+		dev_err(di->dev, "Invalid VSEL ID!\n");
+		return -EINVAL;
+	}
+	/* Init voltage range and step */
+	switch (di->chip_id) {
+	case FAN53555_CHIP_ID_00:
+		if (di->chip_rev == DIE_13_REV) {
+			di->vsel_min = 800000;
+			di->vsel_step = 10000;
+			break;
+		}
+	case FAN53555_CHIP_ID_01:
+	case FAN53555_CHIP_ID_03:
+	case FAN53555_CHIP_ID_05:
+		di->vsel_min = 600000;
+		di->vsel_step = 10000;
+		break;
+	case FAN53555_CHIP_ID_04:
+		di->vsel_min = 603000;
+		di->vsel_step = 12826;
+		break;
+	default:
+		dev_err(di->dev,
+			"Chip ID[%d]\n not supported!\n", di->chip_id);
+		return -EINVAL;
+	}
+	/* Init slew rate */
+	if (pdata->slew_rate & 0x7)
+		di->slew_rate = pdata->slew_rate;
+	else
+		di->slew_rate = FAN53555_SLEW_RATE_64MV;
+	reg = FAN53555_CONTROL;
+	data = di->slew_rate << CTL_SLEW_SHIFT;
+	mask = CTL_SLEW_MASK;
+	return regmap_update_bits(di->regmap, reg, mask, data);
+}
+
+static int fan53555_regulator_register(struct fan53555_device_info *di,
+					struct i2c_client *client)
+{
+	struct regulator_desc *rdesc = &di->desc;
+
+	rdesc->name = "fan53555-reg";
+	if (di->disable_suspend)
+		rdesc->ops = &fan53555_regulator_disable_suspend_ops;
+	else
+		rdesc->ops = &fan53555_regulator_ops;
+	rdesc->type = REGULATOR_VOLTAGE;
+	rdesc->n_voltages = FAN53555_NVOLTAGES;
+	rdesc->owner = THIS_MODULE;
+
+	di->rdev = regulator_register(&di->desc, di->dev,
+			di->regulator, di, client->dev.of_node);
+	return PTR_RET(di->rdev);
+
+}
+
+static struct regmap_config fan53555_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+};
+
+static int fan53555_parse_backup_reg(struct i2c_client *client, u32 *sleep_sel)
+{
+	int rc = -EINVAL;
+
+	rc = of_property_read_u32(client->dev.of_node, "fairchild,backup-vsel",
+				sleep_sel);
+	if (rc) {
+		dev_err(&client->dev, "fairchild,backup-vsel property missing\n");
+	} else {
+		switch (*sleep_sel) {
+		case FAN53555_VSEL_ID_0:
+		case FAN53555_VSEL_ID_1:
+			break;
+		default:
+			dev_err(&client->dev, "Invalid VSEL ID!\n");
+			rc = -EINVAL;
+		}
+	}
+
+	return rc;
+}
+
+static u32 fan53555_get_slew_rate_reg_value(struct i2c_client *client,
+					u32 slew_rate)
+{
+	u32 index;
+
+	for (index = 0; index < ARRAY_SIZE(slew_rate_plan); index++)
+		if (slew_rate == slew_rate_plan[index])
+			break;
+
+	if (index == ARRAY_SIZE(slew_rate_plan)) {
+		dev_err(&client->dev, "invalid slew rate.\n");
+		index = FAN53555_SLEW_RATE_8MV;
+	}
+
+	return index;
+}
+
+static struct fan53555_platform_data *
+	fan53555_get_of_platform_data(struct i2c_client *client)
+{
+	struct fan53555_platform_data *pdata = NULL;
+	struct regulator_init_data *init_data;
+	u32 sleep_sel, slew_rate;
+	int rc;
+
+	init_data = of_get_regulator_init_data(&client->dev,
+			client->dev.of_node);
+	if (!init_data) {
+		dev_err(&client->dev, "regulator init data is missing\n");
+		return pdata;
+	}
+
+	rc = of_property_read_u32(client->dev.of_node, "regulator-ramp-delay",
+					&slew_rate);
+	if (rc)
+		slew_rate = slew_rate_plan[FAN53555_SLEW_RATE_8MV];
+
+	if (fan53555_parse_backup_reg(client, &sleep_sel))
+		return pdata;
+
+	pdata = devm_kzalloc(&client->dev,
+			sizeof(struct fan53555_platform_data), GFP_KERNEL);
+	if (!pdata) {
+		dev_err(&client->dev,
+			"fan53555_platform_data allocation failed.\n");
+		return pdata;
+	}
+
+	init_data->constraints.input_uV = init_data->constraints.max_uV;
+	init_data->constraints.valid_ops_mask |=
+		REGULATOR_CHANGE_STATUS	| REGULATOR_CHANGE_VOLTAGE |
+		REGULATOR_CHANGE_MODE;
+	init_data->constraints.valid_modes_mask =
+				REGULATOR_MODE_NORMAL |
+				REGULATOR_MODE_FAST;
+	init_data->constraints.initial_mode = REGULATOR_MODE_NORMAL;
+
+	pdata->regulator = init_data;
+	pdata->slew_rate = fan53555_get_slew_rate_reg_value(client,
+							slew_rate);
+	pdata->sleep_vsel_id = sleep_sel;
+
+	return pdata;
+}
+
+static int fan53555_restore_working_reg(struct device_node *node,
+			struct fan53555_device_info *di)
+{
+	int ret;
+	u32 val;
+
+	/* Restore register from back up register */
+	ret = regmap_read(di->regmap, di->sleep_reg, &val);
+	if (ret < 0) {
+		dev_err(di->dev,
+			"Failed to get backup data from reg %d, ret = %d\n",
+			di->sleep_reg, ret);
+		return ret;
+	}
+
+	ret = regmap_update_bits(di->regmap,
+		di->vol_reg, VSEL_FULL_MASK, val);
+	if (ret < 0) {
+		dev_err(di->dev,
+			"Failed to update working reg %d, ret = %d\n",
+			di->vol_reg, ret);
+		return ret;
+	}
+
+	return ret;
+}
+
+static int fan53555_of_init(struct device_node *node,
+			struct fan53555_device_info *di)
+{
+	int ret, gpio;
+	enum of_gpio_flags flags;
+
+	if (of_property_read_bool(node, "fairchild,restore-reg")) {
+		ret = fan53555_restore_working_reg(node, di);
+		if (ret)
+			return ret;
+	}
+
+	if (of_find_property(node, "fairchild,vsel-gpio", NULL)) {
+		gpio = of_get_named_gpio_flags(node, "fairchild,vsel-gpio", 0,
+						&flags);
+
+		if (!gpio_is_valid(gpio)) {
+			if (gpio != -EPROBE_DEFER)
+				dev_err(di->dev, "Could not get vsel, ret = %d\n",
+					gpio);
+			return gpio;
+		}
+
+		ret = devm_gpio_request(di->dev, gpio, "fan53555_vsel");
+		if (ret) {
+			dev_err(di->dev, "Failed to obtain gpio %d ret = %d\n",
+				gpio, ret);
+			return ret;
+		}
+
+		ret = gpio_direction_output(gpio, flags & OF_GPIO_ACTIVE_LOW ?
+							0 : 1);
+		if (ret) {
+			dev_err(di->dev,
+				"Failed to set GPIO %d to: %s, ret = %d",
+				gpio, flags & OF_GPIO_ACTIVE_LOW ?
+				"GPIO_LOW" : "GPIO_HIGH", ret);
+			return ret;
+		}
+	}
+
+	di->disable_suspend = of_property_read_bool(node,
+				"fairchild,disable-suspend");
+
+	return 0;
+}
+
+static int __devinit fan53555_regulator_probe(struct i2c_client *client,
+				const struct i2c_device_id *id)
+{
+	struct fan53555_device_info *di;
+	struct fan53555_platform_data *pdata;
+	unsigned int val;
+	int ret;
+
+	if (client->dev.of_node)
+		pdata = fan53555_get_of_platform_data(client);
+	else
+		pdata = client->dev.platform_data;
+
+	if (!pdata || !pdata->regulator) {
+		dev_err(&client->dev, "Platform data not found!\n");
+		return -ENODEV;
+	}
+
+	di = devm_kzalloc(&client->dev, sizeof(struct fan53555_device_info),
+					GFP_KERNEL);
+	if (!di) {
+		dev_err(&client->dev, "Failed to allocate device info data!\n");
+		return -ENOMEM;
+	}
+	di->regmap = devm_regmap_init_i2c(client, &fan53555_regmap_config);
+	if (IS_ERR(di->regmap)) {
+		dev_err(&client->dev, "Failed to allocate regmap!\n");
+		return PTR_ERR(di->regmap);
+	}
+	di->dev = &client->dev;
+	di->regulator = pdata->regulator;
+	i2c_set_clientdata(client, di);
+	/* Get chip ID */
+	ret = regmap_read(di->regmap, FAN53555_ID1, &val);
+	if (ret < 0) {
+		dev_err(&client->dev, "Failed to get chip ID!\n");
+		return -ENODEV;
+	}
+	di->chip_id = val & DIE_ID;
+	/* Get chip revision */
+	ret = regmap_read(di->regmap, FAN53555_ID2, &val);
+	if (ret < 0) {
+		dev_err(&client->dev, "Failed to get chip Rev!\n");
+		return -ENODEV;
+	}
+	di->chip_rev = val & DIE_REV;
+	dev_info(&client->dev, "FAN53555 Option[%d] Rev[%d] Detected!\n",
+				di->chip_id, di->chip_rev);
+	/* Device init */
+	ret = fan53555_device_setup(di, pdata);
+	if (ret < 0) {
+		dev_err(&client->dev, "Failed to setup device!\n");
+		return ret;
+	}
+
+	/* Set up from device tree */
+	if (client->dev.of_node) {
+		ret = fan53555_of_init(client->dev.of_node, di);
+		if (ret)
+			return ret;
+	}
+
+	ret = fan53555_regulator_register(di, client);
+	if (ret < 0)
+		dev_err(&client->dev, "Failed to register regulator!\n");
+
+	return ret;
+
+}
+
+static int __devexit fan53555_regulator_remove(struct i2c_client *client)
+{
+	struct fan53555_device_info *di = i2c_get_clientdata(client);
+
+	regulator_unregister(di->rdev);
+	return 0;
+}
+
+static struct of_device_id fan53555_match_table[] = {
+	{ .compatible = "fairchild,fan53555-regulator",},
+	{},
+};
+MODULE_DEVICE_TABLE(of, fan53555_match_table);
+
+static const struct i2c_device_id fan53555_id[] = {
+	{"fan53555", -1},
+	{ },
+};
+
+static struct i2c_driver fan53555_regulator_driver = {
+	.driver = {
+		.name = "fan53555-regulator",
+		.owner = THIS_MODULE,
+		.of_match_table = fan53555_match_table,
+	},
+	.probe = fan53555_regulator_probe,
+	.remove = __devexit_p(fan53555_regulator_remove),
+	.id_table = fan53555_id,
+};
+
+/**
+ * fan53555_regulator_init() - initialized fan53555 regulator driver
+ * This function registers the fan53555 regulator platform driver.
+ *
+ * Returns 0 on success or errno on failure.
+ */
+int __init fan53555_regulator_init(void)
+{
+	static bool initialized;
+
+	if (initialized)
+		return 0;
+	else
+		initialized = true;
+
+	return i2c_add_driver(&fan53555_regulator_driver);
+}
+EXPORT_SYMBOL(fan53555_regulator_init);
+module_init(fan53555_regulator_init);
+
+static void __exit fan53555_regulator_exit(void)
+{
+	i2c_del_driver(&fan53555_regulator_driver);
+}
+module_exit(fan53555_regulator_exit);
+
+MODULE_AUTHOR("Yunfan Zhang <yfzhang@marvell.com>");
+MODULE_DESCRIPTION("FAN53555 regulator driver");
+MODULE_LICENSE("GPL v2");
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/regulator/onsemi-ncp6335d.c b/drivers/regulator/onsemi-ncp6335d.c
index 329ac46..3d4dd04 100644
--- a/drivers/regulator/onsemi-ncp6335d.c
+++ b/drivers/regulator/onsemi-ncp6335d.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, 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
@@ -12,12 +12,20 @@
 
 #include <linux/module.h>
 #include <linux/err.h>
+#include <linux/gpio.h>
 #include <linux/kernel.h>
 #include <linux/delay.h>
 #include <linux/i2c.h>
+#include <linux/log2.h>
 #include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/of_regulator.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
 #include <linux/regmap.h>
 #include <linux/regulator/onsemi-ncp6335d.h>
+#include <linux/string.h>
+#include <mach/gpiomux.h>
 
 /* registers */
 #define REG_NCP6335D_PID		0x03
@@ -30,6 +38,7 @@
 /* constraints */
 #define NCP6335D_MIN_VOLTAGE_UV		600000
 #define NCP6335D_STEP_VOLTAGE_UV	6250
+#define NCP6335D_VOLTAGE_STEPS		128
 #define NCP6335D_MIN_SLEW_NS		166
 #define NCP6335D_MAX_SLEW_NS		1333
 
@@ -51,9 +60,15 @@
 	struct regmap *regmap;
 	struct device *dev;
 	unsigned int vsel_reg;
+	unsigned int vsel_backup_reg;
 	unsigned int mode_bit;
 	int curr_voltage;
 	int slew_rate;
+
+	unsigned int step_size;
+	unsigned int min_voltage;
+	unsigned int min_slew_ns;
+	unsigned int max_slew_ns;
 };
 
 static void dump_registers(struct ncp6335d_info *dd,
@@ -71,8 +86,8 @@
 	u8 val;
 	int delay;
 
-	val = abs(prev_uV - new_uV) / NCP6335D_STEP_VOLTAGE_UV;
-	delay =  (val * dd->slew_rate / 1000) + 1;
+	val = abs(prev_uV - new_uV) / dd->step_size;
+	delay = ((val * dd->slew_rate) / 1000) + 1;
 
 	dev_dbg(dd->dev, "Slew Delay = %d\n", delay);
 
@@ -120,8 +135,8 @@
 		dev_err(dd->dev, "Unable to get volatge rc(%d)", rc);
 		return rc;
 	}
-	dd->curr_voltage = ((val & NCP6335D_VOUT_SEL_MASK) *
-			NCP6335D_STEP_VOLTAGE_UV) + NCP6335D_MIN_VOLTAGE_UV;
+	dd->curr_voltage = ((val & NCP6335D_VOUT_SEL_MASK) * dd->step_size) +
+				dd->min_voltage;
 
 	dump_registers(dd, dd->vsel_reg, __func__);
 
@@ -134,10 +149,8 @@
 	int rc, set_val, new_uV;
 	struct ncp6335d_info *dd = rdev_get_drvdata(rdev);
 
-	set_val = DIV_ROUND_UP(min_uV - NCP6335D_MIN_VOLTAGE_UV,
-					NCP6335D_STEP_VOLTAGE_UV);
-	new_uV = (set_val * NCP6335D_STEP_VOLTAGE_UV) +
-					NCP6335D_MIN_VOLTAGE_UV;
+	set_val = DIV_ROUND_UP(min_uV - dd->min_voltage, dd->step_size);
+	new_uV = (set_val * dd->step_size) + dd->min_voltage;
 	if (new_uV > max_uV) {
 		dev_err(dd->dev, "Unable to set volatge (%d %d)\n",
 							min_uV, max_uV);
@@ -159,6 +172,17 @@
 	return rc;
 }
 
+static int ncp6335d_list_voltage(struct regulator_dev *rdev,
+					unsigned selector)
+{
+	struct ncp6335d_info *dd = rdev_get_drvdata(rdev);
+
+	if (selector >= NCP6335D_VOLTAGE_STEPS)
+		return 0;
+
+	return selector * dd->step_size + dd->min_voltage;
+}
+
 static int ncp6335d_set_mode(struct regulator_dev *rdev,
 					unsigned int mode)
 {
@@ -213,6 +237,7 @@
 static struct regulator_ops ncp6335d_ops = {
 	.set_voltage = ncp6335d_set_voltage,
 	.get_voltage = ncp6335d_get_voltage,
+	.list_voltage = ncp6335d_list_voltage,
 	.enable = ncp6335d_enable,
 	.disable = ncp6335d_disable,
 	.set_mode = ncp6335d_set_mode,
@@ -222,11 +247,98 @@
 static struct regulator_desc rdesc = {
 	.name = "ncp6335d",
 	.owner = THIS_MODULE,
-	.n_voltages = 128,
+	.n_voltages = NCP6335D_VOLTAGE_STEPS,
 	.ops = &ncp6335d_ops,
 };
 
-static int __devinit ncp6335d_init(struct ncp6335d_info *dd,
+static int ncp6335d_restore_working_reg(struct device_node *node,
+					struct ncp6335d_info *dd)
+{
+	int ret;
+	unsigned int val;
+
+	/* Restore register from back up register */
+	ret = regmap_read(dd->regmap, dd->vsel_backup_reg, &val);
+	if (ret < 0) {
+		dev_err(dd->dev, "Failed to get backup data from reg %d, ret = %d\n",
+			dd->vsel_backup_reg, ret);
+		return ret;
+	}
+
+	ret = regmap_update_bits(dd->regmap, dd->vsel_reg,
+					NCP6335D_VOUT_SEL_MASK, val);
+	if (ret < 0) {
+		dev_err(dd->dev, "Failed to update working reg %d, ret = %d\n",
+			dd->vsel_reg,  ret);
+		return ret;
+	}
+
+	return ret;
+}
+
+static int ncp6335d_parse_gpio(struct device_node *node,
+					struct ncp6335d_info *dd)
+{
+	int ret = 0, gpio;
+	enum of_gpio_flags flags;
+
+	if (!of_find_property(node, "onnn,vsel-gpio", NULL))
+		return ret;
+
+	/* Get GPIO connected to vsel and set its output */
+	gpio = of_get_named_gpio_flags(node,
+			"onnn,vsel-gpio", 0, &flags);
+	if (!gpio_is_valid(gpio)) {
+		if (gpio != -EPROBE_DEFER)
+			dev_err(dd->dev, "Could not get vsel, ret = %d\n",
+				gpio);
+		return gpio;
+	}
+
+	ret = devm_gpio_request(dd->dev, gpio, "ncp6335d_vsel");
+	if (ret) {
+		dev_err(dd->dev, "Failed to obtain gpio %d ret = %d\n",
+				gpio, ret);
+			return ret;
+	}
+
+	ret = gpio_direction_output(gpio, flags & OF_GPIO_ACTIVE_LOW ? 0 : 1);
+	if (ret) {
+		dev_err(dd->dev, "Failed to set GPIO %d to: %s, ret = %d",
+				gpio, flags & OF_GPIO_ACTIVE_LOW ?
+				"GPIO_LOW" : "GPIO_HIGH", ret);
+		return ret;
+	}
+
+	return ret;
+}
+
+static int ncp6335d_parse_tlmm(struct device_node *node,
+				struct ncp6335d_info *dd)
+{
+	int val, ret = 0;
+	u32 tmp[2];
+
+	if (!of_find_property(node, "onnn,tlmm-config", NULL))
+		return ret;
+
+	ret = of_property_read_u32_array(node, "onnn,tlmm-config", tmp, 2);
+	if (ret) {
+		dev_err(dd->dev, "onnn,tlmm-config is misconfigured, ret = %d",
+			ret);
+		return ret;
+	}
+
+	val = msm_tlmm_misc_reg_read(TLMM_SPARE_REG);
+	val &= ~tmp[0];
+	val |= tmp[1] & tmp[0];
+	msm_tlmm_misc_reg_write(TLMM_SPARE_REG, val);
+
+	return ret;
+}
+
+static int __devinit ncp6335d_init(struct i2c_client *client,
+			struct ncp6335d_info *dd,
 			const struct ncp6335d_platform_data *pdata)
 {
 	int rc;
@@ -235,10 +347,12 @@
 	switch (pdata->default_vsel) {
 	case NCP6335D_VSEL0:
 		dd->vsel_reg = REG_NCP6335D_PROGVSEL0;
+		dd->vsel_backup_reg = REG_NCP6335D_PROGVSEL1;
 		dd->mode_bit = NCP6335D_PWM_MODE0;
 	break;
 	case NCP6335D_VSEL1:
 		dd->vsel_reg = REG_NCP6335D_PROGVSEL1;
+		dd->vsel_backup_reg = REG_NCP6335D_PROGVSEL0;
 		dd->mode_bit = NCP6335D_PWM_MODE1;
 	break;
 	default:
@@ -246,6 +360,20 @@
 		return -EINVAL;
 	}
 
+	if (of_property_read_bool(client->dev.of_node, "onnn,restore-reg")) {
+		rc = ncp6335d_restore_working_reg(client->dev.of_node, dd);
+		if (rc)
+			return rc;
+	}
+
+	rc = ncp6335d_parse_gpio(client->dev.of_node, dd);
+	if (rc)
+		return rc;
+
+	rc = ncp6335d_parse_tlmm(client->dev.of_node, dd);
+	if (rc)
+		return rc;
+
 	/* get the current programmed voltage */
 	rc = regmap_read(dd->regmap, dd->vsel_reg, &val);
 	if (rc) {
@@ -253,7 +381,7 @@
 		return rc;
 	}
 	dd->curr_voltage = ((val & NCP6335D_VOUT_SEL_MASK) *
-			NCP6335D_STEP_VOLTAGE_UV) + NCP6335D_MIN_VOLTAGE_UV;
+				dd->step_size) + dd->min_voltage;
 
 	/* set discharge */
 	rc = regmap_update_bits(dd->regmap, REG_NCP6335D_PGOOD,
@@ -266,15 +394,15 @@
 	}
 
 	/* set slew rate */
-	if (pdata->slew_rate_ns < NCP6335D_MIN_SLEW_NS ||
-			pdata->slew_rate_ns > NCP6335D_MAX_SLEW_NS) {
+	if (pdata->slew_rate_ns < dd->min_slew_ns ||
+			pdata->slew_rate_ns > dd->max_slew_ns) {
 		dev_err(dd->dev, "Invalid slew rate %d\n", pdata->slew_rate_ns);
 		return -EINVAL;
 	}
-	val = DIV_ROUND_UP(pdata->slew_rate_ns - NCP6335D_MIN_SLEW_NS,
-						NCP6335D_MIN_SLEW_NS);
-	val >>= 1;
-	dd->slew_rate = val * NCP6335D_MIN_SLEW_NS;
+
+	dd->slew_rate = pdata->slew_rate_ns;
+	val = DIV_ROUND_UP(pdata->slew_rate_ns, dd->min_slew_ns);
+	val = ilog2(val);
 
 	rc = regmap_update_bits(dd->regmap, REG_NCP6335D_TIMING,
 			NCP6335D_SLEW_MASK, val << NCP6335D_SLEW_SHIFT);
@@ -301,6 +429,116 @@
 	.val_bits = 8,
 };
 
+static int ncp6335d_parse_dt(struct i2c_client *client,
+				struct ncp6335d_info *dd)
+{
+	int rc;
+
+	rc = of_property_read_u32(client->dev.of_node,
+			"onnn,step-size", &dd->step_size);
+	if (rc < 0) {
+		dev_err(&client->dev, "step size missing: rc = %d.\n", rc);
+		return rc;
+	}
+
+	rc = of_property_read_u32(client->dev.of_node,
+			"onnn,min-slew-ns", &dd->min_slew_ns);
+	if (rc < 0) {
+		dev_err(&client->dev, "min slew us missing: rc = %d.\n", rc);
+		return rc;
+	}
+
+	rc = of_property_read_u32(client->dev.of_node,
+			"onnn,max-slew-ns", &dd->max_slew_ns);
+	if (rc < 0) {
+		dev_err(&client->dev, "max slew us missing: rc = %d.\n", rc);
+		return rc;
+	}
+
+	rc = of_property_read_u32(client->dev.of_node,
+			"onnn,min-setpoint", &dd->min_voltage);
+	if (rc < 0) {
+		dev_err(&client->dev, "min set point missing: rc = %d.\n", rc);
+		return rc;
+	}
+
+	return rc;
+}
+
+static struct ncp6335d_platform_data *
+	ncp6335d_get_of_platform_data(struct i2c_client *client)
+{
+	struct ncp6335d_platform_data *pdata = NULL;
+	struct regulator_init_data *init_data;
+	const char *mode_name;
+	int rc;
+
+	init_data = of_get_regulator_init_data(&client->dev,
+				client->dev.of_node);
+	if (!init_data) {
+		dev_err(&client->dev, "regulator init data is missing\n");
+		return pdata;
+	}
+
+	pdata = devm_kzalloc(&client->dev,
+			sizeof(struct ncp6335d_platform_data), GFP_KERNEL);
+	if (!pdata) {
+		dev_err(&client->dev, "ncp6335d_platform_data allocation failed.\n");
+		return pdata;
+	}
+
+	rc = of_property_read_u32(client->dev.of_node,
+			"onnn,vsel", &pdata->default_vsel);
+	if (rc < 0) {
+		dev_err(&client->dev, "onnn,vsel property missing: rc = %d.\n",
+			rc);
+		return NULL;
+	}
+
+	rc = of_property_read_u32(client->dev.of_node,
+			"onnn,slew-ns", &pdata->slew_rate_ns);
+	if (rc < 0) {
+		dev_err(&client->dev, "onnn,slew-ns property missing: rc = %d.\n",
+			rc);
+		return NULL;
+	}
+
+	pdata->discharge_enable = of_property_read_bool(client->dev.of_node,
+						"onnn,discharge-enable");
+
+	pdata->sleep_enable = of_property_read_bool(client->dev.of_node,
+						"onnn,sleep-enable");
+
+	pdata->init_data = init_data;
+
+	init_data->constraints.input_uV = init_data->constraints.max_uV;
+	init_data->constraints.valid_ops_mask =
+				REGULATOR_CHANGE_VOLTAGE |
+				REGULATOR_CHANGE_STATUS |
+				REGULATOR_CHANGE_MODE;
+	init_data->constraints.valid_modes_mask =
+				REGULATOR_MODE_NORMAL |
+				REGULATOR_MODE_FAST;
+
+	rc = of_property_read_string(client->dev.of_node, "onnn,mode",
+					&mode_name);
+	if (!rc) {
+		if (strcmp("pwm", mode_name) == 0) {
+			init_data->constraints.initial_mode =
+							REGULATOR_MODE_FAST;
+		} else if (strcmp("auto", mode_name) == 0) {
+			init_data->constraints.initial_mode =
+							REGULATOR_MODE_NORMAL;
+		} else {
+			dev_err(&client->dev, "onnn,mode, unknown regulator mode: %s\n",
+				mode_name);
+			return NULL;
+		}
+	}
+
+	return pdata;
+}
+
 static int __devinit ncp6335d_regulator_probe(struct i2c_client *client,
 					const struct i2c_device_id *id)
 {
@@ -309,7 +547,11 @@
 	struct ncp6335d_info *dd;
 	const struct ncp6335d_platform_data *pdata;
 
-	pdata = client->dev.platform_data;
+	if (client->dev.of_node)
+		pdata = ncp6335d_get_of_platform_data(client);
+	else
+		pdata = client->dev.platform_data;
+
 	if (!pdata) {
 		dev_err(&client->dev, "Platform data not specified\n");
 		return -EINVAL;
@@ -321,6 +563,17 @@
 		return -ENOMEM;
 	}
 
+	if (client->dev.of_node) {
+		rc = ncp6335d_parse_dt(client, dd);
+		if (rc)
+			return rc;
+	} else {
+		dd->step_size	= NCP6335D_STEP_VOLTAGE_UV;
+		dd->min_voltage	= NCP6335D_MIN_VOLTAGE_UV;
+		dd->min_slew_ns	= NCP6335D_MIN_SLEW_NS;
+		dd->max_slew_ns	= NCP6335D_MAX_SLEW_NS;
+	}
+
 	dd->regmap = devm_regmap_init_i2c(client, &ncp6335d_regmap_config);
 	if (IS_ERR(dd->regmap)) {
 		dev_err(&client->dev, "Error allocating regmap\n");
@@ -339,17 +592,19 @@
 	dd->dev = &client->dev;
 	i2c_set_clientdata(client, dd);
 
-	rc = ncp6335d_init(dd, pdata);
+	rc = ncp6335d_init(client, dd, pdata);
 	if (rc) {
 		dev_err(&client->dev, "Unable to intialize the regulator\n");
 		return -EINVAL;
 	}
 
-	dd->regulator = regulator_register(&rdesc, &client->dev,
-					dd->init_data, dd, NULL);
+	dd->regulator = regulator_register(&rdesc, &client->dev, dd->init_data,
+						dd, client->dev.of_node);
+
 	if (IS_ERR(dd->regulator)) {
 		dev_err(&client->dev, "Unable to register regulator rc(%ld)",
 						PTR_ERR(dd->regulator));
+
 		return PTR_ERR(dd->regulator);
 	}
 
@@ -365,6 +620,12 @@
 	return 0;
 }
 
+static struct of_device_id ncp6335d_match_table[] = {
+	{ .compatible = "onnn,ncp6335d-regulator", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, ncp6335d_match_table);
+
 static const struct i2c_device_id ncp6335d_id[] = {
 	{"ncp6335d", -1},
 	{ },
@@ -373,15 +634,32 @@
 static struct i2c_driver ncp6335d_regulator_driver = {
 	.driver = {
 		.name = "ncp6335d-regulator",
+		.owner = THIS_MODULE,
+		.of_match_table = ncp6335d_match_table,
 	},
 	.probe = ncp6335d_regulator_probe,
 	.remove = __devexit_p(ncp6335d_regulator_remove),
 	.id_table = ncp6335d_id,
 };
-static int __init ncp6335d_regulator_init(void)
+
+/**
+ * ncp6335d_regulator_init() - initialized ncp6335d regulator driver
+ * This function registers the ncp6335d regulator platform driver.
+ *
+ * Returns 0 on success or errno on failure.
+ */
+int __init ncp6335d_regulator_init(void)
 {
+	static bool initialized;
+
+	if (initialized)
+		return 0;
+	else
+		initialized = true;
+
 	return i2c_add_driver(&ncp6335d_regulator_driver);
 }
+EXPORT_SYMBOL(ncp6335d_regulator_init);
 subsys_initcall(ncp6335d_regulator_init);
 
 static void __exit ncp6335d_regulator_exit(void)
diff --git a/drivers/rtc/alarm-dev.c b/drivers/rtc/alarm-dev.c
index 4682e9c..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,9 +100,12 @@
 				wake_unlock(&alarm_wake_lock);
 		}
 		alarm_enabled &= ~alarm_type_mask;
-		if (alarm_type == ANDROID_ALARM_RTC_POWEROFF_WAKEUP)
-			set_power_on_alarm(0);
 		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);
+		mutex_unlock(&alarm_mutex);
 		break;
 
 	case ANDROID_ALARM_SET_OLD:
@@ -120,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);
@@ -127,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);
-		spin_unlock_irqrestore(&alarm_slock, flags);
+			set_power_on_alarm(new_alarm_time.tv_sec, 1);
+		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 7d59e28..8531de9 100644
--- a/drivers/rtc/alarm.c
+++ b/drivers/rtc/alarm.c
@@ -65,15 +65,32 @@
 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;
 
-void set_power_on_alarm(long secs)
+static int set_alarm_time_to_rtc(const long);
+
+void set_power_on_alarm(long secs, bool enable)
 {
-	power_on_alarm = secs;
+	mutex_lock(&power_on_alarm_mutex);
+	if (enable) {
+		power_on_alarm = secs;
+	} else {
+		if (power_on_alarm && power_on_alarm != secs) {
+			pr_alarm(FLOW, "power-off alarm mismatch: \
+				previous=%ld, now=%ld\n",
+				power_on_alarm, secs);
+		}
+		else
+			power_on_alarm = 0;
+	}
+
+	set_alarm_time_to_rtc(power_on_alarm);
+	mutex_unlock(&power_on_alarm_mutex);
 }
 
 
@@ -509,25 +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)
+	if (power_on_time <= 0) {
 		goto disable_alarm;
+	}
 
 	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
@@ -543,18 +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);
 
-	spin_unlock_irqrestore(&alarm_slock, flags);
-	return;
+	return 0;
 
 disable_alarm:
 	rtc_alarm_irq_enable(alarm_rtc_dev, 0);
-	spin_unlock_irqrestore(&alarm_slock, flags);
+	return rc;
 }
 
 static struct rtc_task alarm_rtc_task = {
@@ -616,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/rtc/qpnp-rtc.c b/drivers/rtc/qpnp-rtc.c
index bfbae78..e0d5c1e 100644
--- a/drivers/rtc/qpnp-rtc.c
+++ b/drivers/rtc/qpnp-rtc.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-13, 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
@@ -102,6 +102,7 @@
 	int rc;
 	unsigned long secs, irq_flags;
 	u8 value[4], reg = 0, alarm_enabled = 0, ctrl_reg;
+	u8 rtc_disabled = 0, rtc_ctrl_reg;
 	struct qpnp_rtc *rtc_dd = dev_get_drvdata(dev);
 
 	rtc_tm_to_time(tm, &secs);
@@ -152,6 +153,22 @@
 	 * write operation
 	 */
 
+	/* Disable RTC H/w before writing on RTC register*/
+	rtc_ctrl_reg = rtc_dd->rtc_ctrl_reg;
+	if (rtc_ctrl_reg & BIT_RTC_ENABLE) {
+		rtc_disabled = 1;
+		rtc_ctrl_reg &= ~BIT_RTC_ENABLE;
+		rc = qpnp_write_wrapper(rtc_dd, &rtc_ctrl_reg,
+				rtc_dd->rtc_base + REG_OFFSET_RTC_CTRL, 1);
+		if (rc) {
+			dev_err(dev,
+				"Disabling of RTC control reg failed"
+					" with error:%d\n", rc);
+			goto rtc_rw_fail;
+		}
+		rtc_dd->rtc_ctrl_reg = rtc_ctrl_reg;
+	}
+
 	/* Clear WDATA[0] */
 	reg = 0x0;
 	rc = qpnp_write_wrapper(rtc_dd, &reg,
@@ -177,6 +194,20 @@
 		goto rtc_rw_fail;
 	}
 
+	/* Enable RTC H/w after writing on RTC register*/
+	if (rtc_disabled) {
+		rtc_ctrl_reg |= BIT_RTC_ENABLE;
+		rc = qpnp_write_wrapper(rtc_dd, &rtc_ctrl_reg,
+				rtc_dd->rtc_base + REG_OFFSET_RTC_CTRL, 1);
+		if (rc) {
+			dev_err(dev,
+				"Enabling of RTC control reg failed"
+					" with error:%d\n", rc);
+			goto rtc_rw_fail;
+		}
+		rtc_dd->rtc_ctrl_reg = rtc_ctrl_reg;
+	}
+
 	if (alarm_enabled) {
 		ctrl_reg |= BIT_RTC_ALARM_ENABLE;
 		rc = qpnp_write_wrapper(rtc_dd, &ctrl_reg,
@@ -355,6 +386,7 @@
 	unsigned long irq_flags;
 	struct qpnp_rtc *rtc_dd = dev_get_drvdata(dev);
 	u8 ctrl_reg;
+	u8 value[4] = {0};
 
 	spin_lock_irqsave(&rtc_dd->alarm_ctrl_lock, irq_flags);
 	ctrl_reg = rtc_dd->alarm_ctrl_reg1;
@@ -370,6 +402,15 @@
 
 	rtc_dd->alarm_ctrl_reg1 = ctrl_reg;
 
+	/* Clear Alarm register */
+	if (!enabled) {
+		rc = qpnp_write_wrapper(rtc_dd, value,
+			rtc_dd->alarm_base + REG_OFFSET_ALARM_RW,
+			NUM_8_BIT_RTC_REGS);
+		if (rc)
+			dev_err(dev, "Clear ALARM value reg failed\n");
+	}
+
 rtc_rw_fail:
 	spin_unlock_irqrestore(&rtc_dd->alarm_ctrl_lock, irq_flags);
 	return rc;
@@ -522,8 +563,15 @@
 		goto fail_rtc_enable;
 	}
 
+	rc = qpnp_read_wrapper(rtc_dd, &rtc_dd->alarm_ctrl_reg1,
+				rtc_dd->alarm_base + REG_OFFSET_ALARM_CTRL1, 1);
+	if (rc) {
+		dev_err(&spmi->dev,
+			"Read from  Alarm control reg failed\n");
+		goto fail_rtc_enable;
+	}
 	/* Enable abort enable feature */
-	rtc_dd->alarm_ctrl_reg1 = BIT_RTC_ABORT_ENABLE;
+	rtc_dd->alarm_ctrl_reg1 |= BIT_RTC_ABORT_ENABLE;
 	rc = qpnp_write_wrapper(rtc_dd, &rtc_dd->alarm_ctrl_reg1,
 			rtc_dd->alarm_base + REG_OFFSET_ALARM_CTRL1, 1);
 	if (rc) {
diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c
index 01b0374..c29d98b 100644
--- a/drivers/scsi/scsi_scan.c
+++ b/drivers/scsi/scsi_scan.c
@@ -925,6 +925,10 @@
 
 	transport_configure_device(&sdev->sdev_gendev);
 
+	/* The LLD can override auto suspend tunables in ->slave_configure() */
+	sdev->use_rpm_auto = 0;
+	sdev->autosuspend_delay = SCSI_DEFAULT_AUTOSUSPEND_DELAY;
+
 	if (sdev->host->hostt->slave_configure) {
 		ret = sdev->host->hostt->slave_configure(sdev);
 		if (ret) {
diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c
index 04c2a27..89a1af1 100644
--- a/drivers/scsi/scsi_sysfs.c
+++ b/drivers/scsi/scsi_sysfs.c
@@ -885,7 +885,8 @@
 	device_enable_async_suspend(&sdev->sdev_gendev);
 	scsi_autopm_get_target(starget);
 	pm_runtime_set_active(&sdev->sdev_gendev);
-	pm_runtime_forbid(&sdev->sdev_gendev);
+	if (!sdev->use_rpm_auto)
+		pm_runtime_forbid(&sdev->sdev_gendev);
 	pm_runtime_enable(&sdev->sdev_gendev);
 	scsi_autopm_put_target(starget);
 
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index f454610..2b09d59 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -2612,6 +2612,10 @@
 		gd->events |= DISK_EVENT_MEDIA_CHANGE;
 	}
 
+	blk_pm_runtime_init(sdp->request_queue, dev);
+	if (sdp->autosuspend_delay >= 0)
+		pm_runtime_set_autosuspend_delay(dev, sdp->autosuspend_delay);
+
 	add_disk(gd);
 	sd_dif_config_host(sdkp);
 
@@ -2619,7 +2623,6 @@
 
 	sd_printk(KERN_NOTICE, sdkp, "Attached SCSI %sdisk\n",
 		  sdp->removable ? "removable " : "");
-	blk_pm_runtime_init(sdp->request_queue, dev);
 	scsi_autopm_put_device(sdp);
 	put_device(&sdkp->dev);
 }
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index b743bd6..48959ab 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -1773,6 +1773,12 @@
 
 	*hba_handle = hba;
 
+	/*
+	 * The device-initialize-sequence hasn't been invoked yet.
+	 * Set the device to power-off state
+	 */
+	ufshcd_set_ufs_dev_poweroff(hba);
+
 	async_schedule(ufshcd_async_scan, hba);
 
 	return 0;
diff --git a/drivers/sensors/sensors_class.c b/drivers/sensors/sensors_class.c
index 74e0d8d..bbf168c 100644
--- a/drivers/sensors/sensors_class.c
+++ b/drivers/sensors/sensors_class.c
@@ -105,6 +105,78 @@
 			sensors_cdev->fifo_max_event_count);
 }
 
+static ssize_t sensors_enable_store(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t size)
+{
+	struct sensors_classdev *sensors_cdev = dev_get_drvdata(dev);
+	ssize_t ret = -EINVAL;
+	unsigned long data = 0;
+
+	ret = kstrtoul(buf, 10, &data);
+	if (ret)
+		return ret;
+	if (data > 1) {
+		dev_err(dev, "Invalid value of input, input=%ld\n", data);
+		return -EINVAL;
+	}
+
+	if (sensors_cdev->sensors_enable == NULL) {
+		dev_err(dev, "Invalid sensor class enable handle\n");
+		return -EINVAL;
+	}
+	ret = sensors_cdev->sensors_enable(sensors_cdev, data);
+	if (ret)
+		return ret;
+
+	sensors_cdev->enabled = data;
+	return size;
+}
+
+
+static ssize_t sensors_enable_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct sensors_classdev *sensors_cdev = dev_get_drvdata(dev);
+	return snprintf(buf, PAGE_SIZE, "%u\n",
+			sensors_cdev->enabled);
+}
+
+static ssize_t sensors_delay_store(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t size)
+{
+	struct sensors_classdev *sensors_cdev = dev_get_drvdata(dev);
+	ssize_t ret = -EINVAL;
+	unsigned long data = 0;
+
+	ret = kstrtoul(buf, 10, &data);
+	if (ret)
+		return ret;
+	/* The data unit is millisecond, the min_delay unit is microseconds. */
+	if ((data * 1000) < sensors_cdev->min_delay) {
+		dev_err(dev, "Invalid value of delay, delay=%ld\n", data);
+		return -EINVAL;
+	}
+	if (sensors_cdev->sensors_poll_delay == NULL) {
+		dev_err(dev, "Invalid sensor class delay handle\n");
+		return -EINVAL;
+	}
+	ret = sensors_cdev->sensors_poll_delay(sensors_cdev, data);
+	if (ret)
+		return ret;
+
+	sensors_cdev->delay_msec = data;
+	return size;
+}
+
+static ssize_t sensors_delay_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct sensors_classdev *sensors_cdev = dev_get_drvdata(dev);
+	return snprintf(buf, PAGE_SIZE, "%u\n",
+			sensors_cdev->delay_msec);
+}
+
+
 static struct device_attribute sensors_class_attrs[] = {
 	__ATTR(name, 0444, sensors_name_show, NULL),
 	__ATTR(vendor, 0444, sensors_vendor_show, NULL),
@@ -117,6 +189,8 @@
 	__ATTR(min_delay, 0444, sensors_min_delay_show, NULL),
 	__ATTR(fifo_reserved_event_count, 0444, sensors_fifo_event_show, NULL),
 	__ATTR(fifo_max_event_count, 0444, sensors_fifo_max_show, NULL),
+	__ATTR(enable, 0664, sensors_enable_show, sensors_enable_store),
+	__ATTR(poll_delay, 0664, sensors_delay_show, sensors_delay_store),
 	__ATTR_NULL,
 };
 
diff --git a/drivers/slimbus/slim-msm-ctrl.c b/drivers/slimbus/slim-msm-ctrl.c
index 6e7a815..c662a2b 100644
--- a/drivers/slimbus/slim-msm-ctrl.c
+++ b/drivers/slimbus/slim-msm-ctrl.c
@@ -345,10 +345,12 @@
 	 */
 	if (!(txn->mc & SLIM_MSG_CLK_PAUSE_SEQ_FLG))
 		msgv = msm_slim_get_ctrl(dev);
+	if (msgv >= 0)
+		dev->state = MSM_CTRL_AWAKE;
 	mutex_lock(&dev->tx_lock);
 	if (dev->state == MSM_CTRL_ASLEEP ||
 		((!(txn->mc & SLIM_MSG_CLK_PAUSE_SEQ_FLG)) &&
-		dev->state == MSM_CTRL_SLEEPING)) {
+		dev->state == MSM_CTRL_IDLE)) {
 		dev_err(dev->dev, "runtime or system PM suspended state");
 		mutex_unlock(&dev->tx_lock);
 		if (msgv >= 0)
@@ -1452,6 +1454,10 @@
 #ifdef CONFIG_PM_RUNTIME
 static int msm_slim_runtime_idle(struct device *device)
 {
+	struct platform_device *pdev = to_platform_device(device);
+	struct msm_slim_ctrl *dev = platform_get_drvdata(pdev);
+	if (dev->state == MSM_CTRL_AWAKE)
+		dev->state = MSM_CTRL_IDLE;
 	dev_dbg(device, "pm_runtime: idle...\n");
 	pm_request_autosuspend(device);
 	return -EAGAIN;
@@ -1470,7 +1476,6 @@
 	struct msm_slim_ctrl *dev = platform_get_drvdata(pdev);
 	int ret;
 	dev_dbg(device, "pm_runtime: suspending...\n");
-	dev->state = MSM_CTRL_SLEEPING;
 	ret = slim_ctrl_clk_pause(&dev->ctrl, false, SLIM_CLK_UNSPECIFIED);
 	if (ret) {
 		dev_err(device, "clk pause not entered:%d", ret);
@@ -1500,10 +1505,12 @@
 
 static int msm_slim_suspend(struct device *dev)
 {
-	int ret = 0;
-	if (!pm_runtime_enabled(dev) || !pm_runtime_suspended(dev)) {
-		struct platform_device *pdev = to_platform_device(dev);
-		struct msm_slim_ctrl *cdev = platform_get_drvdata(pdev);
+	int ret = -EBUSY;
+	struct platform_device *pdev = to_platform_device(dev);
+	struct msm_slim_ctrl *cdev = platform_get_drvdata(pdev);
+	if (!pm_runtime_enabled(dev) ||
+		(!pm_runtime_suspended(dev) &&
+			cdev->state == MSM_CTRL_IDLE)) {
 		dev_dbg(dev, "system suspend");
 		ret = msm_slim_runtime_suspend(dev);
 		if (!ret) {
diff --git a/drivers/slimbus/slim-msm-ngd.c b/drivers/slimbus/slim-msm-ngd.c
index 67cf049..b4c88cd 100644
--- a/drivers/slimbus/slim-msm-ngd.c
+++ b/drivers/slimbus/slim-msm-ngd.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
@@ -27,7 +27,6 @@
 #include <linux/timer.h>
 #include <mach/sps.h>
 #include "slim-msm.h"
-#include <mach/qdsp6v2/apr.h>
 
 #define NGD_SLIM_NAME	"ngd_msm_ctrl"
 #define SLIM_LA_MGR	0xFF
@@ -83,6 +82,7 @@
 };
 
 static int ngd_slim_runtime_resume(struct device *device);
+static int ngd_slim_power_up(struct msm_slim_ctrl *dev, bool mdm_restart);
 
 static irqreturn_t ngd_slim_interrupt(int irq, void *d)
 {
@@ -91,25 +91,25 @@
 	u32 stat = readl_relaxed(ngd + NGD_INT_STAT);
 	u32 pstat;
 
-	if (stat & NGD_INT_TX_MSG_SENT) {
+	if ((stat & NGD_INT_MSG_BUF_CONTE) ||
+		(stat & NGD_INT_MSG_TX_INVAL) || (stat & NGD_INT_DEV_ERR) ||
+		(stat & NGD_INT_TX_NACKED_2)) {
+		writel_relaxed(stat, ngd + NGD_INT_CLR);
+		dev->err = -EIO;
+
+		SLIM_WARN(dev, "NGD interrupt error:0x%x, err:%d\n", stat,
+								dev->err);
+		/* Guarantee that error interrupts are cleared */
+		mb();
+		if (dev->wr_comp)
+			complete(dev->wr_comp);
+
+	} else if (stat & NGD_INT_TX_MSG_SENT) {
 		writel_relaxed(NGD_INT_TX_MSG_SENT, ngd + NGD_INT_CLR);
 		/* Make sure interrupt is cleared */
 		mb();
 		if (dev->wr_comp)
 			complete(dev->wr_comp);
-	} else if ((stat & NGD_INT_MSG_BUF_CONTE) ||
-		(stat & NGD_INT_MSG_TX_INVAL) || (stat & NGD_INT_DEV_ERR) ||
-		(stat & NGD_INT_TX_NACKED_2)) {
-		dev_err(dev->dev, "NGD interrupt error:0x%x", stat);
-		writel_relaxed(stat, ngd + NGD_INT_CLR);
-		/* Guarantee that error interrupts are cleared */
-		mb();
-		if (((stat & NGD_INT_TX_NACKED_2) ||
-			(stat & NGD_INT_MSG_TX_INVAL))) {
-			dev->err = -EIO;
-		if (dev->wr_comp)
-			complete(dev->wr_comp);
-		}
 	}
 	if (stat & NGD_INT_RX_MSG_RCVD) {
 		u32 rx_buf[10];
@@ -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);
@@ -180,6 +179,63 @@
 	return 0;
 }
 
+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);
+	struct slim_controller *ctrl = &dev->ctrl;
+	u32 laddr;
+	struct slim_device *sbdev;
+
+	switch (code) {
+	case SUBSYS_BEFORE_SHUTDOWN:
+		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:
+		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;
+	}
+	return NOTIFY_DONE;
+}
+
 static int ngd_get_tid(struct slim_controller *ctrl, struct slim_msg_txn *txn,
 				u8 *tid, struct completion *done)
 {
@@ -229,9 +285,13 @@
 	u8 txn_mt;
 	u16 txn_mc = txn->mc;
 	u8 wbuf[SLIM_MSGQ_BUF_LEN];
+	bool report_sat = false;
 
+	if (txn->mc == SLIM_USR_MC_REPORT_SATELLITE &&
+		txn->mt == SLIM_MSG_MT_SRC_REFERRED_USER)
+		report_sat = true;
 	if (!pm_runtime_enabled(dev->dev) && dev->state == MSM_CTRL_ASLEEP &&
-			txn->mc != SLIM_USR_MC_REPORT_SATELLITE) {
+			report_sat == false) {
 		/*
 		 * Counter-part of system-suspend when runtime-pm is not enabled
 		 * This way, resume can be left empty and device will be put in
@@ -241,17 +301,9 @@
 		 */
 		ngd_slim_runtime_resume(dev->dev);
 	}
-	if ((txn->mc == (SLIM_MSG_CLK_PAUSE_SEQ_FLG |
-			SLIM_MSG_MC_RECONFIGURE_NOW)) &&
-			dev->state <= MSM_CTRL_SLEEPING) {
-		msm_slim_disconnect_endp(dev, &dev->rx_msgq,
-					&dev->use_rx_msgqs);
-		msm_slim_disconnect_endp(dev, &dev->tx_msgq,
-					&dev->use_tx_msgqs);
-		return msm_slim_qmi_power_request(dev, false);
-	}
+
 	else if (txn->mc & SLIM_MSG_CLK_PAUSE_SEQ_FLG)
-		return 0;
+		return -EPROTONOSUPPORT;
 
 	if (txn->mt == SLIM_MSG_MT_CORE &&
 		(txn->mc >= SLIM_MSG_MC_BEGIN_RECONFIGURATION &&
@@ -259,17 +311,37 @@
 		return 0;
 	}
 	/* If txn is tried when controller is down, wait for ADSP to boot */
-	if (txn->mc != SLIM_USR_MC_REPORT_SATELLITE) {
+	if (!report_sat) {
 		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.
 			 * clk_pause in resume (which can change state back to
-			 * MSM_CTRL_AWAKE), will need that lock
+			 * MSM_CTRL_AWAKE), will need that lock.
+			 * Port disconnection, channel removal calls should pass
+			 * through since there is no activity on the bus and
+			 * those calls are triggered by clients due to
+			 * device_down callback in that situation.
+			 * Returning 0 on the disconnections and
+			 * removals will ensure consistent state of channels,
+			 * ports with the HW
+			 * Remote requests to remove channel/port will be
+			 * returned from the path where they wait on
+			 * acknowledgement from ADSP
 			 */
+			if ((txn->mt == SLIM_MSG_MT_DEST_REFERRED_USER) &&
+				((mc == SLIM_USR_MC_CHAN_CTRL ||
+				mc == SLIM_USR_MC_DISCONNECT_PORT ||
+				mc == SLIM_USR_MC_RECONFIG_NOW)))
+				return -EREMOTEIO;
+			if ((txn->mt == SLIM_MSG_MT_CORE) &&
+				((mc == SLIM_MSG_MC_DISCONNECT_PORT ||
+				mc == SLIM_MSG_MC_NEXT_REMOVE_CHANNEL ||
+				mc == SLIM_USR_MC_RECONFIG_NOW)))
+				return 0;
 			if ((txn->mt == SLIM_MSG_MT_CORE) &&
 				((mc >= SLIM_MSG_MC_CONNECT_SOURCE &&
 				mc <= SLIM_MSG_MC_CHANGE_CONTENT) ||
@@ -278,21 +350,34 @@
 				return -EREMOTEIO;
 			if ((txn->mt == SLIM_MSG_MT_DEST_REFERRED_USER) &&
 				((mc >= SLIM_USR_MC_DEFINE_CHAN &&
-				mc <= SLIM_USR_MC_DISCONNECT_PORT)))
+				mc < SLIM_USR_MC_DISCONNECT_PORT)))
 				return -EREMOTEIO;
 			timeout = wait_for_completion_timeout(&dev->ctrl_up,
 							HZ);
-			if (!timeout)
+			if (!timeout && dev->state == MSM_CTRL_DOWN)
 				return -ETIMEDOUT;
 		}
-		msm_slim_get_ctrl(dev);
+		ret = msm_slim_get_ctrl(dev);
+		/*
+		 * Runtime-pm's callbacks are not called until runtime-pm's
+		 * error status is cleared
+		 * Setting runtime status to suspended clears the error
+		 * It also makes HW status cosistent with what SW has it here
+		 */
+		if (ret == -ENETRESET && dev->state == MSM_CTRL_DOWN) {
+			pm_runtime_set_suspended(dev->dev);
+			msm_slim_put_ctrl(dev);
+			return -EREMOTEIO;
+		} else if (ret >= 0) {
+			dev->state = MSM_CTRL_AWAKE;
+		}
 	}
 	mutex_lock(&dev->tx_lock);
 
-	if (txn->mc != SLIM_USR_MC_REPORT_SATELLITE &&
-		(dev->state != MSM_CTRL_AWAKE)) {
-		dev_err(dev->dev, "controller not ready");
+	if (report_sat == false && dev->state != MSM_CTRL_AWAKE) {
+		SLIM_ERR(dev, "controller not ready\n");
 		mutex_unlock(&dev->tx_lock);
+		pm_runtime_set_suspended(dev->dev);
 		msm_slim_put_ctrl(dev);
 		return -EREMOTEIO;
 	}
@@ -301,6 +386,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;
@@ -317,10 +410,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;
 				}
@@ -335,7 +429,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;
@@ -345,7 +440,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;
 	}
@@ -367,11 +462,13 @@
 		puc = ((u8 *)pbuf) + 2;
 	if (txn->rbuf)
 		*(puc++) = txn->tid;
-	if ((txn->mt == SLIM_MSG_MT_CORE) &&
+	if (((txn->mt == SLIM_MSG_MT_CORE) &&
 		((txn->mc >= SLIM_MSG_MC_REQUEST_INFORMATION &&
 		txn->mc <= SLIM_MSG_MC_REPORT_INFORMATION) ||
 		(txn->mc >= SLIM_MSG_MC_REQUEST_VALUE &&
-		 txn->mc <= SLIM_MSG_MC_CHANGE_VALUE))) {
+		 txn->mc <= SLIM_MSG_MC_CHANGE_VALUE))) ||
+		(txn->mc == SLIM_USR_MC_REPEAT_CHANGE_VALUE &&
+		txn->mt == SLIM_MSG_MT_DEST_REFERRED_USER)) {
 		*(puc++) = (txn->ec & 0xFF);
 		*(puc++) = (txn->ec >> 8)&0xFF;
 	}
@@ -397,7 +494,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 */
@@ -436,7 +533,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);
@@ -445,9 +542,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 ||
@@ -461,8 +559,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);
@@ -471,14 +570,53 @@
 	}
 ngd_xfer_err:
 	mutex_unlock(&dev->tx_lock);
-	if (txn_mc != SLIM_USR_MC_REPORT_SATELLITE)
+	if (!report_sat)
 		msm_slim_put_ctrl(dev);
 	return ret ? ret : dev->err;
 }
 
+static int ngd_user_msg(struct slim_controller *ctrl, u8 la, u8 mt, u8 mc,
+				struct slim_ele_access *msg, u8 *buf, u8 len)
+{
+	struct slim_msg_txn txn;
+
+	if (mt != SLIM_MSG_MT_DEST_REFERRED_USER ||
+		mc != SLIM_USR_MC_REPEAT_CHANGE_VALUE) {
+		return -EPROTONOSUPPORT;
+	}
+	if (len > SLIM_MAX_VE_SLC_BYTES ||
+		msg->start_offset > MSM_SLIM_VE_MAX_MAP_ADDR)
+		return -EINVAL;
+	if (len <= 4) {
+		txn.ec = len - 1;
+	} else if (len <= 8) {
+		if (len & 0x1)
+			return -EINVAL;
+		txn.ec = ((len >> 1) + 1);
+	} else {
+		if (len & 0x3)
+			return -EINVAL;
+		txn.ec = ((len >> 2) + 3);
+	}
+	txn.ec |= (0x8 | ((msg->start_offset & 0xF) << 4));
+	txn.ec |= ((msg->start_offset & 0xFF0) << 4);
+
+	txn.la = la;
+	txn.mt = mt;
+	txn.mc = mc;
+	txn.dt = SLIM_MSG_DEST_LOGICALADDR;
+	txn.len = len;
+	txn.rl = len + 6;
+	txn.wbuf = buf;
+	txn.rbuf = NULL;
+	txn.comp = msg->comp;
+	return ngd_xfer_msg(ctrl, &txn);
+}
+
 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;
@@ -488,9 +626,11 @@
 		else
 			ret = txn->ec;
 	}
+
 	if (ret) {
-		pr_err("master msg:0x%x,tid:%d ret:%d", txn->mc,
-				txn->tid, ret);
+		if (ret != -EREMOTEIO || txn->mc != SLIM_USR_MC_CHAN_CTRL)
+			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);
@@ -501,12 +641,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;
@@ -519,7 +660,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) |
@@ -550,7 +691,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) {
@@ -565,12 +706,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;
@@ -595,7 +738,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) {
@@ -604,18 +747,22 @@
 					(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;
 		txn.rl = txn.len + 4;
 		ret = ngd_xferandwait_ack(ctrl, &txn);
-		if (ret)
+		/* HW restarting, channel removal should succeed */
+		if (ret == -EREMOTEIO)
+			return 0;
+		else if (ret)
 			return ret;
 
 		txn.mc = SLIM_USR_MC_RECONFIG_NOW;
@@ -714,7 +861,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)
@@ -731,17 +878,20 @@
 		ret = ngd_xfer_msg(&dev->ctrl, &txn);
 		if (!ret) {
 			enum msm_ctrl_state prev_state = dev->state;
+			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)
-				schedule_work(&dev->slave_notify);
+				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++;
@@ -764,8 +914,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;
 		}
@@ -781,7 +932,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;
@@ -789,7 +940,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;
 		}
@@ -799,10 +950,10 @@
 	}
 }
 
-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;
+	int timeout, ret = 0;
 	enum msm_ctrl_state cur_state = dev->state;
 	u32 laddr;
 	u32 ngd_int = (NGD_INT_TX_NACKED_2 |
@@ -810,17 +961,22 @@
 			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");
 	}
 
-	ret = msm_slim_qmi_power_request(dev, true);
-	if (ret) {
-		pr_err("SLIM QMI power request failed:%d", ret);
-		return ret;
+	/* No need to vote if contorller is not in low power mode */
+	if (!mdm_restart &&
+		(cur_state == MSM_CTRL_DOWN || cur_state == MSM_CTRL_ASLEEP)) {
+		ret = msm_slim_qmi_power_request(dev, true);
+		if (ret) {
+			SLIM_ERR(dev, "SLIM QMI power request failed:%d\n",
+					ret);
+			return ret;
+		}
 	}
 	if (!dev->ver) {
 		dev->ver = readl_relaxed(dev->base);
@@ -831,16 +987,40 @@
 	laddr = readl_relaxed(ngd + NGD_STATUS);
 	if (laddr & NGD_LADDR) {
 		/*
+		 * external MDM restart case where ADSP itself was active framer
+		 * For example, modem restarted when playback was active
+		 */
+		if (cur_state == MSM_CTRL_AWAKE) {
+			SLIM_INFO(dev, "Subsys restart: ADSP active framer\n");
+			return 0;
+		}
+		/*
 		 * ADSP power collapse case, where HW wasn't reset.
 		 * Reconnect BAM pipes if disconnected
 		 */
 		ngd_slim_setup_msg_path(dev);
 		return 0;
-	} else if (cur_state != MSM_CTRL_DOWN) {
-		pr_info("ADSP P.C. CTRL state:%d NGD not enumerated:0x%x",
-					dev->state, laddr);
 	}
-	/* ADSP SSR scenario, need to disconnect pipe before connecting */
+
+	if (mdm_restart) {
+		/*
+		 * 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
+		 */
+		/* 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;
+	}
+	/* 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);
@@ -869,11 +1049,14 @@
 
 	timeout = wait_for_completion_timeout(&dev->reconf, HZ);
 	if (!timeout) {
-		pr_err("failed to received 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;
 }
 
@@ -884,20 +1067,7 @@
 		ret = msm_slim_qmi_init(dev, false);
 		/* controller state should be in sync with framework state */
 		if (!ret) {
-			ret = slim_ctrl_clk_pause(&dev->ctrl, false,
-						SLIM_CLK_UNSPECIFIED);
 			complete(&dev->qmi.qmi_comp);
-			/*
-			 * Power-up won't be called if clock pause failed.
-			 * This can happen if ADSP SSR happened when audio
-			 * session is in progress. Framework will think that
-			 * clock pause failed so no need to wakeup controller.
-			 * Call power-up explicitly in that case, since slimbus
-			 * HW needs to be powered-on to be in sync with
-			 * framework state
-			 */
-			if (ret)
-				ngd_slim_power_up(dev);
 			if (!pm_runtime_enabled(dev->dev) ||
 					!pm_runtime_suspended(dev->dev))
 				ngd_slim_runtime_resume(dev->dev);
@@ -906,7 +1076,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);
@@ -915,10 +1085,25 @@
 	return ret;
 }
 
-static int ngd_clk_pause_wakeup(struct slim_controller *ctrl)
+static int ngd_slim_power_down(struct msm_slim_ctrl *dev)
 {
-	struct msm_slim_ctrl *dev = slim_get_ctrldata(ctrl);
-	return ngd_slim_power_up(dev);
+	int i;
+	struct slim_controller *ctrl = &dev->ctrl;
+	mutex_lock(&ctrl->m_ctrl);
+	/* Pending response for a message */
+	for (i = 0; i < ctrl->last_tid; i++) {
+		if (ctrl->txnt[i]) {
+			SLIM_INFO(dev, "NGD down:txn-rsp for %d pending", i);
+			mutex_unlock(&ctrl->m_ctrl);
+			return -EBUSY;
+		}
+	}
+	mutex_unlock(&ctrl->m_ctrl);
+	msm_slim_disconnect_endp(dev, &dev->rx_msgq,
+				&dev->use_rx_msgqs);
+	msm_slim_disconnect_endp(dev, &dev->tx_msgq,
+				&dev->use_tx_msgqs);
+	return msm_slim_qmi_power_request(dev, false);
 }
 
 static int ngd_slim_rx_msgq_thread(void *data)
@@ -933,11 +1118,7 @@
 
 	while (!kthread_should_stop()) {
 		set_current_state(TASK_INTERRUPTIBLE);
-		ret = wait_for_completion_interruptible(notify);
-		if (ret) {
-			dev_err(dev->dev, "rx thread wait err:%d", ret);
-			continue;
-		}
+		wait_for_completion(notify);
 		/* 1 irq notification per message */
 		if (dev->use_rx_msgqs != MSM_MSGQ_ENABLED) {
 			msm_slim_rx_dequeue(dev, (u8 *)buffer);
@@ -946,7 +1127,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;
 		}
 
@@ -966,28 +1147,50 @@
 	return 0;
 }
 
-static void ngd_laddr_lookup(struct work_struct *work)
+static int ngd_notify_slaves(void *data)
 {
-	struct msm_slim_ctrl *dev =
-		container_of(work, struct msm_slim_ctrl, slave_notify);
+	struct msm_slim_ctrl *dev = (struct msm_slim_ctrl *)data;
 	struct slim_controller *ctrl = &dev->ctrl;
 	struct slim_device *sbdev;
-	int i;
-	mutex_lock(&ctrl->m_ctrl);
-	list_for_each_entry(sbdev, &ctrl->devs, dev_list) {
-		int ret = 0;
-		mutex_unlock(&ctrl->m_ctrl);
-		for (i = 0; i < LADDR_RETRY; i++) {
-			ret = slim_get_logical_addr(sbdev, sbdev->e_addr,
-					6, &sbdev->laddr);
-			if (!ret)
-				break;
-			else /* time for ADSP to assign LA */
-				msleep(20);
+	struct list_head *pos, *next;
+	int ret, i = 0;
+	while (!kthread_should_stop()) {
+		set_current_state(TASK_INTERRUPTIBLE);
+		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);
+
+			/*
+			 * Add devices registered with board-info now that
+			 * controller is up
+			 */
+			slim_ctrl_add_boarddevs(&dev->ctrl);
+		} else {
+			slim_framer_booted(ctrl);
 		}
 		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 (j = 0; j < LADDR_RETRY; j++) {
+				ret = slim_get_logical_addr(sbdev,
+						sbdev->e_addr,
+						6, &sbdev->laddr);
+				if (!ret)
+					break;
+				else /* time for ADSP to assign LA */
+					msleep(20);
+			}
+			mutex_lock(&ctrl->m_ctrl);
+		}
+		mutex_unlock(&ctrl->m_ctrl);
 	}
-	mutex_unlock(&ctrl->m_ctrl);
+	return 0;
 }
 
 static void ngd_adsp_down(struct work_struct *work)
@@ -1009,7 +1212,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)
@@ -1021,6 +1224,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;
@@ -1028,16 +1253,9 @@
 	struct resource		*bam_mem;
 	struct resource		*slim_mem;
 	struct resource		*irq, *bam_irq;
-	enum apr_subsys_state q6_state;
 	bool			rxreg_access = false;
-
-	q6_state = apr_get_q6_state();
-	if (q6_state == APR_SUBSYS_DOWN) {
-		dev_dbg(&pdev->dev, "defering %s, adsp_state %d\n", __func__,
-			q6_state);
-		return -EPROBE_DEFER;
-	} else
-		dev_dbg(&pdev->dev, "adsp is ready\n");
+	bool			slim_mdm = false;
+	const char		*ext_modem_id = NULL;
 
 	slim_mem = platform_get_resource_byname(pdev, IORESOURCE_MEM,
 						"slimbus_physical");
@@ -1072,6 +1290,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");
@@ -1098,6 +1336,10 @@
 					&dev->pdata.apps_pipes);
 		of_property_read_u32(pdev->dev.of_node, "qcom,ea-pc",
 					&dev->pdata.eapc);
+		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;
 	}
@@ -1117,7 +1359,8 @@
 	dev->ctrl.get_laddr = ngd_get_laddr;
 	dev->ctrl.allocbw = ngd_allocbw;
 	dev->ctrl.xfer_msg = ngd_xfer_msg;
-	dev->ctrl.wakeup =  ngd_clk_pause_wakeup;
+	dev->ctrl.xfer_user_msg = ngd_user_msg;
+	dev->ctrl.wakeup = NULL;
 	dev->ctrl.alloc_port = msm_alloc_port;
 	dev->ctrl.dealloc_port = msm_dealloc_port;
 	dev->ctrl.port_xfer = msm_slim_port_xfer;
@@ -1141,6 +1384,7 @@
 	dev->use_tx_msgqs = MSM_MSGQ_RESET;
 
 	init_completion(&dev->rx_msgq_notify);
+	init_completion(&dev->qmi.slave_notify);
 
 	/* Register with framework */
 	ret = slim_add_numbered_controller(&dev->ctrl);
@@ -1162,17 +1406,28 @@
 	}
 
 	init_completion(&dev->qmi.qmi_comp);
+	dev->err = -EPROBE_DEFER;
 	pm_runtime_use_autosuspend(dev->dev);
 	pm_runtime_set_autosuspend_delay(dev->dev, MSM_SLIM_AUTOSUSPEND);
 	pm_runtime_set_suspended(dev->dev);
 	pm_runtime_enable(dev->dev);
 
-	INIT_WORK(&dev->slave_notify, ngd_laddr_lookup);
+	if (slim_mdm) {
+		dev->mdm.nb.notifier_call = mdm_ssr_notify_cb;
+		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,
+				"subsys_notif_register_notifier failed %p",
+				dev->mdm.ssr);
+	}
+
 	INIT_WORK(&dev->qmi.ssr_down, ngd_adsp_down);
 	INIT_WORK(&dev->qmi.ssr_up, ngd_adsp_up);
 	dev->qmi.nb.notifier_call = ngd_qmi_available;
 	pm_runtime_get_noresume(dev->dev);
 	ret = qmi_svc_event_notifier_register(SLIMBUS_QMI_SVC_ID,
+				SLIMBUS_QMI_SVC_V1,
 				SLIMBUS_QMI_INS_ID, &dev->qmi.nb);
 	if (ret) {
 		pr_err("Slimbus QMI service registration failed:%d", ret);
@@ -1182,24 +1437,29 @@
 
 	/* Fire up the Rx message queue thread */
 	dev->rx_msgq_thread = kthread_run(ngd_slim_rx_msgq_thread, dev,
-					NGD_SLIM_NAME "_ngd_msgq_thread");
+					"ngd_rx_thread%d", dev->ctrl.nr);
 	if (IS_ERR(dev->rx_msgq_thread)) {
 		ret = PTR_ERR(dev->rx_msgq_thread);
-		dev_err(dev->dev, "Failed to start Rx message queue thread\n");
-		goto err_thread_create_failed;
+		dev_err(dev->dev, "Failed to start Rx thread:%d\n", ret);
+		goto err_rx_thread_create_failed;
 	}
 
-	if (pdev->dev.of_node)
-		of_register_slim_devices(&dev->ctrl);
-
-	/* Add devices registered with board-info now that controller is up */
-	slim_ctrl_add_boarddevs(&dev->ctrl);
-
-	dev_dbg(dev->dev, "NGD SB controller is up!\n");
+	/* Start thread to probe, and notify slaves */
+	dev->qmi.slave_thread = kthread_run(ngd_notify_slaves, dev,
+					"ngd_notify_sl%d", dev->ctrl.nr);
+	if (IS_ERR(dev->qmi.slave_thread)) {
+		ret = PTR_ERR(dev->qmi.slave_thread);
+		dev_err(dev->dev, "Failed to start notifier thread:%d\n", ret);
+		goto err_notify_thread_create_failed;
+	}
+	SLIM_INFO(dev, "NGD SB controller is up!\n");
 	return 0;
 
-err_thread_create_failed:
+err_notify_thread_create_failed:
+	kthread_stop(dev->rx_msgq_thread);
+err_rx_thread_create_failed:
 	qmi_svc_event_notifier_unregister(SLIMBUS_QMI_SVC_ID,
+				SLIMBUS_QMI_SVC_V1,
 				SLIMBUS_QMI_INS_ID, &dev->qmi.nb);
 qmi_register_failed:
 	free_irq(dev->irq, dev);
@@ -1210,6 +1470,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;
 }
@@ -1218,9 +1481,15 @@
 {
 	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);
 	pm_runtime_disable(&pdev->dev);
+	if (!IS_ERR_OR_NULL(dev->mdm.ssr))
+		subsys_notif_unregister_notifier(dev->mdm.ssr, &dev->mdm.nb);
 	free_irq(dev->irq, dev);
 	slim_del_controller(&dev->ctrl);
 	kthread_stop(dev->rx_msgq_thread);
@@ -1233,6 +1502,10 @@
 #ifdef CONFIG_PM_RUNTIME
 static int ngd_slim_runtime_idle(struct device *device)
 {
+	struct platform_device *pdev = to_platform_device(device);
+	struct msm_slim_ctrl *dev = platform_get_drvdata(pdev);
+	if (dev->state == MSM_CTRL_AWAKE)
+		dev->state = MSM_CTRL_IDLE;
 	dev_dbg(device, "pm_runtime: idle...\n");
 	pm_request_autosuspend(device);
 	return -EAGAIN;
@@ -1250,13 +1523,17 @@
 	struct msm_slim_ctrl *dev = platform_get_drvdata(pdev);
 	int ret = 0;
 	if (dev->state >= MSM_CTRL_ASLEEP)
-		ret = slim_ctrl_clk_pause(&dev->ctrl, true, 0);
+		ret = ngd_slim_power_up(dev, false);
 	if (ret) {
-		dev_err(device, "clk pause not exited:%d", ret);
-		dev->state = MSM_CTRL_ASLEEP;
+		/* Did SSR cause this power up failure */
+		if (dev->state != MSM_CTRL_DOWN)
+			dev->state = MSM_CTRL_ASLEEP;
+		else
+			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;
 }
 
@@ -1266,23 +1543,26 @@
 	struct platform_device *pdev = to_platform_device(device);
 	struct msm_slim_ctrl *dev = platform_get_drvdata(pdev);
 	int ret = 0;
-	dev->state = MSM_CTRL_SLEEPING;
-	ret = slim_ctrl_clk_pause(&dev->ctrl, false, SLIM_CLK_UNSPECIFIED);
+	ret = ngd_slim_power_down(dev);
 	if (ret) {
 		if (ret != -EBUSY)
-			dev_err(device, "clk pause not entered:%d", ret);
+			SLIM_INFO(dev, "slim resource not idle:%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;
 }
 
 static int ngd_slim_suspend(struct device *dev)
 {
 	int ret = -EBUSY;
-	if (!pm_runtime_enabled(dev) || !pm_runtime_suspended(dev)) {
-		dev_dbg(dev, "system suspend");
+	struct platform_device *pdev = to_platform_device(dev);
+	struct msm_slim_ctrl *cdev = platform_get_drvdata(pdev);
+	if (!pm_runtime_enabled(dev) ||
+		(!pm_runtime_suspended(dev) &&
+			cdev->state == MSM_CTRL_IDLE)) {
 		ret = ngd_slim_runtime_suspend(dev);
 		/*
 		 * If runtime-PM still thinks it's active, then make sure its
@@ -1309,16 +1589,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 37bc883..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,9 +67,9 @@
 	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(dev->dev);
+		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
@@ -305,7 +305,7 @@
 }
 
 enum slim_port_err msm_slim_port_xfer_status(struct slim_controller *ctr,
-				u8 pn, u8 **done_buf, u32 *done_len)
+				u8 pn, phys_addr_t *done_buf, u32 *done_len)
 {
 	struct msm_slim_ctrl *dev = slim_get_ctrldata(ctr);
 	struct sps_iovec sio;
@@ -313,7 +313,7 @@
 	if (done_len)
 		*done_len = 0;
 	if (done_buf)
-		*done_buf = NULL;
+		*done_buf = 0;
 	if (!dev->pipes[pn].connected)
 		return SLIM_P_DISCONNECT;
 	ret = sps_get_iovec(dev->pipes[pn].sps, &sio);
@@ -321,7 +321,7 @@
 		if (done_len)
 			*done_len = sio.size;
 		if (done_buf)
-			*done_buf = (u8 *)sio.addr;
+			*done_buf = (phys_addr_t)sio.addr;
 	}
 	dev_dbg(dev->dev, "get iovec returned %d\n", ret);
 	return SLIM_P_INPROGRESS;
@@ -346,7 +346,7 @@
 		complete(comp);
 }
 
-int msm_slim_port_xfer(struct slim_controller *ctrl, u8 pn, u8 *iobuf,
+int msm_slim_port_xfer(struct slim_controller *ctrl, u8 pn, phys_addr_t iobuf,
 			u32 len, struct completion *comp)
 {
 	struct sps_register_event sreg;
@@ -366,7 +366,7 @@
 		dev_dbg(dev->dev, "sps register event error:%x\n", ret);
 		return ret;
 	}
-	ret = sps_transfer_one(dev->pipes[pn].sps, (u32)iobuf, len, comp,
+	ret = sps_transfer_one(dev->pipes[pn].sps, iobuf, len, comp,
 				SPS_IOVEC_FLAG_INT);
 	dev_dbg(dev->dev, "sps submit xfer error code:%x\n", ret);
 	if (!ret) {
@@ -392,7 +392,7 @@
 	struct sps_pipe *pipe = endpoint->sps;
 	int ix = (buf - (u8 *)mem->base) / SLIM_MSGQ_BUF_LEN;
 
-	u32 phys_addr = mem->phys_base + (SLIM_MSGQ_BUF_LEN * ix);
+	phys_addr_t phys_addr = mem->phys_base + (SLIM_MSGQ_BUF_LEN * ix);
 
 	for (ret = 0; ret < ((len + 3) >> 2); ret++)
 		pr_debug("BAM TX buf[%d]:0x%x", ret, ((u32 *)buf)[ret]);
@@ -425,7 +425,7 @@
 	}
 
 	/* Calculate buffer index */
-	dev->tx_idx = (iovec.addr - mem->phys_base) / SLIM_MSGQ_BUF_LEN;
+	dev->tx_idx = ((int)(iovec.addr - mem->phys_base)) / SLIM_MSGQ_BUF_LEN;
 
 	return (u32 *)((u8 *)mem->base + (dev->tx_idx * SLIM_MSGQ_BUF_LEN));
 }
@@ -500,9 +500,9 @@
 
 	/* Rx message queue buffers are 4 bytes in length */
 	u8 *virt_addr = mem->base + (4 * ix);
-	u32 phys_addr = mem->phys_base + (4 * ix);
+	phys_addr_t phys_addr = mem->phys_base + (4 * ix);
 
-	pr_debug("index:%d, phys:0x%x, virt:0x%p\n", ix, phys_addr, virt_addr);
+	pr_debug("index:%d, virt:0x%p\n", ix, virt_addr);
 
 	ret = sps_transfer_one(pipe, phys_addr, 4, virt_addr, flags);
 	if (ret)
@@ -884,11 +884,14 @@
 #define SLIMBUS_QMI_SELECT_INSTANCE_RESP_V01 0x0020
 #define SLIMBUS_QMI_POWER_REQ_V01 0x0021
 #define SLIMBUS_QMI_POWER_RESP_V01 0x0021
+#define SLIMBUS_QMI_CHECK_FRAMER_STATUS_REQ 0x0022
+#define SLIMBUS_QMI_CHECK_FRAMER_STATUS_RESP 0x0022
 
 #define SLIMBUS_QMI_POWER_REQ_MAX_MSG_LEN 7
 #define SLIMBUS_QMI_POWER_RESP_MAX_MSG_LEN 7
 #define SLIMBUS_QMI_SELECT_INSTANCE_REQ_MAX_MSG_LEN 14
 #define SLIMBUS_QMI_SELECT_INSTANCE_RESP_MAX_MSG_LEN 7
+#define SLIMBUS_QMI_CHECK_FRAMER_STAT_RESP_MAX_MSG_LEN 7
 
 enum slimbus_mode_enum_type_v01 {
 	/* To force a 32 bit signed enum. Do not change or use*/
@@ -936,6 +939,13 @@
 	struct qmi_response_type_v01 resp;
 };
 
+struct slimbus_chkfrm_resp_msg {
+	/* Mandatory */
+	/* Result Code */
+	struct qmi_response_type_v01 resp;
+};
+
+
 static struct elem_info slimbus_select_inst_req_msg_v01_ei[] = {
 	{
 		.data_type = QMI_UNSIGNED_4_BYTE,
@@ -1042,6 +1052,27 @@
 	},
 };
 
+static struct elem_info slimbus_chkfrm_resp_msg_v01_ei[] = {
+	{
+		.data_type = QMI_STRUCT,
+		.elem_len  = 1,
+		.elem_size = sizeof(struct qmi_response_type_v01),
+		.is_array  = NO_ARRAY,
+		.tlv_type  = 0x02,
+		.offset    = offsetof(struct slimbus_chkfrm_resp_msg, resp),
+		.ei_array  = get_qmi_response_type_v01_ei(),
+	},
+	{
+		.data_type = QMI_EOTI,
+		.elem_len  = 0,
+		.elem_size = 0,
+		.is_array  = NO_ARRAY,
+		.tlv_type  = 0x00,
+		.offset    = 0,
+		.ei_array  = NULL,
+	},
+};
+
 static void msm_slim_qmi_recv_msg(struct kthread_work *work)
 {
 	int rc;
@@ -1102,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;
 	}
@@ -1134,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;
 	}
@@ -1174,9 +1205,10 @@
 	}
 
 	rc = qmi_connect_to_service(handle, SLIMBUS_QMI_SVC_ID,
+						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;
 	}
 
@@ -1231,3 +1263,32 @@
 
 	return msm_slim_qmi_send_power_request(dev, &req);
 }
+
+int msm_slim_qmi_check_framer_request(struct msm_slim_ctrl *dev)
+{
+	struct slimbus_chkfrm_resp_msg resp = { { 0, 0 } };
+	struct msg_desc req_desc, resp_desc;
+	int rc;
+
+	req_desc.msg_id = SLIMBUS_QMI_CHECK_FRAMER_STATUS_REQ;
+	req_desc.max_msg_len = 0;
+	req_desc.ei_array = NULL;
+
+	resp_desc.msg_id = SLIMBUS_QMI_CHECK_FRAMER_STATUS_RESP;
+	resp_desc.max_msg_len = SLIMBUS_QMI_CHECK_FRAMER_STAT_RESP_MAX_MSG_LEN;
+	resp_desc.ei_array = slimbus_chkfrm_resp_msg_v01_ei;
+
+	rc = qmi_send_req_wait(dev->qmi.handle, &req_desc, NULL, 0,
+					&resp_desc, &resp, sizeof(resp), 5000);
+	if (rc < 0) {
+		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) {
+		SLIM_ERR(dev, "%s: QMI request failed 0x%x (%s)\n",
+			__func__, resp.resp.result, get_qmi_error(&resp.resp));
+		return -EREMOTEIO;
+	}
+	return 0;
+}
diff --git a/drivers/slimbus/slim-msm.h b/drivers/slimbus/slim-msm.h
index b5c41ed..9673208 100644
--- a/drivers/slimbus/slim-msm.h
+++ b/drivers/slimbus/slim-msm.h
@@ -16,6 +16,8 @@
 #include <linux/irq.h>
 #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
@@ -36,6 +38,10 @@
 #define SLIM_USR_MC_CONNECT_SINK	0x2D
 #define SLIM_USR_MC_DISCONNECT_PORT	0x2E
 
+#define SLIM_USR_MC_REPEAT_CHANGE_VALUE	0x0
+#define MSM_SLIM_VE_MAX_MAP_ADDR	0xFFF
+#define SLIM_MAX_VE_SLC_BYTES		16
+
 #define MSM_SLIM_AUTOSUSPEND		MSEC_PER_SEC
 
 /*
@@ -82,7 +88,8 @@
 
 /* Slimbus QMI service */
 #define SLIMBUS_QMI_SVC_ID 0x0301
-#define SLIMBUS_QMI_INS_ID 1
+#define SLIMBUS_QMI_SVC_V1 1
+#define SLIMBUS_QMI_INS_ID 0
 
 #define PGD_THIS_EE(r, v) ((v) ? PGD_THIS_EE_V2(r) : PGD_THIS_EE_V1(r))
 #define PGD_PORT(r, p, v) ((v) ? PGD_PORT_V2(r, p) : PGD_PORT_V1(r, p))
@@ -168,7 +175,7 @@
 
 enum msm_ctrl_state {
 	MSM_CTRL_AWAKE,
-	MSM_CTRL_SLEEPING,
+	MSM_CTRL_IDLE,
 	MSM_CTRL_ASLEEP,
 	MSM_CTRL_DOWN,
 };
@@ -197,6 +204,8 @@
 struct msm_slim_qmi {
 	struct qmi_handle		*handle;
 	struct task_struct		*task;
+	struct task_struct		*slave_thread;
+	struct completion		slave_notify;
 	struct kthread_work		kwork;
 	struct kthread_worker		kworker;
 	struct completion		qmi_comp;
@@ -205,6 +214,12 @@
 	struct work_struct		ssr_up;
 };
 
+struct msm_slim_mdm {
+	struct notifier_block nb;
+	void *ssr;
+	enum msm_ctrl_state state;
+};
+
 struct msm_slim_pdata {
 	u32 apps_pipes;
 	u32 eapc;
@@ -250,9 +265,13 @@
 	struct completion	ctrl_up;
 	int			nsats;
 	u32			ver;
-	struct work_struct	slave_notify;
 	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 {
@@ -286,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);
@@ -298,8 +368,8 @@
 void msm_dealloc_port(struct slim_controller *ctrl, u8 pn);
 int msm_slim_connect_pipe_port(struct msm_slim_ctrl *dev, u8 pn);
 enum slim_port_err msm_slim_port_xfer_status(struct slim_controller *ctr,
-				u8 pn, u8 **done_buf, u32 *done_len);
-int msm_slim_port_xfer(struct slim_controller *ctrl, u8 pn, u8 *iobuf,
+				u8 pn, phys_addr_t *done_buf, u32 *done_len);
+int msm_slim_port_xfer(struct slim_controller *ctrl, u8 pn, phys_addr_t iobuf,
 			u32 len, struct completion *comp);
 int msm_send_msg_buf(struct msm_slim_ctrl *dev, u32 *buf, u8 len, u32 tx_reg);
 u32 *msm_get_msg_buf(struct msm_slim_ctrl *dev, int len);
@@ -317,4 +387,5 @@
 void msm_slim_qmi_exit(struct msm_slim_ctrl *dev);
 int msm_slim_qmi_init(struct msm_slim_ctrl *dev, bool apps_is_master);
 int msm_slim_qmi_power_request(struct msm_slim_ctrl *dev, bool active);
+int msm_slim_qmi_check_framer_request(struct msm_slim_ctrl *dev);
 #endif
diff --git a/drivers/slimbus/slimbus.c b/drivers/slimbus/slimbus.c
index b074289..fecf5ec 100644
--- a/drivers/slimbus/slimbus.c
+++ b/drivers/slimbus/slimbus.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
@@ -288,37 +288,27 @@
 
 static void slim_report(struct work_struct *work)
 {
-	u8 laddr;
-	int ret, i;
 	struct slim_driver *sbdrv;
 	struct slim_device *sbdev =
 			container_of(work, struct slim_device, wd);
-	struct slim_controller *ctrl = sbdev->ctrl;
 	if (!sbdev->dev.driver)
 		return;
 	/* check if device-up or down needs to be called */
-	mutex_lock(&ctrl->m_ctrl);
-	/* address no longer valid, means device reported absent */
-	for (i = 0; i < ctrl->num_dev; i++) {
-		if (sbdev->laddr == ctrl->addrt[i].laddr &&
-			ctrl->addrt[i].valid == false &&
-			sbdev->notified)
-			break;
-	}
-	mutex_unlock(&ctrl->m_ctrl);
+	if ((!sbdev->reported && !sbdev->notified) ||
+			(sbdev->reported && sbdev->notified))
+		return;
+
 	sbdrv = to_slim_driver(sbdev->dev.driver);
-	if (i < ctrl->num_dev) {
+	/*
+	 * address no longer valid, means device reported absent, whereas
+	 * address valid, means device reported present
+	 */
+	if (sbdev->notified && !sbdev->reported) {
 		sbdev->notified = false;
 		if (sbdrv->device_down)
 			sbdrv->device_down(sbdev);
-		return;
-	}
-	if (sbdev->notified)
-		return;
-	ret = slim_get_logical_addr(sbdev, sbdev->e_addr, 6, &laddr);
-	if (!ret) {
-		if (sbdrv)
-			sbdev->notified = true;
+	} else if (!sbdev->notified && sbdev->reported) {
+		sbdev->notified = true;
 		if (sbdrv->device_up)
 			sbdrv->device_up(sbdev);
 	}
@@ -645,11 +635,42 @@
 			ctrl->addrt[i].valid = false;
 	}
 	mutex_unlock(&ctrl->m_ctrl);
+	sbdev->reported = false;
 	queue_work(ctrl->wq, &sbdev->wd);
 }
 EXPORT_SYMBOL(slim_report_absent);
 
 /*
+ * slim_framer_booted: This function is called by controller after the active
+ * framer has booted (using Bus Reset sequence, or after it has shutdown and has
+ * come back up). Components, devices on the bus may be in undefined state,
+ * and this function triggers their drivers to do the needful
+ * to bring them back in Reset state so that they can acquire sync, report
+ * present and be operational again.
+ */
+void slim_framer_booted(struct slim_controller *ctrl)
+{
+	struct slim_device *sbdev;
+	struct list_head *pos, *next;
+	if (!ctrl)
+		return;
+	mutex_lock(&ctrl->m_ctrl);
+	list_for_each_safe(pos, next, &ctrl->devs) {
+		struct slim_driver *sbdrv;
+		sbdev = list_entry(pos, struct slim_device, dev_list);
+		mutex_unlock(&ctrl->m_ctrl);
+		if (sbdev && sbdev->dev.driver) {
+			sbdrv = to_slim_driver(sbdev->dev.driver);
+			if (sbdrv->reset_device)
+				sbdrv->reset_device(sbdev);
+		}
+		mutex_lock(&ctrl->m_ctrl);
+	}
+	mutex_unlock(&ctrl->m_ctrl);
+}
+EXPORT_SYMBOL(slim_framer_booted);
+
+/*
  * slim_msg_response: Deliver Message response received from a device to the
  *	framework.
  * @ctrl: Controller handle
@@ -668,9 +689,12 @@
 
 	mutex_lock(&ctrl->m_ctrl);
 	txn = ctrl->txnt[tid];
-	if (txn == NULL) {
-		dev_err(&ctrl->dev, "Got response to invalid TID:%d, len:%d",
+	if (txn == NULL || txn->rbuf == NULL) {
+		if (txn == NULL)
+			dev_err(&ctrl->dev, "Got response to invalid TID:%d, len:%d",
 				tid, len);
+		else
+			dev_err(&ctrl->dev, "Invalid client buffer passed\n");
 		mutex_unlock(&ctrl->m_ctrl);
 		return;
 	}
@@ -773,6 +797,8 @@
 	u8 i = 0;
 	bool exists = false;
 	struct slim_device *sbdev;
+	struct list_head *pos, *next;
+
 	mutex_lock(&ctrl->m_ctrl);
 	/* already assigned */
 	if (ctrl_getlogical_addr(ctrl, e_addr, e_len, &i) == 0) {
@@ -822,10 +848,12 @@
 	pr_info("slimbus:%d laddr:0x%x, EAPC:0x%x:0x%x", ctrl->nr, *laddr,
 				e_addr[1], e_addr[2]);
 	mutex_lock(&ctrl->m_ctrl);
-	list_for_each_entry(sbdev, &ctrl->devs, dev_list) {
+	list_for_each_safe(pos, next, &ctrl->devs) {
+		sbdev = list_entry(pos, struct slim_device, dev_list);
 		if (memcmp(sbdev->e_addr, e_addr, 6) == 0) {
 			struct slim_driver *sbdrv;
 			sbdev->laddr = *laddr;
+			sbdev->reported = true;
 			if (sbdev->dev.driver) {
 				sbdrv = to_slim_driver(sbdev->dev.driver);
 				if (sbdrv->device_up)
@@ -1079,6 +1107,28 @@
 EXPORT_SYMBOL_GPL(slim_xfer_msg);
 
 /*
+ * User message:
+ * slim_user_msg: Send user message that is interpreted by destination device
+ * @sb: Client handle sending the message
+ * @la: Destination device for this user message
+ * @mt: Message Type (Soruce-referred, or Destination-referred)
+ * @mc: Message Code
+ * @msg: Message structure (start offset, number of bytes) to be sent
+ * @buf: data buffer to be sent
+ * @len: data buffer size in bytes
+ */
+int slim_user_msg(struct slim_device *sb, u8 la, u8 mt, u8 mc,
+				struct slim_ele_access *msg, u8 *buf, u8 len)
+{
+	if (!sb || !sb->ctrl || !msg || mt == SLIM_MSG_MT_CORE)
+		return -EINVAL;
+	if (!sb->ctrl->xfer_user_msg)
+		return -EPROTONOSUPPORT;
+	return sb->ctrl->xfer_user_msg(sb->ctrl, la, mt, mc, msg, buf, len);
+}
+EXPORT_SYMBOL(slim_user_msg);
+
+/*
  * slim_alloc_mgrports: Allocate port on manager side.
  * @sb: device/client handle.
  * @req: Port request type.
@@ -1434,7 +1484,7 @@
  * Client will call slim_port_get_xfer_status to get error and/or number of
  * bytes transferred if used asynchronously.
  */
-int slim_port_xfer(struct slim_device *sb, u32 ph, u8 *iobuf, u32 len,
+int slim_port_xfer(struct slim_device *sb, u32 ph, phys_addr_t iobuf, u32 len,
 				struct completion *comp)
 {
 	struct slim_controller *ctrl = sb->ctrl;
@@ -1464,7 +1514,7 @@
  * processed from the multiple transfers.
  */
 enum slim_port_err slim_port_get_xfer_status(struct slim_device *sb, u32 ph,
-			u8 **done_buf, u32 *done_len)
+			phys_addr_t *done_buf, u32 *done_len)
 {
 	struct slim_controller *ctrl = sb->ctrl;
 	u8 pn = SLIM_HDL_TO_PORT(ph);
@@ -1477,7 +1527,7 @@
 	 */
 	if (la != SLIM_LA_MANAGER) {
 		if (done_buf)
-			*done_buf = NULL;
+			*done_buf = 0;
 		if (done_len)
 			*done_len = 0;
 		return SLIM_P_NOT_OWNED;
@@ -1525,7 +1575,8 @@
 	for (j = *len - 1; j > i; j--)
 		arr[j] = arr[j - 1];
 	arr[i] = slc;
-	ctrl->sched.usedslots += sl;
+	if (!ctrl->allocbw)
+		ctrl->sched.usedslots += sl;
 
 	return;
 }
@@ -2631,7 +2682,8 @@
 				u32 sl = slc->seglen << slc->rootexp;
 				if (slc->coeff == SLIM_COEFF_3)
 					sl *= 3;
-				ctrl->sched.usedslots -= sl;
+				if (!ctrl->allocbw)
+					ctrl->sched.usedslots -= sl;
 				slim_remove_ch(ctrl, slc);
 				slc->state = SLIM_CH_DEFINED;
 			}
@@ -2652,7 +2704,8 @@
 		if (revert || slc->def > 0) {
 			if (slc->coeff == SLIM_COEFF_3)
 				sl *= 3;
-			ctrl->sched.usedslots += sl;
+			if (!ctrl->allocbw)
+				ctrl->sched.usedslots += sl;
 			if (revert)
 				slc->def++;
 			slc->state = SLIM_CH_ACTIVE;
@@ -2746,7 +2799,8 @@
 		u32 sl = slc->seglen << slc->rootexp;
 		if (slc->coeff == SLIM_COEFF_3)
 			sl *= 3;
-		ctrl->sched.usedslots -= sl;
+		if (!ctrl->allocbw)
+			ctrl->sched.usedslots -= sl;
 		slc->state = SLIM_CH_PENDING_REMOVAL;
 	}
 	list_for_each_entry(pch, &sb->mark_suspend, pending) {
@@ -3008,7 +3062,7 @@
 					pch = list_entry(pos,
 						struct slim_pending_ch,
 						pending);
-					if (pch->chan == slc->chan) {
+					if (pch->chan == chan) {
 						list_del(&pch->pending);
 						kfree(pch);
 						add_mark_removal = false;
@@ -3101,8 +3155,15 @@
 		 */
 		if (ctrl->clk_state == SLIM_CLK_PAUSED && ctrl->wakeup)
 			ret = ctrl->wakeup(ctrl);
+		/*
+		 * If wakeup fails, make sure that next attempt can succeed.
+		 * Since we already consumed pause_comp, complete it so
+		 * that next wakeup isn't blocked forever
+		 */
 		if (!ret)
 			ctrl->clk_state = SLIM_CLK_ACTIVE;
+		else
+			complete(&ctrl->pause_comp);
 		mutex_unlock(&ctrl->m_ctrl);
 		return ret;
 	} else {
diff --git a/drivers/spi/spi_qsd.c b/drivers/spi/spi_qsd.c
index 45400cb..d8dc6f9 100644
--- a/drivers/spi/spi_qsd.c
+++ b/drivers/spi/spi_qsd.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2008-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
@@ -50,7 +50,7 @@
 
 static int msm_spi_pm_resume_runtime(struct device *device);
 static int msm_spi_pm_suspend_runtime(struct device *device);
-
+static inline void msm_spi_dma_unmap_buffers(struct msm_spi *dd);
 
 static inline int msm_spi_configure_gsbi(struct msm_spi *dd,
 					struct platform_device *pdev)
@@ -135,6 +135,40 @@
 	}
 }
 
+static inline int msm_spi_request_cs_gpio(struct msm_spi *dd)
+{
+	int cs_num;
+	int rc;
+
+	cs_num = dd->cur_msg->spi->chip_select;
+	if ((!(dd->cur_msg->spi->mode & SPI_LOOP)) &&
+		(!(dd->cs_gpios[cs_num].valid)) &&
+		(dd->cs_gpios[cs_num].gpio_num >= 0)) {
+		rc = gpio_request(dd->cs_gpios[cs_num].gpio_num,
+				spi_cs_rsrcs[cs_num]);
+		if (rc) {
+			dev_err(dd->dev,
+				"gpio_request for pin %d failed,error %d\n",
+				dd->cs_gpios[cs_num].gpio_num, rc);
+			return rc;
+		}
+		dd->cs_gpios[cs_num].valid = 1;
+	}
+	return 0;
+}
+
+static inline void msm_spi_free_cs_gpio(struct msm_spi *dd)
+{
+	int cs_num;
+
+	cs_num = dd->cur_msg->spi->chip_select;
+	if (dd->cs_gpios[cs_num].valid) {
+		gpio_free(dd->cs_gpios[cs_num].gpio_num);
+		dd->cs_gpios[cs_num].valid = 0;
+	}
+}
+
+
 /**
  * msm_spi_clk_max_rate: finds the nearest lower rate for a clk
  * @clk the clock for which to find nearest lower rate
@@ -785,117 +819,190 @@
 	msm_spi_bam_pipe_flush(dd, SPI_BAM_PRODUCER_PIPE);
 }
 
+static int
+msm_spi_bam_process_rx(struct msm_spi *dd, u32 *bytes_to_send, u32 desc_cnt)
+{
+	int ret = 0;
+	u32 data_xfr_size = 0, rem_bc = 0;
+	u32 prod_flags = 0;
+
+	rem_bc = dd->cur_rx_transfer->len - dd->bam.curr_rx_bytes_recvd;
+	data_xfr_size = (rem_bc < *bytes_to_send) ? rem_bc : *bytes_to_send;
+
+	/*
+	 * set flags for last descriptor only
+	 */
+	if ((desc_cnt == 1)
+		|| (*bytes_to_send == data_xfr_size))
+		prod_flags = (dd->write_buf)
+			? 0 : (SPS_IOVEC_FLAG_EOT | SPS_IOVEC_FLAG_NWD);
+
+	/*
+	 * enqueue read buffer in BAM
+	 */
+	ret = sps_transfer_one(dd->bam.prod.handle,
+			dd->cur_rx_transfer->rx_dma
+				+ dd->bam.curr_rx_bytes_recvd,
+			data_xfr_size, dd, prod_flags);
+	if (ret < 0) {
+		dev_err(dd->dev,
+		"%s: Failed to queue producer BAM transfer",
+		__func__);
+		return ret;
+	}
+
+	dd->bam.curr_rx_bytes_recvd += data_xfr_size;
+	*bytes_to_send -= data_xfr_size;
+	dd->bam.bam_rx_len -= data_xfr_size;
+
+	if (!(dd->cur_rx_transfer->len - dd->bam.curr_rx_bytes_recvd)) {
+		struct spi_transfer *t = dd->cur_rx_transfer;
+		struct spi_transfer *next;
+		if (t->transfer_list.next != &dd->cur_msg->transfers) {
+			next = list_entry(t->transfer_list.next,
+					struct spi_transfer,
+					transfer_list);
+			dd->read_buf  = next->rx_buf;
+			dd->cur_rx_transfer = next;
+			dd->bam.curr_rx_bytes_recvd = 0;
+		}
+	}
+	return data_xfr_size;
+}
+
+static int
+msm_spi_bam_process_tx(struct msm_spi *dd, u32 *bytes_to_send, u32 desc_cnt)
+{
+	int ret = 0;
+	u32 data_xfr_size = 0, rem_bc = 0;
+	u32 cons_flags = 0;
+
+	rem_bc = dd->cur_tx_transfer->len - dd->bam.curr_tx_bytes_sent;
+	data_xfr_size = (rem_bc < *bytes_to_send) ? rem_bc : *bytes_to_send;
+
+	/*
+	 * set flags for last descriptor only
+	*/
+	if ((desc_cnt == 1)
+		|| (*bytes_to_send == data_xfr_size))
+		cons_flags = SPS_IOVEC_FLAG_EOT | SPS_IOVEC_FLAG_NWD;
+
+	/*
+	 * enqueue write buffer in BAM
+	 */
+	ret = sps_transfer_one(dd->bam.cons.handle,
+			dd->cur_tx_transfer->tx_dma
+				+ dd->bam.curr_tx_bytes_sent,
+			data_xfr_size, dd, cons_flags);
+	if (ret < 0) {
+		dev_err(dd->dev,
+		"%s: Failed to queue consumer BAM transfer",
+		__func__);
+		return ret;
+	}
+
+	dd->bam.curr_tx_bytes_sent	+= data_xfr_size;
+	*bytes_to_send	-= data_xfr_size;
+	dd->bam.bam_tx_len -= data_xfr_size;
+
+	if (!(dd->cur_tx_transfer->len - dd->bam.curr_tx_bytes_sent)) {
+		struct spi_transfer *t = dd->cur_tx_transfer;
+		struct spi_transfer *next;
+		if (t->transfer_list.next != &dd->cur_msg->transfers) {
+			next = list_entry(t->transfer_list.next,
+					struct spi_transfer,
+					transfer_list);
+			dd->write_buf = next->tx_buf;
+			dd->cur_tx_transfer = next;
+			dd->bam.curr_tx_bytes_sent = 0;
+		}
+	}
+	return data_xfr_size;
+}
+
+
 /**
  * msm_spi_bam_begin_transfer: transfer dd->tx_bytes_remaining bytes
  * using BAM.
  * @brief BAM can transfer SPI_MAX_TRFR_BTWN_RESETS byte at a single
  * transfer. Between transfer QUP must change to reset state. A loop is
- * issuing a single BAM transfer at a time. If another tsranfer is
- * required, it waits for the trasfer to finish, then moving to reset
- * state, and back to run state to issue the next transfer.
- * The function dose not wait for the last transfer to end, or if only
- * a single transfer is required, the function dose not wait for it to
- * end.
- * @timeout max time in jiffies to wait for a transfer to finish.
+ * issuing a single BAM transfer at a time.
  * @return zero on success
  */
 static int
-msm_spi_bam_begin_transfer(struct msm_spi *dd, u32 timeout, u8 bpw)
+msm_spi_bam_begin_transfer(struct msm_spi *dd)
 {
-	u32 bytes_to_send, bytes_sent, n_words_xfr, cons_flags, prod_flags;
-	int ret;
-	/*
-	 * QUP must move to reset mode every 64K-1 bytes of transfer
-	 * (counter is 16 bit)
-	 */
-	if (dd->tx_bytes_remaining > SPI_MAX_TRFR_BTWN_RESETS) {
-		/* assert chip select unconditionally */
-		u32 spi_ioc = readl_relaxed(dd->base + SPI_IO_CONTROL);
-		if (!(spi_ioc & SPI_IO_C_FORCE_CS))
-			writel_relaxed(spi_ioc | SPI_IO_C_FORCE_CS,
-				dd->base + SPI_IO_CONTROL);
+	u32 tx_bytes_to_send = 0, rx_bytes_to_recv = 0;
+	u32 n_words_xfr;
+	s32 ret = 0;
+	u32 prod_desc_cnt = SPI_BAM_MAX_DESC_NUM - 1;
+	u32 cons_desc_cnt = SPI_BAM_MAX_DESC_NUM - 1;
+	u32 byte_count = 0;
+
+
+	rx_bytes_to_recv = min_t(u32, dd->bam.bam_rx_len,
+				SPI_MAX_TRFR_BTWN_RESETS);
+	tx_bytes_to_send = min_t(u32, dd->bam.bam_tx_len,
+				SPI_MAX_TRFR_BTWN_RESETS);
+	n_words_xfr = DIV_ROUND_UP(rx_bytes_to_recv,
+				dd->bytes_per_word);
+
+	msm_spi_set_mx_counts(dd, n_words_xfr);
+	ret = msm_spi_set_state(dd, SPI_OP_STATE_RUN);
+	if (ret < 0) {
+		dev_err(dd->dev,
+			"%s: Failed to set QUP state to run",
+			__func__);
+		goto xfr_err;
 	}
 
-	/* Following flags are required since we are waiting on all transfers */
-	cons_flags = SPS_IOVEC_FLAG_EOT | SPS_IOVEC_FLAG_NWD;
-	/*
-	 * on a balanced transaction, BAM will set the flags on the producer
-	 * pipe based on the flags set on the consumer pipe
-	 */
-	prod_flags = (dd->write_buf) ? 0 : cons_flags;
-
-	while (dd->tx_bytes_remaining > 0) {
-		bytes_sent = dd->cur_transfer->len - dd->tx_bytes_remaining;
-		bytes_to_send = min_t(u32, dd->tx_bytes_remaining
-						, SPI_MAX_TRFR_BTWN_RESETS);
-		n_words_xfr = DIV_ROUND_UP(bytes_to_send
-						, dd->bytes_per_word);
-
-		msm_spi_set_mx_counts(dd, n_words_xfr);
-
-		ret = msm_spi_set_state(dd, SPI_OP_STATE_RUN);
-		if (ret < 0) {
-			dev_err(dd->dev,
-				"%s: Failed to set QUP state to run",
-				__func__);
-			goto xfr_err;
+	while ((rx_bytes_to_recv + tx_bytes_to_send) &&
+		((cons_desc_cnt + prod_desc_cnt) > 0)) {
+		if (dd->read_buf && (prod_desc_cnt > 0)) {
+			ret = msm_spi_bam_process_rx(dd, &rx_bytes_to_recv,
+							prod_desc_cnt);
+			if (ret < 0)
+				goto xfr_err;
+			prod_desc_cnt--;
 		}
 
-		/* enqueue read buffer in BAM */
-		if (dd->read_buf) {
-			ret = sps_transfer_one(dd->bam.prod.handle,
-				dd->cur_transfer->rx_dma + bytes_sent,
-				bytes_to_send, dd, prod_flags);
-			if (ret < 0) {
-				dev_err(dd->dev,
-				"%s: Failed to queue producer BAM transfer",
-				__func__);
+		if (dd->write_buf && (cons_desc_cnt > 0)) {
+			ret = msm_spi_bam_process_tx(dd, &tx_bytes_to_send,
+							cons_desc_cnt);
+			if (ret < 0)
 				goto xfr_err;
-			}
+			cons_desc_cnt--;
 		}
-
-		/* enqueue write buffer in BAM */
-		if (dd->write_buf) {
-			ret = sps_transfer_one(dd->bam.cons.handle,
-				dd->cur_transfer->tx_dma + bytes_sent,
-				bytes_to_send, dd, cons_flags);
-			if (ret < 0) {
-				dev_err(dd->dev,
-				"%s: Failed to queue consumer BAM transfer",
-				__func__);
-				goto xfr_err;
-			}
-		}
-
-		dd->tx_bytes_remaining -= bytes_to_send;
-
-		/* move to reset state after SPI_MAX_TRFR_BTWN_RESETS */
-		if (dd->tx_bytes_remaining > 0) {
-			if (!wait_for_completion_timeout(
-				&dd->transfer_complete, timeout)) {
-				dev_err(dd->dev,
-					"%s: SPI transaction timeout",
-					__func__);
-				dd->cur_msg->status = -EIO;
-				ret = -EIO;
-				goto xfr_err;
-			}
-			ret = msm_spi_set_state(dd, SPI_OP_STATE_RESET);
-			if (ret < 0) {
-				dev_err(dd->dev,
-					"%s: Failed to set QUP state to reset",
-					__func__);
-				goto xfr_err;
-			}
-			init_completion(&dd->transfer_complete);
-		}
+		byte_count += ret;
 	}
+
+	dd->tx_bytes_remaining -= min_t(u32, byte_count,
+						SPI_MAX_TRFR_BTWN_RESETS);
 	return 0;
-
 xfr_err:
 	return ret;
 }
 
+static int
+msm_spi_bam_next_transfer(struct msm_spi *dd)
+{
+	if (dd->mode != SPI_BAM_MODE)
+		return 0;
+
+	if (dd->tx_bytes_remaining > 0) {
+		init_completion(&dd->transfer_complete);
+		if (msm_spi_set_state(dd, SPI_OP_STATE_RESET))
+			return 0;
+		if ((msm_spi_bam_begin_transfer(dd)) < 0) {
+			dev_err(dd->dev, "%s: BAM transfer setup failed\n",
+				__func__);
+			return 0;
+		}
+		return 1;
+	}
+	return 0;
+}
+
 static void msm_spi_setup_dm_transfer(struct msm_spi *dd)
 {
 	dmov_box *box;
@@ -1098,6 +1205,16 @@
 	return 0;
 }
 
+static int msm_spi_dma_send_next(struct msm_spi *dd)
+{
+	int ret = 0;
+	if (dd->mode == SPI_DMOV_MODE)
+		ret = msm_spi_dm_send_next(dd);
+	if (dd->mode == SPI_BAM_MODE)
+		ret = msm_spi_bam_next_transfer(dd);
+	return ret;
+}
+
 static inline void msm_spi_ack_transfer(struct msm_spi *dd)
 {
 	writel_relaxed(SPI_OP_MAX_INPUT_DONE_FLAG |
@@ -1167,10 +1284,8 @@
 		if ((!dd->read_buf || op & SPI_OP_MAX_INPUT_DONE_FLAG) &&
 		    (!dd->write_buf || op & SPI_OP_MAX_OUTPUT_DONE_FLAG)) {
 			msm_spi_ack_transfer(dd);
-			if (dd->rx_unaligned_len == 0) {
 				if (atomic_inc_return(&dd->rx_irq_called) == 1)
 					return IRQ_HANDLED;
-			}
 			msm_spi_complete(dd);
 			return IRQ_HANDLED;
 		}
@@ -1299,14 +1414,14 @@
 }
 
 /**
- * msm_spi_dma_map_buffers: prepares buffer for DMA transfer
+ * msm_spi_dmov_map_buffers: prepares buffer for DMA transfer
  * @return zero on success or negative error code
  *
  * calls dma_map_single() on the read/write buffers, effectively invalidating
  * their cash entries. for For WR-WR and WR-RD transfers, allocates temporary
  * buffer and copy the data to/from the client buffers
  */
-static int msm_spi_dma_map_buffers(struct msm_spi *dd)
+static int msm_spi_dmov_map_buffers(struct msm_spi *dd)
 {
 	struct device *dev;
 	struct spi_transfer *first_xfr;
@@ -1325,7 +1440,7 @@
 	 * For WR-WR and WR-RD transfers, we allocate our own temporary
 	 * buffer and copy the data to/from the client buffers.
 	 */
-	if (dd->multi_xfr) {
+	if (!dd->qup_ver && dd->multi_xfr) {
 		dd->temp_buf = kzalloc(dd->cur_msg_len,
 				       GFP_KERNEL | __GFP_DMA);
 		if (!dd->temp_buf)
@@ -1386,6 +1501,70 @@
 	return ret;
 }
 
+static int msm_spi_bam_map_buffers(struct msm_spi *dd)
+{
+	int ret = -EINVAL;
+	struct device *dev;
+	struct spi_transfer *first_xfr;
+	struct spi_transfer *nxt_xfr;
+	void *tx_buf, *rx_buf;
+	u32 tx_len, rx_len;
+	int num_xfrs_grped = dd->num_xfrs_grped;
+
+	dev = &dd->cur_msg->spi->dev;
+	first_xfr = dd->cur_transfer;
+
+	do {
+		tx_buf = (void *)first_xfr->tx_buf;
+		rx_buf = first_xfr->rx_buf;
+		tx_len = rx_len = first_xfr->len;
+		if (tx_buf != NULL) {
+			first_xfr->tx_dma = dma_map_single(dev, tx_buf,
+							tx_len, DMA_TO_DEVICE);
+			if (dma_mapping_error(NULL, first_xfr->tx_dma)) {
+				ret = -ENOMEM;
+				goto error;
+			}
+		}
+
+		if (rx_buf != NULL) {
+			first_xfr->rx_dma = dma_map_single(dev, rx_buf,	rx_len,
+							DMA_FROM_DEVICE);
+			if (dma_mapping_error(NULL, first_xfr->rx_dma)) {
+				if (tx_buf != NULL)
+					dma_unmap_single(NULL,
+							first_xfr->tx_dma,
+							tx_len, DMA_TO_DEVICE);
+				ret = -ENOMEM;
+				goto error;
+			}
+		}
+
+		nxt_xfr = list_entry(first_xfr->transfer_list.next,
+				struct spi_transfer, transfer_list);
+
+		if (nxt_xfr == NULL)
+			break;
+		num_xfrs_grped--;
+		first_xfr = nxt_xfr;
+	} while (num_xfrs_grped > 0);
+
+	return 0;
+error:
+	msm_spi_dma_unmap_buffers(dd);
+	return ret;
+}
+
+static int msm_spi_dma_map_buffers(struct msm_spi *dd)
+{
+	int ret = 0;
+	if (dd->mode == SPI_DMOV_MODE)
+		ret = msm_spi_dmov_map_buffers(dd);
+	else if (dd->mode == SPI_BAM_MODE)
+		ret = msm_spi_bam_map_buffers(dd);
+	return ret;
+}
+
 static void msm_spi_dmov_unmap_buffers(struct msm_spi *dd)
 {
 	struct device *dev;
@@ -1457,21 +1636,39 @@
 static void msm_spi_bam_unmap_buffers(struct msm_spi *dd)
 {
 	struct device *dev;
+	int num_xfrs_grped = dd->num_xfrs_grped;
+	struct spi_transfer *first_xfr;
+	struct spi_transfer *nxt_xfr;
+	void *tx_buf, *rx_buf;
+	u32  tx_len, rx_len;
+
+	dev = &dd->cur_msg->spi->dev;
+	first_xfr = dd->cur_transfer;
 
 	 /* mapped by client */
 	if (dd->cur_msg->is_dma_mapped)
 		return;
 
-	dev = &dd->cur_msg->spi->dev;
-	if (dd->cur_transfer->rx_buf)
-		dma_unmap_single(dev, dd->cur_transfer->rx_dma,
-				dd->cur_transfer->len,
-				DMA_FROM_DEVICE);
+	do {
+		tx_buf = (void *)first_xfr->tx_buf;
+		rx_buf = first_xfr->rx_buf;
+		tx_len = rx_len = first_xfr->len;
+		if (tx_buf != NULL)
+			dma_unmap_single(dev, first_xfr->tx_dma,
+					tx_len, DMA_TO_DEVICE);
 
-	if (dd->cur_transfer->tx_buf)
-		dma_unmap_single(dev, dd->cur_transfer->tx_dma,
-				dd->cur_transfer->len,
-				DMA_TO_DEVICE);
+		if (rx_buf != NULL)
+			dma_unmap_single(dev, first_xfr->rx_dma,
+					rx_len, DMA_FROM_DEVICE);
+
+		nxt_xfr = list_entry(first_xfr->transfer_list.next,
+				struct spi_transfer, transfer_list);
+
+		if (nxt_xfr == NULL)
+			break;
+		num_xfrs_grped--;
+		first_xfr = nxt_xfr;
+	} while (num_xfrs_grped > 0);
 }
 
 static inline void msm_spi_dma_unmap_buffers(struct msm_spi *dd)
@@ -1508,7 +1705,8 @@
 	if (dd->cur_msg_len < 3*dd->input_block_size)
 		return false;
 
-	if (dd->multi_xfr && !dd->read_len && !dd->write_len)
+	if ((dd->qup_ver != SPI_QUP_VERSION_BFAM) &&
+		dd->multi_xfr && !dd->read_len && !dd->write_len)
 		return false;
 
 	if (dd->qup_ver == SPI_QUP_VERSION_NONE) {
@@ -1690,11 +1888,17 @@
 
 	msm_spi_set_transfer_mode(dd, bpw, read_count);
 	msm_spi_set_mx_counts(dd, read_count);
-	if ((dd->mode == SPI_BAM_MODE) || (dd->mode == SPI_DMOV_MODE))
+	if (dd->mode == SPI_DMOV_MODE) {
 		if (msm_spi_dma_map_buffers(dd) < 0) {
 			pr_err("Mapping DMA buffers\n");
 			return;
+			}
+	} else if (dd->mode == SPI_BAM_MODE) {
+			if (msm_spi_dma_map_buffers(dd) < 0) {
+				pr_err("Mapping DMA buffers\n");
+				return;
 		}
+	}
 	msm_spi_set_qup_io_modes(dd);
 	msm_spi_set_spi_config(dd, bpw);
 	msm_spi_set_qup_config(dd, bpw);
@@ -1714,7 +1918,7 @@
 			goto transfer_end;
 		msm_spi_start_write(dd, read_count);
 	} else if (dd->mode == SPI_BAM_MODE) {
-		if ((msm_spi_bam_begin_transfer(dd, timeout, bpw)) < 0)
+		if ((msm_spi_bam_begin_transfer(dd)) < 0)
 			dev_err(dd->dev, "%s: BAM transfer setup failed\n",
 				__func__);
 	}
@@ -1751,9 +1955,10 @@
 					msm_spi_bam_flush(dd);
 				break;
 		}
-	} while (msm_spi_dm_send_next(dd));
+	} while (msm_spi_dma_send_next(dd));
 
-	msm_spi_udelay(dd->cur_transfer->delay_usecs);
+	msm_spi_udelay(dd->xfrs_delay_usec);
+
 transfer_end:
 	msm_spi_dma_unmap_buffers(dd);
 	dd->mode = SPI_MODE_NONE;
@@ -1805,26 +2010,6 @@
 		dd->multi_xfr = 1;
 }
 
-static inline int combine_transfers(struct msm_spi *dd)
-{
-	struct spi_transfer *t = dd->cur_transfer;
-	struct spi_transfer *nxt;
-	int xfrs_grped = 1;
-
-	dd->cur_msg_len = dd->cur_transfer->len;
-	while (t->transfer_list.next != &dd->cur_msg->transfers) {
-		nxt = list_entry(t->transfer_list.next,
-				 struct spi_transfer,
-				 transfer_list);
-		if (t->cs_change != nxt->cs_change)
-			return xfrs_grped;
-		dd->cur_msg_len += nxt->len;
-		xfrs_grped++;
-		t = nxt;
-	}
-	return xfrs_grped;
-}
-
 static inline void write_force_cs(struct msm_spi *dd, bool set_flag)
 {
 	u32 spi_ioc;
@@ -1841,133 +2026,160 @@
 		writel_relaxed(spi_ioc, dd->base + SPI_IO_CONTROL);
 }
 
+static inline int combine_transfers(struct msm_spi *dd)
+{
+	struct spi_transfer *t = dd->cur_transfer;
+	struct spi_transfer *nxt;
+	int xfrs_grped = 1;
+	dd->xfrs_delay_usec = 0;
+
+	dd->bam.bam_rx_len = dd->bam.bam_tx_len = 0;
+
+	dd->cur_msg_len = dd->cur_transfer->len;
+
+	if (dd->cur_transfer->tx_buf)
+		dd->bam.bam_tx_len += dd->cur_transfer->len;
+	if (dd->cur_transfer->rx_buf)
+		dd->bam.bam_rx_len += dd->cur_transfer->len;
+
+	while (t->transfer_list.next != &dd->cur_msg->transfers) {
+		nxt = list_entry(t->transfer_list.next,
+				 struct spi_transfer,
+				 transfer_list);
+		if (t->cs_change != nxt->cs_change)
+			return xfrs_grped;
+		if (t->delay_usecs) {
+			dd->xfrs_delay_usec = t->delay_usecs;
+			dev_info(dd->dev, "SPI slave requests delay per txn :%d usecs",
+					t->delay_usecs);
+			return xfrs_grped;
+		}
+		if (nxt->tx_buf)
+			dd->bam.bam_tx_len += nxt->len;
+		if (nxt->rx_buf)
+			dd->bam.bam_rx_len += nxt->len;
+
+		dd->cur_msg_len += nxt->len;
+		xfrs_grped++;
+		t = nxt;
+	}
+
+	if (1 == xfrs_grped)
+		dd->xfrs_delay_usec = dd->cur_transfer->delay_usecs;
+
+	return xfrs_grped;
+}
+
 static void msm_spi_process_message(struct msm_spi *dd)
 {
 	int xfrs_grped = 0;
-	int cs_num;
 	int rc;
-	bool xfer_delay = false;
-	struct spi_transfer *tr;
 
+	dd->num_xfrs_grped = 0;
+	dd->bam.curr_rx_bytes_recvd = dd->bam.curr_tx_bytes_sent = 0;
 	dd->write_xfr_cnt = dd->read_xfr_cnt = 0;
-	cs_num = dd->cur_msg->spi->chip_select;
-	if ((!(dd->cur_msg->spi->mode & SPI_LOOP)) &&
-		(!(dd->cs_gpios[cs_num].valid)) &&
-		(dd->cs_gpios[cs_num].gpio_num >= 0)) {
-		rc = gpio_request(dd->cs_gpios[cs_num].gpio_num,
-				spi_cs_rsrcs[cs_num]);
-		if (rc) {
-			dev_err(dd->dev, "gpio_request for pin %d failed with "
-				"error %d\n", dd->cs_gpios[cs_num].gpio_num,
-				rc);
-			return;
-		}
-		dd->cs_gpios[cs_num].valid = 1;
-	}
+	rc = msm_spi_request_cs_gpio(dd);
+	if (rc)
+		return;
 
-	list_for_each_entry(tr,
-				&dd->cur_msg->transfers,
-				transfer_list) {
-		if (tr->delay_usecs) {
-			dev_info(dd->dev, "SPI slave requests delay per txn :%d",
-					tr->delay_usecs);
-			xfer_delay = true;
-			break;
-		}
-	}
-
-	/* Don't combine xfers if delay is needed after every xfer */
-	if (dd->qup_ver || xfer_delay) {
-		if (dd->qup_ver)
-			write_force_cs(dd, 0);
-		list_for_each_entry(dd->cur_transfer,
-				&dd->cur_msg->transfers,
-				transfer_list) {
-			struct spi_transfer *t = dd->cur_transfer;
-			struct spi_transfer *nxt;
-
-			if (t->transfer_list.next != &dd->cur_msg->transfers) {
-				nxt = list_entry(t->transfer_list.next,
+	dd->cur_transfer = list_first_entry(&dd->cur_msg->transfers,
 						struct spi_transfer,
 						transfer_list);
 
-				if (dd->qup_ver &&
-					t->cs_change == nxt->cs_change)
-					write_force_cs(dd, 1);
-				else if (dd->qup_ver)
-					write_force_cs(dd, 0);
-			}
+	get_transfer_length(dd);
+	if (dd->qup_ver || (dd->multi_xfr && !dd->read_len && !dd->write_len)) {
 
-			dd->cur_msg_len = dd->cur_transfer->len;
-			msm_spi_process_transfer(dd);
-		}
-	} else {
-		dd->cur_transfer = list_first_entry(&dd->cur_msg->transfers,
-						    struct spi_transfer,
-						    transfer_list);
-		get_transfer_length(dd);
-		if (dd->multi_xfr && !dd->read_len && !dd->write_len) {
-			/*
-			 * Handling of multi-transfers.
-			 * FIFO mode is used by default
-			 */
-			list_for_each_entry(dd->cur_transfer,
-					    &dd->cur_msg->transfers,
-					    transfer_list) {
-				if (!dd->cur_transfer->len)
-					goto error;
-				if (xfrs_grped) {
-					xfrs_grped--;
-					continue;
-				} else {
-					dd->read_len = dd->write_len = 0;
-					xfrs_grped = combine_transfers(dd);
-				}
+		if (dd->qup_ver)
+			write_force_cs(dd, 0);
 
-				dd->cur_tx_transfer = dd->cur_transfer;
-				dd->cur_rx_transfer = dd->cur_transfer;
-				msm_spi_process_transfer(dd);
+		/*
+		 * Handling of multi-transfers.
+		 * FIFO mode is used by default
+		 */
+		list_for_each_entry(dd->cur_transfer,
+					&dd->cur_msg->transfers,
+					transfer_list) {
+			if (!dd->cur_transfer->len)
+				goto error;
+			if (xfrs_grped) {
 				xfrs_grped--;
-			}
-		} else {
-			/* Handling of a single transfer or
-			 * WR-WR or WR-RD transfers
-			 */
-			if ((!dd->cur_msg->is_dma_mapped) &&
-			    (msm_spi_use_dma(dd, dd->cur_transfer,
-					dd->cur_transfer->bits_per_word))) {
-				/* Mapping of DMA buffers */
-				int ret = msm_spi_dma_map_buffers(dd);
-				if (ret < 0) {
-					dd->cur_msg->status = ret;
-					goto error;
-				}
+				continue;
+			} else {
+				dd->read_len = dd->write_len = 0;
+				xfrs_grped = combine_transfers(dd);
+				dd->num_xfrs_grped = xfrs_grped;
+				if (dd->qup_ver)
+					write_force_cs(dd, 1);
 			}
 
 			dd->cur_tx_transfer = dd->cur_transfer;
 			dd->cur_rx_transfer = dd->cur_transfer;
 			msm_spi_process_transfer(dd);
+			if (dd->qup_ver && !dd->xfrs_delay_usec)
+				write_force_cs(dd, 0);
+			xfrs_grped--;
 		}
+	} else {
+		/* Handling of a single transfer or
+		 * WR-WR or WR-RD transfers
+		 */
+		if ((!dd->cur_msg->is_dma_mapped) &&
+			(msm_spi_use_dma(dd, dd->cur_transfer,
+				dd->cur_transfer->bits_per_word))) {
+			/* Mapping of DMA buffers */
+			int ret = msm_spi_dma_map_buffers(dd);
+			if (ret < 0) {
+				dd->cur_msg->status = ret;
+				goto error;
+			}
+		}
+
+		dd->cur_tx_transfer = dd->cur_transfer;
+		dd->cur_rx_transfer = dd->cur_transfer;
+		dd->num_xfrs_grped = 1;
+		msm_spi_process_transfer(dd);
 	}
 
 	return;
 
 error:
-	if (dd->cs_gpios[cs_num].valid) {
-		gpio_free(dd->cs_gpios[cs_num].gpio_num);
-		dd->cs_gpios[cs_num].valid = 0;
-	}
+	msm_spi_free_cs_gpio(dd);
 }
 
-/* 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);
 
@@ -1982,27 +2194,26 @@
 	if (dd->use_rlock)
 		remote_mutex_lock(&dd->r_lock);
 
-	if (!msm_spi_is_valid_state(dd)) {
+	spin_lock_irqsave(&dd->queue_lock, flags);
+	dd->transfer_pending = 1;
+	spin_unlock_irqrestore(&dd->queue_lock, flags);
+
+	if (dd->suspended || !msm_spi_is_valid_state(dd)) {
 		dev_err(dd->dev, "%s: SPI operational state not valid\n",
 			__func__);
 		status_error = 1;
 	}
-
 	spin_lock_irqsave(&dd->queue_lock, flags);
 	dd->transfer_pending = 1;
-	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)
+	dd->cur_msg = msg;
+	spin_unlock_irqrestore(&dd->queue_lock, flags);
+
+	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);
 
@@ -2011,44 +2222,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;
 }
 
@@ -2700,6 +2900,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},
 		};
 
@@ -2793,7 +2995,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);
 
@@ -2833,6 +3039,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) {
@@ -2894,13 +3101,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)) {
@@ -3077,8 +3277,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:
@@ -3241,7 +3439,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..a0c399b 100644
--- a/drivers/spi/spi_qsd.h
+++ b/drivers/spi/spi_qsd.h
@@ -291,6 +291,10 @@
 	struct msm_spi_bam_pipe  prod;
 	struct msm_spi_bam_pipe  cons;
 	bool                     deregister_required;
+	u32			 curr_rx_bytes_recvd;
+	u32			 curr_tx_bytes_sent;
+	u32			 bam_rx_len;
+	u32			 bam_tx_len;
 };
 
 struct msm_spi {
@@ -300,9 +304,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;
@@ -391,6 +392,8 @@
 	struct spi_cs_gpio       cs_gpios[ARRAY_SIZE(spi_cs_rsrcs)];
 	enum msm_spi_qup_version qup_ver;
 	int			 max_trfr_len;
+	int			 num_xfrs_grped;
+	u16			 xfrs_delay_usec;
 };
 
 /* Forward declaration */
diff --git a/drivers/spmi/qpnp-int.c b/drivers/spmi/qpnp-int.c
index 3e14333..9fc7299 100644
--- a/drivers/spmi/qpnp-int.c
+++ b/drivers/spmi/qpnp-int.c
@@ -184,6 +184,22 @@
 	return 0;
 }
 
+static void qpnpint_irq_ack(struct irq_data *d)
+{
+	struct q_irq_data *irq_d = irq_data_get_irq_chip_data(d);
+	int rc;
+
+	pr_debug("hwirq %lu irq: %d\n", d->hwirq, d->irq);
+
+	rc = qpnpint_spmi_write(irq_d, QPNPINT_REG_LATCHED_CLR,
+				&irq_d->mask_shift, 1);
+	if (rc) {
+		pr_err_ratelimited("spmi write failure on irq %d, rc=%d\n",
+				d->irq, rc);
+		return;
+	}
+}
+
 static void qpnpint_irq_mask(struct irq_data *d)
 {
 	struct q_irq_data *irq_d = irq_data_get_irq_chip_data(d);
@@ -223,44 +239,10 @@
 
 static void qpnpint_irq_mask_ack(struct irq_data *d)
 {
-	struct q_irq_data *irq_d = irq_data_get_irq_chip_data(d);
-	struct q_chip_data *chip_d = irq_d->chip_d;
-	struct q_perip_data *per_d = irq_d->per_d;
-	int rc;
-	uint8_t prev_int_en = per_d->int_en;
-
 	pr_debug("hwirq %lu irq: %d\n", d->hwirq, d->irq);
 
-	if (!chip_d->cb) {
-		pr_warn_ratelimited("No arbiter on bus=%u slave=%u offset=%u\n",
-				chip_d->bus_nr, irq_d->spmi_slave,
-				irq_d->spmi_offset);
-		return;
-	}
-
-	per_d->int_en &= ~irq_d->mask_shift;
-
-	if (prev_int_en && !(per_d->int_en)) {
-		/*
-		 * no interrupt on this peripheral is enabled
-		 * ask the arbiter to ignore this peripheral
-		 */
-		qpnpint_arbiter_op(d, irq_d, chip_d->cb->mask);
-	}
-
-	rc = qpnpint_spmi_write(irq_d, QPNPINT_REG_EN_CLR,
-							&irq_d->mask_shift, 1);
-	if (rc) {
-		pr_err("spmi failure on irq %d\n", d->irq);
-		return;
-	}
-
-	rc = qpnpint_spmi_write(irq_d, QPNPINT_REG_LATCHED_CLR,
-							&irq_d->mask_shift, 1);
-	if (rc) {
-		pr_err("spmi failure on irq %d\n", d->irq);
-		return;
-	}
+	qpnpint_irq_mask(d);
+	qpnpint_irq_ack(d);
 }
 
 static void qpnpint_irq_unmask(struct irq_data *d)
@@ -269,6 +251,7 @@
 	struct q_chip_data *chip_d = irq_d->chip_d;
 	struct q_perip_data *per_d = irq_d->per_d;
 	int rc;
+	uint8_t buf[2];
 	uint8_t prev_int_en = per_d->int_en;
 
 	pr_debug("hwirq %lu irq: %d\n", d->hwirq, d->irq);
@@ -289,12 +272,29 @@
 		 */
 		qpnpint_arbiter_op(d, irq_d, chip_d->cb->unmask);
 	}
-	rc = qpnpint_spmi_write(irq_d, QPNPINT_REG_EN_SET,
-					&irq_d->mask_shift, 1);
+
+	/* Check the current state of the interrupt enable bit. */
+	rc = qpnpint_spmi_read(irq_d, QPNPINT_REG_EN_SET, buf, 1);
 	if (rc) {
-		pr_err("spmi failure on irq %d\n", d->irq);
+		pr_err("SPMI read failure for IRQ %d, rc=%d\n", d->irq, rc);
 		return;
 	}
+
+	if (!(buf[0] & irq_d->mask_shift)) {
+		/*
+		 * Since the interrupt is currently disabled, write to both the
+		 * LATCHED_CLR and EN_SET registers so that a spurious interrupt
+		 * cannot be triggered when the interrupt is enabled.
+		 */
+		buf[0] = irq_d->mask_shift;
+		buf[1] = irq_d->mask_shift;
+		rc = qpnpint_spmi_write(irq_d, QPNPINT_REG_LATCHED_CLR, buf, 2);
+		if (rc) {
+			pr_err("SPMI write failure for IRQ %d, rc=%d\n", d->irq,
+				rc);
+			return;
+		}
+	}
 }
 
 static int qpnpint_irq_set_type(struct irq_data *d, unsigned int flow_type)
@@ -336,6 +336,11 @@
 		return rc;
 	}
 
+	if (flow_type & IRQ_TYPE_EDGE_BOTH)
+		__irq_set_handler_locked(d->irq, handle_edge_irq);
+	else
+		__irq_set_handler_locked(d->irq, handle_level_irq);
+
 	return 0;
 }
 
@@ -363,6 +368,7 @@
 
 static struct irq_chip qpnpint_chip = {
 	.name		= "qpnp-int",
+	.irq_ack	= qpnpint_irq_ack,
 	.irq_mask	= qpnpint_irq_mask,
 	.irq_mask_ack	= qpnpint_irq_mask_ack,
 	.irq_unmask	= qpnpint_irq_unmask,
diff --git a/drivers/spmi/spmi-dbgfs.c b/drivers/spmi/spmi-dbgfs.c
index 27df09333..b0a354b 100644
--- a/drivers/spmi/spmi-dbgfs.c
+++ b/drivers/spmi/spmi-dbgfs.c
@@ -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
@@ -48,9 +48,9 @@
 
 /* Log buffer */
 struct spmi_log_buffer {
-	u32  rpos;	/* Current 'read' position in buffer */
-	u32  wpos;	/* Current 'write' position in buffer */
-	u32  len;	/* Length of the buffer */
+	size_t rpos;	/* Current 'read' position in buffer */
+	size_t wpos;	/* Current 'write' position in buffer */
+	size_t len;	/* Length of the buffer */
 	char data[0];	/* Log buffer */
 };
 
@@ -583,10 +583,10 @@
 
 	pr_debug("Creating SPMI debugfs file-system\n");
 	root = debugfs_create_dir(DFS_ROOT_NAME, NULL);
-	if (IS_ERR(root)) {
+	if (IS_ERR_OR_NULL(root)) {
 		pr_err("Error creating top level directory err:%ld",
 			(long)root);
-		if ((int)root == -ENODEV)
+		if (PTR_ERR(root) == -ENODEV)
 			pr_err("debugfs is not enabled in the kernel");
 		return NULL;
 	}
diff --git a/drivers/spmi/spmi-pmic-arb.c b/drivers/spmi/spmi-pmic-arb.c
index bc328e0..e3284d5 100644
--- a/drivers/spmi/spmi-pmic-arb.c
+++ b/drivers/spmi/spmi-pmic-arb.c
@@ -223,7 +223,9 @@
 	if (opc < SPMI_CMD_RESET || opc > SPMI_CMD_WAKEUP)
 		return -EINVAL;
 
-	cmd = ((opc | 0x40) << 27) | ((sid & 0xf) << 20);
+	opc -= SPMI_CMD_RESET - PMIC_ARB_OP_RESET;
+
+	cmd = (opc << 27) | ((sid & 0xf) << 20);
 
 	spin_lock_irqsave(&pmic_arb->lock, flags);
 	pmic_arb_write(pmic_arb, PMIC_ARB_CMD(pmic_arb->channel), cmd);
diff --git a/drivers/spmi/spmi.c b/drivers/spmi/spmi.c
index 348ed3e..43f2710 100644
--- a/drivers/spmi/spmi.c
+++ b/drivers/spmi/spmi.c
@@ -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
@@ -809,8 +809,8 @@
 	if (ret)
 		goto exit;
 
-	dev_dbg(&ctrl->dev, "Bus spmi-%d registered: dev:%x\n",
-					ctrl->nr, (u32)&ctrl->dev);
+	dev_dbg(&ctrl->dev, "Bus spmi-%d registered: dev:0x%p\n",
+					ctrl->nr, &ctrl->dev);
 
 	spmi_dfs_add_controller(ctrl);
 	return 0;
diff --git a/drivers/staging/android/ashmem.c b/drivers/staging/android/ashmem.c
index 42a5a71..41ebc1c 100644
--- a/drivers/staging/android/ashmem.c
+++ b/drivers/staging/android/ashmem.c
@@ -224,21 +224,29 @@
 
 	/* If size is not set, or set to 0, always return EOF. */
 	if (asma->size == 0)
-		goto out;
+		goto out_unlock;
 
 	if (!asma->file) {
 		ret = -EBADF;
-		goto out;
+		goto out_unlock;
 	}
 
+	mutex_unlock(&ashmem_mutex);
+
+	/*
+	 * asma and asma->file are used outside the lock here.  We assume
+	 * once asma->file is set it will never be changed, and will not
+	 * be destroyed until all references to the file are dropped and
+	 * ashmem_release is called.
+	 */
 	ret = asma->file->f_op->read(asma->file, buf, len, pos);
-	if (ret < 0)
-		goto out;
+	if (ret >= 0) {
+		/** Update backing file pos, since f_ops->read() doesn't */
+		asma->file->f_pos = *pos;
+	}
+	return ret;
 
-	/** Update backing file pos, since f_ops->read() doesn't */
-	asma->file->f_pos = *pos;
-
-out:
+out_unlock:
 	mutex_unlock(&ashmem_mutex);
 	return ret;
 }
@@ -357,7 +365,9 @@
 	if (!sc->nr_to_scan)
 		return lru_count;
 
-	mutex_lock(&ashmem_mutex);
+	if (!mutex_trylock(&ashmem_mutex))
+		return -1;
+
 	list_for_each_entry_safe(range, next, &ashmem_lru_list, lru) {
 		struct inode *inode = range->asma->file->f_dentry->d_inode;
 		loff_t start = range->pgstart * PAGE_SIZE;
@@ -406,50 +416,68 @@
 
 static int set_name(struct ashmem_area *asma, void __user *name)
 {
+	int len;
 	int ret = 0;
+	char local_name[ASHMEM_NAME_LEN];
 
+	/*
+	 * Holding the ashmem_mutex while doing a copy_from_user might cause
+	 * an data abort which would try to access mmap_sem. If another
+	 * thread has invoked ashmem_mmap then it will be holding the
+	 * semaphore and will be waiting for ashmem_mutex, there by leading to
+	 * deadlock. We'll release the mutex  and take the name to a local
+	 * variable that does not need protection and later copy the local
+	 * variable to the structure member with lock held.
+	 */
+	len = strncpy_from_user(local_name, name, ASHMEM_NAME_LEN);
+	if (len < 0)
+		return len;
+	if (len == ASHMEM_NAME_LEN)
+		local_name[ASHMEM_NAME_LEN - 1] = '\0';
 	mutex_lock(&ashmem_mutex);
-
 	/* cannot change an existing mapping's name */
-	if (unlikely(asma->file)) {
+	if (unlikely(asma->file))
 		ret = -EINVAL;
-		goto out;
-	}
+	else
+		strcpy(asma->name + ASHMEM_NAME_PREFIX_LEN, local_name);
 
-	if (unlikely(copy_from_user(asma->name + ASHMEM_NAME_PREFIX_LEN,
-				    name, ASHMEM_NAME_LEN)))
-		ret = -EFAULT;
-	asma->name[ASHMEM_FULL_NAME_LEN-1] = '\0';
-
-out:
 	mutex_unlock(&ashmem_mutex);
-
 	return ret;
 }
 
 static int get_name(struct ashmem_area *asma, void __user *name)
 {
 	int ret = 0;
+	size_t len;
+	/*
+	 * Have a local variable to which we'll copy the content
+	 * from asma with the lock held. Later we can copy this to the user
+	 * space safely without holding any locks. So even if we proceed to
+	 * wait for mmap_sem, it won't lead to deadlock.
+	 */
+	char local_name[ASHMEM_NAME_LEN];
 
 	mutex_lock(&ashmem_mutex);
 	if (asma->name[ASHMEM_NAME_PREFIX_LEN] != '\0') {
-		size_t len;
 
 		/*
 		 * Copying only `len', instead of ASHMEM_NAME_LEN, bytes
 		 * prevents us from revealing one user's stack to another.
 		 */
 		len = strlen(asma->name + ASHMEM_NAME_PREFIX_LEN) + 1;
-		if (unlikely(copy_to_user(name,
-				asma->name + ASHMEM_NAME_PREFIX_LEN, len)))
-			ret = -EFAULT;
+		memcpy(local_name, asma->name + ASHMEM_NAME_PREFIX_LEN, len);
 	} else {
-		if (unlikely(copy_to_user(name, ASHMEM_NAME_DEF,
-					  sizeof(ASHMEM_NAME_DEF))))
-			ret = -EFAULT;
+		len = sizeof(ASHMEM_NAME_DEF);
+		memcpy(local_name, ASHMEM_NAME_DEF, len);
 	}
 	mutex_unlock(&ashmem_mutex);
 
+	/*
+	 * Now we are just copying from the stack variable to userland
+	 * No lock held
+	 */
+	if (unlikely(copy_to_user(name, local_name, len)))
+		ret = -EFAULT;
 	return ret;
 }
 
diff --git a/drivers/thermal/msm_thermal.c b/drivers/thermal/msm_thermal.c
index c366086..7b623e4 100644
--- a/drivers/thermal/msm_thermal.c
+++ b/drivers/thermal/msm_thermal.c
@@ -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
@@ -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;
@@ -156,7 +190,7 @@
 
 #define VDD_RES_RO_ATTRIB(_rail, ko_attr, j, _name) \
 	ko_attr.attr.name = __stringify(_name); \
-	ko_attr.attr.mode = 444; \
+	ko_attr.attr.mode = 0444; \
 	ko_attr.show = vdd_rstr_reg_##_name##_show; \
 	ko_attr.store = NULL; \
 	sysfs_attr_init(&ko_attr.attr); \
@@ -164,7 +198,7 @@
 
 #define VDD_RES_RW_ATTRIB(_rail, ko_attr, j, _name) \
 	ko_attr.attr.name = __stringify(_name); \
-	ko_attr.attr.mode = 644; \
+	ko_attr.attr.mode = 0644; \
 	ko_attr.show = vdd_rstr_reg_##_name##_show; \
 	ko_attr.store = vdd_rstr_reg_##_name##_store; \
 	sysfs_attr_init(&ko_attr.attr); \
@@ -181,7 +215,7 @@
 
 #define OCR_RW_ATTRIB(_rail, ko_attr, j, _name) \
 	ko_attr.attr.name = __stringify(_name); \
-	ko_attr.attr.mode = 644; \
+	ko_attr.attr.mode = 0644; \
 	ko_attr.show = ocr_reg_##_name##_show; \
 	ko_attr.store = ocr_reg_##_name##_store; \
 	sysfs_attr_init(&ko_attr.attr); \
@@ -189,7 +223,7 @@
 
 #define PSM_RW_ATTRIB(_rail, ko_attr, j, _name) \
 	ko_attr.attr.name = __stringify(_name); \
-	ko_attr.attr.mode = 644; \
+	ko_attr.attr.mode = 0644; \
 	ko_attr.show = psm_reg_##_name##_show; \
 	ko_attr.store = psm_reg_##_name##_store; \
 	sysfs_attr_init(&ko_attr.attr); \
@@ -425,7 +459,7 @@
 
 static struct vdd_rstr_enable vdd_rstr_en = {
 	.ko_attr.attr.name = __stringify(enabled),
-	.ko_attr.attr.mode = 644,
+	.ko_attr.attr.mode = 0644,
 	.ko_attr.show = vdd_rstr_en_show,
 	.ko_attr.store = vdd_rstr_en_store,
 	.enabled = 1,
@@ -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;
@@ -904,7 +970,9 @@
 		return -EINVAL;
 
 	while (!kthread_should_stop()) {
-		wait_for_completion(&hotplug_notify_complete);
+		while (wait_for_completion_interruptible(
+			&hotplug_notify_complete) != 0)
+			;
 		INIT_COMPLETION(hotplug_notify_complete);
 		mask = 0;
 
@@ -942,7 +1010,6 @@
 
 static int do_ocr(void)
 {
-	struct tsens_device tsens_dev;
 	long temp = 0;
 	int ret = 0;
 	int i = 0, j = 0;
@@ -953,11 +1020,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 +1065,6 @@
 
 static int do_vdd_restriction(void)
 {
-	struct tsens_device tsens_dev;
 	long temp = 0;
 	int ret = 0;
 	int i = 0;
@@ -1015,11 +1080,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 +1112,6 @@
 
 static int do_psm(void)
 {
-	struct tsens_device tsens_dev;
 	long temp = 0;
 	int ret = 0;
 	int i = 0;
@@ -1056,11 +1119,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 +1199,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 +1224,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 +1318,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 +1328,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 +1368,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;
 
@@ -1346,7 +1406,9 @@
 	uint32_t cpu = 0, max_freq_req = 0, min_freq_req = 0;
 
 	while (!kthread_should_stop()) {
-		wait_for_completion(&freq_mitigation_complete);
+		while (wait_for_completion_interruptible(
+			&freq_mitigation_complete) != 0)
+			;
 		INIT_COMPLETION(freq_mitigation_complete);
 
 		get_online_cpus();
@@ -1501,6 +1563,217 @@
 	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()) {
+		while (wait_for_completion_interruptible(
+			&thermal_monitor_complete) != 0)
+			;
+		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 +1784,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 +1798,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 +1897,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,25 +2050,58 @@
 	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;
 
+	for_each_possible_cpu(cpu) {
+		cpus[cpu].cpu = cpu;
+		cpus[cpu].offline = 0;
+		cpus[cpu].user_offline = 0;
+		cpus[cpu].hotplug_thresh_clear = false;
+		cpus[cpu].max_freq = false;
+		cpus[cpu].user_max_freq = UINT_MAX;
+		cpus[cpu].user_min_freq = 0;
+		cpus[cpu].limited_max_freq = UINT_MAX;
+		cpus[cpu].limited_min_freq = 0;
+		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;
-	for_each_possible_cpu(cpu) {
-		cpus[cpu].limited_max_freq = UINT_MAX;
-		cpus[cpu].limited_min_freq = 0;
-	}
+	polling_enabled = 1;
 	ret = cpufreq_register_notifier(&msm_thermal_cpufreq_notifier,
 			CPUFREQ_POLICY_NOTIFIER);
 	if (ret)
@@ -2232,6 +2551,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:
@@ -2426,17 +2750,13 @@
 
 	key = "qcom,cpu-sensors";
 	cpu_cnt = of_property_count_strings(node, key);
-	if (cpu_cnt != num_possible_cpus()) {
-		pr_err("%s: Wrong number of cpu\n", KBUILD_MODNAME);
+	if (cpu_cnt < num_possible_cpus()) {
+		pr_err("%s: Wrong number of cpu sensors\n", KBUILD_MODNAME);
 		ret = -EINVAL;
 		goto hotplug_node_fail;
 	}
 
 	for_each_possible_cpu(cpu) {
-		cpus[cpu].cpu = cpu;
-		cpus[cpu].offline = 0;
-		cpus[cpu].user_offline = 0;
-		cpus[cpu].hotplug_thresh_clear = false;
 		ret = of_property_read_string_index(node, key, cpu,
 				&cpus[cpu].sensor_type);
 		if (ret)
@@ -2470,7 +2790,6 @@
 {
 	char *key = NULL;
 	int ret = 0;
-	uint32_t cpu;
 
 	key = "qcom,freq-mitigation-temp";
 	ret = of_property_read_u32(node, key, &data->freq_mitig_temp_degc);
@@ -2494,14 +2813,6 @@
 		goto PROBE_FREQ_EXIT;
 
 	freq_mitigation_enabled = 1;
-	for_each_possible_cpu(cpu) {
-		cpus[cpu].max_freq = false;
-		cpus[cpu].user_max_freq = UINT_MAX;
-		cpus[cpu].user_min_freq = 0;
-		cpus[cpu].limited_max_freq = UINT_MAX;
-		cpus[cpu].limited_min_freq = 0;
-		cpus[cpu].freq_thresh_clear = false;
-	}
 
 PROBE_FREQ_EXIT:
 	if (ret) {
@@ -2521,6 +2832,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);
@@ -2589,6 +2903,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:
@@ -2602,6 +2922,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;
 }
 
@@ -2637,6 +2963,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/thermal/qpnp-adc-tm.c b/drivers/thermal/qpnp-adc-tm.c
index efb87a9..eb647fa 100644
--- a/drivers/thermal/qpnp-adc-tm.c
+++ b/drivers/thermal/qpnp-adc-tm.c
@@ -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
@@ -471,16 +471,30 @@
 		struct qpnp_adc_tm_chip *chip, uint32_t btm_chan,
 		struct qpnp_vadc_chan_properties *chan_prop)
 {
-	int rc;
-	u8 meas_interval_timer2 = 0;
+	int rc, chan_idx = 0, i = 0;
+	bool chan_found = false;
+	u8 meas_interval_timer2 = 0, timer_interval_store = 0;
 	uint32_t btm_chan_idx = 0;
 
-	/* Configure kernel clients to timer1 */
-	switch (chan_prop->timer_select) {
+	while (i < chip->max_channels_available) {
+		if (chip->sensor[i].btm_channel_num == btm_chan) {
+			chan_idx = i;
+			chan_found = true;
+			i++;
+		} else
+			i++;
+	}
+
+	if (!chan_found) {
+		pr_err("Channel not found\n");
+		return -EINVAL;
+	}
+
+	switch (chip->sensor[chan_idx].timer_select) {
 	case ADC_MEAS_TIMER_SELECT1:
 		rc = qpnp_adc_tm_write_reg(chip,
 				QPNP_ADC_TM_MEAS_INTERVAL_CTL,
-				chan_prop->meas_interval1);
+				chip->sensor[chan_idx].meas_interval);
 		if (rc < 0) {
 			pr_err("timer1 configure failed\n");
 			return rc;
@@ -495,9 +509,10 @@
 			pr_err("timer2 configure read failed\n");
 			return rc;
 		}
-		meas_interval_timer2 |=
-			(chan_prop->meas_interval2 <<
-			QPNP_ADC_TM_MEAS_INTERVAL_CTL2_SHIFT);
+		timer_interval_store = chip->sensor[chan_idx].meas_interval;
+		timer_interval_store <<= QPNP_ADC_TM_MEAS_INTERVAL_CTL2_SHIFT;
+		timer_interval_store &= QPNP_ADC_TM_MEAS_INTERVAL_CTL2_MASK;
+		meas_interval_timer2 |= timer_interval_store;
 		rc = qpnp_adc_tm_write_reg(chip,
 			QPNP_ADC_TM_MEAS_INTERVAL_CTL2,
 			meas_interval_timer2);
@@ -514,8 +529,9 @@
 			pr_err("timer3 read failed\n");
 			return rc;
 		}
-		chan_prop->meas_interval2 = ADC_MEAS3_INTERVAL_1S;
-		meas_interval_timer2 |= chan_prop->meas_interval2;
+		timer_interval_store = chip->sensor[chan_idx].meas_interval;
+		timer_interval_store &= QPNP_ADC_TM_MEAS_INTERVAL_CTL3_MASK;
+		meas_interval_timer2 |= timer_interval_store;
 		rc = qpnp_adc_tm_write_reg(chip,
 			QPNP_ADC_TM_MEAS_INTERVAL_CTL2,
 			meas_interval_timer2);
@@ -535,7 +551,18 @@
 		pr_err("Invalid btm channel idx\n");
 		return rc;
 	}
-	adc_tm_data[btm_chan_idx].meas_interval_ctl = chan_prop->timer_select;
+	rc = qpnp_adc_tm_write_reg(chip,
+			adc_tm_data[btm_chan_idx].meas_interval_ctl,
+				chip->sensor[chan_idx].timer_select);
+	if (rc < 0) {
+		pr_err("TM channel timer configure failed\n");
+		return rc;
+	}
+
+	pr_debug("timer select:%d, timer_value_within_select:%d, channel:%x\n",
+			chip->sensor[chan_idx].timer_select,
+			chip->sensor[chan_idx].meas_interval,
+			btm_chan);
 
 	return rc;
 }
@@ -954,10 +981,6 @@
 			chip->adc->adc_channels[channel].fast_avg_setup;
 		chip->adc->amux_prop->mode_sel =
 			ADC_OP_MEASUREMENT_INTERVAL << QPNP_OP_MODE_SHIFT;
-		chip->adc->amux_prop->chan_prop->timer_select =
-					ADC_MEAS_TIMER_SELECT1;
-		chip->adc->amux_prop->chan_prop->meas_interval1 =
-						ADC_MEAS1_INTERVAL_1S;
 		chip->adc->amux_prop->chan_prop->low_thr = adc_tm->low_thr;
 		chip->adc->amux_prop->chan_prop->high_thr = adc_tm->high_thr;
 		chip->adc->amux_prop->chan_prop->tm_channel_select =
@@ -1673,8 +1696,6 @@
 			chip->adc->adc_channels[dt_index].fast_avg_setup;
 	chip->adc->amux_prop->mode_sel =
 		ADC_OP_MEASUREMENT_INTERVAL << QPNP_OP_MODE_SHIFT;
-	chip->adc->amux_prop->chan_prop->meas_interval1 =
-						ADC_MEAS1_INTERVAL_1S;
 	adc_tm_rscale_fn[scale_type].chan(chip->vadc_dev, param,
 			&chip->adc->amux_prop->chan_prop->low_thr,
 			&chip->adc->amux_prop->chan_prop->high_thr);
@@ -1682,8 +1703,6 @@
 				chip->adc->amux_prop->chan_prop);
 	chip->adc->amux_prop->chan_prop->tm_channel_select =
 				chip->sensor[dt_index].btm_channel_num;
-	chip->adc->amux_prop->chan_prop->timer_select =
-					ADC_MEAS_TIMER_SELECT1;
 	chip->adc->amux_prop->chan_prop->state_request =
 					param->state_request;
 	rc = qpnp_adc_tm_configure(chip, chip->adc->amux_prop);
@@ -1880,7 +1899,7 @@
 
 	for_each_child_of_node(node, child) {
 		char name[25];
-		int btm_channel_num;
+		int btm_channel_num, timer_select = 0;
 
 		rc = of_property_read_u32(child,
 				"qcom,btm-channel-number", &btm_channel_num);
@@ -1888,6 +1907,28 @@
 			pr_err("Invalid btm channel number\n");
 			goto fail;
 		}
+		rc = of_property_read_u32(child,
+				"qcom,meas-interval-timer-idx", &timer_select);
+		if (rc) {
+			pr_debug("Default to timer1 with interval of 1 sec\n");
+			chip->sensor[sen_idx].timer_select =
+							ADC_MEAS_TIMER_SELECT1;
+			chip->sensor[sen_idx].meas_interval =
+							ADC_MEAS1_INTERVAL_1S;
+		} else {
+			if (timer_select >= ADC_MEAS_TIMER_NUM) {
+				pr_err("Invalid timer selection number\n");
+				goto fail;
+			}
+			chip->sensor[sen_idx].timer_select = timer_select;
+			if (timer_select == ADC_MEAS_TIMER_SELECT2)
+				chip->sensor[sen_idx].meas_interval =
+						ADC_MEAS2_INTERVAL_500MS;
+			if (timer_select == ADC_MEAS_TIMER_SELECT3)
+				chip->sensor[sen_idx].meas_interval =
+						ADC_MEAS3_INTERVAL_4S;
+		}
+
 		chip->sensor[sen_idx].btm_channel_num = btm_channel_num;
 		chip->sensor[sen_idx].vadc_channel_num =
 				chip->adc->adc_channels[sen_idx].channel_num;
diff --git a/drivers/thermal/thermal_sys.c b/drivers/thermal/thermal_sys.c
index 739696d..8cd70ac 100644
--- a/drivers/thermal/thermal_sys.c
+++ b/drivers/thermal/thermal_sys.c
@@ -70,16 +70,19 @@
 
 	list_for_each_entry_safe(pos, var, &sensor_info_list, sensor_list) {
 		if (pos->sensor_id == sensor_id)
-			break;
+			return pos;
 	}
 
-	return pos;
+	return NULL;
 }
 
 int sensor_get_id(char *name)
 {
 	struct sensor_info *pos, *var;
 
+	if (!name)
+		return -ENODEV;
+
 	list_for_each_entry_safe(pos, var, &sensor_info_list, sensor_list) {
 		if (!strcmp(pos->tz->type, name))
 			return pos->sensor_id;
@@ -89,13 +92,43 @@
 }
 EXPORT_SYMBOL(sensor_get_id);
 
+static void init_sensor_trip(struct sensor_info *sensor)
+{
+	int ret = 0, i = 0;
+	enum thermal_trip_type type;
+
+	for (i = 0; ((sensor->max_idx == -1) ||
+		(sensor->min_idx == -1)) &&
+		(sensor->tz->ops->get_trip_type) &&
+		(i < sensor->tz->trips); i++) {
+
+		sensor->tz->ops->get_trip_type(sensor->tz, i, &type);
+		if (type == THERMAL_TRIP_CONFIGURABLE_HI)
+			sensor->max_idx = i;
+		if (type == THERMAL_TRIP_CONFIGURABLE_LOW)
+			sensor->min_idx = i;
+		type = 0;
+	}
+
+	ret = sensor->tz->ops->get_trip_temp(sensor->tz,
+		sensor->min_idx, &sensor->threshold_min);
+	if (ret)
+		pr_err("Unable to get MIN trip temp. sensor:%d err:%d\n",
+				sensor->sensor_id, ret);
+
+	ret = sensor->tz->ops->get_trip_temp(sensor->tz,
+		sensor->max_idx, &sensor->threshold_max);
+	if (ret)
+		pr_err("Unable to get MAX trip temp. sensor:%d err:%d\n",
+				sensor->sensor_id, ret);
+}
+
 static int __update_sensor_thresholds(struct sensor_info *sensor)
 {
 	long max_of_low_thresh = LONG_MIN;
 	long min_of_high_thresh = LONG_MAX;
 	struct sensor_threshold *pos, *var;
-	enum thermal_trip_type type;
-	int i, ret = 0;
+	int ret = 0;
 
 	if (!sensor->tz->ops->set_trip_temp ||
 		!sensor->tz->ops->activate_trip_type ||
@@ -105,19 +138,8 @@
 		goto update_done;
 	}
 
-	for (i = 0; ((sensor->max_idx == -1) || (sensor->min_idx == -1)) &&
-		(sensor->tz->ops->get_trip_type) && (i < sensor->tz->trips);
-		i++) {
-		sensor->tz->ops->get_trip_type(sensor->tz, i, &type);
-		if (type == THERMAL_TRIP_CONFIGURABLE_HI)
-			sensor->max_idx = i;
-		if (type == THERMAL_TRIP_CONFIGURABLE_LOW)
-			sensor->min_idx = i;
-		sensor->tz->ops->get_trip_temp(sensor->tz,
-			THERMAL_TRIP_CONFIGURABLE_LOW, &sensor->threshold_min);
-		sensor->tz->ops->get_trip_temp(sensor->tz,
-			THERMAL_TRIP_CONFIGURABLE_HI, &sensor->threshold_max);
-	}
+	if ((sensor->max_idx == -1) || (sensor->min_idx == -1))
+		init_sensor_trip(sensor);
 
 	list_for_each_entry_safe(pos, var, &sensor->threshold_list, list) {
 		if (!pos->active)
@@ -365,7 +387,7 @@
 
 	sensor->sensor_id = tz->id;
 	sensor->tz = tz;
-	sensor->threshold_min = 0;
+	sensor->threshold_min = LONG_MIN;
 	sensor->threshold_max = LONG_MAX;
 	sensor->max_idx = -1;
 	sensor->min_idx = -1;
diff --git a/drivers/tty/serial/msm_serial_hs.c b/drivers/tty/serial/msm_serial_hs.c
index ecfacc0..a701ec8 100644
--- a/drivers/tty/serial/msm_serial_hs.c
+++ b/drivers/tty/serial/msm_serial_hs.c
@@ -3,7 +3,7 @@
  * MSM 7k High speed uart driver
  *
  * Copyright (c) 2008 Google Inc.
- * Copyright (c) 2007-2013, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2007-2014, The Linux Foundation. All rights reserved.
  * Modified: Nick Pelly <npelly@google.com>
  *
  * All source code in this file is licensed under the following license
@@ -94,7 +94,6 @@
 
 #define MSM_HS_DBG(x...) do { \
 	if (hs_serial_debug_mask >= DBG_LEV) { \
-		pr_debug(x); \
 		if (ipc_msm_hs_log_ctxt) \
 			ipc_log_string(ipc_msm_hs_log_ctxt, x); \
 	} \
@@ -102,7 +101,6 @@
 
 #define MSM_HS_INFO(x...) do { \
 	if (hs_serial_debug_mask >= INFO_LEV) {\
-		pr_info(x); \
 		if (ipc_msm_hs_log_ctxt) \
 			ipc_log_string(ipc_msm_hs_log_ctxt, x); \
 	} \
@@ -141,7 +139,7 @@
 	FLUSH_NONE,
 	FLUSH_DATA_READY,
 	FLUSH_DATA_INVALID,  /* values after this indicate invalid data */
-	FLUSH_IGNORE = FLUSH_DATA_INVALID,
+	FLUSH_IGNORE,
 	FLUSH_STOP,
 	FLUSH_SHUTDOWN,
 };
@@ -205,6 +203,8 @@
 	struct delayed_work flip_insert_work;
 	struct tasklet_struct tlet;
 	struct msm_hs_sps_ep_conn_data prod;
+	bool rx_cmd_queued;
+	bool rx_cmd_exec;
 };
 enum buffer_states {
 	NONE_PENDING = 0x0,
@@ -251,7 +251,6 @@
 	struct workqueue_struct *hsuart_wq; /* hsuart workqueue */
 	struct mutex clk_mutex; /* mutex to guard against clock off/clock on */
 	struct work_struct disconnect_rx_endpoint; /* disconnect rx_endpoint */
-	bool tty_flush_receive;
 	enum uart_core_type uart_type;
 	u32 bam_handle;
 	resource_size_t bam_mem;
@@ -271,6 +270,8 @@
 	int rx_count_callback;
 	bool rx_bam_inprogress;
 	unsigned int *reg_ptr;
+	wait_queue_head_t bam_disconnect_wait;
+
 };
 
 unsigned int regmap_nonblsp[UART_DM_LAST] = {
@@ -317,6 +318,7 @@
 		[UART_DM_TXFS] = 0x4c,
 		[UART_DM_RXFS] = 0x50,
 		[UART_DM_RX_TRANS_CTRL] = 0xcc,
+		[UART_DM_BCR] = 0xc8,
 };
 
 static struct of_device_id msm_hs_match_table[] = {
@@ -344,7 +346,6 @@
 #define BLSP_UART_CLK_FMAX 63160000
 
 static struct dentry *debug_base;
-static struct msm_hs_port q_uart_port[UARTDM_NR];
 static struct platform_driver msm_serial_hs_platform_driver;
 static struct uart_driver msm_hs_driver;
 static struct uart_ops msm_hs_ops;
@@ -352,6 +353,7 @@
 static void msm_serial_hs_rx_tlet(unsigned long tlet_ptr);
 static void flip_insert_work(struct work_struct *work);
 static void msm_hs_bus_voting(struct msm_hs_port *msm_uport, unsigned int vote);
+static struct msm_hs_port *msm_hs_get_hs_port(int port_index);
 
 #define UARTDM_TO_MSM(uart_port) \
 	container_of((uart_port), struct msm_hs_port, uport)
@@ -424,6 +426,7 @@
 			}
 		}
 		msm_uport->clk_state = MSM_HS_CLK_ON;
+		MSM_HS_DBG("%s: Clock ON successful\n", __func__);
 	}
 
 
@@ -432,71 +435,98 @@
 
 static void msm_hs_clock_unvote(struct msm_hs_port *msm_uport)
 {
-	int rc = atomic_dec_return(&msm_uport->clk_count);
+	int rc = atomic_read(&msm_uport->clk_count);
 
-	if (rc < 0) {
-		msm_hs_bus_voting(msm_uport, BUS_RESET);
+	if (rc <= 0) {
 		WARN(rc, "msm_uport->clk_count < 0!");
 		dev_err(msm_uport->uport.dev,
-			"%s: Clocks count invalid  [%d]\n", __func__,
-			atomic_read(&msm_uport->clk_count));
+			"%s: Clocks count invalid  [%d]\n", __func__, rc);
 		return;
 	}
 
+	rc = atomic_dec_return(&msm_uport->clk_count);
 	if (0 == rc) {
-		msm_hs_bus_voting(msm_uport, BUS_RESET);
 		/* Turn off the core clk and iface clk*/
 		clk_disable_unprepare(msm_uport->clk);
 		if (msm_uport->pclk)
 			clk_disable_unprepare(msm_uport->pclk);
+		/* Unvote the PNOC clock */
+		msm_hs_bus_voting(msm_uport, BUS_RESET);
 		msm_uport->clk_state = MSM_HS_CLK_OFF;
+		MSM_HS_DBG("%s: Clock OFF successful\n", __func__);
 	}
 }
 
+/* Check if the uport line number matches with user id stored in pdata.
+ * User id information is stored during initialization. This function
+ * ensues that the same device is selected */
+
+static struct msm_hs_port *get_matching_hs_port(struct platform_device *pdev)
+{
+	struct msm_serial_hs_platform_data *pdata = pdev->dev.platform_data;
+	struct msm_hs_port *msm_uport = msm_hs_get_hs_port(pdev->id);
+
+	if ((!msm_uport) || (msm_uport->uport.line != pdev->id
+	   && msm_uport->uport.line != pdata->userid)) {
+		MSM_HS_ERR("uport line number mismatch!");
+		WARN_ON(1);
+		return NULL;
+	}
+
+	return msm_uport;
+}
+
 static ssize_t show_clock(struct device *dev, struct device_attribute *attr,
 			  char *buf)
 {
 	int state = 1;
+	ssize_t ret = 0;
 	enum msm_hs_clk_states_e clk_state;
 	unsigned long flags;
-
 	struct platform_device *pdev = container_of(dev, struct
 						    platform_device, dev);
-	struct msm_hs_port *msm_uport = &q_uart_port[pdev->id];
+	struct msm_hs_port *msm_uport = get_matching_hs_port(pdev);
 
-	spin_lock_irqsave(&msm_uport->uport.lock, flags);
-	clk_state = msm_uport->clk_state;
-	spin_unlock_irqrestore(&msm_uport->uport.lock, flags);
+	/* This check should not fail */
+	if (msm_uport) {
+		spin_lock_irqsave(&msm_uport->uport.lock, flags);
+		clk_state = msm_uport->clk_state;
+		spin_unlock_irqrestore(&msm_uport->uport.lock, flags);
 
-	if (clk_state <= MSM_HS_CLK_OFF)
-		state = 0;
+		if (clk_state <= MSM_HS_CLK_OFF)
+			state = 0;
+		ret = snprintf(buf, PAGE_SIZE, "%d\n", state);
+	}
 
-	return snprintf(buf, PAGE_SIZE, "%d\n", state);
+	return ret;
 }
 
 static ssize_t set_clock(struct device *dev, struct device_attribute *attr,
 			 const char *buf, size_t count)
 {
 	int state;
+	ssize_t ret = 0;
 	struct platform_device *pdev = container_of(dev, struct
 						    platform_device, dev);
-	struct msm_hs_port *msm_uport = &q_uart_port[pdev->id];
+	struct msm_hs_port *msm_uport = get_matching_hs_port(pdev);
 
-	state = buf[0] - '0';
-	switch (state) {
-	case 0: {
-		msm_hs_request_clock_off(&msm_uport->uport);
-		break;
+	/* This check should not fail */
+	if (msm_uport) {
+		state = buf[0] - '0';
+		switch (state) {
+		case 0:
+			msm_hs_request_clock_off(&msm_uport->uport);
+			ret = count;
+			break;
+		case 1:
+			msm_hs_request_clock_on(&msm_uport->uport);
+			ret = count;
+			break;
+		default:
+			ret = -EINVAL;
+		}
 	}
-	case 1: {
-		msm_hs_request_clock_on(&msm_uport->uport);
-		break;
-	}
-	default: {
-		return -EINVAL;
-	}
-	}
-	return count;
+	return ret;
 }
 
 static DEVICE_ATTR(clock, S_IWUSR | S_IRUGO, show_clock, set_clock);
@@ -551,6 +581,25 @@
 	writel_relaxed(value, uport->membase + offset);
 }
 
+static int sps_rx_disconnect(struct sps_pipe *sps_pipe_handler)
+{
+	struct sps_connect config;
+	int ret;
+
+	ret = sps_get_config(sps_pipe_handler, &config);
+	if (ret) {
+		pr_err("%s: sps_get_config() failed ret %d\n", __func__, ret);
+		return ret;
+	}
+	config.options |= SPS_O_POLL;
+	ret = sps_set_config(sps_pipe_handler, &config);
+	if (ret) {
+		pr_err("%s: sps_set_config() failed ret %d\n", __func__, ret);
+		return ret;
+	}
+	return sps_disconnect(sps_pipe_handler);
+}
+
 static void hex_dump_ipc(char *prefix, char *string, int size)
 {
 	char linebuf[512];
@@ -564,22 +613,33 @@
 */
 static void dump_uart_hs_registers(struct msm_hs_port *msm_uport)
 {
-	msm_hs_clock_vote(msm_uport);
-	MSM_HS_DBG("============= UART Registers ================\n");
-	MSM_HS_DBG("UART_DM_MR1:%x\n", msm_hs_read(&(msm_uport->uport),
-		UART_DM_MR1));
-	MSM_HS_DBG("UART_DM_MR2:%x\n", msm_hs_read(&(msm_uport->uport),
-		UART_DM_MR2));
-	MSM_HS_DBG("UART_DM_IPR:%x\n", msm_hs_read(&(msm_uport->uport),
-		UART_DM_IPR));
-	MSM_HS_DBG("UART_DM_RFWR:%x\n", msm_hs_read(&(msm_uport->uport),
-		UART_DM_RFWR));
-	MSM_HS_DBG("UART_DM_SR:%x\n", msm_hs_read(&(msm_uport->uport),
-		UART_DM_SR));
-	MSM_HS_DBG("UART_DM_IMR: %x\n", msm_hs_read(&(msm_uport->uport),
-		UART_DM_IMR));
-	MSM_HS_DBG("=============================================\n");
-	msm_hs_clock_unvote(msm_uport);
+	struct uart_port *uport = &(msm_uport->uport);
+	if (msm_uport->clk_state != MSM_HS_CLK_ON) {
+		MSM_HS_WARN("%s: Failed.Clocks are OFF\n", __func__);
+		return;
+	}
+
+	MSM_HS_DBG(
+	"MR1:%x MR2:%x TFWR:%x RFWR:%x DMEN:%x IMR:%x MISR:%x NCF_TX:%x\n",
+	msm_hs_read(uport, UART_DM_MR1),
+	msm_hs_read(uport, UART_DM_MR2),
+	msm_hs_read(uport, UART_DM_TFWR),
+	msm_hs_read(uport, UART_DM_RFWR),
+	msm_hs_read(uport, UART_DM_DMEN),
+	msm_hs_read(uport, UART_DM_IMR),
+	msm_hs_read(uport, UART_DM_MISR),
+	msm_hs_read(uport, UART_DM_NCF_TX));
+	MSM_HS_INFO("SR:%x ISR:%x DMRX:%x RX_SNAP:%x TXFS:%x RXFS:%x\n",
+	msm_hs_read(uport, UART_DM_SR),
+	msm_hs_read(uport, UART_DM_ISR),
+	msm_hs_read(uport, UART_DM_DMRX),
+	msm_hs_read(uport, UART_DM_RX_TOTAL_SNAP),
+	msm_hs_read(uport, UART_DM_TXFS),
+	msm_hs_read(uport, UART_DM_RXFS));
+	MSM_HS_DBG("clk_req_state:0x%x rx.flush:%u\n",
+				msm_uport->clk_req_off_state,
+					msm_uport->rx.flush);
+	MSM_HS_DBG("clk_state:%d", msm_uport->clk_state);
 }
 
 static void msm_hs_release_port(struct uart_port *port)
@@ -723,9 +783,11 @@
 		return -EINVAL;
 	}
 
-	msm_uport = &q_uart_port[pdev->id];
-	dev = msm_uport->uport.dev;
+	msm_uport = get_matching_hs_port(pdev);
+	if (!msm_uport)
+		return -EINVAL;
 
+	dev = msm_uport->uport.dev;
 	sysfs_remove_file(&pdev->dev.kobj, &dev_attr_clock.attr);
 	debugfs_remove(msm_uport->loopback_dir);
 
@@ -1077,6 +1139,10 @@
 	struct msm_hs_rx *rx = &msm_uport->rx;
 	struct sps_pipe *sps_pipe_handle = rx->prod.pipe_handle;
 
+	if (msm_uport->clk_state != MSM_HS_CLK_ON) {
+		MSM_HS_WARN("%s: Failed.Clocks are OFF\n", __func__);
+		return;
+	}
 	mutex_lock(&msm_uport->clk_mutex);
 	msm_hs_write(uport, UART_DM_IMR, 0);
 
@@ -1090,6 +1156,8 @@
 	data = msm_hs_read(uport, UART_DM_MR1);
 	data &= ~UARTDM_MR1_RX_RDY_CTL_BMSK;
 	msm_hs_write(uport, UART_DM_MR1, data);
+	/* set RFR_N to high */
+	msm_hs_write(uport, UART_DM_CR, RFR_HIGH);
 
 	/*
 	 * Disable Rx channel of UARTDM
@@ -1176,10 +1244,12 @@
 
 	msm_hs_write(uport, UART_DM_CR, RESET_RX);
 	msm_hs_write(uport, UART_DM_CR, RESET_TX);
+	/* Issue TX BAM Start IFC command */
+	msm_hs_write(uport, UART_DM_CR, START_TX_BAM_IFC);
 
 	if (msm_uport->rx.flush == FLUSH_NONE) {
 		wake_lock(&msm_uport->rx.wake_lock);
-		msm_uport->rx.flush = FLUSH_IGNORE;
+		msm_uport->rx.flush = FLUSH_DATA_INVALID;
 		/*
 		 * Before using dmov APIs make sure that
 		 * previous writel are completed. Hence
@@ -1191,11 +1261,12 @@
 				ret = wait_event_timeout(msm_uport->rx.wait,
 					msm_uport->rx_bam_inprogress == false,
 					RX_FLUSH_COMPLETE_TIMEOUT);
-			ret = sps_disconnect(sps_pipe_handle);
+			ret = sps_rx_disconnect(sps_pipe_handle);
 			if (ret)
 				MSM_HS_ERR("%s(): sps_disconnect failed\n",
 							__func__);
 			msm_hs_spsconnect_rx(uport);
+			msm_uport->rx.flush = FLUSH_IGNORE;
 			msm_serial_hs_rx_tlet((unsigned long) &rx->tlet);
 		} else {
 			msm_uport->rx_discard_flush_issued = true;
@@ -1218,12 +1289,12 @@
 	 * UART Core would trigger RFR if it is not having any space with
 	 * RX FIFO.
 	 */
+	/* Pulling RFR line high */
+	msm_hs_write(uport, UART_DM_CR, RFR_LOW);
 	data = msm_hs_read(uport, UART_DM_MR1);
 	data &= ~(UARTDM_MR1_CTS_CTL_BMSK | UARTDM_MR1_RX_RDY_CTL_BMSK);
-	if (c_cflag & CRTSCTS) {
 		data |= UARTDM_MR1_CTS_CTL_BMSK;
 		data |= UARTDM_MR1_RX_RDY_CTL_BMSK;
-	}
 	msm_hs_write(uport, UART_DM_MR1, data);
 
 	msm_hs_write(uport, UART_DM_IMR, msm_uport->imr_reg);
@@ -1246,6 +1317,7 @@
 	msm_hs_clock_vote(msm_uport);
 	data = msm_hs_read(uport, UART_DM_SR);
 	msm_hs_clock_unvote(msm_uport);
+	MSM_HS_DBG("%s(): SR Reg Read 0x%x", __func__, data);
 
 	if (data & UARTDM_SR_TXEMT_BMSK)
 		ret = TIOCSER_TEMT;
@@ -1275,12 +1347,15 @@
 	struct sps_pipe *sps_pipe_handle = rx->prod.pipe_handle;
 	int ret = 0;
 
-	ret = sps_disconnect(sps_pipe_handle);
+	ret = sps_rx_disconnect(sps_pipe_handle);
 	if (ret)
 		MSM_HS_ERR("%s(): sps_disconnect failed\n", __func__);
 
 	wake_lock_timeout(&msm_uport->rx.wake_lock, HZ / 2);
 	msm_uport->rx.flush = FLUSH_SHUTDOWN;
+	MSM_HS_DBG("%s: Calling Completion\n", __func__);
+	wake_up(&msm_uport->bam_disconnect_wait);
+	MSM_HS_DBG("%s: Done Completion\n", __func__);
 	wake_up(&msm_uport->rx.wait);
 }
 
@@ -1297,16 +1372,19 @@
 	struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport);
 	unsigned int data;
 
-	/* disable dlink */
-	data = msm_hs_read(uport, UART_DM_DMEN);
-	if (is_blsp_uart(msm_uport))
-		data &= ~UARTDM_RX_BAM_ENABLE_BMSK;
-	else
-		data &= ~UARTDM_RX_DM_EN_BMSK;
-	msm_hs_write(uport, UART_DM_DMEN, data);
+	MSM_HS_DBG("In %s():\n", __func__);
+	if (msm_uport->clk_state != MSM_HS_CLK_OFF) {
+		/* disable dlink */
+		data = msm_hs_read(uport, UART_DM_DMEN);
+		if (is_blsp_uart(msm_uport))
+			data &= ~UARTDM_RX_BAM_ENABLE_BMSK;
+		else
+			data &= ~UARTDM_RX_DM_EN_BMSK;
+		msm_hs_write(uport, UART_DM_DMEN, data);
 
-	/* calling DMOV or CLOCK API. Hence mb() */
-	mb();
+		/* calling DMOV or CLOCK API. Hence mb() */
+		mb();
+	}
 	/* Disable the receiver */
 	if (msm_uport->rx.flush == FLUSH_NONE) {
 		wake_lock(&msm_uport->rx.wake_lock);
@@ -1333,7 +1411,7 @@
 	int aligned_tx_count;
 	dma_addr_t src_addr;
 	dma_addr_t aligned_src_addr;
-	u32 flags = SPS_IOVEC_FLAG_EOT;
+	u32 flags = SPS_IOVEC_FLAG_EOT | SPS_IOVEC_FLAG_INT;
 	struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport);
 	struct msm_hs_tx *tx = &msm_uport->tx;
 	struct circ_buf *tx_buf = &msm_uport->uport.state->xmit;
@@ -1341,6 +1419,12 @@
 
 	if (uart_circ_empty(tx_buf) || uport->state->port.tty->stopped) {
 		msm_hs_stop_tx_locked(uport);
+		if (msm_uport->clk_state == MSM_HS_CLK_REQUEST_OFF) {
+			MSM_HS_DBG("%s(): Clock off requested calling WQ",
+								__func__);
+			queue_work(msm_uport->hsuart_wq,
+						&msm_uport->clock_off_w);
+		}
 		return;
 	}
 
@@ -1366,10 +1450,9 @@
 	dma_sync_single_for_device(uport->dev, aligned_src_addr,
 			aligned_tx_count, DMA_TO_DEVICE);
 
-	if (is_blsp_uart(msm_uport)) {
-		/* Issue TX BAM Start IFC command */
-		msm_hs_write(uport, UART_DM_CR, START_TX_BAM_IFC);
-	} else {
+	if (is_blsp_uart(msm_uport))
+		tx->tx_count = tx_count;
+	else {
 		tx->command_ptr->num_rows =
 				(((tx_count + 15) >> 4) << 16) |
 				((tx_count + 15) >> 4);
@@ -1380,18 +1463,16 @@
 
 		*tx->command_ptr_ptr = CMD_PTR_LP |
 				DMOV_CMD_ADDR(tx->mapped_cmd_ptr);
+		/* Save tx_count to use in Callback */
+		tx->tx_count = tx_count;
+		msm_hs_write(uport, UART_DM_NCF_TX, tx_count);
+		msm_uport->imr_reg &= ~UARTDM_ISR_TX_READY_BMSK;
+		msm_hs_write(uport, UART_DM_IMR, msm_uport->imr_reg);
+		/* Calling next DMOV API. Hence mb() here. */
+		mb();
+
 	}
 
-	/* Save tx_count to use in Callback */
-	tx->tx_count = tx_count;
-	msm_hs_write(uport, UART_DM_NCF_TX, tx_count);
-
-	/* Disable the tx_ready interrupt */
-	msm_uport->imr_reg &= ~UARTDM_ISR_TX_READY_BMSK;
-	msm_hs_write(uport, UART_DM_IMR, msm_uport->imr_reg);
-	/* Calling next DMOV API. Hence mb() here. */
-	mb();
-
 	msm_uport->tx.flush = FLUSH_NONE;
 
 	if (is_blsp_uart(msm_uport)) {
@@ -1420,6 +1501,16 @@
 	unsigned int buffer_pending = msm_uport->rx.buffer_pending;
 	unsigned int data;
 
+	if (msm_uport->clk_state != MSM_HS_CLK_ON) {
+		MSM_HS_WARN("%s: Failed.Clocks are OFF\n", __func__);
+		return;
+	}
+	if (rx->rx_cmd_exec) {
+		MSM_HS_DBG("%s: Rx Cmd got executed, wait for rx_tlet\n",
+								 __func__);
+		rx->flush = FLUSH_IGNORE;
+		return;
+	}
 	msm_uport->rx.buffer_pending = 0;
 	if (buffer_pending && hs_serial_debug_mask)
 		MSM_HS_ERR("Error: rx started in buffer state = %x",
@@ -1428,8 +1519,6 @@
 	msm_hs_write(uport, UART_DM_CR, RESET_STALE_INT);
 	msm_hs_write(uport, UART_DM_DMRX, UARTDM_RX_BUF_SIZE);
 	msm_hs_write(uport, UART_DM_CR, STALE_EVENT_ENABLE);
-	msm_uport->imr_reg |= UARTDM_ISR_RXLEV_BMSK;
-
 	/*
 	 * Enable UARTDM Rx Interface as previously it has been
 	 * disable in set_termios before configuring baud rate.
@@ -1469,10 +1558,8 @@
 		sps_transfer_one(sps_pipe_handle, rx->rbuffer,
 			UARTDM_RX_BUF_SIZE, msm_uport, flags);
 		msm_uport->rx_bam_inprogress = false;
+		msm_uport->rx.rx_cmd_queued = true;
 		wake_up(&msm_uport->rx.wait);
-	} else {
-		msm_dmov_enqueue_cmd(msm_uport->dma_rx_channel,
-				&msm_uport->rx.xfer);
 	}
 	MSM_HS_DBG("%s:Enqueue Rx Cmd\n", __func__);
 	dump_uart_hs_registers(msm_uport);
@@ -1532,7 +1619,7 @@
 static void msm_serial_hs_rx_tlet(unsigned long tlet_ptr)
 {
 	int retval;
-	int rx_count;
+	int rx_count = 0;
 	unsigned long status;
 	unsigned long flags;
 	unsigned int error_f = 0;
@@ -1552,6 +1639,9 @@
 	notify = &msm_uport->notify;
 	rx = &msm_uport->rx;
 
+	msm_uport->rx.rx_cmd_queued = false;
+	msm_uport->rx.rx_cmd_exec = false;
+
 	status = msm_hs_read(uport, UART_DM_SR);
 
 	spin_lock_irqsave(&uport->lock, flags);
@@ -1600,29 +1690,30 @@
 		}
 	}
 
-	if (error_f)
-		msm_hs_write(uport, UART_DM_CR, RESET_ERROR_STATUS);
-
-	if (msm_uport->clk_req_off_state == CLK_REQ_OFF_FLUSH_ISSUED)
-		msm_uport->clk_req_off_state = CLK_REQ_OFF_RXSTALE_FLUSHED;
+	if (error_f) {
+		if (msm_uport->clk_state == MSM_HS_CLK_ON)
+			msm_hs_write(uport, UART_DM_CR, RESET_ERROR_STATUS);
+		else
+			MSM_HS_WARN("%s: Failed.Clocks are OFF\n", __func__);
+	}
 	flush = msm_uport->rx.flush;
 	if (flush == FLUSH_IGNORE)
-		if (!msm_uport->rx.buffer_pending)
+		if (!msm_uport->rx.buffer_pending) {
+			MSM_HS_DBG("%s: calling start_rx_locked\n", __func__);
 			msm_hs_start_rx_locked(uport);
-
-	if (flush == FLUSH_STOP) {
-		msm_uport->rx.flush = FLUSH_SHUTDOWN;
-		wake_up(&msm_uport->rx.wait);
-	}
+		}
 	if (flush >= FLUSH_DATA_INVALID)
 		goto out;
 
 	if (is_blsp_uart(msm_uport)) {
 		rx_count = msm_uport->rx_count_callback;
 	} else {
-		rx_count = msm_hs_read(uport, UART_DM_RX_TOTAL_SNAP);
-		/* order the read of rx.buffer */
-		rmb();
+		if (msm_uport->clk_state == MSM_HS_CLK_ON) {
+			rx_count = msm_hs_read(uport, UART_DM_RX_TOTAL_SNAP);
+			/* order the read of rx.buffer */
+			rmb();
+		} else
+			MSM_HS_WARN("%s: Failed.Clocks are OFF\n", __func__);
 	}
 
 	MSM_HS_DBG("%s():[UART_RX]<%d>\n", __func__, rx_count);
@@ -1637,24 +1728,21 @@
 				retval << 5 | (rx_count - retval) << 16;
 		}
 	}
-
-	MSM_HS_DBG("%s() read rx buffer complete", __func__);
-	/* order the read of rx.buffer and the start of next rx xfer */
-	wmb();
-
-	if (!msm_uport->rx.buffer_pending) {
+	if (!msm_uport->rx.buffer_pending && !msm_uport->rx.rx_cmd_queued) {
 		if (is_blsp_uart(msm_uport)) {
 			msm_uport->rx.flush = FLUSH_NONE;
 			msm_uport->rx_bam_inprogress = true;
 			sps_pipe_handle = rx->prod.pipe_handle;
+			MSM_HS_DBG("Queing bam descriptor\n");
 			/* Queue transfer request to SPS */
 			sps_transfer_one(sps_pipe_handle, rx->rbuffer,
 				UARTDM_RX_BUF_SIZE, msm_uport, sps_flags);
 			msm_uport->rx_bam_inprogress = false;
+			msm_uport->rx.rx_cmd_queued = true;
 			wake_up(&msm_uport->rx.wait);
-		} else {
+
+		} else
 			msm_hs_start_rx_locked(uport);
-		}
 	}
 out:
 	if (msm_uport->rx.buffer_pending) {
@@ -1676,8 +1764,12 @@
 {
 	struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport);
 
+	if (msm_uport->clk_state != MSM_HS_CLK_ON) {
+		MSM_HS_WARN("%s: Failed.Clocks are OFF\n", __func__);
+	}
 	if (msm_uport->tx.tx_ready_int_en == 0) {
-		msm_uport->tx.tx_ready_int_en = 1;
+		if (!is_blsp_uart(msm_uport))
+			msm_uport->tx.tx_ready_int_en = 1;
 		if (msm_uport->tx.dma_in_flight == 0)
 			msm_hs_submit_tx_locked(uport);
 	}
@@ -1699,11 +1791,12 @@
 		((struct sps_event_notify *)notify)->user;
 
 	msm_uport->notify = *notify;
-	MSM_HS_DBG("%s: sps ev_id=%d, addr=0x%x, size=0x%x, flags=0x%x\n",
-		__func__, notify->event_id,
-		notify->data.transfer.iovec.addr,
-		notify->data.transfer.iovec.size,
-		notify->data.transfer.iovec.flags);
+	MSM_HS_DBG("%s: ev_id=%d, addr=0x%x, size=0x%x, flags=0x%x, line=%d\n",
+			__func__, notify->event_id,
+	notify->data.transfer.iovec.addr,
+	notify->data.transfer.iovec.size,
+	notify->data.transfer.iovec.flags,
+	msm_uport->uport.line);
 
 	tasklet_schedule(&msm_uport->tx.tlet);
 }
@@ -1737,8 +1830,37 @@
 	unsigned long flags;
 	struct msm_hs_port *msm_uport = container_of((struct tasklet_struct *)
 				tlet_ptr, struct msm_hs_port, tx.tlet);
+	struct uart_port *uport = &msm_uport->uport;
+	struct circ_buf *tx_buf = &uport->state->xmit;
+	struct msm_hs_tx *tx = &msm_uport->tx;
 
+	/*
+	 * Do the work buffer related work in BAM
+	 * mode that is equivalent to legacy mode
+	 */
 	spin_lock_irqsave(&(msm_uport->uport.lock), flags);
+
+	if (!uart_circ_empty(tx_buf))
+		tx_buf->tail = (tx_buf->tail +
+		tx->tx_count) & ~UART_XMIT_SIZE;
+	else
+		MSM_HS_DBG("%s:circ buffer is empty\n", __func__);
+
+	tx->dma_in_flight = 0;
+
+	uport->icount.tx += tx->tx_count;
+
+	/*
+	 * Calling to send next chunk of data
+	 * If the circ buffer is empty, we stop
+	 * If the clock off was requested, the clock
+	 * off sequence is kicked off
+	 */
+	 msm_hs_submit_tx_locked(uport);
+
+	if (uart_circ_chars_pending(tx_buf) < WAKEUP_CHARS)
+		uart_write_wakeup(uport);
+
 	if (msm_uport->tx.flush == FLUSH_STOP) {
 		msm_uport->tx.flush = FLUSH_SHUTDOWN;
 		wake_up(&msm_uport->tx.wait);
@@ -1746,10 +1868,14 @@
 		return;
 	}
 
-	msm_uport->imr_reg |= UARTDM_ISR_TX_READY_BMSK;
-	msm_hs_write(&(msm_uport->uport), UART_DM_IMR, msm_uport->imr_reg);
-	/* Calling clk API. Hence mb() requires. */
-	mb();
+	/* TX_READY_BMSK only if non BAM mode */
+	if (!is_blsp_uart(msm_uport)) {
+		msm_uport->imr_reg |= UARTDM_ISR_TX_READY_BMSK;
+		msm_hs_write(&(msm_uport->uport), UART_DM_IMR,
+					msm_uport->imr_reg);
+		/* Calling clk API. Hence mb() requires. */
+		mb();
+	}
 
 	spin_unlock_irqrestore(&(msm_uport->uport.lock), flags);
 	MSM_HS_DBG("In %s()\n", __func__);
@@ -1785,6 +1911,7 @@
 	if (msm_uport->rx.flush == FLUSH_NONE) {
 		spin_lock_irqsave(&uport->lock, flags);
 		msm_uport->rx_count_callback = notify->data.transfer.iovec.size;
+		msm_uport->rx.rx_cmd_exec = true;
 		spin_unlock_irqrestore(&uport->lock, flags);
 		tasklet_schedule(&msm_uport->rx.tlet);
 	}
@@ -1854,7 +1981,12 @@
 {
 	unsigned int set_rts;
 	unsigned int data;
+	struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport);
 
+	if (msm_uport->clk_state != MSM_HS_CLK_ON) {
+		MSM_HS_WARN("%s:Failed.Clocks are OFF\n", __func__);
+		return;
+	}
 	/* RTS is active low */
 	set_rts = TIOCM_RTS & mctrl ? 0 : 1;
 
@@ -1892,6 +2024,11 @@
 {
 	struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport);
 
+	if (msm_uport->clk_state != MSM_HS_CLK_ON) {
+		MSM_HS_WARN("%s:Failed.Clocks are OFF\n", __func__);
+		return;
+	}
+
 	/* Enable DELTA_CTS Interrupt */
 	msm_uport->imr_reg |= UARTDM_ISR_DELTA_CTS_BMSK;
 	msm_hs_write(uport, UART_DM_IMR, msm_uport->imr_reg);
@@ -1899,14 +2036,6 @@
 
 }
 
-static void msm_hs_flush_buffer(struct uart_port *uport)
-{
-	struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport);
-
-	if (msm_uport->tx.dma_in_flight)
-		msm_uport->tty_flush_receive = true;
-}
-
 /*
  *  Standard API, Break Signal
  *
@@ -1916,6 +2045,12 @@
 static void msm_hs_break_ctl(struct uart_port *uport, int ctl)
 {
 	unsigned long flags;
+	struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport);
+
+	if (msm_uport->clk_state != MSM_HS_CLK_ON) {
+		MSM_HS_WARN("%s: Failed.Clocks are OFF\n", __func__);
+		return;
+	}
 
 	spin_lock_irqsave(&uport->lock, flags);
 	msm_hs_write(uport, UART_DM_CR, ctl ? START_BREAK : STOP_BREAK);
@@ -1948,6 +2083,12 @@
 /*  Handle CTS changes (Called from interrupt handler) */
 static void msm_hs_handle_delta_cts_locked(struct uart_port *uport)
 {
+	struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport);
+
+	if (msm_uport->clk_state != MSM_HS_CLK_ON) {
+		MSM_HS_WARN("%s: Failed.Clocks are OFF\n", __func__);
+		return;
+	}
 	/* clear interrupt */
 	msm_hs_write(uport, UART_DM_CR, RESET_CTS);
 	/* Calling CLOCK API. Hence mb() requires here. */
@@ -1967,60 +2108,47 @@
 {
 	unsigned long sr_status;
 	unsigned long flags;
-	int ret;
+	unsigned int data;
 	struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport);
 	struct circ_buf *tx_buf = &uport->state->xmit;
 
 	mutex_lock(&msm_uport->clk_mutex);
 	spin_lock_irqsave(&uport->lock, flags);
 
+	MSM_HS_DBG("In %s:\n", __func__);
 	/* Cancel if tx tty buffer is not empty, dma is in flight,
-	 * or tx fifo is not empty */
+	 * or tx fifo is not empty
+	 */
 	if (msm_uport->clk_state != MSM_HS_CLK_REQUEST_OFF ||
 	    !uart_circ_empty(tx_buf) || msm_uport->tx.dma_in_flight ||
 	    msm_uport->imr_reg & UARTDM_ISR_TXLEV_BMSK) {
 		spin_unlock_irqrestore(&uport->lock, flags);
 		mutex_unlock(&msm_uport->clk_mutex);
+		if (msm_uport->clk_state == MSM_HS_CLK_REQUEST_OFF) {
+			msm_uport->clk_state = MSM_HS_CLK_ON;
+			/* Pulling RFR line high */
+			msm_hs_write(uport, UART_DM_CR, RFR_LOW);
+			/* Enable auto RFR */
+			data = msm_hs_read(uport, UART_DM_MR1);
+			data |= UARTDM_MR1_RX_RDY_CTL_BMSK;
+			msm_hs_write(uport, UART_DM_MR1, data);
+			mb();
+		}
+		MSM_HS_DBG("%s(): clkstate %d", __func__, msm_uport->clk_state);
 		return -1;
 	}
 
-	/* Make sure the uart is finished with the last byte */
-	sr_status = msm_hs_read(uport, UARTDM_SR);
+	/* Make sure the uart is finished with the last byte,
+	 * use BFamily Register
+	 */
+	sr_status = msm_hs_read(uport, UART_DM_SR);
 	if (!(sr_status & UARTDM_SR_TXEMT_BMSK)) {
 		spin_unlock_irqrestore(&uport->lock, flags);
 		mutex_unlock(&msm_uport->clk_mutex);
+		MSM_HS_DBG("%s(): SR TXEMT fail %lx", __func__, sr_status);
 		return 0;  /* retry */
 	}
 
-	/* Make sure forced RXSTALE flush complete */
-	switch (msm_uport->clk_req_off_state) {
-	case CLK_REQ_OFF_START:
-		msm_uport->clk_req_off_state = CLK_REQ_OFF_RXSTALE_ISSUED;
-
-		if (!is_blsp_uart(msm_uport)) {
-			msm_hs_write(uport, UART_DM_CR, FORCE_STALE_EVENT);
-			/*
-			* Before returning make sure that device writel
-			* completed. Hence mb() requires here.
-			*/
-			mb();
-		}
-		spin_unlock_irqrestore(&uport->lock, flags);
-		mutex_unlock(&msm_uport->clk_mutex);
-		return 0;  /* RXSTALE flush not complete - retry */
-	case CLK_REQ_OFF_RXSTALE_ISSUED:
-	case CLK_REQ_OFF_FLUSH_ISSUED:
-		spin_unlock_irqrestore(&uport->lock, flags);
-		if (is_blsp_uart(msm_uport)) {
-			msm_uport->clk_req_off_state =
-				CLK_REQ_OFF_RXSTALE_FLUSHED;
-		}
-		mutex_unlock(&msm_uport->clk_mutex);
-		return 0;  /* RXSTALE flush not complete - retry */
-	case CLK_REQ_OFF_RXSTALE_FLUSHED:
-		break;  /* continue */
-	}
-
 	if (msm_uport->rx.flush != FLUSH_SHUTDOWN) {
 		if (msm_uport->rx.flush == FLUSH_NONE) {
 			msm_hs_stop_rx_locked(uport);
@@ -2028,24 +2156,23 @@
 				msm_uport->rx_discard_flush_issued = true;
 		}
 
+		MSM_HS_DBG("%s: rx.flush %d clk_state %d\n", __func__,
+			msm_uport->rx.flush, msm_uport->clk_state);
 		spin_unlock_irqrestore(&uport->lock, flags);
-		if (msm_uport->rx_discard_flush_issued) {
-			MSM_HS_DBG("%s(): wainting for flush completion.\n",
-								__func__);
-			ret = wait_event_timeout(msm_uport->rx.wait,
-				msm_uport->rx_discard_flush_issued == false,
-				RX_FLUSH_COMPLETE_TIMEOUT);
-			if (!ret)
-				MSM_HS_ERR("%s(): Flush complete pending.\n",
-								__func__);
-		}
-
 		mutex_unlock(&msm_uport->clk_mutex);
 		return 0;  /* come back later to really clock off */
 	}
 
 	spin_unlock_irqrestore(&uport->lock, flags);
 
+	/* Pulling RFR line high */
+	msm_hs_write(uport, UART_DM_CR, RFR_LOW);
+	/* Enable auto RFR */
+	data = msm_hs_read(uport, UART_DM_MR1);
+	data |= UARTDM_MR1_RX_RDY_CTL_BMSK;
+	msm_hs_write(uport, UART_DM_MR1, data);
+	mb();
+
 	/* we really want to clock off */
 	msm_hs_clock_unvote(msm_uport);
 
@@ -2058,8 +2185,6 @@
 
 	spin_unlock_irqrestore(&uport->lock, flags);
 
-	/* Reset PNOC Bus Scaling */
-	msm_hs_bus_voting(msm_uport, BUS_RESET);
 	mutex_unlock(&msm_uport->clk_mutex);
 
 	return 1;
@@ -2123,11 +2248,6 @@
 		mb();
 		MSM_HS_DBG("%s:Stal Interrupt\n", __func__);
 
-		if (msm_uport->clk_req_off_state ==
-					CLK_REQ_OFF_RXSTALE_ISSUED)
-			msm_uport->clk_req_off_state =
-					CLK_REQ_OFF_FLUSH_ISSUED;
-
 		if (!is_blsp_uart(msm_uport) && (rx->flush == FLUSH_NONE)) {
 			rx->flush = FLUSH_DATA_READY;
 			msm_dmov_flush(msm_uport->dma_rx_channel, 1);
@@ -2151,12 +2271,11 @@
 		/* Complete DMA TX transactions and submit new transactions */
 
 		/* Do not update tx_buf.tail if uart_flush_buffer already
-						called in serial core */
-		if (!msm_uport->tty_flush_receive)
+		 * called in serial core
+		 */
+		if (!uart_circ_empty(tx_buf))
 			tx_buf->tail = (tx_buf->tail +
 					tx->tx_count) & ~UART_XMIT_SIZE;
-		else
-			msm_uport->tty_flush_receive = false;
 
 		tx->dma_in_flight = 0;
 
@@ -2188,37 +2307,57 @@
 	return IRQ_HANDLED;
 }
 
-/*
- * Find UART device port using its port index value.
+/* The following two functions provide interfaces to get the underlying
+ * port structure (struct uart_port or struct msm_hs_port) given
+ * the port index. msm_hs_get_uart port is called by clients.
+ * The function msm_hs_get_hs_port is for internal use
  */
+
 struct uart_port *msm_hs_get_uart_port(int port_index)
 {
-	int i;
+	struct uart_state *state = msm_hs_driver.state + port_index;
 
-	for (i = 0; i < UARTDM_NR; i++) {
-		if (q_uart_port[i].uport.line == port_index)
-			return &q_uart_port[i].uport;
-	}
+	/* The uart_driver structure stores the states in an array.
+	 * Thus the corresponding offset from the drv->state returns
+	 * the state for the uart_port that is requested
+	 */
+	if (port_index == state->uart_port->line)
+		return state->uart_port;
 
 	return NULL;
 }
 EXPORT_SYMBOL(msm_hs_get_uart_port);
 
+static struct msm_hs_port *msm_hs_get_hs_port(int port_index)
+{
+	struct uart_port *uport = msm_hs_get_uart_port(port_index);
+	if (uport)
+		return UARTDM_TO_MSM(uport);
+	return NULL;
+}
+
 /* request to turn off uart clock once pending TX is flushed */
 void msm_hs_request_clock_off(struct uart_port *uport) {
 	unsigned long flags;
 	struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport);
+	int data;
 
 	spin_lock_irqsave(&uport->lock, flags);
 	if (msm_uport->clk_state == MSM_HS_CLK_ON) {
 		msm_uport->clk_state = MSM_HS_CLK_REQUEST_OFF;
-		msm_uport->clk_req_off_state = CLK_REQ_OFF_START;
-		msm_uport->imr_reg |= UARTDM_ISR_TXLEV_BMSK;
-		msm_hs_write(uport, UART_DM_IMR, msm_uport->imr_reg);
-		/*
-		 * Complete device write before retuning back.
-		 * Hence mb() requires here.
-		 */
+		data = msm_hs_read(uport, UART_DM_MR1);
+		/*disable auto ready-for-receiving */
+		data &= ~UARTDM_MR1_RX_RDY_CTL_BMSK;
+		msm_hs_write(uport, UART_DM_MR1, data);
+		mb();
+		/* set RFR_N to high */
+		msm_hs_write(uport, UART_DM_CR, RFR_HIGH);
+
+		data = msm_hs_read(uport, UART_DM_SR);
+		MSM_HS_DBG("%s(): TXEMT, queuing clock off work\n",
+			__func__);
+		queue_work(msm_uport->hsuart_wq, &msm_uport->clock_off_w);
+
 		mb();
 	}
 	spin_unlock_irqrestore(&uport->lock, flags);
@@ -2235,6 +2374,15 @@
 	mutex_lock(&msm_uport->clk_mutex);
 	spin_lock_irqsave(&uport->lock, flags);
 
+	if (msm_uport->clk_state == MSM_HS_CLK_REQUEST_OFF) {
+		/* Pulling RFR line high */
+		msm_hs_write(uport, UART_DM_CR, RFR_LOW);
+		/* Enable auto RFR */
+		data = msm_hs_read(uport, UART_DM_MR1);
+		data |= UARTDM_MR1_RX_RDY_CTL_BMSK;
+		msm_hs_write(uport, UART_DM_MR1, data);
+		mb();
+	}
 	switch (msm_uport->clk_state) {
 	case MSM_HS_CLK_OFF:
 		wake_lock(&msm_uport->dma_wake_lock);
@@ -2244,7 +2392,7 @@
 
 		ret = msm_hs_clock_vote(msm_uport);
 		if (ret) {
-			dev_err(uport->dev, "Clock ON Failure"
+			MSM_HS_INFO("Clock ON Failure"
 			"For UART CLK Stalling HSUART\n");
 			break;
 		}
@@ -2252,6 +2400,22 @@
 		spin_lock_irqsave(&uport->lock, flags);
 		/* else fall-through */
 	case MSM_HS_CLK_REQUEST_OFF:
+		hrtimer_cancel(&msm_uport->clk_off_timer);
+		if (msm_uport->rx.flush == FLUSH_STOP) {
+			spin_unlock_irqrestore(&uport->lock, flags);
+			MSM_HS_DBG("%s:Calling wait forxcompletion\n",
+					__func__);
+			ret = wait_event_timeout(msm_uport->bam_disconnect_wait,
+				msm_uport->rx.flush == FLUSH_SHUTDOWN, 300);
+			if (!ret)
+				MSM_HS_ERR("BAM Disconnect not happened\n");
+			spin_lock_irqsave(&uport->lock, flags);
+			MSM_HS_DBG("%s:DONE wait for completion\n", __func__);
+		}
+		MSM_HS_DBG("%s:clock state %d\n\n", __func__,
+				msm_uport->clk_state);
+		if (msm_uport->clk_state == MSM_HS_CLK_REQUEST_OFF)
+				msm_uport->clk_state = MSM_HS_CLK_ON;
 		if (msm_uport->rx.flush == FLUSH_STOP ||
 		    msm_uport->rx.flush == FLUSH_SHUTDOWN) {
 			msm_hs_write(uport, UART_DM_CR, RESET_RX);
@@ -2264,7 +2428,8 @@
 			/* Complete above device write. Hence mb() here. */
 			mb();
 		}
-		hrtimer_try_to_cancel(&msm_uport->clk_off_timer);
+
+		MSM_HS_DBG("%s: rx.flush %d\n", __func__, msm_uport->rx.flush);
 		if (msm_uport->rx.flush == FLUSH_SHUTDOWN) {
 			if (is_blsp_uart(msm_uport)) {
 				spin_unlock_irqrestore(&uport->lock, flags);
@@ -2275,7 +2440,7 @@
 		}
 		if (msm_uport->rx.flush == FLUSH_STOP)
 			msm_uport->rx.flush = FLUSH_IGNORE;
-		msm_uport->clk_state = MSM_HS_CLK_ON;
+
 		break;
 	case MSM_HS_CLK_ON:
 		break;
@@ -2299,7 +2464,8 @@
 	spin_lock_irqsave(&uport->lock, flags);
 	if (msm_uport->clk_state == MSM_HS_CLK_OFF)  {
 		/* ignore the first irq - it is a pending irq that occured
-		 * before enable_irq() */
+		 * before enable_irq()
+		 */
 		if (msm_uport->wakeup.ignore)
 			msm_uport->wakeup.ignore = 0;
 		else
@@ -2308,7 +2474,8 @@
 
 	if (wakeup) {
 		/* the uart was clocked off during an rx, wake up and
-		 * optionally inject char into tty rx */
+		 * optionally inject char into tty rx
+		 */
 		spin_unlock_irqrestore(&uport->lock, flags);
 		msm_hs_request_clock_on(uport);
 		spin_lock_irqsave(&uport->lock, flags);
@@ -2488,6 +2655,11 @@
 		}
 	}
 
+	data = (UARTDM_BCR_TX_BREAK_DISABLE | UARTDM_BCR_STALE_IRQ_EMPTY |
+		UARTDM_BCR_RX_DMRX_LOW_EN | UARTDM_BCR_RX_STAL_IRQ_DMRX_EQL |
+		UARTDM_BCR_RX_DMRX_1BYTE_RES_EN);
+	msm_hs_write(uport, UART_DM_BCR, data);
+
 	/* Set auto RFR Level */
 	data = msm_hs_read(uport, UART_DM_MR1);
 	data &= ~UARTDM_MR1_AUTO_RFR_LEVEL1_BMSK;
@@ -2529,6 +2701,7 @@
 	/* Initialize the tx */
 	tx->tx_ready_int_en = 0;
 	tx->dma_in_flight = 0;
+	rx->rx_cmd_exec = false;
 
 	if (!is_blsp_uart(msm_uport)) {
 		tx->xfer.complete_func = msm_hs_dmov_tx_callback;
@@ -2551,7 +2724,7 @@
 	msm_uport->imr_reg |= UARTDM_ISR_CURRENT_CTS_BMSK;
 
 	/* TXLEV on empty TX fifo */
-	msm_hs_write(uport, UART_DM_TFWR, 0);
+	msm_hs_write(uport, UART_DM_TFWR, 4);
 	/*
 	 * Complete all device write related configuration before
 	 * queuing RX request. Hence mb() requires here.
@@ -2585,17 +2758,12 @@
 		}
 		disable_irq(msm_uport->wakeup.irq);
 	}
-
-	msm_hs_clock_vote(msm_uport);
-
 	spin_lock_irqsave(&uport->lock, flags);
 
 	msm_hs_start_rx_locked(uport);
 
 	spin_unlock_irqrestore(&uport->lock, flags);
 
-	msm_hs_clock_unvote(msm_uport);
-
 	pm_runtime_enable(uport->dev);
 
 	return 0;
@@ -2631,6 +2799,7 @@
 
 	init_waitqueue_head(&rx->wait);
 	init_waitqueue_head(&tx->wait);
+	init_waitqueue_head(&msm_uport->bam_disconnect_wait);
 	wake_lock_init(&rx->wake_lock, WAKE_LOCK_SUSPEND, "msm_serial_hs_rx");
 	wake_lock_init(&msm_uport->dma_wake_lock, WAKE_LOCK_SUSPEND,
 		       "msm_serial_hs_dma");
@@ -2911,7 +3080,6 @@
 		sps_config->mode = SPS_MODE_SRC;
 		sps_config->src_pipe_index = msm_uport->bam_rx_ep_pipe_index;
 		sps_config->dest_pipe_index = 0;
-		sps_config->options = SPS_O_DESC_DONE;
 	} else {
 		/* For UART consumer transfer, source is system memory
 		where as destination is UART peripheral */
@@ -2920,9 +3088,9 @@
 		sps_config->mode = SPS_MODE_DEST;
 		sps_config->src_pipe_index = 0;
 		sps_config->dest_pipe_index = msm_uport->bam_tx_ep_pipe_index;
-		sps_config->options = SPS_O_EOT;
 	}
 
+	sps_config->options = SPS_O_EOT | SPS_O_DESC_DONE | SPS_O_AUTO_ENABLE;
 	sps_config->event_thresh = 0x10;
 
 	/* Allocate maximum descriptor fifo size */
@@ -2942,12 +3110,11 @@
 
 	if (is_producer) {
 		sps_event->callback = msm_hs_sps_rx_callback;
-		sps_event->options = SPS_O_DESC_DONE;
 	} else {
 		sps_event->callback = msm_hs_sps_tx_callback;
-		sps_event->options = SPS_O_EOT;
 	}
 
+	sps_event->options = SPS_O_DESC_DONE | SPS_O_EOT;
 	sps_event->user = (void *)msm_uport;
 
 	/* Now save the sps pipe handle */
@@ -3049,6 +3216,7 @@
 	int core_irqres, bam_irqres, wakeup_irqres;
 	struct msm_serial_hs_platform_data *pdata = pdev->dev.platform_data;
 	const struct of_device_id *match;
+	unsigned long data;
 
 	if (pdev->dev.of_node) {
 		dev_dbg(&pdev->dev, "device tree enabled\n");
@@ -3091,7 +3259,9 @@
 		return -EINVAL;
 	}
 
-	msm_uport = &q_uart_port[pdev->id];
+	msm_uport = devm_kzalloc(&pdev->dev, sizeof(struct msm_hs_port),
+			GFP_KERNEL);
+	msm_uport->uport.type = PORT_UNKNOWN;
 	uport = &msm_uport->uport;
 	uport->dev = &pdev->dev;
 
@@ -3304,6 +3474,17 @@
 	 */
 	mb();
 
+	/*
+	* Set RX_BREAK_ZERO_CHAR_OFF and RX_ERROR_CHAR_OFF
+	* so any rx_break and character having parity of framing
+	* error don't enter inside UART RX FIFO.
+	*/
+	data = msm_hs_read(uport, UART_DM_MR2);
+	data |= (UARTDM_MR2_RX_BREAK_ZERO_CHAR_OFF |
+			UARTDM_MR2_RX_ERROR_CHAR_OFF);
+	msm_hs_write(uport, UART_DM_MR2, data);
+	mb();
+
 	msm_uport->clk_state = MSM_HS_CLK_PORT_OFF;
 	hrtimer_init(&msm_uport->clk_off_timer, CLOCK_MONOTONIC,
 		     HRTIMER_MODE_REL);
@@ -3353,17 +3534,12 @@
 static int __init msm_serial_hs_init(void)
 {
 	int ret;
-	int i;
 
 	ipc_msm_hs_log_ctxt = ipc_log_context_create(IPC_MSM_HS_LOG_PAGES,
 							"msm_serial_hs");
 	if (!ipc_msm_hs_log_ctxt)
 		MSM_HS_WARN("%s: error creating logging context", __func__);
 
-	/* Init all UARTS as non-configured */
-	for (i = 0; i < UARTDM_NR; i++)
-		q_uart_port[i].uport.type = PORT_UNKNOWN;
-
 	ret = uart_register_driver(&msm_hs_driver);
 	if (unlikely(ret)) {
 		MSM_HS_WARN("%s failed to load\n", __func__);
@@ -3454,12 +3630,12 @@
 	 */
 	mb();
 
+	msm_hs_clock_unvote(msm_uport);
 	if (msm_uport->clk_state != MSM_HS_CLK_OFF) {
 		/* to balance clk_state */
 		msm_hs_clock_unvote(msm_uport);
 		wake_unlock(&msm_uport->dma_wake_lock);
 	}
-	msm_hs_clock_unvote(msm_uport);
 
 	msm_uport->clk_state = MSM_HS_CLK_PORT_OFF;
 	dma_unmap_single(uport->dev, msm_uport->tx.dma_base,
@@ -3503,8 +3679,13 @@
 {
 	struct platform_device *pdev = container_of(dev, struct
 						    platform_device, dev);
-	struct msm_hs_port *msm_uport = &q_uart_port[pdev->id];
-	msm_hs_request_clock_on(&msm_uport->uport);
+	struct msm_hs_port *msm_uport = get_matching_hs_port(pdev);
+
+	/* This check should not fail
+	 * During probe, we set uport->line to either pdev->id or userid */
+	if (msm_uport)
+		msm_hs_request_clock_on(&msm_uport->uport);
+
 	return 0;
 }
 
@@ -3512,8 +3693,12 @@
 {
 	struct platform_device *pdev = container_of(dev, struct
 						    platform_device, dev);
-	struct msm_hs_port *msm_uport = &q_uart_port[pdev->id];
-	msm_hs_request_clock_off(&msm_uport->uport);
+	struct msm_hs_port *msm_uport = get_matching_hs_port(pdev);
+
+	/* This check should not fail
+	 * During probe, we set uport->line to either pdev->id or userid */
+	if (msm_uport)
+		msm_hs_request_clock_off(&msm_uport->uport);
 	return 0;
 }
 
@@ -3558,7 +3743,7 @@
 	.config_port = msm_hs_config_port,
 	.release_port = msm_hs_release_port,
 	.request_port = msm_hs_request_port,
-	.flush_buffer = msm_hs_flush_buffer,
+	.flush_buffer = NULL,
 	.ioctl = msm_hs_ioctl,
 };
 
diff --git a/drivers/tty/serial/msm_serial_hs_hwreg.h b/drivers/tty/serial/msm_serial_hs_hwreg.h
index d912b9f..064bbda 100644
--- a/drivers/tty/serial/msm_serial_hs_hwreg.h
+++ b/drivers/tty/serial/msm_serial_hs_hwreg.h
@@ -81,6 +81,7 @@
 	UART_DM_TXFS,
 	UART_DM_RXFS,
 	UART_DM_RX_TRANS_CTRL,
+	UART_DM_BCR,
 	UART_DM_LAST,
 };
 
@@ -94,7 +95,11 @@
  * UARTDM Core v1.4 STALE_IRQ_EMPTY bit defination
  * Stale interrupt will fire if bit is set when RX-FIFO is empty
  */
+#define UARTDM_BCR_TX_BREAK_DISABLE	0x1
 #define UARTDM_BCR_STALE_IRQ_EMPTY	0x2
+#define UARTDM_BCR_RX_DMRX_LOW_EN	0x4
+#define UARTDM_BCR_RX_STAL_IRQ_DMRX_EQL	0x10
+#define UARTDM_BCR_RX_DMRX_1BYTE_RES_EN	0x20
 
 /* TRANSFER_CONTROL Register for UARTDM Core v1.4 */
 #define UARTDM_RX_TRANS_CTRL_ADDR      0xcc
diff --git a/drivers/uio/uio.c b/drivers/uio/uio.c
index a783d53..0470194 100644
--- a/drivers/uio/uio.c
+++ b/drivers/uio/uio.c
@@ -640,38 +640,58 @@
 	return 0;
 }
 
-static const struct vm_operations_struct uio_vm_ops = {
+static const struct vm_operations_struct uio_logical_vm_ops = {
 	.open = uio_vma_open,
 	.close = uio_vma_close,
 	.fault = uio_vma_fault,
 };
 
+static int uio_mmap_logical(struct vm_area_struct *vma)
+{
+	vma->vm_flags |= VM_DONTEXPAND | VM_NODUMP;
+	vma->vm_ops = &uio_logical_vm_ops;
+	uio_vma_open(vma);
+	return 0;
+}
+
+static const struct vm_operations_struct uio_physical_vm_ops = {
+#ifdef CONFIG_HAVE_IOREMAP_PROT
+	.access = generic_access_phys,
+#endif
+};
+
 static int uio_mmap_physical(struct vm_area_struct *vma)
 {
 	struct uio_device *idev = vma->vm_private_data;
 	int mi = uio_find_mem_index(vma);
+	struct uio_mem *mem;
 	if (mi < 0)
 		return -EINVAL;
+	mem = idev->info->mem + mi;
 
-	vma->vm_flags |= VM_IO | VM_RESERVED;
+	if (vma->vm_end - vma->vm_start > mem->size)
+		return -EINVAL;
 
+	vma->vm_ops = &uio_physical_vm_ops;
 	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
 
+	/*
+	 * We cannot use the vm_iomap_memory() helper here,
+	 * because vma->vm_pgoff is the map index we looked
+	 * up above in uio_find_mem_index(), rather than an
+	 * actual page offset into the mmap.
+	 *
+	 * So we just do the physical mmap without a page
+	 * offset.
+	 */
+
 	return remap_pfn_range(vma,
 			       vma->vm_start,
-			       idev->info->mem[mi].addr >> PAGE_SHIFT,
+			       mem->addr >> PAGE_SHIFT,
 			       vma->vm_end - vma->vm_start,
 			       vma->vm_page_prot);
 }
 
-static int uio_mmap_logical(struct vm_area_struct *vma)
-{
-	vma->vm_flags |= VM_RESERVED;
-	vma->vm_ops = &uio_vm_ops;
-	uio_vma_open(vma);
-	return 0;
-}
-
 static int uio_mmap(struct file *filep, struct vm_area_struct *vma)
 {
 	struct uio_listener *listener = filep->private_data;
diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile
index b1ec3fc..2a66c4c 100644
--- a/drivers/usb/Makefile
+++ b/drivers/usb/Makefile
@@ -28,6 +28,7 @@
 obj-$(CONFIG_USB_IMX21_HCD)	+= host/
 obj-$(CONFIG_USB_FSL_MPH_DR_OF)	+= host/
 obj-$(CONFIG_USB_PEHCI_HCD)	+= host/
+obj-$(CONFIG_USB_ICE40_HCD)	+= host/
 
 obj-$(CONFIG_USB_C67X00_HCD)	+= c67x00/
 
@@ -37,6 +38,7 @@
 obj-$(CONFIG_USB_PRINTER)	+= class/
 obj-$(CONFIG_USB_WDM)		+= class/
 obj-$(CONFIG_USB_TMC)		+= class/
+obj-$(CONFIG_USB_CCID_BRIDGE)	+= class/
 
 obj-$(CONFIG_USB_STORAGE)	+= storage/
 obj-$(CONFIG_USB)		+= storage/
diff --git a/drivers/usb/class/Kconfig b/drivers/usb/class/Kconfig
index 2519e32..f7321e5 100644
--- a/drivers/usb/class/Kconfig
+++ b/drivers/usb/class/Kconfig
@@ -50,3 +50,15 @@
 
 	  To compile this driver as a module, choose M here: the
 	  module will be called usbtmc.
+
+config USB_CCID_BRIDGE
+	tristate "USB  Smart Card Class (CCID) support"
+	help
+	  Say Y here if you want to connect a USB Smart Card device that
+	  follows the USB.org specification for Integrated Circuit(s) Cards
+	  Interface Devices to your computer's USB port.  This module
+	  provides a character device interface to exchange the messages.
+	  Ioctls facilitate control transfers and interrupt transfers.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called ccid_bridge.
diff --git a/drivers/usb/class/Makefile b/drivers/usb/class/Makefile
index 32e8527..c2ee6f3 100644
--- a/drivers/usb/class/Makefile
+++ b/drivers/usb/class/Makefile
@@ -7,3 +7,4 @@
 obj-$(CONFIG_USB_PRINTER)	+= usblp.o
 obj-$(CONFIG_USB_WDM)		+= cdc-wdm.o
 obj-$(CONFIG_USB_TMC)		+= usbtmc.o
+obj-$(CONFIG_USB_CCID_BRIDGE)	+= ccid_bridge.o
diff --git a/drivers/usb/class/ccid_bridge.c b/drivers/usb/class/ccid_bridge.c
new file mode 100644
index 0000000..a914902
--- /dev/null
+++ b/drivers/usb/class/ccid_bridge.c
@@ -0,0 +1,891 @@
+/* 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.
+ */
+
+#define pr_fmt(fmt) "%s: " fmt "\n", __func__
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/uaccess.h>
+#include <linux/usb.h>
+#include <linux/wait.h>
+#include <linux/cdev.h>
+
+#include <linux/usb/ccid_bridge.h>
+
+#define CCID_CLASS_DECRIPTOR_TYPE 0x21
+#define CCID_NOTIFY_SLOT_CHANGE	0x50
+#define CCID_NOTIFY_HARDWARE_ERROR 0x51
+#define CCID_ABORT_REQ 0x1
+#define CCID_GET_CLK_FREQ_REQ 0x2
+#define CCID_GET_DATA_RATES 0x3
+
+#define CCID_BRIDGE_MSG_SZ 512
+#define CCID_BRIDGE_OPEN_TIMEOUT 500 /* msec */
+#define CCID_CONTROL_TIMEOUT 500 /* msec */
+#define CCID_BRIDGE_MSG_TIMEOUT 1000 /* msec */
+
+static unsigned ccid_bulk_msg_timeout = CCID_BRIDGE_MSG_TIMEOUT;
+module_param_named(bulk_msg_timeout, ccid_bulk_msg_timeout, uint, 0644);
+MODULE_PARM_DESC(bulk_msg_timeout, "Bulk message timeout (msecs)");
+
+struct ccid_bridge {
+	struct usb_device *udev;
+	struct usb_interface *intf;
+	unsigned int in_pipe;
+	unsigned int out_pipe;
+	unsigned int int_pipe;
+	struct urb *inturb;
+	struct urb *readurb;
+	struct urb *writeurb;
+
+	bool opened;
+	bool events_supported;
+	bool is_suspended;
+	struct mutex open_mutex;
+	struct mutex write_mutex;
+	struct mutex read_mutex;
+	struct mutex event_mutex;
+	int write_result;
+	int read_result;
+	int event_result;
+	wait_queue_head_t open_wq;
+	wait_queue_head_t write_wq;
+	wait_queue_head_t read_wq;
+	wait_queue_head_t event_wq;
+	struct usb_ccid_event cur_event;
+	void *intbuf;
+
+	dev_t chrdev;
+	struct cdev cdev;
+	struct class *class;
+	struct device *device;
+};
+
+static struct ccid_bridge *__ccid_bridge_dev;
+
+static void ccid_bridge_out_cb(struct urb *urb)
+{
+	struct ccid_bridge *ccid = urb->context;
+
+	if (urb->dev->state == USB_STATE_NOTATTACHED)
+		ccid->write_result = -ENODEV;
+	else
+		ccid->write_result = urb->status ? : urb->actual_length;
+
+	pr_debug("write result = %d", ccid->write_result);
+	wake_up(&ccid->write_wq);
+}
+
+static void ccid_bridge_in_cb(struct urb *urb)
+{
+	struct ccid_bridge *ccid = urb->context;
+
+	if (urb->dev->state == USB_STATE_NOTATTACHED)
+		ccid->read_result = -ENODEV;
+	else
+		ccid->read_result = urb->status ? : urb->actual_length;
+
+	pr_debug("read result = %d", ccid->read_result);
+	wake_up(&ccid->read_wq);
+}
+
+static void ccid_bridge_int_cb(struct urb *urb)
+{
+	struct ccid_bridge *ccid = urb->context;
+	u8 *msg_type;
+	bool wakeup = true;
+
+	if (urb->dev->state == USB_STATE_NOTATTACHED || (urb->status &&
+				urb->status != -ENOENT)) {
+		ccid->event_result = -ENODEV;
+		wakeup = true;
+		goto out;
+	}
+
+	/*
+	 * Don't wakeup the event ioctl process during suspend.
+	 * The suspend state is not visible to user space.
+	 * we wake up the process after resume to send RESUME
+	 * event if the device supports remote wakeup.
+	 */
+	if (urb->status == -ENOENT && !urb->actual_length) {
+		ccid->event_result = -ENOENT;
+		wakeup = false;
+		goto out;
+	}
+
+	ccid->event_result = 0;
+	msg_type = urb->transfer_buffer;
+	switch (*msg_type) {
+	case CCID_NOTIFY_SLOT_CHANGE:
+		pr_debug("NOTIFY_SLOT_CHANGE event arrived");
+		ccid->cur_event.event = USB_CCID_NOTIFY_SLOT_CHANGE_EVENT;
+		ccid->cur_event.u.notify.slot_icc_state = *(++msg_type);
+		break;
+	case CCID_NOTIFY_HARDWARE_ERROR:
+		pr_debug("NOTIFY_HARDWARE_ERROR event arrived");
+		ccid->cur_event.event = USB_CCID_HARDWARE_ERROR_EVENT;
+		ccid->cur_event.u.error.slot = *(++msg_type);
+		ccid->cur_event.u.error.seq = *(++msg_type);
+		ccid->cur_event.u.error.error_code = *(++msg_type);
+		break;
+	default:
+		pr_err("UNKNOWN event arrived\n");
+		ccid->event_result = -EINVAL;
+	}
+
+out:
+	pr_debug("returning %d", ccid->event_result);
+	if (wakeup)
+		wake_up(&ccid->event_wq);
+}
+
+static int ccid_bridge_submit_inturb(struct ccid_bridge *ccid)
+{
+	int ret = 0;
+
+	/*
+	 * Don't resume the bus to submit an interrupt URB.
+	 * We submit the URB in resume path.  This is important.
+	 * Because the device will be in suspend state during
+	 * multiple system suspend/resume cycles.  The user space
+	 * process comes here during system resume after it is
+	 * unfrozen.
+	 */
+	if (!ccid->int_pipe || ccid->is_suspended)
+		goto out;
+
+	ret = usb_autopm_get_interface(ccid->intf);
+	if (ret < 0) {
+		pr_debug("fail to get autopm with %d\n", ret);
+		goto out;
+	}
+	ret = usb_submit_urb(ccid->inturb, GFP_KERNEL);
+	if (ret < 0)
+		pr_err("fail to submit int urb with %d\n", ret);
+	usb_autopm_put_interface(ccid->intf);
+
+out:
+	pr_debug("returning %d", ret);
+	return ret;
+}
+
+static int ccid_bridge_get_event(struct ccid_bridge *ccid)
+{
+	int ret = 0;
+
+	/*
+	 * The first event returned after the device resume
+	 * will be RESUME event.  This event is set by
+	 * the resume.
+	 */
+	if (ccid->cur_event.event)
+		goto out;
+
+	ccid->event_result = -EINPROGRESS;
+
+	ret = ccid_bridge_submit_inturb(ccid);
+	if (ret < 0)
+		goto out;
+
+	/*
+	 * Wait for the notification on interrupt endpoint
+	 * or remote wakeup event from the resume.  The
+	 * int urb completion handler and resume callback
+	 * take care of setting the current event.
+	 */
+	mutex_unlock(&ccid->event_mutex);
+	ret = wait_event_interruptible(ccid->event_wq,
+			(ccid->event_result != -EINPROGRESS));
+	mutex_lock(&ccid->event_mutex);
+
+	if (ret == -ERESTARTSYS) /* interrupted */
+		usb_kill_urb(ccid->inturb);
+	else
+		ret = ccid->event_result;
+out:
+	pr_debug("returning %d", ret);
+	return ret;
+}
+
+static int ccid_bridge_open(struct inode *ip, struct file *fp)
+{
+	struct ccid_bridge *ccid = container_of(ip->i_cdev,
+				struct ccid_bridge, cdev);
+	int ret;
+
+	pr_debug("called");
+
+	mutex_lock(&ccid->open_mutex);
+	if (ccid->opened) {
+		ret = -EBUSY;
+		goto out;
+	}
+	mutex_unlock(&ccid->open_mutex);
+
+	ret = wait_event_interruptible_timeout(ccid->open_wq,
+			ccid->intf != NULL, msecs_to_jiffies(
+				CCID_BRIDGE_OPEN_TIMEOUT));
+
+	mutex_lock(&ccid->open_mutex);
+
+	if (ret != -ERESTARTSYS && ccid->intf) {
+		fp->private_data = ccid;
+		ccid->opened = true;
+		ret = 0;
+	} else if (!ret) { /* timed out */
+		ret = -ENODEV;
+	}
+out:
+	mutex_unlock(&ccid->open_mutex);
+	pr_debug("returning %d", ret);
+	return ret;
+}
+
+static ssize_t ccid_bridge_write(struct file *fp, const char __user *ubuf,
+				 size_t count, loff_t *pos)
+{
+	struct ccid_bridge *ccid = fp->private_data;
+	int ret;
+	char *kbuf;
+
+	pr_debug("called with %d", count);
+
+	if (!ccid->intf) {
+		pr_debug("intf is not active");
+		return -ENODEV;
+	}
+
+	mutex_lock(&ccid->write_mutex);
+
+	if (!count || count > CCID_BRIDGE_MSG_SZ) {
+		pr_err("invalid count");
+		ret = -EINVAL;
+		goto out;
+	}
+
+	kbuf = kmalloc(count, GFP_KERNEL);
+	if (!kbuf) {
+		pr_err("fail to allocate memory");
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	ret = copy_from_user(kbuf, ubuf, count);
+	if (ret) {
+		pr_err("fail to copy user buf");
+		ret = -EFAULT;
+		goto free_kbuf;
+	}
+
+	ret = usb_autopm_get_interface(ccid->intf);
+	if (ret) {
+		pr_err("fail to get autopm with %d", ret);
+		goto free_kbuf;
+	}
+
+	ccid->write_result = 0;
+
+	usb_fill_bulk_urb(ccid->writeurb, ccid->udev, ccid->out_pipe,
+			kbuf, count, ccid_bridge_out_cb, ccid);
+	ret = usb_submit_urb(ccid->writeurb, GFP_KERNEL);
+	if (ret < 0) {
+		pr_err("urb submit fail with %d", ret);
+		goto put_pm;
+	}
+
+	ret = wait_event_interruptible_timeout(ccid->write_wq,
+			ccid->write_result != 0,
+			msecs_to_jiffies(ccid_bulk_msg_timeout));
+	if (!ret || ret == -ERESTARTSYS) { /* timedout or interrupted */
+		usb_kill_urb(ccid->writeurb);
+		if (!ret)
+			ret = -ETIMEDOUT;
+	} else {
+		ret = ccid->write_result;
+	}
+
+	pr_debug("returning %d", ret);
+
+put_pm:
+	if (ret != -ENODEV)
+		usb_autopm_put_interface(ccid->intf);
+free_kbuf:
+	kfree(kbuf);
+out:
+	mutex_unlock(&ccid->write_mutex);
+	return ret;
+
+}
+
+static ssize_t ccid_bridge_read(struct file *fp, char __user *ubuf,
+				 size_t count, loff_t *pos)
+{
+	struct ccid_bridge *ccid = fp->private_data;
+	int ret;
+	char *kbuf;
+
+	pr_debug("called with %d", count);
+	if (!ccid->intf) {
+		pr_debug("intf is not active");
+		return -ENODEV;
+	}
+
+	mutex_lock(&ccid->read_mutex);
+
+	if (!count || count > CCID_BRIDGE_MSG_SZ) {
+		pr_err("invalid count");
+		ret = -EINVAL;
+		goto out;
+	}
+
+	kbuf = kmalloc(count, GFP_KERNEL);
+	if (!kbuf) {
+		pr_err("fail to allocate memory");
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	ret = usb_autopm_get_interface(ccid->intf);
+	if (ret) {
+		pr_err("fail to get autopm with %d", ret);
+		goto free_kbuf;
+	}
+
+	ccid->read_result = 0;
+
+	usb_fill_bulk_urb(ccid->readurb, ccid->udev, ccid->in_pipe,
+			kbuf, count, ccid_bridge_in_cb, ccid);
+	ret = usb_submit_urb(ccid->readurb, GFP_KERNEL);
+	if (ret < 0) {
+		pr_err("urb submit fail with %d", ret);
+		if (ret != -ENODEV)
+			usb_autopm_put_interface(ccid->intf);
+		goto free_kbuf;
+	}
+
+
+	ret = wait_event_interruptible_timeout(ccid->read_wq,
+			ccid->read_result != 0,
+			msecs_to_jiffies(ccid_bulk_msg_timeout));
+	if (!ret || ret == -ERESTARTSYS) { /* timedout or interrupted */
+		usb_kill_urb(ccid->readurb);
+		if (!ret)
+			ret = -ETIMEDOUT;
+	} else {
+		ret = ccid->read_result;
+	}
+
+
+	if (ret > 0) {
+		if (copy_to_user(ubuf, kbuf, ret))
+			ret = -EFAULT;
+	}
+
+	usb_autopm_put_interface(ccid->intf);
+	pr_debug("returning %d", ret);
+
+free_kbuf:
+	kfree(kbuf);
+out:
+	mutex_unlock(&ccid->read_mutex);
+	return ret;
+}
+
+static long
+ccid_bridge_ioctl(struct file *fp, unsigned int cmd, unsigned long arg)
+{
+	struct ccid_bridge *ccid = fp->private_data;
+	char *buf;
+	struct usb_ccid_data data;
+	struct usb_ccid_abort abort;
+	struct usb_descriptor_header *header;
+	int ret;
+	struct usb_device *udev = ccid->udev;
+	__u8 intf = ccid->intf->cur_altsetting->desc.bInterfaceNumber;
+	__u8 breq = 0;
+
+	if (!ccid->intf) {
+		pr_debug("intf is not active");
+		return -ENODEV;
+	}
+
+	mutex_lock(&ccid->event_mutex);
+	switch (cmd) {
+	case USB_CCID_GET_CLASS_DESC:
+		pr_debug("GET_CLASS_DESC ioctl called");
+		ret = copy_from_user(&data, (void __user *)arg, sizeof(data));
+		if (ret) {
+			ret = -EFAULT;
+			break;
+		}
+		ret = __usb_get_extra_descriptor(udev->rawdescriptors[0],
+				le16_to_cpu(udev->config[0].desc.wTotalLength),
+				CCID_CLASS_DECRIPTOR_TYPE, (void **) &buf);
+		if (ret) {
+			ret = -ENOENT;
+			break;
+		}
+		header = (struct usb_descriptor_header *) buf;
+		if (data.length != header->bLength) {
+			ret = -EINVAL;
+			break;
+		}
+		ret = copy_to_user((void __user *)data.data, buf, data.length);
+		if (ret)
+			ret = -EFAULT;
+		break;
+	case USB_CCID_GET_CLOCK_FREQUENCIES:
+		pr_debug("GET_CLOCK_FREQUENCIES ioctl called");
+		breq = CCID_GET_CLK_FREQ_REQ;
+		/* fall through */
+	case USB_CCID_GET_DATA_RATES:
+		if (!breq) {
+			pr_debug("GET_DATA_RATES ioctl called");
+			breq = CCID_GET_DATA_RATES;
+		}
+		ret = copy_from_user(&data, (void __user *)arg, sizeof(data));
+		if (ret) {
+			ret = -EFAULT;
+			break;
+		}
+		buf = kmalloc(data.length, GFP_KERNEL);
+		if (!buf) {
+			ret = -ENOMEM;
+			break;
+		}
+		ret = usb_autopm_get_interface(ccid->intf);
+		if (ret < 0) {
+			pr_debug("fail to get autopm with %d", ret);
+			break;
+		}
+		ret = usb_control_msg(ccid->udev,
+				usb_rcvctrlpipe(ccid->udev, 0),
+				breq, (USB_DIR_IN | USB_TYPE_CLASS |
+				 USB_RECIP_INTERFACE), 0, intf, buf,
+				data.length, CCID_CONTROL_TIMEOUT);
+		usb_autopm_put_interface(ccid->intf);
+		if (ret == data.length) {
+			ret = copy_to_user((void __user *)data.data, buf,
+					data.length);
+			if (ret)
+				ret = -EFAULT;
+		} else {
+			if (ret > 0)
+				ret = -EPIPE;
+		}
+		kfree(buf);
+		break;
+	case USB_CCID_ABORT:
+		pr_debug("ABORT ioctl called");
+		breq = CCID_ABORT_REQ;
+		ret = copy_from_user(&abort, (void __user *)arg, sizeof(abort));
+		if (ret) {
+			ret = -EFAULT;
+			break;
+		}
+		ret = usb_autopm_get_interface(ccid->intf);
+		if (ret < 0) {
+			pr_debug("fail to get autopm with %d", ret);
+			break;
+		}
+		ret = usb_control_msg(ccid->udev,
+				usb_sndctrlpipe(ccid->udev, 0),
+				breq, (USB_DIR_OUT | USB_TYPE_CLASS |
+				 USB_RECIP_INTERFACE),
+				(abort.seq << 8) | abort.slot, intf, NULL,
+				0, CCID_CONTROL_TIMEOUT);
+		if (ret < 0)
+			pr_err("abort request failed with err %d\n", ret);
+		usb_autopm_put_interface(ccid->intf);
+		break;
+	case USB_CCID_GET_EVENT:
+		pr_debug("GET_EVENT ioctl called");
+		if (!ccid->events_supported) {
+			ret = -ENOENT;
+			break;
+		}
+		ret = ccid_bridge_get_event(ccid);
+		if (ret == 0) {
+			ret = copy_to_user((void __user *)arg, &ccid->cur_event,
+					sizeof(ccid->cur_event));
+			if (ret)
+				ret = -EFAULT;
+		}
+		ccid->cur_event.event = 0;
+		break;
+	default:
+		pr_err("UNKNOWN ioctl called");
+		ret = -EINVAL;
+		break;
+	}
+
+	mutex_unlock(&ccid->event_mutex);
+	pr_debug("returning %d", ret);
+	return ret;
+}
+
+static int ccid_bridge_release(struct inode *ip, struct file *fp)
+{
+	struct ccid_bridge *ccid = fp->private_data;
+
+	pr_debug("called");
+
+	usb_kill_urb(ccid->writeurb);
+	usb_kill_urb(ccid->readurb);
+	if (ccid->int_pipe)
+		usb_kill_urb(ccid->inturb);
+
+	ccid->event_result = -EIO;
+	wake_up(&ccid->event_wq);
+
+	mutex_lock(&ccid->open_mutex);
+	ccid->opened = false;
+	mutex_unlock(&ccid->open_mutex);
+	return 0;
+}
+
+static const struct file_operations ccid_bridge_fops = {
+	.owner = THIS_MODULE,
+	.open = ccid_bridge_open,
+	.write = ccid_bridge_write,
+	.read = ccid_bridge_read,
+	.unlocked_ioctl = ccid_bridge_ioctl,
+	.release = ccid_bridge_release,
+};
+
+static int ccid_bridge_suspend(struct usb_interface *intf, pm_message_t message)
+{
+	struct ccid_bridge *ccid = usb_get_intfdata(intf);
+	int ret = 0;
+
+	pr_debug("called");
+
+	if (!ccid->opened)
+		goto out;
+
+	mutex_lock(&ccid->event_mutex);
+	if (ccid->int_pipe) {
+		usb_kill_urb(ccid->inturb);
+		if (ccid->event_result != -ENOENT) {
+			ret = -EBUSY;
+			goto rel_mutex;
+		}
+	}
+
+	ccid->is_suspended = true;
+rel_mutex:
+	mutex_unlock(&ccid->event_mutex);
+out:
+	pr_debug("returning %d", ret);
+	return ret;
+}
+
+static int ccid_bridge_resume(struct usb_interface *intf)
+{
+	struct ccid_bridge *ccid = usb_get_intfdata(intf);
+	int ret;
+
+	pr_debug("called");
+
+	if (!ccid->opened)
+		goto out;
+
+	mutex_lock(&ccid->event_mutex);
+
+	ccid->is_suspended = false;
+
+	if (device_can_wakeup(&ccid->udev->dev)) {
+		ccid->event_result = 0;
+		ccid->cur_event.event = USB_CCID_RESUME_EVENT;
+		wake_up(&ccid->event_wq);
+	} else if (ccid->int_pipe) {
+		ccid->event_result = -EINPROGRESS;
+		ret = usb_submit_urb(ccid->inturb, GFP_KERNEL);
+		if (ret < 0)
+			pr_debug("fail to submit inturb with %d\n", ret);
+	}
+
+	mutex_unlock(&ccid->event_mutex);
+out:
+	return 0;
+}
+
+static int
+ccid_bridge_probe(struct usb_interface *intf, const struct usb_device_id *id)
+{
+	struct ccid_bridge *ccid = __ccid_bridge_dev;
+	struct usb_host_interface *intf_desc;
+	struct usb_endpoint_descriptor *ep_desc;
+	struct usb_host_endpoint *ep;
+	__u8 epin_addr = 0, epout_addr = 0, epint_addr = 0;
+	int i, ret;
+
+	intf_desc = intf->cur_altsetting;
+
+	if (intf_desc->desc.bNumEndpoints > 3)
+		return -ENODEV;
+
+	for (i = 0; i < intf_desc->desc.bNumEndpoints; i++) {
+		ep_desc = &intf_desc->endpoint[i].desc;
+
+		if (usb_endpoint_is_bulk_in(ep_desc))
+			epin_addr = ep_desc->bEndpointAddress;
+		else if (usb_endpoint_is_bulk_out(ep_desc))
+			epout_addr = ep_desc->bEndpointAddress;
+		else if (usb_endpoint_is_int_in(ep_desc))
+			epint_addr = ep_desc->bEndpointAddress;
+		else
+			return -ENODEV;
+	}
+
+	if (!epin_addr || !epout_addr)
+		return -ENODEV;
+
+	ccid->udev = usb_get_dev(interface_to_usbdev(intf));
+	ccid->in_pipe = usb_rcvbulkpipe(ccid->udev, epin_addr);
+	ccid->out_pipe = usb_sndbulkpipe(ccid->udev, epout_addr);
+	if (epint_addr)
+		ccid->int_pipe = usb_rcvbulkpipe(ccid->udev, epint_addr);
+
+	ccid->writeurb = usb_alloc_urb(0, GFP_KERNEL);
+	if (!ccid->writeurb) {
+		pr_err("fail to allocate write urb");
+		ret = -ENOMEM;
+		goto put_udev;
+	}
+	ccid->readurb = usb_alloc_urb(0, GFP_KERNEL);
+	if (!ccid->readurb) {
+		pr_err("fail to allocate read urb");
+		ret = -ENOMEM;
+		goto free_writeurb;
+	}
+
+	if (ccid->int_pipe) {
+		pr_debug("interrupt endpoint is present");
+		ep = usb_pipe_endpoint(ccid->udev, ccid->int_pipe);
+		ccid->inturb = usb_alloc_urb(0, GFP_KERNEL);
+		if (!ccid->inturb) {
+			pr_err("fail to allocate int urb");
+			ret = -ENOMEM;
+			goto free_readurb;
+		}
+		ccid->intbuf = kmalloc(usb_endpoint_maxp(&ep->desc),
+				GFP_KERNEL);
+		if (!ccid->intbuf) {
+			pr_err("fail to allocated int buf");
+			ret = -ENOMEM;
+			goto free_inturb;
+		}
+		usb_fill_int_urb(ccid->inturb, ccid->udev,
+				usb_rcvintpipe(ccid->udev, epint_addr),
+				ccid->intbuf, usb_endpoint_maxp(&ep->desc),
+				ccid_bridge_int_cb, ccid,
+				ep->desc.bInterval);
+	}
+
+	if (ccid->int_pipe || device_can_wakeup(&ccid->udev->dev)) {
+		pr_debug("event support is present");
+		ccid->events_supported = true;
+	}
+
+	usb_set_intfdata(intf, ccid);
+	usb_enable_autosuspend(ccid->udev);
+
+	mutex_lock(&ccid->open_mutex);
+	ccid->intf = intf;
+	wake_up(&ccid->open_wq);
+	mutex_unlock(&ccid->open_mutex);
+
+	pr_info("success");
+	return 0;
+
+free_inturb:
+	if (ccid->int_pipe)
+		usb_free_urb(ccid->inturb);
+free_readurb:
+	usb_free_urb(ccid->readurb);
+free_writeurb:
+	usb_free_urb(ccid->writeurb);
+put_udev:
+	usb_put_dev(ccid->udev);
+	return ret;
+}
+
+static void ccid_bridge_disconnect(struct usb_interface *intf)
+{
+	struct ccid_bridge *ccid = usb_get_intfdata(intf);
+
+	pr_debug("called");
+
+	usb_kill_urb(ccid->writeurb);
+	usb_kill_urb(ccid->readurb);
+	if (ccid->int_pipe)
+		usb_kill_urb(ccid->inturb);
+
+	ccid->event_result = -ENODEV;
+	wake_up(&ccid->event_wq);
+
+	/*
+	 * This would synchronize any ongoing read/write/ioctl.
+	 * After acquiring the mutex, we can safely set
+	 * intf to NULL.
+	 */
+	mutex_lock(&ccid->open_mutex);
+	mutex_lock(&ccid->write_mutex);
+	mutex_lock(&ccid->read_mutex);
+	mutex_lock(&ccid->event_mutex);
+
+	usb_free_urb(ccid->writeurb);
+	usb_free_urb(ccid->readurb);
+	if (ccid->int_pipe) {
+		usb_free_urb(ccid->inturb);
+		kfree(ccid->intbuf);
+		ccid->int_pipe = 0;
+	}
+
+	ccid->intf = NULL;
+	usb_put_dev(ccid->udev);
+
+	mutex_unlock(&ccid->event_mutex);
+	mutex_unlock(&ccid->read_mutex);
+	mutex_unlock(&ccid->write_mutex);
+	mutex_unlock(&ccid->open_mutex);
+
+}
+
+static const struct usb_device_id ccid_bridge_ids[] = {
+	{ USB_INTERFACE_INFO(USB_CLASS_CSCID, 0, 0) },
+
+	{} /* terminating entry */
+};
+MODULE_DEVICE_TABLE(usb, ccid_bridge_ids);
+
+static struct usb_driver ccid_bridge_driver = {
+	.name = "ccid_bridge",
+	.probe = ccid_bridge_probe,
+	.disconnect = ccid_bridge_disconnect,
+	.suspend = ccid_bridge_suspend,
+	.resume = ccid_bridge_resume,
+	.id_table = ccid_bridge_ids,
+	.supports_autosuspend = 1,
+};
+
+static int __init ccid_bridge_init(void)
+{
+	int ret;
+	struct ccid_bridge *ccid;
+
+	ccid = kzalloc(sizeof(*ccid), GFP_KERNEL);
+	if (!ccid) {
+		pr_err("Fail to allocate ccid");
+		ret = -ENOMEM;
+		goto out;
+	}
+	__ccid_bridge_dev = ccid;
+
+	mutex_init(&ccid->open_mutex);
+	mutex_init(&ccid->write_mutex);
+	mutex_init(&ccid->read_mutex);
+	mutex_init(&ccid->event_mutex);
+
+	init_waitqueue_head(&ccid->open_wq);
+	init_waitqueue_head(&ccid->write_wq);
+	init_waitqueue_head(&ccid->read_wq);
+	init_waitqueue_head(&ccid->event_wq);
+
+	ret = usb_register(&ccid_bridge_driver);
+	if (ret < 0) {
+		pr_err("Fail to register ccid usb driver with %d", ret);
+		goto free_ccid;
+	}
+
+	ret = alloc_chrdev_region(&ccid->chrdev, 0, 1, "ccid_bridge");
+	if (ret < 0) {
+		pr_err("Fail to allocate ccid char dev region with %d", ret);
+		goto unreg_driver;
+	}
+	ccid->class = class_create(THIS_MODULE, "ccid_bridge");
+	if (IS_ERR(ccid->class)) {
+		ret = PTR_ERR(ccid->class);
+		pr_err("Fail to create ccid class with %d", ret);
+		goto unreg_chrdev;
+	}
+	cdev_init(&ccid->cdev, &ccid_bridge_fops);
+	ccid->cdev.owner = THIS_MODULE;
+
+	ret = cdev_add(&ccid->cdev, ccid->chrdev, 1);
+	if (ret < 0) {
+		pr_err("Fail to add ccid cdev with %d", ret);
+		goto destroy_class;
+	}
+	ccid->device = device_create(ccid->class,
+					NULL, ccid->chrdev, NULL,
+					"ccid_bridge");
+	if (IS_ERR(ccid->device)) {
+		ret = PTR_ERR(ccid->device);
+		pr_err("Fail to create ccid device with %d", ret);
+		goto del_cdev;
+	}
+
+	pr_info("success");
+
+	return 0;
+
+del_cdev:
+	cdev_del(&ccid->cdev);
+destroy_class:
+	class_destroy(ccid->class);
+unreg_chrdev:
+	unregister_chrdev_region(ccid->chrdev, 1);
+unreg_driver:
+	usb_deregister(&ccid_bridge_driver);
+free_ccid:
+	mutex_destroy(&ccid->open_mutex);
+	mutex_destroy(&ccid->write_mutex);
+	mutex_destroy(&ccid->read_mutex);
+	mutex_destroy(&ccid->event_mutex);
+	kfree(ccid);
+	__ccid_bridge_dev = NULL;
+out:
+	return ret;
+}
+
+static void __exit ccid_bridge_exit(void)
+{
+	struct ccid_bridge *ccid = __ccid_bridge_dev;
+
+	pr_debug("called");
+	device_destroy(ccid->class, ccid->chrdev);
+	cdev_del(&ccid->cdev);
+	class_destroy(ccid->class);
+	unregister_chrdev_region(ccid->chrdev, 1);
+
+	usb_deregister(&ccid_bridge_driver);
+
+	mutex_destroy(&ccid->open_mutex);
+	mutex_destroy(&ccid->write_mutex);
+	mutex_destroy(&ccid->read_mutex);
+	mutex_destroy(&ccid->event_mutex);
+
+	kfree(ccid);
+	__ccid_bridge_dev = NULL;
+}
+
+module_init(ccid_bridge_init);
+module_exit(ccid_bridge_exit);
+
+MODULE_DESCRIPTION("USB CCID bridge driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index d97d548..827ac9d 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -3159,7 +3159,8 @@
 	for (i = 0; i < GET_DESCRIPTOR_TRIES; (++i, msleep(100))) {
 		if (USE_NEW_SCHEME(retry_counter) &&
 			!(hcd->driver->flags & HCD_USB3) &&
-			!(hcd->driver->flags & HCD_OLD_ENUM)) {
+			!((hcd->driver->flags & HCD_RT_OLD_ENUM) &&
+				!hdev->parent)) {
 			struct usb_device_descriptor *buf;
 			int r = 0;
 
@@ -3261,7 +3262,8 @@
 			msleep(10);
 			if (USE_NEW_SCHEME(retry_counter) &&
 				!(hcd->driver->flags & HCD_USB3) &&
-				!(hcd->driver->flags & HCD_OLD_ENUM))
+				!((hcd->driver->flags & HCD_RT_OLD_ENUM) &&
+					!hdev->parent))
 				break;
   		}
 
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 1be2550..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)
@@ -631,6 +638,7 @@
 
 	u8			epnum;
 	struct dwc3_trb		*trb;
+	struct dwc3_trb		*ztrb;
 	dma_addr_t		trb_dma;
 
 	unsigned		direction:1;
@@ -742,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/debug.h b/drivers/usb/dwc3/debug.h
index 4901f4b..57d27cd 100644
--- a/drivers/usb/dwc3/debug.h
+++ b/drivers/usb/dwc3/debug.h
@@ -48,15 +48,17 @@
 extern void dwc3_debugfs_exit(struct dwc3 *);
 extern void dbg_print_reg(const char *name, int reg);
 #else
-static inline void dbg_event(u8, const char*, int)
+static inline void dbg_event(u8 ep_num, const char *name, int status)
 {  }
-static inline void dbg_print(u8, const char*, int, const char*)
+static inline void dbg_print(u8 ep_num, const char *name, int status,
+			     const char *extra)
 {  }
-static inline void dbg_done(u8, const u32, int)
+static inline void dbg_done(u8 ep_num, const u32 count, int status)
 {  }
-static inline void dbg_queue(u8, const struct usb_request*, int)
+static inline void dbg_queue(u8 ep_num, const struct usb_request *req,
+			     int status)
 {  }
-static inline void dbg_setup(u8, const struct usb_ctrlrequest*)
+static inline void dbg_setup(u8 ep_num, const struct usb_ctrlrequest *req)
 {  }
 static inline void dbg_print_reg(const char *name, int reg)
 {  }
diff --git a/drivers/usb/dwc3/debugfs.c b/drivers/usb/dwc3/debugfs.c
index a2580fc..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),
@@ -794,9 +795,9 @@
 	.release		= single_release,
 };
 
-static unsigned int ep_addr_rxdbg_mask;
+static unsigned int ep_addr_rxdbg_mask = 1;
 module_param(ep_addr_rxdbg_mask, uint, S_IRUGO | S_IWUSR);
-static unsigned int ep_addr_txdbg_mask;
+static unsigned int ep_addr_txdbg_mask = 1;
 module_param(ep_addr_txdbg_mask, uint, S_IRUGO | S_IWUSR);
 
 /* Maximum debug message length */
diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c
index 97592c4..7d4ecd6 100644
--- a/drivers/usb/dwc3/dwc3-msm.c
+++ b/drivers/usb/dwc3/dwc3-msm.c
@@ -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
@@ -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;
@@ -217,6 +219,7 @@
 	struct qpnp_adc_tm_chip *adc_tm_dev;
 	struct delayed_work	init_adc_work;
 	bool			id_adc_detect;
+	struct qpnp_vadc_chip	*vadc_dev;
 	u8			dcd_retries;
 	u32			bus_perf_client;
 	struct msm_bus_scale_pdata	*bus_scale_table;
@@ -237,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;
@@ -1090,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__);
@@ -1444,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)
@@ -1512,6 +1558,7 @@
 	case DWC3_CONTROLLER_ERROR_EVENT:
 		dev_info(mdwc->dev, "DWC3_CONTROLLER_ERROR_EVENT received\n");
 		dwc3_msm_dump_phy_info(mdwc);
+		dwc3_msm_write_reg(mdwc->base, DWC3_DEVTEN, 0);
 		/*
 		 * schedule work for doing block reset for recovery from erratic
 		 * error event.
@@ -1527,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:
@@ -1567,10 +1615,23 @@
 {
 	struct dwc3_msm *mdwc = container_of(w, struct dwc3_msm,
 						usb_block_reset_work);
+	u32 reg;
 
 	dev_dbg(mdwc->dev, "%s\n", __func__);
 
 	dwc3_msm_block_reset(&mdwc->ext_xceiv, true);
+
+	reg = (DWC3_DEVTEN_EVNTOVERFLOWEN |
+			DWC3_DEVTEN_CMDCMPLTEN |
+			DWC3_DEVTEN_ERRTICERREN |
+			DWC3_DEVTEN_WKUPEVTEN |
+			DWC3_DEVTEN_ULSTCNGEN |
+			DWC3_DEVTEN_CONNECTDONEEN |
+			DWC3_DEVTEN_USBRSTEN |
+			DWC3_DEVTEN_DISCONNEVTEN);
+	dwc3_msm_write_reg(mdwc->base, DWC3_DEVTEN, reg);
+
+
 }
 
 static void dwc3_chg_enable_secondary_det(struct dwc3_msm *mdwc)
@@ -1791,6 +1852,11 @@
 		return;
 	}
 
+	/* Skip if charger type was already detected externally */
+	if (mdwc->chg_state == USB_CHG_STATE_DETECTED &&
+		charger->chg_type != DWC3_INVALID_CHARGER)
+		return;
+
 	mdwc->chg_state = USB_CHG_STATE_UNDEFINED;
 	charger->chg_type = DWC3_INVALID_CHARGER;
 	queue_delayed_work(system_nrt_wq, &mdwc->chg_work, 0);
@@ -1803,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__);
 
@@ -1830,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,
@@ -1932,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;
@@ -2069,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");
 
@@ -2239,6 +2317,27 @@
 	return IRQ_HANDLED;
 }
 
+static int
+get_prop_usbin_voltage_now(struct dwc3_msm *mdwc)
+{
+	int rc = 0;
+	struct qpnp_vadc_result results;
+
+	if (IS_ERR_OR_NULL(mdwc->vadc_dev)) {
+		mdwc->vadc_dev = qpnp_get_vadc(mdwc->dev, "usbin");
+		if (IS_ERR(mdwc->vadc_dev))
+			return PTR_ERR(mdwc->vadc_dev);
+	}
+
+	rc = qpnp_vadc_read(mdwc->vadc_dev, USBIN, &results);
+	if (rc) {
+		pr_err("Unable to read usbin rc=%d\n", rc);
+		return 0;
+	} else {
+		return results.physical;
+	}
+}
+
 static int dwc3_msm_power_get_property_usb(struct power_supply *psy,
 				  enum power_supply_property psp,
 				  union power_supply_propval *val)
@@ -2264,6 +2363,9 @@
 	case POWER_SUPPLY_PROP_TYPE:
 		val->intval = psy->type;
 		break;
+	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+		val->intval = get_prop_usbin_voltage_now(mdwc);
+		break;
 	default:
 		return -EINVAL;
 	}
@@ -2372,6 +2474,7 @@
 	POWER_SUPPLY_PROP_CURRENT_MAX,
 	POWER_SUPPLY_PROP_TYPE,
 	POWER_SUPPLY_PROP_SCOPE,
+	POWER_SUPPLY_PROP_VOLTAGE_NOW,
 };
 
 static void dwc3_init_adc_work(struct work_struct *w);
@@ -2616,6 +2719,42 @@
 			pm_runtime_put(mdwc->dev);
 		}
 		break;
+	case MSM_USB_EXT_CHG_VOLTAGE_INFO:
+		if (get_user(val, (int __user *)arg)) {
+			pr_err("%s: get_user failed\n\n", __func__);
+			ret = -EFAULT;
+			break;
+		}
+
+		if (val == USB_REQUEST_5V)
+			pr_debug("%s:voting 5V voltage request\n", __func__);
+		else if (val == USB_REQUEST_9V)
+			pr_debug("%s:voting 9V voltage request\n", __func__);
+		break;
+	case MSM_USB_EXT_CHG_RESULT:
+		if (get_user(val, (int __user *)arg)) {
+			pr_err("%s: get_user failed\n\n", __func__);
+			ret = -EFAULT;
+			break;
+		}
+
+		if (!val)
+			pr_debug("%s:voltage request successful\n", __func__);
+		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;
 	}
@@ -2795,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");
@@ -2912,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 cacd635..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;
@@ -197,6 +208,14 @@
 	if (on) {
 		dev_dbg(otg->phy->dev, "%s: turn on host\n", __func__);
 
+		dwc3_otg_notify_host_mode(otg, on);
+		ret = regulator_enable(dotg->vbus_otg);
+		if (ret) {
+			dev_err(otg->phy->dev, "unable to enable vbus_otg\n");
+			dwc3_otg_notify_host_mode(otg, 0);
+			return ret;
+		}
+
 		/*
 		 * This should be revisited for more testing post-silicon.
 		 * In worst case we may need to disconnect the root hub
@@ -222,14 +241,8 @@
 			dev_err(otg->phy->dev,
 				"%s: failed to add XHCI pdev ret=%d\n",
 				__func__, ret);
-			return ret;
-		}
-
-		dwc3_otg_notify_host_mode(otg, on);
-		ret = regulator_enable(dotg->vbus_otg);
-		if (ret) {
-			dev_err(otg->phy->dev, "unable to enable vbus_otg\n");
-			platform_device_del(dwc->xhci);
+			regulator_disable(dotg->vbus_otg);
+			dwc3_otg_notify_host_mode(otg, 0);
 			return ret;
 		}
 
@@ -996,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/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c
index 0cfd515..c07f18c 100644
--- a/drivers/usb/dwc3/ep0.c
+++ b/drivers/usb/dwc3/ep0.c
@@ -291,6 +291,7 @@
 	struct dwc3_ep			*dep = to_dwc3_ep(ep);
 	struct dwc3			*dwc = dep->dwc;
 
+	dbg_event(dep->number, "EP0STAL", value);
 	dwc3_ep0_stall_and_restart(dwc);
 
 	return 0;
@@ -752,8 +753,10 @@
 		dwc->delayed_status = true;
 
 out:
-	if (ret < 0)
+	if (ret < 0) {
+		dbg_event(0x0, "ERRSTAL", ret);
 		dwc3_ep0_stall_and_restart(dwc);
+	}
 }
 
 bool zlp_required;
@@ -819,7 +822,7 @@
 
 	if ((epnum & 1) && ur->actual < ur->length) {
 		/* for some reason we did not get everything out */
-
+		dbg_event(epnum, "INDATSTAL", 0);
 		dwc3_ep0_stall_and_restart(dwc);
 	} else {
 		/*
@@ -855,6 +858,7 @@
 		if (ret < 0) {
 			dev_dbg(dwc->dev, "Invalid Test #%d\n",
 					dwc->test_mode_nr);
+			dbg_event(0x00, "INVALTEST", ret);
 			dwc3_ep0_stall_and_restart(dwc);
 			return;
 		}
@@ -1034,6 +1038,7 @@
 
 			dev_vdbg(dwc->dev, "Wrong direction for Data phase\n");
 			dwc3_ep0_end_control_data(dwc, dep);
+			dbg_event(epnum, "WRONGDR", 0);
 			dwc3_ep0_stall_and_restart(dwc);
 			return;
 		}
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index ad3a3a9..4be032a 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -294,6 +294,15 @@
 		if (((dep->busy_slot & DWC3_TRB_MASK) == DWC3_TRB_NUM - 1) &&
 				usb_endpoint_xfer_isoc(dep->endpoint.desc))
 			dep->busy_slot++;
+
+		if (req->request.zero && req->ztrb) {
+			dep->busy_slot++;
+			req->ztrb = NULL;
+			if (((dep->busy_slot & DWC3_TRB_MASK) ==
+				DWC3_TRB_NUM - 1) &&
+				usb_endpoint_xfer_isoc(dep->endpoint.desc))
+				dep->busy_slot++;
+		}
 	}
 	list_del(&req->list);
 	req->trb = NULL;
@@ -864,6 +873,7 @@
 		req->trb_dma = dwc3_trb_dma_offset(dep, trb);
 	}
 
+update_trb:
 	trb->size = DWC3_TRB_SIZE_LENGTH(length);
 	trb->bpl = lower_32_bits(dma);
 	trb->bph = upper_32_bits(dma);
@@ -898,15 +908,31 @@
 	} else {
 		if (chain)
 			trb->ctrl |= DWC3_TRB_CTRL_CHN;
-
-		if (last)
-			trb->ctrl |= DWC3_TRB_CTRL_LST;
 	}
 
 	if (usb_endpoint_xfer_bulk(dep->endpoint.desc) && dep->stream_capable)
 		trb->ctrl |= DWC3_TRB_CTRL_SID_SOFN(req->request.stream_id);
 
 	trb->ctrl |= DWC3_TRB_CTRL_HWO;
+
+	if (req->request.zero && length &&
+			(length % usb_endpoint_maxp(dep->endpoint.desc) == 0)) {
+		trb = &dep->trb_pool[dep->free_slot & DWC3_TRB_MASK];
+		dep->free_slot++;
+
+		/* Skip the LINK-TRB on ISOC */
+		if (((dep->free_slot & DWC3_TRB_MASK) == DWC3_TRB_NUM - 1) &&
+			usb_endpoint_xfer_isoc(dep->endpoint.desc))
+			dep->free_slot++;
+
+		req->ztrb = trb;
+		length = 0;
+
+		goto update_trb;
+	}
+
+	if (!usb_endpoint_xfer_isoc(dep->endpoint.desc) && last)
+		trb->ctrl |= DWC3_TRB_CTRL_LST;
 }
 
 /*
@@ -1007,12 +1033,25 @@
 			}
 			dbg_queue(dep->number, &req->request, 0);
 		} else {
+			struct dwc3_request	*req1;
+			int maxpkt_size = usb_endpoint_maxp(dep->endpoint.desc);
+
 			dma = req->request.dma;
 			length = req->request.length;
 			trbs_left--;
 
-			if (!trbs_left)
+			if (req->request.zero && length &&
+						(length % maxpkt_size == 0))
+				trbs_left--;
+
+			if (!trbs_left) {
 				last_one = 1;
+			} else if (dep->direction && (trbs_left <= 1)) {
+				req1 = next_request(&req->list);
+				if (req1->request.zero && req1->request.length
+				 && (req1->request.length % maxpkt_size == 0))
+					last_one = 1;
+			}
 
 			/* Is this the last request? */
 			if (list_is_last(&req->list, &dep->request_list))
@@ -2052,6 +2091,8 @@
 				s_pkt = 1;
 		}
 
+		if (req->ztrb)
+			trb = req->ztrb;
 		/*
 		 * We assume here we will always receive the entire data block
 		 * which we should receive. Meaning, if we program RX to
@@ -2163,6 +2204,7 @@
 			return;
 		}
 
+		dbg_event(dep->number, "XFRCOMP", 0);
 		dwc3_endpoint_transfer_complete(dwc, dep, event, 1);
 		break;
 	case DWC3_DEPEVT_XFERINPROGRESS:
@@ -2172,9 +2214,11 @@
 			return;
 		}
 
+		dbg_event(dep->number, "XFRPROG", 0);
 		dwc3_endpoint_transfer_complete(dwc, dep, event, 0);
 		break;
 	case DWC3_DEPEVT_XFERNOTREADY:
+		dbg_event(dep->number, "XFRNRDY", 0);
 		if (usb_endpoint_xfer_isoc(dep->endpoint.desc)) {
 			dwc3_gadget_start_isoc(dwc, dep, event);
 		} else {
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/ci13xxx_msm.c b/drivers/usb/gadget/ci13xxx_msm.c
index f1e4220..be30b5f 100644
--- a/drivers/usb/gadget/ci13xxx_msm.c
+++ b/drivers/usb/gadget/ci13xxx_msm.c
@@ -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
@@ -62,11 +62,27 @@
 	struct ci13xxx *udc = _udc;
 	struct usb_phy *phy = udc->transceiver;
 
-	if (phy && (phy->flags & ENABLE_DP_MANUAL_PULLUP))
+	if (phy && (phy->flags & ENABLE_DP_MANUAL_PULLUP)) {
+		u32 temp;
+
 		usb_phy_io_write(phy,
 				ULPI_MISC_A_VBUSVLDEXT |
 				ULPI_MISC_A_VBUSVLDEXTSEL,
 				ULPI_CLR(ULPI_MISC_A));
+
+		/* Notify LINK of VBUS LOW */
+		temp = readl_relaxed(USB_USBCMD);
+		temp &= ~USBCMD_SESS_VLD_CTRL;
+		writel_relaxed(temp, USB_USBCMD);
+
+		/*
+		 * Add memory barrier as it is must to complete
+		 * above USB PHY and Link register writes before
+		 * moving ahead with USB peripheral mode enumeration,
+		 * otherwise USB peripheral mode may not work.
+		 */
+		mb();
+	}
 }
 
 /* Link power management will reduce power consumption by
@@ -345,6 +361,11 @@
 	return 0;
 }
 
+void ci13xxx_msm_shutdown(struct platform_device *pdev)
+{
+	ci13xxx_pullup(&_udc->gadget, 0);
+}
+
 void msm_hw_bam_disable(bool bam_disable)
 {
 	u32 val;
@@ -364,6 +385,7 @@
 		.name = "msm_hsusb",
 	},
 	.remove = ci13xxx_msm_remove,
+	.shutdown = ci13xxx_msm_shutdown,
 };
 MODULE_ALIAS("platform:msm_hsusb");
 
diff --git a/drivers/usb/gadget/f_audio_source.c b/drivers/usb/gadget/f_audio_source.c
index 37f229b..33b645e 100644
--- a/drivers/usb/gadget/f_audio_source.c
+++ b/drivers/usb/gadget/f_audio_source.c
@@ -327,15 +327,22 @@
 	s64 msecs;
 	s64 frames;
 	ktime_t now;
+	unsigned long flags;
 
+	spin_lock_irqsave(&audio->lock, flags);
 	/* audio->substream will be null if we have been closed */
-	if (!audio->substream)
+	if (!audio->substream) {
+		spin_unlock_irqrestore(&audio->lock, flags);
 		return;
+	}
 	/* audio->buffer_pos will be null if we have been stopped */
-	if (!audio->buffer_pos)
+	if (!audio->buffer_pos) {
+		spin_unlock_irqrestore(&audio->lock, flags);
 		return;
+	}
 
 	runtime = audio->substream->runtime;
+	spin_unlock_irqrestore(&audio->lock, flags);
 
 	/* compute number of frames to send */
 	now = ktime_get();
@@ -359,8 +366,21 @@
 
 	while (frames > 0) {
 		req = audio_req_get(audio);
-		if (!req)
+		spin_lock_irqsave(&audio->lock, flags);
+		/* audio->substream will be null if we have been closed */
+		if (!audio->substream) {
+			spin_unlock_irqrestore(&audio->lock, flags);
+			return;
+		}
+		/* audio->buffer_pos will be null if we have been stopped */
+		if (!audio->buffer_pos) {
+			spin_unlock_irqrestore(&audio->lock, flags);
+			return;
+		}
+		if (!req) {
+			spin_unlock_irqrestore(&audio->lock, flags);
 			break;
+		}
 
 		length = frames_to_bytes(runtime, frames);
 		if (length > IN_EP_MAX_PACKET_SIZE)
@@ -386,6 +406,7 @@
 		}
 
 		req->length = length;
+		spin_unlock_irqrestore(&audio->lock, flags);
 		ret = usb_ep_queue(audio->in_ep, req, GFP_ATOMIC);
 		if (ret < 0) {
 			pr_err("usb_ep_queue failed ret: %d\n", ret);
diff --git a/drivers/usb/gadget/f_diag.c b/drivers/usb/gadget/f_diag.c
index effe0fd..993d9fb 100644
--- a/drivers/usb/gadget/f_diag.c
+++ b/drivers/usb/gadget/f_diag.c
@@ -26,6 +26,7 @@
 #include <linux/usb/gadget.h>
 #include <linux/workqueue.h>
 #include <linux/debugfs.h>
+#include <linux/kmemleak.h>
 
 static DEFINE_SPINLOCK(ch_lock);
 static LIST_HEAD(usb_diag_ch_list);
@@ -354,28 +355,6 @@
 }
 
 /**
- * usb_diag_free_req() - Free USB requests
- * @ch: Channel handler
- *
- * This function free read and write USB requests for the interface
- * associated with this channel.
- *
- */
-void usb_diag_free_req(struct usb_diag_ch *ch)
-{
-	struct diag_context *ctxt = ch->priv_usb;
-	unsigned long flags;
-
-	if (ctxt) {
-		spin_lock_irqsave(&ctxt->lock, flags);
-		free_reqs(ctxt);
-		spin_unlock_irqrestore(&ctxt->lock, flags);
-	}
-
-}
-EXPORT_SYMBOL(usb_diag_free_req);
-
-/**
  * usb_diag_alloc_req() - Allocate USB requests
  * @ch: Channel handler
  * @n_write: Number of requests for Tx
@@ -403,6 +382,7 @@
 		req = usb_ep_alloc_request(ctxt->in, GFP_ATOMIC);
 		if (!req)
 			goto fail;
+		kmemleak_not_leak(req);
 		req->complete = diag_write_complete;
 		list_add_tail(&req->list, &ctxt->write_pool);
 	}
@@ -411,6 +391,7 @@
 		req = usb_ep_alloc_request(ctxt->out, GFP_ATOMIC);
 		if (!req)
 			goto fail;
+		kmemleak_not_leak(req);
 		req->complete = diag_read_complete;
 		list_add_tail(&req->list, &ctxt->read_pool);
 	}
@@ -530,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/gadget/f_mbim.c b/drivers/usb/gadget/f_mbim.c
index 15f20ca..88a7bde 100644
--- a/drivers/usb/gadget/f_mbim.c
+++ b/drivers/usb/gadget/f_mbim.c
@@ -1710,8 +1710,10 @@
 		return -EIO;
 	}
 
+	spin_lock(&dev->lock);
 	while (list_empty(&dev->cpkt_req_q)) {
 		pr_debug("Requests list is empty. Wait.\n");
+		spin_unlock(&dev->lock);
 		ret = wait_event_interruptible(dev->read_wq,
 			!list_empty(&dev->cpkt_req_q));
 		if (ret < 0) {
@@ -1720,11 +1722,13 @@
 			return -ERESTARTSYS;
 		}
 		pr_debug("Received request packet\n");
+		spin_lock(&dev->lock);
 	}
 
 	cpkt = list_first_entry(&dev->cpkt_req_q, struct ctrl_pkt,
 							list);
 	if (cpkt->len > count) {
+		spin_unlock(&dev->lock);
 		mbim_unlock(&dev->read_excl);
 		pr_err("cpkt size too big:%d > buf size:%d\n",
 				cpkt->len, count);
@@ -1734,6 +1738,7 @@
 	pr_debug("cpkt size:%d\n", cpkt->len);
 
 	list_del(&cpkt->list);
+	spin_unlock(&dev->lock);
 	mbim_unlock(&dev->read_excl);
 
 	ret = copy_to_user(buf, cpkt->buf, cpkt->len);
diff --git a/drivers/usb/gadget/f_mtp.c b/drivers/usb/gadget/f_mtp.c
index 6d7dd3d..88ebd80 100644
--- a/drivers/usb/gadget/f_mtp.c
+++ b/drivers/usb/gadget/f_mtp.c
@@ -899,7 +899,10 @@
 				dev->rx_done || dev->state != STATE_BUSY);
 			if (dev->state == STATE_CANCELED
 					|| dev->state == STATE_OFFLINE) {
-				r = -ECANCELED;
+				if (dev->state == STATE_OFFLINE)
+					r = -EIO;
+				else
+					r = -ECANCELED;
 				if (!dev->rx_done)
 					usb_ep_dequeue(dev->ep_out, read_req);
 				break;
diff --git a/drivers/usb/gadget/f_qc_rndis.c b/drivers/usb/gadget/f_qc_rndis.c
index c1ab552..69f4b1c 100644
--- a/drivers/usb/gadget/f_qc_rndis.c
+++ b/drivers/usb/gadget/f_qc_rndis.c
@@ -6,7 +6,7 @@
  * Copyright (C) 2008 Nokia Corporation
  * Copyright (C) 2009 Samsung Electronics
  *			Author: Michal Nazarewicz (mina86@mina86.com)
- * 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
@@ -347,7 +347,7 @@
 };
 
 static struct usb_descriptor_header *eth_qc_ss_function[] = {
-	(struct usb_descriptor_header *) &rndis_iad_descriptor,
+	(struct usb_descriptor_header *) &rndis_qc_iad_descriptor,
 
 	/* control interface matches ACM, not Ethernet */
 	(struct usb_descriptor_header *) &rndis_qc_control_intf,
@@ -615,7 +615,6 @@
 		/* read the request; process it later */
 		value = w_length;
 		req->complete = rndis_qc_command_complete;
-		req->context = rndis;
 		/* later, rndis_response_available() sends a notification */
 		break;
 
@@ -651,6 +650,7 @@
 		DBG(cdev, "rndis req%02x.%02x v%04x i%04x l%d\n",
 			ctrl->bRequestType, ctrl->bRequest,
 			w_value, w_index, w_length);
+		req->context = rndis;
 		req->zero = (value < w_length);
 		req->length = value;
 		value = usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC);
diff --git a/drivers/usb/gadget/f_qdss.c b/drivers/usb/gadget/f_qdss.c
index 7e474f3..4ecfeac 100644
--- a/drivers/usb/gadget/f_qdss.c
+++ b/drivers/usb/gadget/f_qdss.c
@@ -1,7 +1,7 @@
 /*
  * f_qdss.c -- QDSS function Driver
  *
- * 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
@@ -415,6 +415,8 @@
 
 	pr_debug("qdss_unbind\n");
 
+	flush_workqueue(qdss->wq);
+
 	if (gadget_is_dwc3(gadget))
 		dwc3_tx_fifo_resize_request(qdss->data, false);
 
diff --git a/drivers/usb/gadget/f_rmnet.c b/drivers/usb/gadget/f_rmnet.c
index 2fa8c63..ebcec96 100644
--- a/drivers/usb/gadget/f_rmnet.c
+++ b/drivers/usb/gadget/f_rmnet.c
@@ -1,5 +1,5 @@
 /*
- * 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
@@ -47,7 +47,7 @@
 
 	/* control info */
 	struct list_head		cpkt_resp_q;
-	atomic_t			notify_count;
+	unsigned long			notify_count;
 	unsigned long			cpkts_len;
 };
 
@@ -605,7 +605,7 @@
 		list_del(&cpkt->list);
 		rmnet_free_ctrl_pkt(cpkt);
 	}
-	atomic_set(&dev->notify_count, 0);
+	dev->notify_count = 0;
 	spin_unlock_irqrestore(&dev->lock, flags);
 }
 
@@ -619,6 +619,7 @@
 		__func__, xport_to_str(dxport),
 		dev, dev->port_num);
 
+	usb_ep_fifo_flush(dev->notify);
 	frmnet_purge_responses(dev);
 
 	port_num = rmnet_ports[dev->port_num].data_xport_num;
@@ -754,7 +755,7 @@
 		return;
 	}
 
-	if (atomic_inc_return(&dev->notify_count) != 1) {
+	if (++dev->notify_count != 1) {
 		spin_unlock_irqrestore(&dev->lock, flags);
 		return;
 	}
@@ -772,7 +773,14 @@
 	if (ret) {
 		spin_lock_irqsave(&dev->lock, flags);
 		if (!list_empty(&dev->cpkt_resp_q)) {
-			atomic_dec(&dev->notify_count);
+			if (dev->notify_count > 0)
+				dev->notify_count--;
+			else {
+				pr_debug("%s: Invalid notify_count=%lu to decrement\n",
+					 __func__, dev->notify_count);
+				spin_unlock_irqrestore(&dev->lock, flags);
+				return;
+			}
 			cpkt = list_first_entry(&dev->cpkt_resp_q,
 					struct rmnet_ctrl_pkt, list);
 			list_del(&cpkt->list);
@@ -911,7 +919,9 @@
 	case -ECONNRESET:
 	case -ESHUTDOWN:
 		/* connection gone */
-		atomic_set(&dev->notify_count, 0);
+		spin_lock_irqsave(&dev->lock, flags);
+		dev->notify_count = 0;
+		spin_unlock_irqrestore(&dev->lock, flags);
 		break;
 	default:
 		pr_err("rmnet notify ep error %d\n", status);
@@ -920,14 +930,34 @@
 		if (!atomic_read(&dev->ctrl_online))
 			break;
 
-		if (atomic_dec_and_test(&dev->notify_count))
+		spin_lock_irqsave(&dev->lock, flags);
+		if (dev->notify_count > 0) {
+			dev->notify_count--;
+			if (dev->notify_count == 0) {
+				spin_unlock_irqrestore(&dev->lock, flags);
+				break;
+			}
+		} else {
+			pr_debug("%s: Invalid notify_count=%lu to decrement\n",
+					__func__, dev->notify_count);
+			spin_unlock_irqrestore(&dev->lock, flags);
 			break;
+		}
+		spin_unlock_irqrestore(&dev->lock, flags);
 
 		status = usb_ep_queue(dev->notify, req, GFP_ATOMIC);
 		if (status) {
 			spin_lock_irqsave(&dev->lock, flags);
 			if (!list_empty(&dev->cpkt_resp_q)) {
-				atomic_dec(&dev->notify_count);
+				if (dev->notify_count > 0)
+					dev->notify_count--;
+				else {
+					pr_err("%s: Invalid notify_count=%lu to decrement\n",
+						__func__, dev->notify_count);
+					spin_unlock_irqrestore(&dev->lock,
+								flags);
+					break;
+				}
 				cpkt = list_first_entry(&dev->cpkt_resp_q,
 						struct rmnet_ctrl_pkt, list);
 				list_del(&cpkt->list);
diff --git a/drivers/usb/gadget/f_uac1.c b/drivers/usb/gadget/f_uac1.c
index e8c9667..883c5fa 100644
--- a/drivers/usb/gadget/f_uac1.c
+++ b/drivers/usb/gadget/f_uac1.c
@@ -1,7 +1,7 @@
 /*
  * f_audio.c -- USB Audio class function driver
  *
- * Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
  * Copyright (C) 2008 Bryan Wu <cooloney@kernel.org>
  * Copyright (C) 2008 Analog Devices, Inc
  *
@@ -438,8 +438,8 @@
 {
 	if (audio_buf) {
 		kfree(audio_buf->buf);
-		kfree(audio_buf);
 		audio_buf->buf = NULL;
+		kfree(audio_buf);
 		audio_buf = NULL;
 	}
 }
diff --git a/drivers/usb/gadget/u_bam.c b/drivers/usb/gadget/u_bam.c
index 843c207..4bd7f39 100644
--- a/drivers/usb/gadget/u_bam.c
+++ b/drivers/usb/gadget/u_bam.c
@@ -54,28 +54,31 @@
 
 #define DL_INTR_THRESHOLD			20
 
-unsigned int bam_mux_tx_pkt_drop_thld = BAM_MUX_TX_PKT_DROP_THRESHOLD;
+static unsigned int bam_pending_limit = BAM_PENDING_LIMIT;
+module_param(bam_pending_limit, uint, S_IRUGO | S_IWUSR);
+
+static unsigned int bam_mux_tx_pkt_drop_thld = BAM_MUX_TX_PKT_DROP_THRESHOLD;
 module_param(bam_mux_tx_pkt_drop_thld, uint, S_IRUGO | S_IWUSR);
 
-unsigned int bam_mux_rx_fctrl_en_thld = BAM_MUX_RX_PKT_FCTRL_EN_TSHOLD;
+static unsigned int bam_mux_rx_fctrl_en_thld = BAM_MUX_RX_PKT_FCTRL_EN_TSHOLD;
 module_param(bam_mux_rx_fctrl_en_thld, uint, S_IRUGO | S_IWUSR);
 
-unsigned int bam_mux_rx_fctrl_support = BAM_MUX_RX_PKT_FLOW_CTRL_SUPPORT;
+static unsigned int bam_mux_rx_fctrl_support = BAM_MUX_RX_PKT_FLOW_CTRL_SUPPORT;
 module_param(bam_mux_rx_fctrl_support, uint, S_IRUGO | S_IWUSR);
 
-unsigned int bam_mux_rx_fctrl_dis_thld = BAM_MUX_RX_PKT_FCTRL_DIS_TSHOLD;
+static unsigned int bam_mux_rx_fctrl_dis_thld = BAM_MUX_RX_PKT_FCTRL_DIS_TSHOLD;
 module_param(bam_mux_rx_fctrl_dis_thld, uint, S_IRUGO | S_IWUSR);
 
-unsigned int bam_mux_tx_q_size = BAM_MUX_TX_Q_SIZE;
+static unsigned int bam_mux_tx_q_size = BAM_MUX_TX_Q_SIZE;
 module_param(bam_mux_tx_q_size, uint, S_IRUGO | S_IWUSR);
 
-unsigned int bam_mux_rx_q_size = BAM_MUX_RX_Q_SIZE;
+static unsigned int bam_mux_rx_q_size = BAM_MUX_RX_Q_SIZE;
 module_param(bam_mux_rx_q_size, uint, S_IRUGO | S_IWUSR);
 
-unsigned int bam_mux_rx_req_size = BAM_MUX_RX_REQ_SIZE;
+static unsigned int bam_mux_rx_req_size = BAM_MUX_RX_REQ_SIZE;
 module_param(bam_mux_rx_req_size, uint, S_IRUGO | S_IWUSR);
 
-unsigned int dl_intr_threshold = DL_INTR_THRESHOLD;
+static unsigned int dl_intr_threshold = DL_INTR_THRESHOLD;
 module_param(dl_intr_threshold, uint, S_IRUGO | S_IWUSR);
 
 #define BAM_CH_OPENED	BIT(0)
@@ -113,6 +116,10 @@
 	unsigned int		rx_len;
 	unsigned long		to_modem;
 	unsigned long		to_host;
+	unsigned int		rx_flow_control_disable;
+	unsigned int		rx_flow_control_enable;
+	unsigned int		rx_flow_control_triggered;
+	unsigned int		max_num_pkts_pending_with_bam;
 };
 
 struct gbam_port {
@@ -324,7 +331,7 @@
 		return;
 	}
 
-	while (d->pending_with_bam < BAM_PENDING_LIMIT) {
+	while (d->pending_with_bam < bam_pending_limit) {
 		skb =  __skb_dequeue(&d->rx_skb_q);
 		if (!skb)
 			break;
@@ -347,14 +354,21 @@
 			dev_kfree_skb_any(skb);
 			break;
 		}
+		if (d->pending_with_bam > d->max_num_pkts_pending_with_bam)
+			d->max_num_pkts_pending_with_bam = d->pending_with_bam;
 	}
 
 	qlen = d->rx_skb_q.qlen;
 
 	spin_unlock_irqrestore(&port->port_lock_ul, flags);
 
-	if (qlen < BAM_MUX_RX_PKT_FCTRL_DIS_TSHOLD)
+	if (qlen < bam_mux_rx_fctrl_dis_thld) {
+		if (d->rx_flow_control_triggered) {
+			d->rx_flow_control_disable++;
+			d->rx_flow_control_triggered = 0;
+		}
 		gbam_start_rx(port);
+	}
 }
 /*-------------------------------------------------------------*/
 
@@ -435,7 +449,10 @@
 	 */
 	if (bam_mux_rx_fctrl_support &&
 		d->rx_skb_q.qlen >= bam_mux_rx_fctrl_en_thld) {
-
+		if (!d->rx_flow_control_triggered) {
+			d->rx_flow_control_triggered = 1;
+			d->rx_flow_control_enable++;
+		}
 		list_add_tail(&req->list, &d->rx_idle);
 		spin_unlock(&port->port_lock_ul);
 		return;
@@ -1223,6 +1240,10 @@
 				"dpkts_pwith_bam: %u\n"
 				"to_usbhost_dcnt:  %u\n"
 				"tomodem__dcnt:  %u\n"
+				"rx_flow_control_disable_count: %u\n"
+				"rx_flow_control_enable_count: %u\n"
+				"rx_flow_control_triggered: %u\n"
+				"max_num_pkts_pending_with_bam: %u\n"
 				"tx_buf_len:	 %u\n"
 				"rx_buf_len:	 %u\n"
 				"data_ch_open:   %d\n"
@@ -1231,6 +1252,10 @@
 				d->to_host, d->to_modem,
 				d->pending_with_bam,
 				d->tohost_drp_cnt, d->tomodem_drp_cnt,
+				d->rx_flow_control_disable,
+				d->rx_flow_control_enable,
+				d->rx_flow_control_triggered,
+				d->max_num_pkts_pending_with_bam,
 				d->tx_skb_q.qlen, d->rx_skb_q.qlen,
 				test_bit(BAM_CH_OPENED, &d->flags),
 				test_bit(BAM_CH_READY, &d->flags));
@@ -1269,6 +1294,10 @@
 		d->pending_with_bam = 0;
 		d->tohost_drp_cnt = 0;
 		d->tomodem_drp_cnt = 0;
+		d->rx_flow_control_disable = 0;
+		d->rx_flow_control_enable = 0;
+		d->rx_flow_control_triggered = 0;
+		d->max_num_pkts_pending_with_bam = 0;
 
 		spin_unlock(&port->port_lock_dl);
 		spin_unlock_irqrestore(&port->port_lock_ul, flags);
@@ -1434,6 +1463,10 @@
 		d->pending_with_bam = 0;
 		d->tohost_drp_cnt = 0;
 		d->tomodem_drp_cnt = 0;
+		d->rx_flow_control_disable = 0;
+		d->rx_flow_control_enable = 0;
+		d->rx_flow_control_triggered = 0;
+		d->max_num_pkts_pending_with_bam = 0;
 	}
 
 	spin_unlock(&port->port_lock_dl);
diff --git a/drivers/usb/gadget/u_ether.c b/drivers/usb/gadget/u_ether.c
index 734619f..a2bc2d9 100644
--- a/drivers/usb/gadget/u_ether.c
+++ b/drivers/usb/gadget/u_ether.c
@@ -532,7 +532,7 @@
 	spin_lock(&dev->req_lock);
 	list_add_tail(&req->list, &dev->tx_reqs);
 
-	if (dev->port_usb->multi_pkt_xfer) {
+	if (dev->port_usb->multi_pkt_xfer && !req->context) {
 		dev->no_tx_req_used--;
 		req->length = 0;
 		in = dev->port_usb->in_ep;
@@ -598,6 +598,14 @@
 		}
 	} else {
 		skb = req->context;
+		/* Is aggregation already enabled and buffers allocated ? */
+		if (dev->port_usb->multi_pkt_xfer && dev->tx_req_bufsize) {
+			req->buf = kzalloc(dev->tx_req_bufsize, GFP_ATOMIC);
+			req->context = NULL;
+		} else {
+			req->buf = NULL;
+		}
+
 		spin_unlock(&dev->req_lock);
 		dev_kfree_skb_any(skb);
 	}
@@ -625,11 +633,14 @@
 
 	list_for_each(act, &dev->tx_reqs) {
 		req = container_of(act, struct usb_request, list);
-		if (!req->buf)
+		if (!req->buf) {
 			req->buf = kzalloc(dev->tx_req_bufsize,
 						GFP_ATOMIC);
 			if (!req->buf)
 				goto free_buf;
+		}
+		/* req->context is not used for multi_pkt_xfers */
+		req->context = NULL;
 	}
 	return 0;
 
@@ -673,11 +684,15 @@
 	}
 
 	/* Allocate memory for tx_reqs to support multi packet transfer */
+	spin_lock_irqsave(&dev->req_lock, flags);
 	if (multi_pkt_xfer && !dev->tx_req_bufsize) {
 		retval = alloc_tx_buffer(dev);
-		if (retval < 0)
+		if (retval < 0) {
+			spin_unlock_irqrestore(&dev->req_lock, flags);
 			return -ENOMEM;
+		}
 	}
+	spin_unlock_irqrestore(&dev->req_lock, flags);
 
 	/* apply outgoing CDC or RNDIS filters */
 	if (!is_promisc(cdc_filter)) {
diff --git a/drivers/usb/gadget/u_serial.c b/drivers/usb/gadget/u_serial.c
index 299f620c..95b6fbc7 100644
--- a/drivers/usb/gadget/u_serial.c
+++ b/drivers/usb/gadget/u_serial.c
@@ -689,18 +689,20 @@
 }
 
 static int gs_alloc_requests(struct usb_ep *ep, struct list_head *head,
-		int num, int size, void (*fn)(struct usb_ep *, struct usb_request *),
+		int queue_size, int req_size,
+		void (*fn)(struct usb_ep *, struct usb_request *),
 		int *allocated)
 {
 	int			i;
 	struct usb_request	*req;
+	int n = allocated ? queue_size - *allocated : queue_size;
 
 	/* Pre-allocate up to QUEUE_SIZE transfers, but if we can't
 	 * do quite that many this time, don't fail ... we just won't
 	 * be as speedy as we might otherwise be.
 	 */
-	for (i = 0; i < num; i++) {
-		req = gs_alloc_req(ep, size, GFP_ATOMIC);
+	for (i = 0; i < n; i++) {
+		req = gs_alloc_req(ep, req_size, GFP_ATOMIC);
 		if (!req)
 			return list_empty(head) ? -ENOMEM : 0;
 		req->complete = fn;
@@ -941,22 +943,6 @@
 			port->port_num, tty, file);
 
 	wake_up_interruptible(&port->close_wait);
-
-	/*
-	 * Freeing the previously queued requests as they are
-	 * allocated again as a part of gs_open()
-	 */
-	if (port->port_usb) {
-		spin_unlock_irq(&port->port_lock);
-		usb_ep_fifo_flush(gser->out);
-		usb_ep_fifo_flush(gser->in);
-		spin_lock_irq(&port->port_lock);
-		gs_free_requests(gser->out, &port->read_queue, NULL);
-		gs_free_requests(gser->out, &port->read_pool, NULL);
-		gs_free_requests(gser->in, &port->write_pool, NULL);
-	}
-	port->read_allocated = port->read_started =
-		port->write_allocated = port->write_started = 0;
 exit:
 	spin_unlock_irq(&port->port_lock);
 }
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index 4357867..2a24bec 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -693,3 +693,16 @@
 config USB_OCTEON2_COMMON
 	bool
 	default y if USB_OCTEON_EHCI || USB_OCTEON_OHCI
+
+config USB_ICE40_HCD
+	tristate "ICE40 FPGA based SPI to Inter-Chip USB host controller"
+	depends on USB && SPI
+	help
+	  A driver for ICE40 FPGA based SPI to Inter-Chip USB host
+	  controller. This driver registers as a SPI protocol driver
+	  and interacts with the SPI subsystem on one side and interacts
+	  with the USB core on the other side. Control and Bulk transfers
+	  are supported.
+
+	  To compile this driver a module, choose M here: the module
+	  will be called "ice40-hcd".
diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile
index 7d35f5b..7c5b452 100644
--- a/drivers/usb/host/Makefile
+++ b/drivers/usb/host/Makefile
@@ -42,3 +42,4 @@
 obj-$(CONFIG_USB_FSL_MPH_DR_OF)	+= fsl-mph-dr-of.o
 obj-$(CONFIG_USB_OCTEON2_COMMON) += octeon2-common.o
 obj-$(CONFIG_MIPS_ALCHEMY)	+= alchemy-common.o
+obj-$(CONFIG_USB_ICE40_HCD)	+= ice40-hcd.o
diff --git a/drivers/usb/host/ehci-msm-hsic.c b/drivers/usb/host/ehci-msm-hsic.c
index 5f20ad1..a89ac06 100644
--- a/drivers/usb/host/ehci-msm-hsic.c
+++ b/drivers/usb/host/ehci-msm-hsic.c
@@ -1,6 +1,6 @@
 /* ehci-msm-hsic.c - HSUSB Host Controller Driver Implementation
  *
- * Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011-2014, The Linux Foundation. All rights reserved.
  *
  * Partly derived from ehci-fsl.c and ehci-hcd.c
  * Copyright (c) 2000-2004 by David Brownell
@@ -1486,7 +1486,7 @@
 	 * generic hardware linkage
 	 */
 	.irq			= msm_hsic_irq,
-	.flags			= HCD_USB2 | HCD_MEMORY | HCD_OLD_ENUM,
+	.flags			= HCD_USB2 | HCD_MEMORY | HCD_RT_OLD_ENUM,
 
 	.reset			= ehci_hsic_reset,
 	.start			= ehci_run,
@@ -2263,6 +2263,9 @@
 	iounmap(hcd->regs);
 	usb_put_hcd(hcd);
 
+	if (pdev->dev.of_node)
+		pdev->dev.platform_data = NULL;
+
 	return 0;
 }
 
diff --git a/drivers/usb/host/ehci-msm2.c b/drivers/usb/host/ehci-msm2.c
index 7ae0a54..ebb226c 100644
--- a/drivers/usb/host/ehci-msm2.c
+++ b/drivers/usb/host/ehci-msm2.c
@@ -46,6 +46,10 @@
 
 #define PDEV_NAME_LEN 20
 
+static bool uicc_card_present;
+module_param(uicc_card_present, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(uicc_card_present, "UICC card inserted");
+
 struct msm_hcd {
 	struct ehci_hcd				ehci;
 	spinlock_t				wakeup_lock;
@@ -295,6 +299,11 @@
 static void msm_ehci_vbus_power(struct msm_hcd *mhcd, bool on)
 {
 	int ret;
+	const struct msm_usb_host_platform_data *pdata;
+
+	pdata = mhcd->dev->platform_data;
+	if (pdata && pdata->is_uicc)
+		return;
 
 	if (!mhcd->vbus) {
 		pr_err("vbus is NULL.");
@@ -352,6 +361,10 @@
 
 	pdata = mhcd->dev->platform_data;
 
+	/* For uicc card connection, external vbus is not required */
+	if (pdata && pdata->is_uicc)
+		return 0;
+
 	if (!init) {
 		if (pdata && pdata->dock_connect_irq)
 			free_irq(pdata->dock_connect_irq, mhcd);
@@ -680,6 +693,8 @@
 	unsigned long timeout;
 	int ret;
 	u32 portsc;
+	const struct msm_usb_host_platform_data *pdata;
+	u32 func_ctrl;
 
 	if (atomic_read(&mhcd->in_lpm)) {
 		dev_dbg(mhcd->dev, "%s called in lpm\n", __func__);
@@ -696,6 +711,14 @@
 		return -EBUSY;
 	}
 
+	pdata = mhcd->dev->platform_data;
+	if (pdata && pdata->is_uicc) {
+		/* put the controller in non-driving mode */
+		func_ctrl = msm_ulpi_read(mhcd, ULPI_FUNC_CTRL);
+		func_ctrl &= ~ULPI_FUNC_CTRL_OPMODE_MASK;
+		func_ctrl |= ULPI_FUNC_CTRL_OPMODE_NONDRIVING;
+		msm_ulpi_write(mhcd, func_ctrl, ULPI_FUNC_CTRL);
+	}
 	/* If port is enabled wait 5ms for PHCD to come up. Reset PHY
 	 * and link if it fails to do so.
 	 * If port is not enabled set the PHCD bit and poll for it to
@@ -800,6 +823,8 @@
 	unsigned temp;
 	int ret;
 	unsigned long flags;
+	u32 func_ctrl;
+	const struct msm_usb_host_platform_data *pdata;
 
 	if (!atomic_read(&mhcd->in_lpm)) {
 		dev_dbg(mhcd->dev, "%s called in !in_lpm\n", __func__);
@@ -869,6 +894,14 @@
 	}
 
 skip_phy_resume:
+	pdata = mhcd->dev->platform_data;
+	if (pdata && pdata->is_uicc) {
+		/* put the controller in normal mode */
+		func_ctrl = msm_ulpi_read(mhcd, ULPI_FUNC_CTRL);
+		func_ctrl &= ~ULPI_FUNC_CTRL_OPMODE_MASK;
+		func_ctrl |= ULPI_FUNC_CTRL_OPMODE_NORMAL;
+		msm_ulpi_write(mhcd, func_ctrl, ULPI_FUNC_CTRL);
+	}
 
 	usb_hcd_resume_root_hub(hcd);
 	atomic_set(&mhcd->in_lpm, 0);
@@ -1323,6 +1356,8 @@
 	pdata->resume_gpio = of_get_named_gpio(node, "qcom,resume-gpio", 0);
 	if (pdata->resume_gpio < 0)
 		pdata->resume_gpio = 0;
+	pdata->is_uicc = of_property_read_bool(node,
+					"qcom,usb2-enable-uicc");
 
 	return pdata;
 }
@@ -1339,6 +1374,14 @@
 
 	dev_dbg(&pdev->dev, "ehci_msm2 probe\n");
 
+	/*
+	 * Fail probe in case of uicc till userspace activates driver through
+	 * sysfs entry.
+	 */
+	if (!uicc_card_present && pdev->dev.of_node && of_property_read_bool(
+				pdev->dev.of_node, "qcom,usb2-enable-uicc"))
+		return -ENODEV;
+
 	if (pdev->dev.of_node) {
 		dev_dbg(&pdev->dev, "device tree enabled\n");
 		pdev->dev.platform_data = ehci_msm2_dt_to_pdata(pdev);
@@ -1612,6 +1655,10 @@
 	if (mhcd->resume_gpio)
 		gpio_free(mhcd->resume_gpio);
 
+	/* If the device was removed no need to call pm_runtime_disable */
+	if (pdev->dev.power.power_state.event != PM_EVENT_INVALID)
+		pm_runtime_disable(&pdev->dev);
+
 	device_init_wakeup(&pdev->dev, 0);
 	pm_runtime_set_suspended(&pdev->dev);
 
diff --git a/drivers/usb/host/ice40-hcd.c b/drivers/usb/host/ice40-hcd.c
new file mode 100644
index 0000000..7b0a789
--- /dev/null
+++ b/drivers/usb/host/ice40-hcd.c
@@ -0,0 +1,2140 @@
+/*
+ * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2001-2004 by David Brownell
+ *
+ * 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.
+ *
+ */
+
+/*
+ * Root HUB management and Asynchronous scheduling traversal
+ * Based on ehci-hub.c and ehci-q.c
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/ktime.h>
+#include <linux/uaccess.h>
+#include <linux/debugfs.h>
+#include <linux/pm_runtime.h>
+#include <linux/regulator/consumer.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+#include <linux/spinlock.h>
+#include <linux/firmware.h>
+#include <linux/spi/spi.h>
+#include <linux/usb.h>
+#include <linux/usb/hcd.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/ch11.h>
+
+#include <asm/unaligned.h>
+#include <mach/gpiomux.h>
+
+#define CREATE_TRACE_POINTS
+#include <trace/events/ice40.h>
+
+#define FADDR_REG 0x00 /* R/W: Device address */
+#define HCMD_REG 0x01 /* R/W: Host transfer command */
+#define XFRST_REG 0x02 /* R: Transfer status */
+#define IRQ_REG 0x03 /* R/C: IRQ status */
+#define IEN_REG 0x04 /* R/W: IRQ enable */
+#define CTRL0_REG 0x05 /* R/W: Host control command */
+#define CTRL1_REG 0x06 /* R/W: Host control command */
+#define WBUF0_REG 0x10 /* W: Tx fifo 0 */
+#define WBUF1_REG 0x11 /* W: Tx fifo 1 */
+#define SUBUF_REG 0x12 /* W: SETUP fifo */
+#define WBLEN_REG 0x13 /* W: Tx fifo size */
+#define RBUF0_REG 0x18 /* R: Rx fifo 0 */
+#define RBUF1_REG 0x19 /* R: Rx fifo 1 */
+#define RBLEN_REG 0x1B /* R: Rx fifo size */
+
+#define WRITE_CMD(addr) ((addr << 3) | 1)
+#define READ_CMD(addr) ((addr << 3) | 0)
+
+/* Host controller command register definitions */
+#define HCMD_EP(ep) (ep & 0xF)
+#define HCMD_BSEL(sel) (sel << 4)
+#define HCMD_TOGV(toggle) (toggle << 5)
+#define HCMD_PT(token) (token << 6)
+
+/* Transfer status register definitions */
+#define XFR_MASK(xfr) (xfr & 0xF)
+#define XFR_SUCCESS 0x0
+#define XFR_BUSY 0x1
+#define XFR_PKTERR 0x2
+#define XFR_PIDERR 0x3
+#define XFR_NAK 0x4
+#define XFR_STALL 0x5
+#define XFR_WRONGPID 0x6
+#define XFR_CRCERR 0x7
+#define XFR_TOGERR 0x8
+#define XFR_BADLEN 0x9
+#define XFR_TIMEOUT 0xA
+
+#define LINE_STATE(xfr) ((xfr & 0x30) >> 4) /* D+, D- */
+#define DPST	BIT(5)
+#define DMST	BIT(4)
+#define PLLOK	BIT(6)
+#define R64B	BIT(7)
+
+/* Interrupt enable/status register definitions */
+#define RESET_IRQ BIT(0)
+#define RESUME_IRQ BIT(1)
+#define SUSP_IRQ BIT(3)
+#define DISCONNECT_IRQ BIT(4)
+#define CONNECT_IRQ BIT(5)
+#define FRAME_IRQ BIT(6)
+#define XFR_IRQ BIT(7)
+
+/* Control 0 register definitions */
+#define RESET_CTRL BIT(0)
+#define FRAME_RESET_CTRL BIT(1)
+#define DET_BUS_CTRL BIT(2)
+#define RESUME_CTRL BIT(3)
+#define SOFEN_CTRL BIT(4)
+#define DM_PD_CTRL BIT(6)
+#define DP_PD_CTRL BIT(7)
+#define HRST_CTRL  BIT(5)
+
+/* Control 1 register definitions */
+#define INT_EN_CTRL BIT(0)
+
+enum ice40_xfr_type {
+	FIRMWARE_XFR,
+	REG_WRITE_XFR,
+	REG_READ_XFR,
+	SETUP_XFR,
+	DATA_IN_XFR,
+	DATA_OUT_XFR,
+};
+
+enum ice40_ep_phase {
+	SETUP_PHASE = 1,
+	DATA_PHASE,
+	STATUS_PHASE,
+};
+
+struct ice40_ep {
+	u8 xcat_err;
+	bool unlinking;
+	bool halted;
+	struct usb_host_endpoint *ep;
+	struct list_head ep_list;
+};
+
+struct ice40_hcd {
+	spinlock_t lock;
+
+	struct mutex wlock;
+	struct mutex rlock;
+
+	u8 devnum;
+	u32 port_flags;
+	u8 ctrl0;
+	u8 wblen0;
+
+	enum ice40_ep_phase ep0_state;
+	struct usb_hcd *hcd;
+
+	struct list_head async_list;
+	struct workqueue_struct *wq;
+	struct work_struct async_work;
+
+	int reset_gpio;
+	int slave_select_gpio;
+	int config_done_gpio;
+	int vcc_en_gpio;
+	int clk_en_gpio;
+
+	struct regulator *core_vcc;
+	struct regulator *spi_vcc;
+	struct regulator *gpio_vcc;
+	bool powered;
+
+	struct dentry *dbg_root;
+	bool pcd_pending;
+
+	/* SPI stuff later */
+	struct spi_device *spi;
+
+	struct spi_message *fmsg;
+	struct spi_transfer *fmsg_xfr; /* size 1 */
+
+	struct spi_message *wmsg;
+	struct spi_transfer *wmsg_xfr; /* size 1 */
+	u8 *w_tx_buf;
+	u8 *w_rx_buf;
+
+	struct spi_message *rmsg;
+	struct spi_transfer *rmsg_xfr; /* size 1 */
+	u8 *r_tx_buf;
+	u8 *r_rx_buf;
+
+	struct spi_message *setup_msg;
+	struct spi_transfer *setup_xfr; /* size 2 */
+	u8 *setup_buf; /* size 1 for SUBUF */
+
+	struct spi_message *in_msg;
+	struct spi_transfer *in_xfr; /* size 2 */
+	u8 *in_buf; /* size 2 for reading from RBUF0 */
+
+	struct spi_message *out_msg;
+	struct spi_transfer *out_xfr; /* size 2 */
+	u8 *out_buf; /* size 1 for writing WBUF0 */
+};
+
+static char fw_name[16] = "ice40.bin";
+module_param_string(fw, fw_name, sizeof(fw_name), S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(fw, "firmware blob file name");
+
+static bool debugger;
+module_param(debugger, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debugger, "true to use the debug port");
+
+static inline struct ice40_hcd *hcd_to_ihcd(struct usb_hcd *hcd)
+{
+	return *((struct ice40_hcd **) hcd->hcd_priv);
+}
+
+static void ice40_spi_reg_write(struct ice40_hcd *ihcd, u8 val, u8 addr)
+{
+	int ret;
+
+	/*
+	 * Register Write Pattern:
+	 * TX: 1st byte is CMD (register + write), 2nd byte is value
+	 * RX: Ignore
+	 *
+	 * The Mutex is to protect concurrent register writes as
+	 * we have only 1 SPI message struct.
+	 */
+
+	mutex_lock(&ihcd->wlock);
+
+	ihcd->w_tx_buf[0] = WRITE_CMD(addr);
+	ihcd->w_tx_buf[1] = val;
+	ret = spi_sync(ihcd->spi, ihcd->wmsg);
+	if (ret < 0) /* should not happen */
+		pr_err("failed. val = %d addr = %d\n", val, addr);
+
+	trace_ice40_reg_write(addr, val, ihcd->w_tx_buf[0],
+			ihcd->w_tx_buf[1], ret);
+
+	mutex_unlock(&ihcd->wlock);
+}
+
+static int ice40_spi_reg_read(struct ice40_hcd *ihcd, u8 addr)
+{
+	int ret;
+
+	/*
+	 * Register Read Pattern:
+	 * TX: 1st byte is CMD (register + read)
+	 * RX: 1st, 2nd byte Ignore, 3rd byte value.
+	 *
+	 * The Mutex is to protect concurrent register reads as
+	 * we have only 1 SPI message struct.
+	 */
+
+	mutex_lock(&ihcd->rlock);
+
+	ihcd->r_tx_buf[0] = READ_CMD(addr);
+	ret = spi_sync(ihcd->spi, ihcd->rmsg);
+	if (ret < 0)
+		pr_err("failed. addr = %d\n", addr);
+	else
+		ret = ihcd->r_rx_buf[2];
+
+	trace_ice40_reg_read(addr, ihcd->r_tx_buf[0], ret);
+
+	mutex_unlock(&ihcd->rlock);
+
+	return ret;
+}
+
+static int ice40_poll_xfer(struct ice40_hcd *ihcd, int usecs)
+{
+	ktime_t start = ktime_get();
+	u8 val, retry = 0;
+	u8 ret = ~0; /* time out */
+
+again:
+
+	/*
+	 * The SPI transaction may take tens of usec. Use ktime
+	 * based checks rather than loop count.
+	 */
+	do {
+		val = ice40_spi_reg_read(ihcd, XFRST_REG);
+
+		if (XFR_MASK(val) != XFR_BUSY)
+			return val;
+
+	} while (ktime_us_delta(ktime_get(), start) < usecs);
+
+	/*
+	 * The SPI transaction involves a context switch. For any
+	 * reason, if we are scheduled out more than usecs after
+	 * the 1st read, this extra read will help.
+	 */
+	if (!retry) {
+		retry = 1;
+		goto again;
+	}
+
+	return ret;
+}
+
+static int
+ice40_handshake(struct ice40_hcd *ihcd, u8 reg, u8 mask, u8 done, int usecs)
+{
+	ktime_t start = ktime_get();
+	u8 val, retry = 0;
+
+again:
+	do {
+		val = ice40_spi_reg_read(ihcd, reg);
+		val &= mask;
+
+		if (val == done)
+			return 0;
+
+	} while (ktime_us_delta(ktime_get(), start) < usecs);
+
+	if (!retry) {
+		retry = 1;
+		goto again;
+	}
+
+	return -ETIMEDOUT;
+}
+
+
+static const char hcd_name[] = "ice40-hcd";
+
+static int ice40_reset(struct usb_hcd *hcd)
+{
+	struct ice40_hcd *ihcd = hcd_to_ihcd(hcd);
+	u8 ctrl, status;
+	int ret = 0;
+
+	/*
+	 * Program the defualt address 0. The device address is
+	 * re-programmed after SET_ADDRESS in URB handling path.
+	 */
+	ihcd->devnum = 0;
+	ice40_spi_reg_write(ihcd, 0, FADDR_REG);
+
+	ihcd->wblen0 = ~0;
+	/*
+	 * Read the line state. This driver is loaded after the
+	 * UICC card insertion. So the line state should indicate
+	 * that a Full-speed device is connected. Return error
+	 * if there is no device connected.
+	 *
+	 * There can be no device connected during debug. A debugfs
+	 * file is provided to sample the bus line and update the
+	 * port flags accordingly.
+	 */
+
+	if (debugger)
+		goto out;
+
+	ctrl = ice40_spi_reg_read(ihcd, CTRL0_REG);
+	ice40_spi_reg_write(ihcd, ctrl | DET_BUS_CTRL, CTRL0_REG);
+
+	ret = ice40_handshake(ihcd, CTRL0_REG, DET_BUS_CTRL, 0, 5000);
+	if (ret) {
+		pr_err("bus detection failed\n");
+		goto out;
+	}
+
+	status = ice40_spi_reg_read(ihcd, XFRST_REG);
+	pr_debug("line state (D+, D-) is %d\n", LINE_STATE(status));
+
+	if (status & DPST) {
+		pr_debug("Full speed device connected\n");
+		ihcd->port_flags |= USB_PORT_STAT_CONNECTION;
+	} else {
+		pr_err("No device connected\n");
+		ret = -ENODEV;
+	}
+out:
+	return ret;
+}
+
+static int ice40_run(struct usb_hcd *hcd)
+{
+	struct ice40_hcd *ihcd = hcd_to_ihcd(hcd);
+
+	/*
+	 * HCD_FLAG_POLL_RH flag is not set by us. Core will not poll
+	 * for the port status periodically. This uses_new_polling
+	 * flag tells core that this hcd will call usb_hcd_poll_rh_status
+	 * upon port change.
+	 */
+	hcd->uses_new_polling = 1;
+
+	/*
+	 * Cache the ctrl0 register to avoid multiple reads. This register
+	 * is written during reset and resume.
+	 */
+	ihcd->ctrl0 = ice40_spi_reg_read(ihcd, CTRL0_REG);
+	ihcd->ctrl0 |= SOFEN_CTRL;
+	ice40_spi_reg_write(ihcd, ihcd->ctrl0, CTRL0_REG);
+
+	return 0;
+}
+
+static void ice40_stop(struct usb_hcd *hcd)
+{
+	struct ice40_hcd *ihcd = hcd_to_ihcd(hcd);
+
+	cancel_work_sync(&ihcd->async_work);
+}
+
+/*
+ * The _Error looks odd. But very helpful when looking for
+ * any errors in logs.
+ */
+static char __maybe_unused *xfr_status_string(int status)
+{
+	switch (XFR_MASK(status)) {
+	case XFR_SUCCESS:
+		return "Ack";
+	case XFR_BUSY:
+		return "Busy_Error";
+	case XFR_PKTERR:
+		return "Pkt_Error";
+	case XFR_PIDERR:
+		return "PID_Error";
+	case XFR_NAK:
+		return "Nak";
+	case XFR_STALL:
+		return "Stall_Error";
+	case XFR_WRONGPID:
+		return "WrongPID_Error";
+	case XFR_CRCERR:
+		return "CRC_Error";
+	case XFR_TOGERR:
+		return "Togg_Error";
+	case XFR_BADLEN:
+		return "BadLen_Error";
+	case XFR_TIMEOUT:
+		return "Timeout_Error";
+	default:
+		return "Unknown_Error";
+	}
+}
+
+static int ice40_xfer_setup(struct ice40_hcd *ihcd, struct urb *urb)
+{
+	struct usb_host_endpoint *ep = urb->ep;
+	struct ice40_ep *iep = ep->hcpriv;
+	void *buf = urb->setup_packet;
+	int ret, status;
+	u8 cmd;
+
+	/*
+	 * SETUP transaction Handling:
+	 * - copy the setup buffer to SUBUF fifo
+	 * - Program HCMD register to initiate the SETP transaction.
+	 * - poll for completion by reading XFRST register.
+	 * - Interpret the result.
+	 */
+
+	ihcd->setup_buf[0] = WRITE_CMD(SUBUF_REG);
+	ihcd->setup_xfr[1].tx_buf = buf;
+	ihcd->setup_xfr[1].len = sizeof(struct usb_ctrlrequest);
+
+	ret = spi_sync(ihcd->spi, ihcd->setup_msg);
+	if (ret < 0) {
+		pr_err("SPI transfer failed\n");
+		status = ret = -EIO;
+		goto out;
+	}
+
+	cmd = HCMD_PT(2) | HCMD_TOGV(0) | HCMD_BSEL(0) | HCMD_EP(0);
+	ice40_spi_reg_write(ihcd, cmd, HCMD_REG);
+
+	status = ice40_poll_xfer(ihcd, 1000);
+	switch (XFR_MASK(status)) {
+	case XFR_SUCCESS:
+		iep->xcat_err = 0;
+		ret = 0;
+		break;
+	case XFR_NAK: /* Device should not return Nak for SETUP */
+	case XFR_STALL:
+		iep->xcat_err = 0;
+		ret = -EPIPE;
+		break;
+	case XFR_PKTERR:
+	case XFR_PIDERR:
+	case XFR_WRONGPID:
+	case XFR_CRCERR:
+	case XFR_TIMEOUT:
+		if (++iep->xcat_err < 8)
+			ret = -EINPROGRESS;
+		else
+			ret = -EPROTO;
+		break;
+	default:
+		pr_err("transaction timed out\n");
+		ret = -EIO;
+	}
+
+out:
+	trace_ice40_setup(xfr_status_string(status), ret);
+	return ret;
+}
+
+static int ice40_xfer_in(struct ice40_hcd *ihcd, struct urb *urb)
+{
+	struct usb_host_endpoint *ep = urb->ep;
+	struct usb_device *udev = urb->dev;
+	u32 total_len = urb->transfer_buffer_length;
+	u16 maxpacket = usb_endpoint_maxp(&ep->desc);
+	u8 epnum = usb_pipeendpoint(urb->pipe);
+	bool is_out = usb_pipeout(urb->pipe);
+	struct ice40_ep *iep = ep->hcpriv;
+	u8 cmd, status, len = 0, t, expected_len;
+	void *buf;
+	int ret;
+	bool short_packet = true;
+
+	if (epnum == 0 && ihcd->ep0_state == STATUS_PHASE) {
+		expected_len = 0;
+		buf = NULL;
+		t = 1; /* STATUS PHASE is always DATA1 */
+	} else {
+		expected_len = min_t(u32, maxpacket,
+				total_len - urb->actual_length);
+		buf = urb->transfer_buffer + urb->actual_length;
+		t = usb_gettoggle(udev, epnum, is_out);
+	}
+
+	/*
+	 * IN transaction Handling:
+	 * - Program HCMD register to initiate the IN transaction.
+	 * - poll for completion by reading XFRST register.
+	 * - Interpret the result.
+	 * - If ACK is received and we expect some data, read RBLEN
+	 * - Read the data from RBUF
+	 */
+
+	cmd = HCMD_PT(0) | HCMD_TOGV(t) | HCMD_BSEL(0) | HCMD_EP(epnum);
+	ice40_spi_reg_write(ihcd, cmd, HCMD_REG);
+
+	status = ice40_poll_xfer(ihcd, 1000);
+	switch (XFR_MASK(status)) {
+	case XFR_SUCCESS:
+		usb_dotoggle(udev, epnum, is_out);
+		iep->xcat_err = 0;
+		ret = 0;
+		if ((expected_len == 64) && (status & R64B))
+			short_packet = false;
+		break;
+	case XFR_NAK:
+		iep->xcat_err = 0;
+		ret = -EINPROGRESS;
+		break;
+	case XFR_TOGERR:
+		/*
+		 * Peripheral had missed the previous Ack and sent
+		 * the same packet again. Ack is sent by the hardware.
+		 * As the data is received already, ignore this
+		 * event.
+		 */
+		ret = -EINPROGRESS;
+		break;
+	case XFR_PKTERR:
+	case XFR_PIDERR:
+	case XFR_WRONGPID:
+	case XFR_CRCERR:
+	case XFR_TIMEOUT:
+		if (++iep->xcat_err < 8)
+			ret = -EINPROGRESS;
+		else
+			ret = -EPROTO;
+		break;
+	case XFR_STALL:
+		ret = -EPIPE;
+		break;
+	case XFR_BADLEN:
+		ret = -EOVERFLOW;
+		break;
+	default:
+		pr_err("transaction timed out\n");
+		ret = -EIO;
+	}
+
+	/*
+	 * Proceed further only if Ack is received and
+	 * we are expecting some data.
+	 */
+	if (ret || !expected_len)
+		goto out;
+
+	if (short_packet)
+		len = ice40_spi_reg_read(ihcd, RBLEN_REG);
+	else
+		len = 64;
+
+	/* babble condition */
+	if (len > expected_len) {
+		pr_err("overflow condition\n");
+		ret = -EOVERFLOW;
+		goto out;
+	}
+
+	/*
+	 * zero len packet received. nothing to read from
+	 * FIFO.
+	 */
+	if (len == 0) {
+		ret = 0;
+		goto out;
+	}
+
+	ihcd->in_buf[0] = READ_CMD(RBUF0_REG);
+
+	ihcd->in_xfr[1].rx_buf = buf;
+	ihcd->in_xfr[1].len = len;
+
+	ret = spi_sync(ihcd->spi, ihcd->in_msg);
+	if (ret < 0) {
+		pr_err("SPI transfer failed\n");
+		ret = -EIO;
+		goto out;
+	}
+
+	urb->actual_length += len;
+	if ((urb->actual_length == total_len) ||
+			(len < expected_len))
+		ret = 0; /* URB completed */
+	else
+		ret = -EINPROGRESS; /* still pending */
+out:
+	trace_ice40_in(epnum, xfr_status_string(status), len,
+			expected_len, ret);
+	return ret;
+}
+
+static int ice40_xfer_out(struct ice40_hcd *ihcd, struct urb *urb)
+{
+	struct usb_host_endpoint *ep = urb->ep;
+	struct usb_device *udev = urb->dev;
+	u32 total_len = urb->transfer_buffer_length;
+	u16 maxpacket = usb_endpoint_maxp(&ep->desc);
+	u8 epnum = usb_pipeendpoint(urb->pipe);
+	bool is_out = usb_pipeout(urb->pipe);
+	struct ice40_ep *iep = ep->hcpriv;
+	u8 cmd, status, len, t;
+	void *buf;
+	int ret;
+
+	if (epnum == 0 && ihcd->ep0_state == STATUS_PHASE) {
+		len = 0;
+		buf = NULL;
+		t = 1; /* STATUS PHASE is always DATA1 */
+	} else {
+		len = min_t(u32, maxpacket, total_len - urb->actual_length);
+		buf = urb->transfer_buffer + urb->actual_length;
+		t = usb_gettoggle(udev, epnum, is_out);
+	}
+
+	/*
+	 * OUT transaction Handling:
+	 * - If we need to send data, write the data to WBUF Fifo
+	 * - Program the WBLEN register
+	 * - Program HCMD register to initiate the OUT transaction.
+	 * - poll for completion by reading XFRST register.
+	 * - Interpret the result.
+	 */
+
+
+	if (!len)
+		goto no_data;
+
+	ihcd->out_buf[0] = WRITE_CMD(WBUF0_REG);
+
+	ihcd->out_xfr[1].tx_buf = buf;
+	ihcd->out_xfr[1].len = len;
+
+	ret = spi_sync(ihcd->spi, ihcd->out_msg);
+	if (ret < 0) {
+		pr_err("SPI transaction failed\n");
+		status = ret = -EIO;
+		goto out;
+	}
+
+no_data:
+	/*
+	 * Cache the WBLEN register and update it only if it
+	 * is changed from the previous value.
+	 */
+	if (len != ihcd->wblen0) {
+		ice40_spi_reg_write(ihcd, len, WBLEN_REG);
+		ihcd->wblen0 = len;
+	}
+
+	cmd = HCMD_PT(1) | HCMD_TOGV(t) | HCMD_BSEL(0) | HCMD_EP(epnum);
+	ice40_spi_reg_write(ihcd, cmd, HCMD_REG);
+
+	status = ice40_poll_xfer(ihcd, 1000);
+	switch (XFR_MASK(status)) {
+	case XFR_SUCCESS:
+		usb_dotoggle(udev, epnum, is_out);
+		urb->actual_length += len;
+		iep->xcat_err = 0;
+		if (!len || (urb->actual_length == total_len))
+			ret = 0; /* URB completed */
+		else
+			ret = -EINPROGRESS; /* pending */
+		break;
+	case XFR_NAK:
+		iep->xcat_err = 0;
+		ret = -EINPROGRESS;
+		break;
+	case XFR_PKTERR:
+	case XFR_PIDERR:
+	case XFR_WRONGPID:
+	case XFR_CRCERR:
+	case XFR_TIMEOUT:
+		if (++iep->xcat_err < 8)
+			ret = -EINPROGRESS;
+		else
+			ret = -EPROTO;
+		break;
+	case XFR_STALL:
+		ret = -EPIPE;
+		break;
+	case XFR_BADLEN:
+		ret = -EOVERFLOW;
+		break;
+	default:
+		pr_err("transaction timed out\n");
+		ret = -EIO;
+	}
+
+out:
+	trace_ice40_out(epnum, xfr_status_string(status), len, ret);
+	return ret;
+}
+
+static int ice40_process_urb(struct ice40_hcd *ihcd, struct urb *urb)
+{
+	struct usb_device *udev = urb->dev;
+	u8 devnum = usb_pipedevice(urb->pipe);
+	bool is_out = usb_pipeout(urb->pipe);
+	u32 total_len = urb->transfer_buffer_length;
+	int ret = 0;
+
+	/*
+	 * The USB device address can be reset to 0 by core temporarily
+	 * during reset recovery process. Don't assume anything about
+	 * device address. The device address is programmed as 0 by
+	 * default. If the device address is different to the previous
+	 * cached value, re-program it here before proceeding. The device
+	 * address register (FADDR) holds the value across multiple
+	 * transactions and we support only one device.
+	 */
+	if (ihcd->devnum != devnum) {
+		ice40_spi_reg_write(ihcd, devnum, FADDR_REG);
+		ihcd->devnum = devnum;
+	}
+
+	switch (usb_pipetype(urb->pipe)) {
+	case PIPE_CONTROL:
+		switch (ihcd->ep0_state) {
+		case SETUP_PHASE:
+			trace_ice40_ep0("SETUP");
+			ret = ice40_xfer_setup(ihcd, urb);
+			if (ret)
+				break;
+			if (total_len) {
+				ihcd->ep0_state = DATA_PHASE;
+				/*
+				 * Data stage always begin with
+				 * DATA1 PID.
+				 */
+				usb_settoggle(udev, 0, is_out, 1);
+			} else {
+				ihcd->ep0_state = STATUS_PHASE;
+				goto do_status;
+			}
+			/* fall through */
+		case DATA_PHASE:
+			trace_ice40_ep0("DATA");
+			if (is_out)
+				ret = ice40_xfer_out(ihcd, urb);
+			else
+				ret = ice40_xfer_in(ihcd, urb);
+			if (ret)
+				break;
+			/* DATA Phase is completed successfully */
+			ihcd->ep0_state = STATUS_PHASE;
+			/* fall through */
+		case STATUS_PHASE:
+do_status:
+			trace_ice40_ep0("STATUS");
+			/* zero len DATA transfers have IN status */
+			if (!total_len || is_out)
+				ret = ice40_xfer_in(ihcd, urb);
+			else
+				ret = ice40_xfer_out(ihcd, urb);
+			if (ret)
+				break;
+			ihcd->ep0_state = SETUP_PHASE;
+			break;
+		default:
+			pr_err("unknown stage for a control transfer\n");
+			break;
+		}
+		break;
+	case PIPE_BULK:
+		if (is_out)
+			ret = ice40_xfer_out(ihcd, urb);
+		else
+			ret = ice40_xfer_in(ihcd, urb);
+		/*
+		 * We may have to support zero len packet terminations
+		 * for URB_ZERO_PACKET URBs.
+		 */
+		break;
+	default:
+		pr_err("IN/ISO transfers not supported\n");
+		break;
+	}
+
+	return ret;
+}
+
+/* Must be called with spin lock and interrupts disabled */
+static void ice40_complete_urb(struct usb_hcd *hcd, struct urb *urb, int status)
+{
+	struct ice40_hcd *ihcd = hcd_to_ihcd(hcd);
+	struct usb_host_endpoint *ep = urb->ep;
+	struct ice40_ep *iep = ep->hcpriv;
+	struct urb *first_urb;
+	bool needs_update = false;
+	bool control = usb_pipecontrol(urb->pipe);
+
+	/*
+	 * If the active URB i.e the first URB in the ep list is being
+	 * removed, clear the transaction error count. If it is a control
+	 * URB ep0_state needs to be reset to SETUP_PHASE.
+	 */
+	first_urb = list_first_entry(&ep->urb_list, struct urb, urb_list);
+	if (urb == first_urb)
+		needs_update = true;
+
+	usb_hcd_unlink_urb_from_ep(hcd, urb);
+	spin_unlock(&ihcd->lock);
+	trace_ice40_urb_done(urb, status);
+	usb_hcd_giveback_urb(ihcd->hcd, urb, status);
+	spin_lock(&ihcd->lock);
+
+	if (needs_update) {
+		iep->xcat_err = 0;
+		if (control)
+			ihcd->ep0_state = SETUP_PHASE;
+	}
+}
+
+static void ice40_async_work(struct work_struct *work)
+{
+	struct ice40_hcd *ihcd = container_of(work,
+			struct ice40_hcd, async_work);
+	struct usb_hcd *hcd = ihcd->hcd;
+	struct list_head *tmp, *uent, *utmp;
+	struct ice40_ep *iep;
+	struct usb_host_endpoint *ep;
+	struct urb *urb;
+	unsigned long flags;
+	int status;
+
+	/*
+	 * Traverse the active endpoints circularly and process URBs.
+	 * If any endpoint is marked for unlinking, the URBs are
+	 * completed here. The endpoint is removed from active list
+	 * if a URB is retired with -EPIPE/-EPROTO errors.
+	 */
+
+	spin_lock_irqsave(&ihcd->lock, flags);
+
+	if (list_empty(&ihcd->async_list))
+		goto out;
+
+	iep = list_first_entry(&ihcd->async_list, struct ice40_ep, ep_list);
+	while (1) {
+		ep = iep->ep;
+
+		urb = list_first_entry(&ep->urb_list, struct urb, urb_list);
+		if (urb->unlinked) {
+			status = urb->unlinked;
+		} else {
+			spin_unlock_irqrestore(&ihcd->lock, flags);
+			status = ice40_process_urb(ihcd, urb);
+			spin_lock_irqsave(&ihcd->lock, flags);
+		}
+
+		if ((status == -EPIPE) || (status == -EPROTO))
+			iep->halted = true;
+
+		if (status != -EINPROGRESS)
+			ice40_complete_urb(hcd, urb, status);
+
+		if (iep->unlinking) {
+			list_for_each_safe(uent, utmp, &ep->urb_list) {
+				urb = list_entry(uent, struct urb, urb_list);
+				if (urb->unlinked)
+					ice40_complete_urb(hcd, urb, 0);
+			}
+			iep->unlinking = false;
+		}
+
+		tmp = iep->ep_list.next;
+		if (list_empty(&ep->urb_list) || iep->halted) {
+			list_del_init(&iep->ep_list);
+
+			if (list_empty(&ihcd->async_list))
+				break;
+		}
+
+		if (tmp == &ihcd->async_list)
+			tmp = tmp->next;
+		iep = list_entry(tmp, struct ice40_ep, ep_list);
+	}
+out:
+	spin_unlock_irqrestore(&ihcd->lock, flags);
+}
+
+static int
+ice40_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags)
+{
+	struct ice40_hcd *ihcd = hcd_to_ihcd(hcd);
+	struct usb_device *udev = urb->dev;
+	struct usb_host_endpoint *ep = urb->ep;
+	bool is_out = usb_pipeout(urb->pipe);
+	u8 epnum = usb_pipeendpoint(urb->pipe);
+	struct ice40_ep *iep;
+	unsigned long flags;
+	int ret;
+
+	/*
+	 * This bridge chip supports only Full-speed. So ISO is not
+	 * supported. Interrupt support is not implemented as there
+	 * is no use case.
+	 */
+	if (usb_pipeisoc(urb->pipe) || usb_pipeint(urb->pipe)) {
+		pr_debug("iso and int xfers not supported\n");
+		ret = -ENOTSUPP;
+		goto out;
+	}
+
+	spin_lock_irqsave(&ihcd->lock, flags);
+
+	ret = usb_hcd_link_urb_to_ep(hcd, urb);
+	if (ret)
+		goto rel_lock;
+
+	trace_ice40_urb_enqueue(urb);
+
+	iep = ep->hcpriv;
+	if (!iep) {
+		iep = kzalloc(sizeof(struct ice40_ep), GFP_ATOMIC);
+		if (!iep) {
+			pr_debug("fail to allocate iep\n");
+			ret = -ENOMEM;
+			goto unlink;
+		}
+		ep->hcpriv = iep;
+		INIT_LIST_HEAD(&iep->ep_list);
+		iep->ep = ep;
+		usb_settoggle(udev, epnum, is_out, 0);
+		if (usb_pipecontrol(urb->pipe))
+			ihcd->ep0_state = SETUP_PHASE;
+	}
+
+	/*
+	 * We expect the interface driver to clear the stall condition
+	 * before queueing another URB. For example mass storage
+	 * device may STALL a bulk endpoint for un-supported command.
+	 * The storage driver clear the STALL condition before queueing
+	 * another URB.
+	 */
+	iep->halted = false;
+	if (list_empty(&iep->ep_list))
+		list_add_tail(&iep->ep_list, &ihcd->async_list);
+
+	queue_work(ihcd->wq, &ihcd->async_work);
+
+	spin_unlock_irqrestore(&ihcd->lock, flags);
+
+	return 0;
+unlink:
+	usb_hcd_unlink_urb_from_ep(hcd, urb);
+rel_lock:
+	spin_unlock_irqrestore(&ihcd->lock, flags);
+out:
+	return ret;
+}
+
+static int
+ice40_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
+{
+	struct ice40_hcd *ihcd = hcd_to_ihcd(hcd);
+	struct usb_host_endpoint *ep = urb->ep;
+	struct ice40_ep *iep;
+	unsigned long flags;
+	int ret;
+
+	spin_lock_irqsave(&ihcd->lock, flags);
+
+	ret = usb_hcd_check_unlink_urb(hcd, urb, status);
+	if (ret)
+		goto rel_lock;
+
+	trace_ice40_urb_dequeue(urb);
+	iep = ep->hcpriv;
+
+	/*
+	 * If the endpoint is not in asynchronous schedule, complete
+	 * the URB immediately. Otherwise mark it as being unlinked.
+	 * The asynchronous schedule work will take care of completing
+	 * the URB when this endpoint is encountered during traversal.
+	 */
+	if (list_empty(&iep->ep_list))
+		ice40_complete_urb(hcd, urb, status);
+	else
+		iep->unlinking = true;
+
+rel_lock:
+	spin_unlock_irqrestore(&ihcd->lock, flags);
+	return ret;
+}
+
+static void
+ice40_endpoint_disable(struct usb_hcd *hcd, struct usb_host_endpoint *ep)
+{
+	struct ice40_ep	*iep = ep->hcpriv;
+
+	/*
+	 * If there is no I/O on this endpoint before, ep->hcpriv
+	 * will be NULL. nothing to do in this case.
+	 */
+	if (!iep)
+		return;
+
+	if (!list_empty(&ep->urb_list))
+		pr_err("trying to disable an non-empty endpoint\n");
+
+	kfree(iep);
+	ep->hcpriv = NULL;
+}
+
+
+static int ice40_hub_status_data(struct usb_hcd *hcd, char *buf)
+{
+	struct ice40_hcd *ihcd = hcd_to_ihcd(hcd);
+	int ret = 0;
+
+	/*
+	 * core calls hub_status_method during suspend/resume.
+	 * return 0 if there is no port change. pcd_pending
+	 * is set to true when a device is connected and line
+	 * state is sampled via debugfs command. clear this
+	 * flag after returning the port change status.
+	 */
+	if (ihcd->pcd_pending) {
+		*buf = (1 << 1);
+		ret = 1;
+		ihcd->pcd_pending = false;
+	}
+
+	return ret;
+}
+
+static void ice40_hub_descriptor(struct usb_hub_descriptor *desc)
+{
+	/* There is nothing special about us!! */
+	desc->bDescLength = 9;
+	desc->bDescriptorType = 0x29;
+	desc->bNbrPorts = 1;
+	desc->wHubCharacteristics = cpu_to_le16(HUB_CHAR_NO_LPSM |
+				HUB_CHAR_NO_OCPM);
+	desc->bPwrOn2PwrGood = 0;
+	desc->bHubContrCurrent = 0;
+	desc->u.hs.DeviceRemovable[0] = 0;
+	desc->u.hs.DeviceRemovable[1] = ~0;
+}
+
+static int
+ice40_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
+			u16 wIndex, char *buf, u16 wLength)
+{
+	int ret = 0;
+	u8 ctrl;
+	struct ice40_hcd *ihcd = hcd_to_ihcd(hcd);
+
+	/*
+	 * We have only 1 port. No special locking is required while
+	 * handling root hub commands. The bridge chip does not maintain
+	 * any port states. Maintain different port states in software.
+	 */
+	switch (typeReq) {
+	case ClearPortFeature:
+		if (wIndex != 1 || wLength != 0)
+			goto error;
+		switch (wValue) {
+		case USB_PORT_FEAT_SUSPEND:
+			/*
+			 * The device is resumed as part of the root hub
+			 * resume to simplify the resume sequence. so
+			 * we may simply return from here. If device is
+			 * resumed before root hub is suspended, this
+			 * flags will be cleared here.
+			 */
+			if (!(ihcd->port_flags & USB_PORT_STAT_SUSPEND))
+				break;
+			ihcd->port_flags &= ~USB_PORT_STAT_SUSPEND;
+			break;
+		case USB_PORT_FEAT_ENABLE:
+			ihcd->port_flags &= ~USB_PORT_STAT_ENABLE;
+			break;
+		case USB_PORT_FEAT_POWER:
+			ihcd->port_flags &= ~USB_PORT_STAT_POWER;
+			break;
+		case USB_PORT_FEAT_C_CONNECTION:
+			ihcd->port_flags &= ~(USB_PORT_STAT_C_CONNECTION << 16);
+			break;
+		case USB_PORT_FEAT_C_ENABLE:
+		case USB_PORT_FEAT_C_SUSPEND:
+		case USB_PORT_FEAT_C_OVER_CURRENT:
+		case USB_PORT_FEAT_C_RESET:
+			/* nothing special here */
+			break;
+		default:
+			goto error;
+		}
+		break;
+	case GetHubDescriptor:
+		ice40_hub_descriptor((struct usb_hub_descriptor *) buf);
+		break;
+	case GetHubStatus:
+		put_unaligned_le32(0, buf);
+		break;
+	case GetPortStatus:
+		if (wIndex != 1)
+			goto error;
+
+		/*
+		 * Core resets the device and requests port status to
+		 * stop the reset signaling. If there is a reset in
+		 * progress, finish it here.
+		 */
+		ctrl = ice40_spi_reg_read(ihcd, CTRL0_REG);
+		if (!(ctrl & RESET_CTRL))
+			ihcd->port_flags &= ~USB_PORT_STAT_RESET;
+
+		put_unaligned_le32(ihcd->port_flags, buf);
+		break;
+	case SetPortFeature:
+		if (wIndex != 1 || wLength != 0)
+			goto error;
+		switch (wValue) {
+		case USB_PORT_FEAT_SUSPEND:
+			if (ihcd->port_flags & USB_PORT_STAT_RESET)
+				goto error;
+			if (!(ihcd->port_flags & USB_PORT_STAT_ENABLE))
+				goto error;
+			/* SOFs will be stopped during root hub suspend */
+			ihcd->port_flags |= USB_PORT_STAT_SUSPEND;
+			break;
+		case USB_PORT_FEAT_POWER:
+			ihcd->port_flags |= USB_PORT_STAT_POWER;
+			break;
+		case USB_PORT_FEAT_RESET:
+			/* Good time to enable the port */
+			ice40_spi_reg_write(ihcd, ihcd->ctrl0 |
+					RESET_CTRL, CTRL0_REG);
+			ihcd->port_flags |= USB_PORT_STAT_RESET;
+			ihcd->port_flags |= USB_PORT_STAT_ENABLE;
+			break;
+		default:
+			goto error;
+		}
+		break;
+	default:
+error:
+		/* "protocol stall" on error */
+		ret = -EPIPE;
+	}
+
+	trace_ice40_hub_control(typeReq, wValue, wIndex, wLength, ret);
+	return ret;
+}
+
+static void ice40_spi_power_off(struct ice40_hcd *ihcd);
+static int ice40_bus_suspend(struct usb_hcd *hcd)
+{
+	struct ice40_hcd *ihcd = hcd_to_ihcd(hcd);
+
+	trace_ice40_bus_suspend(0); /* start */
+
+	/* This happens only during debugging */
+	if (!ihcd->devnum) {
+		pr_debug("device still not connected. abort suspend\n");
+		trace_ice40_bus_suspend(2); /* failure */
+		return -EAGAIN;
+	}
+	/*
+	 * Stop sending the SOFs on downstream port. The device
+	 * finds the bus idle and enter suspend. The device
+	 * takes ~3 msec to enter suspend.
+	 */
+	ihcd->ctrl0 &= ~SOFEN_CTRL;
+	ice40_spi_reg_write(ihcd, ihcd->ctrl0, CTRL0_REG);
+	usleep_range(4500, 5000);
+
+	/*
+	 * Power collapse the bridge chip to avoid the leakage
+	 * current.
+	 */
+	ice40_spi_power_off(ihcd);
+
+	trace_ice40_bus_suspend(1); /* successful */
+	pm_relax(&ihcd->spi->dev);
+	return 0;
+}
+
+static int ice40_spi_load_fw(struct ice40_hcd *ihcd);
+static int ice40_bus_resume(struct usb_hcd *hcd)
+{
+	struct ice40_hcd *ihcd = hcd_to_ihcd(hcd);
+	u8 ctrl0;
+	int ret, i;
+
+	pm_stay_awake(&ihcd->spi->dev);
+	trace_ice40_bus_resume(0); /* start */
+	/*
+	 * Power up the bridge chip and load the configuration file.
+	 * Re-program the previous settings. For now we need to
+	 * update the device address only.
+	 */
+
+	for (i = 0; i < 3; i++) {
+		ret = ice40_spi_load_fw(ihcd);
+		if (!ret)
+			break;
+	}
+
+	if (ret) {
+		pr_err("Load firmware failed with ret: %d\n", ret);
+		return ret;
+	}
+
+	ice40_spi_reg_write(ihcd, ihcd->devnum, FADDR_REG);
+	ihcd->wblen0 = ~0;
+
+	/*
+	 * Program the bridge chip to drive resume signaling. The SOFs
+	 * are automatically transmitted after resume completion. It
+	 * will take ~20 msec for resume completion.
+	 */
+	ice40_spi_reg_write(ihcd, ihcd->ctrl0 | RESUME_CTRL, CTRL0_REG);
+	usleep_range(20000, 21000);
+	ret = ice40_handshake(ihcd, CTRL0_REG, RESUME_CTRL, 0, 5000);
+	if (ret) {
+		pr_err("resume failed\n");
+		trace_ice40_bus_resume(2); /* failure */
+		return -ENODEV;
+	}
+
+	ctrl0 = ice40_spi_reg_read(ihcd, CTRL0_REG);
+	if (!(ctrl0 & SOFEN_CTRL)) {
+		pr_err("SOFs are not transmitted after resume\n");
+		trace_ice40_bus_resume(3); /* failure */
+		return -ENODEV;
+	}
+
+	ihcd->port_flags &= ~USB_PORT_STAT_SUSPEND;
+	ihcd->ctrl0 |= SOFEN_CTRL;
+
+	trace_ice40_bus_resume(1); /* success */
+	return 0;
+}
+
+static void ice40_set_autosuspend_delay(struct usb_device *dev)
+{
+	/*
+	 * Immediate suspend for root hub and 500 msec auto-suspend
+	 * timeout for the card.
+	 */
+	if (!dev->parent)
+		pm_runtime_set_autosuspend_delay(&dev->dev, 0);
+	else
+		pm_runtime_set_autosuspend_delay(&dev->dev, 500);
+}
+
+static const struct hc_driver ice40_hc_driver = {
+	.description = hcd_name,
+	.product_desc = "ICE40 SPI Host Controller",
+	.hcd_priv_size = sizeof(struct ice40_hcd *),
+	.flags = HCD_USB11,
+
+	/* setup and clean up */
+	.reset = ice40_reset,
+	.start = ice40_run,
+	.stop = ice40_stop,
+
+	/* endpoint and I/O routines */
+	.urb_enqueue = ice40_urb_enqueue,
+	.urb_dequeue = ice40_urb_dequeue,
+	.endpoint_disable = ice40_endpoint_disable,
+
+	/* Root hub operations */
+	.hub_status_data = ice40_hub_status_data,
+	.hub_control = ice40_hub_control,
+	.bus_suspend = ice40_bus_suspend,
+	.bus_resume = ice40_bus_resume,
+
+	.set_autosuspend_delay = ice40_set_autosuspend_delay,
+};
+
+static int ice40_spi_parse_dt(struct ice40_hcd *ihcd)
+{
+	struct device_node *node = ihcd->spi->dev.of_node;
+	int ret = 0;
+
+	if (!node) {
+		pr_err("device specific info missing\n");
+		ret = -ENODEV;
+		goto out;
+	}
+
+	ihcd->reset_gpio = of_get_named_gpio(node, "lattice,reset-gpio", 0);
+	if (ihcd->reset_gpio < 0) {
+		pr_err("reset gpio is missing\n");
+		ret = ihcd->reset_gpio;
+		goto out;
+	}
+
+	ihcd->slave_select_gpio = of_get_named_gpio(node,
+				"lattice,slave-select-gpio", 0);
+	if (ihcd->slave_select_gpio < 0) {
+		pr_err("slave select gpio is missing\n");
+		ret = ihcd->slave_select_gpio;
+		goto out;
+	}
+
+	ihcd->config_done_gpio = of_get_named_gpio(node,
+				"lattice,config-done-gpio", 0);
+	if (ihcd->config_done_gpio < 0) {
+		pr_err("config done gpio is missing\n");
+		ret = ihcd->config_done_gpio;
+		goto out;
+	}
+
+	ihcd->vcc_en_gpio = of_get_named_gpio(node, "lattice,vcc-en-gpio", 0);
+	if (ihcd->vcc_en_gpio < 0) {
+		pr_err("vcc enable gpio is missing\n");
+		ret = ihcd->vcc_en_gpio;
+		goto out;
+	}
+
+	/*
+	 * When clk-en-gpio is present, it is used to enable the 19.2 MHz
+	 * clock from MSM to the bridge chip. Otherwise on-board clock
+	 * is used.
+	 */
+	ihcd->clk_en_gpio = of_get_named_gpio(node, "lattice,clk-en-gpio", 0);
+	if (ihcd->clk_en_gpio < 0)
+		ihcd->clk_en_gpio = 0;
+out:
+	return ret;
+}
+
+static void ice40_spi_power_off(struct ice40_hcd *ihcd)
+{
+	if (!ihcd->powered)
+		return;
+
+	gpio_direction_output(ihcd->vcc_en_gpio, 0);
+	regulator_disable(ihcd->core_vcc);
+	regulator_disable(ihcd->spi_vcc);
+	if (ihcd->gpio_vcc)
+		regulator_disable(ihcd->gpio_vcc);
+	if (ihcd->clk_en_gpio)
+		gpio_direction_output(ihcd->clk_en_gpio, 0);
+
+	ihcd->powered = false;
+}
+
+static int ice40_spi_power_up(struct ice40_hcd *ihcd)
+{
+	int ret;
+
+	if (ihcd->clk_en_gpio) {
+		ret = gpio_direction_output(ihcd->clk_en_gpio, 1);
+		if (ret < 0) {
+			pr_err("fail to enabel clk %d\n", ret);
+			goto out;
+		}
+	}
+
+	if (ihcd->gpio_vcc) {
+		ret = regulator_enable(ihcd->gpio_vcc); /* 1.8 V */
+		if (ret < 0) {
+			pr_err("fail to enable gpio vcc\n");
+			goto disable_clk;
+		}
+	}
+
+	ret = regulator_enable(ihcd->spi_vcc); /* 1.8 V */
+	if (ret < 0) {
+		pr_err("fail to enable spi vcc\n");
+		goto disable_gpio_vcc;
+	}
+
+	ret = regulator_enable(ihcd->core_vcc); /* 1.2 V */
+	if (ret < 0) {
+		pr_err("fail to enable core vcc\n");
+		goto disable_spi_vcc;
+	}
+
+	ret = gpio_direction_output(ihcd->vcc_en_gpio, 1);
+	if (ret < 0) {
+		pr_err("fail to assert vcc gpio\n");
+		goto disable_core_vcc;
+	}
+
+	ihcd->powered = true;
+
+	return 0;
+
+disable_core_vcc:
+	regulator_disable(ihcd->core_vcc);
+disable_spi_vcc:
+	regulator_disable(ihcd->spi_vcc);
+disable_gpio_vcc:
+	if (ihcd->gpio_vcc)
+		regulator_disable(ihcd->gpio_vcc);
+disable_clk:
+	if (ihcd->clk_en_gpio)
+		gpio_direction_output(ihcd->clk_en_gpio, 0);
+out:
+	return ret;
+}
+
+static struct gpiomux_setting slave_select_setting = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_NONE,
+	.dir = GPIOMUX_OUT_LOW,
+};
+
+static int ice40_spi_cache_fw(struct ice40_hcd *ihcd)
+{
+	const struct firmware *fw;
+	void *buf;
+	size_t buf_len;
+	int ret;
+
+	ret = request_firmware(&fw, fw_name, &ihcd->spi->dev);
+	if (ret < 0) {
+		pr_err("fail to get the firmware\n");
+		goto out;
+	}
+
+	pr_debug("received firmware size = %zu\n", fw->size);
+
+	/*
+	 * The bridge expects additional clock cycles after
+	 * receiving the configuration data. We don't have a
+	 * direct control over SPI clock. Add extra bytes
+	 * to the confiration data.
+	 */
+	buf_len = fw->size + 16;
+	buf = devm_kzalloc(&ihcd->spi->dev, buf_len, GFP_KERNEL);
+	if (!buf) {
+		pr_err("fail to allocate firmware buffer\n");
+		ret = -ENOMEM;
+		goto release;
+	}
+
+	/*
+	 * The firmware buffer can not be used for DMA as it
+	 * is not physically contiguous. We copy the data
+	 * in kmalloc buffer. This buffer will be freed only
+	 * during unbind or rmmod.
+	 */
+	memcpy(buf, fw->data, fw->size);
+	release_firmware(fw);
+
+	/*
+	 * The bridge supports only 25 MHz during configuration
+	 * file loading.
+	 */
+	ihcd->fmsg_xfr[0].tx_buf = buf;
+	ihcd->fmsg_xfr[0].len = buf_len;
+	ihcd->fmsg_xfr[0].speed_hz = 25000000;
+
+	return 0;
+
+release:
+	release_firmware(fw);
+out:
+	return ret;
+}
+
+static int ice40_spi_load_fw(struct ice40_hcd *ihcd)
+{
+	int ret, i;
+	struct gpiomux_setting active_old_setting, suspend_old_setting;
+
+	ret = gpio_direction_output(ihcd->reset_gpio, 0);
+	if (ret  < 0) {
+		pr_err("fail to assert reset %d\n", ret);
+		goto out;
+	}
+
+	ret = gpio_direction_output(ihcd->vcc_en_gpio, 0);
+	if (ret < 0) {
+		pr_err("fail to de-assert vcc_en gpio %d\n", ret);
+		goto out;
+	}
+
+	/*
+	 * The bridge chip samples the chip select signal during
+	 * power-up. If it is low, it enters SPI slave mode and
+	 * accepts the configuration data from us. The chip
+	 * select signal is managed by the SPI controller driver.
+	 * We temporarily override the chip select config to
+	 * drive it low. The SPI bus needs to be locked down during
+	 * this period to avoid other slave data going to our
+	 * bridge chip. Disable the SPI runtime suspend for exclusive
+	 * chip select access.
+	 */
+	pm_runtime_get_sync(ihcd->spi->master->dev.parent);
+
+	spi_bus_lock(ihcd->spi->master);
+
+	ret = msm_gpiomux_write(ihcd->slave_select_gpio, GPIOMUX_SUSPENDED,
+			&slave_select_setting, &suspend_old_setting);
+	if (ret < 0) {
+		pr_err("fail to override suspend setting and select slave %d\n",
+				ret);
+		spi_bus_unlock(ihcd->spi->master);
+		pm_runtime_put_noidle(ihcd->spi->master->dev.parent);
+		goto out;
+	}
+
+	ret = msm_gpiomux_write(ihcd->slave_select_gpio, GPIOMUX_ACTIVE,
+			&slave_select_setting, &active_old_setting);
+	if (ret < 0) {
+		pr_err("fail to override active setting and select slave %d\n",
+				ret);
+		spi_bus_unlock(ihcd->spi->master);
+		pm_runtime_put_noidle(ihcd->spi->master->dev.parent);
+		goto out;
+	}
+
+	ret = ice40_spi_power_up(ihcd);
+	if (ret < 0) {
+		pr_err("fail to power up the chip\n");
+		spi_bus_unlock(ihcd->spi->master);
+		pm_runtime_put_noidle(ihcd->spi->master->dev.parent);
+		goto out;
+	}
+
+
+	/*
+	 * The databook says 1200 usec is required before the
+	 * chip becomes ready for the SPI transfer.
+	 */
+	usleep_range(1200, 1250);
+
+	ret = msm_gpiomux_write(ihcd->slave_select_gpio, GPIOMUX_SUSPENDED,
+			&suspend_old_setting, NULL);
+	if (ret < 0) {
+		pr_err("fail to rewrite suspend setting %d\n", ret);
+		spi_bus_unlock(ihcd->spi->master);
+		pm_runtime_put_noidle(ihcd->spi->master->dev.parent);
+		goto power_off;
+	}
+
+	ret = msm_gpiomux_write(ihcd->slave_select_gpio, GPIOMUX_ACTIVE,
+			&active_old_setting, NULL);
+	if (ret < 0) {
+		pr_err("fail to rewrite active setting %d\n", ret);
+		spi_bus_unlock(ihcd->spi->master);
+		pm_runtime_put_noidle(ihcd->spi->master->dev.parent);
+		goto power_off;
+	}
+
+	pm_runtime_put_noidle(ihcd->spi->master->dev.parent);
+
+	ret = spi_sync_locked(ihcd->spi, ihcd->fmsg);
+
+	spi_bus_unlock(ihcd->spi->master);
+
+	if (ret < 0) {
+		pr_err("spi write failed\n");
+		goto power_off;
+	}
+
+	for (i = 0; i < 1000; i++) {
+		ret = gpio_get_value(ihcd->config_done_gpio);
+		if (ret) {
+			pr_debug("config done asserted %d\n", i);
+			break;
+		}
+		udelay(1);
+	}
+
+	if (ret <= 0) {
+		pr_err("config done not asserted\n");
+		ret = -ENODEV;
+		goto power_off;
+	}
+
+	ret = gpio_direction_output(ihcd->reset_gpio, 1);
+	if (ret  < 0) {
+		pr_err("fail to assert reset %d\n", ret);
+		goto power_off;
+	}
+	udelay(50);
+
+	ret = ice40_spi_reg_read(ihcd, XFRST_REG);
+	pr_debug("XFRST val is %x\n", ret);
+	if (!(ret & PLLOK)) {
+		pr_err("The PLL2 is not synchronized\n");
+		goto power_off;
+	}
+
+	pr_info("Firmware load success\n");
+
+	return 0;
+
+power_off:
+	ice40_spi_power_off(ihcd);
+out:
+	return ret;
+}
+
+static int ice40_spi_init_regulators(struct ice40_hcd *ihcd)
+{
+	int ret;
+
+	ihcd->spi_vcc = devm_regulator_get(&ihcd->spi->dev, "spi-vcc");
+	if (IS_ERR(ihcd->spi_vcc)) {
+		ret = PTR_ERR(ihcd->spi_vcc);
+		if (ret != -EPROBE_DEFER)
+			pr_err("fail to get spi-vcc %d\n", ret);
+		goto out;
+	}
+
+	ret = regulator_set_voltage(ihcd->spi_vcc, 1800000, 1800000);
+	if (ret < 0) {
+		pr_err("fail to set spi-vcc %d\n", ret);
+		goto out;
+	}
+
+	ihcd->core_vcc = devm_regulator_get(&ihcd->spi->dev, "core-vcc");
+	if (IS_ERR(ihcd->core_vcc)) {
+		ret = PTR_ERR(ihcd->core_vcc);
+		if (ret != -EPROBE_DEFER)
+			pr_err("fail to get core-vcc %d\n", ret);
+		goto out;
+	}
+
+	ret = regulator_set_voltage(ihcd->core_vcc, 1200000, 1200000);
+	if (ret < 0) {
+		pr_err("fail to set core-vcc %d\n", ret);
+		goto out;
+	}
+
+	if (!of_get_property(ihcd->spi->dev.of_node, "gpio-supply", NULL))
+		goto out;
+
+	ihcd->gpio_vcc = devm_regulator_get(&ihcd->spi->dev, "gpio");
+	if (IS_ERR(ihcd->gpio_vcc)) {
+		ret = PTR_ERR(ihcd->gpio_vcc);
+		if (ret != -EPROBE_DEFER)
+			pr_err("fail to get gpio_vcc %d\n", ret);
+		goto out;
+	}
+
+	ret = regulator_set_voltage(ihcd->gpio_vcc, 1800000, 1800000);
+	if (ret < 0) {
+		pr_err("fail to set gpio_vcc %d\n", ret);
+		goto out;
+	}
+
+out:
+	return ret;
+}
+
+static int ice40_spi_request_gpios(struct ice40_hcd *ihcd)
+{
+	int ret;
+
+	ret = devm_gpio_request(&ihcd->spi->dev, ihcd->reset_gpio,
+				"ice40_reset");
+	if (ret < 0) {
+		pr_err("fail to request reset gpio\n");
+		goto out;
+	}
+
+	ret = devm_gpio_request(&ihcd->spi->dev, ihcd->config_done_gpio,
+				"ice40_config_done");
+	if (ret < 0) {
+		pr_err("fail to request config_done gpio\n");
+		goto out;
+	}
+
+	ret = devm_gpio_request(&ihcd->spi->dev, ihcd->vcc_en_gpio,
+				"ice40_vcc_en");
+	if (ret < 0) {
+		pr_err("fail to request vcc_en gpio\n");
+		goto out;
+	}
+
+	if (ihcd->clk_en_gpio) {
+
+		ret = devm_gpio_request(&ihcd->spi->dev, ihcd->clk_en_gpio,
+					"ice40_clk_en");
+		if (ret < 0)
+			pr_err("fail to request clk_en gpio\n");
+	}
+
+out:
+	return ret;
+}
+
+static int
+ice40_spi_init_one_xfr(struct ice40_hcd *ihcd, enum ice40_xfr_type type)
+{
+	struct spi_message **m;
+	struct spi_transfer **t;
+	int n;
+
+	switch (type) {
+	case FIRMWARE_XFR:
+		m = &ihcd->fmsg;
+		t = &ihcd->fmsg_xfr;
+		n = 1;
+		break;
+	case REG_WRITE_XFR:
+		m = &ihcd->wmsg;
+		t = &ihcd->wmsg_xfr;
+		n = 1;
+		break;
+	case REG_READ_XFR:
+		m = &ihcd->rmsg;
+		t = &ihcd->rmsg_xfr;
+		n = 1;
+		break;
+	case SETUP_XFR:
+		m = &ihcd->setup_msg;
+		t = &ihcd->setup_xfr;
+		n = 2;
+		break;
+	case DATA_IN_XFR:
+		m = &ihcd->in_msg;
+		t = &ihcd->in_xfr;
+		n = 2;
+		break;
+	case DATA_OUT_XFR:
+		m = &ihcd->out_msg;
+		t = &ihcd->out_xfr;
+		n = 2;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	*m = devm_kzalloc(&ihcd->spi->dev, sizeof(**m), GFP_KERNEL);
+	if (*m == NULL)
+		goto out;
+
+	*t = devm_kzalloc(&ihcd->spi->dev, n * sizeof(**t), GFP_KERNEL);
+	if (*t == NULL)
+		goto out;
+
+	spi_message_init_with_transfers(*m, *t, n);
+
+	return 0;
+out:
+	return -ENOMEM;
+}
+
+static int ice40_spi_init_xfrs(struct ice40_hcd *ihcd)
+{
+	int ret = -ENOMEM;
+
+	ret = ice40_spi_init_one_xfr(ihcd, FIRMWARE_XFR);
+	if (ret < 0)
+		goto out;
+
+	ret = ice40_spi_init_one_xfr(ihcd, REG_WRITE_XFR);
+	if (ret < 0)
+		goto out;
+
+	ihcd->w_tx_buf = devm_kzalloc(&ihcd->spi->dev, 2, GFP_KERNEL);
+	if (!ihcd->w_tx_buf)
+		goto out;
+
+	ihcd->w_rx_buf = devm_kzalloc(&ihcd->spi->dev, 2, GFP_KERNEL);
+	if (!ihcd->w_rx_buf)
+		goto out;
+
+	ihcd->wmsg_xfr[0].tx_buf = ihcd->w_tx_buf;
+	ihcd->wmsg_xfr[0].rx_buf = ihcd->w_rx_buf;
+	ihcd->wmsg_xfr[0].len = 2;
+
+	ret = ice40_spi_init_one_xfr(ihcd, REG_READ_XFR);
+	if (ret < 0)
+		goto out;
+
+	ihcd->r_tx_buf = devm_kzalloc(&ihcd->spi->dev, 3, GFP_KERNEL);
+	if (!ihcd->r_tx_buf)
+		goto out;
+
+	ihcd->r_rx_buf = devm_kzalloc(&ihcd->spi->dev, 3, GFP_KERNEL);
+	if (!ihcd->r_rx_buf)
+		goto out;
+
+	ihcd->rmsg_xfr[0].tx_buf = ihcd->r_tx_buf;
+	ihcd->rmsg_xfr[0].rx_buf = ihcd->r_rx_buf;
+	ihcd->rmsg_xfr[0].len = 3;
+
+	ret = ice40_spi_init_one_xfr(ihcd, SETUP_XFR);
+	if (ret < 0)
+		goto out;
+
+	ihcd->setup_buf = devm_kzalloc(&ihcd->spi->dev, 1, GFP_KERNEL);
+	if (!ihcd->setup_buf)
+		goto out;
+	ihcd->setup_xfr[0].tx_buf = ihcd->setup_buf;
+	ihcd->setup_xfr[0].len = 1;
+
+	ret = ice40_spi_init_one_xfr(ihcd, DATA_IN_XFR);
+	if (ret < 0)
+		goto out;
+	ihcd->in_buf = devm_kzalloc(&ihcd->spi->dev, 2, GFP_KERNEL);
+	if (!ihcd->in_buf)
+		goto out;
+	ihcd->in_xfr[0].tx_buf = ihcd->in_buf;
+	ihcd->in_xfr[0].len = 2;
+
+	ret = ice40_spi_init_one_xfr(ihcd, DATA_OUT_XFR);
+	if (ret < 0)
+		goto out;
+	ihcd->out_buf = devm_kzalloc(&ihcd->spi->dev, 1, GFP_KERNEL);
+	if (!ihcd->out_buf)
+		goto out;
+	ihcd->out_xfr[0].tx_buf = ihcd->out_buf;
+	ihcd->out_xfr[0].len = 1;
+
+	return 0;
+
+out:
+	return -ENOMEM;
+}
+
+static int ice40_dbg_cmd_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, NULL, inode->i_private);
+}
+
+static ssize_t ice40_dbg_cmd_write(struct file *file, const char __user *ubuf,
+				size_t count, loff_t *ppos)
+{
+	struct seq_file *s = file->private_data;
+	struct ice40_hcd *ihcd = s->private;
+	char buf[32];
+	int ret;
+	u8 status, addr;
+
+	memset(buf, 0x00, sizeof(buf));
+
+	if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) {
+		ret = -EFAULT;
+		goto out;
+	}
+
+	if (!strcmp(buf, "poll")) {
+		if (!HCD_RH_RUNNING(ihcd->hcd)) {
+			ret = -EAGAIN;
+			goto out;
+		}
+		/*
+		 * The bridge chip supports interrupt for device
+		 * connect and disconnect. We don;t have a real
+		 * use case of connect/disconnect. This debugfs
+		 * interface provides a way to enumerate the
+		 * attached device.
+		 */
+		ice40_spi_reg_write(ihcd, ihcd->ctrl0 |
+				DET_BUS_CTRL, CTRL0_REG);
+		ice40_handshake(ihcd, CTRL0_REG, DET_BUS_CTRL, 0, 5000);
+		status = ice40_spi_reg_read(ihcd, XFRST_REG);
+		if ((status & DPST)) {
+			ihcd->port_flags |= USB_PORT_STAT_CONNECTION;
+			ihcd->port_flags |= USB_PORT_STAT_C_CONNECTION << 16;
+			ihcd->pcd_pending = true;
+			usb_hcd_poll_rh_status(ihcd->hcd);
+		} else if (ihcd->port_flags & USB_PORT_STAT_CONNECTION) {
+			ihcd->port_flags &= ~USB_PORT_STAT_ENABLE;
+			ihcd->port_flags &= ~USB_PORT_STAT_CONNECTION;
+			ihcd->port_flags |= (USB_PORT_STAT_C_CONNECTION << 16);
+			ihcd->pcd_pending = true;
+			usb_hcd_poll_rh_status(ihcd->hcd);
+		}
+	} else if (!strcmp(buf, "rwtest")) {
+		ihcd->devnum = 1;
+		ice40_spi_reg_write(ihcd, 0x1, FADDR_REG);
+		addr = ice40_spi_reg_read(ihcd, FADDR_REG);
+		pr_info("addr written was 0x1 read as %x\n", addr);
+	} else if (!strcmp(buf, "force_disconnect")) {
+		if (!HCD_RH_RUNNING(ihcd->hcd)) {
+			ret = -EAGAIN;
+			goto out;
+		}
+		/*
+		 * Forcfully disconnect the device. This is required
+		 * for simulating the disconnect on a USB port which
+		 * does not have pull-down resistors.
+		 */
+		ihcd->port_flags &= ~USB_PORT_STAT_ENABLE;
+		ihcd->port_flags &= ~USB_PORT_STAT_CONNECTION;
+		ihcd->port_flags |= (USB_PORT_STAT_C_CONNECTION << 16);
+		ihcd->pcd_pending = true;
+		usb_hcd_poll_rh_status(ihcd->hcd);
+	} else if (!strcmp(buf, "config_test")) {
+		ice40_spi_power_off(ihcd);
+		ret = ice40_spi_load_fw(ihcd);
+		if (ret) {
+			pr_err("config load failed\n");
+			goto out;
+		}
+	} else {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	ret = count;
+out:
+	return ret;
+}
+
+const struct file_operations ice40_dbg_cmd_ops = {
+	.open = ice40_dbg_cmd_open,
+	.write = ice40_dbg_cmd_write,
+	.llseek = seq_lseek,
+	.release = single_release,
+};
+
+static int ice40_debugfs_init(struct ice40_hcd *ihcd)
+{
+	struct dentry *dir;
+	int ret = 0;
+
+	dir = debugfs_create_dir("ice40_hcd", NULL);
+
+	if (!dir || IS_ERR(dir)) {
+		ret = -ENODEV;
+		goto out;
+	}
+
+	ihcd->dbg_root = dir;
+
+	dir = debugfs_create_file("command", S_IWUSR, ihcd->dbg_root, ihcd,
+			&ice40_dbg_cmd_ops);
+
+	if (!dir) {
+		debugfs_remove_recursive(ihcd->dbg_root);
+		ihcd->dbg_root = NULL;
+		ret = -ENODEV;
+	}
+
+out:
+	return ret;
+}
+
+static int ice40_spi_probe(struct spi_device *spi)
+{
+	struct ice40_hcd *ihcd;
+	int ret;
+
+	ihcd = devm_kzalloc(&spi->dev, sizeof(*ihcd), GFP_KERNEL);
+	if (!ihcd) {
+		pr_err("fail to allocate ihcd\n");
+		ret = -ENOMEM;
+		goto out;
+	}
+	ihcd->spi = spi;
+
+	ret = ice40_spi_parse_dt(ihcd);
+	if (ret) {
+		pr_err("fail to parse dt node\n");
+		goto out;
+	}
+
+	ret = ice40_spi_init_regulators(ihcd);
+	if (ret) {
+		pr_err("fail to init regulators\n");
+		goto out;
+	}
+
+	ret = ice40_spi_request_gpios(ihcd);
+	if (ret) {
+		pr_err("fail to request gpios\n");
+		goto out;
+	}
+
+	spin_lock_init(&ihcd->lock);
+	INIT_LIST_HEAD(&ihcd->async_list);
+	INIT_WORK(&ihcd->async_work, ice40_async_work);
+	mutex_init(&ihcd->wlock);
+	mutex_init(&ihcd->rlock);
+
+	/*
+	 * Enable all our trace points. Useful in debugging card
+	 * enumeration issues.
+	 */
+	ret = trace_set_clr_event(__stringify(TRACE_SYSTEM), NULL, 1);
+	if (ret < 0)
+		pr_err("fail to enable trace points with %d\n", ret);
+
+	ihcd->wq = create_singlethread_workqueue("ice40_wq");
+	if (!ihcd->wq) {
+		pr_err("fail to create workqueue\n");
+		ret = -ENOMEM;
+		goto destroy_mutex;
+	}
+
+	ret = ice40_spi_init_xfrs(ihcd);
+	if (ret) {
+		pr_err("fail to init spi xfrs %d\n", ret);
+		goto destroy_wq;
+	}
+
+	ret = ice40_spi_cache_fw(ihcd);
+	if (ret) {
+		pr_err("fail to cache fw %d\n", ret);
+		goto destroy_wq;
+	}
+
+	ret = ice40_spi_load_fw(ihcd);
+	if (ret) {
+		pr_err("fail to load fw %d\n", ret);
+		goto destroy_wq;
+	}
+
+	ihcd->hcd = usb_create_hcd(&ice40_hc_driver, &spi->dev, "ice40");
+	if (!ihcd->hcd) {
+		pr_err("fail to alloc hcd\n");
+		ret = -ENOMEM;
+		goto power_off;
+	}
+	*((struct ice40_hcd **) ihcd->hcd->hcd_priv) = ihcd;
+
+	ret = usb_add_hcd(ihcd->hcd, 0, 0);
+
+	if (ret < 0) {
+		pr_err("fail to add HCD\n");
+		goto put_hcd;
+	}
+
+	ice40_debugfs_init(ihcd);
+
+	/*
+	 * We manage the power states of the bridge chip
+	 * as part of root hub suspend/resume. We don't
+	 * need to implement any additional runtime PM
+	 * methods.
+	 */
+	pm_runtime_no_callbacks(&spi->dev);
+	pm_runtime_set_active(&spi->dev);
+	pm_runtime_enable(&spi->dev);
+
+	/*
+	 * This does not mean bridge chip can wakeup the
+	 * system from sleep. It's activity can prevent
+	 * or abort the system sleep. The device_init_wakeup
+	 * creates the wakeup source for us which we will
+	 * use to control system sleep.
+	 */
+	device_init_wakeup(&spi->dev, 1);
+	pm_stay_awake(&spi->dev);
+
+	pr_debug("success\n");
+
+	return 0;
+
+put_hcd:
+	usb_put_hcd(ihcd->hcd);
+power_off:
+	ice40_spi_power_off(ihcd);
+destroy_wq:
+	destroy_workqueue(ihcd->wq);
+destroy_mutex:
+	mutex_destroy(&ihcd->rlock);
+	mutex_destroy(&ihcd->wlock);
+out:
+	pr_info("ice40_spi_probe failed\n");
+	return ret;
+}
+
+static int ice40_spi_remove(struct spi_device *spi)
+{
+	struct usb_hcd *hcd = spi_get_drvdata(spi);
+	struct ice40_hcd *ihcd = hcd_to_ihcd(hcd);
+
+	debugfs_remove_recursive(ihcd->dbg_root);
+
+	usb_remove_hcd(hcd);
+	usb_put_hcd(hcd);
+	destroy_workqueue(ihcd->wq);
+	ice40_spi_power_off(ihcd);
+
+	pm_runtime_disable(&spi->dev);
+	pm_relax(&spi->dev);
+
+	return 0;
+}
+
+static struct of_device_id ice40_spi_of_match_table[] = {
+	{ .compatible = "lattice,ice40-spi-usb", },
+	{},
+};
+
+static struct spi_driver ice40_spi_driver = {
+	.driver = {
+		.name =		"ice40_spi",
+		.owner =	THIS_MODULE,
+		.of_match_table = ice40_spi_of_match_table,
+	},
+	.probe =	ice40_spi_probe,
+	.remove =	ice40_spi_remove,
+};
+
+module_spi_driver(ice40_spi_driver);
+
+MODULE_DESCRIPTION("ICE40 FPGA based SPI-USB bridge HCD");
+MODULE_LICENSE("GPL v2");
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 ad09139..f8bc1c5 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -1013,9 +1013,6 @@
 	}
 
 	xhci = hcd_to_xhci(hcd);
-	if (xhci->xhc_state & XHCI_STATE_HALTED)
-		return -ENODEV;
-
 	if (check_virt_dev) {
 		if (!udev->slot_id || !xhci->devs[udev->slot_id]) {
 			printk(KERN_DEBUG "xHCI %s called with unaddressed "
@@ -1031,6 +1028,9 @@
 		}
 	}
 
+	if (xhci->xhc_state & XHCI_STATE_HALTED)
+		return -ENODEV;
+
 	return 1;
 }
 
@@ -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/misc/mdm_ctrl_bridge.c b/drivers/usb/misc/mdm_ctrl_bridge.c
index 75fce2f..262b6c2 100644
--- a/drivers/usb/misc/mdm_ctrl_bridge.c
+++ b/drivers/usb/misc/mdm_ctrl_bridge.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
@@ -26,10 +26,6 @@
 #include <asm/unaligned.h>
 #include <mach/usb_bridge.h>
 
-/* polling interval for Interrupt ep */
-#define HS_INTERVAL		7
-#define FS_LS_INTERVAL		3
-
 #define ACM_CTRL_DTR		(1 << 0)
 #define DEFAULT_READ_URB_LENGTH	4096
 
@@ -719,8 +715,7 @@
 		goto free_inturb;
 	}
 
-	interval =
-		(udev->speed == USB_SPEED_HIGH) ? HS_INTERVAL : FS_LS_INTERVAL;
+	interval = int_in->desc.bInterval;
 
 	usb_fill_int_urb(dev->inturb, udev, dev->int_pipe,
 				dev->intbuf, wMaxPacketSize,
diff --git a/drivers/usb/otg/msm_otg.c b/drivers/usb/otg/msm_otg.c
index 8287ad7..b5641b6 100644
--- a/drivers/usb/otg/msm_otg.c
+++ b/drivers/usb/otg/msm_otg.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009-2013, Linux Foundation. All rights reserved.
+/* Copyright (c) 2009-2014, 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,7 @@
 #include <linux/mfd/pm8xxx/pm8921-charger.h>
 #include <linux/mfd/pm8xxx/misc.h>
 #include <linux/mhl_8334.h>
+#include <linux/qpnp/qpnp-adc.h>
 
 #include <mach/scm.h>
 #include <mach/clk.h>
@@ -455,8 +456,10 @@
 			dev_dbg(motg->phy.dev, "block_reset DEASSERT\n");
 			ret = clk_reset(motg->core_clk, CLK_RESET_DEASSERT);
 			ndelay(200);
-			clk_prepare_enable(motg->core_clk);
-			clk_prepare_enable(motg->pclk);
+			ret = clk_prepare_enable(motg->core_clk);
+			WARN(ret, "USB core_clk enable failed\n");
+			ret = clk_prepare_enable(motg->pclk);
+			WARN(ret, "USB pclk enable failed\n");
 		}
 		if (ret)
 			dev_err(motg->phy.dev, "usb hs_clk deassert failed\n");
@@ -1167,8 +1170,10 @@
 	}
 
 	if (motg->lpm_flags & CLOCKS_DOWN) {
-		clk_prepare_enable(motg->core_clk);
-		clk_prepare_enable(motg->pclk);
+		ret = clk_prepare_enable(motg->core_clk);
+		WARN(ret, "USB core_clk enable failed\n");
+		ret = clk_prepare_enable(motg->pclk);
+		WARN(ret, "USB pclk enable failed\n");
 		motg->lpm_flags &= ~CLOCKS_DOWN;
 	}
 
@@ -1376,6 +1381,16 @@
 	return -ENXIO;
 }
 
+static void msm_otg_set_online_status(struct msm_otg *motg)
+{
+	if (!psy)
+		dev_dbg(motg->phy.dev, "no usb power supply registered\n");
+
+	/* Set power supply online status to false */
+	if (power_supply_set_online(psy, false))
+		dev_dbg(motg->phy.dev, "error setting power supply property\n");
+}
+
 static void msm_otg_notify_charger(struct msm_otg *motg, unsigned mA)
 {
 	struct usb_gadget *g = motg->phy.otg->gadget;
@@ -1395,6 +1410,13 @@
 			"Failed notifying %d charger type to PMIC\n",
 							motg->chg_type);
 
+	/*
+	 * This condition will be true when usb cable is disconnected
+	 * during bootup before charger detection mechanism starts.
+	 */
+	if (motg->online && motg->cur_power == 0  && mA == 0)
+		msm_otg_set_online_status(motg);
+
 	if (motg->cur_power == mA)
 		return;
 
@@ -2521,12 +2543,15 @@
 
 	if (motg->ext_chg_active) {
 
+do_wait:
 		pr_debug("before msm_otg ext chg wait\n");
 
 		t = wait_for_completion_timeout(&motg->ext_chg_wait,
 				msecs_to_jiffies(3000));
 		if (!t)
 			pr_err("msm_otg ext chg wait timeout\n");
+		else if (motg->ext_chg_active)
+			goto do_wait;
 		else
 			pr_debug("msm_otg ext chg wait done\n");
 	}
@@ -2551,6 +2576,10 @@
 	bool work = 0, srp_reqd, dcp;
 
 	pm_runtime_resume(otg->phy->dev);
+	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:
@@ -2676,6 +2705,7 @@
 				/* Turn off VDP_SRC */
 				ulpi_write(otg->phy, 0x2, 0x86);
 			}
+			msm_chg_block_off(motg);
 			msm_otg_reset(otg->phy);
 			/*
 			 * There is a small window where ID interrupt
@@ -2696,6 +2726,7 @@
 			 */
 			pm_runtime_mark_last_busy(otg->phy->dev);
 			pm_runtime_autosuspend(otg->phy->dev);
+			motg->pm_done = 1;
 		}
 		break;
 	case OTG_STATE_B_SRP_INIT:
@@ -3638,6 +3669,27 @@
 	return count;
 }
 
+static int
+otg_get_prop_usbin_voltage_now(struct msm_otg *motg)
+{
+	int rc = 0;
+	struct qpnp_vadc_result results;
+
+	if (IS_ERR_OR_NULL(motg->vadc_dev)) {
+		motg->vadc_dev = qpnp_get_vadc(motg->phy.dev, "usbin");
+		if (IS_ERR(motg->vadc_dev))
+			return PTR_ERR(motg->vadc_dev);
+	}
+
+	rc = qpnp_vadc_read(motg->vadc_dev, USBIN, &results);
+	if (rc) {
+		pr_err("Unable to read usbin rc=%d\n", rc);
+		return 0;
+	} else {
+		return results.physical;
+	}
+}
+
 static int otg_power_get_property_usb(struct power_supply *psy,
 				  enum power_supply_property psp,
 				  union power_supply_propval *val)
@@ -3667,6 +3719,9 @@
 	case POWER_SUPPLY_PROP_HEALTH:
 		val->intval = motg->usbin_health;
 		break;
+	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+		val->intval = otg_get_prop_usbin_voltage_now(motg);
+		break;
 	default:
 		return -EINVAL;
 	}
@@ -3737,6 +3792,7 @@
 	POWER_SUPPLY_PROP_CURRENT_MAX,
 	POWER_SUPPLY_PROP_SCOPE,
 	POWER_SUPPLY_PROP_TYPE,
+	POWER_SUPPLY_PROP_VOLTAGE_NOW,
 };
 
 const struct file_operations msm_otg_bus_fops = {
@@ -3998,6 +4054,7 @@
 		pr_debug("%s: LPM block request %d\n", __func__, val);
 		if (val) { /* block LPM */
 			if (motg->chg_type == USB_DCP_CHARGER) {
+				motg->ext_chg_active = true;
 				/*
 				 * If device is already suspended, resume it.
 				 * The PM usage counter is incremented in
@@ -4020,6 +4077,42 @@
 			pm_runtime_put(motg->phy.dev);
 		}
 		break;
+	case MSM_USB_EXT_CHG_VOLTAGE_INFO:
+		if (get_user(val, (int __user *)arg)) {
+			pr_err("%s: get_user failed\n\n", __func__);
+			ret = -EFAULT;
+			break;
+		}
+
+		if (val == USB_REQUEST_5V)
+			pr_debug("%s:voting 5V voltage request\n", __func__);
+		else if (val == USB_REQUEST_9V)
+			pr_debug("%s:voting 9V voltage request\n", __func__);
+		break;
+	case MSM_USB_EXT_CHG_RESULT:
+		if (get_user(val, (int __user *)arg)) {
+			pr_err("%s: get_user failed\n\n", __func__);
+			ret = -EFAULT;
+			break;
+		}
+
+		if (!val)
+			pr_debug("%s:voltage request successful\n", __func__);
+		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;
 	}
@@ -4842,6 +4935,7 @@
 
 	dev_dbg(dev, "OTG runtime resume\n");
 	pm_runtime_get_noresume(dev);
+	motg->pm_done = 0;
 	return msm_otg_resume(motg);
 }
 #endif
@@ -4869,6 +4963,7 @@
 
 	dev_dbg(dev, "OTG PM resume\n");
 
+	motg->pm_done = 0;
 	atomic_set(&motg->pm_suspended, 0);
 	if (motg->async_int || motg->sm_work_pending) {
 		pm_runtime_get_noresume(dev);
diff --git a/drivers/usb/storage/scsiglue.c b/drivers/usb/storage/scsiglue.c
index a324a5d..05292f9 100644
--- a/drivers/usb/storage/scsiglue.c
+++ b/drivers/usb/storage/scsiglue.c
@@ -230,6 +230,20 @@
 					US_FL_SCM_MULT_TARG)) &&
 				us->protocol == USB_PR_BULK)
 			us->use_last_sector_hacks = 1;
+
+		if (us->sdev_autosuspend_delay >= 0) {
+			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.c b/drivers/usb/storage/usb.c
index 2653e73..be7044b 100644
--- a/drivers/usb/storage/usb.c
+++ b/drivers/usb/storage/usb.c
@@ -742,6 +742,28 @@
 	return 0;
 }
 
+/* Initialize SCSI device auto-suspend timeout here */
+static void usb_stor_set_scsi_autosuspend(struct us_data *us)
+{
+	struct usb_device *udev = us->pusb_dev;
+	struct usb_host_config *config = udev->actconfig;
+	struct usb_host_interface *intf;
+	int i;
+
+	/*
+	 * Some USB UICC devices has Mass storage interface along
+	 * with CCID interface.  These cards are inserted all the
+	 * time.  Enable SCSI auto-suspend for such devices.
+	 */
+	for (i = 0; i < config->desc.bNumInterfaces; i++) {
+		intf = config->interface[i]->cur_altsetting;
+		if (intf->desc.bInterfaceClass == USB_CLASS_CSCID) {
+			us->sdev_autosuspend_delay = 2000; /* msec */
+			return;
+		}
+	}
+}
+
 /* Initialize all the dynamic resources we need */
 static int usb_stor_acquire_resources(struct us_data *us)
 {
@@ -990,6 +1012,10 @@
 	result = usb_stor_acquire_resources(us);
 	if (result)
 		goto BadDevice;
+
+	us->sdev_autosuspend_delay = -1;
+	usb_stor_set_scsi_autosuspend(us);
+
 	snprintf(us->scsi_name, sizeof(us->scsi_name), "usb-storage %s",
 					dev_name(&us->pusb_intf->dev));
 	result = scsi_add_host(us_to_host(us), dev);
diff --git a/drivers/usb/storage/usb.h b/drivers/usb/storage/usb.h
index 75f70f0..b079984 100644
--- a/drivers/usb/storage/usb.h
+++ b/drivers/usb/storage/usb.h
@@ -161,6 +161,9 @@
 	/* hacks for READ CAPACITY bug handling */
 	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/au1100fb.c b/drivers/video/au1100fb.c
index ffbce45..1d8d91a 100644
--- a/drivers/video/au1100fb.c
+++ b/drivers/video/au1100fb.c
@@ -375,39 +375,13 @@
 int au1100fb_fb_mmap(struct fb_info *fbi, struct vm_area_struct *vma)
 {
 	struct au1100fb_device *fbdev;
-	unsigned int len;
-	unsigned long start=0, off;
 
 	fbdev = to_au1100fb_device(fbi);
 
-	if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT)) {
-		return -EINVAL;
-	}
-
-	start = fbdev->fb_phys & PAGE_MASK;
-	len = PAGE_ALIGN((start & ~PAGE_MASK) + fbdev->fb_len);
-
-	off = vma->vm_pgoff << PAGE_SHIFT;
-
-	if ((vma->vm_end - vma->vm_start + off) > len) {
-		return -EINVAL;
-	}
-
-	off += start;
-	vma->vm_pgoff = off >> PAGE_SHIFT;
-
 	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
 	pgprot_val(vma->vm_page_prot) |= (6 << 9); //CCA=6
 
-	vma->vm_flags |= VM_IO;
-
-	if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT,
-				vma->vm_end - vma->vm_start,
-				vma->vm_page_prot)) {
-		return -EAGAIN;
-	}
-
-	return 0;
+	return vm_iomap_memory(vma, fbdev->fb_phys, fbdev->fb_len);
 }
 
 static struct fb_ops au1100fb_ops =
diff --git a/drivers/video/au1200fb.c b/drivers/video/au1200fb.c
index 7ca79f0..768f372 100644
--- a/drivers/video/au1200fb.c
+++ b/drivers/video/au1200fb.c
@@ -1235,36 +1235,12 @@
 static int au1200fb_fb_mmap(struct fb_info *info, struct vm_area_struct *vma)
 
 {
-	unsigned int len;
-	unsigned long start=0, off;
 	struct au1200fb_device *fbdev = info->par;
 
-	if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT)) {
-		return -EINVAL;
-	}
-
-	start = fbdev->fb_phys & PAGE_MASK;
-	len = PAGE_ALIGN((start & ~PAGE_MASK) + fbdev->fb_len);
-
-	off = vma->vm_pgoff << PAGE_SHIFT;
-
-	if ((vma->vm_end - vma->vm_start + off) > len) {
-		return -EINVAL;
-	}
-
-	off += start;
-	vma->vm_pgoff = off >> PAGE_SHIFT;
-
 	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
 	pgprot_val(vma->vm_page_prot) |= _CACHE_MASK; /* CCA=7 */
 
-	vma->vm_flags |= VM_IO;
-
-	return io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT,
-				  vma->vm_end - vma->vm_start,
-				  vma->vm_page_prot);
-
-	return 0;
+	return vm_iomap_memory(vma, fbdev->fb_phys, fbdev->fb_len);
 }
 
 static void set_global(u_int cmd, struct au1200_lcd_global_regs_t *pdata)
diff --git a/drivers/video/msm/mdss/Makefile b/drivers/video/msm/mdss/Makefile
index fd03b63..ae13322 100644
--- a/drivers/video/msm/mdss/Makefile
+++ b/drivers/video/msm/mdss/Makefile
@@ -1,19 +1,20 @@
-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
 mdss-mdp-objs += mdss_mdp_intf_writeback.o
 mdss-mdp-objs += mdss_mdp_rotator.o
 mdss-mdp-objs += mdss_mdp_overlay.o
+mdss-mdp-objs += mdss_mdp_splash_logo.o
 mdss-mdp-objs += mdss_mdp_wb.o
 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 +43,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 25ee3e4..99e1c21 100644
--- a/drivers/video/msm/mdss/dsi_host_v2.c
+++ b/drivers/video/msm/mdss/dsi_host_v2.c
@@ -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
@@ -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
@@ -203,6 +204,13 @@
 	struct mdss_dsi_ctrl_pdata *ctrl =
 		(struct mdss_dsi_ctrl_pdata *)ptr;
 
+	spin_lock(&ctrl->mdp_lock);
+
+	if (ctrl->dsi_irq_mask == 0) {
+		spin_unlock(&ctrl->mdp_lock);
+		return IRQ_HANDLED;
+	}
+
 	isr = MIPI_INP(dsi_host_private->dsi_base + DSI_INT_CTRL);
 	MIPI_OUTP(dsi_host_private->dsi_base + DSI_INT_CTRL, isr);
 
@@ -213,22 +221,20 @@
 		msm_dsi_error(dsi_host_private->dsi_base);
 	}
 
-	spin_lock(&ctrl->mdp_lock);
-
 	if (isr & DSI_INTR_VIDEO_DONE)
 		complete(&ctrl->video_comp);
 
 	if (isr & DSI_INTR_CMD_DMA_DONE)
 		complete(&ctrl->dma_comp);
 
-	spin_unlock(&ctrl->mdp_lock);
-
 	if (isr & DSI_INTR_BTA_DONE)
 		complete(&ctrl->bta_comp);
 
 	if (isr & DSI_INTR_CMD_MDP_DONE)
 		complete(&ctrl->mdp_comp);
 
+	spin_unlock(&ctrl->mdp_lock);
+
 	return IRQ_HANDLED;
 }
 
@@ -236,6 +242,13 @@
 			struct mdss_dsi_ctrl_pdata *ctrl)
 {
 	int ret;
+	u32 isr;
+
+	msm_dsi_ahb_ctrl(1);
+	isr = MIPI_INP(dsi_host_private->dsi_base + DSI_INT_CTRL);
+	isr &= ~DSI_INTR_ALL_MASK;
+	MIPI_OUTP(dsi_host_private->dsi_base + DSI_INT_CTRL, isr);
+	msm_dsi_ahb_ctrl(0);
 
 	ret = devm_request_irq(dev, irq_no, msm_dsi_isr_handler,
 				IRQF_DISABLED, "DSI", ctrl);
@@ -524,8 +537,11 @@
 	if (readl_poll_timeout((ctrl_base + DSI_STATUS),
 				status,
 				((status & 0x02) == 0),
-				DSI_POLL_SLEEP_US, DSI_POLL_TIMEOUT_US))
+				DSI_POLL_SLEEP_US, DSI_POLL_TIMEOUT_US)) {
 		pr_err("%s: DSI status=%x failed\n", __func__, status);
+		pr_err("%s: Doing sw reset\n", __func__);
+		msm_dsi_sw_reset();
+	}
 
 	/* Check for x_HS_FIFO_EMPTY */
 	if (readl_poll_timeout((ctrl_base + DSI_FIFO_STATUS),
@@ -956,15 +972,28 @@
 		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))
+		dsi_set_tx_power_mode(0);
+
 	if (req->flags & CMD_REQ_RX)
 		msm_dsi_cmdlist_rx(ctrl, req);
 	else
 		msm_dsi_cmdlist_tx(ctrl, req);
 
+	if (0 == (req->flags & CMD_REQ_LP_MODE))
+		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;
@@ -1207,6 +1236,13 @@
 		mutex_unlock(&ctrl_pdata->mutex);
 		return ret;
 	}
+	pinfo->panel_power_on = 1;
+	ret = mdss_dsi_panel_reset(pdata, 1);
+	if (ret) {
+		pr_err("%s: Panel reset failed\n", __func__);
+		mutex_unlock(&ctrl_pdata->mutex);
+		return ret;
+	}
 
 	msm_dsi_ahb_ctrl(1);
 	msm_dsi_prepare_clocks();
@@ -1403,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);
 		}
 	}
@@ -1494,14 +1533,6 @@
 							__func__, __LINE__);
 		rc = -ENODEV;
 		goto error_irq_resource;
-	} else {
-		rc = msm_dsi_irq_init(&pdev->dev, mdss_dsi_mres->start,
-					ctrl_pdata);
-		if (rc) {
-			dev_err(&pdev->dev, "%s: failed to init irq, rc=%d\n",
-								__func__, rc);
-			goto error_irq_resource;
-		}
 	}
 
 	rc = of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev);
@@ -1564,6 +1595,14 @@
 
 	msm_dsi_ctrl_init(ctrl_pdata);
 
+	rc = msm_dsi_irq_init(&pdev->dev, mdss_dsi_mres->start,
+					   ctrl_pdata);
+	if (rc) {
+		dev_err(&pdev->dev, "%s: failed to init irq, rc=%d\n",
+			__func__, rc);
+		goto error_device_register;
+	}
+
 	rc = dsi_panel_device_register_v2(pdev, ctrl_pdata);
 	if (rc) {
 		pr_err("%s: dsi panel dev reg failed\n", __func__);
diff --git a/drivers/video/msm/mdss/dsi_host_v2.h b/drivers/video/msm/mdss/dsi_host_v2.h
index b297452..0f3ea8d 100644
--- a/drivers/video/msm/mdss/dsi_host_v2.h
+++ b/drivers/video/msm/mdss/dsi_host_v2.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
@@ -25,6 +25,7 @@
 #define DSI_INTR_CMD_MDP_DONE			BIT(8)
 #define DSI_INTR_CMD_DMA_DONE_MASK		BIT(1)
 #define DSI_INTR_CMD_DMA_DONE			BIT(0)
+#define DSI_INTR_ALL_MASK			0x2220202
 
 #define DSI_BTA_TERM				BIT(1)
 
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..4f7e4da
--- /dev/null
+++ b/drivers/video/msm/mdss/dsi_status_6g.c
@@ -0,0 +1,118 @@
+/* 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);
+	if (!pstatus_data || !(pstatus_data->mfd)) {
+		pr_err("%s: mfd not available\n", __func__);
+		return;
+	}
+
+	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) {
+		pr_err("%s: Display is off\n", __func__);
+		return;
+	}
+
+	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 d62ddf3..f0966cc 100644
--- a/drivers/video/msm/mdss/dsi_status_v2.c
+++ b/drivers/video/msm/mdss/dsi_status_v2.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
@@ -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,9 +38,10 @@
 	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__);
+	struct dsi_status_data, check_status);
+
+	if (!pdsi_status || !(pdsi_status->mfd)) {
+		pr_err("%s: mfd not available\n", __func__);
 		return;
 	}
 
@@ -72,117 +50,51 @@
 		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;
+	if (!mdp3_session) {
+		pr_err("%s: Display is off\n", __func__);
+		return;
+	}
+
 	mutex_lock(&mdp3_session->lock);
+	if (!mdp3_session->status) {
+		pr_info("display off already\n");
+		mutex_unlock(&mdp3_session->lock);
+		return;
+	}
 
-	ret = ctrl_pdata->check_status(ctrl_pdata);
+	if (mdp3_session->wait_for_dma_done)
+		ret = mdp3_session->wait_for_dma_done(mdp3_session);
 
+	if (!ret)
+		ret = ctrl_pdata->check_status(ctrl_pdata);
+	else
+		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/dsi_v2.c b/drivers/video/msm/mdss/dsi_v2.c
index ccde545..bc76fd0 100644
--- a/drivers/video/msm/mdss/dsi_v2.c
+++ b/drivers/video/msm/mdss/dsi_v2.c
@@ -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
@@ -66,6 +66,7 @@
 	if (enable) {
 		dsi_ctrl_gpio_request(ctrl_pdata);
 		mdss_dsi_panel_reset(pdata, 1);
+		pdata->panel_info.panel_power_on = 1;
 		rc = ctrl_pdata->on(pdata);
 		if (rc)
 			pr_err("dsi_panel_handler panel on failed %d\n", rc);
@@ -73,6 +74,7 @@
 		if (dsi_intf.op_mode_config)
 			dsi_intf.op_mode_config(DSI_CMD_MODE, pdata);
 		rc = ctrl_pdata->off(pdata);
+		pdata->panel_info.panel_power_on = 0;
 		mdss_dsi_panel_reset(pdata, 0);
 		dsi_ctrl_gpio_free(ctrl_pdata);
 	}
@@ -202,75 +204,23 @@
 {
 	int rc = 0;
 
-	if (gpio_is_valid(ctrl_pdata->disp_en_gpio)) {
-		rc = gpio_request(ctrl_pdata->disp_en_gpio, "disp_enable");
-		if (rc)
-			goto gpio_request_err4;
-
-		ctrl_pdata->disp_en_gpio_requested = 1;
-	}
-
-	if (gpio_is_valid(ctrl_pdata->rst_gpio)) {
-		rc = gpio_request(ctrl_pdata->rst_gpio, "disp_rst_n");
-		if (rc)
-			goto gpio_request_err3;
-
-		ctrl_pdata->rst_gpio_requested = 1;
-	}
-
 	if (gpio_is_valid(ctrl_pdata->disp_te_gpio)) {
 		rc = gpio_request(ctrl_pdata->disp_te_gpio, "disp_te");
 		if (rc)
-			goto gpio_request_err2;
-
-		ctrl_pdata->disp_te_gpio_requested = 1;
+			ctrl_pdata->disp_te_gpio_requested = 0;
+		else
+			ctrl_pdata->disp_te_gpio_requested = 1;
 	}
 
-	if (gpio_is_valid(ctrl_pdata->mode_gpio)) {
-		rc = gpio_request(ctrl_pdata->mode_gpio, "panel_mode");
-		if (rc)
-			goto gpio_request_err1;
-
-		ctrl_pdata->mode_gpio_requested = 1;
-	}
-
-	return rc;
-
-gpio_request_err1:
-	if (gpio_is_valid(ctrl_pdata->disp_te_gpio))
-		gpio_free(ctrl_pdata->disp_te_gpio);
-gpio_request_err2:
-	if (gpio_is_valid(ctrl_pdata->rst_gpio))
-		gpio_free(ctrl_pdata->rst_gpio);
-gpio_request_err3:
-	if (gpio_is_valid(ctrl_pdata->disp_en_gpio))
-		gpio_free(ctrl_pdata->disp_en_gpio);
-gpio_request_err4:
-	ctrl_pdata->disp_en_gpio_requested = 0;
-	ctrl_pdata->rst_gpio_requested = 0;
-	ctrl_pdata->disp_te_gpio_requested = 0;
-	ctrl_pdata->mode_gpio_requested = 0;
 	return rc;
 }
 
 void dsi_ctrl_gpio_free(struct mdss_dsi_ctrl_pdata *ctrl_pdata)
 {
-	if (ctrl_pdata->disp_en_gpio_requested) {
-		gpio_free(ctrl_pdata->disp_en_gpio);
-		ctrl_pdata->disp_en_gpio_requested = 0;
-	}
-	if (ctrl_pdata->rst_gpio_requested) {
-		gpio_free(ctrl_pdata->rst_gpio);
-		ctrl_pdata->rst_gpio_requested = 0;
-	}
 	if (ctrl_pdata->disp_te_gpio_requested) {
 		gpio_free(ctrl_pdata->disp_te_gpio);
 		ctrl_pdata->disp_te_gpio_requested = 0;
 	}
-	if (ctrl_pdata->mode_gpio_requested) {
-		gpio_free(ctrl_pdata->mode_gpio);
-		ctrl_pdata->mode_gpio_requested = 0;
-	}
 }
 
 static int dsi_parse_vreg(struct device *dev, struct dss_module_power *mp)
diff --git a/drivers/video/msm/mdss/mdp3.c b/drivers/video/msm/mdss/mdp3.c
index 02bd7e9..37134b4 100644
--- a/drivers/video/msm/mdss/mdp3.c
+++ b/drivers/video/msm/mdss/mdp3.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
  * Copyright (C) 2007 Google Incorporated
  *
  * This software is licensed under the terms of the GNU General Public
@@ -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;
 }
@@ -674,9 +738,11 @@
 	if (context >= MDP3_IOMMU_CTX_MAX)
 		return -EINVAL;
 
+	mutex_lock(&mdp3_res->iommu_lock);
 	context_map = mdp3_res->iommu_contexts + context;
 	if (context_map->attached) {
 		pr_warn("mdp iommu already attached\n");
+		mutex_unlock(&mdp3_res->iommu_lock);
 		return 0;
 	}
 
@@ -685,6 +751,7 @@
 	iommu_attach_device(domain_map->domain, context_map->ctx);
 
 	context_map->attached = true;
+	mutex_unlock(&mdp3_res->iommu_lock);
 	return 0;
 }
 
@@ -697,9 +764,11 @@
 		context >= MDP3_IOMMU_CTX_MAX)
 		return -EINVAL;
 
+	mutex_lock(&mdp3_res->iommu_lock);
 	context_map = mdp3_res->iommu_contexts + context;
 	if (!context_map->attached) {
 		pr_warn("mdp iommu not attached\n");
+		mutex_unlock(&mdp3_res->iommu_lock);
 		return 0;
 	}
 
@@ -707,6 +776,7 @@
 	iommu_detach_device(domain_map->domain, context_map->ctx);
 	context_map->attached = false;
 
+	mutex_unlock(&mdp3_res->iommu_lock);
 	return 0;
 }
 
@@ -1141,6 +1211,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 +1291,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;
@@ -1667,69 +1791,79 @@
 		return xres * bpp;
 }
 
-static int mdp3_alloc(size_t size, void **virt, unsigned long *phys)
+static int mdp3_alloc(struct msm_fb_data_type *mfd)
 {
-	int ret = 0;
+	int ret;
+	int dom;
+	void *virt;
+	unsigned long phys;
+	u32 offsets[2];
+	size_t size;
+	struct platform_device *pdev = mfd->pdev;
 
-	if (mdp3_res->ion_handle) {
-		pr_debug("memory already alloc\n");
-		*virt = mdp3_res->virt;
-		*phys = mdp3_res->phys;
-		return 0;
+	mfd->fbi->screen_base = NULL;
+	mfd->fbi->fix.smem_start = 0;
+	mfd->fbi->fix.smem_len = 0;
+
+	ret = of_property_read_u32_array(pdev->dev.of_node,
+				"qcom,memblock-reserve", offsets, 2);
+
+	if (ret) {
+		pr_err("fail to parse splash memory address\n");
+		return ret;
 	}
 
-	mdp3_res->ion_handle = ion_alloc(mdp3_res->ion_client, size,
-					SZ_1M,
-					ION_HEAP(ION_QSECOM_HEAP_ID), 0);
+	phys = offsets[0];
+	size = PAGE_ALIGN(mfd->fbi->fix.line_length *
+		mfd->fbi->var.yres_virtual);
 
-	if (!IS_ERR_OR_NULL(mdp3_res->ion_handle)) {
-		*virt = ion_map_kernel(mdp3_res->ion_client,
-					mdp3_res->ion_handle);
-		if (IS_ERR(*virt)) {
-			pr_err("map kernel error\n");
-			goto ion_map_kernel_err;
-		}
+	if (size > offsets[1]) {
+		pr_err("reserved splash memory size too small\n");
+		return -EINVAL;
+	}
 
-		ret = ion_phys(mdp3_res->ion_client, mdp3_res->ion_handle,
-				phys, &size);
-		if (ret) {
-			pr_err("%s ion_phys error\n", __func__);
-			goto ion_map_phys_err;
-		}
-
-		mdp3_res->virt = *virt;
-		mdp3_res->phys = *phys;
-		mdp3_res->size = size;
-	} else {
-		pr_err("%s ion alloc fail\n", __func__);
-		mdp3_res->ion_handle = NULL;
+	virt = phys_to_virt(phys);
+	if (unlikely(!virt)) {
+		pr_err("unable to map in splash memory\n");
 		return -ENOMEM;
 	}
 
-	return 0;
+	dom = mdp3_res->domains[MDP3_DMA_IOMMU_DOMAIN].domain_idx;
+	ret = msm_iommu_map_contig_buffer(phys, dom, 0, size, SZ_4K, 0,
+					&mfd->iova);
 
-ion_map_phys_err:
-	ion_unmap_kernel(mdp3_res->ion_client, mdp3_res->ion_handle);
-ion_map_kernel_err:
-	ion_free(mdp3_res->ion_client, mdp3_res->ion_handle);
-	mdp3_res->ion_handle = NULL;
-	mdp3_res->virt = NULL;
-	mdp3_res->phys = 0;
-	mdp3_res->size = 0;
-	return -ENOMEM;
+	if (ret) {
+		pr_err("fail to map to IOMMU %d\n", ret);
+		return ret;
+	}
+	pr_info("allocating %u bytes at %p (%lx phys) for fb %d\n",
+		size, virt, phys, mfd->index);
+
+	mfd->fbi->screen_base = virt;
+	mfd->fbi->fix.smem_start = phys;
+	mfd->fbi->fix.smem_len = size;
+
+	return 0;
 }
 
-void mdp3_free(void)
+void mdp3_free(struct msm_fb_data_type *mfd)
 {
-	pr_debug("mdp3_fbmem_free\n");
-	if (mdp3_res->ion_handle) {
-		ion_unmap_kernel(mdp3_res->ion_client, mdp3_res->ion_handle);
-		ion_free(mdp3_res->ion_client, mdp3_res->ion_handle);
-		mdp3_res->ion_handle = NULL;
-		mdp3_res->virt = NULL;
-		mdp3_res->phys = 0;
-		mdp3_res->size = 0;
+	size_t size = 0;
+	int dom;
+
+	if (!mfd->iova || !mfd->fbi->screen_base) {
+		pr_info("no fbmem allocated\n");
+		return;
 	}
+
+	size = mfd->fbi->fix.smem_len;
+	dom = mdp3_res->domains[MDP3_DMA_IOMMU_DOMAIN].domain_idx;
+	msm_iommu_unmap_contig_buffer(mfd->iova, dom, 0, size);
+
+	mfd->fbi->screen_base = NULL;
+	mfd->fbi->fix.smem_start = 0;
+	mfd->fbi->fix.smem_len = 0;
+	mfd->iova = 0;
 }
 
 int mdp3_parse_dt_splash(struct msm_fb_data_type *mfd)
@@ -1752,16 +1886,17 @@
 	mdp3_res->splash_mem_addr = offsets[0];
 	mdp3_res->splash_mem_size = offsets[1];
 
-	pr_debug("memaddr=%x size=%x\n", mdp3_res->splash_mem_addr,
+	pr_debug("memaddr=%lx size=%x\n", mdp3_res->splash_mem_addr,
 		mdp3_res->splash_mem_size);
 
 	return rc;
 }
 
-void mdp3_release_splash_memory(void)
+void mdp3_release_splash_memory(struct msm_fb_data_type *mfd)
 {
 	/* Give back the reserved memory to the system */
 	if (mdp3_res->splash_mem_addr) {
+		mdp3_free(mfd);
 		pr_debug("mdp3_release_splash_memory\n");
 		memblock_free(mdp3_res->splash_mem_addr,
 				mdp3_res->splash_mem_size);
@@ -1811,44 +1946,6 @@
 	return mdp3_res->cont_splash_en;
 }
 
-int mdp3_continuous_splash_copy(struct mdss_panel_data *pdata)
-{
-	unsigned long splash_phys, phys;
-	void *splash_virt, *virt;
-	u32 height, width, rgb_size, stride;
-	size_t size;
-	int rc;
-
-	if (pdata->panel_info.type != MIPI_VIDEO_PANEL) {
-		pr_debug("cmd mode panel, no need to copy splash image\n");
-		return 0;
-	}
-
-	rgb_size = MDP3_REG_READ(MDP3_REG_DMA_P_SIZE);
-	stride = MDP3_REG_READ(MDP3_REG_DMA_P_IBUF_Y_STRIDE);
-	stride = stride & 0x3FFF;
-	splash_phys = MDP3_REG_READ(MDP3_REG_DMA_P_IBUF_ADDR);
-
-	height = (rgb_size >> 16) & 0xffff;
-	width  = rgb_size & 0xffff;
-	size = PAGE_ALIGN(height * stride);
-	pr_debug("splash_height=%d splash_width=%d Buffer size=%d\n",
-		height, width, size);
-
-	rc = mdp3_alloc(size, &virt, &phys);
-	if (rc) {
-		pr_err("fail to allocate memory for continuous splash image\n");
-		return rc;
-	}
-
-	splash_virt = ioremap(splash_phys, stride * height);
-	memcpy(virt, splash_virt, stride * height);
-	iounmap(splash_virt);
-	MDP3_REG_WRITE(MDP3_REG_DMA_P_IBUF_ADDR, phys);
-
-	return 0;
-}
-
 static int mdp3_is_display_on(struct mdss_panel_data *pdata)
 {
 	int rc = 0;
@@ -1876,33 +1973,35 @@
 static int mdp3_continuous_splash_on(struct mdss_panel_data *pdata)
 {
 	struct mdss_panel_info *panel_info = &pdata->panel_info;
-	int ab, ib, rc;
+	struct mdp3_bus_handle_map *bus_handle;
+	u64 ab, ib;
+	int rc;
 
 	pr_debug("mdp3__continuous_splash_on\n");
 
 	mdp3_clk_set_rate(MDP3_CLK_VSYNC, MDP_VSYNC_CLK_RATE,
 			MDP3_CLIENT_DMA_P);
 
-	rc = mdp3_clk_prepare();
-	if (rc) {
-		pr_err("fail to prepare clk\n");
-		return rc;
-	}
+	mdp3_clk_set_rate(MDP3_CLK_CORE, MDP_CORE_CLK_RATE,
+			MDP3_CLIENT_DMA_P);
 
-	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();
@@ -1911,8 +2010,6 @@
 		goto splash_on_err;
 	}
 
-	mdp3_irq_register();
-
 	if (pdata->event_handler) {
 		rc = pdata->event_handler(pdata, MDSS_EVENT_CONT_SPLASH_BEGIN,
 					NULL);
@@ -1927,15 +2024,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;
 }
 
@@ -1955,6 +2051,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;
 }
 
@@ -1969,11 +2071,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();
 	}
 }
 
@@ -2171,6 +2271,8 @@
 	.fb_mem_get_iommu_domain = mdp3_fb_mem_get_iommu_domain,
 	.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 = {
@@ -2280,13 +2382,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 f1f0455..137a1b8 100644
--- a/drivers/video/msm/mdss/mdp3.h
+++ b/drivers/video/msm/mdss/mdp3.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
  * Copyright (C) 2007 Google Incorporated
  *
  * This program is free software; you can redistribute it and/or modify
@@ -26,6 +26,7 @@
 #include "mdss_fb.h"
 
 #define MDP_VSYNC_CLK_RATE	19200000
+#define MDP_CORE_CLK_RATE	100000000
 #define KOFF_TIMEOUT msecs_to_jiffies(84)
 
 enum  {
@@ -73,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;
 };
 
@@ -133,12 +137,10 @@
 	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;
-	void *virt;
-	unsigned long phys;
-	size_t size;
 
 	struct mdp3_dma dma[MDP3_DMA_MAX];
 	struct mdp3_intf intf[MDP3_DMA_OUTPUT_SEL_MAX];
@@ -146,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;
 
@@ -153,7 +156,7 @@
 
 	struct early_suspend suspend_handler;
 	struct mdss_panel_cfg pan_cfg;
-	u32 splash_mem_addr;
+	unsigned long splash_mem_addr;
 	u32 splash_mem_size;
 
 	int clk_prepare_count;
@@ -161,6 +164,7 @@
 
 	bool batfet_required;
 	struct regulator *batfet;
+	struct regulator *vdd_cx;
 };
 
 struct mdp3_img_data {
@@ -185,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,
@@ -194,9 +197,9 @@
 int mdp3_iommu_enable(int client);
 int mdp3_iommu_disable(int client);
 int mdp3_iommu_is_attached(int client);
-void mdp3_free(void);
+void mdp3_free(struct msm_fb_data_type *mfd);
 int mdp3_parse_dt_splash(struct msm_fb_data_type *mfd);
-void mdp3_release_splash_memory(void);
+void mdp3_release_splash_memory(struct msm_fb_data_type *mfd);
 int mdp3_create_sysfs_link(struct device *dev);
 int mdp3_get_cont_spash_en(void);
 int mdp3_get_mdp_dsi_clk(void);
@@ -205,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 6fc6195..8acb9b0 100644
--- a/drivers/video/msm/mdss/mdp3_ctrl.c
+++ b/drivers/video/msm/mdss/mdp3_ctrl.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
@@ -25,7 +25,6 @@
 #include "mdp3.h"
 #include "mdp3_ppp.h"
 
-#define MDP_CORE_CLK_RATE	100000000
 #define VSYNC_EXPIRE_TICK	4
 
 static void mdp3_ctrl_pan_display(struct msm_fb_data_type *mfd);
@@ -111,6 +110,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,
@@ -118,7 +118,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)
@@ -154,7 +160,9 @@
 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);
 }
 
 void vsync_count_down(void *arg)
@@ -214,7 +222,8 @@
 	 * active or when dsi clocks are currently off
 	 */
 	if (enable && mdp3_session->status == 1
-			&& mdp3_session->vsync_before_commit) {
+			&& (mdp3_session->vsync_before_commit ||
+			!mdp3_session->intf->active)) {
 		mod_timer(&mdp3_session->vsync_timer,
 			jiffies + msecs_to_jiffies(mdp3_session->vsync_period));
 	} else if (enable && !mdp3_session->clk_on) {
@@ -230,7 +239,8 @@
 void mdp3_vsync_timer_func(unsigned long arg)
 {
 	struct mdp3_session_data *session = (struct mdp3_session_data *)arg;
-	if (session->status == 1 && session->vsync_before_commit) {
+	if (session->status == 1 && (session->vsync_before_commit ||
+			!session->intf->active)) {
 		pr_debug("mdp3_vsync_timer_func trigger\n");
 		vsync_notify_handler(session);
 		mod_timer(&session->vsync_timer,
@@ -292,7 +302,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;
 }
 
@@ -325,7 +335,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);
 	}
@@ -339,8 +349,8 @@
 	int rc = 0;
 	if (status) {
 		struct mdss_panel_info *panel_info = mfd->panel_info;
-		int ab = 0;
-		int ib = 0;
+		u64 ab = 0;
+		u64 ib = 0;
 		ab = panel_info->xres * panel_info->yres * 4;
 		ab *= panel_info->mipi.frame_rate;
 		ib = (ab * 3) / 2;
@@ -361,24 +371,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;
 }
@@ -402,10 +403,10 @@
 	return type;
 }
 
-static int mdp3_ctrl_get_source_format(struct msm_fb_data_type *mfd)
+static int mdp3_ctrl_get_source_format(u32 imgType)
 {
 	int format;
-	switch (mfd->fb_imgType) {
+	switch (imgType) {
 	case MDP_RGB_565:
 		format = MDP3_DMA_IBUF_FORMAT_RGB565;
 		break;
@@ -422,10 +423,10 @@
 	return format;
 }
 
-static int mdp3_ctrl_get_pack_pattern(struct msm_fb_data_type *mfd)
+static int mdp3_ctrl_get_pack_pattern(u32 imgType)
 {
 	int packPattern = MDP3_DMA_OUTPUT_PACK_PATTERN_RGB;
-	if (mfd->fb_imgType == MDP_RGBA_8888)
+	if (imgType == MDP_RGBA_8888)
 		packPattern = MDP3_DMA_OUTPUT_PACK_PATTERN_BGR;
 	return packPattern;
 }
@@ -473,6 +474,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;
@@ -501,6 +503,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;
@@ -511,7 +514,7 @@
 	fix = &fbi->fix;
 	var = &fbi->var;
 
-	sourceConfig.format = mdp3_ctrl_get_source_format(mfd);
+	sourceConfig.format = mdp3_ctrl_get_source_format(mfd->fb_imgType);
 	sourceConfig.width = panel_info->xres;
 	sourceConfig.height = panel_info->yres;
 	sourceConfig.x = 0;
@@ -526,18 +529,34 @@
 	outputConfig.out_sel = mdp3_ctrl_get_intf_type(mfd);
 	outputConfig.bit_mask_polarity = 0;
 	outputConfig.color_components_flip = 0;
-	outputConfig.pack_pattern = mdp3_ctrl_get_pack_pattern(mfd);
+	outputConfig.pack_pattern = mdp3_ctrl_get_pack_pattern(mfd->fb_imgType);
 	outputConfig.pack_align = MDP3_DMA_OUTPUT_PACK_ALIGN_LSB;
 	outputConfig.color_comp_out_bits = (MDP3_DMA_OUTPUT_COMP_BITS_8 << 4) |
 					(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);
@@ -570,16 +589,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) {
@@ -602,8 +615,6 @@
 		goto on_error;
 	}
 
-	mdp3_irq_register();
-
 	rc = mdp3_ctrl_dma_init(mfd, mdp3_session->dma);
 	if (rc) {
 		pr_err("dma init failed\n");
@@ -621,19 +632,9 @@
 		pr_err("display interface init failed\n");
 		goto on_error;
 	}
-
 	mdp3_session->clk_on = 1;
-	pr_debug("mdp3_ctrl_on dma start\n");
-	if (mfd->fbi->screen_base) {
-		rc = mdp3_session->dma->start(mdp3_session->dma,
-						mdp3_session->intf);
-		if (rc) {
-			pr_err("fail to start the MDP display interface\n");
-			goto on_error;
-		}
-	} else {
-		mdp3_session->first_commit = true;
-	}
+
+	mdp3_session->first_commit = true;
 
 on_error:
 	if (!rc)
@@ -659,6 +660,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;
@@ -682,7 +686,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");
 
@@ -693,29 +697,23 @@
 		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:
 	mdp3_session->status = 0;
 	mdp3_bufq_deinit(&mdp3_session->bufq_out);
+	if (mdp3_session->overlay.id != MSMFB_NEW_REQUEST) {
+		mdp3_session->overlay.id = MSMFB_NEW_REQUEST;
+		mdp3_bufq_deinit(&mdp3_session->bufq_in);
+	}
 	mutex_unlock(&mdp3_session->lock);
-	if (mdp3_session->overlay.id != MSMFB_NEW_REQUEST)
-		mdp3_overlay_unset(mfd, mdp3_session->overlay.id);
 	return 0;
 }
 
@@ -759,10 +757,8 @@
 	if (vsync_client.handler)
 		mdp3_dma->vsync_enable(mdp3_dma, &vsync_client);
 
-	if (mfd->fbi->screen_base)
-		rc = mdp3_dma->start(mdp3_dma, mdp3_session->intf);
-	else
-		mdp3_session->first_commit = true;
+	mdp3_session->first_commit = true;
+	mdp3_session->in_splash_screen = 0;
 
 reset_error:
 	mutex_unlock(&mdp3_session->lock);
@@ -798,16 +794,16 @@
 	if (panel && panel->set_backlight)
 		panel->set_backlight(panel, 0);
 
-	rc = mdp3_dma->stop(mdp3_dma, mdp3_session->intf);
-	if (rc) {
-		pr_err("fail to stop the MDP3 dma\n");
-		goto reset_error;
-	}
-
 	rc = panel->event_handler(panel, MDSS_EVENT_PANEL_OFF, NULL);
 	if (rc)
 		pr_err("fail to turn off panel\n");
 
+	rc = mdp3_dma->stop(mdp3_dma, mdp3_session->intf);
+	if (rc) {
+		pr_err("fail to stop the MDP3 dma %d\n", rc);
+		goto reset_error;
+	}
+
 	rc = mdp3_put_mdp_dsi_clk();
 	if (rc) {
 		pr_err("fail to release mdp clocks\n");
@@ -850,10 +846,8 @@
 	if (vsync_client.handler)
 		mdp3_dma->vsync_enable(mdp3_dma, &vsync_client);
 
-	if (mfd->fbi->screen_base)
-		rc = mdp3_dma->start(mdp3_dma, mdp3_session->intf);
-	else
-		mdp3_session->first_commit = true;
+	mdp3_session->first_commit = true;
+	mdp3_session->in_splash_screen = 0;
 
 reset_error:
 	mutex_unlock(&mdp3_session->lock);
@@ -883,14 +877,15 @@
 {
 	int rc = 0;
 	struct mdp3_session_data *mdp3_session = mfd->mdp.private1;
-	struct fb_var_screeninfo *var;
+	struct mdp3_dma *dma = mdp3_session->dma;
 	struct fb_fix_screeninfo *fix;
 	struct fb_info *fbi = mfd->fbi;
 	int stride;
+	int format;
 
 	fix = &fbi->fix;
-	var = &fbi->var;
-	stride = req->src.width * var->bits_per_pixel/8;
+	stride = req->src.width * ppp_bpp(req->src.format);
+	format = mdp3_ctrl_get_source_format(req->src.format);
 
 	mutex_lock(&mdp3_session->lock);
 
@@ -899,9 +894,14 @@
 
 	mdp3_session->overlay = *req;
 	if (req->id == MSMFB_NEW_REQUEST) {
-		if (fix->line_length != stride)
-			mdp3_session->dma->config_stride(
-						mdp3_session->dma, stride);
+		if (dma->source_config.stride != stride ||
+				dma->source_config.format != format) {
+			dma->source_config.format = format;
+			dma->source_config.stride = stride;
+			dma->output_config.pack_pattern =
+				mdp3_ctrl_get_pack_pattern(req->src.format);
+			dma->update_src_cfg = true;
+		}
 		mdp3_session->overlay.id = 1;
 		req->id = 1;
 	}
@@ -917,13 +917,13 @@
 	struct mdp3_session_data *mdp3_session = mfd->mdp.private1;
 	struct fb_info *fbi = mfd->fbi;
 	struct fb_fix_screeninfo *fix;
+	int format;
 
 	fix = &fbi->fix;
+	format = mdp3_ctrl_get_source_format(mfd->fb_imgType);
 	mutex_lock(&mdp3_session->lock);
 
 	if (mdp3_session->overlay.id == ndx && ndx == 1) {
-		mdp3_session->dma->config_stride(mdp3_session->dma,
-							fix->line_length);
 		mdp3_session->overlay.id = MSMFB_NEW_REQUEST;
 		mdp3_bufq_deinit(&mdp3_session->bufq_in);
 	} else {
@@ -1002,12 +1002,15 @@
 	}
 
 	panel = mdp3_session->panel;
-	if (!mdp3_iommu_is_attached(MDP3_CLIENT_DMA_P)) {
+	if (mdp3_session->in_splash_screen) {
 		pr_debug("continuous splash screen, IOMMU not attached\n");
-		mdp3_ctrl_reset(mfd);
+		rc = mdp3_ctrl_reset(mfd);
+		if (rc) {
+			pr_err("fail to reset display\n");
+			return -EINVAL;
+		}
 		reset_done = true;
 	}
-	mdp3_release_splash_memory();
 
 	mutex_lock(&mdp3_session->lock);
 
@@ -1036,12 +1039,14 @@
 					MDP_NOTIFY_FRAME_DONE);
 			}
 		}
-
+		mdp3_session->dma_active = 1;
+		init_completion(&mdp3_session->dma_completion);
 		mdp3_ctrl_notify(mdp3_session, MDP_NOTIFY_FRAME_FLUSHED);
 		mdp3_bufq_push(&mdp3_session->bufq_out, data);
 	}
 
 	if (mdp3_bufq_count(&mdp3_session->bufq_out) > 1) {
+		mdp3_release_splash_memory(mfd);
 		data = mdp3_bufq_pop(&mdp3_session->bufq_out);
 		mdp3_put_img(data, MDP3_CLIENT_DMA_P);
 	}
@@ -1080,11 +1085,14 @@
 	if (!mdp3_session || !mdp3_session->dma)
 		return;
 
-	if (!mdp3_iommu_is_attached(MDP3_CLIENT_DMA_P)) {
+	if (mdp3_session->in_splash_screen) {
 		pr_debug("continuous splash screen, IOMMU not attached\n");
-		mdp3_ctrl_reset(mfd);
+		rc = mdp3_ctrl_reset(mfd);
+		if (rc) {
+			pr_err("fail to reset display\n");
+			return;
+		}
 	}
-	mdp3_release_splash_memory();
 
 	mutex_lock(&mdp3_session->lock);
 
@@ -1123,6 +1131,8 @@
 					MDP_NOTIFY_FRAME_DONE);
 			}
 		}
+		mdp3_session->dma_active = 1;
+		init_completion(&mdp3_session->dma_completion);
 		mdp3_ctrl_notify(mdp3_session, MDP_NOTIFY_FRAME_FLUSHED);
 	} else {
 		pr_debug("mdp3_ctrl_pan_display no memory, stop interface");
@@ -1269,7 +1279,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");
@@ -1295,7 +1305,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;
 }
@@ -1599,6 +1609,47 @@
 	return rc;
 }
 
+static int mdp3_overlay_prepare(struct msm_fb_data_type *mfd,
+		struct mdp_overlay_list __user *user_ovlist)
+{
+	struct mdp_overlay_list ovlist;
+	struct mdp3_session_data *mdp3_session = mfd->mdp.private1;
+	struct mdp_overlay *req_list;
+	struct mdp_overlay *req;
+	int rc;
+
+	if (!mdp3_session)
+		return -ENODEV;
+
+	req = &mdp3_session->req_overlay;
+
+	if (copy_from_user(&ovlist, user_ovlist, sizeof(ovlist)))
+		return -EFAULT;
+
+	if (ovlist.num_overlays != 1) {
+		pr_err("OV_PREPARE failed: only 1 overlay allowed\n");
+		return -EINVAL;
+	}
+
+	if (copy_from_user(&req_list, ovlist.overlay_list, sizeof(struct mdp_overlay*)))
+		return -EFAULT;
+
+	if (copy_from_user(req, req_list, sizeof(*req)))
+		return -EFAULT;
+
+	rc = mdp3_overlay_set(mfd, req);
+	if (!IS_ERR_VALUE(rc)) {
+		if (copy_to_user(req_list, req, sizeof(*req)))
+			return -EFAULT;
+	}
+
+	if (put_user(IS_ERR_VALUE(rc) ? 0 : 1,
+			&user_ovlist->processed_overlays))
+		return -EFAULT;
+
+	return rc;
+}
+
 static int mdp3_ctrl_ioctl_handler(struct msm_fb_data_type *mfd,
 					u32 cmd, void __user *argp)
 {
@@ -1615,7 +1666,8 @@
 
 	req = &mdp3_session->req_overlay;
 
-	if (!mdp3_session->status && cmd != MSMFB_METADATA_GET) {
+	if (!mdp3_session->status && cmd != MSMFB_METADATA_GET &&
+		cmd != MSMFB_HISTOGRAM_STOP) {
 		pr_err("mdp3_ctrl_ioctl_handler, display off!\n");
 		return -EPERM;
 	}
@@ -1697,12 +1749,32 @@
 		if (rc)
 			pr_err("OVERLAY_PLAY failed (%d)\n", rc);
 		break;
+	case MSMFB_OVERLAY_PREPARE:
+		rc = mdp3_overlay_prepare(mfd, argp);
+		break;
 	default:
 		break;
 	}
 	return rc;
 }
 
+int mdp3_wait_for_dma_done(struct mdp3_session_data *session)
+{
+	int rc = 0;
+
+	if (session->dma_active) {
+		rc = wait_for_completion_timeout(&session->dma_completion,
+			KOFF_TIMEOUT);
+		if (rc > 0) {
+			session->dma_active = 0;
+			rc = 0;
+		} else if (rc == 0) {
+			rc = -ETIME;
+		}
+	}
+	return rc;
+}
+
 int mdp3_ctrl_init(struct msm_fb_data_type *mfd)
 {
 	struct device *dev = mfd->fbi->dev;
@@ -1777,6 +1849,9 @@
 	mdp3_session->vsync_timer.data = (u32)mdp3_session;
 	mdp3_session->vsync_period = 1000 / mfd->panel_info->mipi.frame_rate;
 	mfd->mdp.private1 = mdp3_session;
+	init_completion(&mdp3_session->dma_completion);
+	if (intf_type != MDP3_DMA_OUTPUT_SEL_DSI_VIDEO)
+		mdp3_session->wait_for_dma_done = mdp3_wait_for_dma_done;
 
 	rc = sysfs_create_group(&dev->kobj, &vsync_fs_attr_group);
 	if (rc) {
@@ -1801,6 +1876,7 @@
 
 	if (mdp3_get_cont_spash_en()) {
 		mdp3_session->clk_on = 1;
+		mdp3_session->in_splash_screen = 1;
 		mdp3_ctrl_notifier_register(mdp3_session,
 			&mdp3_session->mfd->mdp_sync_pt_data.notifier);
 	}
diff --git a/drivers/video/msm/mdss/mdp3_ctrl.h b/drivers/video/msm/mdss/mdp3_ctrl.h
index cfad1d3..93356e2 100644
--- a/drivers/video/msm/mdss/mdp3_ctrl.h
+++ b/drivers/video/msm/mdss/mdp3_ctrl.h
@@ -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
@@ -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;
@@ -61,6 +62,11 @@
 
 	int vsync_enabled;
 	atomic_t vsync_countdown; /* Used to count down  */
+	bool in_splash_screen;
+
+	bool dma_active;
+	struct completion dma_completion;
+	int (*wait_for_dma_done)(struct mdp3_session_data *session);
 };
 
 int mdp3_ctrl_init(struct msm_fb_data_type *mfd);
diff --git a/drivers/video/msm/mdss/mdp3_dma.c b/drivers/video/msm/mdss/mdp3_dma.c
index 5cae2de..2dd66f8 100644
--- a/drivers/video/msm/mdss/mdp3_dma.c
+++ b/drivers/video/msm/mdss/mdp3_dma.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
@@ -18,12 +18,17 @@
 #include "mdp3_hwio.h"
 
 #define DMA_STOP_POLL_SLEEP_US 1000
-#define DMA_STOP_POLL_TIMEOUT_US 32000
+#define DMA_STOP_POLL_TIMEOUT_US 200000
 #define DMA_HISTO_RESET_TIMEOUT_MS 40
 #define DMA_LUT_CONFIG_MASK 0xfffffbe8
 #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,52 +271,51 @@
 	}
 }
 
-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;
 }
 
-static void mdp3_dma_stride_config(struct mdp3_dma *dma, int stride)
-{
-	struct mdp3_dma_source *source_config;
-	u32 dma_stride_offset;
-
-	if (dma->dma_sel == MDP3_DMA_P)
-		dma_stride_offset = MDP3_REG_DMA_P_IBUF_Y_STRIDE;
-	else
-		dma_stride_offset = MDP3_REG_DMA_S_IBUF_Y_STRIDE;
-
-	source_config = &dma->source_config;
-	source_config->stride = stride;
-	pr_debug("%s: Update the fb stride for DMA to %d", __func__,
-						(u32)source_config->stride);
-	MDP3_REG_WRITE(dma_stride_offset, source_config->stride);
-}
-
 static int mdp3_dmap_config(struct mdp3_dma *dma,
 			struct mdp3_dma_source *source_config,
 			struct mdp3_dma_output_config *output_config)
@@ -341,13 +345,29 @@
 
 	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;
 }
 
+static void mdp3_dmap_config_source(struct mdp3_dma *dma)
+{
+	struct mdp3_dma_source *source_config = &dma->source_config;
+	u32 dma_p_cfg_reg, dma_p_size;
+
+	dma_p_cfg_reg = MDP3_REG_READ(MDP3_REG_DMA_P_CONFIG);
+	dma_p_cfg_reg &= ~MDP3_DMA_IBUF_FORMAT_MASK;
+	dma_p_cfg_reg |= source_config->format << 25;
+	dma_p_cfg_reg &= ~MDP3_DMA_PACK_PATTERN_MASK;
+	dma_p_cfg_reg |= dma->output_config.pack_pattern << 8;
+
+	dma_p_size = source_config->width | (source_config->height << 16);
+
+	MDP3_REG_WRITE(MDP3_REG_DMA_P_CONFIG, dma_p_cfg_reg);
+	MDP3_REG_WRITE(MDP3_REG_DMA_P_SIZE, dma_p_size);
+	MDP3_REG_WRITE(MDP3_REG_DMA_P_IBUF_Y_STRIDE, source_config->stride);
+}
+
 static int mdp3_dmas_config(struct mdp3_dma *dma,
 			struct mdp3_dma_source *source_config,
 			struct mdp3_dma_output_config *output_config)
@@ -377,12 +397,27 @@
 
 	dma->source_config = *source_config;
 	dma->output_config = *output_config;
-	mdp3_dma_sync_config(dma, source_config);
 
 	mdp3_dma_callback_setup(dma);
 	return 0;
 }
 
+static void mdp3_dmas_config_source(struct mdp3_dma *dma)
+{
+	struct mdp3_dma_source *source_config = &dma->source_config;
+	u32 dma_s_cfg_reg, dma_s_size;
+
+	dma_s_cfg_reg = MDP3_REG_READ(MDP3_REG_DMA_S_CONFIG);
+	dma_s_cfg_reg &= ~MDP3_DMA_IBUF_FORMAT_MASK;
+	dma_s_cfg_reg |= source_config->format << 25;
+
+	dma_s_size = source_config->width | (source_config->height << 16);
+
+	MDP3_REG_WRITE(MDP3_REG_DMA_S_CONFIG, dma_s_cfg_reg);
+	MDP3_REG_WRITE(MDP3_REG_DMA_S_SIZE, dma_s_size);
+	MDP3_REG_WRITE(MDP3_REG_DMA_S_IBUF_Y_STRIDE, source_config->stride);
+}
+
 static int mdp3_dmap_cursor_config(struct mdp3_dma *dma,
 				struct mdp3_dma_cursor *cursor)
 {
@@ -588,6 +623,13 @@
 			}
 		}
 	}
+	if (dma->update_src_cfg) {
+		if (dma->output_config.out_sel ==
+				 MDP3_DMA_OUTPUT_SEL_DSI_VIDEO && intf->active)
+			pr_err("configuring dma source while dma is active\n");
+		dma->dma_config_source(dma);
+		dma->update_src_cfg = false;
+	}
 	spin_lock_irqsave(&dma->dma_lock, flag);
 	MDP3_REG_WRITE(MDP3_REG_DMA_P_IBUF_ADDR, (u32)buf);
 	dma->source_config.buf = buf;
@@ -901,6 +943,8 @@
 	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;
 		dma->config_histo = mdp3_dmap_histo_config;
@@ -913,10 +957,11 @@
 		dma->dma_done_notifier = mdp3_dma_done_notifier;
 		dma->start = mdp3_dma_start;
 		dma->stop = mdp3_dma_stop;
-		dma->config_stride = mdp3_dma_stride_config;
 		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;
 		dma->config_histo = NULL;
@@ -928,7 +973,6 @@
 		dma->vsync_enable = mdp3_dma_vsync_enable;
 		dma->start = mdp3_dma_start;
 		dma->stop = mdp3_dma_stop;
-		dma->config_stride = mdp3_dma_stride_config;
 		break;
 	case MDP3_DMA_E:
 	default:
@@ -944,6 +988,7 @@
 	dma->vsync_client.handler = NULL;
 	dma->vsync_client.arg = NULL;
 	dma->histo_state = MDP3_DMA_HISTO_STATE_IDLE;
+	dma->update_src_cfg = false;
 
 	memset(&dma->cursor, 0, sizeof(dma->cursor));
 	memset(&dma->ccs_config, 0, sizeof(dma->ccs_config));
@@ -1035,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 04955d4..d07e06d 100644
--- a/drivers/video/msm/mdss/mdp3_dma.h
+++ b/drivers/video/msm/mdss/mdp3_dma.h
@@ -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
@@ -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 {
@@ -259,11 +272,17 @@
 	int histo_state;
 	struct mdp3_dma_histogram_data histo_data;
 	unsigned int vsync_status;
+	bool update_src_cfg;
 
 	int (*dma_config)(struct mdp3_dma *dma,
 			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);
 
 	int (*stop)(struct mdp3_dma *dma, struct mdp3_intf *intf);
@@ -290,8 +309,6 @@
 
 	int (*histo_op)(struct mdp3_dma *dma, u32 op);
 
-	void (*config_stride)(struct mdp3_dma *dma, int stride);
-
 	void (*vsync_enable)(struct mdp3_dma *dma,
 			struct mdp3_notification *vsync_client);
 
@@ -318,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_hwio.h b/drivers/video/msm/mdss/mdp3_hwio.h
index b457c10..c40ee47 100644
--- a/drivers/video/msm/mdss/mdp3_hwio.h
+++ b/drivers/video/msm/mdss/mdp3_hwio.h
@@ -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
@@ -118,6 +118,10 @@
 #define MDP3_REG_DMA_S_IBUF_Y_STRIDE			0xA000C
 #define MDP3_REG_DMA_S_OUT_XY				0xA0010
 
+/*DMA MASK*/
+#define MDP3_DMA_IBUF_FORMAT_MASK 0x06000000
+#define MDP3_DMA_PACK_PATTERN_MASK 0x00003f00
+
 /*MISR*/
 #define MDP3_REG_MODE_CLK				0x000D0000
 #define MDP3_REG_MISR_RESET_CLK			0x000D0004
@@ -269,6 +273,8 @@
 
 #define MDP3_PPP_BLEND_BG_ALPHA_SEL	0x70010
 
+#define MDP3_PPP_ACTIVE BIT(0)
+
 /*interrupt mask*/
 
 #define MDP3_INTR_DP0_ROI_DONE_BIT			BIT(0)
diff --git a/drivers/video/msm/mdss/mdp3_ppp.c b/drivers/video/msm/mdss/mdp3_ppp.c
index d778af8..afa0b7c 100644
--- a/drivers/video/msm/mdss/mdp3_ppp.c
+++ b/drivers/video/msm/mdss/mdp3_ppp.c
@@ -83,9 +83,7 @@
 };
 
 struct ppp_status {
-	int busy;
 	bool wait_for_pop;
-	spinlock_t ppp_lock;
 	struct completion ppp_comp;
 	struct completion pop_q_comp;
 	struct mutex req_mutex; /* Protect request queue */
@@ -101,6 +99,7 @@
 	struct timer_list free_bw_timer;
 	struct work_struct free_bw_work;
 	bool bw_on;
+	bool bw_optimal;
 };
 
 static struct ppp_status *ppp_stat;
@@ -271,24 +270,16 @@
 int mdp3_ppp_pipe_wait(void)
 {
 	int ret = 1;
-	int wait;
-	unsigned long flag;
 
 	/*
-	 * wait 5 secs for operation to complete before declaring
+	 * wait 200 ms for ppp operation to complete before declaring
 	 * the MDP hung
 	 */
-	spin_lock_irqsave(&ppp_stat->ppp_lock, flag);
-	wait = ppp_stat->busy;
-	spin_unlock_irqrestore(&ppp_stat->ppp_lock, flag);
-
-	if (wait) {
-		ret = wait_for_completion_interruptible_timeout(
-		   &ppp_stat->ppp_comp, 5 * HZ);
-		if (!ret)
-			pr_err("%s: Timed out waiting for the MDP.\n",
-				__func__);
-	}
+	ret = wait_for_completion_timeout(
+	  &ppp_stat->ppp_comp, msecs_to_jiffies(200));
+	if (!ret)
+		pr_err("%s: Timed out waiting for the MDP.\n",
+			__func__);
 
 	return ret;
 }
@@ -321,11 +312,7 @@
 
 static void mdp3_ppp_intr_handler(int type, void *arg)
 {
-	spin_lock(&ppp_stat->ppp_lock);
-	ppp_stat->busy = false;
-	spin_unlock(&ppp_stat->ppp_lock);
 	complete(&ppp_stat->ppp_comp);
-	mdp3_irq_disable_nosync(type);
 }
 
 static int mdp3_ppp_callback_setup(void)
@@ -342,44 +329,71 @@
 
 void mdp3_ppp_kickoff(void)
 {
-	unsigned long flag;
-	mdp3_irq_enable(MDP3_PPP_DONE);
-
 	init_completion(&ppp_stat->ppp_comp);
-
-	spin_lock_irqsave(&ppp_stat->ppp_lock, flag);
-	ppp_stat->busy = true;
-	spin_unlock_irqrestore(&ppp_stat->ppp_lock, flag);
+	mdp3_irq_enable(MDP3_PPP_DONE);
 	ppp_enable();
-
 	mdp3_ppp_pipe_wait();
+	mdp3_irq_disable(MDP3_PPP_DONE);
+}
+
+int mdp3_ppp_vote_update(struct msm_fb_data_type *mfd)
+{
+	struct mdss_panel_info *panel_info = mfd->panel_info;
+	uint64_t req_bw = 0, ab = 0, ib = 0;
+	int rate = 0;
+	int rc = 0;
+	if (!ppp_stat->bw_on)
+		pr_err("%s: PPP vote update in wrong state\n", __func__);
+
+	rate = MDP_BLIT_CLK_RATE;
+	req_bw = panel_info->xres * panel_info->yres *
+		panel_info->mipi.frame_rate *
+		MDP_PPP_MAX_BPP *
+		MDP_PPP_DYNAMIC_FACTOR *
+		MDP_PPP_MAX_READ_WRITE;
+	ib = (req_bw * 3) / 2;
+
+	if (ppp_stat->bw_optimal)
+		ab = ib / 2;
+	else
+		ab = req_bw;
+	rc = mdp3_bus_scale_set_quota(MDP3_CLIENT_PPP, ab, ib);
+	if (rc < 0) {
+		pr_err("%s: scale_set_quota failed\n", __func__);
+		return rc;
+	}
+	return rc;
 }
 
 int mdp3_ppp_turnon(struct msm_fb_data_type *mfd, int on_off)
 {
 	struct mdss_panel_info *panel_info = mfd->panel_info;
-	uint64_t ab = 0, ib = 0;
+	uint64_t req_bw = 0, ab = 0, ib = 0;
 	int rate = 0;
 	int rc;
 
 	if (on_off) {
 		rate = MDP_BLIT_CLK_RATE;
-		ab = panel_info->xres * panel_info->yres *
+		req_bw = panel_info->xres * panel_info->yres *
 			panel_info->mipi.frame_rate *
 			MDP_PPP_MAX_BPP *
 			MDP_PPP_DYNAMIC_FACTOR *
 			MDP_PPP_MAX_READ_WRITE;
-		ib = (ab * 3) / 2;
+		ib = (req_bw * 3) / 2;
+		if (ppp_stat->bw_optimal)
+			ab = ib / 2;
+		else
+			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;
 	}
@@ -387,10 +401,21 @@
 	return 0;
 }
 
+bool mdp3_optimal_bw(int req_cnt)
+{
+	if (req_cnt == 1 && ppp_stat->req_q.count == 1)
+		return true;
+	return false;
+}
+
 void mdp3_start_ppp(struct ppp_blit_op *blit_op)
 {
 	/* Wait for the pipe to clear */
-	do { } while (mdp3_ppp_pipe_wait() <= 0);
+	if (MDP3_REG_READ(MDP3_REG_DISPLAY_STATUS) &
+			MDP3_PPP_ACTIVE) {
+		pr_err("ppp core is hung up on previous request\n");
+		return;
+	}
 	config_ppp_op_mode(blit_op);
 	if (blit_op->solid_fill) {
 		MDP3_REG_WRITE(0x10138, 0x10000000);
@@ -840,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;
 		}
@@ -1014,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);
 }
@@ -1040,15 +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;
@@ -1079,6 +1094,10 @@
 		if (ppp_stat->wait_for_pop)
 			complete(&ppp_stat->pop_q_comp);
 		mutex_unlock(&ppp_stat->req_mutex);
+		if (req && (ppp_stat->bw_optimal != mdp3_optimal_bw(req->count))) {
+			ppp_stat->bw_optimal = !ppp_stat->bw_optimal;
+			mdp3_ppp_vote_update(mfd);
+		}
 	}
 	mod_timer(&ppp_stat->free_bw_timer, jiffies +
 		msecs_to_jiffies(MDP_RELEASE_BW_TIMEOUT));
@@ -1099,7 +1118,7 @@
 	while (req_q->count >= MDP3_PPP_MAX_LIST_REQ) {
 		ppp_stat->wait_for_pop = true;
 		mutex_unlock(&ppp_stat->req_mutex);
-		rc = wait_for_completion_interruptible_timeout(
+		rc = wait_for_completion_timeout(
 		   &ppp_stat->pop_q_comp, 5 * HZ);
 		if (rc == 0) {
 			/* This will only occur if there is serious problem */
@@ -1211,13 +1230,11 @@
 	INIT_WORK(&ppp_stat->blit_work, mdp3_ppp_blit_wq_handler);
 	INIT_WORK(&ppp_stat->free_bw_work, mdp3_free_bw_wq_handler);
 	init_completion(&ppp_stat->pop_q_comp);
-	spin_lock_init(&ppp_stat->ppp_lock);
 	mutex_init(&ppp_stat->req_mutex);
 	mutex_init(&ppp_stat->config_ppp_mutex);
 	init_timer(&ppp_stat->free_bw_timer);
 	ppp_stat->free_bw_timer.function = mdp3_free_fw_timer_func;
 	ppp_stat->free_bw_timer.data = 0;
-	ppp_stat->busy = false;
 	ppp_stat->mfd = mfd;
 	mdp3_ppp_callback_setup();
 	return 0;
diff --git a/drivers/video/msm/mdss/mdp3_ppp.h b/drivers/video/msm/mdss/mdp3_ppp.h
index 9753e94..a0ad3c3 100644
--- a/drivers/video/msm/mdss/mdp3_ppp.h
+++ b/drivers/video/msm/mdss/mdp3_ppp.h
@@ -391,7 +391,7 @@
 uint32_t ppp_bpp(uint32_t type);
 uint32_t ppp_src_config(uint32_t type);
 uint32_t ppp_out_config(uint32_t type);
-uint32_t ppp_pack_pattern(uint32_t type);
+uint32_t ppp_pack_pattern(uint32_t type, uint32_t yuv2rgb);
 uint32_t ppp_dst_op_reg(uint32_t type);
 uint32_t ppp_src_op_reg(uint32_t type);
 bool ppp_per_p_alpha(uint32_t type);
diff --git a/drivers/video/msm/mdss/mdp3_ppp_data.c b/drivers/video/msm/mdss/mdp3_ppp_data.c
index e562ad3..5748842 100644
--- a/drivers/video/msm/mdss/mdp3_ppp_data.c
+++ b/drivers/video/msm/mdss/mdp3_ppp_data.c
@@ -88,6 +88,35 @@
 		CLR_G, CLR_R, 8),
 };
 
+const uint32_t swapped_pack_patt_lut[MDP_IMGTYPE_LIMIT] = {
+	[MDP_RGB_565] = PPP_GET_PACK_PATTERN(0, CLR_B, CLR_G, CLR_R, 8),
+	[MDP_BGR_565] = PPP_GET_PACK_PATTERN(0, CLR_R, CLR_G, CLR_B, 8),
+	[MDP_RGB_888] = PPP_GET_PACK_PATTERN(0, CLR_B, CLR_G, CLR_R, 8),
+	[MDP_BGR_888] = PPP_GET_PACK_PATTERN(0, CLR_R, CLR_G, CLR_B, 8),
+	[MDP_BGRA_8888] = PPP_GET_PACK_PATTERN(CLR_ALPHA, CLR_R,
+		CLR_G, CLR_B, 8),
+	[MDP_RGBA_8888] = PPP_GET_PACK_PATTERN(CLR_ALPHA, CLR_B,
+		CLR_G, CLR_R, 8),
+	[MDP_ARGB_8888] = PPP_GET_PACK_PATTERN(CLR_ALPHA, CLR_B,
+		CLR_G, CLR_R, 8),
+	[MDP_XRGB_8888] = PPP_GET_PACK_PATTERN(CLR_ALPHA, CLR_B,
+		CLR_G, CLR_R, 8),
+	[MDP_RGBX_8888] = PPP_GET_PACK_PATTERN(CLR_ALPHA, CLR_B,
+		CLR_G, CLR_R, 8),
+	[MDP_Y_CRCB_H2V2] = PPP_GET_PACK_PATTERN(0, 0, CLR_CB, CLR_CR, 8),
+	[MDP_Y_CBCR_H2V2] = PPP_GET_PACK_PATTERN(0, 0, CLR_CR, CLR_CB, 8),
+	[MDP_Y_CBCR_H2V2_ADRENO] = PPP_GET_PACK_PATTERN(0, 0, CLR_CR,
+		CLR_CB, 8),
+	[MDP_Y_CBCR_H2V2_VENUS] = PPP_GET_PACK_PATTERN(0, 0, CLR_CR,
+		CLR_CB, 8),
+	[MDP_YCRYCB_H2V1] = PPP_GET_PACK_PATTERN(CLR_Y,
+		CLR_CB, CLR_Y, CLR_CR, 8),
+	[MDP_Y_CBCR_H2V1] = PPP_GET_PACK_PATTERN(0, 0, CLR_CR, CLR_CB, 8),
+	[MDP_Y_CRCB_H2V1] = PPP_GET_PACK_PATTERN(0, 0, CLR_CB, CLR_CR, 8),
+	[MDP_BGRX_8888] = PPP_GET_PACK_PATTERN(CLR_ALPHA, CLR_R,
+		CLR_G, CLR_B, 8),
+};
+
 const uint32_t dst_op_reg[MDP_IMGTYPE_LIMIT] = {
 	[MDP_Y_CRCB_H2V2] = PPP_OP_DST_CHROMA_420,
 	[MDP_Y_CBCR_H2V2] = PPP_OP_DST_CHROMA_420,
@@ -1530,10 +1559,13 @@
 	return out_cfg_lut[type];
 }
 
-uint32_t ppp_pack_pattern(uint32_t type)
+uint32_t ppp_pack_pattern(uint32_t type, uint32_t yuv2rgb)
 {
 	if (MDP_IS_IMGTYPE_BAD(type))
 		return 0;
+	if (yuv2rgb)
+		return swapped_pack_patt_lut[type];
+
 	return pack_patt_lut[type];
 }
 
diff --git a/drivers/video/msm/mdss/mdp3_ppp_hwio.c b/drivers/video/msm/mdss/mdp3_ppp_hwio.c
index eb01d00..a25c2c7 100644
--- a/drivers/video/msm/mdss/mdp3_ppp_hwio.c
+++ b/drivers/video/msm/mdss/mdp3_ppp_hwio.c
@@ -486,7 +486,7 @@
 	return load_secondary_matrix(csc);
 }
 
-int config_ppp_src(struct ppp_img_desc *src)
+int config_ppp_src(struct ppp_img_desc *src, uint32_t yuv2rgb)
 {
 	uint32_t val;
 
@@ -510,12 +510,12 @@
 	val |= (src->roi.x % 2) ? PPP_SRC_BPP_ROI_ODD_X : 0;
 	val |= (src->roi.y % 2) ? PPP_SRC_BPP_ROI_ODD_Y : 0;
 	PPP_WRITEL(val, MDP3_PPP_SRC_FORMAT);
-	PPP_WRITEL(ppp_pack_pattern(src->color_fmt),
+	PPP_WRITEL(ppp_pack_pattern(src->color_fmt, yuv2rgb),
 		MDP3_PPP_SRC_UNPACK_PATTERN1);
 	return 0;
 }
 
-int config_ppp_out(struct ppp_img_desc *dst)
+int config_ppp_out(struct ppp_img_desc *dst, uint32_t yuv2rgb)
 {
 	uint32_t val;
 	bool pseudoplanr_output = false;
@@ -534,7 +534,7 @@
 	if (pseudoplanr_output)
 		val |= PPP_DST_PLANE_PSEUDOPLN;
 	PPP_WRITEL(val, MDP3_PPP_OUT_FORMAT);
-	PPP_WRITEL(ppp_pack_pattern(dst->color_fmt),
+	PPP_WRITEL(ppp_pack_pattern(dst->color_fmt, yuv2rgb),
 		MDP3_PPP_OUT_PACK_PATTERN1);
 
 	val = ((dst->roi.height & MDP3_PPP_XY_MASK) << MDP3_PPP_XY_OFFSET) |
@@ -573,7 +573,7 @@
 
 	PPP_WRITEL(ppp_src_config(bg->color_fmt),
 		MDP3_PPP_BG_FORMAT);
-	PPP_WRITEL(ppp_pack_pattern(bg->color_fmt),
+	PPP_WRITEL(ppp_pack_pattern(bg->color_fmt, 0),
 		MDP3_PPP_BG_UNPACK_PATTERN1);
 	return 0;
 }
@@ -1108,6 +1108,7 @@
 
 int config_ppp_op_mode(struct ppp_blit_op *blit_op)
 {
+	uint32_t yuv2rgb;
 	uint32_t ppp_operation_reg = 0;
 	int sv_slice, sh_slice;
 	int dv_slice, dh_slice;
@@ -1153,6 +1154,7 @@
 
 	config_ppp_csc(blit_op->src.color_fmt,
 		blit_op->dst.color_fmt, &ppp_operation_reg);
+	yuv2rgb = ppp_operation_reg & PPP_OP_CONVERT_YCBCR2RGB;
 
 	if (blit_op->mdp_op & MDPOP_DITHER)
 		ppp_operation_reg |= PPP_OP_DITHER_EN;
@@ -1197,8 +1199,8 @@
 
 	config_ppp_blend(blit_op, &ppp_operation_reg);
 
-	config_ppp_src(&blit_op->src);
-	config_ppp_out(&blit_op->dst);
+	config_ppp_src(&blit_op->src, yuv2rgb);
+	config_ppp_out(&blit_op->dst, yuv2rgb);
 	PPP_WRITEL(ppp_operation_reg, MDP3_PPP_OP_MODE);
 	mb();
 	return 0;
diff --git a/drivers/video/msm/mdss/mdss.h b/drivers/video/msm/mdss/mdss.h
index ce4005e..72cceaa 100644
--- a/drivers/video/msm/mdss/mdss.h
+++ b/drivers/video/msm/mdss/mdss.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
@@ -79,6 +79,21 @@
 	spinlock_t lock;
 };
 
+struct mdss_fudge_factor {
+	u32 numer;
+	u32 denom;
+};
+
+struct mdss_prefill_data {
+	u32 ot_bytes;
+	u32 y_buf_bytes;
+	u32 y_scaler_lines_bilinear;
+	u32 y_scaler_lines_caf;
+	u32 post_scaler_pixels;
+	u32 pp_pixels;
+	u32 fbc_lines;
+};
+
 struct mdss_data_type {
 	u32 mdp_rev;
 	struct clk *mdp_clk[MDSS_MAX_CLK];
@@ -93,6 +108,8 @@
 	size_t mdp_reg_size;
 	char __iomem *vbif_base;
 
+	struct mutex reg_lock;
+
 	u32 irq;
 	u32 irq_mask;
 	u32 irq_ena;
@@ -100,8 +117,10 @@
 	u32 has_bwc;
 	u32 has_decimation;
 	u8 has_wfd_blk;
+	u32 has_no_lut_read;
 	u8 has_wb_ad;
 
+	u32 rotator_ot_limit;
 	u32 mdp_irq_mask;
 	u32 mdp_hist_irq_mask;
 
@@ -112,8 +131,8 @@
 	unsigned long min_mdp_clk;
 
 	u32 res_init;
-	u32 bus_hdl;
 
+	u32 highest_bank_bit;
 	u32 smp_mb_cnt;
 	u32 smp_mb_size;
 	u32 smp_mb_per_pipe;
@@ -123,6 +142,19 @@
 	u32 max_bw_low;
 	u32 max_bw_high;
 
+	u32 axi_port_cnt;
+	u32 curr_bw_uc_idx;
+	u32 bus_hdl;
+	struct msm_bus_scale_pdata *bus_scale_table;
+
+	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;
@@ -160,9 +192,12 @@
 
 	struct early_suspend early_suspend;
 	struct mdss_debug_inf debug_inf;
-	int current_bus_idx;
 	bool mixer_switched;
 	struct mdss_panel_cfg pan_cfg;
+
+	int handoff_pending;
+	struct mdss_prefill_data prefill_data;
+	bool ulps;
 };
 extern struct mdss_data_type *mdss_res;
 
diff --git a/drivers/video/msm/mdss/mdss_debug.c b/drivers/video/msm/mdss/mdss_debug.c
index 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 54c8a06..dd8eec5 100644
--- a/drivers/video/msm/mdss/mdss_dsi.c
+++ b/drivers/video/msm/mdss/mdss_dsi.c
@@ -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
@@ -27,8 +27,6 @@
 #include "mdss_dsi.h"
 #include "mdss_debug.h"
 
-static unsigned char *mdss_dsi_base;
-
 static int mdss_dsi_regulator_init(struct platform_device *pdev)
 {
 	struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
@@ -74,13 +72,25 @@
 			goto error;
 		}
 
-		if (pdata->panel_info.panel_power_on == 0)
-			mdss_dsi_panel_reset(pdata, 1);
-
+		if (!pdata->panel_info.mipi.lp11_init) {
+			ret = mdss_dsi_panel_reset(pdata, 1);
+			if (ret) {
+				pr_err("%s: Panel reset failed. rc=%d\n",
+						__func__, ret);
+				if (msm_dss_enable_vreg(
+				ctrl_pdata->power_data.vreg_config,
+				ctrl_pdata->power_data.num_vreg, 0))
+					pr_err("Disable vregs failed\n");
+				goto error;
+			}
+		}
 	} else {
-
-		mdss_dsi_panel_reset(pdata, 0);
-
+		ret = mdss_dsi_panel_reset(pdata, 0);
+		if (ret) {
+			pr_err("%s: Panel reset failed. rc=%d\n",
+					__func__, ret);
+			goto error;
+		}
 		ret = msm_dss_enable_vreg(
 			ctrl_pdata->power_data.vreg_config,
 			ctrl_pdata->power_data.num_vreg, 0);
@@ -298,7 +308,7 @@
 
 	if (!pdata->panel_info.panel_power_on) {
 		pr_warn("%s:%d Panel already off.\n", __func__, __LINE__);
-		return -EPERM;
+		return 0;
 	}
 
 	pdata->panel_info.panel_power_on = 0;
@@ -311,25 +321,15 @@
 				ctrl_pdata, ctrl_pdata->ndx);
 
 	if (pdata->panel_info.type == MIPI_CMD_PANEL)
-		mdss_dsi_clk_ctrl(ctrl_pdata, 1);
+		mdss_dsi_clk_ctrl(ctrl_pdata, DSI_ALL_CLKS, 1);
 
 	/* disable DSI controller */
 	mdss_dsi_controller_cfg(0, pdata);
 
-	mdss_dsi_clk_ctrl(ctrl_pdata, 0);
-
-	ret = mdss_dsi_enable_bus_clocks(ctrl_pdata);
-	if (ret) {
-		pr_err("%s: failed to enable bus clocks. rc=%d\n", __func__,
-			ret);
-		mdss_dsi_panel_power_on(pdata, 0);
-		return ret;
-	}
-
 	/* disable DSI phy */
-	mdss_dsi_phy_enable(ctrl_pdata, 0);
+	mdss_dsi_phy_disable(ctrl_pdata);
 
-	mdss_dsi_disable_bus_clocks(ctrl_pdata);
+	mdss_dsi_clk_ctrl(ctrl_pdata, DSI_ALL_CLKS, 0);
 
 	ret = mdss_dsi_panel_power_on(pdata, 0);
 	if (ret) {
@@ -347,63 +347,22 @@
 	return ret;
 }
 
-int mdss_dsi_on(struct mdss_panel_data *pdata)
+static void __mdss_dsi_ctrl_setup(struct mdss_panel_data *pdata)
 {
-	int ret = 0;
-	u32 clk_rate;
+	struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
 	struct mdss_panel_info *pinfo;
 	struct mipi_panel_info *mipi;
+	u32 clk_rate;
 	u32 hbp, hfp, vbp, vfp, hspw, vspw, width, height;
 	u32 ystride, bpp, data, dst_bpp;
 	u32 dummy_xres, dummy_yres;
-	struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
 	u32 hsync_period, vsync_period;
 
-	if (pdata == NULL) {
-		pr_err("%s: Invalid input data\n", __func__);
-		return -EINVAL;
-	}
-
-	if (pdata->panel_info.panel_power_on) {
-		pr_warn("%s:%d Panel already on.\n", __func__, __LINE__);
-		return 0;
-	}
-
 	ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
 				panel_data);
 
-	pr_debug("%s+: ctrl=%p ndx=%d\n",
-				__func__, ctrl_pdata, ctrl_pdata->ndx);
-
 	pinfo = &pdata->panel_info;
 
-	ret = msm_dss_enable_vreg(ctrl_pdata->power_data.vreg_config,
-				ctrl_pdata->power_data.num_vreg, 1);
-	if (ret) {
-		pr_err("%s:Failed to enable vregs. rc=%d\n", __func__, ret);
-		return ret;
-	}
-
-	pdata->panel_info.panel_power_on = 1;
-
-	if (!pdata->panel_info.mipi.lp11_init)
-		mdss_dsi_panel_reset(pdata, 1);
-
-	ret = mdss_dsi_enable_bus_clocks(ctrl_pdata);
-	if (ret) {
-		pr_err("%s: failed to enable bus clocks. rc=%d\n", __func__,
-			ret);
-		mdss_dsi_panel_power_on(pdata, 0);
-		pdata->panel_info.panel_power_on = 0;
-		return ret;
-	}
-
-	mdss_dsi_phy_sw_reset((ctrl_pdata->ctrl_base));
-	mdss_dsi_phy_init(pdata);
-	mdss_dsi_disable_bus_clocks(ctrl_pdata);
-
-	mdss_dsi_clk_ctrl(ctrl_pdata, 1);
-
 	clk_rate = pdata->panel_info.clk_rate;
 	clk_rate = min(clk_rate, pdata->panel_info.clk_max);
 
@@ -433,7 +392,7 @@
 	vsync_period = vspw + vbp + height + dummy_yres + vfp;
 	hsync_period = hspw + hbp + width + dummy_xres + hfp;
 
-	mipi  = &pdata->panel_info.mipi;
+	mipi = &pdata->panel_info.mipi;
 	if (pdata->panel_info.type == MIPI_VIDEO_PANEL) {
 		MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x24,
 			((hspw + hbp + width + dummy_xres) << 16 |
@@ -471,19 +430,265 @@
 		MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x64, data);
 		MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x5C, data);
 	}
+}
 
+static inline bool __mdss_dsi_ulps_feature_enabled(
+	struct mdss_panel_data *pdata)
+{
+	return pdata->panel_info.ulps_feature_enabled;
+}
+
+static int mdss_dsi_ulps_config_sub(struct mdss_dsi_ctrl_pdata *ctrl_pdata,
+	int enable)
+{
+	int ret = 0;
+	struct mdss_panel_data *pdata = NULL;
+	struct mipi_panel_info *pinfo = NULL;
+	u32 lane_status = 0;
+	u32 active_lanes = 0;
+
+	if (!ctrl_pdata) {
+		pr_err("%s: invalid input\n", __func__);
+		return -EINVAL;
+	}
+
+	pdata = &ctrl_pdata->panel_data;
+	if (!pdata) {
+		pr_err("%s: Invalid panel data\n", __func__);
+		return -EINVAL;
+	}
+	pinfo = &pdata->panel_info.mipi;
+
+	if (!__mdss_dsi_ulps_feature_enabled(pdata)) {
+		pr_debug("%s: ULPS feature not supported. enable=%d\n",
+			__func__, enable);
+		return -ENOTSUPP;
+	}
+
+	if (enable && !ctrl_pdata->ulps) {
+		/* No need to configure ULPS mode when entering suspend state */
+		if (!pdata->panel_info.panel_power_on) {
+			pr_err("%s: panel off. returning\n", __func__);
+			goto error;
+		}
+
+		if (__mdss_dsi_clk_enabled(ctrl_pdata, DSI_LINK_CLKS)) {
+			pr_err("%s: cannot enter ulps mode if dsi clocks are on\n",
+				__func__);
+			ret = -EPERM;
+			goto error;
+		}
+
+		ret = mdss_dsi_clk_ctrl(ctrl_pdata, DSI_ALL_CLKS, 1);
+		if (ret) {
+			pr_err("%s: Failed to enable clocks. rc=%d\n",
+				__func__, ret);
+			goto error;
+		}
+
+		/*
+		 * ULPS Entry Request.
+		 * Wait for a short duration to ensure that the lanes
+		 * enter ULP state.
+		 */
+		MIPI_OUTP(ctrl_pdata->ctrl_base + 0x0AC, 0x01F);
+		usleep(100);
+
+		/* Check to make sure that all active data lanes are in ULPS */
+		if (pinfo->data_lane3)
+			active_lanes |= BIT(11);
+		if (pinfo->data_lane2)
+			active_lanes |= BIT(10);
+		if (pinfo->data_lane1)
+			active_lanes |= BIT(9);
+		if (pinfo->data_lane0)
+			active_lanes |= BIT(8);
+		active_lanes |= BIT(12); /* clock lane */
+		lane_status = MIPI_INP(ctrl_pdata->ctrl_base + 0xA8);
+		if (lane_status & active_lanes) {
+			pr_err("%s: ULPS entry req failed. Lane status=0x%08x\n",
+				__func__, lane_status);
+			ret = -EINVAL;
+			mdss_dsi_clk_ctrl(ctrl_pdata, DSI_ALL_CLKS, 0);
+			goto error;
+		}
+
+		/* Enable MMSS DSI Clamps */
+		MIPI_OUTP(ctrl_pdata->mmss_misc_io.base + 0x14, 0x3FF);
+		MIPI_OUTP(ctrl_pdata->mmss_misc_io.base + 0x14, 0x83FF);
+
+		wmb();
+
+		MIPI_OUTP(ctrl_pdata->mmss_misc_io.base + 0x108, 0x1);
+		/* disable DSI controller */
+		mdss_dsi_controller_cfg(0, pdata);
+
+		mdss_dsi_clk_ctrl(ctrl_pdata, DSI_ALL_CLKS, 0);
+		ctrl_pdata->ulps = true;
+	} else if (ctrl_pdata->ulps) {
+		ret = mdss_dsi_clk_ctrl(ctrl_pdata, DSI_BUS_CLKS, 1);
+		if (ret) {
+			pr_err("%s: Failed to enable bus clocks. rc=%d\n",
+				__func__, ret);
+			goto error;
+		}
+
+		MIPI_OUTP(ctrl_pdata->mmss_misc_io.base + 0x108, 0x0);
+		mdss_dsi_phy_init(pdata);
+
+		__mdss_dsi_ctrl_setup(pdata);
+		mdss_dsi_sw_reset(pdata);
+		mdss_dsi_host_init(pdata);
+		mdss_dsi_op_mode_config(pdata->panel_info.mipi.mode,
+			pdata);
+
+		/*
+		 * ULPS Entry Request. This is needed because, after power
+		 * collapse and reset, the DSI controller resets back to
+		 * idle state and not ULPS.
+		 * Wait for a short duration to ensure that the lanes
+		 * enter ULP state.
+		 */
+		MIPI_OUTP(ctrl_pdata->ctrl_base + 0x0AC, 0x01F);
+		usleep(100);
+
+		/* Disable MMSS DSI Clamps */
+		MIPI_OUTP(ctrl_pdata->mmss_misc_io.base + 0x14, 0x3FF);
+		MIPI_OUTP(ctrl_pdata->mmss_misc_io.base + 0x14, 0x0);
+
+		ret = mdss_dsi_clk_ctrl(ctrl_pdata, DSI_LINK_CLKS, 1);
+		if (ret) {
+			pr_err("%s: Failed to enable link clocks. rc=%d\n",
+				__func__, ret);
+			mdss_dsi_clk_ctrl(ctrl_pdata, DSI_BUS_CLKS, 0);
+			goto error;
+		}
+
+		/*
+		 * ULPS Exit Request
+		 * Hardware requirement is to wait for at least 1ms
+		 */
+		MIPI_OUTP(ctrl_pdata->ctrl_base + 0x0AC, 0x1F00);
+		usleep(1000);
+		MIPI_OUTP(ctrl_pdata->ctrl_base + 0x0AC, 0x0);
+
+		/*
+		 * Wait for a short duration before enabling
+		 * data transmission
+		 */
+		usleep(100);
+
+		lane_status = MIPI_INP(ctrl_pdata->ctrl_base + 0xA8);
+		mdss_dsi_clk_ctrl(ctrl_pdata, DSI_LINK_CLKS, 0);
+		mdss_dsi_clk_ctrl(ctrl_pdata, DSI_BUS_CLKS, 0);
+		ctrl_pdata->ulps = false;
+	}
+
+	pr_debug("%s: DSI lane status = 0x%08x. Ulps %s\n", __func__,
+		lane_status, enable ? "enabled" : "disabled");
+
+error:
+	return ret;
+}
+
+static int mdss_dsi_ulps_config(struct mdss_dsi_ctrl_pdata *ctrl,
+	int enable)
+{
+	int rc;
+	struct mdss_dsi_ctrl_pdata *mctrl = NULL;
+
+	if (&ctrl->mmss_misc_io == NULL) {
+		pr_err("%s: mmss_misc_io is NULL. ULPS not valid\n", __func__);
+		return -EINVAL;
+	}
+
+	if (mdss_dsi_is_slave_ctrl(ctrl)) {
+		mctrl = mdss_dsi_get_master_ctrl();
+		if (!mctrl) {
+			pr_err("%s: Unable to get master control\n", __func__);
+			return -EINVAL;
+		}
+	}
+
+	if (mctrl) {
+		pr_debug("%s: configuring ulps (%s) for master ctrl%d\n",
+			__func__, (enable ? "on" : "off"), ctrl->ndx);
+		rc = mdss_dsi_ulps_config_sub(mctrl, enable);
+		if (rc)
+			return rc;
+	}
+
+	pr_debug("%s: configuring ulps (%s) for ctrl%d\n",
+		__func__, (enable ? "on" : "off"), ctrl->ndx);
+	return mdss_dsi_ulps_config_sub(ctrl, enable);
+}
+
+int mdss_dsi_on(struct mdss_panel_data *pdata)
+{
+	int ret = 0;
+	struct mdss_panel_info *pinfo;
+	struct mipi_panel_info *mipi;
+	struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
+
+	if (pdata == NULL) {
+		pr_err("%s: Invalid input data\n", __func__);
+		return -EINVAL;
+	}
+
+	if (pdata->panel_info.panel_power_on) {
+		pr_warn("%s:%d Panel already on.\n", __func__, __LINE__);
+		return 0;
+	}
+
+	ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
+				panel_data);
+
+	pr_debug("%s+: ctrl=%p ndx=%d\n",
+				__func__, ctrl_pdata, ctrl_pdata->ndx);
+
+	pinfo = &pdata->panel_info;
+	mipi = &pdata->panel_info.mipi;
+
+	ret = mdss_dsi_panel_power_on(pdata, 1);
+	if (ret) {
+		pr_err("%s:Panel power on failed. rc=%d\n", __func__, ret);
+		return ret;
+	}
+
+	mdss_dsi_clk_ctrl(ctrl_pdata, DSI_BUS_CLKS, 1);
+	if (ret) {
+		pr_err("%s: failed to enable bus clocks. rc=%d\n", __func__,
+			ret);
+		ret = mdss_dsi_panel_power_on(pdata, 0);
+		if (ret) {
+			pr_err("%s: Panel reset failed. rc=%d\n",
+					__func__, ret);
+			return ret;
+		}
+		pdata->panel_info.panel_power_on = 0;
+		return ret;
+	}
+	pdata->panel_info.panel_power_on = 1;
+
+	mdss_dsi_phy_sw_reset((ctrl_pdata->ctrl_base));
+	mdss_dsi_phy_init(pdata);
+	mdss_dsi_clk_ctrl(ctrl_pdata, DSI_BUS_CLKS, 0);
+
+	mdss_dsi_clk_ctrl(ctrl_pdata, DSI_ALL_CLKS, 1);
+
+	__mdss_dsi_ctrl_setup(pdata);
 	mdss_dsi_sw_reset(pdata);
-	mdss_dsi_host_init(mipi, pdata);
+	mdss_dsi_host_init(pdata);
 
 	/*
 	 * Issue hardware reset line after enabling the DSI clocks and data
 	 * data lanes for LP11 init
 	 */
-	if (pdata->panel_info.mipi.lp11_init)
+	if (mipi->lp11_init)
 		mdss_dsi_panel_reset(pdata, 1);
 
-	if (pdata->panel_info.mipi.init_delay)
-		usleep(pdata->panel_info.mipi.init_delay);
+	if (mipi->init_delay)
+		usleep(mipi->init_delay);
 
 	if (mipi->force_clk_lane_hs) {
 		u32 tmp;
@@ -495,7 +700,7 @@
 	}
 
 	if (pdata->panel_info.type == MIPI_CMD_PANEL)
-		mdss_dsi_clk_ctrl(ctrl_pdata, 0);
+		mdss_dsi_clk_ctrl(ctrl_pdata, DSI_ALL_CLKS, 0);
 
 	pr_debug("%s-:\n", __func__);
 	return 0;
@@ -557,6 +762,23 @@
 				panel_data);
 	mipi = &pdata->panel_info.mipi;
 
+	if (__mdss_dsi_ulps_feature_enabled(pdata) &&
+		(ctrl_pdata->ulps)) {
+		/* Disable ULPS mode before blanking the panel */
+		ret = mdss_dsi_ulps_config(ctrl_pdata, 0);
+		if (ret) {
+			pr_err("%s: failed to exit ULPS mode. rc=%d\n",
+				__func__, ret);
+			return ret;
+		}
+	}
+
+	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) {
@@ -603,17 +825,8 @@
 		"Incorrect Ctrl state=0x%x\n", ctrl_pdata->ctrl_state);
 
 	mdss_dsi_sw_reset(pdata);
-	mdss_dsi_host_init(mipi, 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;
 }
@@ -642,33 +855,58 @@
 
 	if (new_fps !=
 		ctrl_pdata->panel_data.panel_info.mipi.frame_rate) {
-		rc = mdss_dsi_clk_div_config
-			(&ctrl_pdata->panel_data.panel_info, new_fps);
-		if (rc) {
-			pr_err("%s: unable to initialize the clk dividers\n",
-							__func__);
-			return rc;
-		}
-		ctrl_pdata->pclk_rate =
-			ctrl_pdata->panel_data.panel_info.mipi.dsi_pclk_rate;
-		ctrl_pdata->byte_clk_rate =
-			ctrl_pdata->panel_data.panel_info.clk_rate / 8;
-
 		if (pdata->panel_info.dfps_update
-				== DFPS_IMMEDIATE_CLK_UPDATE_MODE) {
-			dsi_ctrl = MIPI_INP((ctrl_pdata->ctrl_base) +
-					    0x0004);
-			ctrl_pdata->panel_data.panel_info.mipi.frame_rate =
-									new_fps;
-			dsi_ctrl &= ~0x2;
-			MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x0004,
-							dsi_ctrl);
-			mdss_dsi_controller_cfg(true, pdata);
-			mdss_dsi_clk_ctrl(ctrl_pdata, 0);
-			mdss_dsi_clk_ctrl(ctrl_pdata, 1);
-			dsi_ctrl |= 0x2;
-			MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x0004,
-							dsi_ctrl);
+			== DFPS_IMMEDIATE_PORCH_UPDATE_MODE) {
+			u32 hsync_period, vsync_period;
+			u32 new_dsi_v_total, current_dsi_v_total;
+			vsync_period =
+				mdss_panel_get_vtotal(&pdata->panel_info);
+			hsync_period =
+				mdss_panel_get_htotal(&pdata->panel_info);
+			current_dsi_v_total =
+				MIPI_INP((ctrl_pdata->ctrl_base) + 0x2C);
+			new_dsi_v_total =
+				((vsync_period - 1) << 16) | (hsync_period - 1);
+			MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x2C,
+				(current_dsi_v_total | 0x8000000));
+			if (new_dsi_v_total & 0x8000000) {
+				MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x2C,
+					new_dsi_v_total);
+			} else {
+				MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x2C,
+					(new_dsi_v_total | 0x8000000));
+				MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x2C,
+					(new_dsi_v_total & 0x7ffffff));
+			}
+			pdata->panel_info.mipi.frame_rate = new_fps;
+		} else {
+			rc = mdss_dsi_clk_div_config
+				(&ctrl_pdata->panel_data.panel_info, new_fps);
+			if (rc) {
+				pr_err("%s: unable to initialize the clk dividers\n",
+								__func__);
+				return rc;
+			}
+			ctrl_pdata->pclk_rate =
+				pdata->panel_info.mipi.dsi_pclk_rate;
+			ctrl_pdata->byte_clk_rate =
+				pdata->panel_info.clk_rate / 8;
+
+			if (pdata->panel_info.dfps_update
+					== DFPS_IMMEDIATE_CLK_UPDATE_MODE) {
+				dsi_ctrl = MIPI_INP((ctrl_pdata->ctrl_base) +
+						    0x0004);
+				pdata->panel_info.mipi.frame_rate = new_fps;
+				dsi_ctrl &= ~0x2;
+				MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x0004,
+								dsi_ctrl);
+				mdss_dsi_controller_cfg(true, pdata);
+				mdss_dsi_clk_ctrl(ctrl_pdata, DSI_ALL_CLKS, 0);
+				mdss_dsi_clk_ctrl(ctrl_pdata, DSI_ALL_CLKS, 1);
+				dsi_ctrl |= 0x2;
+				MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x0004,
+								dsi_ctrl);
+			}
 		}
 	} else {
 		pr_debug("%s: Panel is already at this FPS\n", __func__);
@@ -728,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);
@@ -752,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);
@@ -785,6 +1020,9 @@
 	case MDSS_EVENT_ENABLE_PARTIAL_UPDATE:
 		rc = mdss_dsi_ctl_partial_update(pdata);
 		break;
+	case MDSS_EVENT_DSI_ULPS_CTRL:
+		rc = mdss_dsi_ulps_config(ctrl_pdata, (int)arg);
+		break;
 	default:
 		pr_debug("%s: unhandled event=%d\n", __func__, event);
 		break;
@@ -825,35 +1063,39 @@
 static struct device_node *mdss_dsi_find_panel_of_node(
 		struct platform_device *pdev, char *panel_cfg)
 {
-	int l;
-	int ctrl_id = -1;
-	char *panel_name;
+	int len, i;
+	int ctrl_id = pdev->id - 1;
+	char panel_name[MDSS_MAX_PANEL_LEN];
+	char ctrl_id_stream[3] =  "0:";
+	char *stream = NULL, *pan = NULL;
 	struct device_node *dsi_pan_node = NULL, *mdss_node = NULL;
 
-	l = strlen(panel_cfg);
-	if (!l) {
+	len = strlen(panel_cfg);
+	if (!len) {
 		/* no panel cfg chg, parse dt */
 		pr_debug("%s:%d: no cmd line cfg present\n",
 			 __func__, __LINE__);
-		dsi_pan_node = mdss_dsi_pref_prim_panel(pdev);
+		goto end;
 	} else {
-		if (panel_cfg[0] == '0') {
-			pr_debug("%s:%d: DSI ctrl 1\n", __func__, __LINE__);
-			ctrl_id = 0;
-		} else if (panel_cfg[0] == '1') {
-			pr_debug("%s:%d: DSI ctrl 2\n", __func__, __LINE__);
-			ctrl_id = 1;
+		if (ctrl_id == 1)
+			strlcpy(ctrl_id_stream, "1:", 3);
+
+		stream = strnstr(panel_cfg, ctrl_id_stream, len);
+		if (!stream) {
+			pr_err("controller config is not present\n");
+			goto end;
 		}
-		if ((pdev->id - 1) != ctrl_id) {
-			pr_err("%s:%d:pdev_ID=[%d]\n",
-			       __func__, __LINE__, pdev->id);
-			return NULL;
+		stream += 2;
+
+		pan = strnchr(stream, strlen(stream), ':');
+		if (!pan) {
+			strlcpy(panel_name, stream, MDSS_MAX_PANEL_LEN);
+		} else {
+			for (i = 0; (stream + i) < pan; i++)
+				panel_name[i] = *(stream + i);
+			panel_name[i] = 0;
 		}
-		/*
-		 * skip first two chars '<dsi_ctrl_id>' and
-		 * ':' to get to the panel name
-		 */
-		panel_name = panel_cfg + 2;
+
 		pr_debug("%s:%d:%s:%s\n", __func__, __LINE__,
 			 panel_cfg, panel_name);
 
@@ -870,9 +1112,12 @@
 		if (!dsi_pan_node) {
 			pr_err("%s: invalid pan node, selecting prim panel\n",
 			       __func__);
-			dsi_pan_node = mdss_dsi_pref_prim_panel(pdev);
+			goto end;
 		}
+		return dsi_pan_node;
 	}
+end:
+	dsi_pan_node = mdss_dsi_pref_prim_panel(pdev);
 
 	return dsi_pan_node;
 }
@@ -884,7 +1129,6 @@
 	struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
 	struct device_node *dsi_pan_node = NULL;
 	char panel_cfg[MDSS_MAX_PANEL_LEN];
-	struct resource *mdss_dsi_mres;
 	const char *ctrl_name;
 	bool cmd_cfg_cont_splash = true;
 
@@ -934,30 +1178,13 @@
 	else
 		pdev->id = 2;
 
-	mdss_dsi_mres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!mdss_dsi_mres) {
-		pr_err("%s:%d unable to get the MDSS resources",
-		       __func__, __LINE__);
-		rc = -ENOMEM;
-		goto error_no_mem;
-	}
-
-	mdss_dsi_base = ioremap(mdss_dsi_mres->start,
-				resource_size(mdss_dsi_mres));
-	if (!mdss_dsi_base) {
-		pr_err("%s:%d unable to remap dsi resources",
-		       __func__, __LINE__);
-		rc = -ENOMEM;
-		goto error_no_mem;
-	}
-
 	rc = of_platform_populate(pdev->dev.of_node,
 				  NULL, NULL, &pdev->dev);
 	if (rc) {
 		dev_err(&pdev->dev,
 			"%s: failed to add child nodes, rc=%d\n",
 			__func__, rc);
-		goto error_ioremap;
+		goto error_no_mem;
 	}
 
 	/* Parse the regulator information */
@@ -1004,8 +1231,6 @@
 	of_node_put(dsi_pan_node);
 error_vreg:
 	mdss_dsi_put_dt_vreg_data(&pdev->dev, &ctrl_pdata->power_data);
-error_ioremap:
-	iounmap(mdss_dsi_base);
 error_no_mem:
 	devm_kfree(&pdev->dev, ctrl_pdata);
 
@@ -1028,7 +1253,9 @@
 		pr_err("%s: failed to de-init vregs\n", __func__);
 	mdss_dsi_put_dt_vreg_data(&pdev->dev, &ctrl_pdata->power_data);
 	mfd = platform_get_drvdata(pdev);
-	iounmap(mdss_dsi_base);
+	msm_dss_iounmap(&ctrl_pdata->mmss_misc_io);
+	msm_dss_iounmap(&ctrl_pdata->phy_io);
+	msm_dss_iounmap(&ctrl_pdata->ctrl_io);
 	return 0;
 }
 
@@ -1039,7 +1266,6 @@
 {
 	int rc = 0;
 	u32 index;
-	struct resource *mdss_dsi_mres;
 
 	rc = of_property_read_u32(pdev->dev.of_node, "cell-index", &index);
 	if (rc) {
@@ -1067,25 +1293,33 @@
 		return -EPERM;
 	}
 
-	mdss_dsi_mres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!mdss_dsi_mres) {
-		pr_err("%s:%d unable to get the DSI ctrl resources",
+	rc = msm_dss_ioremap_byname(pdev, &ctrl->ctrl_io, "dsi_ctrl");
+	if (rc) {
+		pr_err("%s:%d unable to remap dsi ctrl resources",
 			       __func__, __LINE__);
-		return -ENOMEM;
+		return rc;
 	}
 
-	ctrl->ctrl_base = ioremap(mdss_dsi_mres->start,
-		resource_size(mdss_dsi_mres));
-	if (!(ctrl->ctrl_base)) {
-		pr_err("%s:%d unable to remap dsi resources",
+	ctrl->ctrl_base = ctrl->ctrl_io.base;
+	ctrl->reg_size = ctrl->ctrl_io.len;
+
+	rc = msm_dss_ioremap_byname(pdev, &ctrl->phy_io, "dsi_phy");
+	if (rc) {
+		pr_err("%s:%d unable to remap dsi phy resources",
 			       __func__, __LINE__);
-		return -ENOMEM;
+		return rc;
 	}
 
-	ctrl->reg_size = resource_size(mdss_dsi_mres);
+	pr_info("%s: ctrl_base=%p ctrl_size=%x phy_base=%p phy_size=%x\n",
+		__func__, ctrl->ctrl_base, ctrl->reg_size, ctrl->phy_io.base,
+		ctrl->phy_io.len);
 
-	pr_info("%s: dsi base=%x size=%x\n",
-		__func__, (int)ctrl->ctrl_base, ctrl->reg_size);
+	rc = msm_dss_ioremap_byname(pdev, &ctrl->mmss_misc_io,
+		"mmss_misc_phys");
+	if (rc) {
+		pr_debug("%s:%d mmss_misc IO remap failed\n",
+			__func__, __LINE__);
+	}
 
 	return 0;
 }
@@ -1196,6 +1430,12 @@
 						DFPS_IMMEDIATE_CLK_UPDATE_MODE;
 				pr_debug("%s: dfps mode: Immediate clk\n",
 								__func__);
+			} else if (!strcmp(data,
+					    "dfps_immediate_porch_mode")) {
+				pinfo->dfps_update =
+					DFPS_IMMEDIATE_PORCH_UPDATE_MODE;
+				pr_debug("%s: dfps mode: Immediate porch\n",
+								__func__);
 			} else {
 				pr_debug("%s: dfps to default mode\n",
 								__func__);
@@ -1218,18 +1458,9 @@
 	ctrl_pdata->disp_en_gpio = of_get_named_gpio(ctrl_pdev->dev.of_node,
 		"qcom,platform-enable-gpio", 0);
 
-	if (!gpio_is_valid(ctrl_pdata->disp_en_gpio)) {
+	if (!gpio_is_valid(ctrl_pdata->disp_en_gpio))
 		pr_err("%s:%d, Disp_en gpio not specified\n",
 						__func__, __LINE__);
-	} else {
-		rc = gpio_request(ctrl_pdata->disp_en_gpio, "disp_enable");
-		if (rc) {
-			pr_err("request reset gpio failed, rc=%d\n",
-			       rc);
-			gpio_free(ctrl_pdata->disp_en_gpio);
-			return -ENODEV;
-		}
-	}
 
 	if (pinfo->type == MIPI_CMD_PANEL) {
 		ctrl_pdata->disp_te_gpio = of_get_named_gpio(ctrl_pdev->dev.of_node,
@@ -1246,7 +1477,6 @@
 		if (rc) {
 			pr_err("request TE gpio failed, rc=%d\n",
 			       rc);
-			gpio_free(ctrl_pdata->disp_te_gpio);
 			return -ENODEV;
 		}
 		rc = gpio_tlmm_config(GPIO_CFG(
@@ -1276,44 +1506,18 @@
 
 	ctrl_pdata->rst_gpio = of_get_named_gpio(ctrl_pdev->dev.of_node,
 			 "qcom,platform-reset-gpio", 0);
-	if (!gpio_is_valid(ctrl_pdata->rst_gpio)) {
+	if (!gpio_is_valid(ctrl_pdata->rst_gpio))
 		pr_err("%s:%d, reset gpio not specified\n",
 						__func__, __LINE__);
-	} else {
-		rc = gpio_request(ctrl_pdata->rst_gpio, "disp_rst_n");
-		if (rc) {
-			pr_err("request reset gpio failed, rc=%d\n",
-				rc);
-			gpio_free(ctrl_pdata->rst_gpio);
-			if (gpio_is_valid(ctrl_pdata->disp_en_gpio))
-				gpio_free(ctrl_pdata->disp_en_gpio);
-			return -ENODEV;
-		}
-	}
 
 	if (pinfo->mode_gpio_state != MODE_GPIO_NOT_VALID) {
 
 		ctrl_pdata->mode_gpio = of_get_named_gpio(
 					ctrl_pdev->dev.of_node,
 					"qcom,platform-mode-gpio", 0);
-		if (!gpio_is_valid(ctrl_pdata->mode_gpio)) {
+		if (!gpio_is_valid(ctrl_pdata->mode_gpio))
 			pr_info("%s:%d, mode gpio not specified\n",
 							__func__, __LINE__);
-		} else {
-			rc = gpio_request(ctrl_pdata->mode_gpio, "panel_mode");
-			if (rc) {
-				pr_err("request panel mode gpio failed,rc=%d\n",
-									rc);
-				gpio_free(ctrl_pdata->mode_gpio);
-				if (gpio_is_valid(ctrl_pdata->disp_en_gpio))
-					gpio_free(ctrl_pdata->disp_en_gpio);
-				if (gpio_is_valid(ctrl_pdata->rst_gpio))
-					gpio_free(ctrl_pdata->rst_gpio);
-				if (gpio_is_valid(ctrl_pdata->disp_te_gpio))
-					gpio_free(ctrl_pdata->disp_te_gpio);
-				return -ENODEV;
-			}
-		}
 	}
 
 	if (mdss_dsi_clk_init(ctrl_pdev, ctrl_pdata)) {
@@ -1354,7 +1558,7 @@
 			return rc;
 		}
 
-		mdss_dsi_clk_ctrl(ctrl_pdata, 1);
+		mdss_dsi_clk_ctrl(ctrl_pdata, DSI_ALL_CLKS, 1);
 		ctrl_pdata->ctrl_state |=
 			(CTRL_STATE_PANEL_INIT | CTRL_STATE_MDP_ACTIVE);
 	} else {
@@ -1364,10 +1568,6 @@
 	rc = mdss_register_panel(ctrl_pdev, &(ctrl_pdata->panel_data));
 	if (rc) {
 		pr_err("%s: unable to register MIPI DSI panel\n", __func__);
-		if (ctrl_pdata->rst_gpio)
-			gpio_free(ctrl_pdata->rst_gpio);
-		if (gpio_is_valid(ctrl_pdata->disp_en_gpio))
-			gpio_free(ctrl_pdata->disp_en_gpio);
 		return rc;
 	}
 
@@ -1422,7 +1622,6 @@
 
 static void __exit mdss_dsi_driver_cleanup(void)
 {
-	iounmap(mdss_dsi_base);
 	platform_driver_unregister(&mdss_dsi_ctrl_driver);
 }
 module_exit(mdss_dsi_driver_cleanup);
diff --git a/drivers/video/msm/mdss/mdss_dsi.h b/drivers/video/msm/mdss/mdss_dsi.h
index 855ec6c..962599d 100644
--- a/drivers/video/msm/mdss/mdss_dsi.h
+++ b/drivers/video/msm/mdss/mdss_dsi.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
@@ -151,8 +151,8 @@
 #define DSI_CMD_TERM    BIT(0)
 
 extern struct device dsi_dev;
-extern int mdss_dsi_clk_on;
 extern u32 dsi_irq;
+extern struct mdss_dsi_ctrl_pdata *ctrl_list[];
 
 struct dsiphy_pll_divider_config {
 	u32 clk_rate;
@@ -223,6 +223,14 @@
 	DSI_CTRL_MAX,
 };
 
+/* DSI controller #0 is always treated as a master in broadcast mode */
+#define DSI_CTRL_MASTER		DSI_CTRL_0
+#define DSI_CTRL_SLAVE		DSI_CTRL_1
+
+#define DSI_BUS_CLKS	BIT(0)
+#define DSI_LINK_CLKS	BIT(1)
+#define DSI_ALL_CLKS	((DSI_BUS_CLKS) | (DSI_LINK_CLKS))
+
 #define DSI_EV_PLL_UNLOCKED		0x0001
 #define DSI_EV_MDP_FIFO_UNDERFLOW	0x0002
 #define DSI_EV_MDP_BUSY_RELEASE		0x80000000
@@ -236,26 +244,28 @@
 	int (*cmdlist_commit)(struct mdss_dsi_ctrl_pdata *ctrl, int from_mdp);
 	struct mdss_panel_data panel_data;
 	unsigned char *ctrl_base;
+	struct dss_io_data ctrl_io;
+	struct dss_io_data mmss_misc_io;
+	struct dss_io_data phy_io;
 	int reg_size;
-	u32 clk_cnt;
+	u32 bus_clk_cnt;
+	u32 link_clk_cnt;
+	u32 flags;
 	struct clk *mdp_core_clk;
 	struct clk *ahb_clk;
 	struct clk *axi_clk;
+	struct clk *mmss_misc_ahb_clk;
 	struct clk *byte_clk;
 	struct clk *esc_clk;
 	struct clk *pixel_clk;
 	u8 ctrl_state;
 	int panel_mode;
 	int irq_cnt;
-	int mdss_dsi_clk_on;
 	int rst_gpio;
 	int disp_en_gpio;
 	int disp_te_gpio;
 	int mode_gpio;
-	int rst_gpio_requested;
-	int disp_en_gpio_requested;
 	int disp_te_gpio_requested;
-	int mode_gpio_requested;
 	int bklt_ctrl;	/* backlight ctrl */
 	int pwm_period;
 	int pwm_pmic_gpio;
@@ -286,10 +296,18 @@
 	struct mutex mutex;
 	struct mutex cmd_mutex;
 
+	bool ulps;
+
 	struct dsi_buf tx_buf;
 	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);
 
@@ -299,8 +317,7 @@
 int mdss_dsi_cmds_rx(struct mdss_dsi_ctrl_pdata *ctrl,
 			struct dsi_cmd_desc *cmds, int rlen);
 
-void mdss_dsi_host_init(struct mipi_panel_info *pinfo,
-				struct mdss_panel_data *pdata);
+void mdss_dsi_host_init(struct mdss_panel_data *pdata);
 void mdss_dsi_op_mode_config(int mode,
 				struct mdss_panel_data *pdata);
 void mdss_dsi_cmd_mode_ctrl(int enable);
@@ -308,7 +325,8 @@
 void mdss_dsi_cmd_mdp_start(struct mdss_dsi_ctrl_pdata *ctrl);
 void mdss_dsi_cmd_bta_sw_trigger(struct mdss_panel_data *pdata);
 void mdss_dsi_ack_err_status(struct mdss_dsi_ctrl_pdata *ctrl);
-int mdss_dsi_clk_ctrl(struct mdss_dsi_ctrl_pdata *ctrl, int enable);
+int mdss_dsi_clk_ctrl(struct mdss_dsi_ctrl_pdata *ctrl,
+	u8 clk_type, int enable);
 void mdss_dsi_clk_req(struct mdss_dsi_ctrl_pdata *ctrl,
 				int enable);
 void mdss_dsi_controller_cfg(int enable,
@@ -318,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,
@@ -326,11 +344,12 @@
 void mdss_dsi_clk_deinit(struct mdss_dsi_ctrl_pdata *ctrl_pdata);
 int mdss_dsi_enable_bus_clocks(struct mdss_dsi_ctrl_pdata *ctrl_pdata);
 void mdss_dsi_disable_bus_clocks(struct mdss_dsi_ctrl_pdata *ctrl_pdata);
-void mdss_dsi_panel_reset(struct mdss_panel_data *pdata, int enable);
-void mdss_dsi_phy_enable(struct mdss_dsi_ctrl_pdata *ctrl, int on);
+int mdss_dsi_panel_reset(struct mdss_panel_data *pdata, int enable);
+void mdss_dsi_phy_disable(struct mdss_dsi_ctrl_pdata *ctrl);
 void mdss_dsi_phy_init(struct mdss_panel_data *pdata);
 void mdss_dsi_phy_sw_reset(unsigned char *ctrl_base);
-void mdss_dsi_cmd_test_pattern(struct mdss_panel_data *pdata);
+void mdss_dsi_cmd_test_pattern(struct mdss_dsi_ctrl_pdata *ctrl);
+void mdss_dsi_video_test_pattern(struct mdss_dsi_ctrl_pdata *ctrl);
 void mdss_dsi_panel_pwm_cfg(struct mdss_dsi_ctrl_pdata *ctrl);
 
 void mdss_dsi_ctrl_init(struct mdss_dsi_ctrl_pdata *ctrl);
@@ -339,8 +358,52 @@
 int mdss_dsi_cmdlist_commit(struct mdss_dsi_ctrl_pdata *ctrl, int from_mdp);
 void mdss_dsi_cmdlist_kickoff(int intf);
 int mdss_dsi_bta_status_check(struct mdss_dsi_ctrl_pdata *ctrl);
+bool __mdss_dsi_clk_enabled(struct mdss_dsi_ctrl_pdata *ctrl, u8 clk_type);
 
 int mdss_dsi_panel_init(struct device_node *node,
 		struct mdss_dsi_ctrl_pdata *ctrl_pdata,
 		bool cmd_cfg_cont_splash);
+
+static inline bool mdss_dsi_broadcast_mode_enabled(void)
+{
+	return ctrl_list[DSI_CTRL_MASTER]->shared_pdata.broadcast_enable &&
+		ctrl_list[DSI_CTRL_SLAVE] &&
+		ctrl_list[DSI_CTRL_SLAVE]->shared_pdata.broadcast_enable;
+}
+
+static inline struct mdss_dsi_ctrl_pdata *mdss_dsi_get_master_ctrl(void)
+{
+	if (mdss_dsi_broadcast_mode_enabled())
+		return ctrl_list[DSI_CTRL_MASTER];
+	else
+		return NULL;
+}
+
+static inline struct mdss_dsi_ctrl_pdata *mdss_dsi_get_slave_ctrl(void)
+{
+	if (mdss_dsi_broadcast_mode_enabled())
+		return ctrl_list[DSI_CTRL_SLAVE];
+	else
+		return NULL;
+}
+
+static inline bool mdss_dsi_is_master_ctrl(struct mdss_dsi_ctrl_pdata *ctrl)
+{
+	return mdss_dsi_broadcast_mode_enabled() &&
+		(ctrl->ndx == DSI_CTRL_MASTER);
+}
+
+static inline bool mdss_dsi_is_slave_ctrl(struct mdss_dsi_ctrl_pdata *ctrl)
+{
+	return mdss_dsi_broadcast_mode_enabled() &&
+		(ctrl->ndx == DSI_CTRL_SLAVE);
+}
+
+static inline struct mdss_dsi_ctrl_pdata *mdss_dsi_get_ctrl_by_index(int ndx)
+{
+	if (ndx >= DSI_CTRL_MAX)
+		return NULL;
+
+	return ctrl_list[ndx];
+}
 #endif /* MDSS_DSI_H */
diff --git a/drivers/video/msm/mdss/mdss_dsi_cmd.h b/drivers/video/msm/mdss/mdss_dsi_cmd.h
index c480756..f806e78 100644
--- a/drivers/video/msm/mdss/mdss_dsi_cmd.h
+++ b/drivers/video/msm/mdss/mdss_dsi_cmd.h
@@ -98,6 +98,7 @@
 #define CMD_REQ_COMMIT  0x0002
 #define CMD_CLK_CTRL    0x0004
 #define CMD_REQ_NO_MAX_PKT_SIZE 0x0008
+#define CMD_REQ_LP_MODE 0x0010
 
 struct dcs_cmd_req {
 	struct dsi_cmd_desc *cmds;
diff --git a/drivers/video/msm/mdss/mdss_dsi_host.c b/drivers/video/msm/mdss/mdss_dsi_host.c
index 65e6214..95e7c6e 100644
--- a/drivers/video/msm/mdss/mdss_dsi_host.c
+++ b/drivers/video/msm/mdss/mdss_dsi_host.c
@@ -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
@@ -26,13 +26,11 @@
 #include "mdss.h"
 #include "mdss_dsi.h"
 #include "mdss_panel.h"
+#include "mdss_debug.h"
 
 #define VSYNC_PERIOD 17
 
-static struct mdss_dsi_ctrl_pdata *left_ctrl_pdata;
-
-static struct mdss_dsi_ctrl_pdata *ctrl_list[DSI_CTRL_MAX];
-
+struct mdss_dsi_ctrl_pdata *ctrl_list[DSI_CTRL_MAX];
 
 struct mdss_hw mdss_dsi0_hw = {
 	.hw_ndx = MDSS_HW_DSI0,
@@ -72,14 +70,6 @@
 
 void mdss_dsi_ctrl_init(struct mdss_dsi_ctrl_pdata *ctrl)
 {
-	if (ctrl->shared_pdata.broadcast_enable)
-		if (ctrl->panel_data.panel_info.pdest
-					== DISPLAY_1) {
-			pr_debug("%s: Broadcast mode enabled.\n",
-				 __func__);
-			left_ctrl_pdata = ctrl;
-		}
-
 	if (ctrl->panel_data.panel_info.pdest == DISPLAY_1) {
 		mdss_dsi0_hw.ptr = (void *)(ctrl);
 		ctrl->dsi_hw = &mdss_dsi0_hw;
@@ -90,6 +80,8 @@
 		ctrl->ndx = DSI_CTRL_1;
 	}
 
+	ctrl->panel_mode = ctrl->panel_data.panel_info.mipi.mode;
+
 	ctrl_list[ctrl->ndx] = ctrl;	/* keep it */
 
 	if (mdss_register_irq(ctrl->dsi_hw))
@@ -119,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);
@@ -126,22 +119,27 @@
 		mutex_unlock(&ctrl->cmd_mutex);
 	}
 
-	mdss_dsi_clk_ctrl(ctrl, enable);
+	MDSS_XLOG(ctrl->ndx, enable, ctrl->mdp_busy, current->pid);
+	mdss_dsi_clk_ctrl(ctrl, DSI_ALL_CLKS, enable);
 }
 
 void mdss_dsi_pll_relock(struct mdss_dsi_ctrl_pdata *ctrl)
 {
 	int i, cnt;
 
-	cnt = ctrl->clk_cnt;
+	/*
+	 * todo: this code does not work very well with dual
+	 * dsi use cases. Need to fix this eventually.
+	 */
+	cnt = ctrl->link_clk_cnt;
 
 	/* disable dsi clk */
 	for (i = 0; i < cnt; i++)
-		mdss_dsi_clk_ctrl(ctrl, 0);
+		mdss_dsi_clk_ctrl(ctrl, DSI_LINK_CLKS, 0);
 
 	/* enable dsi clk */
 	for (i = 0; i < cnt; i++)
-		mdss_dsi_clk_ctrl(ctrl, 1);
+		mdss_dsi_clk_ctrl(ctrl, DSI_LINK_CLKS, 1);
 }
 
 void mdss_dsi_enable_irq(struct mdss_dsi_ctrl_pdata *ctrl, u32 term)
@@ -154,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);
@@ -173,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);
@@ -193,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);
@@ -200,36 +201,42 @@
 	spin_unlock(&ctrl->irq_lock);
 }
 
-void mdss_dsi_cmd_test_pattern(struct mdss_panel_data *pdata)
+void mdss_dsi_video_test_pattern(struct mdss_dsi_ctrl_pdata *ctrl)
 {
-	struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
 	int i;
 
-	if (pdata == NULL) {
-		pr_err("%s: Invalid input data\n", __func__);
-		return;
-	}
-
-	ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
-				panel_data);
-
-	MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x015c, 0x201);
-	MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x016c, 0xff0000); /* red */
+	MIPI_OUTP((ctrl->ctrl_base) + 0x015c, 0x021);
+	MIPI_OUTP((ctrl->ctrl_base) + 0x0164, 0xff0000); /* red */
 	i = 0;
 	while (i++ < 50) {
-		MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x0184, 0x1);
+		MIPI_OUTP((ctrl->ctrl_base) + 0x0180, 0x1);
 		/* Add sleep to get ~50 fps frame rate*/
 		msleep(20);
 	}
-	MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x015c, 0x0);
+	MIPI_OUTP((ctrl->ctrl_base) + 0x015c, 0x0);
 }
 
-void mdss_dsi_host_init(struct mipi_panel_info *pinfo,
-				struct mdss_panel_data *pdata)
+void mdss_dsi_cmd_test_pattern(struct mdss_dsi_ctrl_pdata *ctrl)
+{
+	int i;
+
+	MIPI_OUTP((ctrl->ctrl_base) + 0x015c, 0x201);
+	MIPI_OUTP((ctrl->ctrl_base) + 0x016c, 0xff0000); /* red */
+	i = 0;
+	while (i++ < 50) {
+		MIPI_OUTP((ctrl->ctrl_base) + 0x0184, 0x1);
+		/* Add sleep to get ~50 fps frame rate*/
+		msleep(20);
+	}
+	MIPI_OUTP((ctrl->ctrl_base) + 0x015c, 0x0);
+}
+
+void mdss_dsi_host_init(struct mdss_panel_data *pdata)
 {
 	u32 dsi_ctrl, intr_ctrl;
 	u32 data;
 	struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
+	struct mipi_panel_info *pinfo = NULL;
 
 	if (pdata == NULL) {
 		pr_err("%s: Invalid input data\n", __func__);
@@ -239,9 +246,9 @@
 	ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
 				panel_data);
 
-	pinfo->rgb_swap = DSI_RGB_SWAP_RGB;
+	pinfo = &pdata->panel_info.mipi;
 
-	ctrl_pdata->panel_mode = pinfo->mode;
+	pinfo->rgb_swap = DSI_RGB_SWAP_RGB;
 
 	if (pinfo->mode == DSI_VIDEO_MODE) {
 		data = 0;
@@ -313,7 +320,7 @@
 
 	/* from frame buffer, low power mode */
 	/* DSI_COMMAND_MODE_DMA_CTRL */
-	if (ctrl_pdata->shared_pdata.broadcast_enable)
+	if (mdss_dsi_broadcast_mode_enabled())
 		MIPI_OUTP(ctrl_pdata->ctrl_base + 0x3C, 0x94000000);
 	else
 		MIPI_OUTP(ctrl_pdata->ctrl_base + 0x3C, 0x14000000);
@@ -364,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;
@@ -516,6 +523,7 @@
 {
 	u32 dsi_ctrl, intr_ctrl;
 	struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
+	struct mdss_dsi_ctrl_pdata *mctrl = NULL;
 
 	if (pdata == NULL) {
 		pr_err("%s: Invalid input data\n", __func__);
@@ -525,12 +533,15 @@
 	ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
 				panel_data);
 
-	if (ctrl_pdata->shared_pdata.broadcast_enable)
-		if (pdata->panel_info.pdest == DISPLAY_1) {
-			pr_debug("%s: Broadcast mode. 1st ctrl\n",
-				 __func__);
-			return;
-		}
+	/*
+	 * In broadcast mode, the configuration for master controller
+	 * would be done when the slave controller is configured
+	 */
+	if (mdss_dsi_is_master_ctrl(ctrl_pdata)) {
+		pr_debug("%s: Broadcast mode enabled. skipping config for ctrl%d\n",
+			__func__, ctrl_pdata->ndx);
+		return;
+	}
 
 	dsi_ctrl = MIPI_INP((ctrl_pdata->ctrl_base) + 0x0004);
 	/*If Video enabled, Keep Video and Cmd mode ON */
@@ -551,17 +562,22 @@
 			DSI_INTR_CMD_MDP_DONE_MASK | DSI_INTR_BTA_DONE_MASK;
 	}
 
-	if (ctrl_pdata->shared_pdata.broadcast_enable)
-		if ((pdata->panel_info.pdest == DISPLAY_2)
-		  && (left_ctrl_pdata != NULL)) {
-			MIPI_OUTP(left_ctrl_pdata->ctrl_base + 0x0110,
-				  intr_ctrl); /* DSI_INTL_CTRL */
-			MIPI_OUTP(left_ctrl_pdata->ctrl_base + 0x0004,
-					dsi_ctrl);
+	/* Ensure that for slave controller, master is also configured */
+	if (mdss_dsi_is_slave_ctrl(ctrl_pdata)) {
+		mctrl = mdss_dsi_get_master_ctrl();
+		if (mctrl) {
+			pr_debug("%s: configuring ctrl%d\n", __func__,
+				mctrl->ndx);
+			MIPI_OUTP(mctrl->ctrl_base + 0x0110, intr_ctrl);
+			MIPI_OUTP(mctrl->ctrl_base + 0x0004, dsi_ctrl);
+		} else {
+			pr_warn("%s: Unable to get master control\n",
+				__func__);
 		}
+	}
 
-	MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x0110,
-				intr_ctrl); /* DSI_INTL_CTRL */
+	pr_debug("%s: configuring ctrl%d\n", __func__, ctrl_pdata->ndx);
+	MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x0110, intr_ctrl);
 	MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x0004, dsi_ctrl);
 	wmb();
 }
@@ -612,7 +628,7 @@
 
 	pr_debug("%s: Checking BTA status\n", __func__);
 
-	mdss_dsi_clk_ctrl(ctrl_pdata, 1);
+	mdss_dsi_clk_ctrl(ctrl_pdata, DSI_ALL_CLKS, 1);
 	spin_lock_irqsave(&ctrl_pdata->mdp_lock, flag);
 	INIT_COMPLETION(ctrl_pdata->bta_comp);
 	mdss_dsi_enable_irq(ctrl_pdata, DSI_BTA_TERM);
@@ -627,7 +643,7 @@
 		pr_err("%s: DSI BTA error: %i\n", __func__, ret);
 	}
 
-	mdss_dsi_clk_ctrl(ctrl_pdata, 0);
+	mdss_dsi_clk_ctrl(ctrl_pdata, DSI_ALL_CLKS, 0);
 	pr_debug("%s: BTA done with ret: %d\n", __func__, ret);
 
 	return ret;
@@ -716,6 +732,40 @@
 	return tot;
 }
 
+/**
+ * __mdss_dsi_cmd_mode_config() - Enable/disable command mode engine
+ * @ctrl: pointer to the dsi controller structure
+ * @enable: true to enable command mode, false to disable command mode
+ *
+ * This function can be used to temporarily enable the command mode
+ * engine (even for video mode panels) so as to transfer any dma commands to
+ * the panel. It can also be used to disable the command mode engine
+ * when no longer needed.
+ *
+ * Return: true, if there was a mode switch to command mode for video mode
+ * panels.
+ */
+static inline bool __mdss_dsi_cmd_mode_config(
+	struct mdss_dsi_ctrl_pdata *ctrl, bool enable)
+{
+	bool mode_changed = false;
+	u32 dsi_ctrl;
+
+	dsi_ctrl = MIPI_INP((ctrl->ctrl_base) + 0x0004);
+	/* if currently in video mode, enable command mode */
+	if (enable) {
+		if ((dsi_ctrl) & BIT(1)) {
+			MIPI_OUTP((ctrl->ctrl_base) + 0x0004,
+				dsi_ctrl | BIT(2));
+			mode_changed = true;
+		}
+	} else {
+		MIPI_OUTP((ctrl->ctrl_base) + 0x0004, dsi_ctrl & ~BIT(2));
+	}
+
+	return mode_changed;
+}
+
 /*
  * mdss_dsi_cmds_tx:
  * thread context only
@@ -723,61 +773,49 @@
 int mdss_dsi_cmds_tx(struct mdss_dsi_ctrl_pdata *ctrl,
 		struct dsi_cmd_desc *cmds, int cnt)
 {
-	u32 dsi_ctrl, data;
-	int video_mode, ret = 0;
-	u32 left_dsi_ctrl = 0;
-	bool left_ctrl_restore = false;
+	int ret = 0;
+	bool ctrl_restore = false, mctrl_restore = false;
+	struct mdss_dsi_ctrl_pdata *mctrl = NULL;
 
-	if (ctrl->shared_pdata.broadcast_enable) {
-		if (ctrl->ndx == DSI_CTRL_0) {
-			pr_debug("%s: Broadcast mode. 1st ctrl\n",
-				 __func__);
-			return 0;
-		}
+	/*
+	 * In broadcast mode, the configuration for master controller
+	 * would be done when the slave controller is configured
+	 */
+	if (mdss_dsi_is_master_ctrl(ctrl)) {
+		pr_debug("%s: Broadcast mode enabled. skipping config for ctrl%d\n",
+			__func__, ctrl->ndx);
+		return 0;
 	}
 
-	if (ctrl->shared_pdata.broadcast_enable) {
-		if ((ctrl->ndx == DSI_CTRL_1)
-		  && (left_ctrl_pdata != NULL)) {
-			left_dsi_ctrl = MIPI_INP(left_ctrl_pdata->ctrl_base
-								+ 0x0004);
-			video_mode =
-				left_dsi_ctrl & 0x02; /* VIDEO_MODE_EN */
-			if (video_mode) {
-				data = left_dsi_ctrl | 0x04; /* CMD_MODE_EN */
-				MIPI_OUTP(left_ctrl_pdata->ctrl_base + 0x0004,
-						data);
-				left_ctrl_restore = true;
-			}
-		}
+	/*
+	 * Turn on cmd mode in order to transmit the commands.
+	 * For video mode, do not send cmds more than one pixel line,
+	 * since it only transmit it during BLLP.
+	 * Ensure that for slave controller, master is also configured
+	 */
+	if (mdss_dsi_is_slave_ctrl(ctrl)) {
+		mctrl = mdss_dsi_get_master_ctrl();
+		if (!mctrl)
+			pr_warn("%s: Unable to get master control\n",
+				__func__);
+		else
+			mctrl_restore = __mdss_dsi_cmd_mode_config(mctrl, 1);
 	}
 
-	/* turn on cmd mode
-	* for video mode, do not send cmds more than
-	* one pixel line, since it only transmit it
-	* during BLLP.
-	*/
-	dsi_ctrl = MIPI_INP((ctrl->ctrl_base) + 0x0004);
-	video_mode = dsi_ctrl & 0x02; /* VIDEO_MODE_EN */
-	if (video_mode) {
-		data = dsi_ctrl | 0x04; /* CMD_MODE_EN */
-		MIPI_OUTP((ctrl->ctrl_base) + 0x0004, data);
-	}
+	ctrl_restore = __mdss_dsi_cmd_mode_config(ctrl, 1);
 
 	ret = mdss_dsi_cmds2buf_tx(ctrl, cmds, cnt);
 	if (IS_ERR_VALUE(ret)) {
-		pr_err("%s: failed to call\n",
-			__func__);
+		pr_err("%s: failed to call\n", __func__);
 		cnt = -EINVAL;
 	}
 
-	if (left_ctrl_restore)
-		MIPI_OUTP(left_ctrl_pdata->ctrl_base + 0x0004,
-					left_dsi_ctrl); /*restore */
+	if (mctrl_restore)
+		__mdss_dsi_cmd_mode_config(mctrl, 0);
 
-	if (video_mode)
-		MIPI_OUTP((ctrl->ctrl_base) + 0x0004,
-					dsi_ctrl); /* restore */
+	if (ctrl_restore)
+		__mdss_dsi_cmd_mode_config(ctrl, 0);
+
 	return cnt;
 }
 
@@ -810,47 +848,37 @@
 	int short_response, diff, pkt_size, ret = 0;
 	struct dsi_buf *tp, *rp;
 	char cmd;
-	u32 dsi_ctrl, data;
-	int video_mode;
-	u32 left_dsi_ctrl = 0;
-	bool left_ctrl_restore = false;
+	bool ctrl_restore = false, mctrl_restore = false;
+	struct mdss_dsi_ctrl_pdata *mctrl = NULL;
 
-	if (ctrl->shared_pdata.broadcast_enable) {
-		if (ctrl->ndx == DSI_CTRL_0) {
-			pr_debug("%s: Broadcast mode. 1st ctrl\n",
-				 __func__);
-			return 0;
-		}
+	/*
+	 * In broadcast mode, the configuration for master controller
+	 * would be done when the slave controller is configured
+	 */
+	if (mdss_dsi_is_master_ctrl(ctrl)) {
+		pr_debug("%s: Broadcast mode enabled. skipping config for ctrl%d\n",
+			__func__, ctrl->ndx);
+		return 0;
 	}
 
-	if (ctrl->shared_pdata.broadcast_enable) {
-		if ((ctrl->ndx == DSI_CTRL_1)
-		  && (left_ctrl_pdata != NULL)) {
-			left_dsi_ctrl = MIPI_INP(left_ctrl_pdata->ctrl_base
-								+ 0x0004);
-			video_mode = left_dsi_ctrl & 0x02; /* VIDEO_MODE_EN */
-			if (video_mode) {
-				data = left_dsi_ctrl | 0x04; /* CMD_MODE_EN */
-				MIPI_OUTP(left_ctrl_pdata->ctrl_base + 0x0004,
-						data);
-				left_ctrl_restore = true;
-			}
-		}
+	/*
+	 * Turn on cmd mode in order to transmit the commands.
+	 * For video mode, do not send cmds more than one pixel line,
+	 * since it only transmit it during BLLP.
+	 * Ensure that for slave controller, master is also configured
+	 */
+	if (mdss_dsi_is_slave_ctrl(ctrl)) {
+		mctrl = mdss_dsi_get_master_ctrl();
+		if (!mctrl)
+			pr_warn("%s: Unable to get master control\n",
+				__func__);
+		else
+			mctrl_restore = __mdss_dsi_cmd_mode_config(mctrl, 1);
 	}
 
-	/* turn on cmd mode
-	* for video mode, do not send cmds more than
-	* one pixel line, since it only transmit it
-	* during BLLP.
-	*/
-	dsi_ctrl = MIPI_INP((ctrl->ctrl_base) + 0x0004);
-	video_mode = dsi_ctrl & 0x02; /* VIDEO_MODE_EN */
-	if (video_mode) {
-		data = dsi_ctrl | 0x04; /* CMD_MODE_EN */
-		MIPI_OUTP((ctrl->ctrl_base) + 0x0004, data);
-	}
+	ctrl_restore = __mdss_dsi_cmd_mode_config(ctrl, 1);
 
-	if (rlen == 0) {
+	if (rlen <= 2) {
 		short_response = 1;
 		rx_byte = 4;
 	} else {
@@ -975,12 +1003,11 @@
 		rp->len = 0;
 	}
 end:
-	if (left_ctrl_restore)
-		MIPI_OUTP(left_ctrl_pdata->ctrl_base + 0x0004,
-					left_dsi_ctrl); /*restore */
-	if (video_mode)
-		MIPI_OUTP((ctrl->ctrl_base) + 0x0004,
-					dsi_ctrl); /* restore */
+	if (mctrl_restore)
+		__mdss_dsi_cmd_mode_config(mctrl, 0);
+
+	if (ctrl_restore)
+		__mdss_dsi_cmd_mode_config(ctrl, 0);
 
 	return rp->len;
 }
@@ -994,6 +1021,7 @@
 	int domain = MDSS_IOMMU_DOMAIN_UNSECURE;
 	char *bp;
 	unsigned long size, addr;
+	struct mdss_dsi_ctrl_pdata *mctrl = NULL;
 
 	bp = tp->data;
 
@@ -1015,24 +1043,27 @@
 
 	INIT_COMPLETION(ctrl->dma_comp);
 
-	if (ctrl->shared_pdata.broadcast_enable)
-		if ((ctrl->ndx == DSI_CTRL_1)
-		  && (left_ctrl_pdata != NULL)) {
-			MIPI_OUTP(left_ctrl_pdata->ctrl_base + 0x048, addr);
-			MIPI_OUTP(left_ctrl_pdata->ctrl_base + 0x04c, len);
+	/* Ensure that for slave controller, master is also configured */
+	if (mdss_dsi_is_slave_ctrl(ctrl)) {
+		mctrl = mdss_dsi_get_master_ctrl();
+		if (mctrl) {
+			MIPI_OUTP(mctrl->ctrl_base + 0x048, addr);
+			MIPI_OUTP(mctrl->ctrl_base + 0x04c, len);
+		} else {
+			pr_warn("%s: Unable to get master control\n",
+				__func__);
 		}
+	}
 
 	MIPI_OUTP((ctrl->ctrl_base) + 0x048, addr);
 	MIPI_OUTP((ctrl->ctrl_base) + 0x04c, len);
 	wmb();
 
-	if (ctrl->shared_pdata.broadcast_enable)
-		if ((ctrl->ndx == DSI_CTRL_1)
-		  && (left_ctrl_pdata != NULL)) {
-			MIPI_OUTP(left_ctrl_pdata->ctrl_base + 0x090, 0x01);
-		}
+	/* Trigger on master controller as well */
+	if (mctrl)
+		MIPI_OUTP(mctrl->ctrl_base + 0x090, 0x01);
 
-	MIPI_OUTP((ctrl->ctrl_base) + 0x090, 0x01);	/* trigger */
+	MIPI_OUTP((ctrl->ctrl_base) + 0x090, 0x01);
 	wmb();
 
 	ret = wait_for_completion_timeout(&ctrl->dma_comp,
@@ -1128,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);
 }
 
@@ -1138,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++;
@@ -1148,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,
@@ -1182,13 +1219,11 @@
 		len = mdss_dsi_cmds_rx(ctrl, req->cmds, req->rlen);
 		memcpy(req->rbuf, rp->data, rp->len);
 		/*
-		 * For dual DSI cases, early return of controller - 0
+		 * For dual DSI cases, early return of master ctrl
 		 * is valid. Hence, for those cases the return value
 		 * is zero even though we don't send any commands.
-		 *
 		 */
-		if ((ctrl->shared_pdata.broadcast_enable &&
-			ctrl->ndx == DSI_CTRL_0) || (len != 0))
+		if (mdss_dsi_is_master_ctrl(ctrl) || (len != 0))
 			ret = 0;
 	} else {
 		pr_err("%s: No rx buffer provided\n", __func__);
@@ -1208,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);
 
@@ -1216,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
@@ -1225,14 +1265,14 @@
 	mdss_bus_bandwidth_ctrl(1);
 
 	pr_debug("%s:  from_mdp=%d pid=%d\n", __func__, from_mdp, current->pid);
-	mdss_dsi_clk_ctrl(ctrl, 1);
+	mdss_dsi_clk_ctrl(ctrl, DSI_ALL_CLKS, 1);
 
 	if (req->flags & CMD_REQ_RX)
 		ret = mdss_dsi_cmdlist_rx(ctrl, req);
 	else
 		ret = mdss_dsi_cmdlist_tx(ctrl, req);
 
-	mdss_dsi_clk_ctrl(ctrl, 0);
+	mdss_dsi_clk_ctrl(ctrl, DSI_ALL_CLKS, 0);
 	mdss_bus_bandwidth_ctrl(0);
 
 need_lock:
@@ -1240,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;
@@ -1305,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);
@@ -1382,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");
 	}
 }
 
@@ -1437,6 +1515,7 @@
 	u32 isr;
 	struct mdss_dsi_ctrl_pdata *ctrl =
 			(struct mdss_dsi_ctrl_pdata *)ptr;
+	struct mdss_dsi_ctrl_pdata *mctrl = NULL;
 
 	if (!ctrl->ctrl_base)
 		pr_err("%s:%d DSI base adr no Initialized",
@@ -1445,19 +1524,25 @@
 	isr = MIPI_INP(ctrl->ctrl_base + 0x0110);/* DSI_INTR_CTRL */
 	MIPI_OUTP(ctrl->ctrl_base + 0x0110, isr);
 
-	if (ctrl->shared_pdata.broadcast_enable)
-		if ((ctrl->panel_data.panel_info.pdest == DISPLAY_2)
-		    && (left_ctrl_pdata != NULL)) {
+	if (mdss_dsi_is_slave_ctrl(ctrl)) {
+		mctrl = mdss_dsi_get_master_ctrl();
+		if (mctrl) {
 			u32 isr0;
-			isr0 = MIPI_INP(left_ctrl_pdata->ctrl_base
-						+ 0x0110);/* DSI_INTR_CTRL */
-			MIPI_OUTP(left_ctrl_pdata->ctrl_base + 0x0110, isr0);
+			isr0 = MIPI_INP(mctrl->ctrl_base + 0x0110);
+			if (isr0 & DSI_INTR_CMD_DMA_DONE)
+				MIPI_OUTP(mctrl->ctrl_base + 0x0110,
+					DSI_INTR_CMD_DMA_DONE);
+		} else {
+			pr_warn("%s: Unable to get master control\n",
+				__func__);
 		}
+	}
 
-	pr_debug("%s: isr=%x", __func__, isr);
+	pr_debug("%s: ndx=%d isr=%x\n", __func__, ctrl->ndx, isr);
 
 	if (isr & DSI_INTR_ERROR) {
-		pr_err("%s: isr=%x %x", __func__, isr, (int)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);
 	}
 
@@ -1469,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);
@@ -1476,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 3c7d17c..f58e2a1 100644
--- a/drivers/video/msm/mdss/mdss_dsi_panel.c
+++ b/drivers/video/msm/mdss/mdss_dsi_panel.c
@@ -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
@@ -118,6 +118,11 @@
 	cmdreq.cmds = pcmds->cmds;
 	cmdreq.cmds_cnt = pcmds->cmd_cnt;
 	cmdreq.flags = CMD_REQ_COMMIT;
+
+	/*Panel ON/Off commands should be sent in DSI Low Power Mode*/
+	if (pcmds->link_state == DSI_LP_MODE)
+		cmdreq.flags  |= CMD_REQ_LP_MODE;
+
 	cmdreq.rlen = 0;
 	cmdreq.cb = NULL;
 
@@ -148,15 +153,53 @@
 	mdss_dsi_cmdlist_put(ctrl, &cmdreq);
 }
 
-void mdss_dsi_panel_reset(struct mdss_panel_data *pdata, int enable)
+static int mdss_dsi_request_gpios(struct mdss_dsi_ctrl_pdata *ctrl_pdata)
+{
+	int rc = 0;
+
+	if (gpio_is_valid(ctrl_pdata->disp_en_gpio)) {
+		rc = gpio_request(ctrl_pdata->disp_en_gpio,
+						"disp_enable");
+		if (rc) {
+			pr_err("request disp_en gpio failed, rc=%d\n",
+				       rc);
+			goto disp_en_gpio_err;
+		}
+	}
+	rc = gpio_request(ctrl_pdata->rst_gpio, "disp_rst_n");
+	if (rc) {
+		pr_err("request reset gpio failed, rc=%d\n",
+			rc);
+		goto rst_gpio_err;
+	}
+	if (gpio_is_valid(ctrl_pdata->mode_gpio)) {
+		rc = gpio_request(ctrl_pdata->mode_gpio, "panel_mode");
+		if (rc) {
+			pr_err("request panel mode gpio failed,rc=%d\n",
+								rc);
+			goto mode_gpio_err;
+		}
+	}
+	return rc;
+
+mode_gpio_err:
+	gpio_free(ctrl_pdata->rst_gpio);
+rst_gpio_err:
+	if (gpio_is_valid(ctrl_pdata->disp_en_gpio))
+		gpio_free(ctrl_pdata->disp_en_gpio);
+disp_en_gpio_err:
+	return rc;
+}
+
+int mdss_dsi_panel_reset(struct mdss_panel_data *pdata, int enable)
 {
 	struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
 	struct mdss_panel_info *pinfo = NULL;
-	int i;
+	int i, rc = 0;
 
 	if (pdata == NULL) {
 		pr_err("%s: Invalid input data\n", __func__);
-		return;
+		return -EINVAL;
 	}
 
 	ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
@@ -170,21 +213,28 @@
 	if (!gpio_is_valid(ctrl_pdata->rst_gpio)) {
 		pr_debug("%s:%d, reset line not configured\n",
 			   __func__, __LINE__);
-		return;
+		return rc;
 	}
 
 	pr_debug("%s: enable = %d\n", __func__, enable);
 	pinfo = &(ctrl_pdata->panel_data.panel_info);
 
 	if (enable) {
-		if (gpio_is_valid(ctrl_pdata->disp_en_gpio))
-			gpio_set_value((ctrl_pdata->disp_en_gpio), 1);
+		rc = mdss_dsi_request_gpios(ctrl_pdata);
+		if (rc) {
+			pr_err("gpio request failed\n");
+			return rc;
+		}
+		if (!pinfo->panel_power_on) {
+			if (gpio_is_valid(ctrl_pdata->disp_en_gpio))
+				gpio_set_value((ctrl_pdata->disp_en_gpio), 1);
 
-		for (i = 0; i < pdata->panel_info.rst_seq_len; ++i) {
-			gpio_set_value((ctrl_pdata->rst_gpio),
-				pdata->panel_info.rst_seq[i]);
-			if (pdata->panel_info.rst_seq[++i])
-				usleep(pdata->panel_info.rst_seq[i] * 1000);
+			for (i = 0; i < pdata->panel_info.rst_seq_len; ++i) {
+				gpio_set_value((ctrl_pdata->rst_gpio),
+					pdata->panel_info.rst_seq[i]);
+				if (pdata->panel_info.rst_seq[++i])
+					usleep(pinfo->rst_seq[i] * 1000);
+			}
 		}
 
 		if (gpio_is_valid(ctrl_pdata->mode_gpio)) {
@@ -200,10 +250,16 @@
 			pr_debug("%s: Reset panel done\n", __func__);
 		}
 	} else {
-		gpio_set_value((ctrl_pdata->rst_gpio), 0);
-		if (gpio_is_valid(ctrl_pdata->disp_en_gpio))
+		if (gpio_is_valid(ctrl_pdata->disp_en_gpio)) {
 			gpio_set_value((ctrl_pdata->disp_en_gpio), 0);
+			gpio_free(ctrl_pdata->disp_en_gpio);
+		}
+		gpio_set_value((ctrl_pdata->rst_gpio), 0);
+		gpio_free(ctrl_pdata->rst_gpio);
+		if (gpio_is_valid(ctrl_pdata->mode_gpio))
+			gpio_free(ctrl_pdata->mode_gpio);
 	}
+	return rc;
 }
 
 static char caset[] = {0x2a, 0x00, 0x00, 0x03, 0x00};	/* DTYPE_DCS_LWRITE */
@@ -292,6 +348,16 @@
 		break;
 	case BL_DCS_CMD:
 		mdss_dsi_panel_bklt_dcs(ctrl_pdata, bl_level);
+		if (mdss_dsi_is_master_ctrl(ctrl_pdata)) {
+			struct mdss_dsi_ctrl_pdata *sctrl =
+				mdss_dsi_get_slave_ctrl();
+			if (!sctrl) {
+				pr_err("%s: Invalid slave ctrl data\n",
+					__func__);
+				return;
+			}
+			mdss_dsi_panel_bklt_dcs(sctrl, bl_level);
+		}
 		break;
 	default:
 		pr_err("%s: Unknown bl_ctrl configuration\n",
@@ -598,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,
@@ -627,6 +728,35 @@
 	return 0;
 }
 
+static int mdss_dsi_parse_panel_features(struct device_node *np,
+	struct mdss_dsi_ctrl_pdata *ctrl)
+{
+	struct mdss_panel_info *pinfo;
+
+	if (!np || !ctrl) {
+		pr_err("%s: Invalid arguments\n", __func__);
+		return -ENODEV;
+	}
+
+	pinfo = &ctrl->panel_data.panel_info;
+
+	pinfo->cont_splash_enabled = of_property_read_bool(np,
+		"qcom,cont-splash-enabled");
+
+	pinfo->partial_update_enabled = of_property_read_bool(np,
+		"qcom,partial-update-enabled");
+	pr_info("%s:%d Partial update %s\n", __func__, __LINE__,
+		(pinfo->partial_update_enabled ? "enabled" : "disabled"));
+	if (pinfo->partial_update_enabled)
+		ctrl->partial_update_fnc = mdss_dsi_panel_partial_update;
+
+	pinfo->ulps_feature_enabled = of_property_read_bool(np,
+		"qcom,ulps-enabled");
+	pr_info("%s: ulps feature %s", __func__,
+		(pinfo->ulps_feature_enabled ? "enabled" : "disabled"));
+
+	return 0;
+}
 
 static int mdss_panel_parse_dt(struct device_node *np,
 			struct mdss_dsi_ctrl_pdata *ctrl_pdata)
@@ -767,6 +897,8 @@
 			ctrl_pdata->bklt_ctrl = BL_DCS_CMD;
 		}
 	}
+	rc = of_property_read_u32(np, "qcom,mdss-brightness-max-level", &tmp);
+	pinfo->brightness_max = (!rc ? tmp : MDSS_MAX_BL_BRIGHTNESS);
 	rc = of_property_read_u32(np, "qcom,mdss-dsi-bl-min-level", &tmp);
 	pinfo->bl_min = (!rc ? tmp : 0);
 	rc = of_property_read_u32(np, "qcom,mdss-dsi-bl-max-level", &tmp);
@@ -808,11 +940,11 @@
 	pinfo->mipi.insert_dcs_cmd =
 			(!rc ? tmp : 1);
 	rc = of_property_read_u32(np,
-		"qcom,mdss-dsi-te-v-sync-continue-lines", &tmp);
+		"qcom,mdss-dsi-wr-mem-continue", &tmp);
 	pinfo->mipi.wr_mem_continue =
 			(!rc ? tmp : 0x3c);
 	rc = of_property_read_u32(np,
-		"qcom,mdss-dsi-te-v-sync-rd-ptr-irq-line", &tmp);
+		"qcom,mdss-dsi-wr-mem-start", &tmp);
 	pinfo->mipi.wr_mem_start =
 			(!rc ? tmp : 0x2c);
 	rc = of_property_read_u32(np,
@@ -822,7 +954,7 @@
 	rc = of_property_read_u32(np, "qcom,mdss-dsi-virtual-channel-id", &tmp);
 	pinfo->mipi.vc = (!rc ? tmp : 0);
 	pinfo->mipi.rgb_swap = DSI_RGB_SWAP_RGB;
-	data = of_get_property(np, "mdss-dsi-color-order", NULL);
+	data = of_get_property(np, "qcom,mdss-dsi-color-order", NULL);
 	if (data) {
 		if (!strcmp(data, "rgb_swap_rbg"))
 			pinfo->mipi.rgb_swap = DSI_RGB_SWAP_RBG;
@@ -849,6 +981,11 @@
 	rc = of_property_read_u32(np, "qcom,mdss-dsi-t-clk-post", &tmp);
 	pinfo->mipi.t_clk_post = (!rc ? tmp : 0x03);
 
+	pinfo->mipi.rx_eot_ignore = of_property_read_bool(np,
+		"qcom,mdss-dsi-rx-eot-ignore");
+	pinfo->mipi.tx_eot_append = of_property_read_bool(np,
+		"qcom,mdss-dsi-tx-eot-append");
+
 	rc = of_property_read_u32(np, "qcom,mdss-dsi-stream", &tmp);
 	pinfo->mipi.stream = (!rc ? tmp : 0);
 
@@ -892,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");
@@ -899,6 +1037,12 @@
 	mdss_dsi_parse_dcs_cmds(np, &ctrl_pdata->off_cmds,
 		"qcom,mdss-dsi-off-command", "qcom,mdss-dsi-off-command-state");
 
+	rc = mdss_dsi_parse_panel_features(np, ctrl_pdata);
+	if (rc) {
+		pr_err("%s: failed to parse panel features\n", __func__);
+		goto error;
+	}
+
 	return 0;
 
 error:
@@ -911,14 +1055,15 @@
 {
 	int rc = 0;
 	static const char *panel_name;
-	bool cont_splash_enabled;
-	bool partial_update_enabled;
+	struct mdss_panel_info *pinfo;
 
-	if (!node) {
-		pr_err("%s: no panel node\n", __func__);
+	if (!node || !ctrl_pdata) {
+		pr_err("%s: Invalid arguments\n", __func__);
 		return -ENODEV;
 	}
 
+	pinfo = &ctrl_pdata->panel_data.panel_info;
+
 	pr_debug("%s:%d\n", __func__, __LINE__);
 	panel_name = of_get_property(node, "qcom,mdss-dsi-panel-name", NULL);
 	if (!panel_name)
@@ -933,33 +1078,10 @@
 		return rc;
 	}
 
-	if (cmd_cfg_cont_splash)
-		cont_splash_enabled = of_property_read_bool(node,
-				"qcom,cont-splash-enabled");
-	else
-		cont_splash_enabled = false;
-	if (!cont_splash_enabled) {
-		pr_info("%s:%d Continuous splash flag not found.\n",
-				__func__, __LINE__);
-		ctrl_pdata->panel_data.panel_info.cont_splash_enabled = 0;
-	} else {
-		pr_info("%s:%d Continuous splash flag enabled.\n",
-				__func__, __LINE__);
-
-		ctrl_pdata->panel_data.panel_info.cont_splash_enabled = 1;
-	}
-
-	partial_update_enabled = of_property_read_bool(node,
-						"qcom,partial-update-enabled");
-	if (partial_update_enabled) {
-		pr_info("%s:%d Partial update enabled.\n", __func__, __LINE__);
-		ctrl_pdata->panel_data.panel_info.partial_update_enabled = 1;
-		ctrl_pdata->partial_update_fnc = mdss_dsi_panel_partial_update;
-	} else {
-		pr_info("%s:%d Partial update disabled.\n", __func__, __LINE__);
-		ctrl_pdata->panel_data.panel_info.partial_update_enabled = 0;
-		ctrl_pdata->partial_update_fnc = NULL;
-	}
+	if (!cmd_cfg_cont_splash)
+		pinfo->cont_splash_enabled = false;
+	pr_info("%s: Continuous splash %s", __func__,
+		pinfo->cont_splash_enabled ? "enabled" : "disabled");
 
 	ctrl_pdata->on = mdss_dsi_panel_on;
 	ctrl_pdata->off = mdss_dsi_panel_off;
diff --git a/drivers/video/msm/mdss/mdss_dsi_status.c b/drivers/video/msm/mdss/mdss_dsi_status.c
index f0c4f4c..c68155a 100644
--- a/drivers/video/msm/mdss/mdss_dsi_status.c
+++ b/drivers/video/msm/mdss/mdss_dsi_status.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
@@ -30,99 +30,37 @@
 #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;
 	}
 
-	pdata = dev_get_platdata(&pdsi_status->mfd->pdev->dev);
-	if (!pdata) {
-		pr_err("%s: Panel data not available\n", __func__);
+	if (!pdsi_status->mfd) {
+		pr_err("%s: FB data not available\n", __func__);
 		return;
 	}
 
-	ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
-							panel_data);
-	if (!ctrl_pdata || !ctrl_pdata->check_status) {
-		pr_err("%s: DSI ctrl or status_check callback not available\n",
-								__func__);
-		return;
-	}
-
-	mdp5_data = mfd_to_mdp5_data(pdsi_status->mfd);
-	ctl = mfd_to_ctl(pdsi_status->mfd);
-
-	if (ctl->shared_lock)
-		mutex_lock(ctl->shared_lock);
-	mutex_lock(&mdp5_data->ov_lock);
-
-	/*
-	 * For the command mode panels, we return pan display
-	 * IOCTL on vsync interrupt. So, after vsync interrupt comes
-	 * and when DMA_P is in progress, if the panel stops responding
-	 * and if we trigger BTA before DMA_P finishes, then the DSI
-	 * FIFO will not be cleared since the DSI data bus control
-	 * doesn't come back to the host after BTA. This may cause the
-	 * display reset not to be proper. Hence, wait for DMA_P done
-	 * for command mode panels before triggering BTA.
-	 */
-	if (ctl->wait_pingpong)
-		ctl->wait_pingpong(ctl, NULL);
-
-	pr_debug("%s: DSI ctrl wait for ping pong done\n", __func__);
-
-	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
-	ret = ctrl_pdata->check_status(ctrl_pdata);
-	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
-
-	mutex_unlock(&mdp5_data->ov_lock);
-	if (ctl->shared_lock)
-		mutex_unlock(ctl->shared_lock);
-
-	if ((pdsi_status->mfd->panel_power_on)) {
-		if (ret > 0) {
-			schedule_delayed_work(&pdsi_status->check_status,
-				msecs_to_jiffies(pdsi_status->check_interval));
-		} else {
-			char *envp[2] = {"PANEL_ALIVE=0", NULL};
-			pdata->panel_info.panel_dead = true;
-			ret = kobject_uevent_env(
-				&pdsi_status->mfd->fbi->dev->kobj,
-							KOBJ_CHANGE, envp);
-			pr_err("%s: Panel has gone bad, sending uevent - %s\n",
-							__func__, envp[0]);
-		}
-	}
+	pdsi_status->mfd->mdp.check_dsi_status(work, interval);
 }
 
 /*
@@ -142,23 +80,80 @@
 	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;
+		struct dsi_status_data *pdata = container_of(self,
+				struct dsi_status_data, fb_notifier);
+		pdata->mfd = evdata->info->par;
+
 		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:
+		case FB_BLANK_HSYNC_SUSPEND:
+		case FB_BLANK_VSYNC_SUSPEND:
+		case FB_BLANK_NORMAL:
 			cancel_delayed_work(&pdata->check_status);
 			break;
+		default:
+			pr_err("Unknown case in FB_EVENT_BLANK event\n");
+			break;
 		}
 	}
 	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;
@@ -179,7 +174,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);
@@ -197,11 +191,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_edp.c b/drivers/video/msm/mdss/mdss_edp.c
index 6dbca10..eca73a8 100644
--- a/drivers/video/msm/mdss/mdss_edp.c
+++ b/drivers/video/msm/mdss/mdss_edp.c
@@ -33,8 +33,6 @@
 #include <mach/dma.h>
 
 #include "mdss.h"
-#include "mdss_panel.h"
-#include "mdss_mdp.h"
 #include "mdss_edp.h"
 #include "mdss_debug.h"
 
@@ -198,6 +196,7 @@
 	int ret = 0;
 	struct mdss_edp_drv_pdata *edp_drv = NULL;
 	int bl_max;
+	int period_ns;
 
 	edp_drv = container_of(pdata, struct mdss_edp_drv_pdata, panel_data);
 	if (!edp_drv) {
@@ -210,13 +209,29 @@
 		if (bl_level > bl_max)
 			bl_level = bl_max;
 
-		ret = pwm_config_us(edp_drv->bl_pwm,
-				bl_level * edp_drv->pwm_period / bl_max,
-				edp_drv->pwm_period);
-		if (ret) {
-			pr_err("%s: pwm_config_us() failed err=%d.\n", __func__,
-					ret);
-			return;
+		/* In order to avoid overflow, use the microsecond version
+		 * of pwm_config if the pwm_period is greater than or equal
+		 * to 1 second.
+		 */
+		if (edp_drv->pwm_period >= USEC_PER_SEC) {
+			ret = pwm_config_us(edp_drv->bl_pwm,
+					bl_level * edp_drv->pwm_period / bl_max,
+					edp_drv->pwm_period);
+			if (ret) {
+				pr_err("%s: pwm_config_us() failed err=%d.\n",
+						__func__, ret);
+				return;
+			}
+		} else {
+			period_ns = edp_drv->pwm_period * NSEC_PER_USEC;
+			ret = pwm_config(edp_drv->bl_pwm,
+					bl_level * period_ns / bl_max,
+					period_ns);
+			if (ret) {
+				pr_err("%s: pwm_config() failed err=%d.\n",
+						__func__, ret);
+				return;
+			}
 		}
 
 		ret = pwm_enable(edp_drv->bl_pwm);
@@ -375,6 +390,7 @@
 void mdss_edp_clock_synchrous(struct mdss_edp_drv_pdata *ep, int sync)
 {
 	u32 data;
+	u32 color;
 
 	/* EDP_MISC1_MISC0 */
 	data = edp_read(ep->base + 0x02c);
@@ -384,6 +400,20 @@
 	else
 		data &= ~0x01;
 
+	/* only legacy rgb mode supported */
+	color = 0; /* 6 bits */
+	if (ep->edid.color_depth == 8)
+		color = 0x01;
+	else if (ep->edid.color_depth == 10)
+		color = 0x02;
+	else if (ep->edid.color_depth == 12)
+		color = 0x03;
+	else if (ep->edid.color_depth == 16)
+		color = 0x04;
+
+	color <<= 5;    /* bit 5 to bit 7 */
+
+	data |= color;
 	/* EDP_MISC1_MISC0 */
 	edp_write(ep->base + 0x2c, data);
 }
@@ -515,8 +545,6 @@
 
 	pr_debug("%s:+, cont_splash=%d\n", __func__, edp_drv->cont_splash);
 
-	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
-
 	if (!edp_drv->cont_splash) { /* vote for clocks */
 		mdss_edp_phy_pll_reset(edp_drv);
 		mdss_edp_aux_reset(edp_drv);
@@ -576,6 +604,8 @@
 	}
 	pr_debug("%s:+, cont_splash=%d\n", __func__, edp_drv->cont_splash);
 
+	/* wait until link training is completed */
+	mutex_lock(&edp_drv->train_mutex);
 
 	INIT_COMPLETION(edp_drv->idle_comp);
 	mdss_edp_state_ctrl(edp_drv, ST_PUSH_IDLE);
@@ -605,12 +635,12 @@
 	mdss_edp_clk_disable(edp_drv);
 	mdss_edp_unprepare_clocks(edp_drv);
 
-	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
-
 	mdss_edp_aux_ctrl(edp_drv, 0);
 
 	pr_debug("%s-: state_ctrl=%x\n", __func__,
 				edp_read(edp_drv->base + 0x8));
+
+	mutex_unlock(&edp_drv->train_mutex);
 	return 0;
 }
 
@@ -697,10 +727,18 @@
 static int mdss_edp_device_register(struct mdss_edp_drv_pdata *edp_drv)
 {
 	int ret;
+	u32 tmp;
 
 	mdss_edp_edid2pinfo(edp_drv);
 	edp_drv->panel_data.panel_info.bl_min = 1;
 	edp_drv->panel_data.panel_info.bl_max = 255;
+	ret = of_property_read_u32(edp_drv->pdev->dev.of_node,
+		"qcom,mdss-brightness-max-level", &tmp);
+	edp_drv->panel_data.panel_info.brightness_max =
+		(!ret ? tmp : MDSS_MAX_BL_BRIGHTNESS);
+
+	edp_drv->panel_data.panel_info.edp.frame_rate =
+				DEFAULT_FRAME_RATE;/* 60 fps */
 
 	edp_drv->panel_data.event_handler = mdss_edp_event_handler;
 	edp_drv->panel_data.set_backlight = mdss_edp_set_backlight;
@@ -787,7 +825,6 @@
 	if (ep->cont_splash)
 		return;
 
-	INIT_COMPLETION(ep->train_comp);
 	mdss_edp_link_train(ep);
 }
 
@@ -1068,10 +1105,6 @@
 
 	pr_debug("%s:cont_splash=%d\n", __func__, edp_drv->cont_splash);
 
-	/* need mdss clock to receive irq */
-	if (!edp_drv->cont_splash)
-		mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
-
 	/* only need aux and ahb clock for aux channel */
 	mdss_edp_prepare_aux_clocks(edp_drv);
 	mdss_edp_aux_clk_enable(edp_drv);
@@ -1100,9 +1133,6 @@
 	mdss_edp_aux_clk_disable(edp_drv);
 	mdss_edp_unprepare_aux_clocks(edp_drv);
 
-	if (!edp_drv->cont_splash)
-		mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
-
 	if (edp_drv->cont_splash) { /* vote for clocks */
 		mdss_edp_prepare_clocks(edp_drv);
 		mdss_edp_clk_enable(edp_drv);
diff --git a/drivers/video/msm/mdss/mdss_edp.h b/drivers/video/msm/mdss/mdss_edp.h
index 0c0200d..12e3be7 100644
--- a/drivers/video/msm/mdss/mdss_edp.h
+++ b/drivers/video/msm/mdss/mdss_edp.h
@@ -293,6 +293,7 @@
 	struct clk *pixel_clk;
 	struct clk *ahb_clk;
 	struct clk *link_clk;
+	struct clk *mdp_core_clk;
 	int clk_on;
 
 	/* gpios */
@@ -314,6 +315,7 @@
 	struct completion idle_comp;
 	struct completion video_comp;
 	struct mutex aux_mutex;
+	struct mutex train_mutex;
 	u32 aux_cmd_busy;
 	u32 aux_cmd_i2c;
 	int aux_trans_num;
diff --git a/drivers/video/msm/mdss/mdss_edp_aux.c b/drivers/video/msm/mdss/mdss_edp_aux.c
index bbcee19..1c36ab0 100644
--- a/drivers/video/msm/mdss/mdss_edp_aux.c
+++ b/drivers/video/msm/mdss/mdss_edp_aux.c
@@ -1196,7 +1196,6 @@
 static void edp_clear_training_pattern(struct mdss_edp_drv_pdata *ep)
 {
 	pr_debug("%s:\n", __func__);
-	edp_write(ep->base + EDP_STATE_CTRL, 0);
 	edp_train_pattern_set_write(ep, 0);
 	usleep(ep->dpcd.training_read_interval);
 }
@@ -1224,6 +1223,7 @@
 	mdss_edp_config_ctrl(ep);
 	mdss_edp_lane_power_ctrl(ep, 1);
 
+	mdss_edp_state_ctrl(ep, 0);
 	edp_clear_training_pattern(ep);
 	usleep(ep->dpcd.training_read_interval);
 
@@ -1240,6 +1240,7 @@
 
 	pr_debug("%s: Training 1 completed successfully", __func__);
 
+	mdss_edp_state_ctrl(ep, 0);
 	edp_clear_training_pattern(ep);
 	ret = edp_start_link_train_2(ep);
 	if (ret < 0) {
@@ -1312,12 +1313,18 @@
 
 int mdss_edp_link_train(struct mdss_edp_drv_pdata *ep)
 {
-	return edp_aux_link_train(ep);
+	int ret;
+
+	mutex_lock(&ep->train_mutex);
+	ret = edp_aux_link_train(ep);
+	mutex_unlock(&ep->train_mutex);
+	return ret;
 }
 
 void mdss_edp_aux_init(struct mdss_edp_drv_pdata *ep)
 {
 	mutex_init(&ep->aux_mutex);
+	mutex_init(&ep->train_mutex);
 	init_completion(&ep->aux_comp);
 	init_completion(&ep->train_comp);
 	init_completion(&ep->idle_comp);
diff --git a/drivers/video/msm/mdss/mdss_fb.c b/drivers/video/msm/mdss/mdss_fb.c
index 54e3bc8..4395d1b 100644
--- a/drivers/video/msm/mdss/mdss_fb.c
+++ b/drivers/video/msm/mdss/mdss_fb.c
@@ -2,7 +2,7 @@
  * Core MDSS framebuffer driver.
  *
  * Copyright (C) 2007 Google Incorporated
- * Copyright (c) 2008-2013, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2008-2014, The Linux Foundation. All rights reserved.
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
@@ -52,6 +52,7 @@
 #include <mach/msm_memtypes.h>
 
 #include "mdss_fb.h"
+#include "mdss_mdp_splash_logo.h"
 
 #ifdef CONFIG_FB_MSM_TRIPLE_BUFFER
 #define MDSS_FB_NUM 3
@@ -106,6 +107,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)
 {
@@ -121,15 +147,35 @@
 	if (notify > NOTIFY_UPDATE_POWER_OFF)
 		return -EINVAL;
 
-	if (notify == NOTIFY_UPDATE_START) {
+	if (mfd->update.is_suspend) {
+		to_user = NOTIFY_TYPE_SUSPEND;
+		mfd->update.is_suspend = 0;
+		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;
+			ret = 1;
+		}
 	} 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) {
@@ -154,13 +200,13 @@
 	struct msm_fb_data_type *mfd = dev_get_drvdata(led_cdev->dev->parent);
 	int bl_lvl;
 
-	if (value > MDSS_MAX_BL_BRIGHTNESS)
-		value = MDSS_MAX_BL_BRIGHTNESS;
+	if (value > mfd->panel_info->brightness_max)
+		value = mfd->panel_info->brightness_max;
 
 	/* This maps android backlight level 0 to 255 into
 	   driver backlight level 0 to bl_max with rounding */
 	MDSS_BRIGHT_TO_BL(bl_lvl, value, mfd->panel_info->bl_max,
-						MDSS_MAX_BL_BRIGHTNESS);
+				mfd->panel_info->brightness_max);
 
 	if (!bl_lvl && value)
 		bl_lvl = 1;
@@ -219,23 +265,32 @@
 	return ret;
 }
 
-static void mdss_fb_parse_dt_split(struct msm_fb_data_type *mfd)
+static void mdss_fb_parse_dt(struct msm_fb_data_type *mfd)
 {
-	u32 data[2];
+	u32 data[2] = {0};
+	u32 panel_xres;
 	struct platform_device *pdev = mfd->pdev;
-	if (of_property_read_u32_array(pdev->dev.of_node, "qcom,mdss-fb-split",
-				       data, 2))
-		return;
-	if (data[0] && data[1] &&
-	    (mfd->panel_info->xres == (data[0] + data[1]))) {
-		mfd->split_fb_left = data[0];
-		mfd->split_fb_right = data[1];
-		pr_info("split framebuffer left=%d right=%d\n",
-			mfd->split_fb_left, mfd->split_fb_right);
+
+	of_property_read_u32_array(pdev->dev.of_node,
+		"qcom,mdss-fb-split", data, 2);
+
+	panel_xres = mfd->panel_info->xres;
+	if (data[0] && data[1]) {
+		if (mfd->split_display)
+			panel_xres *= 2;
+
+		if (panel_xres == data[0] + data[1]) {
+			mfd->split_fb_left = data[0];
+			mfd->split_fb_right = data[1];
+		}
 	} else {
-		mfd->split_fb_left = 0;
-		mfd->split_fb_right = 0;
+		if (mfd->split_display)
+			mfd->split_fb_left = mfd->split_fb_right = panel_xres;
+		else
+			mfd->split_fb_left = mfd->split_fb_right = 0;
 	}
+	pr_info("split framebuffer left=%d right=%d\n",
+		mfd->split_fb_left, mfd->split_fb_right);
 }
 
 static ssize_t mdss_fb_get_split(struct device *dev,
@@ -263,14 +318,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,
 };
 
@@ -374,6 +490,9 @@
 
 	/* android supports only one lcd-backlight/lcd for now */
 	if (!lcd_backlight_registered) {
+
+		backlight_led.brightness = mfd->panel_info->brightness_max;
+		backlight_led.max_brightness = mfd->panel_info->brightness_max;
 		if (led_classdev_register(&pdev->dev, &backlight_led))
 			pr_err("led_classdev_register failed\n");
 		else
@@ -391,17 +510,32 @@
 		 mfd->mdp_sync_pt_data.timeline =
 				sw_sync_timeline_create(timeline_name);
 		if (mfd->mdp_sync_pt_data.timeline == NULL) {
-			pr_err("%s: cannot create time line", __func__);
+			pr_err("cannot create release fence time line\n");
 			return -ENOMEM;
 		}
 		mfd->mdp_sync_pt_data.notifier.notifier_call =
 			__mdss_fb_sync_buf_done_callback;
 	}
-	if ((mfd->panel.type == WRITEBACK_PANEL) ||
-			(mfd->panel.type == MIPI_CMD_PANEL))
+
+	switch (mfd->panel.type) {
+	case WRITEBACK_PANEL:
 		mfd->mdp_sync_pt_data.threshold = 1;
-	else
+		mfd->mdp_sync_pt_data.retire_threshold = 0;
+		break;
+	case MIPI_CMD_PANEL:
+		mfd->mdp_sync_pt_data.threshold = 1;
+		mfd->mdp_sync_pt_data.retire_threshold = 1;
+		break;
+	default:
 		mfd->mdp_sync_pt_data.threshold = 2;
+		mfd->mdp_sync_pt_data.retire_threshold = 0;
+		break;
+	}
+
+	if (mfd->mdp.splash_init_fnc)
+		mfd->mdp.splash_init_fnc(mfd);
+
+	INIT_DELAYED_WORK(&mfd->idle_notify_work, __mdss_fb_idle_notify_work);
 
 	return rc;
 }
@@ -671,6 +805,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);
 		}
 	}
@@ -715,7 +850,13 @@
 			}
 			mutex_lock(&mfd->update.lock);
 			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;
 
@@ -729,7 +870,9 @@
 
 			mutex_lock(&mfd->update.lock);
 			mfd->update.type = NOTIFY_TYPE_SUSPEND;
+			mfd->update.is_suspend = 1;
 			mutex_unlock(&mfd->update.lock);
+			complete(&mfd->update.comp);
 			del_timer(&mfd->no_update.timer);
 			mfd->no_update.value = NOTIFY_TYPE_SUSPEND;
 			complete(&mfd->no_update.comp);
@@ -749,6 +892,8 @@
 		}
 		break;
 	}
+	/* Notify listeners */
+	sysfs_notify(&mfd->fbi->dev->kobj, NULL, "show_blank_event");
 
 	return ret;
 }
@@ -1086,7 +1231,7 @@
 	mfd->panel_power_on = false;
 	mfd->dcm_state = DCM_UNINIT;
 
-	mdss_fb_parse_dt_split(mfd);
+	mdss_fb_parse_dt(mfd);
 
 	if (mdss_fb_alloc_fbmem(mfd)) {
 		pr_err("unable to allocate framebuffer memory\n");
@@ -1100,16 +1245,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)
@@ -1135,9 +1286,11 @@
 	struct mdss_fb_proc_info *pinfo = NULL;
 	int result;
 	int pid = current->tgid;
+	struct task_struct *task = current->group_leader;
 
 	if (mfd->shutdown_pending) {
-		pr_err("Shutdown pending. Aborting operation\n");
+		pr_err("Shutdown pending. Aborting operation. Request from pid:%d name=%s\n",
+				pid, task->comm);
 		return -EPERM;
 	}
 
@@ -1220,6 +1373,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");
@@ -1297,6 +1456,7 @@
 				mfd->index, ret, task->comm, pid);
 			return ret;
 		}
+		atomic_set(&mfd->ioctl_ref_cnt, 0);
 	}
 
 	return ret;
@@ -1433,10 +1593,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);
@@ -1487,6 +1657,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)
@@ -1525,6 +1714,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)
@@ -1617,6 +1807,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);
@@ -1653,6 +1845,7 @@
 	}
 
 	atomic_set(&mfd->commits_pending, 0);
+	atomic_set(&mfd->kickoff_pending, 0);
 	wake_up_all(&mfd->idle_wait_q);
 
 	return ret;
@@ -1929,42 +2122,37 @@
 }
 
 /**
- * mdss_fb_sync_get_rel_fence() - get release fence from sync pt timeline
- * @sync_pt_data:	Sync pt structure holding timeline and fence info.
+ * mdss_fb_sync_get_fence() - get fence from timeline
+ * @timeline:	Timeline to create the fence on
+ * @fence_name:	Name of the fence that will be created for debugging
+ * @val:	Timeline value at which the fence will be signaled
  *
- * Function returns a release fence on the timeline associated with the
- * sync pt struct given and it's associated information. The release fence
- * created can be used to signal when buffers provided will be released.
+ * Function returns a fence on the timeline given with the name provided.
+ * The fence created will be signaled when the timeline is advanced.
  */
-static struct sync_fence *__mdss_fb_sync_get_rel_fence(
-		struct msm_sync_pt_data *sync_pt_data)
+struct sync_fence *mdss_fb_sync_get_fence(struct sw_sync_timeline *timeline,
+		const char *fence_name, int val)
 {
-	struct sync_pt *rel_sync_pt;
-	struct sync_fence *rel_fence;
-	int val;
+	struct sync_pt *sync_pt;
+	struct sync_fence *fence;
 
-	val = sync_pt_data->timeline_value + sync_pt_data->threshold +
-		atomic_read(&sync_pt_data->commit_cnt);
+	pr_debug("%s: buf sync fence timeline=%d\n", fence_name, val);
 
-	pr_debug("%s: buf sync rel fence timeline=%d\n",
-		sync_pt_data->fence_name, val);
-
-	rel_sync_pt = sw_sync_pt_create(sync_pt_data->timeline, val);
-	if (rel_sync_pt == NULL) {
-		pr_err("%s: cannot create sync point\n",
-				sync_pt_data->fence_name);
+	sync_pt = sw_sync_pt_create(timeline, val);
+	if (sync_pt == NULL) {
+		pr_err("%s: cannot create sync point\n", fence_name);
 		return NULL;
 	}
 
 	/* create fence */
-	rel_fence = sync_fence_create(sync_pt_data->fence_name, rel_sync_pt);
-	if (rel_fence == NULL) {
-		sync_pt_free(rel_sync_pt);
-		pr_err("%s: cannot create fence\n", sync_pt_data->fence_name);
+	fence = sync_fence_create(fence_name, sync_pt);
+	if (fence == NULL) {
+		sync_pt_free(sync_pt);
+		pr_err("%s: cannot create fence\n", fence_name);
 		return NULL;
 	}
 
-	return rel_fence;
+	return fence;
 }
 
 static int mdss_fb_handle_buf_sync_ioctl(struct msm_sync_pt_data *sync_pt_data,
@@ -1972,8 +2160,10 @@
 {
 	int i, ret = 0;
 	int acq_fen_fd[MDP_MAX_FENCE_FD];
-	struct sync_fence *fence, *rel_fence;
+	struct sync_fence *fence, *rel_fence, *retire_fence;
 	int rel_fen_fd;
+	int retire_fen_fd;
+	int val;
 
 	if ((buf_sync->acq_fen_fd_cnt > MDP_MAX_FENCE_FD) ||
 				(sync_pt_data->timeline == NULL))
@@ -2010,7 +2200,12 @@
 	if (ret)
 		goto buf_sync_err_1;
 
-	rel_fence = __mdss_fb_sync_get_rel_fence(sync_pt_data);
+	val = sync_pt_data->timeline_value + sync_pt_data->threshold +
+			atomic_read(&sync_pt_data->commit_cnt);
+
+	/* Set release fence */
+	rel_fence = mdss_fb_sync_get_fence(sync_pt_data->timeline,
+			sync_pt_data->fence_name, val);
 	if (IS_ERR_OR_NULL(rel_fence)) {
 		pr_err("%s: unable to retrieve release fence\n",
 				sync_pt_data->fence_name);
@@ -2034,6 +2229,50 @@
 		pr_err("%s: copy_to_user failed\n", sync_pt_data->fence_name);
 		goto buf_sync_err_3;
 	}
+
+	if (!(buf_sync->flags & MDP_BUF_SYNC_FLAG_RETIRE_FENCE))
+		goto skip_retire_fence;
+
+	if (sync_pt_data->get_retire_fence)
+		retire_fence = sync_pt_data->get_retire_fence(sync_pt_data);
+	else
+		retire_fence = NULL;
+
+	if (IS_ERR_OR_NULL(retire_fence)) {
+		val += sync_pt_data->retire_threshold;
+		retire_fence = mdss_fb_sync_get_fence(
+			sync_pt_data->timeline, "mdp-retire", val);
+	}
+
+	if (IS_ERR_OR_NULL(retire_fence)) {
+		pr_err("%s: unable to retrieve retire fence\n",
+				sync_pt_data->fence_name);
+		ret = retire_fence ? PTR_ERR(rel_fence) : -ENOMEM;
+		goto buf_sync_err_3;
+	}
+	retire_fen_fd = get_unused_fd_flags(0);
+
+	if (retire_fen_fd < 0) {
+		pr_err("%s: get_unused_fd_flags failed for retire fence\n",
+				sync_pt_data->fence_name);
+		ret = -EIO;
+		sync_fence_put(retire_fence);
+		goto buf_sync_err_3;
+	}
+
+	sync_fence_install(retire_fence, retire_fen_fd);
+
+	ret = copy_to_user(buf_sync->retire_fen_fd, &retire_fen_fd,
+			sizeof(int));
+	if (ret) {
+		pr_err("%s: copy_to_user failed for retire fence\n",
+				sync_pt_data->fence_name);
+		put_unused_fd(retire_fen_fd);
+		sync_fence_put(retire_fence);
+		goto buf_sync_err_3;
+	}
+
+skip_retire_fence:
 	mutex_unlock(&sync_pt_data->sync_mutex);
 
 	if (buf_sync->flags & MDP_BUF_SYNC_FLAG_WAIT)
@@ -2066,6 +2305,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)
@@ -2076,20 +2336,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)) {
-		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:
@@ -2106,15 +2370,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)
@@ -2143,6 +2411,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;
 }
 
@@ -2178,13 +2450,6 @@
 		return -EEXIST;
 	}
 
-	if ((fb_pdata->panel_info.type != MIPI_VIDEO_PANEL) ||
-			(pdata->panel_info.type != MIPI_VIDEO_PANEL)) {
-		pr_err("Split panel not supported for panel type %d\n",
-				pdata->panel_info.type);
-		return -EINVAL;
-	}
-
 	fb_pdata->next = pdata;
 
 	return 0;
@@ -2291,3 +2556,27 @@
 }
 
 module_init(mdss_fb_init);
+
+int mdss_fb_suspres_panel(struct device *dev, void *data)
+{
+	struct msm_fb_data_type *mfd;
+	int rc;
+	u32 event;
+
+	if (!data) {
+		pr_err("Device state not defined\n");
+		return -EINVAL;
+	}
+	mfd = dev_get_drvdata(dev);
+	if (!mfd)
+		return 0;
+
+	event = *((bool *) data) ? MDSS_EVENT_RESUME : MDSS_EVENT_SUSPEND;
+
+	rc = mdss_fb_send_panel_event(mfd, event, NULL);
+	if (rc)
+		pr_warn("unable to %s fb%d (%d)\n",
+			event == MDSS_EVENT_RESUME ? "resume" : "suspend",
+			mfd->index, rc);
+	return rc;
+}
diff --git a/drivers/video/msm/mdss/mdss_fb.h b/drivers/video/msm/mdss/mdss_fb.h
index e245dd3..3416b9e 100644
--- a/drivers/video/msm/mdss/mdss_fb.h
+++ b/drivers/video/msm/mdss/mdss_fb.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2008-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
@@ -21,6 +21,7 @@
 #include <linux/notifier.h>
 
 #include "mdss_panel.h"
+#include "mdss_mdp_splash_logo.h"
 
 #define MSM_FB_DEFAULT_PAGE_SIZE 2
 #define MFD_KEY  0x11161126
@@ -78,6 +79,8 @@
 	struct completion comp;
 	struct mutex lock;
 	int value;
+	int is_suspend;
+	int ref_count;
 };
 
 struct msm_sync_pt_data {
@@ -88,13 +91,16 @@
 	struct sw_sync_timeline *timeline;
 	int timeline_value;
 	u32 threshold;
-
+	u32 retire_threshold;
 	atomic_t commit_cnt;
 	bool flushed;
 	bool async_wait_fences;
 
 	struct mutex sync_mutex;
 	struct notifier_block notifier;
+
+	struct sync_fence *(*get_retire_fence)
+		(struct msm_sync_pt_data *sync_pt_data);
 };
 
 struct msm_fb_data_type;
@@ -119,8 +125,10 @@
 	int (*update_ad_input)(struct msm_fb_data_type *mfd);
 	int (*panel_register_done)(struct mdss_panel_data *pdata);
 	u32 (*fb_stride)(u32 fb_index, u32 xres, int bpp);
+	int (*splash_init_fnc)(struct msm_fb_data_type *mfd);
 	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;
 };
 
@@ -156,6 +164,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;
@@ -197,16 +208,24 @@
 	/* 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 msm_fb_splash_info splash_info;
+
+	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)
@@ -233,6 +252,9 @@
 void mdss_fb_update_backlight(struct msm_fb_data_type *mfd);
 void mdss_fb_wait_for_fence(struct msm_sync_pt_data *sync_pt_data);
 void mdss_fb_signal_timeline(struct msm_sync_pt_data *sync_pt_data);
+struct sync_fence *mdss_fb_sync_get_fence(struct sw_sync_timeline *timeline,
+				const char *fence_name, int val);
 int mdss_fb_register_mdp_instance(struct msm_mdp_interface *mdp);
 int mdss_fb_dcm(struct msm_fb_data_type *mfd, int req_state);
+int mdss_fb_suspres_panel(struct device *dev, void *data);
 #endif /* MDSS_FB_H */
diff --git a/drivers/video/msm/mdss/mdss_hdmi_cec.c b/drivers/video/msm/mdss/mdss_hdmi_cec.c
index 410f2b3..9d85070 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_cec.c
+++ b/drivers/video/msm/mdss/mdss_hdmi_cec.c
@@ -366,7 +366,7 @@
 	DSS_REG_W(io, HDMI_CEC_CTRL, BIT(0) | BIT(1) |
 		((msg->frame_size & 0x1F) << 4) | BIT(9));
 
-	if (!wait_for_completion_interruptible_timeout(
+	if (!wait_for_completion_timeout(
 		&cec_ctrl->cec_msg_wr_done, HZ)) {
 		DEV_ERR("%s: timedout", __func__);
 		hdmi_cec_dump_msg(cec_ctrl, msg);
diff --git a/drivers/video/msm/mdss/mdss_hdmi_edid.c b/drivers/video/msm/mdss/mdss_hdmi_edid.c
index a45876b..d0b89a3 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_edid.c
+++ b/drivers/video/msm/mdss/mdss_hdmi_edid.c
@@ -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
@@ -1120,7 +1120,7 @@
 	u8 i = 0, offset = 0, std_blk = 0;
 	u32 video_format = HDMI_VFRMT_640x480p60_4_3;
 	u32 has480p = false;
-	u8 len;
+	u8 len = 0;
 	int rc;
 	const u8 *edid_blk0 = NULL;
 	const u8 *edid_blk1 = NULL;
@@ -1140,7 +1140,7 @@
 		hdmi_edid_find_block(data_buf+0x80, DBC_START_OFFSET,
 			VIDEO_DATA_BLOCK, &len) : NULL;
 
-	if (svd == NULL || len == 0 || len > MAX_DATA_BLOCK_SIZE) {
+	if (num_of_cea_blocks && (len == 0 || len > MAX_DATA_BLOCK_SIZE)) {
 		DEV_DBG("%s: No/Invalid Video Data Block\n",
 			__func__);
 		return;
diff --git a/drivers/video/msm/mdss/mdss_hdmi_hdcp.c b/drivers/video/msm/mdss/mdss_hdmi_hdcp.c
index 8ff9059..2240941 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_hdcp.c
+++ b/drivers/video/msm/mdss/mdss_hdmi_hdcp.c
@@ -520,7 +520,7 @@
 	/* Write R0' to HDCP registers and check to see if it is a match */
 	INIT_COMPLETION(hdcp_ctrl->r0_checked);
 	DSS_REG_W(io, HDMI_HDCP_RCVPORT_DATA2_0, (((u32)buf[1]) << 8) | buf[0]);
-	timeout_count = wait_for_completion_interruptible_timeout(
+	timeout_count = wait_for_completion_timeout(
 		&hdcp_ctrl->r0_checked, HZ*2);
 	link0_status = DSS_REG_R(io, HDMI_HDCP_LINK0_STATUS);
 	is_match = link0_status & BIT(12);
@@ -1050,7 +1050,10 @@
 	}
 
 	if (++hdcp_ctrl->auth_retries == AUTH_RETRIES_TIME) {
-		hdmi_hdcp_off(hdcp_ctrl);
+		mutex_lock(hdcp_ctrl->init_data.mutex);
+		hdcp_ctrl->hdcp_state = HDCP_STATE_INACTIVE;
+		mutex_unlock(hdcp_ctrl->init_data.mutex);
+
 		hdcp_ctrl->auth_retries = 0;
 		ret = -ERANGE;
 	}
@@ -1077,13 +1080,6 @@
 		return 0;
 	}
 
-	ret = hdmi_msm_if_abort_reauth(hdcp_ctrl);
-
-	if (ret) {
-		DEV_ERR("%s: abort reauthentication!\n", __func__);
-		return ret;
-	}
-
 	/*
 	 * Disable HPD circuitry.
 	 * This is needed to reset the HDCP cipher engine so that when we
@@ -1109,6 +1105,13 @@
 		DSS_REG_R(hdcp_ctrl->init_data.core_io,
 		HDMI_HPD_CTRL) | BIT(28));
 
+	ret = hdmi_msm_if_abort_reauth(hdcp_ctrl);
+
+	if (ret) {
+		DEV_ERR("%s: abort reauthentication!\n", __func__);
+		return ret;
+	}
+
 	/* Restart authentication attempt */
 	DEV_DBG("%s: %s: Scheduling work to start HDCP authentication",
 		__func__, HDCP_STATE_NAME);
diff --git a/drivers/video/msm/mdss/mdss_hdmi_tx.c b/drivers/video/msm/mdss/mdss_hdmi_tx.c
index b45a446..2b409f5 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_tx.c
+++ b/drivers/video/msm/mdss/mdss_hdmi_tx.c
@@ -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
@@ -20,6 +20,7 @@
 #include <linux/of_gpio.h>
 #include <linux/of_platform.h>
 #include <linux/types.h>
+#include <linux/msm_hdmi.h>
 #include <mach/msm_hdmi_audio_codec.h>
 
 #define REG_DUMP 0
@@ -70,6 +71,24 @@
 #define MSM_HDMI_AUDIO_CHANNEL_7	7
 #define MSM_HDMI_AUDIO_CHANNEL_8	8
 
+#define NUM_MODES_AVI 20
+
+/* AVI Infoframe data byte 3, bit 7 (msb) represents ITC bit */
+#define SET_ITC_BIT(byte)  (byte = (byte | BIT(7)))
+#define CLR_ITC_BIT(byte)  (byte = (byte & ~BIT(7)))
+
+/*
+ * CN represents IT content type, if ITC bit in infoframe data byte 3
+ * is set, CN bits will represent content type as below:
+ * 0b00 Graphics
+ * 0b01 Photo
+ * 0b10 Cinema
+ * 0b11 Game
+*/
+#define CONFIG_CN_BITS(bits, byte) \
+		(byte = (byte & ~(BIT(4) | BIT(5))) |\
+			((bits & (BIT(0) | BIT(1))) << 4))
+
 enum msm_hdmi_supported_audio_sample_rates {
 	AUDIO_SAMPLE_RATE_32KHZ,
 	AUDIO_SAMPLE_RATE_44_1KHZ,
@@ -101,6 +120,7 @@
 static inline void hdmi_tx_set_audio_switch_node(struct hdmi_tx_ctrl *hdmi_ctrl,
 	int val, bool force);
 static int hdmi_tx_audio_setup(struct hdmi_tx_ctrl *hdmi_ctrl);
+static void hdmi_tx_en_encryption(struct hdmi_tx_ctrl *hdmi_ctrl, u32 on);
 
 struct mdss_hw hdmi_tx_hw = {
 	.hw_ndx = MDSS_HW_HDMI,
@@ -115,6 +135,7 @@
 };
 
 struct dss_gpio ddc_gpio_config[] = {
+	{0, 1, COMPATIBLE_NAME "-ddc-mux-sel"},
 	{0, 1, COMPATIBLE_NAME "-ddc-clk"},
 	{0, 1, COMPATIBLE_NAME "-ddc-data"}
 };
@@ -137,12 +158,6 @@
 	}
 } /* hdmi_pm_name */
 
-static DEFINE_MUTEX(avi_iframe_lut_lock);
-#define NUM_MODES_AVI 20
-#define SET_ITC_BIT(byte)  (byte | 0x80)
-#define CLR_ITC_BIT(byte)  (byte & 0x7F)
-#define CONFIG_CN_BITS(bits, byte)  ((byte & ~(0x03 << 4)) | (bits << 4))
-
 static u8 hdmi_tx_avi_iframe_lut[][NUM_MODES_AVI] = {
 	{0x10,	0x10,	0x10,	0x10,	0x10,	0x10,	0x10,	0x10,	0x10,
 	 0x10,	0x10,	0x10,	0x10,	0x10,	0x10,	0x10,	0x10,	0x10,
@@ -210,54 +225,76 @@
 		{20480, 247500} } },
 };
 
-/* To statically config ITC bit from sysfs attribute */
-static int hdmi_tx_config_itc_bit(int itc)
+int register_hdmi_cable_notification(struct hdmi_cable_notify *handler)
 {
-	int ret = 0, loop = NUM_MODES_AVI;
+	struct hdmi_tx_ctrl *hdmi_ctrl = NULL;
+	struct list_head *pos;
 
-	if (mutex_lock_interruptible(&avi_iframe_lut_lock)) {
-		ret = -ERESTARTSYS;
-		goto signal_intr;
+	if (!hdmi_tx_hw.ptr) {
+		DEV_WARN("%s: HDMI Tx core not ready\n", __func__);
+		return -EPROBE_DEFER;
 	}
 
-	do {
-		--loop;
-		if (itc == 0)
-			hdmi_tx_avi_iframe_lut[2][loop] =
-				CLR_ITC_BIT(hdmi_tx_avi_iframe_lut[2][loop]);
-		if (itc == 1)
-			hdmi_tx_avi_iframe_lut[2][loop] =
-				SET_ITC_BIT(hdmi_tx_avi_iframe_lut[2][loop]);
-	} while (loop);
-
-	mutex_unlock(&avi_iframe_lut_lock);
-
-signal_intr:
-	return ret;
-}
-
-/* To configure CN0_1 bits from sysfs attribute */
-static int hdmi_tx_config_cn_bits(int cns)
-{
-	int ret = 0, loop = NUM_MODES_AVI;
-
-	if (mutex_lock_interruptible(&avi_iframe_lut_lock)) {
-		ret = -ERESTARTSYS;
-		goto signal_intr;
+	if (!handler) {
+		DEV_ERR("%s: Empty handler\n", __func__);
+		return -ENODEV;
 	}
 
-	do {
-		--loop;
-		hdmi_tx_avi_iframe_lut[4][loop] =
-			CONFIG_CN_BITS(cns, hdmi_tx_avi_iframe_lut[4][loop]);
-	} while (loop);
+	hdmi_ctrl = (struct hdmi_tx_ctrl *) hdmi_tx_hw.ptr;
 
-	mutex_unlock(&avi_iframe_lut_lock);
+	mutex_lock(&hdmi_ctrl->cable_notify_mutex);
+	handler->status = hdmi_ctrl->hpd_state;
+	list_for_each(pos, &hdmi_ctrl->cable_notify_handlers);
+	list_add_tail(&handler->link, pos);
+	mutex_unlock(&hdmi_ctrl->cable_notify_mutex);
 
-signal_intr:
-	return ret;
-}
+	return handler->status;
+} /* register_hdmi_cable_notification */
 
+int unregister_hdmi_cable_notification(struct hdmi_cable_notify *handler)
+{
+	struct hdmi_tx_ctrl *hdmi_ctrl = NULL;
+
+	if (!hdmi_tx_hw.ptr) {
+		DEV_WARN("%s: HDMI Tx core not ready\n", __func__);
+		return -ENODEV;
+	}
+
+	if (!handler) {
+		DEV_ERR("%s: Empty handler\n", __func__);
+		return -ENODEV;
+	}
+
+	hdmi_ctrl = (struct hdmi_tx_ctrl *) hdmi_tx_hw.ptr;
+
+	mutex_lock(&hdmi_ctrl->cable_notify_mutex);
+	list_del(&handler->link);
+	mutex_unlock(&hdmi_ctrl->cable_notify_mutex);
+
+	return 0;
+} /* unregister_hdmi_cable_notification */
+
+static void hdmi_tx_cable_notify_work(struct work_struct *work)
+{
+	struct hdmi_tx_ctrl *hdmi_ctrl = NULL;
+	struct hdmi_cable_notify *pos;
+
+	hdmi_ctrl = container_of(work, struct hdmi_tx_ctrl, cable_notify_work);
+
+	if (!hdmi_ctrl) {
+		DEV_ERR("%s: invalid hdmi data\n", __func__);
+		return;
+	}
+
+	mutex_lock(&hdmi_ctrl->cable_notify_mutex);
+	list_for_each_entry(pos, &hdmi_ctrl->cable_notify_handlers, link) {
+		if (pos->status != hdmi_ctrl->hpd_state) {
+			pos->status = hdmi_ctrl->hpd_state;
+			pos->hpd_notify(pos);
+		}
+	}
+	mutex_unlock(&hdmi_ctrl->cable_notify_mutex);
+} /* hdmi_tx_cable_notify_work */
 
 static bool hdmi_tx_is_cea_format(int mode)
 {
@@ -364,6 +401,9 @@
 
 	if (!hdmi_ctrl->pdata.primary && (hdmi_ctrl->sdev.state != val))
 		switch_set_state(&hdmi_ctrl->sdev, val);
+
+	/* Notify all registered modules of cable connection status */
+	schedule_work(&hdmi_ctrl->cable_notify_work);
 } /* hdmi_tx_send_cable_notification */
 
 static inline u32 hdmi_tx_is_dvi_mode(struct hdmi_tx_ctrl *hdmi_ctrl)
@@ -682,53 +722,80 @@
 	struct device_attribute *attr, const char *buf, size_t count)
 {
 	ssize_t ret = strnlen(buf, PAGE_SIZE);
-	int err = 0;
-	int itc = 0, rc = 0;
+	u8 *avi_byte3 = hdmi_tx_avi_iframe_lut[2];
+	struct hdmi_tx_ctrl *hdmi_ctrl = NULL;
+	int loop = 0, itc = 0, rc = 0;
+
+	hdmi_ctrl = hdmi_tx_get_drvdata_from_sysfs_dev(dev);
+
+	if (!hdmi_ctrl) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		return -EINVAL;
+	}
 
 	rc = kstrtoint(buf, 10, &itc);
 	if (rc) {
-		DEV_ERR("%s: kstrtoint failed. rc=%d\n", __func__, rc);
+		DEV_ERR("%s: kstrtoint failed. rc =%d\n", __func__, rc);
 		return rc;
 	}
 
-	if (itc == 0 || itc == 1) {
-		if (hdmi_tx_config_itc_bit(itc))
-			ret = err;
-		else
-			DEV_DBG("%s: '%d is configured'!\n", __func__, itc);
-	} else {
-		DEV_ERR("%s: unknown ITC '%d', should be either 0 or 1\n",
-				__func__, itc);
+	if (itc < 0 || itc > 1) {
+		DEV_ERR("%s: Invalid ITC %d\n", __func__, itc);
+		return ret;
 	}
 
+	if (mutex_lock_interruptible(&hdmi_ctrl->lut_lock))
+		return -ERESTARTSYS;
+
+	for (loop = 0; loop < NUM_MODES_AVI; loop++) {
+		if (itc)
+			SET_ITC_BIT(avi_byte3[loop]);
+		else
+			CLR_ITC_BIT(avi_byte3[loop]);
+	}
+
+	mutex_unlock(&hdmi_ctrl->lut_lock);
+
 	return ret;
 } /* hdmi_tx_sysfs_wta_avi_itc */
 
-static ssize_t hdmi_tx_sysfs_wta_avi_cn0_1(struct device *dev,
+static ssize_t hdmi_tx_sysfs_wta_avi_cn_bits(struct device *dev,
 	struct device_attribute *attr, const char *buf, size_t count)
 {
 	ssize_t ret = strnlen(buf, PAGE_SIZE);
-	int err = 0;
-	int cns = 0, rc = 0;
+	u8 *avi_byte5 = hdmi_tx_avi_iframe_lut[4];
+	struct hdmi_tx_ctrl *hdmi_ctrl = NULL;
+	int loop = 0, cn_bits = 0, rc = 0;
 
-	rc = kstrtoint(buf, 10, &cns);
+	hdmi_ctrl = hdmi_tx_get_drvdata_from_sysfs_dev(dev);
+
+	if (!hdmi_ctrl) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		return -EINVAL;
+	}
+
+	rc = kstrtoint(buf, 10, &cn_bits);
 	if (rc) {
 		DEV_ERR("%s: kstrtoint failed. rc=%d\n", __func__, rc);
 		return rc;
 	}
 
-	if (cns == 0 || cns == 1 || cns == 2 || cns == 3) {
-		if (hdmi_tx_config_cn_bits(cns))
-			ret = err;
-		else
-			DEV_DBG("%s: '%d is configured'!\n", __func__, cns);
-	} else {
-		DEV_ERR("%s: unknown CN '%d' should be either 0 or 1, 2 ,3\n",
-				__func__, cns);
+	/* As per CEA-861-E, CN is a positive number and can be max 3 */
+	if (cn_bits < 0 || cn_bits > 3) {
+		DEV_ERR("%s: Invalid CN %d\n", __func__, cn_bits);
+		return ret;
 	}
 
+	if (mutex_lock_interruptible(&hdmi_ctrl->lut_lock))
+		return -ERESTARTSYS;
+
+	for (loop = 0; loop < NUM_MODES_AVI; loop++)
+		CONFIG_CN_BITS(cn_bits, avi_byte5[loop]);
+
+	mutex_unlock(&hdmi_ctrl->lut_lock);
+
 	return ret;
-} /* hdmi_tx_sysfs_wta_avi_cn0_1 */
+} /* hdmi_tx_sysfs_wta_cn_bits */
 
 static DEVICE_ATTR(connected, S_IRUGO, hdmi_tx_sysfs_rda_connected, NULL);
 static DEVICE_ATTR(hpd, S_IRUGO | S_IWUSR, hdmi_tx_sysfs_rda_hpd,
@@ -739,7 +806,7 @@
 	hdmi_tx_sysfs_rda_product_description,
 	hdmi_tx_sysfs_wta_product_description);
 static DEVICE_ATTR(avi_itc, S_IWUSR, NULL, hdmi_tx_sysfs_wta_avi_itc);
-static DEVICE_ATTR(avi_cn0_1, S_IWUSR, NULL, hdmi_tx_sysfs_wta_avi_cn0_1);
+static DEVICE_ATTR(avi_cn0_1, S_IWUSR, NULL, hdmi_tx_sysfs_wta_avi_cn_bits);
 
 static struct attribute *hdmi_tx_fs_attrs[] = {
 	&dev_attr_connected.attr,
@@ -850,11 +917,11 @@
 	switch (status) {
 	case HDCP_STATE_AUTHENTICATED:
 		if (hdmi_ctrl->hpd_state) {
-			/* Clear AV Mute */
-			rc = hdmi_tx_config_avmute(hdmi_ctrl, 0);
-			if (rc)
-				DEV_ERR("%s: Failed to clear av mute. rc=%d\n",
-					__func__, rc);
+			if (hdmi_ctrl->pdata.primary)
+				hdmi_tx_en_encryption(hdmi_ctrl, true);
+			else
+				/* Clear AV Mute */
+				rc = hdmi_tx_config_avmute(hdmi_ctrl, 0);
 			hdmi_tx_set_audio_switch_node(hdmi_ctrl, 1, false);
 		}
 		break;
@@ -862,11 +929,11 @@
 		hdmi_tx_set_audio_switch_node(hdmi_ctrl, 0, false);
 
 		if (hdmi_ctrl->hpd_state) {
-			/* Set AV Mute */
-			rc = hdmi_tx_config_avmute(hdmi_ctrl, 1);
-			if (rc)
-				DEV_ERR("%s: Failed to set av mute. rc=%d\n",
-					__func__, rc);
+			if (hdmi_ctrl->pdata.primary)
+				hdmi_tx_en_encryption(hdmi_ctrl, false);
+			else
+				/* Set AV Mute */
+				rc = hdmi_tx_config_avmute(hdmi_ctrl, 1);
 
 			DEV_DBG("%s: Reauthenticating\n", __func__);
 			rc = hdmi_hdcp_reauthenticate(
@@ -1060,6 +1127,17 @@
 	DEV_DBG("%s: Got HPD interrupt\n", __func__);
 
 	if (hdmi_ctrl->hpd_state) {
+		/*
+		 * If a down stream device or bridge chip is attached to hdmi
+		 * Tx core output, it is likely that it might be powering the
+		 * hpd module ON/OFF on cable connect/disconnect as it would
+		 * have its own mechanism of detecting cable. Flush power off
+		 * work is needed in case there is any race condidtion between
+		 * power off and on during fast cable plug in/out.
+		 */
+		if (hdmi_ctrl->ds_registered)
+			flush_work(&hdmi_ctrl->power_off_work);
+
 		if (hdmi_tx_enable_power(hdmi_ctrl, HDMI_TX_DDC_PM, true)) {
 			DEV_ERR("%s: Failed to enable ddc power\n", __func__);
 			return;
@@ -1076,6 +1154,13 @@
 		hdmi_tx_set_audio_switch_node(hdmi_ctrl, 0, false);
 		hdmi_tx_wait_for_audio_engine(hdmi_ctrl);
 
+		if (!hdmi_ctrl->panel_power_on) {
+			if (hdmi_tx_enable_power(hdmi_ctrl, HDMI_TX_DDC_PM,
+				false))
+				DEV_WARN("%s: Failed to disable ddc power\n",
+					__func__);
+		}
+
 		hdmi_tx_send_cable_notification(hdmi_ctrl, 0);
 		DEV_INFO("%s: sense cable DISCONNECTED: state switch to %d\n",
 			__func__, hdmi_ctrl->sdev.state);
@@ -1580,6 +1665,28 @@
 	DSS_REG_W(io, HDMI_GEN_PKT_CTRL, packet_control);
 } /* hdmi_tx_set_spd_infoframe */
 
+static void hdmi_tx_en_encryption(struct hdmi_tx_ctrl *hdmi_ctrl, u32 on)
+{
+	u32 reg_val;
+	struct dss_io_data *io = NULL;
+
+	if (!hdmi_ctrl->hdcp_feature_on || !hdmi_ctrl->present_hdcp)
+		return;
+
+	io = &hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO];
+
+	mutex_lock(&hdmi_ctrl->mutex);
+	reg_val = DSS_REG_R_ND(io, HDMI_CTRL);
+
+	if (on)
+		reg_val |= BIT(2);
+	else
+		reg_val &= ~BIT(2);
+	DSS_REG_W(io, HDMI_CTRL, reg_val);
+
+	mutex_unlock(&hdmi_ctrl->mutex);
+} /* hdmi_tx_en_encryption */
+
 static void hdmi_tx_set_mode(struct hdmi_tx_ctrl *hdmi_ctrl, u32 power_on)
 {
 	struct dss_io_data *io = NULL;
@@ -1596,12 +1703,14 @@
 		return;
 	}
 
+	mutex_lock(&hdmi_ctrl->mutex);
 	if (power_on) {
 		/* Enable the block */
 		reg_val |= BIT(0);
 
 		/* HDMI Encryption, if HDCP is enabled */
-		if (hdmi_ctrl->hdcp_feature_on && hdmi_ctrl->present_hdcp)
+		if (hdmi_ctrl->hdcp_feature_on &&
+			hdmi_ctrl->present_hdcp && !hdmi_ctrl->pdata.primary)
 			reg_val |= BIT(2);
 
 		/* Set transmission mode to DVI based in EDID info */
@@ -1611,6 +1720,7 @@
 	}
 
 	DSS_REG_W(io, HDMI_CTRL, reg_val);
+	mutex_unlock(&hdmi_ctrl->mutex);
 
 	DEV_DBG("HDMI Core: %s, HDMI_CTRL=0x%08x\n",
 		power_on ? "Enable" : "Disable", reg_val);
@@ -2252,6 +2362,8 @@
 	ops->set_mhl_max_pclk = hdmi_tx_set_mhl_max_pclk;
 	ops->set_upstream_hpd = hdmi_tx_set_mhl_hpd;
 
+	hdmi_ctrl->ds_registered = true;
+
 	return 0;
 }
 
@@ -2546,7 +2658,7 @@
 	flush_work_sync(&hdmi_ctrl->power_off_work);
 
 	if (hdmi_ctrl->pdata.primary) {
-		timeout = wait_for_completion_interruptible_timeout(
+		timeout = wait_for_completion_timeout(
 			&hdmi_ctrl->hpd_done, HZ);
 		if (!timeout) {
 			DEV_ERR("%s: cable connection hasn't happened yet\n",
@@ -2576,6 +2688,11 @@
 	hdmi_ctrl->panel_power_on = true;
 	mutex_unlock(&hdmi_ctrl->mutex);
 
+	if (hdmi_ctrl->pdata.primary) {
+		if (hdmi_tx_enable_power(hdmi_ctrl, HDMI_TX_DDC_PM, true))
+			DEV_ERR("%s: Failed to enable ddc power\n", __func__);
+	}
+
 	hdmi_cec_config(hdmi_ctrl->feature_data[HDMI_TX_FEAT_CEC]);
 
 	if (hdmi_ctrl->hpd_state) {
@@ -2844,6 +2961,8 @@
 	switch_dev_unregister(&hdmi_ctrl->sdev);
 	if (hdmi_ctrl->workq)
 		destroy_workqueue(hdmi_ctrl->workq);
+	mutex_destroy(&hdmi_ctrl->lut_lock);
+	mutex_destroy(&hdmi_ctrl->cable_notify_mutex);
 	mutex_destroy(&hdmi_ctrl->mutex);
 
 	hdmi_tx_hw.ptr = NULL;
@@ -2872,6 +2991,11 @@
 
 	hdmi_setup_video_mode_lut();
 	mutex_init(&hdmi_ctrl->mutex);
+	mutex_init(&hdmi_ctrl->lut_lock);
+	mutex_init(&hdmi_ctrl->cable_notify_mutex);
+
+	INIT_LIST_HEAD(&hdmi_ctrl->cable_notify_handlers);
+
 	hdmi_ctrl->workq = create_workqueue("hdmi_tx_workq");
 	if (!hdmi_ctrl->workq) {
 		DEV_ERR("%s: hdmi_tx_workq creation failed.\n", __func__);
@@ -2889,8 +3013,9 @@
 	hdmi_ctrl->hpd_initialized = false;
 	hdmi_ctrl->hpd_off_pending = false;
 	init_completion(&hdmi_ctrl->hpd_done);
-	INIT_WORK(&hdmi_ctrl->hpd_int_work, hdmi_tx_hpd_int_work);
 
+	INIT_WORK(&hdmi_ctrl->hpd_int_work, hdmi_tx_hpd_int_work);
+	INIT_WORK(&hdmi_ctrl->cable_notify_work, hdmi_tx_cable_notify_work);
 	INIT_WORK(&hdmi_ctrl->power_off_work, hdmi_tx_power_off_work);
 
 	spin_lock_init(&hdmi_ctrl->hpd_state_lock);
@@ -2920,6 +3045,7 @@
 fail_create_workq:
 	if (hdmi_ctrl->workq)
 		destroy_workqueue(hdmi_ctrl->workq);
+	mutex_destroy(&hdmi_ctrl->lut_lock);
 	mutex_destroy(&hdmi_ctrl->mutex);
 fail_no_hdmi:
 	return rc;
@@ -3010,7 +3136,7 @@
 			u32 timeout;
 			hdmi_ctrl->panel_suspend = false;
 
-			timeout = wait_for_completion_interruptible_timeout(
+			timeout = wait_for_completion_timeout(
 				&hdmi_ctrl->hpd_done, HZ/10);
 			if (!timeout & !hdmi_ctrl->hpd_state) {
 				DEV_INFO("%s: cable removed during suspend\n",
@@ -3034,10 +3160,10 @@
 	case MDSS_EVENT_PANEL_ON:
 		if (hdmi_ctrl->hdcp_feature_on && hdmi_ctrl->present_hdcp) {
 			/* Set AV Mute before starting authentication */
-			rc = hdmi_tx_config_avmute(hdmi_ctrl, 1);
-			if (rc)
-				DEV_ERR("%s: Failed to set av mute. rc=%d\n",
-					__func__, rc);
+			if (hdmi_ctrl->pdata.primary)
+				hdmi_tx_en_encryption(hdmi_ctrl, false);
+			else
+				rc = hdmi_tx_config_avmute(hdmi_ctrl, 1);
 
 			DEV_DBG("%s: Starting HDCP authentication\n", __func__);
 			rc = hdmi_hdcp_authenticate(
@@ -3766,6 +3892,7 @@
 
 static const struct of_device_id hdmi_tx_dt_match[] = {
 	{.compatible = COMPATIBLE_NAME,},
+	{ /* Sentinel */ },
 };
 MODULE_DEVICE_TABLE(of, hdmi_tx_dt_match);
 
diff --git a/drivers/video/msm/mdss/mdss_hdmi_tx.h b/drivers/video/msm/mdss/mdss_hdmi_tx.h
index 66071e9..54d80dc 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_tx.h
+++ b/drivers/video/msm/mdss/mdss_hdmi_tx.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
@@ -54,6 +54,9 @@
 	struct hdmi_audio audio_data;
 
 	struct mutex mutex;
+	struct mutex lut_lock;
+	struct mutex cable_notify_mutex;
+	struct list_head cable_notify_handlers;
 	struct kobject *kobj;
 	struct switch_dev sdev;
 	struct switch_dev audio_sdev;
@@ -77,8 +80,10 @@
 	struct work_struct hpd_int_work;
 
 	struct work_struct power_off_work;
+	struct work_struct cable_notify_work;
 
 	bool hdcp_feature_on;
+	bool ds_registered;
 	u32 present_hdcp;
 
 	u8 spd_vendor_name[9];
diff --git a/drivers/video/msm/mdss/mdss_hdmi_util.c b/drivers/video/msm/mdss/mdss_hdmi_util.c
index 711ec68..6f6c805 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_util.c
+++ b/drivers/video/msm/mdss/mdss_hdmi_util.c
@@ -46,6 +46,7 @@
 int hdmi_get_video_id_code(struct msm_hdmi_mode_timing_info *timing_in)
 {
 	int i, vic = -1;
+	struct msm_hdmi_mode_timing_info *supported_timing;
 
 	if (!timing_in) {
 		DEV_ERR("%s: invalid input\n", __func__);
@@ -54,8 +55,7 @@
 
 	/* active_low_h, active_low_v and interlaced are not checked against */
 	for (i = 0; i < HDMI_VFRMT_MAX; i++) {
-		struct msm_hdmi_mode_timing_info *supported_timing =
-			&hdmi_supported_video_mode_lut[i];
+		supported_timing = &hdmi_supported_video_mode_lut[i];
 
 		if (!supported_timing->supported)
 			continue;
@@ -84,8 +84,24 @@
 		break;
 	}
 
-	if (vic < 0)
-		DEV_ERR("%s: timing asked is not yet supported\n", __func__);
+	if (vic < 0) {
+		for (i = 0; i < HDMI_VFRMT_MAX; i++) {
+			supported_timing = &hdmi_supported_video_mode_lut[i];
+			if (!supported_timing->supported)
+				continue;
+			if (timing_in->active_h != supported_timing->active_h)
+				continue;
+			if (timing_in->active_v != supported_timing->active_v)
+				continue;
+			vic = (int)supported_timing->video_format;
+			break;
+		}
+	}
+
+	if (vic < 0) {
+		DEV_ERR("%s: timing is not supported h=%d v=%d\n",
+			__func__, timing_in->active_h, timing_in->active_v);
+	}
 
 exit:
 	DEV_DBG("%s: vic = %d timing = %s\n", __func__, vic,
@@ -296,7 +312,7 @@
 	INIT_COMPLETION(ddc_ctrl->ddc_sw_done);
 	DSS_REG_W_ND(ddc_ctrl->io, HDMI_DDC_CTRL, BIT(0) | BIT(20));
 
-	time_out_count = wait_for_completion_interruptible_timeout(
+	time_out_count = wait_for_completion_timeout(
 		&ddc_ctrl->ddc_sw_done, HZ/2);
 	DSS_REG_W_ND(ddc_ctrl->io, HDMI_DDC_INT_CTRL, BIT(1));
 	if (!time_out_count) {
@@ -547,7 +563,7 @@
 	INIT_COMPLETION(ddc_ctrl->ddc_sw_done);
 	DSS_REG_W_ND(ddc_ctrl->io, HDMI_DDC_CTRL, BIT(0) | BIT(21));
 
-	time_out_count = wait_for_completion_interruptible_timeout(
+	time_out_count = wait_for_completion_timeout(
 		&ddc_ctrl->ddc_sw_done, HZ/2);
 
 	reg_val = DSS_REG_R(ddc_ctrl->io, HDMI_DDC_INT_CTRL);
@@ -721,7 +737,7 @@
 	INIT_COMPLETION(ddc_ctrl->ddc_sw_done);
 	DSS_REG_W_ND(ddc_ctrl->io, HDMI_DDC_CTRL, BIT(0) | BIT(20));
 
-	time_out_count = wait_for_completion_interruptible_timeout(
+	time_out_count = wait_for_completion_timeout(
 		&ddc_ctrl->ddc_sw_done, HZ/2);
 
 	reg_val = DSS_REG_R(ddc_ctrl->io, HDMI_DDC_INT_CTRL);
diff --git a/drivers/video/msm/mdss/mdss_mdp.c b/drivers/video/msm/mdss/mdss_mdp.c
index 3269eec..97d4dc9 100644
--- a/drivers/video/msm/mdss/mdss_mdp.c
+++ b/drivers/video/msm/mdss/mdss_mdp.c
@@ -1,7 +1,7 @@
 /*
  * MDSS MDP Interface (used by framebuffer core)
  *
- * Copyright (c) 2007-2013, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2007-2014, The Linux Foundation. All rights reserved.
  * Copyright (C) 2007 Google Incorporated
  *
  * This software is licensed under the terms of the GNU General Public
@@ -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
@@ -80,21 +81,7 @@
 static DEFINE_SPINLOCK(mdp_lock);
 static DEFINE_MUTEX(mdp_clk_lock);
 static DEFINE_MUTEX(bus_bw_lock);
-
-#define MDP_BUS_VECTOR_ENTRY(ab_val, ib_val)		\
-	{						\
-		.src = MSM_BUS_MASTER_MDP_PORT0,	\
-		.dst = MSM_BUS_SLAVE_EBI_CH0,		\
-		.ab = (ab_val),				\
-		.ib = (ib_val),				\
-	}
-
-static struct msm_bus_vectors mdp_bus_vectors[] = {
-	MDP_BUS_VECTOR_ENTRY(0, 0),
-	MDP_BUS_VECTOR_ENTRY(SZ_128M, SZ_256M),
-	MDP_BUS_VECTOR_ENTRY(SZ_256M, SZ_512M),
-};
-static struct msm_bus_paths mdp_bus_usecases[ARRAY_SIZE(mdp_bus_vectors)];
+static DEFINE_MUTEX(mdp_iommu_lock);
 
 static struct mdss_panel_intf pan_types[] = {
 	{"dsi", MDSS_PANEL_INTF_DSI},
@@ -102,12 +89,6 @@
 	{"hdmi", MDSS_PANEL_INTF_HDMI},
 };
 
-static struct msm_bus_scale_pdata mdp_bus_scale_table = {
-	.usecase = mdp_bus_usecases,
-	.num_usecases = ARRAY_SIZE(mdp_bus_usecases),
-	.name = "mdss_mdp",
-};
-
 struct mdss_iommu_map_type mdss_iommu_map[MDSS_IOMMU_MAX_DOMAIN] = {
 	[MDSS_IOMMU_DOMAIN_UNSECURE] = {
 		.client_name = "mdp_ns",
@@ -153,8 +134,10 @@
 static int mdss_mdp_parse_dt_prop_len(struct platform_device *pdev,
 				       char *prop_name);
 static int mdss_mdp_parse_dt_smp(struct platform_device *pdev);
+static int mdss_mdp_parse_dt_prefill(struct platform_device *pdev);
 static int mdss_mdp_parse_dt_misc(struct platform_device *pdev);
 static int mdss_mdp_parse_dt_ad_cfg(struct platform_device *pdev);
+static int mdss_mdp_parse_dt_bus_scale(struct platform_device *pdev);
 
 u32 mdss_mdp_fb_stride(u32 fb_index, u32 xres, int bpp)
 {
@@ -314,6 +297,7 @@
 	pr_debug("Disable HW=%d irq ena=%d mask=%x\n", hw->hw_ndx,
 			mdss_res->irq_ena, mdss_res->irq_mask);
 
+	spin_lock(&mdss_lock);
 	if (!(mdss_res->irq_mask & ndx_bit)) {
 		pr_warn("MDSS HW ndx=%d is NOT set, mask=%x, hist mask=%x\n",
 			hw->hw_ndx, mdss_res->mdp_irq_mask,
@@ -325,29 +309,24 @@
 			disable_irq_nosync(mdss_res->irq);
 		}
 	}
+	spin_unlock(&mdss_lock);
 }
 EXPORT_SYMBOL(mdss_disable_irq_nosync);
 
 static int mdss_mdp_bus_scale_register(struct mdss_data_type *mdata)
 {
 	if (!mdata->bus_hdl) {
-		struct msm_bus_scale_pdata *bus_pdata = &mdp_bus_scale_table;
-		int i;
-
-		for (i = 0; i < bus_pdata->num_usecases; i++) {
-			mdp_bus_usecases[i].num_paths = 1;
-			mdp_bus_usecases[i].vectors = &mdp_bus_vectors[i];
-		}
-
-		mdata->bus_hdl = msm_bus_scale_register_client(bus_pdata);
-		if (!mdata->bus_hdl) {
-			pr_err("not able to get bus scale\n");
-			return -ENOMEM;
+		mdata->bus_hdl =
+			msm_bus_scale_register_client(mdata->bus_scale_table);
+		if (IS_ERR_VALUE(mdata->bus_hdl)) {
+			pr_err("bus_client register failed\n");
+			return -EINVAL;
 		}
 
 		pr_debug("register bus_hdl=%x\n", mdata->bus_hdl);
 	}
-	return 0;
+
+	return mdss_mdp_bus_scale_set_quota(AB_QUOTA, IB_QUOTA);
 }
 
 static void mdss_mdp_bus_scale_unregister(struct mdss_data_type *mdata)
@@ -360,7 +339,7 @@
 
 int mdss_mdp_bus_scale_set_quota(u64 ab_quota, u64 ib_quota)
 {
-	int bus_idx;
+	int new_uc_idx;
 
 	if (mdss_res->bus_hdl < 1) {
 		pr_err("invalid bus handle %d\n", mdss_res->bus_hdl);
@@ -368,32 +347,50 @@
 	}
 
 	if ((ab_quota | ib_quota) == 0) {
-		bus_idx = 0;
+		new_uc_idx = 0;
 	} else {
-		int num_cases = mdp_bus_scale_table.num_usecases;
+		int i;
 		struct msm_bus_vectors *vect = NULL;
+		struct msm_bus_scale_pdata *bw_table =
+			mdss_res->bus_scale_table;
+		unsigned long size;
 
-		bus_idx = (mdss_res->current_bus_idx % (num_cases - 1)) + 1;
-
-		vect = mdp_bus_scale_table.usecase[mdss_res->current_bus_idx].
-			vectors;
-
-		/* avoid performing updates for small changes */
-		if ((ALIGN(ab_quota, SZ_64M) == ALIGN(vect->ab, SZ_64M)) &&
-			(ALIGN(ib_quota, SZ_64M) == ALIGN(vect->ib, SZ_64M))) {
-			pr_debug("skip bus scaling, no change in vectors\n");
-			return 0;
+		if (!bw_table || !mdss_res->axi_port_cnt) {
+			pr_err("invalid input\n");
+			return -EINVAL;
 		}
 
-		vect = mdp_bus_scale_table.usecase[bus_idx].vectors;
-		vect->ab = ab_quota;
-		vect->ib = ib_quota;
+		size = SZ_64M / mdss_res->axi_port_cnt;
 
-		pr_debug("bus scale idx=%d ab=%llu ib=%llu\n", bus_idx,
-				vect->ab, vect->ib);
+		ab_quota = div_u64(ab_quota, mdss_res->axi_port_cnt);
+		ib_quota = div_u64(ib_quota, mdss_res->axi_port_cnt);
+
+		new_uc_idx = (mdss_res->curr_bw_uc_idx %
+			(bw_table->num_usecases - 1)) + 1;
+
+		for (i = 0; i < mdss_res->axi_port_cnt; i++) {
+			vect = &bw_table->usecase[mdss_res->curr_bw_uc_idx].
+				vectors[i];
+
+			/* avoid performing updates for small changes */
+			if ((ALIGN(ab_quota, size) == ALIGN(vect->ab, size)) &&
+			    (ALIGN(ib_quota, size) == ALIGN(vect->ib, size))) {
+				pr_debug("skip bus scaling, no changes\n");
+				return 0;
+			}
+
+			vect = &bw_table->usecase[new_uc_idx].vectors[i];
+			vect->ab = ab_quota;
+			vect->ib = ib_quota;
+
+			pr_debug("uc_idx=%d path_idx=%d ab=%llu ib=%llu\n",
+				new_uc_idx, i, vect->ab, vect->ib);
+		}
 	}
-	mdss_res->current_bus_idx = bus_idx;
-	return msm_bus_scale_client_update_request(mdss_res->bus_hdl, bus_idx);
+	mdss_res->curr_bw_uc_idx = new_uc_idx;
+
+	return msm_bus_scale_client_update_request(mdss_res->bus_hdl,
+		new_uc_idx);
 }
 
 static inline u32 mdss_mdp_irq_mask(u32 intr_type, u32 intf_num)
@@ -511,7 +508,16 @@
 	spin_unlock_irqrestore(&mdp_lock, irq_flags);
 }
 
-/* called from interrupt context */
+/**
+ * mdss_mdp_irq_disable_nosync() - disable mdp irq
+ * @intr_type:	mdp interface type
+ * @intf_num:	mdp interface num
+ *
+ * This fucntion is called from interrupt context
+ * mdp_lock is already held at up stream (mdss_irq_handler)
+ * therefore spin_lock(&mdp_lock) is not allowed here
+ *
+*/
 void mdss_mdp_irq_disable_nosync(u32 intr_type, u32 intf_num)
 {
 	u32 irq;
@@ -546,6 +552,8 @@
 	if (clk) {
 		pr_debug("clk=%d en=%d\n", clk_idx, enable);
 		if (enable) {
+			if (clk_idx == MDSS_CLK_MDP_VSYNC)
+				clk_set_rate(clk, 19200000);
 			ret = clk_prepare_enable(clk);
 		} else {
 			clk_disable_unprepare(clk);
@@ -651,7 +659,9 @@
 		} else {
 			pm_runtime_get_sync(&mdata->pdev->dev);
 			msm_bus_scale_client_update_request(
-				mdata->bus_hdl, mdata->current_bus_idx);
+				mdata->bus_hdl, mdata->curr_bw_uc_idx);
+			if (!mdata->handoff_pending)
+				mdss_iommu_attach(mdata);
 		}
 	}
 
@@ -680,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);
 
@@ -782,8 +793,12 @@
 	struct mdss_iommu_map_type *iomap;
 	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);
 		return 0;
 	}
 
@@ -800,6 +815,7 @@
 	}
 
 	mdata->iommu_attached = true;
+	mutex_unlock(&mdp_iommu_lock);
 
 	return 0;
 }
@@ -810,8 +826,12 @@
 	struct mdss_iommu_map_type *iomap;
 	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);
 		return 0;
 	}
 
@@ -828,6 +848,7 @@
 	}
 
 	mdata->iommu_attached = false;
+	mutex_unlock(&mdp_iommu_lock);
 
 	return 0;
 }
@@ -904,7 +925,8 @@
 	int i, total = 0;
 
 	for (i = 0; i < mdata->nctl; i++)
-		total += mdss_debug_stat_ctl_dump(mdata->ctl_off + i, buf, len);
+		total += mdss_debug_stat_ctl_dump(mdata->ctl_off + i,
+			buf + total, len - total);
 
 	total += scnprintf(buf + total, len - total, "\n");
 
@@ -949,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;
 }
@@ -996,8 +1018,9 @@
 		writel_relaxed(1, offset + 16);
 	}
 
-	mdata->nmax_concurrent_ad_hw = (mdata->mdp_rev <= MDSS_MDP_HW_REV_102) ?
-									1 : 2;
+	mdata->nmax_concurrent_ad_hw =
+		(mdata->mdp_rev < MDSS_MDP_HW_REV_103) ? 1 : 2;
+
 	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
 	pr_debug("MDP hw init done\n");
 
@@ -1039,17 +1062,29 @@
 	return rc;
 }
 
+/**
+ * mdss_mdp_footswitch_ctrl_splash() - clocks handoff for cont. splash screen
+ * @on: 1 to start handoff, 0 to complete the handoff after first frame update
+ *
+ * MDSS Clocks and GDSC are already on during continous splash screen, but
+ * increasing ref count will keep clocks from being turned off until handoff
+ * has properly happend after frame update.
+ */
 void mdss_mdp_footswitch_ctrl_splash(int on)
 {
 	struct mdss_data_type *mdata = mdss_mdp_get_mdata();
 	if (mdata != NULL) {
 		if (on) {
 			pr_debug("Enable MDP FS for splash.\n");
+			mdata->handoff_pending = true;
 			regulator_enable(mdata->fs);
+			mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
 			mdss_hw_init(mdata);
 		} else {
 			pr_debug("Disable MDP FS for splash.\n");
+			mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
 			regulator_disable(mdata->fs);
+			mdata->handoff_pending = false;
 		}
 	} else {
 		pr_warn("mdss mdata not initialized\n");
@@ -1073,6 +1108,7 @@
 	SPRINT("dma_pipes=%d\n", mdata->ndma_pipes);
 	SPRINT("smp_count=%d\n", mdata->smp_mb_cnt);
 	SPRINT("smp_size=%d\n", mdata->smp_mb_size);
+	SPRINT("smp_mb_per_pipe=%d\n", mdata->smp_mb_per_pipe);
 	SPRINT("max_downscale_ratio=%d\n", MAX_DOWNSCALE_RATIO);
 	SPRINT("max_upscale_ratio=%d\n", MAX_UPSCALE_RATIO);
 	if (mdata->max_bw_low)
@@ -1084,6 +1120,8 @@
 		SPRINT(" bwc");
 	if (mdata->has_decimation)
 		SPRINT(" decimation");
+	if (mdata->highest_bank_bit)
+		SPRINT(" tile_format");
 	SPRINT("\n");
 
 	return cnt;
@@ -1134,6 +1172,7 @@
 	mdata->pdev = pdev;
 	platform_set_drvdata(pdev, mdata);
 	mdss_res = mdata;
+	mutex_init(&mdata->reg_lock);
 
 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mdp_phys");
 	if (!res) {
@@ -1203,7 +1242,6 @@
 		pr_err("unable to register bus scaling\n");
 		goto probe_done;
 	}
-	mdss_mdp_bus_scale_set_quota(AB_QUOTA, IB_QUOTA);
 
 	rc = mdss_mdp_debug_init(mdata);
 	if (rc) {
@@ -1232,6 +1270,7 @@
 	if (IS_ERR_VALUE(rc)) {
 		mdss_mdp_hw.ptr = NULL;
 		mdss_mdp_pp_term(&pdev->dev);
+		mutex_destroy(&mdata->reg_lock);
 		mdss_res = NULL;
 	}
 
@@ -1523,6 +1562,12 @@
 		return rc;
 	}
 
+	rc = mdss_mdp_parse_dt_prefill(pdev);
+	if (rc) {
+		pr_err("Error in device tree : prefill\n");
+		return rc;
+	}
+
 	rc = mdss_mdp_parse_dt_misc(pdev);
 	if (rc) {
 		pr_err("Error in device tree : misc\n");
@@ -1542,16 +1587,77 @@
 		return rc;
 	}
 
+	rc = mdss_mdp_parse_dt_bus_scale(pdev);
+	if (rc) {
+		pr_err("Error in device tree : bus scale\n");
+		return rc;
+	}
+
 	return 0;
 }
 
+static int  mdss_mdp_parse_dt_pipe_clk_ctrl(struct platform_device *pdev,
+	char *prop_name, struct mdss_mdp_pipe *pipe_list, u32 npipes)
+{
+	int rc = 0;
+	size_t len;
+	const u32 *arr;
+
+	arr = of_get_property(pdev->dev.of_node, prop_name, &len);
+	if (arr) {
+		int i, j;
+
+		len /= sizeof(u32);
+		for (i = 0, j = 0; i < len; j++) {
+			struct mdss_mdp_pipe *pipe = NULL;
+
+			if (j >= npipes) {
+				pr_err("invalid clk ctrl enries for prop: %s\n",
+					prop_name);
+				return -EINVAL;
+			}
+
+			pipe = &pipe_list[j];
+
+			pipe->clk_ctrl.reg_off = be32_to_cpu(arr[i++]);
+			pipe->clk_ctrl.bit_off = be32_to_cpu(arr[i++]);
+
+			/* status register is next in line to ctrl register */
+			pipe->clk_status.reg_off = pipe->clk_ctrl.reg_off + 4;
+			pipe->clk_status.bit_off = be32_to_cpu(arr[i++]);
+
+			pr_debug("%s[%d]: ctrl: reg_off: 0x%x bit_off: %d\n",
+				prop_name, j, pipe->clk_ctrl.reg_off,
+				pipe->clk_ctrl.bit_off);
+			pr_debug("%s[%d]: status: reg_off: 0x%x bit_off: %d\n",
+				prop_name, j, pipe->clk_status.reg_off,
+				pipe->clk_status.bit_off);
+		}
+		if (j != npipes) {
+			pr_err("%s: %d entries found. required %d\n",
+				prop_name, j, npipes);
+			for (i = 0; i < npipes; i++) {
+				memset(&pipe_list[i].clk_ctrl, 0,
+					sizeof(pipe_list[i].clk_ctrl));
+				memset(&pipe_list[i].clk_status, 0,
+					sizeof(pipe_list[i].clk_status));
+			}
+			rc = -EINVAL;
+		}
+	} else {
+		pr_err("error mandatory property '%s' not found\n", prop_name);
+		rc = -EINVAL;
+	}
+
+	return rc;
+}
 
 static int mdss_mdp_parse_dt_pipe(struct platform_device *pdev)
 {
 	u32 npipes, dma_off;
 	int rc = 0;
-	u32 nids = 0, setup_cnt = 0, len;
-	u32 *offsets = NULL, *ftch_id = NULL;
+	u32 nfids = 0, setup_cnt = 0, len, nxids = 0;
+	u32 *offsets = NULL, *ftch_id = NULL, *xin_id = NULL;
 
 	struct mdss_data_type *mdata = platform_get_drvdata(pdev);
 
@@ -1562,33 +1668,47 @@
 	mdata->ndma_pipes = mdss_mdp_parse_dt_prop_len(pdev,
 				"qcom,mdss-pipe-dma-off");
 
-	nids  += mdss_mdp_parse_dt_prop_len(pdev,
-			"qcom,mdss-pipe-vig-fetch-id");
-	nids  += mdss_mdp_parse_dt_prop_len(pdev,
-			"qcom,mdss-pipe-rgb-fetch-id");
-	nids  += mdss_mdp_parse_dt_prop_len(pdev,
-			"qcom,mdss-pipe-dma-fetch-id");
-
 	npipes = mdata->nvig_pipes + mdata->nrgb_pipes + mdata->ndma_pipes;
 
-	if (npipes != nids) {
+	nfids  += mdss_mdp_parse_dt_prop_len(pdev,
+			"qcom,mdss-pipe-vig-fetch-id");
+	nfids  += mdss_mdp_parse_dt_prop_len(pdev,
+			"qcom,mdss-pipe-rgb-fetch-id");
+	nfids  += mdss_mdp_parse_dt_prop_len(pdev,
+			"qcom,mdss-pipe-dma-fetch-id");
+	if (npipes != nfids) {
 		pr_err("device tree err: unequal number of pipes and smp ids");
 		return -EINVAL;
 	}
 
+	nxids += mdss_mdp_parse_dt_prop_len(pdev, "qcom,mdss-pipe-vig-xin-id");
+	nxids += mdss_mdp_parse_dt_prop_len(pdev, "qcom,mdss-pipe-rgb-xin-id");
+	nxids += mdss_mdp_parse_dt_prop_len(pdev, "qcom,mdss-pipe-dma-xin-id");
+	if (npipes != nxids) {
+		pr_err("device tree err: unequal number of pipes and xin ids");
+		return -EINVAL;
+	}
+
 	offsets = kzalloc(sizeof(u32) * npipes, GFP_KERNEL);
 	if (!offsets) {
 		pr_err("no mem assigned for offsets: kzalloc fail\n");
 		return -ENOMEM;
 	}
 
-	ftch_id = kzalloc(sizeof(u32) * nids, GFP_KERNEL);
+	ftch_id = kzalloc(sizeof(u32) * nfids, GFP_KERNEL);
 	if (!ftch_id) {
 		pr_err("no mem assigned for ftch_id: kzalloc fail\n");
 		rc = -ENOMEM;
 		goto ftch_alloc_fail;
 	}
 
+	xin_id = kzalloc(sizeof(u32) * nxids, GFP_KERNEL);
+	if (!xin_id) {
+		pr_err("no mem assigned for xin_id: kzalloc fail\n");
+		rc = -ENOMEM;
+		goto xin_alloc_fail;
+	}
+
 	mdata->vig_pipes = devm_kzalloc(&mdata->pdev->dev,
 		sizeof(struct mdss_mdp_pipe) * mdata->nvig_pipes, GFP_KERNEL);
 	if (!mdata->vig_pipes) {
@@ -1616,7 +1736,12 @@
 	rc = mdss_mdp_parse_dt_handler(pdev, "qcom,mdss-pipe-vig-fetch-id",
 		ftch_id, mdata->nvig_pipes);
 	if (rc)
-		goto parse_done;
+		goto parse_fail;
+
+	rc = mdss_mdp_parse_dt_handler(pdev, "qcom,mdss-pipe-vig-xin-id",
+		xin_id, mdata->nvig_pipes);
+	if (rc)
+		goto parse_fail;
 
 	rc = mdss_mdp_parse_dt_handler(pdev, "qcom,mdss-pipe-vig-off",
 		offsets, mdata->nvig_pipes);
@@ -1625,7 +1750,7 @@
 
 	len = min_t(int, DEFAULT_TOTAL_VIG_PIPES, (int)mdata->nvig_pipes);
 	rc = mdss_mdp_pipe_addr_setup(mdata, mdata->vig_pipes, offsets, ftch_id,
-		MDSS_MDP_PIPE_TYPE_VIG, MDSS_MDP_SSPP_VIG0, len);
+		xin_id, MDSS_MDP_PIPE_TYPE_VIG, MDSS_MDP_SSPP_VIG0, len);
 	if (rc)
 		goto parse_fail;
 
@@ -1636,6 +1761,11 @@
 	if (rc)
 		goto parse_fail;
 
+	rc = mdss_mdp_parse_dt_handler(pdev, "qcom,mdss-pipe-rgb-xin-id",
+		xin_id + mdata->nvig_pipes, mdata->nrgb_pipes);
+	if (rc)
+		goto parse_fail;
+
 	rc = mdss_mdp_parse_dt_handler(pdev, "qcom,mdss-pipe-rgb-off",
 		offsets + mdata->nvig_pipes, mdata->nrgb_pipes);
 	if (rc)
@@ -1644,7 +1774,8 @@
 	len = min_t(int, DEFAULT_TOTAL_RGB_PIPES, (int)mdata->nrgb_pipes);
 	rc = mdss_mdp_pipe_addr_setup(mdata, mdata->rgb_pipes,
 		offsets + mdata->nvig_pipes, ftch_id + mdata->nvig_pipes,
-		MDSS_MDP_PIPE_TYPE_RGB, MDSS_MDP_SSPP_RGB0, len);
+		xin_id + mdata->nvig_pipes, MDSS_MDP_PIPE_TYPE_RGB,
+		MDSS_MDP_SSPP_RGB0, len);
 	if (rc)
 		goto parse_fail;
 
@@ -1656,6 +1787,11 @@
 	if (rc)
 		goto parse_fail;
 
+	rc = mdss_mdp_parse_dt_handler(pdev, "qcom,mdss-pipe-dma-xin-id",
+		xin_id + dma_off, mdata->ndma_pipes);
+	if (rc)
+		goto parse_fail;
+
 	rc = mdss_mdp_parse_dt_handler(pdev, "qcom,mdss-pipe-dma-off",
 		offsets + dma_off, mdata->ndma_pipes);
 	if (rc)
@@ -1663,8 +1799,8 @@
 
 	len = mdata->ndma_pipes;
 	rc = mdss_mdp_pipe_addr_setup(mdata, mdata->dma_pipes,
-		 offsets + dma_off, ftch_id + dma_off, MDSS_MDP_PIPE_TYPE_DMA,
-		 MDSS_MDP_SSPP_DMA0, len);
+		offsets + dma_off, ftch_id + dma_off, xin_id + dma_off,
+		MDSS_MDP_PIPE_TYPE_DMA, MDSS_MDP_SSPP_DMA0, len);
 	if (rc)
 		goto parse_fail;
 
@@ -1675,6 +1811,7 @@
 			mdata->vig_pipes + DEFAULT_TOTAL_VIG_PIPES,
 			offsets + DEFAULT_TOTAL_VIG_PIPES,
 			ftch_id + DEFAULT_TOTAL_VIG_PIPES,
+			xin_id + DEFAULT_TOTAL_VIG_PIPES,
 			MDSS_MDP_PIPE_TYPE_VIG, setup_cnt,
 			mdata->nvig_pipes - DEFAULT_TOTAL_VIG_PIPES);
 		if (rc)
@@ -1688,6 +1825,7 @@
 			mdata->rgb_pipes + DEFAULT_TOTAL_RGB_PIPES,
 			offsets + mdata->nvig_pipes + DEFAULT_TOTAL_RGB_PIPES,
 			ftch_id + mdata->nvig_pipes + DEFAULT_TOTAL_RGB_PIPES,
+			xin_id + mdata->nvig_pipes + DEFAULT_TOTAL_RGB_PIPES,
 			MDSS_MDP_PIPE_TYPE_RGB, setup_cnt,
 			mdata->nrgb_pipes - DEFAULT_TOTAL_RGB_PIPES);
 		if (rc)
@@ -1696,6 +1834,25 @@
 		setup_cnt += mdata->nrgb_pipes - DEFAULT_TOTAL_RGB_PIPES;
 	}
 
+	rc = mdss_mdp_parse_dt_pipe_clk_ctrl(pdev,
+		"qcom,mdss-pipe-vig-clk-ctrl-offsets", mdata->vig_pipes,
+		mdata->nvig_pipes);
+	if (rc)
+		goto parse_fail;
+
+	rc = mdss_mdp_parse_dt_pipe_clk_ctrl(pdev,
+		"qcom,mdss-pipe-rgb-clk-ctrl-offsets", mdata->rgb_pipes,
+		mdata->nrgb_pipes);
+	if (rc)
+		goto parse_fail;
+
+	rc = mdss_mdp_parse_dt_pipe_clk_ctrl(pdev,
+		"qcom,mdss-pipe-dma-clk-ctrl-offsets", mdata->dma_pipes,
+		mdata->ndma_pipes);
+	if (rc)
+		goto parse_fail;
+
+
 	goto parse_done;
 
 parse_fail:
@@ -1706,6 +1863,8 @@
 	kfree(mdata->vig_pipes);
 parse_done:
 vig_alloc_fail:
+	kfree(xin_id);
+xin_alloc_fail:
 	kfree(ftch_id);
 ftch_alloc_fail:
 	kfree(offsets);
@@ -1964,6 +2123,84 @@
 	return rc;
 }
 
+static void mdss_mdp_parse_dt_fudge_factors(struct platform_device *pdev,
+	char *prop_name, struct mdss_fudge_factor *ff)
+{
+	int rc;
+	u32 data[2] = {1, 1};
+
+	rc = mdss_mdp_parse_dt_handler(pdev, prop_name, data, 2);
+	if (rc) {
+		pr_err("err reading %s\n", prop_name);
+	} else {
+		ff->numer = data[0];
+		ff->denom = data[1];
+	}
+}
+
+static int mdss_mdp_parse_dt_prefill(struct platform_device *pdev)
+{
+	struct mdss_data_type *mdata = platform_get_drvdata(pdev);
+	struct mdss_prefill_data *prefill = &mdata->prefill_data;
+	int rc;
+
+	rc = of_property_read_u32(pdev->dev.of_node,
+		"qcom,mdss-prefill-outstanding-buffer-bytes",
+		&prefill->ot_bytes);
+	if (rc) {
+		pr_err("prefill outstanding buffer bytes not specified\n");
+		return rc;
+	}
+
+	rc = of_property_read_u32(pdev->dev.of_node,
+		"qcom,mdss-prefill-y-buffer-bytes", &prefill->y_buf_bytes);
+	if (rc) {
+		pr_err("prefill y buffer bytes not specified\n");
+		return rc;
+	}
+
+	rc = of_property_read_u32(pdev->dev.of_node,
+		"qcom,mdss-prefill-scaler-buffer-lines-bilinear",
+		&prefill->y_scaler_lines_bilinear);
+	if (rc) {
+		pr_err("prefill scaler lines for bilinear not specified\n");
+		return rc;
+	}
+
+	rc = of_property_read_u32(pdev->dev.of_node,
+		"qcom,mdss-prefill-scaler-buffer-lines-caf",
+		&prefill->y_scaler_lines_caf);
+	if (rc) {
+		pr_debug("prefill scaler lines for caf not specified\n");
+		return rc;
+	}
+
+	rc = of_property_read_u32(pdev->dev.of_node,
+		"qcom,mdss-prefill-post-scaler-buffer-pixels",
+		&prefill->post_scaler_pixels);
+	if (rc) {
+		pr_err("prefill post scaler buffer pixels not specified\n");
+		return rc;
+	}
+
+	rc = of_property_read_u32(pdev->dev.of_node,
+		"qcom,mdss-prefill-pingpong-buffer-pixels",
+		&prefill->pp_pixels);
+	if (rc) {
+		pr_err("prefill pingpong buffer lines not specified\n");
+		return rc;
+	}
+
+	rc = of_property_read_u32(pdev->dev.of_node,
+		"qcom,mdss-prefill-fbc-lines", &prefill->fbc_lines);
+	if (rc) {
+		pr_err("prefill FBC lines not specified\n");
+		return rc;
+	}
+
+	return 0;
+}
+
 static int mdss_mdp_parse_dt_misc(struct platform_device *pdev)
 {
 	struct mdss_data_type *mdata = platform_get_drvdata(pdev);
@@ -1975,14 +2212,59 @@
 		&data);
 	mdata->rot_block_size = (!rc ? data : 128);
 
+	rc = of_property_read_u32(pdev->dev.of_node,
+		"qcom,mdss-rotator-ot-limit", &data);
+	mdata->rotator_ot_limit = (!rc ? data : 0);
+
 	mdata->has_bwc = of_property_read_bool(pdev->dev.of_node,
 					       "qcom,mdss-has-bwc");
 	mdata->has_decimation = of_property_read_bool(pdev->dev.of_node,
 		"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,
+		 "qcom,mdss-highest-bank-bit", &(mdata->highest_bank_bit));
+	if (rc)
+		pr_debug("Could not read optional property: highest bank bit\n");
+
+	/*
+	 * 2x factor on AB because bus driver will divide by 2
+	 * due to 2x ports to BIMC
+	 */
+	mdata->ab_factor.numer = 2;
+	mdata->ab_factor.denom = 1;
+	mdss_mdp_parse_dt_fudge_factors(pdev, "qcom,mdss-ab-factor",
+		&mdata->ab_factor);
+
+	/*
+	 * 1.2 factor on ib as default value. This value is
+	 * experimentally determined and should be tuned in device
+	 * tree.
+	 */
+	mdata->ib_factor.numer = 6;
+	mdata->ib_factor.denom = 5;
+	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",
+		&mdata->clk_factor);
 
 	rc = of_property_read_u32(pdev->dev.of_node,
 			"qcom,max-bandwidth-low-kbps", &mdata->max_bw_low);
@@ -1994,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;
 }
 
@@ -2037,6 +2336,31 @@
 	return rc;
 }
 
+static int mdss_mdp_parse_dt_bus_scale(struct platform_device *pdev)
+{
+	int rc;
+	struct mdss_data_type *mdata = platform_get_drvdata(pdev);
+
+	rc = of_property_read_u32(pdev->dev.of_node, "qcom,msm-bus,num-paths",
+		&mdata->axi_port_cnt);
+	if (rc) {
+		pr_err("Error. qcom,msm-bus,num-paths prop not found.rc=%d\n",
+			rc);
+		return rc;
+	}
+
+	mdata->bus_scale_table = msm_bus_cl_get_pdata(pdev);
+	if (IS_ERR_OR_NULL(mdata->bus_scale_table)) {
+		rc = PTR_ERR(mdata->bus_scale_table);
+		if (!rc)
+			rc = -EINVAL;
+		pr_err("msm_bus_cl_get_pdata failed. rc=%d\n", rc);
+		mdata->bus_scale_table = NULL;
+	}
+
+	return rc;
+}
+
 static int mdss_mdp_parse_dt_handler(struct platform_device *pdev,
 		char *prop_name, u32 *offsets, int len)
 {
@@ -2116,7 +2440,7 @@
 	int rc;
 
 	if (!mdss_res || !mdss_res->pan_cfg.init_done)
-		rc = -EPROBE_DEFER;
+		return -EPROBE_DEFER;
 	if (mdss_res->pan_cfg.lk_cfg)
 		rc = 1;
 	else
@@ -2203,8 +2527,10 @@
 		pr_debug("Enable MDP FS\n");
 		if (!mdata->fs_ena) {
 			regulator_enable(mdata->fs);
-			mdss_mdp_cx_ctrl(mdata, true);
-			mdss_mdp_batfet_ctrl(mdata, true);
+			if (!mdata->ulps) {
+				mdss_mdp_cx_ctrl(mdata, true);
+				mdss_mdp_batfet_ctrl(mdata, true);
+			}
 		}
 		mdata->fs_ena = true;
 	} else {
@@ -2212,13 +2538,41 @@
 		mdss_iommu_dettach(mdata);
 		if (mdata->fs_ena) {
 			regulator_disable(mdata->fs);
-			mdss_mdp_cx_ctrl(mdata, false);
-			mdss_mdp_batfet_ctrl(mdata, false);
+			if (!mdata->ulps) {
+				mdss_mdp_cx_ctrl(mdata, false);
+				mdss_mdp_batfet_ctrl(mdata, false);
+			}
 		}
 		mdata->fs_ena = false;
 	}
 }
 
+/**
+ * mdss_mdp_footswitch_ctrl_ulps() - MDSS GDSC control with ULPS feature
+ * @on: 1 to turn on footswitch, 0 to turn off footswitch
+ * @dev: framebuffer device node
+ *
+ * MDSS GDSC can be voted off during idle-screen usecase for MIPI DSI command
+ * mode displays with Ultra-Low Power State (ULPS) feature enabled. Upon
+ * subsequent frame update, MDSS GDSC needs to turned back on and hw state
+ * needs to be restored.
+ */
+void mdss_mdp_footswitch_ctrl_ulps(int on, struct device *dev)
+{
+	struct mdss_data_type *mdata = mdss_mdp_get_mdata();
+
+	pr_debug("called on=%d\n", on);
+	if (on) {
+		pm_runtime_get_sync(dev);
+		mdss_iommu_attach(mdata);
+		mdss_hw_init(mdata);
+		mdata->ulps = false;
+	} else {
+		mdata->ulps = true;
+		pm_runtime_put_sync(dev);
+	}
+}
+
 static inline int mdss_mdp_suspend_sub(struct mdss_data_type *mdata)
 {
 	mdata->suspend_fs_ena = mdata->fs_ena;
@@ -2300,11 +2654,12 @@
 static int mdss_mdp_runtime_resume(struct device *dev)
 {
 	struct mdss_data_type *mdata = dev_get_drvdata(dev);
+	bool device_on = true;
 	if (!mdata)
 		return -ENODEV;
 
 	dev_dbg(dev, "pm_runtime: resuming...\n");
-
+	device_for_each_child(dev, &device_on, mdss_fb_suspres_panel);
 	mdss_mdp_footswitch_ctrl(mdata, true);
 
 	return 0;
@@ -2324,6 +2679,7 @@
 static int mdss_mdp_runtime_suspend(struct device *dev)
 {
 	struct mdss_data_type *mdata = dev_get_drvdata(dev);
+	bool device_on = false;
 	if (!mdata)
 		return -ENODEV;
 	dev_dbg(dev, "pm_runtime: suspending...\n");
@@ -2332,6 +2688,7 @@
 		pr_err("MDP suspend failed\n");
 		return -EBUSY;
 	}
+	device_for_each_child(dev, &device_on, mdss_fb_suspres_panel);
 	mdss_mdp_footswitch_ctrl(mdata, false);
 
 	return 0;
diff --git a/drivers/video/msm/mdss/mdss_mdp.h b/drivers/video/msm/mdss/mdss_mdp.h
index fad6b0c..1e17205 100644
--- a/drivers/video/msm/mdss/mdss_mdp.h
+++ b/drivers/video/msm/mdss/mdss_mdp.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
@@ -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"
@@ -32,7 +33,8 @@
 #define MDP_CLK_DEFAULT_RATE	200000000
 #define PHASE_STEP_SHIFT	21
 #define MAX_MIXER_WIDTH		2048
-#define MAX_MIXER_HEIGHT	2400
+#define MAX_LINE_BUFFER_WIDTH	2048
+#define MAX_MIXER_HEIGHT	0xFFFF
 #define MAX_IMG_WIDTH		0x3FFF
 #define MAX_IMG_HEIGHT		0x3FFF
 #define MAX_DST_W		MAX_MIXER_WIDTH
@@ -75,6 +77,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,
@@ -145,6 +154,14 @@
 	MDSS_MDP_WB_CTL_TYPE_LINE
 };
 
+struct mdss_mdp_perf_params {
+	u64 bw_overlap;
+	u64 bw_prefill;
+	u32 prefill_bytes;
+	u64 bw_ctl;
+	u32 mdp_clk_rate;
+};
+
 struct mdss_mdp_ctl {
 	u32 num;
 	char __iomem *base;
@@ -168,11 +185,11 @@
 	u32 dst_format;
 	bool is_secure;
 
-	u32 bus_ab_quota;
-	u32 bus_ib_quota;
 	u32 clk_rate;
-	u32 perf_changed;
 	int force_screen_state;
+	struct mdss_mdp_perf_params cur_perf;
+	struct mdss_mdp_perf_params new_perf;
+	u32 perf_transaction_status;
 
 	struct mdss_data_type *mdata;
 	struct msm_fb_data_type *mfd;
@@ -180,11 +197,16 @@
 	struct mdss_mdp_mixer *mixer_right;
 	struct mutex lock;
 	struct mutex *shared_lock;
+	spinlock_t spin_lock;
 
 	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);
@@ -198,7 +220,8 @@
 					struct mdss_mdp_vsync_handler *);
 	int (*remove_vsync_handler) (struct mdss_mdp_ctl *,
 					struct mdss_mdp_vsync_handler *);
-	int (*config_fps_fnc) (struct mdss_mdp_ctl *ctl, int new_fps);
+	int (*config_fps_fnc) (struct mdss_mdp_ctl *ctl,
+				struct mdss_mdp_ctl *sctl, int new_fps);
 
 	struct blocking_notifier_head notifier_head;
 
@@ -237,7 +260,7 @@
 	u8 unpack_count;	/* 0 = 1 component, 1 = 2 component ... */
 	u8 bpp;
 	u8 alpha_enable;	/*  source has alpha */
-
+	u8 tile;
 	u8 bits[MAX_PLANES];
 	u8 element[MAX_PLANES];
 };
@@ -274,7 +297,6 @@
 	u32 hist_cnt_sent;
 	u32 hist_cnt_time;
 	u32 frame_cnt;
-	u32 is_kick_ready;
 	struct completion comp;
 	u32 data[HIST_V_SIZE];
 	struct mutex hist_mutex;
@@ -310,6 +332,7 @@
 	uint32_t bl_bright_shift;
 	uint32_t bl_lin[AD_BL_LIN_LEN];
 	uint32_t bl_lin_inv[AD_BL_LIN_LEN];
+	uint32_t bl_att_lut[AD_BL_ATT_LUT_LEN];
 };
 
 struct pp_sts_type {
@@ -339,13 +362,23 @@
 	DECLARE_BITMAP(fixed, MAX_DRV_SUP_MMB_BLKS);
 };
 
+struct mdss_mdp_shared_reg_ctrl {
+	u32 reg_off;
+	u32 bit_off;
+};
+
 struct mdss_mdp_pipe {
 	u32 num;
 	u32 type;
 	u32 ndx;
 	char __iomem *base;
 	u32 ftch_id;
-	atomic_t ref_cnt;
+	u32 xin_id;
+	struct mdss_mdp_shared_reg_ctrl clk_ctrl;
+	struct mdss_mdp_shared_reg_ctrl clk_status;
+
+	struct kref kref;
+
 	u32 play_cnt;
 	int pid;
 	bool is_handed_off;
@@ -369,7 +402,6 @@
 	u8 overfetch_disable;
 	u32 transp;
 	u32 bg_color;
-	u8 has_buf;
 
 	struct msm_fb_data_type *mfd;
 	struct mdss_mdp_mixer *mixer;
@@ -423,12 +455,11 @@
 	u32 splash_mem_addr;
 	u32 splash_mem_size;
 	u32 sd_enabled;
-};
 
-struct mdss_mdp_perf_params {
-	u32 ib_quota;
-	u32 ab_quota;
-	u32 mdp_clk_rate;
+	struct sw_sync_timeline *vsync_timeline;
+	struct mdss_mdp_vsync_handler vsync_retire_handler;
+	struct work_struct retire_work;
+	int retire_cnt;
 };
 
 /**
@@ -443,6 +474,16 @@
 };
 
 #define is_vig_pipe(_pipe_id_) ((_pipe_id_) <= MDSS_MDP_SSPP_VIG2)
+
+static inline struct mdss_mdp_ctl *mdss_mdp_get_split_ctl(
+	struct mdss_mdp_ctl *ctl)
+{
+	if (ctl && ctl->mixer_right && (ctl->mixer_right->ctl != ctl))
+		return ctl->mixer_right->ctl;
+
+	return NULL;
+}
+
 static inline void mdss_mdp_ctl_write(struct mdss_mdp_ctl *ctl,
 				      u32 reg, u32 val)
 {
@@ -465,6 +506,17 @@
 	return readl_relaxed(mixer->pingpong_base + reg);
 }
 
+static inline int mdss_mdp_iommu_dyn_attach_supported(
+	struct mdss_data_type *mdata)
+{
+	return (mdata->mdp_rev >= MDSS_MDP_HW_REV_103);
+}
+
+static inline int mdss_mdp_line_buffer_width(void)
+{
+	return MAX_LINE_BUFFER_WIDTH;
+}
+
 irqreturn_t mdss_mdp_isr(int irq, void *ptr);
 int mdss_iommu_attach(struct mdss_data_type *mdata);
 int mdss_iommu_dettach(struct mdss_data_type *mdata);
@@ -498,6 +550,12 @@
 			     struct msmfb_data *planes,
 			     int num_planes,
 			     u32 flags);
+int mdss_mdp_overlay_pipe_setup(struct msm_fb_data_type *mfd,
+	struct mdp_overlay *req, struct mdss_mdp_pipe **ppipe);
+void mdss_mdp_handoff_cleanup_pipes(struct msm_fb_data_type *mfd,
+							u32 type);
+int mdss_mdp_overlay_release(struct msm_fb_data_type *mfd, int ndx);
+int mdss_mdp_overlay_start(struct msm_fb_data_type *mfd);
 int mdss_mdp_video_addr_setup(struct mdss_data_type *mdata,
 		u32 *offsets,  u32 count);
 int mdss_mdp_video_start(struct mdss_mdp_ctl *ctl);
@@ -520,8 +578,12 @@
 int mdss_mdp_ctl_start(struct mdss_mdp_ctl *ctl, bool handoff);
 int mdss_mdp_ctl_stop(struct mdss_mdp_ctl *ctl);
 int mdss_mdp_ctl_intf_event(struct mdss_mdp_ctl *ctl, int event, void *arg);
+int mdss_mdp_perf_bw_check(struct mdss_mdp_ctl *ctl,
+		struct mdss_mdp_pipe **left_plist, int left_cnt,
+		struct mdss_mdp_pipe **right_plist, int right_cnt);
 int mdss_mdp_perf_calc_pipe(struct mdss_mdp_pipe *pipe,
-		struct mdss_mdp_perf_params *perf);
+	struct mdss_mdp_perf_params *perf, struct mdss_mdp_img_rect *roi,
+	bool apply_fudge);
 int mdss_mdp_ctl_notify(struct mdss_mdp_ctl *ctl, int event);
 void mdss_mdp_ctl_notifier_register(struct mdss_mdp_ctl *ctl,
 	struct notifier_block *notifier);
@@ -530,8 +592,13 @@
 
 int mdss_mdp_mixer_handoff(struct mdss_mdp_ctl *ctl, u32 num,
 	struct mdss_mdp_pipe *pipe);
+
 int mdss_mdp_scan_pipes(void);
 
+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);
 int mdss_mdp_wb_mixer_destroy(struct mdss_mdp_mixer *mixer);
 struct mdss_mdp_mixer *mdss_mdp_mixer_get(struct mdss_mdp_ctl *ctl, int mux);
@@ -539,6 +606,7 @@
 						int mux, int stage);
 int mdss_mdp_mixer_pipe_update(struct mdss_mdp_pipe *pipe, int params_changed);
 int mdss_mdp_mixer_pipe_unstage(struct mdss_mdp_pipe *pipe);
+void mdss_mdp_mixer_unstage_all(struct mdss_mdp_mixer *mixer);
 int mdss_mdp_display_commit(struct mdss_mdp_ctl *ctl, void *arg);
 int mdss_mdp_display_wait4comp(struct mdss_mdp_ctl *ctl);
 int mdss_mdp_display_wait4pingpong(struct mdss_mdp_ctl *ctl);
@@ -599,18 +667,20 @@
 void mdss_mdp_pipe_unmap(struct mdss_mdp_pipe *pipe);
 struct mdss_mdp_pipe *mdss_mdp_pipe_alloc_dma(struct mdss_mdp_mixer *mixer);
 
+u32 mdss_mdp_smp_get_size(struct mdss_mdp_pipe *pipe);
 int mdss_mdp_smp_reserve(struct mdss_mdp_pipe *pipe);
 void mdss_mdp_smp_unreserve(struct mdss_mdp_pipe *pipe);
 void mdss_mdp_smp_release(struct mdss_mdp_pipe *pipe);
 
 int mdss_mdp_pipe_addr_setup(struct mdss_data_type *mdata,
-	struct mdss_mdp_pipe *head, u32 *offsets, u32 *ftch_y_id, u32 type,
-	u32 num_base, u32 len);
+	struct mdss_mdp_pipe *head, u32 *offsets, u32 *ftch_y_id, u32 *xin_id,
+	u32 type, u32 num_base, u32 len);
 int mdss_mdp_mixer_addr_setup(struct mdss_data_type *mdata, u32 *mixer_offsets,
 		u32 *dspp_offsets, u32 *pingpong_offsets, u32 type, u32 len);
 int mdss_mdp_ctl_addr_setup(struct mdss_data_type *mdata, u32 *ctl_offsets,
 		u32 *wb_offsets, u32 len);
 
+int mdss_mdp_pipe_fetch_halt(struct mdss_mdp_pipe *pipe);
 int mdss_mdp_pipe_destroy(struct mdss_mdp_pipe *pipe);
 int mdss_mdp_pipe_queue_data(struct mdss_mdp_pipe *pipe,
 			     struct mdss_mdp_data *src_data);
@@ -632,12 +702,17 @@
 void mdss_mdp_intersect_rect(struct mdss_mdp_img_rect *res_rect,
 	const struct mdss_mdp_img_rect *dst_rect,
 	const struct mdss_mdp_img_rect *sci_rect);
+void mdss_mdp_crop_rect(struct mdss_mdp_img_rect *src_rect,
+	struct mdss_mdp_img_rect *dst_rect,
+	const struct mdss_mdp_img_rect *sci_rect);
+
 
 int mdss_mdp_wb_kickoff(struct msm_fb_data_type *mfd);
 int mdss_mdp_wb_ioctl_handler(struct msm_fb_data_type *mfd, u32 cmd, void *arg);
 
 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);
@@ -652,12 +727,14 @@
 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);
 
 int mdss_mdp_wb_set_secure(struct msm_fb_data_type *mfd, int enable);
 int mdss_mdp_wb_get_secure(struct msm_fb_data_type *mfd, uint8_t *enable);
+void mdss_mdp_ctl_restore(struct mdss_mdp_ctl *ctl);
+void mdss_mdp_footswitch_ctrl_ulps(int on, struct device *dev);
 
 int mdss_mdp_pipe_program_pixel_extn(struct mdss_mdp_pipe *pipe);
 #define mfd_to_mdp5_data(mfd) (mfd->mdp.private1)
diff --git a/drivers/video/msm/mdss/mdss_mdp_ctl.c b/drivers/video/msm/mdss/mdss_mdp_ctl.c
index d57e4fb..65d28a0 100644
--- a/drivers/video/msm/mdss/mdss_mdp_ctl.c
+++ b/drivers/video/msm/mdss/mdss_mdp_ctl.c
@@ -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
@@ -18,30 +18,25 @@
 #include <linux/platform_device.h>
 #include <linux/dma-mapping.h>
 #include <linux/delay.h>
+#include <linux/sort.h>
 
 #include "mdss_fb.h"
 #include "mdss_mdp.h"
+#include "mdss_debug.h"
 
-/* truncate at 1k */
-#define MDSS_MDP_BUS_FACTOR_SHIFT 10
-/* 1.5 bus fudge factor */
-#define MDSS_MDP_BUS_FUDGE_FACTOR_IB(val) (((val) / 2) * 3)
-#define MDSS_MDP_BUS_FUDGE_FACTOR_HIGH_IB(val) (val << 1)
-#define MDSS_MDP_BUS_FUDGE_FACTOR_AB(val) (val << 1)
-#define MDSS_MDP_BUS_FLOOR_BW (1600000000ULL >> MDSS_MDP_BUS_FACTOR_SHIFT)
+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);
+	do_div(result, denom);
+	return result;
+}
 
-/* 1.25 clock fudge factor */
-#define MDSS_MDP_CLK_FUDGE_FACTOR(val) (((val) * 5) / 4)
-
-enum {
-	MDSS_MDP_PERF_UPDATE_SKIP,
-	MDSS_MDP_PERF_UPDATE_EARLY,
-	MDSS_MDP_PERF_UPDATE_LATE,
-};
-
-#define MDSS_MDP_PERF_UPDATE_CLK BIT(0)
-#define MDSS_MDP_PERF_UPDATE_BUS BIT(1)
-#define MDSS_MDP_PERF_UPDATE_ALL -1
+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);
 
@@ -54,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;
@@ -63,112 +63,243 @@
 		pinfo->clk_rate;
 }
 
-static u32 __mdss_mdp_ctrl_perf_ovrd_helper(struct mdss_mdp_mixer *mixer,
-		u32 *npipe)
+static inline u32 mdss_mdp_clk_fudge_factor(struct mdss_mdp_mixer *mixer,
+						u32 rate)
 {
-	struct mdss_panel_info *pinfo;
-	struct mdss_mdp_pipe *pipe;
-	u32 mnum, ovrd = 0;
+	struct mdss_panel_info *pinfo = &mixer->ctl->panel_data->panel_info;
 
-	if (!mixer || !mixer->ctl->panel_data)
-		return 0;
+	rate = apply_fudge_factor(rate, &mdss_res->clk_factor);
 
-	pinfo = &mixer->ctl->panel_data->panel_info;
-	for (mnum = 0; mnum < MDSS_MDP_MAX_STAGE; mnum++) {
-		pipe = mixer->stage_pipe[mnum];
-		if (pipe && pinfo) {
-			*npipe = *npipe + 1;
-			if ((pipe->src.w >= pipe->src.h) &&
-					(pipe->src.w >= pinfo->xres))
-				ovrd = 1;
-		}
-	}
+	/*
+	 * If the panel is video mode and its back porch period is
+	 * small, the workaround of increasing mdp clk is needed to
+	 * avoid underrun.
+	 */
+	if (mixer->ctl->is_video_mode && pinfo &&
+		(pinfo->lcdc.v_back_porch < MDP_MIN_VBP))
+		rate = apply_fudge_factor(rate, &mdss_res->clk_factor);
 
-	return ovrd;
+	return rate;
 }
 
-/**
- * mdss_mdp_ctrl_perf_ovrd() - Determines if performance override is needed
- * @mdata:	Struct containing references to all MDP5 hardware structures
- *		and status info such as interupts, target caps etc.
- * @ab_quota:	Arbitrated bandwidth quota
- * @ib_quota:	Instantaneous bandwidth quota
- *
- * Function calculates the minimum required MDP and BIMC clocks to avoid MDP
- * underflow during portrait video playback. The calculations are based on the
- * way MDP fetches (bandwidth requirement) and processes data through
- * MDP pipeline (MDP clock requirement) based on frame size and scaling
- * requirements.
- */
-static void __mdss_mdp_ctrl_perf_ovrd(struct mdss_data_type *mdata,
-	u64 *ab_quota, u64 *ib_quota)
+struct mdss_mdp_prefill_params {
+	u32 smp_bytes;
+	u32 xres;
+	u32 src_w;
+	u32 dst_w;
+	u32 src_h;
+	u32 dst_h;
+	u32 dst_y;
+	u32 bpp;
+	bool is_yuv;
+	bool is_caf;
+	bool is_fbc;
+	bool is_bwc;
+	bool is_tile;
+	bool is_hflip;
+};
+
+static inline bool mdss_mdp_perf_is_caf(struct mdss_mdp_pipe *pipe)
 {
-	struct mdss_mdp_ctl *ctl;
-	u32 i, npipe = 0, ovrd = 0;
+	struct mdss_data_type *mdata = mdss_mdp_get_mdata();
 
-	for (i = 0; i < mdata->nctl; i++) {
-		ctl = mdata->ctl_off + i;
-		if (!ctl->power_on)
-			continue;
-		ovrd |= __mdss_mdp_ctrl_perf_ovrd_helper(
-				ctl->mixer_left, &npipe);
-		ovrd |= __mdss_mdp_ctrl_perf_ovrd_helper(
-				ctl->mixer_right, &npipe);
-	}
+	/*
+	 * CAF mode filter is enabled when format is yuv and
+	 * upscaling. Post processing had the decision to use CAF
+	 * under these conditions.
+	 */
+	return ((mdata->mdp_rev >= MDSS_MDP_HW_REV_102) &&
+		pipe->src_fmt->is_yuv && ((pipe->src.h >> pipe->vert_deci) <=
+			pipe->dst.h));
+}
 
-	*ab_quota = MDSS_MDP_BUS_FUDGE_FACTOR_AB(*ab_quota);
-	if (npipe > 1)
-		*ib_quota = MDSS_MDP_BUS_FUDGE_FACTOR_HIGH_IB(*ib_quota);
-	else
-		*ib_quota = MDSS_MDP_BUS_FUDGE_FACTOR_IB(*ib_quota);
+static inline u32 mdss_mdp_calc_y_scaler_bytes(struct mdss_mdp_prefill_params
+	*params, struct mdss_prefill_data *prefill)
+{
+	u32 y_scaler_bytes = 0, y_scaler_lines = 0;
 
-	if (ovrd && (*ib_quota < MDSS_MDP_BUS_FLOOR_BW)) {
-		*ib_quota = MDSS_MDP_BUS_FLOOR_BW;
-		pr_debug("forcing the BIMC clock to 200 MHz : %llu bytes",
-			*ib_quota);
+	if (params->is_yuv) {
+		if (params->src_h != params->dst_h) {
+			y_scaler_lines = (params->is_caf) ?
+				prefill->y_scaler_lines_caf :
+				prefill->y_scaler_lines_bilinear;
+			/*
+			 * y is src_width, u is src_width/2 and v is
+			 * src_width/2, so the total is scaler_lines *
+			 * src_w * 2
+			 */
+			y_scaler_bytes = y_scaler_lines * params->src_w * 2;
+		}
 	} else {
-		pr_debug("ib quota : %llu bytes", *ib_quota);
-	}
-}
-
-static int mdss_mdp_ctl_perf_commit(struct mdss_data_type *mdata, u32 flags)
-{
-	struct mdss_mdp_ctl *ctl;
-	int cnum;
-	unsigned long clk_rate = 0;
-	u64 bus_ab_quota = 0, bus_ib_quota = 0;
-
-	if (!flags) {
-		pr_err("nothing to update\n");
-		return -EINVAL;
-	}
-
-	mutex_lock(&mdss_mdp_ctl_lock);
-	for (cnum = 0; cnum < mdata->nctl; cnum++) {
-		ctl = mdata->ctl_off + cnum;
-		if (ctl->power_on) {
-			bus_ab_quota += ctl->bus_ab_quota;
-			bus_ib_quota += ctl->bus_ib_quota;
-
-			if (ctl->clk_rate > clk_rate)
-				clk_rate = ctl->clk_rate;
+		if (params->src_h != params->dst_h) {
+			y_scaler_lines = prefill->y_scaler_lines_bilinear;
+			y_scaler_bytes = y_scaler_lines * params->src_w *
+				params->bpp;
 		}
 	}
-	if (flags & MDSS_MDP_PERF_UPDATE_BUS) {
-		bus_ab_quota = bus_ib_quota;
-		__mdss_mdp_ctrl_perf_ovrd(mdata, &bus_ab_quota, &bus_ib_quota);
-		bus_ib_quota <<= MDSS_MDP_BUS_FACTOR_SHIFT;
-		bus_ab_quota <<= MDSS_MDP_BUS_FACTOR_SHIFT;
-		mdss_mdp_bus_scale_set_quota(bus_ab_quota, bus_ib_quota);
-	}
-	if (flags & MDSS_MDP_PERF_UPDATE_CLK) {
-		clk_rate = MDSS_MDP_CLK_FUDGE_FACTOR(clk_rate);
-		pr_debug("update clk rate = %lu HZ\n", clk_rate);
-		mdss_mdp_set_clk_rate(clk_rate);
-	}
-	mutex_unlock(&mdss_mdp_ctl_lock);
 
-	return 0;
+	return y_scaler_bytes;
+}
+
+static inline u32 mdss_mdp_calc_latency_buf_bytes(struct mdss_mdp_prefill_params
+	*params, struct mdss_prefill_data *prefill)
+{
+	struct mdss_data_type *mdata = mdss_mdp_get_mdata();
+	u32 latency_lines, latency_buf_bytes;
+
+	if (params->is_yuv) {
+		if (params->is_bwc) {
+			latency_lines = 4;
+			latency_buf_bytes = params->src_w * params->bpp *
+				latency_lines;
+		} else {
+			latency_lines = 2;
+			latency_buf_bytes = ALIGN(params->src_w * params->bpp *
+				latency_lines, mdata->smp_mb_size) * 2;
+		}
+	} else {
+		if (params->is_tile) {
+			latency_lines = 8;
+			latency_buf_bytes = params->src_w * params->bpp *
+				latency_lines;
+		} else if (params->is_bwc) {
+			latency_lines = 4;
+			latency_buf_bytes = params->src_w * params->bpp *
+				latency_lines;
+		} else {
+			latency_lines = 2;
+			latency_buf_bytes = ALIGN(params->src_w * params->bpp *
+				latency_lines, mdata->smp_mb_size);
+		}
+	}
+
+	return latency_buf_bytes;
+}
+
+static inline u32 mdss_mdp_calc_scaling_w_h(u32 val, u32 src_h, u32 dst_h,
+	u32 src_w, u32 dst_w)
+{
+	if (dst_h)
+		val = mult_frac(val, src_h, dst_h);
+	if (dst_w)
+		val = mult_frac(val, src_w, dst_w);
+
+	return val;
+}
+
+static u32 mdss_mdp_perf_calc_pipe_prefill_video(struct mdss_mdp_prefill_params
+	*params)
+{
+	struct mdss_data_type *mdata = mdss_mdp_get_mdata();
+	struct mdss_prefill_data *prefill = &mdata->prefill_data;
+	u32 prefill_bytes;
+	u32 latency_buf_bytes;
+	u32 y_buf_bytes = 0;
+	u32 y_scaler_bytes;
+	u32 pp_bytes = 0, pp_lines = 0;
+	u32 post_scaler_bytes;
+	u32 fbc_bytes = 0;
+
+	prefill_bytes = prefill->ot_bytes;
+
+	latency_buf_bytes = mdss_mdp_calc_latency_buf_bytes(params, prefill);
+	prefill_bytes += latency_buf_bytes;
+	pr_debug("latency_buf_bytes bw_calc=%d actual=%d\n", latency_buf_bytes,
+		params->smp_bytes);
+
+	if (params->is_yuv)
+		y_buf_bytes = prefill->y_buf_bytes;
+
+	y_scaler_bytes = mdss_mdp_calc_y_scaler_bytes(params, prefill);
+
+	prefill_bytes += y_buf_bytes + y_scaler_bytes;
+
+	post_scaler_bytes = prefill->post_scaler_pixels * params->bpp;
+	post_scaler_bytes = mdss_mdp_calc_scaling_w_h(post_scaler_bytes,
+		params->src_h, params->dst_h, params->src_w, params->dst_w);
+	prefill_bytes += post_scaler_bytes;
+
+	if (params->xres)
+		pp_lines = DIV_ROUND_UP(prefill->pp_pixels, params->xres);
+	if (params->xres && params->dst_h && (params->dst_y <= pp_lines))
+		pp_bytes = ((params->src_w * params->bpp * prefill->pp_pixels /
+				params->xres) * params->src_h) / params->dst_h;
+	prefill_bytes += pp_bytes;
+
+	if (params->is_fbc) {
+		fbc_bytes = prefill->fbc_lines * params->bpp;
+		fbc_bytes = mdss_mdp_calc_scaling_w_h(fbc_bytes, params->src_h,
+			params->dst_h, params->src_w, params->dst_w);
+	}
+	prefill_bytes += fbc_bytes;
+
+	pr_debug("ot=%d y_buf=%d pp_lines=%d pp=%d post_sc=%d fbc_bytes=%d\n",
+		prefill->ot_bytes, y_buf_bytes, pp_lines, pp_bytes,
+		post_scaler_bytes, fbc_bytes);
+
+	return prefill_bytes;
+}
+
+static u32 mdss_mdp_perf_calc_pipe_prefill_cmd(struct mdss_mdp_prefill_params
+	*params)
+{
+	struct mdss_data_type *mdata = mdss_mdp_get_mdata();
+	struct mdss_prefill_data *prefill = &mdata->prefill_data;
+	u32 prefill_bytes;
+	u32 ot_bytes = 0;
+	u32 latency_lines, latency_buf_bytes;
+	u32 y_buf_bytes = 0;
+	u32 y_scaler_bytes;
+	u32 fbc_cmd_lines = 0, fbc_cmd_bytes = 0;
+	u32 post_scaler_bytes = 0;
+
+	/* y_scaler_bytes are same for the first or non first line */
+	y_scaler_bytes = mdss_mdp_calc_y_scaler_bytes(params, prefill);
+	prefill_bytes = y_scaler_bytes;
+
+	/* 1st line if fbc is not enabled and 2nd line if fbc is enabled */
+	if (((params->dst_y == 0) && !params->is_fbc) ||
+		((params->dst_y <= 1) && params->is_fbc)) {
+		if (params->is_bwc || params->is_tile)
+			latency_lines = 4;
+		else if (!params->is_caf && params->is_hflip)
+			latency_lines = 1;
+		else
+			latency_lines = 0;
+		latency_buf_bytes = params->src_w * params->bpp * latency_lines;
+		prefill_bytes += latency_buf_bytes;
+
+		fbc_cmd_lines++;
+		if (params->is_fbc)
+			fbc_cmd_lines++;
+		fbc_cmd_bytes = params->bpp * params->dst_w * fbc_cmd_lines;
+		fbc_cmd_bytes = mdss_mdp_calc_scaling_w_h(fbc_cmd_bytes,
+			params->src_h, params->dst_h, params->src_w,
+			params->dst_w);
+		prefill_bytes += fbc_cmd_bytes;
+	} else {
+		ot_bytes = prefill->ot_bytes;
+		prefill_bytes += ot_bytes;
+
+		latency_buf_bytes = mdss_mdp_calc_latency_buf_bytes(params,
+			prefill);
+		prefill_bytes += latency_buf_bytes;
+
+		if (params->is_yuv)
+			y_buf_bytes = prefill->y_buf_bytes;
+		prefill_bytes += y_buf_bytes;
+
+		post_scaler_bytes = prefill->post_scaler_pixels * params->bpp;
+		post_scaler_bytes = mdss_mdp_calc_scaling_w_h(post_scaler_bytes,
+			params->src_h, params->dst_h, params->src_w,
+			params->dst_w);
+		prefill_bytes += post_scaler_bytes;
+	}
+
+	pr_debug("ot=%d bwc=%d smp=%d y_buf=%d fbc=%d\n", ot_bytes,
+		params->is_bwc, latency_buf_bytes, y_buf_bytes, fbc_cmd_bytes);
+
+	return prefill_bytes;
 }
 
 /**
@@ -176,6 +307,7 @@
  * @pipe:	Source pipe struct containing updated pipe params
  * @perf:	Structure containing values that should be updated for
  *		performance tuning
+ * @apply_fudge:	Boolean to determine if mdp clock fudge is applicable
  *
  * Function calculates the minimum required performance calculations in order
  * to avoid MDP underflow. The calculations are based on the way MDP
@@ -183,16 +315,23 @@
  * (MDP clock requirement) based on frame size and scaling requirements.
  */
 int mdss_mdp_perf_calc_pipe(struct mdss_mdp_pipe *pipe,
-		struct mdss_mdp_perf_params *perf)
+	struct mdss_mdp_perf_params *perf, struct mdss_mdp_img_rect *roi,
+	bool apply_fudge)
 {
 	struct mdss_mdp_mixer *mixer;
 	int fps = DEFAULT_FRAME_RATE;
-	u32 quota, rate, v_total, src_h;
+	u32 quota, rate, v_total, src_h, xres = 0;
+	struct mdss_mdp_img_rect src, dst;
+	bool is_fbc = false;
+	struct mdss_mdp_prefill_params prefill_params;
 
 	if (!pipe || !perf || !pipe->mixer)
 		return -EINVAL;
 
 	mixer = pipe->mixer;
+	dst = pipe->dst;
+	src = pipe->src;
+
 	if (mixer->rotator_mode) {
 		v_total = pipe->flags & MDP_ROT_90 ? pipe->dst.w : pipe->dst.h;
 	} else if (mixer->type == MDSS_MDP_MIXER_TYPE_INTF) {
@@ -201,18 +340,31 @@
 		pinfo = &mixer->ctl->panel_data->panel_info;
 		fps = mdss_panel_get_framerate(pinfo);
 		v_total = mdss_panel_get_vtotal(pinfo);
+		xres = pinfo->xres;
+		is_fbc = pinfo->fbc.enabled;
 	} else {
 		v_total = mixer->height;
+		xres = mixer->width;
 	}
 
+	if (roi)
+		mdss_mdp_crop_rect(&src, &dst, roi);
+
+	pr_debug("v_total=%d, xres=%d fps=%d\n", v_total, xres, fps);
+
 	/*
 	 * when doing vertical decimation lines will be skipped, hence there is
 	 * no need to account for these lines in MDP clock or request bus
 	 * bandwidth to fetch them.
 	 */
-	src_h = pipe->src.h >> pipe->vert_deci;
+	src_h = src.h >> pipe->vert_deci;
 
-	quota = fps * pipe->src.w * src_h;
+	quota = fps * src.w * src_h;
+
+	pr_debug("src(w,h)(%d,%d) dst(w,h)(%d,%d) dst_y=%d bpp=%d yuv=%d\n",
+		 pipe->src.w, src_h, pipe->dst.w, pipe->dst.h, pipe->dst.y,
+		 pipe->src_fmt->bpp, pipe->src_fmt->is_yuv);
+
 	if (pipe->src_fmt->chroma_sample == MDSS_MDP_CHROMA_420)
 		/*
 		 * with decimation, chroma is not downsampled, this means we
@@ -225,41 +377,84 @@
 	else
 		quota *= pipe->src_fmt->bpp;
 
-	rate = pipe->dst.w;
-	if (src_h > pipe->dst.h)
-		rate = (rate * src_h) / pipe->dst.h;
+	rate = dst.w;
+	if (src_h > dst.h)
+		rate = (rate * src_h) / dst.h;
 
 	rate *= v_total * fps;
 	if (mixer->rotator_mode) {
 		rate /= 4; /* block mode fetch at 4 pix/clk */
 		quota *= 2; /* bus read + write */
-		perf->ib_quota = quota;
+		perf->bw_overlap = quota;
 	} else {
-		perf->ib_quota = (quota / pipe->dst.h) * v_total;
+		perf->bw_overlap = (quota / dst.h) * v_total;
 	}
-	perf->ab_quota = quota;
-	perf->mdp_clk_rate = rate;
 
-	pr_debug("mixer=%d pnum=%d clk_rate=%u bus ab=%u ib=%u\n",
-		 mixer->num, pipe->num, rate, perf->ab_quota, perf->ib_quota);
+	if (apply_fudge)
+		perf->mdp_clk_rate = mdss_mdp_clk_fudge_factor(mixer, rate);
+	else
+		perf->mdp_clk_rate = rate;
+
+	prefill_params.smp_bytes = mdss_mdp_smp_get_size(pipe);
+	prefill_params.xres = xres;
+	prefill_params.src_w = src.w;
+	prefill_params.src_h = src_h;
+	prefill_params.dst_w = dst.w;
+	prefill_params.dst_h = dst.h;
+	prefill_params.dst_y = dst.y;
+	prefill_params.bpp = pipe->src_fmt->bpp;
+	prefill_params.is_yuv = pipe->src_fmt->is_yuv;
+	prefill_params.is_caf = mdss_mdp_perf_is_caf(pipe);
+	prefill_params.is_fbc = is_fbc;
+	prefill_params.is_bwc = pipe->bwc_mode;
+	prefill_params.is_tile = pipe->src_fmt->tile;
+	prefill_params.is_hflip = pipe->flags & MDP_FLIP_LR;
+
+	if (mixer->type == MDSS_MDP_MIXER_TYPE_INTF) {
+		perf->prefill_bytes = (mixer->ctl->is_video_mode) ?
+			mdss_mdp_perf_calc_pipe_prefill_video(&prefill_params) :
+			mdss_mdp_perf_calc_pipe_prefill_cmd(&prefill_params);
+	}
+	else
+		perf->prefill_bytes = 0;
+
+	pr_debug("mixer=%d pnum=%d clk_rate=%u bw_overlap=%llu prefill=%d\n",
+		 mixer->num, pipe->num, perf->mdp_clk_rate, perf->bw_overlap,
+		 perf->prefill_bytes);
 
 	return 0;
 }
 
-static void mdss_mdp_perf_mixer_update(struct mdss_mdp_mixer *mixer,
-				       u32 *bus_ab_quota, u32 *bus_ib_quota,
-				       u32 *clk_rate)
+static inline int mdss_mdp_perf_is_overlap(u32 y00, u32 y01, u32 y10, u32 y11)
+{
+	return (y10 < y00 && y11 >= y01) || (y10 >= y00 && y10 < y01);
+}
+
+static inline int cmpu32(const void *a, const void *b)
+{
+	return (*(u32 *)a < *(u32 *)b) ? -1 : 0;
+}
+
+static void mdss_mdp_perf_calc_mixer(struct mdss_mdp_mixer *mixer,
+		struct mdss_mdp_perf_params *perf,
+		struct mdss_mdp_pipe **pipe_list, int num_pipes)
 {
 	struct mdss_mdp_pipe *pipe;
 	struct mdss_panel_info *pinfo = NULL;
 	int fps = DEFAULT_FRAME_RATE;
-	u32 v_total;
+	u32 v_total = 0;
 	int i;
-	u32 max_clk_rate = 0, ab_total = 0, ib_total = 0;
+	u32 max_clk_rate = 0;
+	u64 bw_overlap_max = 0;
+	u64 bw_overlap[MDSS_MDP_MAX_STAGE] = { 0 };
+	u32 v_region[MDSS_MDP_MAX_STAGE * 2] = { 0 };
+	u32 prefill_bytes = 0;
+	struct mdss_data_type *mdata = mdss_mdp_get_mdata();
+	bool apply_fudge = true;
 
-	*bus_ab_quota = 0;
-	*bus_ib_quota = 0;
-	*clk_rate = 0;
+	BUG_ON(num_pipes > MDSS_MDP_MAX_STAGE);
+
+	memset(perf, 0, sizeof(*perf));
 
 	if (!mixer->rotator_mode) {
 		if (mixer->type == MDSS_MDP_MIXER_TYPE_INTF) {
@@ -272,100 +467,519 @@
 		} else {
 			v_total = mixer->height;
 		}
-		*clk_rate = mixer->width * v_total * fps;
-		if (pinfo && pinfo->lcdc.v_back_porch < MDP_MIN_VBP)
-			*clk_rate = MDSS_MDP_CLK_FUDGE_FACTOR(*clk_rate);
 
-		if (!pinfo) {
-			/* perf for bus writeback */
-			*bus_ab_quota = fps * mixer->width * mixer->height * 3;
-			*bus_ab_quota >>= MDSS_MDP_BUS_FACTOR_SHIFT;
-			*bus_ib_quota = *bus_ab_quota;
+		perf->mdp_clk_rate = mixer->width * v_total * fps;
+		perf->mdp_clk_rate =
+			mdss_mdp_clk_fudge_factor(mixer, perf->mdp_clk_rate);
+
+		if (!pinfo)	/* perf for bus writeback */
+			perf->bw_overlap =
+				fps * mixer->width * mixer->height * 3;
+	}
+
+	memset(bw_overlap, 0, sizeof(u64) * MDSS_MDP_MAX_STAGE);
+	memset(v_region, 0, sizeof(u32) * MDSS_MDP_MAX_STAGE * 2);
+
+	/*
+	* Apply this logic only for 8x26 to reduce clock rate
+	* for single video playback use case
+	*/
+	if (IS_MDSS_MAJOR_MINOR_SAME(mdata->mdp_rev, MDSS_MDP_HW_REV_101)
+		 && mixer->type == MDSS_MDP_MIXER_TYPE_INTF) {
+		u32 npipes = 0;
+		for (i = 0; i < MDSS_MDP_MAX_STAGE; i++) {
+			pipe = mixer->stage_pipe[i];
+			if (pipe) {
+				if (npipes) {
+					apply_fudge = true;
+					break;
+				}
+				npipes++;
+				apply_fudge = !(pipe->src_fmt->is_yuv)
+					|| !(pipe->flags
+					& MDP_SOURCE_ROTATED_90);
+			}
 		}
 	}
 
-	for (i = 0; i < MDSS_MDP_MAX_STAGE; i++) {
-		struct mdss_mdp_perf_params perf;
-		pipe = mixer->stage_pipe[i];
+	for (i = 0; i < num_pipes; i++) {
+		struct mdss_mdp_perf_params tmp;
+		pipe = pipe_list[i];
 		if (pipe == NULL)
 			continue;
 
-		if (mdss_mdp_perf_calc_pipe(pipe, &perf))
+		if (mdss_mdp_perf_calc_pipe(pipe, &tmp, &mixer->roi,
+			apply_fudge))
 			continue;
-
-		ab_total += perf.ab_quota >> MDSS_MDP_BUS_FACTOR_SHIFT;
-		ib_total += perf.ib_quota >> MDSS_MDP_BUS_FACTOR_SHIFT;
-		if (perf.mdp_clk_rate > max_clk_rate)
-			max_clk_rate = perf.mdp_clk_rate;
+		prefill_bytes += tmp.prefill_bytes;
+		bw_overlap[i] = tmp.bw_overlap;
+		v_region[2*i] = pipe->dst.y;
+		v_region[2*i + 1] = pipe->dst.y + pipe->dst.h;
+		if (tmp.mdp_clk_rate > max_clk_rate)
+			max_clk_rate = tmp.mdp_clk_rate;
 	}
 
-	*bus_ab_quota += ab_total;
-	*bus_ib_quota += ib_total;
-	if (max_clk_rate > *clk_rate)
-		*clk_rate = max_clk_rate;
+	/*
+	 * Sort the v_region array so the total display area can be
+	 * divided into individual regions. Check how many pipes fetch
+	 * data for each region and sum them up, then the worst case
+	 * of all regions is ib request.
+	 */
+	sort(v_region, num_pipes * 2, sizeof(u32), cmpu32, NULL);
+	for (i = 1; i < num_pipes * 2; i++) {
+		int j;
+		u64 bw_max_region = 0;
+		u32 y0, y1;
+		pr_debug("v_region[%d]%d\n", i, v_region[i]);
+		if (v_region[i] == v_region[i-1])
+			continue;
+		y0 = v_region[i-1];
+		y1 = v_region[i];
+		for (j = 0; j < num_pipes; j++) {
+			if (!bw_overlap[j])
+				continue;
+			pipe = pipe_list[j];
+			if (mdss_mdp_perf_is_overlap(y0, y1, pipe->dst.y,
+				(pipe->dst.y + pipe->dst.h)))
+				bw_max_region += bw_overlap[j];
+			pr_debug("v[%d](%d,%d)pipe[%d](%d,%d)bw(%llu %llu)\n",
+				i, y0, y1, j, pipe->dst.y,
+				pipe->dst.y + pipe->dst.h, bw_overlap[j],
+				bw_max_region);
+		}
+		bw_overlap_max = max(bw_overlap_max, bw_max_region);
+	}
 
-	pr_debug("final mixer=%d clk_rate=%u bus ab=%u ib=%u\n", mixer->num,
-		 *clk_rate, *bus_ab_quota, *bus_ib_quota);
+	perf->bw_overlap += bw_overlap_max;
+	perf->prefill_bytes += prefill_bytes;
+
+	if (max_clk_rate > perf->mdp_clk_rate)
+		perf->mdp_clk_rate = max_clk_rate;
+
+	pr_debug("final mixer=%d video=%d clk_rate=%u bw=%llu prefill=%d\n",
+		mixer->num, mixer->ctl->is_video_mode, perf->mdp_clk_rate,
+		perf->bw_overlap, perf->prefill_bytes);
+
 }
 
-static int mdss_mdp_ctl_perf_update(struct mdss_mdp_ctl *ctl)
+static u32 mdss_mdp_get_vbp_factor(struct mdss_mdp_ctl *ctl)
 {
-	int ret = MDSS_MDP_PERF_UPDATE_SKIP;
-	u32 clk_rate, ab_quota, ib_quota;
-	u32 max_clk_rate = 0, total_ab_quota = 0, total_ib_quota = 0;
+	u32 fps, v_total, vbp, vbp_fac;
+	struct mdss_panel_info *pinfo;
 
-	if (ctl->mixer_left) {
-		mdss_mdp_perf_mixer_update(ctl->mixer_left, &ab_quota,
-					   &ib_quota, &clk_rate);
-		total_ab_quota += ab_quota;
-		total_ib_quota += ib_quota;
-		max_clk_rate = clk_rate;
+	if (!ctl || !ctl->panel_data)
+		return 0;
+
+	pinfo = &ctl->panel_data->panel_info;
+	fps = mdss_panel_get_framerate(pinfo);
+	v_total = mdss_panel_get_vtotal(pinfo);
+	vbp = pinfo->lcdc.v_back_porch + pinfo->lcdc.v_pulse_width;
+	vbp_fac = (vbp) ? fps * v_total / vbp : 0;
+	pr_debug("vbp_fac=%d vbp=%d v_total=%d\n", vbp_fac, vbp, v_total);
+
+	return vbp_fac;
+}
+
+static u32 mdss_mdp_get_vbp_factor_max(struct mdss_mdp_ctl *ctl)
+{
+	u32 vbp_max = 0;
+	int i;
+	struct mdss_data_type *mdata;
+
+	if (!ctl || !ctl->mdata)
+		return 0;
+
+	mdata = ctl->mdata;
+	for (i = 0; i < mdata->nctl; i++) {
+		struct mdss_mdp_ctl *ctl = mdata->ctl_off + i;
+		u32 vbp_fac;
+
+		if (ctl->power_on) {
+			vbp_fac = mdss_mdp_get_vbp_factor(ctl);
+			vbp_max = max(vbp_max, vbp_fac);
+		}
 	}
 
-	if (ctl->mixer_right) {
-		mdss_mdp_perf_mixer_update(ctl->mixer_right, &ab_quota,
-					   &ib_quota, &clk_rate);
-		total_ab_quota += ab_quota;
-		total_ib_quota += ib_quota;
-		if (clk_rate > max_clk_rate)
-			max_clk_rate = clk_rate;
+	return vbp_max;
+}
+
+static void __mdss_mdp_perf_calc_ctl_helper(struct mdss_mdp_ctl *ctl,
+		struct mdss_mdp_perf_params *perf,
+		struct mdss_mdp_pipe **left_plist, int left_cnt,
+		struct mdss_mdp_pipe **right_plist, int right_cnt)
+{
+	struct mdss_mdp_perf_params tmp;
+
+	memset(perf, 0, sizeof(*perf));
+
+	if (left_cnt && ctl->mixer_left) {
+		mdss_mdp_perf_calc_mixer(ctl->mixer_left, &tmp,
+				left_plist, left_cnt);
+		perf->bw_overlap += tmp.bw_overlap;
+		perf->prefill_bytes += tmp.prefill_bytes;
+		perf->mdp_clk_rate = tmp.mdp_clk_rate;
+	}
+
+	if (right_cnt && ctl->mixer_right) {
+		mdss_mdp_perf_calc_mixer(ctl->mixer_right, &tmp,
+				right_plist, right_cnt);
+		perf->bw_overlap += tmp.bw_overlap;
+		perf->prefill_bytes += tmp.prefill_bytes;
+		if (tmp.mdp_clk_rate > perf->mdp_clk_rate)
+			perf->mdp_clk_rate = tmp.mdp_clk_rate;
 
 		if (ctl->intf_type) {
-			clk_rate = mdss_mdp_get_pclk_rate(ctl);
+			u32 clk_rate = mdss_mdp_get_pclk_rate(ctl);
 			/* minimum clock rate due to inefficiency in 3dmux */
 			clk_rate = mult_frac(clk_rate >> 1, 9, 8);
-			if (clk_rate > max_clk_rate)
-				max_clk_rate = clk_rate;
+			if (clk_rate > perf->mdp_clk_rate)
+				perf->mdp_clk_rate = clk_rate;
 		}
 	}
 
 	/* request minimum bandwidth to have bus clock on when display is on */
-	if (total_ib_quota == 0)
-		total_ib_quota = SZ_16M >> MDSS_MDP_BUS_FACTOR_SHIFT;
+	if (perf->bw_overlap == 0)
+		perf->bw_overlap = SZ_16M;
 
-	if (max_clk_rate != ctl->clk_rate) {
-		if (max_clk_rate > ctl->clk_rate)
-			ret = MDSS_MDP_PERF_UPDATE_EARLY;
+	if (ctl->intf_type != MDSS_MDP_NO_INTF) {
+		u32 vbp_fac = mdss_mdp_get_vbp_factor_max(ctl);
+
+		perf->bw_prefill = perf->prefill_bytes;
+		/*
+		 * Prefill bandwidth equals the amount of data (number
+		 * of prefill_bytes) divided by the the amount time
+		 * available (blanking period). It is equivalent that
+		 * prefill bytes times a factor in unit Hz, which is
+		 * the reciprocal of time.
+		 */
+		perf->bw_prefill *= vbp_fac;
+	}
+
+	perf->bw_ctl = max(perf->bw_prefill, perf->bw_overlap);
+}
+
+int mdss_mdp_perf_bw_check(struct mdss_mdp_ctl *ctl,
+		struct mdss_mdp_pipe **left_plist, int left_cnt,
+		struct mdss_mdp_pipe **right_plist, int right_cnt)
+{
+	struct mdss_data_type *mdata = ctl->mdata;
+	struct mdss_mdp_perf_params perf;
+	u32 bw, threshold;
+
+	/* we only need bandwidth check on real-time clients (interfaces) */
+	if (ctl->intf_type == MDSS_MDP_NO_INTF)
+		return 0;
+
+	__mdss_mdp_perf_calc_ctl_helper(ctl, &perf,
+			left_plist, left_cnt, right_plist, right_cnt);
+
+	/* convert bandwidth to kb */
+	bw = DIV_ROUND_UP_ULL(perf.bw_ctl, 1000);
+	pr_debug("calculated bandwidth=%uk\n", bw);
+
+	threshold = ctl->is_video_mode ? mdata->max_bw_low : mdata->max_bw_high;
+	if (bw > threshold) {
+		pr_debug("exceeds bandwidth: %ukb > %ukb\n", bw, threshold);
+		return -E2BIG;
+	}
+
+	return 0;
+}
+
+static void mdss_mdp_perf_calc_ctl(struct mdss_mdp_ctl *ctl,
+		struct mdss_mdp_perf_params *perf)
+{
+	struct mdss_mdp_pipe **left_plist, **right_plist;
+
+	left_plist = ctl->mixer_left ? ctl->mixer_left->stage_pipe : NULL;
+	right_plist = ctl->mixer_right ? ctl->mixer_right->stage_pipe : NULL;
+
+	__mdss_mdp_perf_calc_ctl_helper(ctl, perf,
+			left_plist, (left_plist ? MDSS_MDP_MAX_STAGE : 0),
+			right_plist, (right_plist ? MDSS_MDP_MAX_STAGE : 0));
+
+	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
-			ret = MDSS_MDP_PERF_UPDATE_LATE;
-		ctl->clk_rate = max_clk_rate;
-		ctl->perf_changed |= MDSS_MDP_PERF_UPDATE_CLK;
+			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_bytes=%d\n",
+		 perf->bw_overlap, perf->bw_prefill, perf->prefill_bytes);
+}
+
+static void set_status(u32 *value, bool status, u32 bit_num)
+{
+	if (status)
+		*value |= BIT(bit_num);
+	else
+		*value &= ~BIT(bit_num);
+}
+
+/**
+ * @ 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
+ *
+ * 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_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_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;
 	}
 
-	if ((total_ab_quota != ctl->bus_ab_quota) ||
-			(total_ib_quota != ctl->bus_ib_quota)) {
-		if (ret == MDSS_MDP_PERF_UPDATE_SKIP) {
-			if (total_ib_quota >= ctl->bus_ib_quota)
-				ret = MDSS_MDP_PERF_UPDATE_EARLY;
-			else
-				ret = MDSS_MDP_PERF_UPDATE_LATE;
+	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)
+{
+	u64 bw_sum_of_intfs = 0;
+	u64 bus_ab_quota, bus_ib_quota;
+	struct mdss_data_type *mdata;
+	int i;
+
+	if (!ctl || !ctl->mdata)
+		return;
+
+	mdata = ctl->mdata;
+	for (i = 0; i < mdata->nctl; i++) {
+		struct mdss_mdp_ctl *ctl;
+		ctl = mdata->ctl_off + i;
+		if (ctl->power_on) {
+			bw_sum_of_intfs += ctl->cur_perf.bw_ctl;
+			pr_debug("c=%d bw=%llu\n", ctl->num,
+				ctl->cur_perf.bw_ctl);
 		}
-		ctl->bus_ab_quota = total_ab_quota;
-		ctl->bus_ib_quota = total_ib_quota;
-		ctl->perf_changed |= MDSS_MDP_PERF_UPDATE_BUS;
+	}
+	bus_ib_quota = 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);
+}
+
+/**
+ * @mdss_mdp_ctl_perf_release_bw() - request zero bandwidth
+ * @ctl - pointer to a ctl
+ *
+ * Function checks a state variable for the ctl, if all pending commit
+ * requests are done, meaning no more bandwidth is needed, release
+ * bandwidth request.
+ */
+void mdss_mdp_ctl_perf_release_bw(struct mdss_mdp_ctl *ctl)
+{
+	int transaction_status;
+	struct mdss_data_type *mdata;
+	int i;
+
+	/* only do this for command panel */
+	if (!ctl || !ctl->mdata || !ctl->panel_data ||
+		(ctl->panel_data->panel_info.type != MIPI_CMD_PANEL))
+		return;
+
+	mutex_lock(&mdss_mdp_ctl_lock);
+	mdata = ctl->mdata;
+	/*
+	 * If video interface present, cmd panel bandwidth cannot be
+	 * released.
+	 */
+	for (i = 0; i < mdata->nctl; i++) {
+		struct mdss_mdp_ctl *ctl = mdata->ctl_off + i;
+
+		if (ctl->power_on && ctl->is_video_mode)
+			goto exit;
 	}
 
-	return ret;
+	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;
+		}
+	}
+
+	return clk_rate;
+}
+
+static void mdss_mdp_ctl_perf_update(struct mdss_mdp_ctl *ctl,
+		int params_changed)
+{
+	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;
+
+	mutex_lock(&mdss_mdp_ctl_lock);
+
+	mdata = ctl->mdata;
+	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 (is_bw_released || params_changed)
+			mdss_mdp_perf_calc_ctl(ctl, new);
+		/*
+		 * if params have just changed delay the update until
+		 * later once the hw configuration has been flushed to
+		 * MDP
+		 */
+		if ((params_changed && (new->bw_ctl > old->bw_ctl)) ||
+		    (!params_changed && (new->bw_ctl < old->bw_ctl))) {
+			pr_debug("c=%d p=%d new_bw=%llu,old_bw=%llu\n",
+				ctl->num, params_changed, new->bw_ctl,
+				old->bw_ctl);
+			old->bw_ctl = new->bw_ctl;
+			update_bus = 1;
+		}
+
+		if ((params_changed && (new->mdp_clk_rate > old->mdp_clk_rate))
+		    || (!params_changed && (new->mdp_clk_rate <
+					    old->mdp_clk_rate))) {
+			old->mdp_clk_rate = new->mdp_clk_rate;
+			update_clk = 1;
+		}
+	} else {
+		memset(old, 0, sizeof(old));
+		memset(new, 0, sizeof(new));
+		update_bus = 1;
+		update_clk = 1;
+	}
+
+	if (update_bus)
+		mdss_mdp_ctl_perf_update_bus(ctl);
+
+	if (update_clk) {
+		u32 clk_rate = 0;
+		int i;
+
+		for (i = 0; i < mdata->nctl; i++) {
+			struct mdss_mdp_ctl *ctl;
+			ctl = mdata->ctl_off + i;
+			if (ctl->power_on)
+				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);
+	}
+
+	mutex_unlock(&mdss_mdp_ctl_lock);
 }
 
 static struct mdss_mdp_ctl *mdss_mdp_ctl_alloc(struct mdss_data_type *mdata,
@@ -385,6 +999,7 @@
 			ctl->ref_cnt++;
 			ctl->mdata = mdata;
 			mutex_init(&ctl->lock);
+			spin_lock_init(&ctl->spin_lock);
 			BLOCKING_INIT_NOTIFIER_HEAD(&ctl->notifier_head);
 			pr_debug("alloc ctl_num=%d\n", ctl->num);
 			break;
@@ -606,13 +1221,17 @@
 
 	mdss_mdp_ctl_free(ctl);
 
-	mdss_mdp_ctl_perf_commit(ctl->mdata, MDSS_MDP_PERF_UPDATE_ALL);
+	mdss_mdp_ctl_perf_update(ctl, 0);
 
 	return 0;
 }
 
 int mdss_mdp_ctl_splash_finish(struct mdss_mdp_ctl *ctl, bool handoff)
 {
+	struct mdss_mdp_ctl *sctl = mdss_mdp_get_split_ctl(ctl);
+	if (sctl)
+		sctl->panel_data->panel_info.cont_splash_enabled = 0;
+
 	switch (ctl->panel_data->panel_info.type) {
 	case MIPI_VIDEO_PANEL:
 	case EDP_PANEL:
@@ -637,15 +1256,6 @@
 	return 0;
 }
 
-static inline struct mdss_mdp_ctl *mdss_mdp_get_split_ctl(
-		struct mdss_mdp_ctl *ctl)
-{
-	if (ctl && ctl->mixer_right && (ctl->mixer_right->ctl != ctl))
-		return ctl->mixer_right->ctl;
-
-	return NULL;
-}
-
 static int mdss_mdp_ctl_fbc_enable(int enable,
 		struct mdss_mdp_mixer *mixer, struct mdss_panel_info *pdata)
 {
@@ -1062,6 +1672,27 @@
 	return rc;
 }
 
+/*
+ * mdss_mdp_ctl_restore() - restore mdp ctl path
+ * @ctl: mdp controller.
+ *
+ * This function is called whenever MDP comes out of a power collapse as
+ * a result of a screen update when DSI ULPS mode is enabled. It restores
+ * the MDP controller's software state to the hardware registers.
+ */
+void mdss_mdp_ctl_restore(struct mdss_mdp_ctl *ctl)
+{
+	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)
 {
 	struct mdss_mdp_mixer *mixer;
@@ -1142,9 +1773,7 @@
 	if (!handoff)
 		ctl->power_on = true;
 
-	ctl->bus_ab_quota = 0;
-	ctl->bus_ib_quota = 0;
-	ctl->clk_rate = 0;
+	memset(&ctl->cur_perf, 0, sizeof(ctl->cur_perf));
 
 	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
 
@@ -1233,8 +1862,7 @@
 
 		ctl->power_on = false;
 		ctl->play_cnt = 0;
-		ctl->clk_rate = 0;
-		mdss_mdp_ctl_perf_commit(ctl->mdata, MDSS_MDP_PERF_UPDATE_ALL);
+		mdss_mdp_ctl_perf_update(ctl, 0);
 	}
 
 	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
@@ -1331,6 +1959,7 @@
 	int stage, secure = 0;
 	int screen_state;
 	int outsize = 0;
+	u32 op_mode;
 
 	screen_state = ctl->force_screen_state;
 
@@ -1459,9 +2088,16 @@
 
 	if (mixer->num == MDSS_MDP_INTF_LAYERMIXER3)
 		ctl->flush_bits |= BIT(20);
+	else if (mixer->type == MDSS_MDP_MIXER_TYPE_WRITEBACK)
+		ctl->flush_bits |= BIT(9) << mixer->num;
 	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);
@@ -1676,6 +2312,33 @@
 	return 0;
 }
 
+/**
+ * mdss_mdp_mixer_unstage_all() - Unstage all pipes from mixer
+ * @mixer:	Mixer from which to unstage all pipes
+ *
+ * Unstage any pipes that are currently attached to mixer.
+ *
+ * NOTE: this will not update the pipe structure, and thus a full
+ * deinitialization or reconfiguration of all pipes is expected after this call.
+ */
+void mdss_mdp_mixer_unstage_all(struct mdss_mdp_mixer *mixer)
+{
+	struct mdss_mdp_pipe *tmp;
+	int i;
+
+	if (!mixer)
+		return;
+
+	for (i = 0; i < MDSS_MDP_MAX_STAGE; i++) {
+		tmp = mixer->stage_pipe[i];
+		if (tmp) {
+			mixer->stage_pipe[i] = NULL;
+			mixer->params_changed++;
+			tmp->params_changed++;
+		}
+	}
+}
+
 int mdss_mdp_mixer_pipe_unstage(struct mdss_mdp_pipe *pipe)
 {
 	struct mdss_mdp_ctl *ctl;
@@ -1727,9 +2390,12 @@
 int mdss_mdp_ctl_update_fps(struct mdss_mdp_ctl *ctl, int fps)
 {
 	int ret = 0;
+	struct mdss_mdp_ctl *sctl = NULL;
+
+	sctl = mdss_mdp_get_split_ctl(ctl);
 
 	if (ctl->config_fps_fnc)
-		ret = ctl->config_fps_fnc(ctl, fps);
+		ret = ctl->config_fps_fnc(ctl, sctl, fps);
 
 	return ret;
 }
@@ -1820,10 +2486,7 @@
 	if (ctl->wait_fnc)
 		ret = ctl->wait_fnc(ctl, NULL);
 
-	if (ctl->perf_changed) {
-		mdss_mdp_ctl_perf_commit(ctl->mdata, ctl->perf_changed);
-		ctl->perf_changed = 0;
-	}
+	mdss_mdp_ctl_perf_update(ctl, 0);
 
 	mutex_unlock(&ctl->lock);
 
@@ -1856,7 +2519,7 @@
 	struct mdss_mdp_ctl *sctl = NULL;
 	int mixer1_changed, mixer2_changed;
 	int ret = 0;
-	int perf_update = MDSS_MDP_PERF_UPDATE_SKIP;
+	bool is_bw_released;
 
 	if (!ctl) {
 		pr_err("display function not set\n");
@@ -1877,10 +2540,17 @@
 	mixer2_changed = (ctl->mixer_right && ctl->mixer_right->params_changed);
 
 	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
-	if (mixer1_changed || mixer2_changed
-			|| ctl->force_screen_state) {
-		perf_update = mdss_mdp_ctl_perf_update(ctl);
 
+	/*
+	 * 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);
 		if (ret) {
@@ -1888,10 +2558,7 @@
 			goto done;
 		}
 
-		if (perf_update == MDSS_MDP_PERF_UPDATE_EARLY) {
-			mdss_mdp_ctl_perf_commit(ctl->mdata, ctl->perf_changed);
-			ctl->perf_changed = 0;
-		}
+		mdss_mdp_ctl_perf_update(ctl, 1);
 
 		if (mixer1_changed)
 			mdss_mdp_mixer_update(ctl->mixer_left);
@@ -1908,11 +2575,15 @@
 		}
 	}
 
-	mdss_mdp_ctl_notify(ctl, MDP_NOTIFY_FRAME_READY);
+	if (!ctl->shared_lock)
+		mdss_mdp_ctl_notify(ctl, MDP_NOTIFY_FRAME_READY);
 
 	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);
@@ -1925,6 +2596,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)
@@ -2090,3 +2763,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_formats.h b/drivers/video/msm/mdss/mdss_mdp_formats.h
index a2edf90..dcbff88 100644
--- a/drivers/video/msm/mdss/mdss_mdp_formats.h
+++ b/drivers/video/msm/mdss/mdss_mdp_formats.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
@@ -81,6 +81,25 @@
 		},						\
 	}
 
+#define FMT_RGB_8888_TILE(fmt, alpha_en, e0, e1, e2, e3)	\
+	{							\
+		.format = (fmt),				\
+		.fetch_planes = MDSS_MDP_PLANE_INTERLEAVED,	\
+		.unpack_tight = 1,				\
+		.unpack_align_msb = 0,				\
+		.alpha_enable = (alpha_en),			\
+		.unpack_count = 4,				\
+		.bpp = 4,					\
+		.tile = 1,					\
+		.element = { (e0), (e1), (e2), (e3) },		\
+		.bits = {					\
+			[C3_ALPHA] = COLOR_8BIT,		\
+			[C2_R_Cr] = COLOR_8BIT,			\
+			[C0_G_Y] = COLOR_8BIT,			\
+			[C1_B_Cb] = COLOR_8BIT,			\
+		},						\
+	}
+
 #define FMT_YUV_COMMON(fmt)					\
 		.format = (fmt),				\
 		.is_yuv = 1,					\
@@ -125,6 +144,22 @@
 	FMT_RGB_8888(MDP_RGBX_8888, 0, C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA),
 	FMT_RGB_8888(MDP_BGRA_8888, 1, C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA),
 	FMT_RGB_8888(MDP_BGRX_8888, 0, C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA),
+	FMT_RGB_8888_TILE(MDP_RGBA_8888_TILE, 1, C2_R_Cr, C0_G_Y, C1_B_Cb,
+			C3_ALPHA),
+	FMT_RGB_8888_TILE(MDP_ARGB_8888_TILE, 1, C3_ALPHA, C2_R_Cr, C0_G_Y,
+			C1_B_Cb),
+	FMT_RGB_8888_TILE(MDP_ABGR_8888_TILE, 1, C3_ALPHA, C1_B_Cb, C0_G_Y,
+			C2_R_Cr),
+	FMT_RGB_8888_TILE(MDP_BGRA_8888_TILE, 1, C1_B_Cb, C0_G_Y, C2_R_Cr,
+			C3_ALPHA),
+	FMT_RGB_8888_TILE(MDP_RGBX_8888_TILE, 0, C2_R_Cr, C0_G_Y, C1_B_Cb,
+			C3_ALPHA),
+	FMT_RGB_8888_TILE(MDP_XRGB_8888_TILE, 0, C3_ALPHA, C2_R_Cr, C0_G_Y,
+			C1_B_Cb),
+	FMT_RGB_8888_TILE(MDP_XBGR_8888_TILE, 0, C3_ALPHA, C1_B_Cb, C0_G_Y,
+			C2_R_Cr),
+	FMT_RGB_8888_TILE(MDP_BGRX_8888_TILE, 0, C1_B_Cb, C0_G_Y, C2_R_Cr,
+			C3_ALPHA),
 
 	FMT_YUV_PSEUDO(MDP_Y_CRCB_H1V1, MDSS_MDP_CHROMA_RGB, C2_R_Cr, C1_B_Cb),
 	FMT_YUV_PSEUDO(MDP_Y_CBCR_H1V1, MDSS_MDP_CHROMA_RGB, C1_B_Cb, C2_R_Cr),
diff --git a/drivers/video/msm/mdss/mdss_mdp_hwio.h b/drivers/video/msm/mdss/mdss_mdp_hwio.h
index bcd3cf4..c11b438 100644
--- a/drivers/video/msm/mdss/mdss_mdp_hwio.h
+++ b/drivers/video/msm/mdss/mdss_mdp_hwio.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
@@ -20,11 +20,8 @@
 #define GC_LUT_SEGMENTS	16
 #define ENHIST_LUT_ENTRIES 256
 #define HIST_V_SIZE	256
-#define SIX_ZONE_LUT_ENTRIES 384
 
-#define MDSS_MDP_HW_REV_100		0x10000000
-#define MDSS_MDP_HW_REV_102		0x10020000
-#define MDSS_MDP_HW_REV_103		0x10030000
+#define MDSS_MDP_FETCH_CONFIG_RESET_VALUE	0x00000087
 
 #define MDSS_REG_HW_VERSION				0x0
 #define MDSS_REG_HW_INTR_STATUS				0x10
@@ -112,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
@@ -439,6 +437,7 @@
 #define MDSS_MDP_REG_DSPP_HIST_CTL_BASE			0x210
 #define MDSS_MDP_REG_DSPP_HIST_LUT_BASE			0x230
 #define MDSS_MDP_REG_DSPP_PA_BASE			0x238
+#define MDSS_MDP_REG_DSPP_SIX_ZONE_BASE			0x248
 #define MDSS_MDP_REG_DSPP_GAMUT_BASE			0x2DC
 #define MDSS_MDP_REG_DSPP_GC_BASE			0x2B0
 
@@ -580,4 +579,8 @@
 #define MDSS_MDP_LP_MISR_SEL_LMIX4_BLEND	0x10
 #define MDSS_MDP_LP_MISR_SEL_LMIX4_GC		0x11
 
+/* following offsets are with respect to MDP VBIF base */
+#define MMSS_VBIF_XIN_HALT_CTRL0	0x200
+#define MMSS_VBIF_XIN_HALT_CTRL1	0x204
+
 #endif
diff --git a/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c b/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c
index c4a0645..293b192 100644
--- a/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c
+++ b/drivers/video/msm/mdss/mdss_mdp_intf_cmd.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
@@ -15,18 +15,17 @@
 
 #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) */
 #define KOFF_TIMEOUT msecs_to_jiffies(84)
 
-#define STOP_TIMEOUT msecs_to_jiffies(16 * (VSYNC_EXPIRE_TICK + 2))
+#define STOP_TIMEOUT(hz) msecs_to_jiffies((1000 / hz) * (VSYNC_EXPIRE_TICK + 2))
+#define ULPS_ENTER_TIME msecs_to_jiffies(100)
 
 struct mdss_mdp_cmd_ctx {
 	struct mdss_mdp_ctl *ctl;
@@ -43,6 +42,7 @@
 	struct mutex clk_mtx;
 	spinlock_t clk_lock;
 	struct work_struct clk_work;
+	struct delayed_work ulps_work;
 	struct work_struct pp_done_work;
 	atomic_t pp_done_cnt;
 
@@ -53,6 +53,7 @@
 	u16 start_threshold;
 	u32 vclk_line;	/* vsync clock per line */
 	struct mdss_panel_recovery recovery;
+	bool ulps;
 };
 
 struct mdss_mdp_cmd_ctx mdss_mdp_cmd_ctx_list[MAX_SESSIONS];
@@ -101,108 +102,117 @@
 	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)
 {
 	unsigned long flags;
 	struct mdss_data_type *mdata = mdss_mdp_get_mdata();
+
+	if (!ctx->panel_on)
+		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))
+			pr_debug("deleted pending ulps work\n");
+
+		mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+
+		if (ctx->ulps) {
+			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);
+			ctx->ulps = false;
+		}
+
 		mdss_mdp_ctl_intf_event
 			(ctx->ctl, MDSS_EVENT_PANEL_CLK_CTRL, (void *)1);
-		mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+
 		mdss_mdp_hist_intr_setup(&mdata->hist_intr, MDSS_IRQ_RESUME);
 	}
 	spin_lock_irqsave(&ctx->clk_lock, flags);
@@ -220,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;
@@ -231,6 +243,8 @@
 		mdss_mdp_ctl_intf_event
 			(ctx->ctl, MDSS_EVENT_PANEL_CLK_CTRL, (void *)0);
 		mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+		if (ctx->panel_on)
+			schedule_delayed_work(&ctx->ulps_work, ULPS_ENTER_TIME);
 	}
 	mutex_unlock(&ctx->clk_mtx);
 }
@@ -249,6 +263,8 @@
 
 	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) {
@@ -259,6 +275,10 @@
 	if (!ctx->vsync_enabled) {
 		if (ctx->rdptr_enabled)
 			ctx->rdptr_enabled--;
+
+		/* keep clk on during kickoff */
+		if (ctx->rdptr_enabled == 0 && ctx->koff_cnt)
+			ctx->rdptr_enabled++;
 	}
 
 	if (ctx->rdptr_enabled == 0) {
@@ -308,6 +328,9 @@
 		return;
 	}
 
+	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) {
 		if (tmp->enabled && tmp->cmd_post_flush)
@@ -316,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);
@@ -340,9 +365,12 @@
 	struct mdss_mdp_cmd_ctx *ctx =
 		container_of(work, typeof(*ctx), pp_done_work);
 
-	if (ctx->ctl)
+	if (ctx->ctl) {
 		while (atomic_add_unless(&ctx->pp_done_cnt, -1, 0))
 			mdss_mdp_ctl_notify(ctx->ctl, MDP_NOTIFY_FRAME_DONE);
+
+		mdss_mdp_ctl_perf_release_bw(ctx->ctl);
+	}
 }
 
 static void clk_ctrl_work(struct work_struct *work)
@@ -358,11 +386,44 @@
 	mdss_mdp_cmd_clk_off(ctx);
 }
 
+static void __mdss_mdp_cmd_ulps_work(struct work_struct *work)
+{
+	struct delayed_work *dw = to_delayed_work(work);
+	struct mdss_mdp_cmd_ctx *ctx =
+		container_of(dw, struct mdss_mdp_cmd_ctx, ulps_work);
+
+	if (!ctx) {
+		pr_err("%s: invalid ctx\n", __func__);
+		return;
+	}
+
+	mutex_lock(&ctx->clk_mtx);
+	if (ctx->clk_enabled) {
+		mutex_unlock(&ctx->clk_mtx);
+		pr_warn("Cannot enter ulps mode if DSI clocks are on\n");
+		return;
+	}
+	mutex_unlock(&ctx->clk_mtx);
+
+	if (!ctx->panel_on) {
+		pr_err("Panel is off. skipping ULPS configuration\n");
+		return;
+	}
+
+	if (!mdss_mdp_ctl_intf_event(ctx->ctl, MDSS_EVENT_DSI_ULPS_CTRL,
+		(void *)1)) {
+		ctx->ulps = true;
+		ctx->ctl->play_cnt = 0;
+		mdss_mdp_footswitch_ctrl_ulps(0, &ctx->ctl->mfd->pdev->dev);
+	}
+}
+
 static int mdss_mdp_cmd_add_vsync_handler(struct mdss_mdp_ctl *ctl,
 		struct mdss_mdp_vsync_handler *handle)
 {
 	struct mdss_mdp_cmd_ctx *ctx;
 	unsigned long flags;
+	bool enable_rdptr = false;
 
 	ctx = (struct mdss_mdp_cmd_ctx *) ctl->priv_data;
 	if (!ctx) {
@@ -370,16 +431,21 @@
 		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;
 		list_add(&handle->list, &ctx->vsync_handlers);
-		if (!handle->cmd_post_flush)
-			ctx->vsync_enabled = 1;
+
+		enable_rdptr = !handle->cmd_post_flush;
+		if (enable_rdptr)
+			ctx->vsync_enabled++;
 	}
 	spin_unlock_irqrestore(&ctx->clk_lock, flags);
 
-	if (!handle->cmd_post_flush)
+	if (enable_rdptr)
 		mdss_mdp_cmd_clk_on(ctx);
 
 	return 0;
@@ -388,11 +454,8 @@
 static int mdss_mdp_cmd_remove_vsync_handler(struct mdss_mdp_ctl *ctl,
 		struct mdss_mdp_vsync_handler *handle)
 {
-
 	struct mdss_mdp_cmd_ctx *ctx;
 	unsigned long flags;
-	struct mdss_mdp_vsync_handler *tmp;
-	int num_rdptr_vsync = 0;
 
 	ctx = (struct mdss_mdp_cmd_ctx *) ctl->priv_data;
 	if (!ctx) {
@@ -400,19 +463,20 @@
 		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;
 		list_del_init(&handle->list);
-	}
-	list_for_each_entry(tmp, &ctx->vsync_handlers, list) {
-		if (!tmp->cmd_post_flush)
-			num_rdptr_vsync++;
-	}
-	if (!num_rdptr_vsync) {
-		ctx->vsync_enabled = 0;
-		ctx->rdptr_enabled = VSYNC_EXPIRE_TICK;
+
+		if (!handle->cmd_post_flush) {
+			if (ctx->vsync_enabled)
+				ctx->vsync_enabled--;
+			else
+				WARN(1, "unbalanced vsync disable");
+		}
 	}
 	spin_unlock_irqrestore(&ctx->clk_lock, flags);
 	return 0;
@@ -427,11 +491,7 @@
 
 	pdata->panel_info.cont_splash_enabled = 0;
 
-	ret = mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_CONT_SPLASH_FINISH,
-			NULL);
-
 	mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_PANEL_CLK_CTRL, (void *)0);
-	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
 
 	return ret;
 }
@@ -439,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;
@@ -449,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);
 
@@ -464,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 {
@@ -471,6 +544,8 @@
 		}
 	}
 
+	MDSS_XLOG(ctl->num, ctx->koff_cnt, ctx->clk_enabled,
+					ctx->rdptr_enabled, rc);
 	return rc;
 }
 
@@ -502,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);
@@ -512,23 +590,30 @@
 		WARN(rc, "intf %d panel on error (%d)\n", ctl->intf_num, rc);
 	}
 
-	mdss_mdp_cmd_set_partial_roi(ctl);
+	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);
 
 	mdss_mdp_cmd_clk_on(ctx);
 
+	mdss_mdp_cmd_set_partial_roi(ctl);
+
 	/*
 	 * tx dcs command if had any
 	 */
 	mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_DSI_CMDLIST_KOFF,
 						(void *)&ctx->recovery);
-
 	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);
-	spin_lock_irqsave(&ctx->clk_lock, flags);
-	ctx->koff_cnt++;
-	spin_unlock_irqrestore(&ctx->clk_lock, flags);
+	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;
 }
@@ -541,6 +626,7 @@
 	struct mdss_mdp_vsync_handler *tmp, *handle;
 	int need_wait = 0;
 	int ret = 0;
+	int hz;
 
 	ctx = (struct mdss_mdp_cmd_ctx *) ctl->priv_data;
 	if (!ctx) {
@@ -550,6 +636,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) {
@@ -558,8 +646,11 @@
 	}
 	spin_unlock_irqrestore(&ctx->clk_lock, flags);
 
+	hz = mdss_panel_get_framerate(&ctl->panel_data->panel_info);
+
 	if (need_wait)
-		if (wait_for_completion_timeout(&ctx->stop_comp, STOP_TIMEOUT)
+		if (wait_for_completion_timeout(&ctx->stop_comp,
+					STOP_TIMEOUT(hz))
 		    <= 0) {
 			WARN(1, "stop cmd time out\n");
 
@@ -580,11 +671,14 @@
 	if (cancel_work_sync(&ctx->clk_work))
 		pr_debug("no pending clk work\n");
 
+	if (cancel_delayed_work_sync(&ctx->ulps_work))
+		pr_debug("deleted pending ulps work\n");
+
+	ctx->panel_on = 0;
 	mdss_mdp_cmd_clk_off(ctx);
 
 	flush_work(&ctx->pp_done_work);
 
-	ctx->panel_on = 0;
 
 	mdss_mdp_set_intr_callback(MDSS_MDP_IRQ_PING_PONG_RD_PTR, ctx->pp_num,
 				   NULL, NULL);
@@ -606,6 +700,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;
@@ -650,6 +746,7 @@
 	spin_lock_init(&ctx->clk_lock);
 	mutex_init(&ctx->clk_mtx);
 	INIT_WORK(&ctx->clk_work, clk_ctrl_work);
+	INIT_DELAYED_WORK(&ctx->ulps_work, __mdss_mdp_cmd_ulps_work);
 	INIT_WORK(&ctx->pp_done_work, pingpong_done_work);
 	atomic_set(&ctx->pp_done_cnt, 0);
 	INIT_LIST_HEAD(&ctx->vsync_handlers);
@@ -659,6 +756,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);
@@ -666,7 +765,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 bd1c3eb..b07aab4 100644
--- a/drivers/video/msm/mdss/mdss_mdp_intf_video.c
+++ b/drivers/video/msm/mdss/mdss_mdp_intf_video.c
@@ -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,12 +16,12 @@
 #include <linux/iopoll.h>
 #include <linux/delay.h>
 #include <linux/dma-mapping.h>
-#include <linux/bootmem.h>
 #include <linux/memblock.h>
 
 #include "mdss_fb.h"
 #include "mdss_mdp.h"
 #include "mdss_panel.h"
+#include "mdss_debug.h"
 
 /* wait for at least 2 vsyncs for lowest refresh rate (24hz) */
 #define VSYNC_TIMEOUT_US 100000
@@ -62,6 +62,7 @@
 
 	atomic_t vsync_ref;
 	spinlock_t vsync_lock;
+	struct mutex vsync_mtx;
 	struct list_head vsync_handlers;
 };
 
@@ -216,19 +217,23 @@
 {
 	struct mdss_mdp_video_ctx *ctx = ctl->priv_data;
 
+	mutex_lock(&ctx->vsync_mtx);
 	if (atomic_inc_return(&ctx->vsync_ref) == 1)
 		mdss_mdp_irq_enable(MDSS_MDP_IRQ_INTF_VSYNC, ctl->intf_num);
 	else if (clear)
 		mdss_mdp_irq_clear(ctl->mdata, MDSS_MDP_IRQ_INTF_VSYNC,
 				ctl->intf_num);
+	mutex_unlock(&ctx->vsync_mtx);
 }
 
 static inline void video_vsync_irq_disable(struct mdss_mdp_ctl *ctl)
 {
 	struct mdss_mdp_video_ctx *ctx = ctl->priv_data;
 
+	mutex_lock(&ctx->vsync_mtx);
 	if (atomic_dec_return(&ctx->vsync_ref) == 0)
 		mdss_mdp_irq_disable(MDSS_MDP_IRQ_INTF_VSYNC, ctl->intf_num);
+	mutex_unlock(&ctx->vsync_mtx);
 }
 
 static int mdss_mdp_video_add_vsync_handler(struct mdss_mdp_ctl *ctl,
@@ -251,6 +256,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;
@@ -277,6 +284,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;
@@ -293,6 +302,7 @@
 {
 	struct mdss_mdp_video_ctx *ctx;
 	struct mdss_mdp_vsync_handler *tmp, *handle;
+	struct mdss_mdp_ctl *sctl;
 	int rc;
 	u32 frame_rate = 0;
 
@@ -303,7 +313,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) {
@@ -330,6 +340,10 @@
 
 		mdss_mdp_irq_disable(MDSS_MDP_IRQ_INTF_UNDER_RUN,
 			ctl->intf_num);
+		sctl = mdss_mdp_get_split_ctl(ctl);
+		if (sctl)
+			mdss_mdp_irq_disable(MDSS_MDP_IRQ_INTF_UNDER_RUN,
+				sctl->intf_num);
 	}
 
 	list_for_each_entry_safe(handle, tmp, &ctx->vsync_handlers, list)
@@ -362,6 +376,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));
 
@@ -391,6 +407,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++;
@@ -428,8 +445,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);
@@ -450,6 +469,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;
@@ -457,11 +491,72 @@
 		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_config_fps(struct mdss_mdp_ctl *ctl, int new_fps)
+static int mdss_mdp_video_vfp_fps_update(struct mdss_mdp_ctl *ctl, int new_fps)
+{
+	int curr_fps;
+	u32 add_v_lines = 0;
+	u32 current_vsync_period_f0, new_vsync_period_f0;
+	struct mdss_panel_data *pdata;
+	struct mdss_mdp_video_ctx *ctx;
+	u32 vsync_period, hsync_period;
+
+	ctx = (struct mdss_mdp_video_ctx *) ctl->priv_data;
+	if (!ctx) {
+		pr_err("invalid ctx\n");
+		return -ENODEV;
+	}
+
+	pdata = ctl->panel_data;
+	if (pdata == NULL) {
+		pr_err("%s: Invalid panel data\n", __func__);
+		return -EINVAL;
+	}
+
+	vsync_period = mdss_panel_get_vtotal(&pdata->panel_info);
+	hsync_period = mdss_panel_get_htotal(&pdata->panel_info);
+	curr_fps = mdss_panel_get_framerate(&pdata->panel_info);
+
+	if (curr_fps > new_fps) {
+		add_v_lines = mult_frac(vsync_period,
+				(curr_fps - new_fps), new_fps);
+		pdata->panel_info.lcdc.v_front_porch += add_v_lines;
+	} else {
+		add_v_lines = mult_frac(vsync_period,
+				(new_fps - curr_fps), new_fps);
+		pdata->panel_info.lcdc.v_front_porch -= add_v_lines;
+	}
+
+	vsync_period = mdss_panel_get_vtotal(&pdata->panel_info);
+	current_vsync_period_f0 = mdp_video_read(ctx,
+		MDSS_MDP_REG_INTF_VSYNC_PERIOD_F0);
+	new_vsync_period_f0 = (vsync_period * hsync_period);
+
+	mdp_video_write(ctx, MDSS_MDP_REG_INTF_VSYNC_PERIOD_F0,
+			current_vsync_period_f0 | 0x800000);
+	if (new_vsync_period_f0 & 0x800000) {
+		mdp_video_write(ctx, MDSS_MDP_REG_INTF_VSYNC_PERIOD_F0,
+			new_vsync_period_f0);
+	} else {
+		mdp_video_write(ctx, MDSS_MDP_REG_INTF_VSYNC_PERIOD_F0,
+			new_vsync_period_f0 | 0x800000);
+		mdp_video_write(ctx, MDSS_MDP_REG_INTF_VSYNC_PERIOD_F0,
+			new_vsync_period_f0 & 0x7fffff);
+	}
+
+	return 0;
+}
+
+static int mdss_mdp_video_config_fps(struct mdss_mdp_ctl *ctl,
+					struct mdss_mdp_ctl *sctl, int new_fps)
 {
 	struct mdss_mdp_video_ctx *ctx;
 	struct mdss_panel_data *pdata;
@@ -524,6 +619,40 @@
 			ctl->force_screen_state = MDSS_SCREEN_DEFAULT;
 			mdss_mdp_display_commit(ctl, NULL);
 			mdss_mdp_display_wait4comp(ctl);
+		} else if (pdata->panel_info.dfps_update
+				== DFPS_IMMEDIATE_PORCH_UPDATE_MODE){
+			if (!ctx->timegen_en) {
+				pr_err("TG is OFF. DFPS mode invalid\n");
+				return -EINVAL;
+			}
+
+			video_vsync_irq_enable(ctl, true);
+			INIT_COMPLETION(ctx->vsync_comp);
+			rc = wait_for_completion_timeout(&ctx->vsync_comp,
+				usecs_to_jiffies(VSYNC_TIMEOUT_US));
+			WARN(rc <= 0, "timeout (%d) vsync interrupt on ctl=%d\n",
+				rc, ctl->num);
+			rc = 0;
+			video_vsync_irq_disable(ctl);
+
+			rc = mdss_mdp_video_vfp_fps_update(ctl, new_fps);
+			if (rc < 0) {
+				pr_err("%s: Error during DFPS\n", __func__);
+				return rc;
+			}
+			if (sctl) {
+				rc = mdss_mdp_video_vfp_fps_update(sctl,
+								new_fps);
+				if (rc < 0) {
+					pr_err("%s: DFPS error\n", __func__);
+					return rc;
+				}
+			}
+			rc = mdss_mdp_ctl_intf_event(ctl,
+						MDSS_EVENT_PANEL_UPDATE_FPS,
+						(void *)new_fps);
+			WARN(rc, "intf %d panel fps update error (%d)\n",
+							ctl->intf_num, rc);
 		} else {
 			pr_err("intf %d panel, unknown FPS mode\n",
 							ctl->intf_num);
@@ -540,12 +669,10 @@
 	return rc;
 }
 
-
-
-
 static int mdss_mdp_video_display(struct mdss_mdp_ctl *ctl, void *arg)
 {
 	struct mdss_mdp_video_ctx *ctx;
+	struct mdss_mdp_ctl *sctl;
 	int rc;
 
 	pr_debug("kickoff ctl=%d\n", ctl->num);
@@ -564,6 +691,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) {
@@ -579,6 +708,11 @@
 		mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
 
 		mdss_mdp_irq_enable(MDSS_MDP_IRQ_INTF_UNDER_RUN, ctl->intf_num);
+		sctl = mdss_mdp_get_split_ctl(ctl);
+		if (sctl)
+			mdss_mdp_irq_enable(MDSS_MDP_IRQ_INTF_UNDER_RUN,
+				sctl->intf_num);
+
 		mdp_video_write(ctx, MDSS_MDP_REG_INTF_TIMING_ENGINE_EN, 1);
 		wmb();
 
@@ -600,7 +734,6 @@
 {
 	struct mdss_panel_data *pdata = ctl->panel_data;
 	int i, ret = 0;
-	struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(ctl->mfd);
 	struct mdss_mdp_video_ctx *ctx;
 	struct mdss_data_type *mdata = ctl->mdata;
 
@@ -635,13 +768,6 @@
 
 error:
 	pdata->panel_info.cont_splash_enabled = 0;
-
-	/* Give back the reserved memory to the system */
-	memblock_free(mdp5_data->splash_mem_addr, mdp5_data->splash_mem_size);
-	free_bootmem_late(mdp5_data->splash_mem_addr,
-				 mdp5_data->splash_mem_size);
-
-	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
 	return ret;
 }
 
@@ -678,13 +804,16 @@
 		return -EINVAL;
 	}
 
+	MDSS_XLOG(ctl->num, ctl->vsync_cnt);
 	pr_debug("start ctl=%u\n", ctl->num);
 
 	ctl->priv_data = ctx;
 	ctx->intf_type = ctl->intf_type;
 	init_completion(&ctx->vsync_comp);
 	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_intf_writeback.c b/drivers/video/msm/mdss/mdss_mdp_intf_writeback.c
index ff55c57..27a7707 100644
--- a/drivers/video/msm/mdss/mdss_mdp_intf_writeback.c
+++ b/drivers/video/msm/mdss/mdss_mdp_intf_writeback.c
@@ -17,6 +17,9 @@
 #include "mdss_mdp_rotator.h"
 #include "mdss_panel.h"
 
+#define VBIF_WR_LIM_CONF    0xC0
+#define MDSS_DEFAULT_OT_SETTING    0x10
+
 enum mdss_mdp_writeback_type {
 	MDSS_MDP_WRITEBACK_TYPE_ROTATOR,
 	MDSS_MDP_WRITEBACK_TYPE_LINE,
@@ -34,6 +37,9 @@
 	u32 intr_type;
 	u32 intf_num;
 
+	u32 xin_id;
+	u32 wr_lim;
+
 	u32 opmode;
 	struct mdss_mdp_format_params *dst_fmt;
 	u16 width;
@@ -55,26 +61,31 @@
 		.type = MDSS_MDP_WRITEBACK_TYPE_ROTATOR,
 		.intr_type = MDSS_MDP_IRQ_WB_ROT_COMP,
 		.intf_num = 0,
+		.xin_id = 3,
 	},
 	{
 		.type = MDSS_MDP_WRITEBACK_TYPE_ROTATOR,
 		.intr_type = MDSS_MDP_IRQ_WB_ROT_COMP,
 		.intf_num = 1,
+		.xin_id = 11,
 	},
 	{
 		.type = MDSS_MDP_WRITEBACK_TYPE_LINE,
 		.intr_type = MDSS_MDP_IRQ_WB_ROT_COMP,
 		.intf_num = 0,
+		.xin_id = 3,
 	},
 	{
 		.type = MDSS_MDP_WRITEBACK_TYPE_LINE,
 		.intr_type = MDSS_MDP_IRQ_WB_ROT_COMP,
 		.intf_num = 1,
+		.xin_id = 11,
 	},
 	{
 		.type = MDSS_MDP_WRITEBACK_TYPE_WFD,
 		.intr_type = MDSS_MDP_IRQ_WB_WFD,
 		.intf_num = 0,
+		.xin_id = 6,
 	},
 };
 
@@ -438,9 +449,12 @@
 {
 	struct mdss_mdp_writeback_ctx *ctx;
 	struct mdss_mdp_writeback_arg *wb_args;
-	u32 flush_bits;
+	u32 flush_bits, val, off;
 	int ret;
 
+	if (!ctl || !ctl->mdata)
+		return -ENODEV;
+
 	ctx = (struct mdss_mdp_writeback_ctx *) ctl->priv_data;
 	if (!ctx)
 		return -ENODEV;
@@ -451,6 +465,18 @@
 		return -EPERM;
 	}
 
+	if (ctl->mdata->rotator_ot_limit) {
+		if (ctx->type == MDSS_MDP_WRITEBACK_TYPE_ROTATOR)
+			ctx->wr_lim = ctl->mdata->rotator_ot_limit;
+		else
+			ctx->wr_lim = MDSS_DEFAULT_OT_SETTING;
+		off = (ctx->xin_id % 4) * 8;
+		val = readl_relaxed(ctl->mdata->vbif_base + VBIF_WR_LIM_CONF);
+		val &= ~(0xFF << off);
+		val |= (ctx->wr_lim) << off;
+		writel_relaxed(val, ctl->mdata->vbif_base + VBIF_WR_LIM_CONF);
+	}
+
 	wb_args = (struct mdss_mdp_writeback_arg *) arg;
 	if (!wb_args)
 		return -ENOENT;
diff --git a/drivers/video/msm/mdss/mdss_mdp_overlay.c b/drivers/video/msm/mdss/mdss_mdp_overlay.c
index 4c89064..057483c 100644
--- a/drivers/video/msm/mdss/mdss_mdp_overlay.c
+++ b/drivers/video/msm/mdss/mdss_mdp_overlay.c
@@ -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
@@ -23,6 +23,7 @@
 #include <linux/delay.h>
 #include <linux/msm_mdp.h>
 #include <linux/memblock.h>
+#include <linux/sw_sync.h>
 
 #include <mach/iommu_domains.h>
 #include <mach/event_timer.h>
@@ -44,6 +45,8 @@
 
 #define MEM_PROTECT_SD_CTRL 0xF
 
+#define OVERLAY_MAX 10
+
 struct sd_ctrl_req {
 	unsigned int enable;
 } __attribute__ ((__packed__));
@@ -52,7 +55,7 @@
 static int mdss_mdp_overlay_free_fb_pipe(struct msm_fb_data_type *mfd);
 static int mdss_mdp_overlay_fb_parse_dt(struct msm_fb_data_type *mfd);
 static int mdss_mdp_overlay_off(struct msm_fb_data_type *mfd);
-static int mdss_mdp_overlay_splash_parse_dt(struct msm_fb_data_type *mfd);
+static void __overlay_kickoff_requeue(struct msm_fb_data_type *mfd);
 
 static int mdss_mdp_overlay_sd_ctrl(struct msm_fb_data_type *mfd,
 					unsigned int enable)
@@ -151,6 +154,12 @@
 			pr_err("Invalid decimation factors horz=%d vert=%d\n",
 					req->horz_deci, req->vert_deci);
 			return -EINVAL;
+		} else if (req->flags & MDP_BWC_EN) {
+			pr_err("Decimation can't be enabled with BWC\n");
+			return -EINVAL;
+		} else if (fmt->tile) {
+			pr_err("Decimation can't be enabled with MacroTile format\n");
+			return -EINVAL;
 		}
 	}
 
@@ -257,7 +266,7 @@
 	int rc;
 
 	for (;;) {
-		rc = mdss_mdp_perf_calc_pipe(pipe, &perf);
+		rc = mdss_mdp_perf_calc_pipe(pipe, &perf, NULL, true);
 
 		if (!rc && (perf.mdp_clk_rate <= mdata->max_mdp_clk_rate))
 			break;
@@ -267,7 +276,8 @@
 		 * requirement by applying vertical decimation and reduce
 		 * mdp clock requirement
 		 */
-		if (mdata->has_decimation && (pipe->vert_deci < MAX_DECIMATION))
+		if (mdata->has_decimation && (pipe->vert_deci < MAX_DECIMATION)
+			&& !pipe->bwc_mode && !pipe->src_fmt->tile)
 			pipe->vert_deci++;
 		else
 			return -EPERM;
@@ -288,7 +298,10 @@
 	memset(&pipe->scale, 0, sizeof(struct mdp_scale_data));
 	rc = mdss_mdp_calc_phase_step(src, pipe->dst.w,
 			&pipe->scale.phase_step_x[0]);
-	if (rc) {
+	if (rc == -EOVERFLOW) {
+		/* overflow on horizontal direction is acceptable */
+		rc = 0;
+	} else if (rc) {
 		pr_err("Horizontal scaling calculation failed=%d! %d->%d\n",
 				rc, src, pipe->dst.w);
 		return rc;
@@ -297,16 +310,16 @@
 	src = pipe->src.h >> pipe->vert_deci;
 	rc = mdss_mdp_calc_phase_step(src, pipe->dst.h,
 			&pipe->scale.phase_step_y[0]);
-	if (rc) {
+
+	if ((rc == -EOVERFLOW) && (pipe->type == MDSS_MDP_PIPE_TYPE_VIG)) {
+		/* overflow on Qseed2 scaler is acceptable */
+		rc = 0;
+	} else if (rc) {
 		pr_err("Vertical scaling calculation failed=%d! %d->%d\n",
 				rc, src, pipe->dst.h);
 		return rc;
 	}
-	pipe->scale.init_phase_x[0] = (pipe->scale.phase_step_x[0] -
-					(1 << PHASE_STEP_SHIFT)) / 2;
-	pipe->scale.init_phase_y[0] = (pipe->scale.phase_step_y[0] -
-					(1 << PHASE_STEP_SHIFT)) / 2;
-	return 0;
+	return rc;
 }
 
 static inline void __mdss_mdp_overlay_set_chroma_sample(
@@ -332,7 +345,7 @@
 		pipe->chroma_sample_v = 0;
 }
 
-static int mdss_mdp_overlay_pipe_setup(struct msm_fb_data_type *mfd,
+int mdss_mdp_overlay_pipe_setup(struct msm_fb_data_type *mfd,
 				       struct mdp_overlay *req,
 				       struct mdss_mdp_pipe **ppipe)
 {
@@ -587,12 +600,6 @@
 		!mdp5_data->mdata->has_wfd_blk)
 		mdss_mdp_smp_release(pipe);
 
-	/*
-	 * Clear previous SMP reservations and reserve according to the
-	 * latest configuration
-	 */
-	mdss_mdp_smp_unreserve(pipe);
-
 	ret = mdss_mdp_smp_reserve(pipe);
 	if (ret) {
 		pr_debug("mdss_mdp_smp_reserve failed. ret=%d\n", ret);
@@ -600,7 +607,6 @@
 	}
 
 	pipe->params_changed++;
-	pipe->has_buf = 0;
 
 	req->vert_deci = pipe->vert_deci;
 
@@ -677,6 +683,7 @@
 	if ((num_planes <= 0) || (num_planes > MAX_PLANES))
 		return -EINVAL;
 
+	mdss_bus_bandwidth_ctrl(1);
 	memset(data, 0, sizeof(*data));
 	for (i = 0; i < num_planes; i++) {
 		data->p[i].flags = flags;
@@ -690,6 +697,7 @@
 			break;
 		}
 	}
+	mdss_bus_bandwidth_ctrl(0);
 
 	data->num_planes = i;
 
@@ -699,8 +707,11 @@
 int mdss_mdp_overlay_free_buf(struct mdss_mdp_data *data)
 {
 	int i;
+
+	mdss_bus_bandwidth_ctrl(1);
 	for (i = 0; i < data->num_planes && data->p[i].len; i++)
 		mdss_mdp_put_img(&data->p[i]);
+	mdss_bus_bandwidth_ctrl(0);
 
 	data->num_planes = 0;
 
@@ -750,19 +761,41 @@
 {
 	struct mdss_mdp_pipe *pipe, *tmp;
 	struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
+	struct mdss_mdp_ctl *ctl = mfd_to_ctl(mfd);
+	bool recovery_mode = false;
 	LIST_HEAD(destroy_pipes);
 
 	mutex_lock(&mfd->lock);
-	__mdss_mdp_overlay_free_list_purge(mfd);
-
 	list_for_each_entry_safe(pipe, tmp, &mdp5_data->pipes_cleanup,
 				cleanup_list) {
 		list_move(&pipe->cleanup_list, &destroy_pipes);
-		mdss_mdp_overlay_free_buf(&pipe->back_buf);
-		__mdss_mdp_overlay_free_list_add(mfd, &pipe->front_buf);
-		pipe->mfd = NULL;
+
+		/* make sure pipe fetch has been halted before freeing buffer */
+		if (mdss_mdp_pipe_fetch_halt(pipe)) {
+			/*
+			 * if pipe is not able to halt. Enter recovery mode,
+			 * by un-staging any pipes that are attached to mixer
+			 * so that any freed pipes that are not able to halt
+			 * can be staged in solid fill mode and be reset
+			 * with next vsync
+			 */
+			if (!recovery_mode) {
+				recovery_mode = true;
+				mdss_mdp_mixer_unstage_all(ctl->mixer_left);
+				mdss_mdp_mixer_unstage_all(ctl->mixer_right);
+			}
+			pipe->params_changed++;
+			mdss_mdp_pipe_queue_data(pipe, NULL);
+		}
 	}
 
+	if (recovery_mode) {
+		pr_warn("performing recovery sequence for fb%d\n", mfd->index);
+		__overlay_kickoff_requeue(mfd);
+	}
+
+	__mdss_mdp_overlay_free_list_purge(mfd);
+
 	list_for_each_entry(pipe, &mdp5_data->pipes_used, used_list) {
 		if (pipe->back_buf.num_planes) {
 			/* make back buffer active */
@@ -770,12 +803,23 @@
 			swap(pipe->back_buf, pipe->front_buf);
 		}
 	}
-	mutex_unlock(&mfd->lock);
-	list_for_each_entry_safe(pipe, tmp, &destroy_pipes, cleanup_list)
+
+	list_for_each_entry_safe(pipe, tmp, &destroy_pipes, cleanup_list) {
+		/*
+		 * in case of secure UI, the buffer needs to be released as
+		 * soon as session is closed.
+		 */
+		if (pipe->flags & MDP_SECURE_DISPLAY_OVERLAY_SESSION)
+			mdss_mdp_overlay_free_buf(&pipe->front_buf);
+		else
+			__mdss_mdp_overlay_free_list_add(mfd, &pipe->front_buf);
+		mdss_mdp_overlay_free_buf(&pipe->back_buf);
 		mdss_mdp_pipe_destroy(pipe);
+	}
+	mutex_unlock(&mfd->lock);
 }
 
-static void __mdss_mdp_handoff_cleanup_pipes(struct msm_fb_data_type *mfd,
+void mdss_mdp_handoff_cleanup_pipes(struct msm_fb_data_type *mfd,
 	u32 type)
 {
 	u32 i, npipes;
@@ -822,18 +866,23 @@
  * from the the splash screen to the android boot animation when the
  * continuous splash screen feature is enabled.
  */
-static int mdss_mdp_overlay_start(struct msm_fb_data_type *mfd)
+int mdss_mdp_overlay_start(struct msm_fb_data_type *mfd)
 {
 	int rc;
 	struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
 	struct mdss_mdp_ctl *ctl = mdp5_data->ctl;
 
 	if (ctl->power_on) {
+		if (mdp5_data->mdata->ulps) {
+			mdss_mdp_footswitch_ctrl_ulps(1, &mfd->pdev->dev);
+			mdss_mdp_ctl_restore(ctl);
+		}
+
 		if (!mdp5_data->mdata->batfet)
 			mdss_mdp_batfet_ctrl(mdp5_data->mdata, true);
-		if (!is_mdss_iommu_attached() &&
-					!mfd->panel_info->cont_splash_enabled)
+		if (!mfd->panel_info->cont_splash_enabled)
 			mdss_iommu_attach(mdp5_data->mdata);
+		mdss_mdp_release_splash_pipe(mfd);
 		return 0;
 	}
 
@@ -870,55 +919,7 @@
 		goto error;
 	}
 
-	if (mfd->panel_info->cont_splash_enabled) {
-		if (mdp5_data->handoff) {
-			/*
-			 * Set up border-fill on the handed off pipes.
-			 * This is needed to ensure that there are no memory
-			 * accesses prior to attaching iommu during continuous
-			 * splash screen case. However, for command mode
-			 * displays, this is not necessary since the panels can
-			 * refresh from their internal memory if no data is sent
-			 * out on the dsi lanes.
-			 */
-			if (ctl && ctl->is_video_mode) {
-				rc = mdss_mdp_display_commit(ctl, NULL);
-				if (!IS_ERR_VALUE(rc)) {
-					mdss_mdp_display_wait4comp(ctl);
-				} else {
-					/*
-					 * Since border-fill setup failed, we
-					 * need to ensure that we turn off the
-					 * MDP timing generator before attaching
-					 * iommu
-					 */
-					pr_err("failed to set BF at handoff\n");
-					mdp5_data->handoff = false;
-					rc = 0;
-				}
-			}
-
-			/* Add all the handed off pipes to the cleanup list */
-			__mdss_mdp_handoff_cleanup_pipes(mfd,
-				MDSS_MDP_PIPE_TYPE_RGB);
-			__mdss_mdp_handoff_cleanup_pipes(mfd,
-				MDSS_MDP_PIPE_TYPE_VIG);
-			__mdss_mdp_handoff_cleanup_pipes(mfd,
-				MDSS_MDP_PIPE_TYPE_DMA);
-		}
-		rc = mdss_mdp_ctl_splash_finish(ctl, mdp5_data->handoff);
-		/*
-		 * Remove the vote for footswitch even if above function
-		 * returned error
-		 */
-		mdss_mdp_footswitch_ctrl_splash(0);
-		if (rc)
-			goto error;
-
-		if (!is_mdss_iommu_attached())
-			mdss_iommu_attach(mdss_res);
-	}
-
+	rc = mdss_mdp_splash_cleanup(mfd, true);
 error:
 	if (rc) {
 		mdss_mdp_ctl_destroy(ctl);
@@ -942,49 +943,22 @@
 	activate_event_timer(mdp5_data->cpu_pm_hdl, wakeup_time);
 }
 
-int mdss_mdp_overlay_kickoff(struct msm_fb_data_type *mfd,
-				struct mdp_display_commit *data)
+static int __overlay_queue_pipes(struct msm_fb_data_type *mfd)
 {
 	struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
 	struct mdss_mdp_pipe *pipe;
 	struct mdss_mdp_ctl *ctl = mfd_to_ctl(mfd);
 	struct mdss_mdp_ctl *tmp;
 	int ret = 0;
-	int sd_in_pipe = 0;
-
-	if (!is_mdss_iommu_attached() && !mfd->panel_info->cont_splash_enabled)
-		mdss_iommu_attach(mdp5_data->mdata);
-
-	if (ctl->shared_lock)
-		mutex_lock(ctl->shared_lock);
-
-	mutex_lock(&mdp5_data->ov_lock);
-	mutex_lock(&mfd->lock);
 
 	/*
-	 * check if there is a secure display session
+	 * Setup pipe in solid fill before unstaging,
+	 * to ensure no fetches are happening after dettach or reattach.
 	 */
-	list_for_each_entry(pipe, &mdp5_data->pipes_used, used_list) {
-		if (pipe->flags & MDP_SECURE_DISPLAY_OVERLAY_SESSION) {
-			sd_in_pipe |= 1;
-			pr_debug("Secure pipe: %u : %08X\n",
-					pipe->num, pipe->flags);
-		}
+	list_for_each_entry(pipe, &mdp5_data->pipes_cleanup, cleanup_list) {
+		mdss_mdp_pipe_queue_data(pipe, NULL);
+		mdss_mdp_mixer_pipe_unstage(pipe);
 	}
-	/*
-	 * If there is no secure display session and sd_enabled, disable the
-	 * secure display session
-	 */
-	if (!sd_in_pipe && mdp5_data->sd_enabled) {
-		if (0 == mdss_mdp_overlay_sd_ctrl(mfd, 0))
-			mdp5_data->sd_enabled = 0;
-	}
-
-	mdss_mdp_ctl_notify(ctl, MDP_NOTIFY_FRAME_BEGIN);
-	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
-
-	if (data)
-		mdss_mdp_set_roi(ctl, data);
 
 	list_for_each_entry(pipe, &mdp5_data->pipes_used, used_list) {
 		struct mdss_mdp_data *buf;
@@ -1014,25 +988,23 @@
 			if (ret) {
 				pr_err("can't reset DMA pipe ret=%d ctl=%d\n",
 					ret, ctl->num);
-				mutex_unlock(&mfd->lock);
-				goto commit_fail;
+				return ret;
 			}
 
 			tmp = mdss_mdp_ctl_mixer_switch(ctl,
 					MDSS_MDP_WB_CTL_TYPE_LINE);
-			if (!tmp) {
-				mutex_unlock(&mfd->lock);
-				ret = -EINVAL;
-				goto commit_fail;
-			}
+			if (!tmp)
+				return -EINVAL;
 			pipe->mixer = mdss_mdp_mixer_get(tmp,
 					MDSS_MDP_MIXER_MUX_DEFAULT);
 		}
+
+		/* ensure pipes are always reconfigured after power off/on */
+		if (ctl->play_cnt == 0)
+			pipe->params_changed++;
+
 		if (pipe->back_buf.num_planes) {
 			buf = &pipe->back_buf;
-		} else if (ctl->play_cnt == 0 && pipe->front_buf.num_planes) {
-			pipe->params_changed++;
-			buf = &pipe->front_buf;
 		} else if (!pipe->params_changed) {
 			continue;
 		} else if (pipe->front_buf.num_planes) {
@@ -1051,19 +1023,95 @@
 		}
 	}
 
+	return 0;
+}
+
+static void __overlay_kickoff_requeue(struct msm_fb_data_type *mfd)
+{
+	struct mdss_mdp_ctl *ctl = mfd_to_ctl(mfd);
+
+	mdss_mdp_display_commit(ctl, NULL);
+	mdss_mdp_display_wait4comp(ctl);
+
+	__overlay_queue_pipes(mfd);
+
+	mdss_mdp_display_commit(ctl, NULL);
+	mdss_mdp_display_wait4comp(ctl);
+}
+
+int mdss_mdp_overlay_kickoff(struct msm_fb_data_type *mfd,
+				struct mdp_display_commit *data)
+{
+	struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
+	struct mdss_mdp_pipe *pipe;
+	struct mdss_mdp_ctl *ctl = mfd_to_ctl(mfd);
+	int ret = 0;
+	int sd_in_pipe = 0;
+
+	if (ctl->shared_lock) {
+		mdss_mdp_ctl_notify(ctl, MDP_NOTIFY_FRAME_BEGIN);
+		mdss_mdp_ctl_notify(ctl, MDP_NOTIFY_FRAME_READY);
+		mutex_lock(ctl->shared_lock);
+	}
+
+	mutex_lock(&mdp5_data->ov_lock);
+	mutex_lock(&mfd->lock);
+
+	/*
+	 * check if there is a secure display session
+	 */
+	list_for_each_entry(pipe, &mdp5_data->pipes_used, used_list) {
+		if (pipe->flags & MDP_SECURE_DISPLAY_OVERLAY_SESSION) {
+			sd_in_pipe = 1;
+			pr_debug("Secure pipe: %u : %08X\n",
+					pipe->num, pipe->flags);
+		}
+	}
+	/*
+	 * If there is no secure display session and sd_enabled, disable the
+	 * secure display session
+	 */
+	if (!sd_in_pipe && mdp5_data->sd_enabled) {
+		if (0 == mdss_mdp_overlay_sd_ctrl(mfd, 0))
+			mdp5_data->sd_enabled = 0;
+	}
+
+	if (!ctl->shared_lock)
+		mdss_mdp_ctl_notify(ctl, MDP_NOTIFY_FRAME_BEGIN);
+
+	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+
+	if (data)
+		mdss_mdp_set_roi(ctl, data);
+
+	/*
+	 * Setup pipe in solid fill before unstaging,
+	 * to ensure no fetches are happening after dettach or reattach.
+	 */
+	list_for_each_entry(pipe, &mdp5_data->pipes_cleanup, cleanup_list) {
+		mdss_mdp_pipe_queue_data(pipe, NULL);
+		mdss_mdp_mixer_pipe_unstage(pipe);
+	}
+
+	ret = __overlay_queue_pipes(mfd);
+
 	if (mfd->panel.type == WRITEBACK_PANEL)
 		ret = mdss_mdp_wb_kickoff(mfd);
 	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);
@@ -1088,12 +1136,12 @@
 	return ret;
 }
 
-static int mdss_mdp_overlay_release(struct msm_fb_data_type *mfd, int ndx)
+int mdss_mdp_overlay_release(struct msm_fb_data_type *mfd, int ndx)
 {
 	struct mdss_mdp_pipe *pipe;
 	struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
 	u32 pipe_ndx, unset_ndx = 0;
-	int i;
+	int i, destroy_pipe;
 
 	for (i = 0; unset_ndx != ndx && i < MDSS_MDP_MAX_SSPP; i++) {
 		pipe_ndx = BIT(i);
@@ -1104,16 +1152,21 @@
 				pr_warn("unknown pipe ndx=%x\n", pipe_ndx);
 				continue;
 			}
+
 			mutex_lock(&mfd->lock);
 			pipe->pid = 0;
+			destroy_pipe = pipe->play_cnt == 0;
+
 			if (!list_empty(&pipe->used_list)) {
 				list_del_init(&pipe->used_list);
-				list_add(&pipe->cleanup_list,
-					&mdp5_data->pipes_cleanup);
+				if (!destroy_pipe)
+					list_add(&pipe->cleanup_list,
+						&mdp5_data->pipes_cleanup);
 			}
 			mutex_unlock(&mfd->lock);
-			mdss_mdp_mixer_pipe_unstage(pipe);
 			mdss_mdp_pipe_unmap(pipe);
+			if (destroy_pipe)
+				mdss_mdp_pipe_destroy(pipe);
 		}
 	}
 	return 0;
@@ -1254,9 +1307,15 @@
 
 	pr_debug("ov queue pnum=%d\n", pipe->num);
 
+	if (pipe->flags & MDP_SOLID_FILL)
+		pr_warn("Unexpected buffer queue to a solid fill pipe\n");
+
 	flags = (pipe->flags & MDP_SECURE_OVERLAY_SESSION);
 	flags |= (pipe->flags & MDP_SECURE_DISPLAY_OVERLAY_SESSION);
 
+	if (!mfd->panel_info->cont_splash_enabled)
+		mdss_iommu_attach(mdata);
+
 	src_data = &pipe->back_buf;
 	if (src_data->num_planes) {
 		pr_warn("dropped buffer pnum=%d play=%d addr=0x%x\n",
@@ -1268,7 +1327,6 @@
 	if (IS_ERR_VALUE(ret)) {
 		pr_err("src_data pmem error\n");
 	}
-	pipe->has_buf = 1;
 	mdss_mdp_pipe_unmap(pipe);
 
 	return ret;
@@ -1302,8 +1360,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);
+		}
 	}
 }
 
@@ -1379,14 +1442,16 @@
 {
 	struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
 	struct mdss_mdp_pipe *pipe;
+	int ret;
 
 	pipe = mdss_mdp_mixer_stage_pipe(mdp5_data->ctl, mixer_mux,
 					 MDSS_MDP_STAGE_BASE);
+
 	if (pipe == NULL) {
 		struct mdp_overlay req;
 		struct fb_info *fbi = mfd->fbi;
 		struct mdss_mdp_mixer *mixer;
-		int ret, bpp;
+		int bpp;
 
 		mixer = mdss_mdp_mixer_get(mdp5_data->ctl,
 					MDSS_MDP_MIXER_MUX_LEFT);
@@ -1408,18 +1473,16 @@
 				return -EINVAL;
 			}
 
-			req.flags |= MDSS_MDP_RIGHT_MIXER;
 			req.src_rect.x = mixer->width;
 			req.src_rect.w = fbi->var.xres - mixer->width;
 		} else {
 			req.src_rect.x = 0;
-			req.src_rect.w = MIN(fbi->var.xres, mixer->width);
+			req.src_rect.w = MIN(fbi->var.xres,
+							mixer->width);
 		}
 
 		req.src_rect.y = 0;
 		req.src_rect.h = req.src.height;
-		req.dst_rect.x = 0;
-		req.dst_rect.y = 0;
 		req.dst_rect.w = req.src_rect.w;
 		req.dst_rect.h = req.src_rect.h;
 		req.z_order = MDSS_MDP_STAGE_BASE;
@@ -1429,9 +1492,8 @@
 		ret = mdss_mdp_overlay_pipe_setup(mfd, &req, &pipe);
 		if (ret)
 			return ret;
-
-		pr_debug("ctl=%d pnum=%d\n", mdp5_data->ctl->num, pipe->num);
 	}
+	pr_debug("ctl=%d pnum=%d\n", mdp5_data->ctl->num, pipe->num);
 
 	*ppipe = pipe;
 	return 0;
@@ -1469,6 +1531,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;
@@ -1485,8 +1548,8 @@
 		goto pan_display_error;
 	}
 
-
-	ret = mdss_mdp_overlay_get_fb_pipe(mfd, &pipe, MDSS_MDP_MIXER_MUX_LEFT);
+	ret = mdss_mdp_overlay_get_fb_pipe(mfd, &pipe,
+					MDSS_MDP_MIXER_MUX_LEFT);
 	if (ret) {
 		pr_err("unable to allocate base pipe\n");
 		goto pan_display_error;
@@ -1501,6 +1564,7 @@
 	if (is_mdss_iommu_attached()) {
 		if (!mfd->iova) {
 			pr_err("mfd iova is zero\n");
+			mdss_mdp_pipe_unmap(pipe);
 			goto pan_display_error;
 		}
 		buf->p[0].addr = mfd->iova;
@@ -1511,12 +1575,11 @@
 	buf->p[0].addr += offset;
 	buf->p[0].len = fbi->fix.smem_len - offset;
 	buf->num_planes = 1;
-	pipe->has_buf = 1;
 	mdss_mdp_pipe_unmap(pipe);
 
 	if (fbi->var.xres > MAX_MIXER_WIDTH || mfd->split_display) {
 		ret = mdss_mdp_overlay_get_fb_pipe(mfd, &pipe,
-						   MDSS_MDP_MIXER_MUX_RIGHT);
+					   MDSS_MDP_MIXER_MUX_RIGHT);
 		if (ret) {
 			pr_err("unable to allocate right base pipe\n");
 			goto pan_display_error;
@@ -1525,8 +1588,8 @@
 			pr_err("unable to map right base pipe\n");
 			goto pan_display_error;
 		}
+
 		pipe->back_buf = *buf;
-		pipe->has_buf = 1;
 		mdss_mdp_pipe_unmap(pipe);
 	}
 	mutex_unlock(&mdp5_data->ov_lock);
@@ -1535,12 +1598,43 @@
 	    (fbi->var.activate & FB_ACTIVATE_FORCE))
 		mfd->mdp.kickoff_fnc(mfd, NULL);
 
+	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)
@@ -1706,7 +1800,7 @@
 	vsync_ticks = ktime_to_ns(mdp5_data->vsync_time);
 
 	pr_debug("fb%d vsync=%llu", mfd->index, vsync_ticks);
-	ret = scnprintf(buf, PAGE_SIZE, "VSYNC=%llu", vsync_ticks);
+	ret = scnprintf(buf, PAGE_SIZE, "VSYNC=%llu\n", vsync_ticks);
 
 	return ret;
 }
@@ -2163,6 +2257,10 @@
 		caps->features |= MDP_BWC_EN;
 	if (mdata->has_decimation)
 		caps->features |= MDP_DECIMATION_EN;
+
+	caps->max_smp_cnt = mdss_res->smp_mb_cnt;
+	caps->smp_per_pipe = mdata->smp_mb_per_pipe;
+
 	return 0;
 }
 
@@ -2201,6 +2299,133 @@
 	return ret;
 }
 
+static int __handle_overlay_prepare(struct msm_fb_data_type *mfd,
+		struct mdp_overlay_list *ovlist,
+		struct mdp_overlay *overlays)
+{
+	struct mdss_mdp_pipe *right_plist[MDSS_MDP_MAX_STAGE] = { 0 };
+	struct mdss_mdp_pipe *left_plist[MDSS_MDP_MAX_STAGE] = { 0 };
+	struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
+	struct mdss_mdp_pipe *pipe;
+	struct mdp_overlay *req;
+	int ret = 0, left_cnt = 0, right_cnt = 0;
+	int i;
+	u32 new_reqs = 0;
+
+	ret = mutex_lock_interruptible(&mdp5_data->ov_lock);
+	if (ret)
+		return ret;
+
+	if (!mfd->panel_power_on) {
+		mutex_unlock(&mdp5_data->ov_lock);
+		return -EPERM;
+	}
+
+	pr_debug("prepare fb%d num_overlays=%d\n", mfd->index,
+			ovlist->num_overlays);
+
+	for (i = 0; i < ovlist->num_overlays; i++) {
+		req = overlays + i;
+
+		req->z_order += MDSS_MDP_STAGE_0;
+		ret = mdss_mdp_overlay_pipe_setup(mfd, req, &pipe);
+		req->z_order -= MDSS_MDP_STAGE_0;
+
+		if (IS_ERR_VALUE(ret))
+			goto validate_exit;
+
+		/* keep track of the new overlays to unset in case of errors */
+		if (pipe->play_cnt == 0)
+			new_reqs |= pipe->ndx;
+
+		if (pipe->flags & MDSS_MDP_RIGHT_MIXER) {
+			if (right_cnt >= MDSS_MDP_MAX_STAGE) {
+				pr_err("too many pipes on right mixer\n");
+				ret = -EINVAL;
+				goto validate_exit;
+			}
+			right_plist[right_cnt] = pipe;
+			right_cnt++;
+		} else {
+			if (left_cnt >= MDSS_MDP_MAX_STAGE) {
+				pr_err("too many pipes on left mixer\n");
+				ret = -EINVAL;
+				goto validate_exit;
+			}
+			left_plist[left_cnt] = pipe;
+			left_cnt++;
+		}
+	}
+
+	ret = mdss_mdp_perf_bw_check(mdp5_data->ctl, left_plist, left_cnt,
+			right_plist, right_cnt);
+
+validate_exit:
+	if (IS_ERR_VALUE(ret))
+		mdss_mdp_overlay_release(mfd, new_reqs);
+	mutex_unlock(&mdp5_data->ov_lock);
+
+	ovlist->processed_overlays = i;
+
+	return ret;
+}
+
+static int __handle_ioctl_overlay_prepare(struct msm_fb_data_type *mfd,
+		void __user *argp)
+{
+	struct mdp_overlay_list ovlist;
+	struct mdp_overlay *req_list[OVERLAY_MAX];
+	struct mdp_overlay *overlays;
+	int i, ret;
+
+	if (copy_from_user(&ovlist, argp, sizeof(ovlist)))
+		return -EFAULT;
+
+	if (ovlist.num_overlays >= OVERLAY_MAX) {
+		pr_err("Number of overlays exceeds max\n");
+		return -EINVAL;
+	}
+
+	overlays = kmalloc(ovlist.num_overlays * sizeof(*overlays), GFP_KERNEL);
+	if (!overlays) {
+		pr_err("Unable to allocate memory for overlays\n");
+		return -ENOMEM;
+	}
+
+	if (copy_from_user(req_list, ovlist.overlay_list,
+				sizeof(struct mdp_overlay*) * ovlist.num_overlays)) {
+		ret = -EFAULT;
+		goto validate_exit;
+	}
+
+	for (i = 0; i < ovlist.num_overlays; i++) {
+		if (copy_from_user(overlays + i, req_list[i],
+				sizeof(struct mdp_overlay))) {
+			ret = -EFAULT;
+			goto validate_exit;
+		}
+	}
+
+	ret = __handle_overlay_prepare(mfd, &ovlist, overlays);
+	if (!IS_ERR_VALUE(ret)) {
+		for (i = 0; i < ovlist.num_overlays; i++) {
+			if (copy_to_user(req_list[i], overlays + i,
+					sizeof(struct mdp_overlay))) {
+				ret = -EFAULT;
+				goto validate_exit;
+			}
+		}
+	}
+
+	if (copy_to_user(argp, &ovlist, sizeof(ovlist)))
+		ret = -EFAULT;
+
+validate_exit:
+	kfree(overlays);
+
+	return ret;
+}
+
 static int mdss_mdp_overlay_ioctl_handler(struct msm_fb_data_type *mfd,
 					  u32 cmd, void __user *argp)
 {
@@ -2324,6 +2549,9 @@
 		if (!ret)
 			ret = copy_to_user(argp, &metadata, sizeof(metadata));
 		break;
+	case MSMFB_OVERLAY_PREPARE:
+		ret = __handle_ioctl_overlay_prepare(mfd, argp);
+		break;
 	default:
 		if (mfd->panel.type == WRITEBACK_PANEL)
 			ret = mdss_mdp_wb_ioctl_handler(mfd, cmd, argp);
@@ -2372,6 +2600,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);
@@ -2412,10 +2647,10 @@
 	}
 
 	if (!mfd->panel_info->cont_splash_enabled &&
-		(mfd->panel_info->type != DTV_PANEL) &&
-		(mfd->panel_info->type != WRITEBACK_PANEL)) {
+		(mfd->panel_info->type != DTV_PANEL)) {
 		rc = mdss_mdp_overlay_start(mfd);
-		if (!IS_ERR_VALUE(rc))
+		if (!IS_ERR_VALUE(rc) &&
+			(mfd->panel_info->type != WRITEBACK_PANEL))
 			rc = mdss_mdp_overlay_kickoff(mfd, NULL);
 	} else {
 		rc = mdss_mdp_ctl_setup(mdp5_data->ctl);
@@ -2497,17 +2732,62 @@
 
 int mdss_panel_register_done(struct mdss_panel_data *pdata)
 {
-	/*
-	 * Clocks are already on if continuous splash is enabled,
-	 * increasing ref_cnt to help balance clocks once done.
-	 */
-	if (pdata->panel_info.cont_splash_enabled) {
-		mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+	if (pdata->panel_info.cont_splash_enabled)
 		mdss_mdp_footswitch_ctrl_splash(1);
-	}
+
 	return 0;
 }
 
+static int __mdss_mdp_ctl_handoff(struct mdss_mdp_ctl *ctl,
+	struct mdss_data_type *mdata)
+{
+	int rc = 0;
+	int i, j;
+	u32 mixercfg;
+	struct mdss_mdp_pipe *pipe = NULL;
+
+	if (!ctl || !mdata)
+		return -EINVAL;
+
+	for (i = 0; i < mdata->nmixers_intf; i++) {
+		mixercfg = mdss_mdp_ctl_read(ctl, MDSS_MDP_REG_CTL_LAYER(i));
+		pr_debug("for lm%d mixercfg = 0x%09x\n", i, mixercfg);
+
+		j = MDSS_MDP_SSPP_VIG0;
+		for (; j < MDSS_MDP_MAX_SSPP && mixercfg; j++) {
+			u32 cfg = j * 3;
+			if ((j == MDSS_MDP_SSPP_VIG3) ||
+			    (j == MDSS_MDP_SSPP_RGB3)) {
+				/* Add 2 to account for Cursor & Border bits */
+				cfg += 2;
+			}
+			if (mixercfg & (0x7 << cfg)) {
+				pr_debug("Pipe %d staged\n", j);
+				pipe = mdss_mdp_pipe_search(mdata, BIT(j));
+				if (!pipe) {
+					pr_warn("Invalid pipe %d staged\n", j);
+					continue;
+				}
+
+				rc = mdss_mdp_pipe_handoff(pipe);
+				if (rc) {
+					pr_err("Failed to handoff pipe%d\n",
+						pipe->num);
+					goto exit;
+				}
+
+				rc = mdss_mdp_mixer_handoff(ctl, i, pipe);
+				if (rc) {
+					pr_err("failed to handoff mix%d\n", i);
+					goto exit;
+				}
+			}
+		}
+	}
+exit:
+	return rc;
+}
+
 /**
  * mdss_mdp_overlay_handoff() - Read MDP registers to handoff an active ctl path
  * @mfd: Msm frame buffer structure associated with the fb device.
@@ -2523,10 +2803,8 @@
 	int rc = 0;
 	struct mdss_data_type *mdata = mfd_to_mdata(mfd);
 	struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
-	int i, j;
-	u32 reg;
-	struct mdss_mdp_pipe *pipe = NULL;
 	struct mdss_mdp_ctl *ctl = NULL;
+	struct mdss_mdp_ctl *sctl = NULL;
 
 	if (!mdp5_data->ctl) {
 		ctl = __mdss_mdp_overlay_ctl_init(mfd);
@@ -2550,38 +2828,23 @@
 	ctl->clk_rate = mdss_mdp_get_clk_rate(MDSS_CLK_MDP_SRC);
 	pr_debug("Set the ctl clock rate to %d Hz\n", ctl->clk_rate);
 
-	for (i = 0; i < mdata->nmixers_intf; i++) {
-		reg = mdss_mdp_ctl_read(ctl, MDSS_MDP_REG_CTL_LAYER(i));
-		pr_debug("for lm%d reg = 0x%09x\n", i, reg);
-		for (j = MDSS_MDP_SSPP_VIG0; j < MDSS_MDP_MAX_SSPP; j++) {
-			u32 cfg = j * 3;
-			if ((j == MDSS_MDP_SSPP_VIG3) ||
-				(j == MDSS_MDP_SSPP_RGB3)) {
-				/* Add 2 to account for Cursor & Border bits */
-				cfg += 2;
-			}
-			if (reg & (0x7 << cfg)) {
-				pr_debug("Pipe %d staged\n", j);
-				pipe = mdss_mdp_pipe_search(mdata, BIT(j));
-				if (!pipe) {
-					pr_warn("Invalid pipe %d staged\n", j);
-					continue;
-				}
+	rc = __mdss_mdp_ctl_handoff(ctl, mdata);
+	if (rc) {
+		pr_err("primary ctl handoff failed. rc=%d\n", rc);
+		goto error;
+	}
 
-				rc = mdss_mdp_pipe_handoff(pipe);
-				if (rc) {
-					pr_err("Failed to handoff pipe num %d\n"
-						, pipe->num);
-					goto error;
-				}
-
-				rc = mdss_mdp_mixer_handoff(ctl, i, pipe);
-				if (rc) {
-					pr_err("failed to handoff mixer num %d\n"
-						, i);
-					goto error;
-				}
-			}
+	if (mfd->split_display) {
+		sctl = mdss_mdp_get_split_ctl(ctl);
+		if (!sctl) {
+			pr_err("cannot get secondary ctl. fail the handoff\n");
+			rc = -EPERM;
+			goto error;
+		}
+		rc = __mdss_mdp_ctl_handoff(sctl, mdata);
+		if (rc) {
+			pr_err("secondary ctl handoff failed. rc=%d\n", rc);
+			goto error;
 		}
 	}
 
@@ -2593,9 +2856,9 @@
 
 error:
 	if (rc && ctl) {
-		__mdss_mdp_handoff_cleanup_pipes(mfd, MDSS_MDP_PIPE_TYPE_RGB);
-		__mdss_mdp_handoff_cleanup_pipes(mfd, MDSS_MDP_PIPE_TYPE_VIG);
-		__mdss_mdp_handoff_cleanup_pipes(mfd, MDSS_MDP_PIPE_TYPE_DMA);
+		mdss_mdp_handoff_cleanup_pipes(mfd, MDSS_MDP_PIPE_TYPE_RGB);
+		mdss_mdp_handoff_cleanup_pipes(mfd, MDSS_MDP_PIPE_TYPE_VIG);
+		mdss_mdp_handoff_cleanup_pipes(mfd, MDSS_MDP_PIPE_TYPE_DMA);
 		mdss_mdp_ctl_destroy(ctl);
 		mdp5_data->ctl = NULL;
 		mdp5_data->handoff = false;
@@ -2604,6 +2867,107 @@
 	return rc;
 }
 
+static void __vsync_retire_handle_vsync(struct mdss_mdp_ctl *ctl, ktime_t t)
+{
+	struct msm_fb_data_type *mfd = ctl->mfd;
+	struct mdss_overlay_private *mdp5_data;
+
+	if (!mfd || !mfd->mdp.private1) {
+		pr_warn("Invalid handle for vsync\n");
+		return;
+	}
+
+	mdp5_data = mfd_to_mdp5_data(mfd);
+	schedule_work(&mdp5_data->retire_work);
+}
+
+static void __vsync_retire_work_handler(struct work_struct *work)
+{
+	struct mdss_overlay_private *mdp5_data =
+		container_of(work, typeof(*mdp5_data), retire_work);
+	struct msm_sync_pt_data *sync_pt_data;
+
+	if (!mdp5_data->ctl || !mdp5_data->ctl->mfd)
+		return;
+
+	if (!mdp5_data->ctl->remove_vsync_handler)
+		return;
+
+	sync_pt_data = &mdp5_data->ctl->mfd->mdp_sync_pt_data;
+	mutex_lock(&sync_pt_data->sync_mutex);
+	if (mdp5_data->retire_cnt > 0) {
+		sw_sync_timeline_inc(mdp5_data->vsync_timeline, 1);
+
+		mdp5_data->retire_cnt--;
+		if (mdp5_data->retire_cnt == 0) {
+			mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+			mdp5_data->ctl->remove_vsync_handler(mdp5_data->ctl,
+					&mdp5_data->vsync_retire_handler);
+			mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+		}
+	}
+	mutex_unlock(&sync_pt_data->sync_mutex);
+}
+
+static struct sync_fence *
+__vsync_retire_get_fence(struct msm_sync_pt_data *sync_pt_data)
+{
+	struct msm_fb_data_type *mfd;
+	struct mdss_overlay_private *mdp5_data;
+	struct mdss_mdp_ctl *ctl;
+	int rc, value;
+
+	mfd = container_of(sync_pt_data, typeof(*mfd), mdp_sync_pt_data);
+	mdp5_data = mfd_to_mdp5_data(mfd);
+
+	if (!mdp5_data || !mdp5_data->ctl)
+		return ERR_PTR(-ENODEV);
+
+	ctl = mdp5_data->ctl;
+	if (!ctl->add_vsync_handler)
+		return ERR_PTR(-EOPNOTSUPP);
+
+	if (!ctl->power_on) {
+		pr_debug("fb%d vsync pending first update\n", mfd->index);
+		return ERR_PTR(-EPERM);
+	}
+
+	if (mdp5_data->retire_cnt == 0) {
+		mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+		rc = ctl->add_vsync_handler(ctl,
+				&mdp5_data->vsync_retire_handler);
+		mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+		if (IS_ERR_VALUE(rc))
+			return ERR_PTR(rc);
+	}
+	value = mdp5_data->vsync_timeline->value + 1 + mdp5_data->retire_cnt;
+	mdp5_data->retire_cnt++;
+
+	return mdss_fb_sync_get_fence(mdp5_data->vsync_timeline,
+			"mdp-retire", value);
+}
+
+static int __vsync_retire_setup(struct msm_fb_data_type *mfd)
+{
+	struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
+	char name[24];
+
+	snprintf(name, sizeof(name), "mdss_fb%d_retire", mfd->index);
+	mdp5_data->vsync_timeline = sw_sync_timeline_create(name);
+	if (mdp5_data->vsync_timeline == NULL) {
+		pr_err("cannot vsync create time line");
+		return -ENOMEM;
+	}
+	mfd->mdp_sync_pt_data.get_retire_fence = __vsync_retire_get_fence;
+
+	mdp5_data->vsync_retire_handler.vsync_handler =
+		__vsync_retire_handle_vsync;
+	mdp5_data->vsync_retire_handler.cmd_post_flush = false;
+	INIT_WORK(&mdp5_data->retire_work, __vsync_retire_work_handler);
+
+	return 0;
+}
+
 int mdss_mdp_overlay_init(struct msm_fb_data_type *mfd)
 {
 	struct device *dev = mfd->fbi->dev;
@@ -2621,6 +2985,7 @@
 	mdp5_interface->panel_register_done = mdss_panel_register_done;
 	mdp5_interface->kickoff_fnc = mdss_mdp_overlay_kickoff;
 	mdp5_interface->get_sync_fnc = mdss_mdp_rotator_sync_pt_get;
+	mdp5_interface->splash_init_fnc = mdss_mdp_splash_init;
 
 	mdp5_data = kmalloc(sizeof(struct mdss_overlay_private), GFP_KERNEL);
 	if (!mdp5_data) {
@@ -2643,6 +3008,7 @@
 		goto init_fail;
 	}
 	mfd->mdp.private1 = mdp5_data;
+	mfd->wait_for_kickoff = true;
 
 	rc = mdss_mdp_overlay_fb_parse_dt(mfd);
 	if (rc)
@@ -2669,6 +3035,12 @@
 			pr_err("Error dfps sysfs creation ret=%d\n", rc);
 			goto init_fail;
 		}
+	} else if (mfd->panel_info->type == MIPI_CMD_PANEL) {
+		rc = __vsync_retire_setup(mfd);
+		if (IS_ERR_VALUE(rc)) {
+			pr_err("unable to create vsync timeline\n");
+			goto init_fail;
+		}
 	}
 	mfd->mdp_sync_pt_data.async_wait_fences = true;
 	rc = sysfs_create_link_nowarn(&dev->kobj,
@@ -2707,45 +3079,6 @@
 	return rc;
 }
 
-static __ref int mdss_mdp_overlay_splash_parse_dt(struct msm_fb_data_type *mfd)
-{
-	struct platform_device *pdev = mfd->pdev;
-	struct mdss_overlay_private *mdp5_mdata = mfd_to_mdp5_data(mfd);
-	int len = 0, rc = 0;
-	u32 offsets[2];
-
-	of_find_property(pdev->dev.of_node, "qcom,memblock-reserve", &len);
-
-	if (len < 1) {
-		pr_debug("mem reservation for splash screen fb not present\n");
-		rc = -EINVAL;
-		goto error;
-	}
-
-	len = len/sizeof(u32);
-
-	rc = of_property_read_u32_array(pdev->dev.of_node,
-			"qcom,memblock-reserve", offsets, len);
-	if (rc) {
-		pr_debug("Error reading mem reserve settings for fb\n");
-		goto error;
-	}
-
-	if (!memblock_is_reserved(offsets[0])) {
-		pr_debug("failed to reserve memory for fb splash\n");
-		rc = -EINVAL;
-		goto error;
-	}
-
-	mdp5_mdata->splash_mem_addr = offsets[0];
-	mdp5_mdata->splash_mem_size = offsets[1];
-	pr_debug("memaddr=%x size=%x\n", mdp5_mdata->splash_mem_addr,
-		mdp5_mdata->splash_mem_size);
-
-error:
-	return rc;
-}
-
 static int mdss_mdp_overlay_fb_parse_dt(struct msm_fb_data_type *mfd)
 {
 	int rc = 0;
@@ -2759,13 +3092,5 @@
 			pdev->name);
 	}
 
-	rc = mdss_mdp_overlay_splash_parse_dt(mfd);
-	if (rc && mfd->panel_info->cont_splash_enabled) {
-		pr_err("No rsvd mem found in DT for splash screen\n");
-	} else {
-		pr_debug("Mem reservation not reqd if cont splash diasbled\n");
-		rc = 0;
-	}
-
 	return rc;
 }
diff --git a/drivers/video/msm/mdss/mdss_mdp_pipe.c b/drivers/video/msm/mdss/mdss_mdp_pipe.c
index 0abd4d5..c522857 100644
--- a/drivers/video/msm/mdss/mdss_mdp_pipe.c
+++ b/drivers/video/msm/mdss/mdss_mdp_pipe.c
@@ -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
@@ -15,6 +15,7 @@
 
 #include <linux/bitmap.h>
 #include <linux/errno.h>
+#include <linux/iopoll.h>
 #include <linux/mutex.h>
 
 #include "mdss_mdp.h"
@@ -25,10 +26,20 @@
 #define SMP_MB_ENTRY_SIZE	16
 #define MAX_BPP 4
 
+#define PIPE_HALT_TIMEOUT_US	0x4000
+
+/* following offsets are relative to ctrl register bit offset */
+#define CLK_FORCE_ON_OFFSET	0x0
+#define CLK_FORCE_OFF_OFFSET	0x1
+/* following offsets are relative to status register bit offset */
+#define CLK_STATUS_OFFSET	0x0
+
 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(
 	struct mdss_data_type *mdata, int client_id);
 
@@ -55,8 +66,27 @@
 	else
 		n -= fixed_cnt;
 
-	/* reserve more blocks if needed, but can't free mmb at this point */
-	for (i = bitmap_weight(smp_map->allocated, SMP_MB_CNT); i < n; i++) {
+	i = bitmap_weight(smp_map->allocated, SMP_MB_CNT);
+
+	/*
+	 * SMP programming is not double buffered. Fail the request,
+	 * that calls for change in smp configuration (addition/removal
+	 * of smp blocks), so that fallback solution happens.
+	 */
+	if (i != 0 && n != i) {
+		pr_debug("Can't change mmb config, num_blks: %d alloc: %d\n",
+			n, i);
+		return 0;
+	}
+
+	/*
+	 * Clear previous SMP reservations and reserve according to the
+	 * latest configuration
+	 */
+	mdss_mdp_smp_mmb_free(smp_map->reserved, false);
+
+	/* Reserve mmb blocks*/
+	for (; i < n; i++) {
 		if (bitmap_full(mdata->mmb_alloc_map, SMP_MB_CNT))
 			break;
 
@@ -105,6 +135,26 @@
 	}
 }
 
+/**
+ * @mdss_mdp_smp_get_size - get allocated smp size for a pipe
+ * @pipe: pointer to a pipe
+ *
+ * Function counts number of blocks that are currently allocated for a
+ * pipe, then smp buffer size is number of blocks multiplied by block
+ * size.
+ */
+u32 mdss_mdp_smp_get_size(struct mdss_mdp_pipe *pipe)
+{
+	int i, mb_cnt = 0;
+
+	for (i = 0; i < MAX_PLANES; i++) {
+		mb_cnt += bitmap_weight(pipe->smp_map[i].allocated, SMP_MB_CNT);
+		mb_cnt += bitmap_weight(pipe->smp_map[i].fixed, SMP_MB_CNT);
+	}
+
+	return mb_cnt * SMP_MB_SIZE;
+}
+
 static void mdss_mdp_smp_set_wm_levels(struct mdss_mdp_pipe *pipe, int mb_cnt)
 {
 	u32 fetch_size, val, wm[3];
@@ -165,8 +215,8 @@
 	u32 num_blks = 0, reserved = 0;
 	struct mdss_mdp_plane_sizes ps;
 	int i;
-	int rc = 0, rot_mode = 0;
-	u32 nlines, format;
+	int rc = 0, rot_mode = 0, wb_mixer = 0;
+	u32 nlines, format, seg_w;
 	u16 width;
 
 	width = pipe->src.w >> pipe->horz_deci;
@@ -176,6 +226,29 @@
 			pipe->src_fmt, &ps);
 		if (rc)
 			return rc;
+		/*
+		 * Override fetch strides with SMP buffer size for both the
+		 * planes. BWC line buffer needs to be divided into 16
+		 * segments and every segment is aligned to format
+		 * specific RAU size
+		 */
+		seg_w = DIV_ROUND_UP(pipe->src.w, 16);
+		if (pipe->src_fmt->fetch_planes == MDSS_MDP_PLANE_INTERLEAVED) {
+			ps.ystride[0] = ALIGN(seg_w, 32) * 16 * ps.rau_h[0] *
+					pipe->src_fmt->bpp;
+			ps.ystride[1] = 0;
+		} else {
+			u32 bwc_width = ALIGN(seg_w, 64) * 16;
+			ps.ystride[0] = bwc_width * ps.rau_h[0];
+			ps.ystride[1] = bwc_width * ps.rau_h[1];
+			/*
+			 * Since chroma for H1V2 is not subsampled it needs
+			 * to be accounted for with bpp factor
+			 */
+			if (pipe->src_fmt->chroma_sample ==
+				MDSS_MDP_CHROMA_H1V2)
+				ps.ystride[1] *= 2;
+		}
 		pr_debug("BWC SMP strides ystride0=%x ystride1=%x\n",
 			ps.ystride[0], ps.ystride[1]);
 	} else {
@@ -221,11 +294,26 @@
 		}
 	}
 
-	nlines = pipe->bwc_mode ? 1 : 2;
+	if (pipe->src_fmt->tile)
+		nlines = 8;
+	else
+		nlines = pipe->bwc_mode ? 1 : 2;
+
+	if (pipe->mixer->type == MDSS_MDP_MIXER_TYPE_WRITEBACK)
+		wb_mixer = 1;
 
 	mutex_lock(&mdss_mdp_smp_lock);
+	for (i = (MAX_PLANES - 1); i >= ps.num_planes; i--) {
+		if (bitmap_weight(pipe->smp_map[i].allocated, SMP_MB_CNT)) {
+			pr_debug("Extra mmb identified for pnum=%d plane=%d\n",
+				pipe->num, i);
+			mutex_unlock(&mdss_mdp_smp_lock);
+			return -EAGAIN;
+		}
+	}
+
 	for (i = 0; i < ps.num_planes; i++) {
-		if (rot_mode) {
+		if (rot_mode || wb_mixer) {
 			num_blks = 1;
 		} else {
 			num_blks = DIV_ROUND_UP(ps.ystride[i] * nlines,
@@ -393,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;
 }
 
@@ -453,24 +537,31 @@
 
 	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;
 		}
 		pipe = NULL;
 	}
 
+	if (pipe && mdss_mdp_pipe_fetch_halt(pipe)) {
+		pr_err("%d failed because pipe is in bad state\n",
+			pipe->num);
+		return NULL;
+	}
+
 	if (pipe) {
 		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;
-		mdss_mdp_pipe_map(pipe);
+		kref_get(&pipe->kref);
 		pr_debug("pipe sharing for pipe=%d\n", pipe->num);
 	} else {
 		pr_err("no %d type pipes available\n", type);
@@ -492,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;
@@ -579,38 +670,145 @@
 	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;
 
-	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
-	mdss_mdp_pipe_sspp_term(pipe);
-	mdss_mdp_smp_free(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);
+		mdss_mdp_pipe_fetch_halt(pipe);
+		mdss_mdp_pipe_sspp_term(pipe);
+		mdss_mdp_smp_free(pipe);
+		mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+	} else {
+		mdss_mdp_smp_unreserve(pipe);
+	}
+
 	pipe->flags = 0;
 	pipe->bwc_mode = 0;
+	pipe->mfd = NULL;
 	memset(&pipe->scale, 0, sizeof(struct mdp_scale_data));
+}
 
+static int mdss_mdp_is_pipe_idle(struct mdss_mdp_pipe *pipe,
+	bool ignore_force_on)
+{
+	u32 reg_val;
+	u32 vbif_idle_mask, forced_on_mask, clk_status_idle_mask;
+	bool is_idle = false, is_forced_on;
+	struct mdss_data_type *mdata = mdss_mdp_get_mdata();
+
+	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+
+	forced_on_mask = BIT(pipe->clk_ctrl.bit_off + CLK_FORCE_ON_OFFSET);
+	reg_val = readl_relaxed(mdata->mdp_base + pipe->clk_ctrl.reg_off);
+	is_forced_on = (reg_val & forced_on_mask) ? true : false;
+
+	pr_debug("pipe#:%d clk_ctrl: 0x%x forced_on_mask: 0x%x\n", pipe->num,
+		reg_val, forced_on_mask);
+	/* if forced on then no need to check status */
+	if (!is_forced_on) {
+		clk_status_idle_mask =
+			BIT(pipe->clk_status.bit_off + CLK_STATUS_OFFSET);
+		reg_val = readl_relaxed(mdata->mdp_base +
+			pipe->clk_status.reg_off);
+
+		if (reg_val & clk_status_idle_mask)
+			is_idle = false;
+
+		pr_debug("pipe#:%d clk_status:0x%x clk_status_idle_mask:0x%x\n",
+			pipe->num, reg_val, clk_status_idle_mask);
+	}
+
+	if (!ignore_force_on && (is_forced_on || !is_idle))
+		goto exit;
+
+	vbif_idle_mask = BIT(pipe->xin_id + 16);
+	reg_val = readl_relaxed(mdata->vbif_base + MMSS_VBIF_XIN_HALT_CTRL1);
+
+	if (reg_val & vbif_idle_mask)
+		is_idle = true;
+
+	pr_debug("pipe#:%d XIN_HALT_CTRL1: 0x%x\n", pipe->num, reg_val);
+
+exit:
 	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
 
-	return 0;
+	return is_idle;
+}
+
+/**
+ * mdss_mdp_pipe_fetch_halt() - Halt VBIF client corresponding to specified pipe
+ * @pipe: pointer to the pipe data structure which needs to be halted.
+ *
+ * Check if VBIF client corresponding to specified pipe is idle or not. If not
+ * send a halt request for the client in question and wait for it be idle.
+ *
+ * This function would typically be called after pipe is unstaged or before it
+ * is initialized. On success it should be assumed that pipe is in idle state
+ * and would not fetch any more data. This function cannot be called from
+ * interrupt context.
+ */
+int mdss_mdp_pipe_fetch_halt(struct mdss_mdp_pipe *pipe)
+{
+	bool is_idle;
+	int rc = 0;
+	u32 reg_val, idle_mask, status;
+	struct mdss_data_type *mdata = mdss_mdp_get_mdata();
+
+	is_idle = mdss_mdp_is_pipe_idle(pipe, true);
+	if (!is_idle) {
+		pr_err("%pS: pipe%d is not idle. xin_id=%d\n",
+			__builtin_return_address(0), pipe->num, pipe->xin_id);
+
+		mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+		mutex_lock(&mdata->reg_lock);
+		idle_mask = BIT(pipe->xin_id + 16);
+
+		reg_val = readl_relaxed(mdata->vbif_base +
+			MMSS_VBIF_XIN_HALT_CTRL0);
+		writel_relaxed(reg_val | BIT(pipe->xin_id),
+			mdata->vbif_base + MMSS_VBIF_XIN_HALT_CTRL0);
+		mutex_unlock(&mdata->reg_lock);
+
+		rc = readl_poll_timeout(mdata->vbif_base +
+			MMSS_VBIF_XIN_HALT_CTRL1, status, (status & idle_mask),
+			1000, PIPE_HALT_TIMEOUT_US);
+		if (rc == -ETIMEDOUT)
+			pr_err("VBIF client %d not halting. TIMEDOUT.\n",
+				pipe->xin_id);
+		else
+			pr_debug("VBIF client %d is halted\n", pipe->xin_id);
+
+		mutex_lock(&mdata->reg_lock);
+		reg_val = readl_relaxed(mdata->vbif_base +
+			MMSS_VBIF_XIN_HALT_CTRL0);
+		writel_relaxed(reg_val & ~BIT(pipe->xin_id),
+			mdata->vbif_base + MMSS_VBIF_XIN_HALT_CTRL0);
+
+		mutex_unlock(&mdata->reg_lock);
+		mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+	}
+
+	return rc;
 }
 
 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;
-
 }
 
 /**
@@ -668,31 +866,14 @@
 		pipe->src_fmt->bpp);
 
 	pipe->is_handed_off = true;
-	atomic_inc(&pipe->ref_cnt);
+	pipe->play_cnt = 1;
+	kref_init(&pipe->kref);
 
 error:
 	return rc;
 }
 
-void mdss_mdp_crop_rect(struct mdss_mdp_img_rect *src_rect,
-	struct mdss_mdp_img_rect *dst_rect,
-	const struct mdss_mdp_img_rect *sci_rect)
-{
-	struct mdss_mdp_img_rect res;
-	mdss_mdp_intersect_rect(&res, dst_rect, sci_rect);
 
-	if (res.w && res.h) {
-		if ((res.w != dst_rect->w) || (res.h != dst_rect->h)) {
-			src_rect->x = src_rect->x + (res.x - dst_rect->x);
-			src_rect->y = src_rect->y + (res.y - dst_rect->y);
-			src_rect->w = res.w;
-			src_rect->h = res.h;
-		}
-		*dst_rect = (struct mdss_mdp_img_rect)
-			{(res.x - sci_rect->x), (res.y - sci_rect->y),
-			res.w, res.h};
-	}
-}
 
 static int mdss_mdp_image_setup(struct mdss_mdp_pipe *pipe,
 					struct mdss_mdp_data *data)
@@ -795,6 +976,7 @@
 	u32 chroma_samp, unpack, src_format;
 	u32 secure = 0;
 	u32 opmode;
+	struct mdss_data_type *mdata = mdss_mdp_get_mdata();
 
 	fmt = pipe->src_fmt;
 
@@ -825,6 +1007,9 @@
 		     (fmt->bits[C1_B_Cb] << 2) |
 		     (fmt->bits[C0_G_Y] << 0);
 
+	if (fmt->tile)
+		src_format |= BIT(30);
+
 	if (pipe->flags & MDP_ROT_90)
 		src_format |= BIT(11); /* ROT90 */
 
@@ -844,6 +1029,11 @@
 	if (pipe->scale.enable_pxl_ext)
 		opmode |= (1 << 31);
 
+	if (fmt->tile && mdata->highest_bank_bit) {
+		mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_FETCH_CONFIG,
+			MDSS_MDP_FETCH_CONFIG_RESET_VALUE |
+				 mdata->highest_bank_bit << 18);
+	}
 	mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC_FORMAT, src_format);
 	mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC_UNPACK_PATTERN, unpack);
 	mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC_OP_MODE, opmode);
@@ -853,8 +1043,8 @@
 }
 
 int mdss_mdp_pipe_addr_setup(struct mdss_data_type *mdata,
-	struct mdss_mdp_pipe *head, u32 *offsets, u32 *ftch_id, u32 type,
-	u32 num_base, u32 len)
+	struct mdss_mdp_pipe *head, u32 *offsets, u32 *ftch_id, u32 *xin_id,
+	u32 type, u32 num_base, u32 len)
 {
 	u32 i;
 
@@ -866,6 +1056,7 @@
 	for (i = 0; i < len; i++) {
 		head[i].type = type;
 		head[i].ftch_id  = ftch_id[i];
+		head[i].xin_id = xin_id[i];
 		head[i].num = i + num_base;
 		head[i].ndx = BIT(i + num_base);
 		head[i].base = mdata->mdp_base + offsets[i];
@@ -918,7 +1109,7 @@
 static int mdss_mdp_pipe_solidfill_setup(struct mdss_mdp_pipe *pipe)
 {
 	int ret;
-	u32 secure, format;
+	u32 secure, format, unpack;
 
 	pr_debug("solid fill setup on pnum=%d\n", pipe->num);
 
@@ -931,10 +1122,21 @@
 	format = MDSS_MDP_FMT_SOLID_FILL;
 	secure = (pipe->flags & MDP_SECURE_OVERLAY_SESSION ? 0xF : 0x0);
 
+	/* support ARGB color format only */
+	unpack = (C3_ALPHA << 24) | (C2_R_Cr << 16) |
+		(C1_B_Cb << 8) | (C0_G_Y << 0);
 	mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC_FORMAT, format);
 	mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC_CONSTANT_COLOR,
 		pipe->bg_color);
+	mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC_UNPACK_PATTERN, unpack);
 	mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC_ADDR_SW_STATUS, secure);
+	mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC_OP_MODE, 0);
+
+	if (pipe->type != MDSS_MDP_PIPE_TYPE_DMA) {
+		mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SCALE_CONFIG, 0);
+		if (pipe->type == MDSS_MDP_PIPE_TYPE_VIG)
+			mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_VIG_OP_MODE, 0);
+	}
 
 	return 0;
 }
@@ -972,7 +1174,7 @@
 			 (pipe->mixer->type == MDSS_MDP_MIXER_TYPE_WRITEBACK)
 			 && (ctl->mdata->mixer_switched)) ||
 			 ctl->roi_changed;
-	if (src_data == NULL || !pipe->has_buf) {
+	if (src_data == NULL || (pipe->flags & MDP_SOLID_FILL)) {
 		pipe->params_changed = 0;
 		mdss_mdp_pipe_solidfill_setup(pipe);
 		goto update_nobuf;
diff --git a/drivers/video/msm/mdss/mdss_mdp_pp.c b/drivers/video/msm/mdss/mdss_mdp_pp.c
index 555974b..6b497bb 100644
--- a/drivers/video/msm/mdss/mdss_mdp_pp.c
+++ b/drivers/video/msm/mdss/mdss_mdp_pp.c
@@ -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
@@ -174,10 +174,14 @@
 	GAMUT_T5_SIZE + GAMUT_T6_SIZE + GAMUT_T7_SIZE)
 
 #define MDSS_MDP_PA_SIZE		0xC
+#define MDSS_MDP_SIX_ZONE_SIZE		0xC
+#define MDSS_MDP_MEM_COL_SIZE		0x3C
 #define MDSS_MDP_GC_SIZE		0x28
 #define MDSS_MDP_PCC_SIZE		0xB8
 #define MDSS_MDP_GAMUT_SIZE		0x5C
-#define MDSS_MDP_IGC_DSPP_COLORS	0x3
+#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
@@ -293,8 +297,8 @@
 	u32 enhist_lut[MDSS_BLOCK_DISP_NUM][ENHIST_LUT_ENTRIES];
 	struct mdp_pa_cfg pa_disp_cfg[MDSS_BLOCK_DISP_NUM];
 	struct mdp_pa_v2_data pa_v2_disp_cfg[MDSS_BLOCK_DISP_NUM];
-	u32 six_zone_lut_curve_p0[MDSS_BLOCK_DISP_NUM][SIX_ZONE_LUT_ENTRIES];
-	u32 six_zone_lut_curve_p1[MDSS_BLOCK_DISP_NUM][SIX_ZONE_LUT_ENTRIES];
+	u32 six_zone_lut_curve_p0[MDSS_BLOCK_DISP_NUM][MDP_SIX_ZONE_LUT_SIZE];
+	u32 six_zone_lut_curve_p1[MDSS_BLOCK_DISP_NUM][MDP_SIX_ZONE_LUT_SIZE];
 	struct mdp_pcc_cfg_data pcc_disp_cfg[MDSS_BLOCK_DISP_NUM];
 	struct mdp_igc_lut_data igc_disp_cfg[MDSS_BLOCK_DISP_NUM];
 	struct mdp_pgc_lut_data argc_disp_cfg[MDSS_BLOCK_DISP_NUM];
@@ -393,6 +397,7 @@
 				struct mdss_mdp_ctl *ctl, u32 num, u32 *opmode);
 static int mdss_mdp_ad_setup(struct msm_fb_data_type *mfd);
 static void pp_ad_cfg_lut(char __iomem *addr, u32 *data);
+static u32 pp_ad_attenuate_bl(u32 bl, struct mdss_ad_info *ad);
 static int pp_num_to_side(struct mdss_mdp_ctl *ctl, u32 num);
 static inline bool pp_sts_is_enabled(u32 sts, int side);
 static inline void pp_sts_set_split_bits(u32 *sts, u32 bits);
@@ -643,7 +648,7 @@
 				data, addr);
 
 		/* Remove Index Update */
-		for (i = 1; i < SIX_ZONE_LUT_ENTRIES; i++) {
+		for (i = 1; i < MDP_SIX_ZONE_LUT_SIZE; i++) {
 			addr += 4;
 			writel_relaxed(pa_v2_config->six_zone_curve_p1[i],
 					addr);
@@ -785,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)) {
@@ -821,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)) {
@@ -906,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
@@ -944,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) ||
@@ -1089,7 +1116,7 @@
 
 		/*program pixel extn values for the SSPP*/
 		mdss_mdp_pipe_program_pixel_extn(pipe);
-	} else {
+	} else if (pipe->type == MDSS_MDP_PIPE_TYPE_VIG) {
 		writel_relaxed(phasex_step, pipe->base +
 		   MDSS_MDP_REG_SCALE_PHASE_STEP_X);
 		writel_relaxed(phasey_step, pipe->base +
@@ -1098,6 +1125,11 @@
 			MDSS_MDP_REG_SCALE_INIT_PHASE_X);
 		writel_relaxed(init_phasey, pipe->base +
 			MDSS_MDP_REG_SCALE_INIT_PHASE_Y);
+	} else {
+		writel_relaxed(phasex_step, pipe->base +
+		   MDSS_MDP_REG_SCALE_PHASE_STEP_X);
+		writel_relaxed(phasey_step, pipe->base +
+		   MDSS_MDP_REG_SCALE_PHASE_STEP_Y);
 	}
 
 	writel_relaxed(scale_config, pipe->base +
@@ -1146,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?
@@ -1297,22 +1342,19 @@
 		goto error;
 	}
 
+	mutex_lock(&hist_info->hist_mutex);
+	spin_lock_irqsave(&hist_info->hist_lock, flag);
 	if (hist_info->col_en) {
 		*op |= op_flags;
-		mutex_lock(&hist_info->hist_mutex);
-		spin_lock_irqsave(&hist_info->hist_lock, flag);
 		col_state = hist_info->col_state;
-		if (hist_info->is_kick_ready &&
-			((col_state == HIST_IDLE) ||
-			((false == hist_info->read_request) &&
-				col_state == HIST_READY))) {
+		if (col_state == HIST_IDLE) {
 			/* Kick off collection */
 			writel_relaxed(1, base + kick_base);
 			hist_info->col_state = HIST_START;
 		}
-		spin_unlock_irqrestore(&hist_info->hist_lock, flag);
-		mutex_unlock(&hist_info->hist_mutex);
 	}
+	spin_unlock_irqrestore(&hist_info->hist_lock, flag);
+	mutex_unlock(&hist_info->hist_mutex);
 	ret = 0;
 error:
 	return ret;
@@ -1512,6 +1554,9 @@
 		pp_sts_set_split_bits(&pp_sts->pgc_sts, pgc_config->flags);
 	}
 
+	pp_dspp_opmode_config(ctl, dspp_num, pp_sts, mdata->mdp_rev, &opmode);
+
+flush_exit:
 	if (ad_hw) {
 		mutex_lock(&ad->lock);
 		ad_flags = ad->reg_sts;
@@ -1526,8 +1571,6 @@
 		mutex_unlock(&ad->lock);
 	}
 
-	pp_dspp_opmode_config(ctl, dspp_num, pp_sts, mdata->mdp_rev, &opmode);
-flush_exit:
 	writel_relaxed(opmode, base + MDSS_MDP_REG_DSPP_OP_MODE);
 	ctl->flush_bits |= BIT(13 + dspp_num);
 	wmb();
@@ -1583,7 +1626,7 @@
 	if (mdata->nad_cfgs == 0)
 		valid_mixers = false;
 	for (i = 0; i < mixer_cnt && valid_mixers; i++) {
-		if (mixer_id[i] > mdata->nad_cfgs)
+		if (mixer_id[i] >= mdata->nad_cfgs)
 			valid_mixers = false;
 	}
 	if (valid_mixers && (mixer_cnt <= mdata->nmax_concurrent_ad_hw)) {
@@ -1618,7 +1661,7 @@
  */
 int mdss_mdp_pp_resume(struct mdss_mdp_ctl *ctl, u32 dspp_num)
 {
-	u32 flags = 0, disp_num, bl;
+	u32 flags = 0, disp_num, bl, ret = 0;
 	struct pp_sts_type pp_sts;
 	struct mdss_ad_info *ad;
 	struct mdss_data_type *mdata = ctl->mdata;
@@ -1629,7 +1672,9 @@
 	disp_num = ctl->mfd->index;
 
 	if (dspp_num < mdata->nad_cfgs) {
-		ad = &mdata->ad_cfgs[dspp_num];
+		ret = mdss_mdp_get_ad(ctl->mfd, &ad);
+		if (ret)
+			return ret;
 
 		if (PP_AD_STATE_CFG & ad->state)
 			pp_ad_cfg_write(&mdata->ad_off[dspp_num], ad);
@@ -1642,6 +1687,7 @@
 			if (ad->state & PP_AD_STATE_BL_LIN) {
 				bl = ad->bl_lin[bl >> ad->bl_bright_shift];
 				bl = bl << ad->bl_bright_shift;
+				bl = pp_ad_attenuate_bl(bl, ad);
 			}
 			ad->bl_data = bl;
 			pp_ad_input_write(&mdata->ad_off[dspp_num], ad);
@@ -1740,6 +1786,8 @@
 					&mdss_pp_res->dspp_hist[i].hist_mutex);
 				spin_lock_init(
 					&mdss_pp_res->dspp_hist[i].hist_lock);
+				init_completion(
+					&mdss_pp_res->dspp_hist[i].comp);
 			}
 		}
 	}
@@ -1748,6 +1796,7 @@
 		for (i = 0; i < mdata->nvig_pipes; i++) {
 			mutex_init(&vig[i].pp_res.hist.hist_mutex);
 			spin_lock_init(&vig[i].pp_res.hist.hist_lock);
+			init_completion(&vig[i].pp_res.hist.comp);
 		}
 		if (!mdata->pp_bus_hdl) {
 			pp_bus_pdata = &mdp_pp_bus_scale_table;
@@ -1940,10 +1989,13 @@
 
 	/* Six zone LUT and thresh data */
 	if (pa_v2_config->flags & MDP_PP_PA_SIX_ZONE_ENABLE) {
+		if (pa_v2_config->six_zone_len != MDP_SIX_ZONE_LUT_SIZE)
+			return -EINVAL;
+
 		data = (3 << 25);
 		writel_relaxed(data, addr);
 
-		for (i = 0; i < SIX_ZONE_LUT_ENTRIES; i++) {
+		for (i = 0; i < MDP_SIX_ZONE_LUT_SIZE; i++) {
 			addr += 4;
 			mdss_pp_res->six_zone_lut_curve_p1[disp_num][i] =
 				readl_relaxed(addr);
@@ -1954,13 +2006,13 @@
 
 		if (copy_to_user(pa_v2_config->six_zone_curve_p0,
 			&mdss_pp_res->six_zone_lut_curve_p0[disp_num][0],
-			SIX_ZONE_LUT_ENTRIES * sizeof(u32))) {
+			pa_v2_config->six_zone_len * sizeof(u32))) {
 			return -EFAULT;
 		}
 
 		if (copy_to_user(pa_v2_config->six_zone_curve_p1,
 			&mdss_pp_res->six_zone_lut_curve_p1[disp_num][0],
-			SIX_ZONE_LUT_ENTRIES * sizeof(u32))) {
+			pa_v2_config->six_zone_len * sizeof(u32))) {
 			return -EFAULT;
 		}
 
@@ -2005,14 +2057,17 @@
 static int pp_copy_pa_six_zone_lut(struct mdp_pa_v2_cfg_data *pa_v2_config,
 				u32 disp_num)
 {
+	if (pa_v2_config->pa_v2_data.six_zone_len != MDP_SIX_ZONE_LUT_SIZE)
+		return -EINVAL;
+
 	if (copy_from_user(&mdss_pp_res->six_zone_lut_curve_p0[disp_num][0],
 			pa_v2_config->pa_v2_data.six_zone_curve_p0,
-			SIX_ZONE_LUT_ENTRIES * sizeof(u32))) {
+			pa_v2_config->pa_v2_data.six_zone_len * sizeof(u32))) {
 		return -EFAULT;
 	}
 	if (copy_from_user(&mdss_pp_res->six_zone_lut_curve_p1[disp_num][0],
 			pa_v2_config->pa_v2_data.six_zone_curve_p1,
-			SIX_ZONE_LUT_ENTRIES * sizeof(u32))) {
+			pa_v2_config->pa_v2_data.six_zone_len * sizeof(u32))) {
 		return -EFAULT;
 	}
 
@@ -2189,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)
 {
@@ -2309,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);
@@ -2363,7 +2435,7 @@
 {
 	int i, start_idx, idx;
 
-	start_idx = (readl_relaxed(addr) >> 16) & 0xF;
+	start_idx = ((readl_relaxed(addr) >> 16) & 0xF) + 1;
 	for (i = start_idx; i < GC_LUT_SEGMENTS; i++) {
 		idx = min((uint8_t)i, (uint8_t)(num_stages-1));
 		writel_relaxed(lut_data[idx].x_start, addr);
@@ -2373,7 +2445,7 @@
 		writel_relaxed(lut_data[idx].x_start, addr);
 	}
 	addr += 4;
-	start_idx = (readl_relaxed(addr) >> 16) & 0xF;
+	start_idx = ((readl_relaxed(addr) >> 16) & 0xF) + 1;
 	for (i = start_idx; i < GC_LUT_SEGMENTS; i++) {
 		idx = min((uint8_t)i, (uint8_t)(num_stages-1));
 		writel_relaxed(lut_data[idx].slope, addr);
@@ -2383,7 +2455,7 @@
 		writel_relaxed(lut_data[idx].slope, addr);
 	}
 	addr += 4;
-	start_idx = (readl_relaxed(addr) >> 16) & 0xF;
+	start_idx = ((readl_relaxed(addr) >> 16) & 0xF) + 1;
 	for (i = start_idx; i < GC_LUT_SEGMENTS; i++) {
 		idx = min((uint8_t)i, (uint8_t)(num_stages-1));
 		writel_relaxed(lut_data[idx].offset, addr);
@@ -2456,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)
@@ -2479,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))
@@ -2492,20 +2603,28 @@
 	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) +
 			MDSS_MDP_REG_LM_GC_LUT_BASE;
 		pgc_ptr = &mdss_pp_res->argc_disp_cfg[disp_num];
-		mdss_pp_res->pp_disp_flags[disp_num] |=
-			PP_FLAGS_DIRTY_ARGC;
+		if (config->flags & MDP_PP_OPS_WRITE)
+			mdss_pp_res->pp_disp_flags[disp_num] |=
+				PP_FLAGS_DIRTY_ARGC;
 		break;
 	case MDSS_PP_DSPP_CFG:
 		argc_addr = mdss_mdp_get_dspp_addr_off(dspp_num) +
 					MDSS_MDP_REG_DSPP_GC_BASE;
 		pgc_ptr = &mdss_pp_res->pgc_disp_cfg[disp_num];
-		mdss_pp_res->pp_disp_flags[disp_num] |=
-			PP_FLAGS_DIRTY_PGC;
+		if (config->flags & MDP_PP_OPS_WRITE)
+			mdss_pp_res->pp_disp_flags[disp_num] |=
+				PP_FLAGS_DIRTY_PGC;
 		break;
 	default:
 		goto argc_config_exit;
@@ -2515,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 =
@@ -2529,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;
@@ -2869,23 +2992,23 @@
 
 	mutex_lock(&hist_info->hist_mutex);
 	/* check if it is idle */
+	spin_lock_irqsave(&hist_info->hist_lock, flag);
 	if (hist_info->col_en) {
+		spin_unlock_irqrestore(&hist_info->hist_lock, flag);
 		pr_info("%s Hist collection has already been enabled %d",
 			__func__, (u32) ctl_base);
 		ret = -EINVAL;
 		goto exit;
 	}
-	hist_info->frame_cnt = req->frame_cnt;
-	init_completion(&hist_info->comp);
-	hist_info->hist_cnt_read = 0;
-	hist_info->hist_cnt_sent = 0;
-	hist_info->hist_cnt_time = 0;
-	spin_lock_irqsave(&hist_info->hist_lock, flag);
-	hist_info->read_request = false;
+	hist_info->read_request = 0;
 	hist_info->col_state = HIST_RESET;
 	hist_info->col_en = true;
 	spin_unlock_irqrestore(&hist_info->hist_lock, flag);
-	hist_info->is_kick_ready = true;
+	hist_info->frame_cnt = req->frame_cnt;
+	INIT_COMPLETION(hist_info->comp);
+	hist_info->hist_cnt_read = 0;
+	hist_info->hist_cnt_sent = 0;
+	hist_info->hist_cnt_time = 0;
 	mdss_mdp_hist_intr_req(&mdata->hist_intr, 3 << shift_bit, true);
 	writel_relaxed(req->frame_cnt, ctl_base + 8);
 	/* Kick out reset start */
@@ -2996,18 +3119,18 @@
 	struct mdss_data_type *mdata = mdss_mdp_get_mdata();
 
 	mutex_lock(&hist_info->hist_mutex);
+	spin_lock_irqsave(&hist_info->hist_lock, flag);
 	if (hist_info->col_en == false) {
+		spin_unlock_irqrestore(&hist_info->hist_lock, flag);
 		pr_debug("Histogram already disabled (%d)", (u32) ctl_base);
 		ret = -EINVAL;
 		goto exit;
 	}
-	complete_all(&hist_info->comp);
-	spin_lock_irqsave(&hist_info->hist_lock, flag);
 	hist_info->col_en = false;
 	hist_info->col_state = HIST_UNKNOWN;
 	spin_unlock_irqrestore(&hist_info->hist_lock, flag);
-	hist_info->is_kick_ready = false;
 	mdss_mdp_hist_intr_req(&mdata->hist_intr, done_bit, false);
+	complete_all(&hist_info->comp);
 	writel_relaxed(BIT(1), ctl_base);/* cancel */
 	ret = 0;
 exit:
@@ -3248,15 +3371,15 @@
 	struct mdss_mdp_pipe *pipe;
 
 	mutex_lock(&hist_info->hist_mutex);
+	spin_lock_irqsave(&hist_info->hist_lock, flag);
 	if ((hist_info->col_en == 0) ||
 			(hist_info->col_state == HIST_UNKNOWN)) {
+		spin_unlock_irqrestore(&hist_info->hist_lock, flag);
 		ret = -EINVAL;
 		goto hist_collect_exit;
 	}
-	spin_lock_irqsave(&hist_info->hist_lock, flag);
 	/* wait for hist done if cache has no data */
 	if (hist_info->col_state != HIST_READY) {
-		hist_info->read_request = true;
 		spin_unlock_irqrestore(&hist_info->hist_lock, flag);
 		timeout = HIST_WAIT_TIMEOUT(hist_info->frame_cnt);
 		mutex_unlock(&hist_info->hist_mutex);
@@ -3270,9 +3393,9 @@
 				&(hist_info->comp), timeout);
 
 		mutex_lock(&hist_info->hist_mutex);
+		spin_lock_irqsave(&hist_info->hist_lock, flag);
 		if (wait_ret == 0) {
 			ret = -ETIMEDOUT;
-			spin_lock_irqsave(&hist_info->hist_lock, flag);
 			pr_debug("bin collection timedout, state %d",
 					hist_info->col_state);
 			/*
@@ -3287,37 +3410,36 @@
 			 */
 			hist_info->hist_cnt_time++;
 			hist_info->col_state = HIST_READY;
-			spin_unlock_irqrestore(&hist_info->hist_lock, flag);
 		} else if (wait_ret < 0) {
+			spin_unlock_irqrestore(&hist_info->hist_lock, flag);
 			ret = -EINTR;
 			pr_debug("%s: bin collection interrupted",
 					__func__);
 			goto hist_collect_exit;
 		}
-		if (hist_info->col_state != HIST_READY) {
+		if (hist_info->col_state != HIST_READY &&
+				hist_info->col_state != HIST_UNKNOWN) {
 			ret = -ENODATA;
+			hist_info->col_state = HIST_READY;
 			pr_debug("%s: state is not ready: %d",
 					__func__, hist_info->col_state);
-			goto hist_collect_exit;
 		}
-	} else {
-		spin_unlock_irqrestore(&hist_info->hist_lock, flag);
 	}
-	spin_lock_irqsave(&hist_info->hist_lock, flag);
 	if (hist_info->col_state == HIST_READY) {
+		hist_info->col_state = HIST_IDLE;
 		spin_unlock_irqrestore(&hist_info->hist_lock, flag);
 		v_base = ctl_base + 0x1C;
 		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);
-		spin_lock_irqsave(&hist_info->hist_lock, flag);
-		if (!expect_sum || sum == expect_sum)
-			hist_info->read_request = false;
-		else
+		if (expect_sum && sum != expect_sum) {
+			pr_debug("hist error: bin sum incorrect! (%d/%d)\n",
+				sum, expect_sum);
 			ret = -ENODATA;
-		hist_info->col_state = HIST_IDLE;
+		}
+	} else {
+		spin_unlock_irqrestore(&hist_info->hist_lock, flag);
 	}
-	spin_unlock_irqrestore(&hist_info->hist_lock, flag);
 hist_collect_exit:
 	mutex_unlock(&hist_info->hist_mutex);
 	return ret;
@@ -3325,8 +3447,9 @@
 
 int mdss_mdp_hist_collect(struct mdp_histogram_data *hist)
 {
-	int i, j, off, ret = 0;
+	int i, j, off, ret = 0, temp_ret = 0;
 	struct pp_hist_col_info *hist_info;
+	struct pp_hist_col_info *hists[MDSS_MDP_INTF_MAX_LAYERMIXER];
 	u32 dspp_num, disp_num;
 	char __iomem *ctl_base;
 	u32 hist_cnt, mixer_id[MDSS_MDP_INTF_MAX_LAYERMIXER];
@@ -3337,6 +3460,7 @@
 	u32 exp_sum = 0;
 	struct mdss_mdp_pipe *pipe;
 	struct mdss_data_type *mdata = mdss_mdp_get_mdata();
+	unsigned long flag;
 
 	if ((PP_BLOCK(hist->block) < MDP_LOGICAL_BLOCK_DISP_0) ||
 		(PP_BLOCK(hist->block) >= MDP_BLOCK_MAX))
@@ -3357,20 +3481,44 @@
 		ret = -EPERM;
 		goto hist_collect_exit;
 	}
+
 	if (PP_LOCAT(hist->block) == MDSS_PP_DSPP_CFG) {
-		hist_info = &mdss_pp_res->dspp_hist[disp_num];
 		for (i = 0; i < hist_cnt; i++) {
 			dspp_num = mixer_id[i];
-			hist_info = &mdss_pp_res->dspp_hist[dspp_num];
+			hists[i] = &mdss_pp_res->dspp_hist[dspp_num];
+		}
+		for (i = 0; i < hist_cnt; i++) {
+			spin_lock_irqsave(&hists[i]->hist_lock, flag);
+			/* mark that collect is ready to handle completions */
+			hists[i]->read_request = 1;
+			spin_unlock_irqrestore(&hists[i]->hist_lock, flag);
+		}
+		for (i = 0; i < hist_cnt; i++) {
+			dspp_num = mixer_id[i];
 			ctl_base = mdss_mdp_get_dspp_addr_off(dspp_num) +
 				MDSS_MDP_REG_DSPP_HIST_CTL_BASE;
 			exp_sum = (mdata->mixer_intf[dspp_num].width *
 					mdata->mixer_intf[dspp_num].height);
-			ret = pp_hist_collect(hist, hist_info, ctl_base,
+			if (ret)
+				temp_ret = ret;
+			ret = pp_hist_collect(hist, hists[i], ctl_base,
 								exp_sum);
 			if (ret)
-				goto hist_collect_exit;
+				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 */
+			spin_lock_irqsave(&hists[i]->hist_lock, flag);
+			hists[i]->read_request = 0;
+			INIT_COMPLETION(hists[i]->comp);
+			spin_unlock_irqrestore(&hists[i]->hist_lock, flag);
+		}
+		if (ret || temp_ret) {
+			ret = ret ? ret : temp_ret;
+			goto hist_collect_exit;
+		}
+
 		if (hist->bin_cnt != HIST_V_SIZE) {
 			pr_err("User not expecting size %d output",
 							HIST_V_SIZE);
@@ -3386,19 +3534,19 @@
 			}
 			memset(hist_concat, 0, HIST_V_SIZE * sizeof(u32));
 			for (i = 0; i < hist_cnt; i++) {
-				dspp_num = mixer_id[i];
-				hist_info = &mdss_pp_res->dspp_hist[dspp_num];
-				mutex_lock(&hist_info->hist_mutex);
+				mutex_lock(&hists[i]->hist_mutex);
 				for (j = 0; j < HIST_V_SIZE; j++)
-					hist_concat[j] += hist_info->data[j];
-				mutex_unlock(&hist_info->hist_mutex);
+					hist_concat[j] += hists[i]->data[j];
+				mutex_unlock(&hists[i]->hist_mutex);
 			}
 			hist_data_addr = hist_concat;
 		} else {
-			hist_data_addr = hist_info->data;
+			hist_data_addr = hists[0]->data;
 		}
-		hist_info = &mdss_pp_res->dspp_hist[disp_num];
-		hist_info->hist_cnt_sent++;
+
+		for (i = 0; i < hist_cnt; i++)
+			hists[i]->hist_cnt_sent++;
+
 	} else if (PP_LOCAT(hist->block) == MDSS_PP_SSPP_CFG) {
 
 		hist_cnt = MDSS_PP_ARG_MASK & hist->block;
@@ -3434,14 +3582,54 @@
 				continue;
 			}
 			hist_info = &pipe->pp_res.hist;
+			spin_lock_irqsave(&hist_info->hist_lock, flag);
+			hist_info->read_request = 1;
+			spin_unlock_irqrestore(&hist_info->hist_lock, flag);
+		}
+		for (i = pipe_num; i < MDSS_PP_ARG_NUM; i++) {
+			if (!PP_ARG(i, hist->block))
+				continue;
+			pipe_cnt++;
+			pipe = mdss_mdp_pipe_get(mdata, BIT(i));
+			if (IS_ERR_OR_NULL(pipe) ||
+					pipe->num > MDSS_MDP_SSPP_VIG2) {
+				pr_warn("Invalid Hist pipe (%d)", i);
+				continue;
+			}
+			hist_info = &pipe->pp_res.hist;
 			ctl_base = pipe->base +
 				MDSS_MDP_REG_VIG_HIST_CTL_BASE;
+			if (ret)
+				temp_ret = ret;
 			ret = pp_hist_collect(hist, hist_info, ctl_base,
 								exp_sum);
-			mdss_mdp_pipe_unmap(pipe);
 			if (ret)
-				goto hist_collect_exit;
+				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++) {
+			if (!PP_ARG(i, hist->block))
+				continue;
+			pipe_cnt++;
+			pipe = mdss_mdp_pipe_get(mdata, BIT(i));
+			if (IS_ERR_OR_NULL(pipe) ||
+					pipe->num > MDSS_MDP_SSPP_VIG2) {
+				pr_warn("Invalid Hist pipe (%d)", i);
+				continue;
+			}
+			hist_info = &pipe->pp_res.hist;
+			spin_lock_irqsave(&hist_info->hist_lock, flag);
+			hist_info->read_request = 0;
+			INIT_COMPLETION(hist_info->comp);
+			spin_unlock_irqrestore(&hist_info->hist_lock, flag);
+		}
+		if (ret || temp_ret) {
+			ret = ret ? ret : temp_ret;
+			goto hist_collect_exit;
+		}
+
 		if (pipe_cnt != 0 &&
 			(hist->bin_cnt != (HIST_V_SIZE * pipe_cnt))) {
 			pr_err("User not expecting size %d output",
@@ -3539,8 +3727,10 @@
 			spin_lock(&hist_info->hist_lock);
 			hist_info->col_state = HIST_READY;
 			spin_unlock(&hist_info->hist_lock);
-			if (hist_info->read_request)
+			if (hist_info->read_request == 1) {
 				complete(&hist_info->comp);
+				hist_info->read_request++;
+			}
 		}
 		/* Histogram Reset Done Interrupt */
 		if ((isr_blk & 0x2) &&
@@ -3708,9 +3898,8 @@
 			struct mdss_ad_init_cfg *init_cfg)
 {
 	struct mdss_ad_info *ad;
-	struct mdss_mdp_ctl *ctl;
 	struct msm_fb_data_type *bl_mfd;
-	int lin_ret = -1, inv_ret = -1, ret = 0;
+	int lin_ret = -1, inv_ret = -1, att_ret = -1, ret = 0;
 	u32 ratio_temp, shift = 0, last_ops;
 
 	ret = mdss_mdp_get_ad(mfd, &ad);
@@ -3736,10 +3925,12 @@
 		if (init_cfg->params.init.bl_lin_len == AD_BL_LIN_LEN) {
 			lin_ret = copy_from_user(&ad->bl_lin,
 				init_cfg->params.init.bl_lin,
-				AD_BL_LIN_LEN * sizeof(uint32_t));
+				init_cfg->params.init.bl_lin_len *
+				sizeof(uint32_t));
 			inv_ret = copy_from_user(&ad->bl_lin_inv,
 				init_cfg->params.init.bl_lin_inv,
-				AD_BL_LIN_LEN * sizeof(uint32_t));
+				init_cfg->params.init.bl_lin_len *
+				sizeof(uint32_t));
 			if (lin_ret || inv_ret)
 				ret = -ENOMEM;
 			ratio_temp =  mfd->panel_info->bl_max / AD_BL_LIN_LEN;
@@ -3748,13 +3939,31 @@
 				shift++;
 			}
 			ad->bl_bright_shift = shift;
-		} else if (init_cfg->params.init.bl_lin_len) {
+		} else {
 			ret = -EINVAL;
 		}
-		if (!lin_ret && !inv_ret)
+		if (ret) {
+			ad->state &= ~PP_AD_STATE_BL_LIN;
+			goto ad_config_exit;
+		} else
 			ad->state |= PP_AD_STATE_BL_LIN;
-		else
-			ad->state &= !PP_AD_STATE_BL_LIN;
+
+		if ((init_cfg->params.init.bl_att_len == AD_BL_ATT_LUT_LEN) &&
+			(init_cfg->params.init.bl_att_lut)) {
+			att_ret = copy_from_user(&ad->bl_att_lut,
+				init_cfg->params.init.bl_att_lut,
+				init_cfg->params.init.bl_att_len *
+				sizeof(uint32_t));
+			if (att_ret)
+				ret = -ENOMEM;
+		} else {
+			ret = -EINVAL;
+		}
+		if (ret) {
+			ad->state &= ~PP_AD_STATE_BL_LIN;
+			goto ad_config_exit;
+		} else
+			ad->state |= PP_AD_STATE_BL_LIN;
 
 		ad->sts |= PP_AD_STS_DIRTY_INIT;
 	} else if (init_cfg->ops & MDP_PP_AD_CFG) {
@@ -3796,8 +4005,8 @@
 		ad->mfd = mfd;
 		ad->bl_mfd = bl_mfd;
 	}
+ad_config_exit:
 	mutex_unlock(&ad->lock);
-	ctl = mfd_to_ctl(mfd);
 	return ret;
 }
 
@@ -3869,7 +4078,7 @@
 			mutex_unlock(&ad->lock);
 			mutex_lock(&mfd->bl_lock);
 			MDSS_BRIGHT_TO_BL(bl, bl, mfd->panel_info->bl_max,
-							MDSS_MAX_BL_BRIGHTNESS);
+					mfd->panel_info->brightness_max);
 			mdss_fb_set_backlight(mfd, bl);
 			mutex_unlock(&mfd->bl_lock);
 			mutex_lock(&ad->lock);
@@ -3891,7 +4100,7 @@
 			mutex_unlock(&ad->lock);
 		}
 		if (wait) {
-			ret = wait_for_completion_interruptible_timeout(
+			ret = wait_for_completion_timeout(
 					&ad->comp, HIST_WAIT_TIMEOUT(1));
 			if (ret == 0)
 				ret = -ETIMEDOUT;
@@ -4182,6 +4391,7 @@
 			if (ad->state & PP_AD_STATE_BL_LIN) {
 				bl = ad->bl_lin[bl >> ad->bl_bright_shift];
 				bl = bl << ad->bl_bright_shift;
+				bl = pp_ad_attenuate_bl(bl, ad);
 			}
 			ad->bl_data = bl;
 		}
@@ -4256,6 +4466,8 @@
 								AD_BL_LIN_LEN);
 			memset(&ad->bl_lin_inv, 0, sizeof(uint32_t) *
 								AD_BL_LIN_LEN);
+			memset(&ad->bl_att_lut, 0, sizeof(uint32_t) *
+				AD_BL_ATT_LUT_LEN);
 			memset(&ad->init, 0, sizeof(struct mdss_ad_init));
 			memset(&ad->cfg, 0, sizeof(struct mdss_ad_cfg));
 			mutex_lock(&bl_mfd->bl_lock);
@@ -4317,7 +4529,7 @@
 	ctl = mfd_to_ctl(ad->mfd);
 	mdata = mfd_to_mdata(ad->mfd);
 
-	if (!mdata || ad->calc_hw_num > mdata->nad_cfgs) {
+	if (!mdata || ad->calc_hw_num >= mdata->nad_cfgs) {
 		mutex_unlock(&ad->lock);
 		return;
 	}
@@ -4351,8 +4563,7 @@
 						MDSS_MDP_REG_AD_BL_OUT);
 				if (ad->state & PP_AD_STATE_BL_LIN) {
 					bl = bl >> ad->bl_bright_shift;
-					bl = min_t(u32, bl,
-						MDSS_MAX_BL_BRIGHTNESS);
+					bl = min_t(u32, bl, (AD_BL_LIN_LEN-1));
 					bl = ad->bl_lin_inv[bl];
 					bl = bl << ad->bl_bright_shift;
 				}
@@ -4401,6 +4612,30 @@
 			addr + ((PP_AD_LUT_LEN - 1) * 2));
 }
 
+static u32 pp_ad_attenuate_bl(u32 bl, struct mdss_ad_info *ad)
+{
+	u32 shift = 0, ratio_temp = 0;
+	u32 n, lut_interval, bl_att, out;
+
+	ratio_temp = ad->cfg.backlight_max / (AD_BL_ATT_LUT_LEN - 1);
+	while (ratio_temp > 0) {
+		ratio_temp = ratio_temp >> 1;
+		shift++;
+	}
+	n = bl >> shift;
+	lut_interval = (ad->cfg.backlight_max + 1) / (AD_BL_ATT_LUT_LEN - 1);
+	bl_att = ad->bl_att_lut[n] + (bl - lut_interval * n) *
+			(ad->bl_att_lut[n + 1] - ad->bl_att_lut[n]) /
+			lut_interval;
+	if (ad->init.alpha_base)
+		out = (ad->init.alpha * bl_att +
+			(ad->init.alpha_base - ad->init.alpha) * bl) /
+			ad->init.alpha_base;
+	else
+		out = bl;
+	return out;
+}
+
 int mdss_mdp_ad_addr_setup(struct mdss_data_type *mdata, u32 *ad_offsets)
 {
 	u32 i;
@@ -4463,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;
@@ -4515,6 +4751,14 @@
 		} else if ((ptr == base + MDSS_MDP_REG_DSPP_DITHER_DEPTH)) {
 			ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
 			break;
+		/* Six zone and mem color */
+		} else if (mdss_res->mdp_rev >= MDSS_MDP_HW_REV_103 &&
+			(ptr >= base + MDSS_MDP_REG_DSPP_SIX_ZONE_BASE) &&
+			(ptr <= base + MDSS_MDP_REG_DSPP_SIX_ZONE_BASE +
+					MDSS_MDP_SIX_ZONE_SIZE +
+					MDSS_MDP_MEM_COL_SIZE)) {
+			ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
+			break;
 		}
 	}
 
@@ -4531,7 +4775,10 @@
 		pipe = mdss_res->vig_pipes + counter;
 		base = pipe->base;
 
-		if (ptr == base + MDSS_MDP_REG_SSPP_SRC_FORMAT) {
+		if (ptr == base + MDSS_MDP_REG_VIG_OP_MODE) {
+			ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
+			break;
+		} else if (ptr == base + MDSS_MDP_REG_SSPP_SRC_FORMAT) {
 			ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
 			break;
 		} else if (ptr == base + MDSS_MDP_REG_SSPP_SRC_CONSTANT_COLOR) {
@@ -4540,7 +4787,13 @@
 		} else if (ptr == base + MDSS_MDP_REG_SSPP_SRC_UNPACK_PATTERN) {
 			ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
 			break;
-		} else if ((ptr == base + MDSS_MDP_REG_VIG_QSEED2_SHARP)) {
+		} else if (ptr == base + MDSS_MDP_REG_SSPP_SRC_OP_MODE) {
+			ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
+			break;
+		/* 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 */
@@ -4549,10 +4802,11 @@
 						MDSS_MDP_PA_SIZE)) {
 			ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
 			break;
-		/* IGC range */
-		} else if ((ptr >= base + MDSS_MDP_REG_IGC_VIG_BASE) &&
-				(ptr <= base + MDSS_MDP_REG_IGC_VIG_BASE +
-						MDSS_MDP_GC_SIZE)) {
+		/* Mem color range */
+		} else if (mdss_res->mdp_rev >= MDSS_MDP_HW_REV_103 &&
+			(ptr >= base + MDSS_MDP_REG_VIG_MEM_COL_BASE) &&
+				(ptr <= base + MDSS_MDP_REG_VIG_MEM_COL_BASE +
+						MDSS_MDP_MEM_COL_SIZE)) {
 			ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
 			break;
 		}
@@ -4580,10 +4834,7 @@
 		} else if (ptr == base + MDSS_MDP_REG_SSPP_SRC_UNPACK_PATTERN) {
 			ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
 			break;
-		/* IGC range */
-		} else if ((ptr >= base + MDSS_MDP_REG_IGC_RGB_BASE) &&
-				(ptr <= base + MDSS_MDP_REG_IGC_RGB_BASE +
-						MDSS_MDP_GC_SIZE)) {
+		} else if (ptr == base + MDSS_MDP_REG_SSPP_SRC_OP_MODE) {
 			ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
 			break;
 		}
@@ -4611,10 +4862,7 @@
 		} else if (ptr == base + MDSS_MDP_REG_SSPP_SRC_UNPACK_PATTERN) {
 			ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
 			break;
-		/* IGC range */
-		} else if ((ptr >= base + MDSS_MDP_REG_IGC_DMA_BASE) &&
-				(ptr <= base + MDSS_MDP_REG_IGC_DMA_BASE +
-						MDSS_MDP_GC_SIZE)) {
+		} else if (ptr == base + MDSS_MDP_REG_SSPP_SRC_OP_MODE) {
 			ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
 			break;
 		}
@@ -4630,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;
 
@@ -4681,11 +4930,18 @@
 	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 */
 	} else if (ptr >= (mdss_res->mdp_base + MDSS_MDP_REG_IGC_DSPP_BASE) &&
-		    ptr < (mdss_res->mdp_base + MDSS_MDP_REG_IGC_DSPP_BASE +
-						MDSS_MDP_IGC_DSPP_COLORS)) {
+		    ptr <= (mdss_res->mdp_base + MDSS_MDP_REG_IGC_DSPP_BASE +
+						MDSS_MDP_IGC_DSPP_SIZE)) {
+		ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
+	/* IGC SSPP range */
+	} else if (ptr >= (mdss_res->mdp_base + MDSS_MDP_REG_IGC_VIG_BASE) &&
+		    ptr <= (mdss_res->mdp_base + MDSS_MDP_REG_IGC_VIG_BASE +
+						MDSS_MDP_IGC_SSPP_SIZE)) {
 		ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
 	} else if (ptr >= dspp_base && ptr < (dspp_base +
 		(mdss_res->nmixers_intf * MDSS_MDP_DSPP_ADDRESS_OFFSET))) {
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 e2e41bb..ee892e2
--- a/drivers/video/msm/mdss/mdss_mdp_rotator.c
+++ b/drivers/video/msm/mdss/mdss_mdp_rotator.c
@@ -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
@@ -48,6 +48,8 @@
 			rot->ref_cnt++;
 			rot->session_id = i | MDSS_MDP_ROT_SESSION_MASK;
 			mutex_init(&rot->lock);
+			INIT_LIST_HEAD(&rot->head);
+			INIT_LIST_HEAD(&rot->list);
 			break;
 		}
 	}
@@ -104,8 +106,11 @@
 	if (!pipe) {
 		mdss_mdp_wb_mixer_destroy(mixer);
 		pr_debug("dma pipe allocation failed\n");
+		return NULL;
 	}
 
+	pipe->mixer_stage = MDSS_MDP_STAGE_UNUSED;
+
 	return pipe;
 }
 
@@ -125,7 +130,6 @@
 		if (ctl->shared_lock)
 			mutex_unlock(ctl->shared_lock);
 	}
-	mdss_mdp_smp_release(rot->pipe);
 	mutex_unlock(&rot->lock);
 
 	return 0;
@@ -167,7 +171,6 @@
 		if (rot->pipe) {
 			pr_debug("use new rotator pipe=%d\n", rot->pipe->num);
 
-			rot->pipe->mixer_stage = MDSS_MDP_STAGE_UNUSED;
 			list_add_tail(&rot->head, &rotator_queue);
 		} else if (!list_empty(&rotator_queue)) {
 			tmp = list_first_entry(&rotator_queue,
@@ -197,12 +200,45 @@
 	return 0;
 }
 
+/**
+ * __mdss_mdp_rotator_to_pipe() - setup pipe according to rotator session params
+ * @rot:	Pointer to rotator session
+ * @pipe:	Pointer to pipe driving structure
+ *
+ * After calling this the pipe structure will contain all parameters required
+ * to use rotator pipe. Note that this function assumes rotator pipe is idle.
+ */
+static int __mdss_mdp_rotator_to_pipe(struct mdss_mdp_rotator_session *rot,
+		struct mdss_mdp_pipe *pipe)
+{
+	int ret;
+
+	pipe->flags = rot->flags;
+	pipe->src_fmt = mdss_mdp_get_format_params(rot->format);
+	pipe->img_width = rot->img_width;
+	pipe->img_height = rot->img_height;
+	pipe->src = rot->src_rect;
+	pipe->dst = rot->src_rect;
+	pipe->dst.x = 0;
+	pipe->dst.y = 0;
+	pipe->params_changed++;
+	rot->params_changed = 0;
+
+	ret = mdss_mdp_smp_reserve(pipe);
+	if (ret) {
+		pr_debug("unable to mdss_mdp_smp_reserve rot data\n");
+		return ret;
+	}
+
+	return 0;
+}
+
 static int mdss_mdp_rotator_queue_sub(struct mdss_mdp_rotator_session *rot,
 			   struct mdss_mdp_data *src_data,
 			   struct mdss_mdp_data *dst_data)
 {
 	struct mdss_mdp_pipe *rot_pipe = NULL;
-	struct mdss_mdp_ctl *ctl;
+	struct mdss_mdp_ctl *orig_ctl, *rot_ctl;
 	int ret;
 
 	if (!rot || !rot->ref_cnt)
@@ -218,51 +254,40 @@
 
 	pr_debug("queue rotator pnum=%d\n", rot_pipe->num);
 
-	ctl = rot_pipe->mixer->ctl;
-	if (ctl->shared_lock)
-		mutex_lock(ctl->shared_lock);
+	orig_ctl = rot_pipe->mixer->ctl;
+	if (orig_ctl->shared_lock)
+		mutex_lock(orig_ctl->shared_lock);
 
-	ctl = mdss_mdp_ctl_mixer_switch(ctl,
+	rot_ctl = mdss_mdp_ctl_mixer_switch(orig_ctl,
 			MDSS_MDP_WB_CTL_TYPE_BLOCK);
-	if (!ctl) {
+	if (!rot_ctl) {
 		ret = -EINVAL;
 		goto error;
 	} else {
-		rot->pipe->mixer = ctl->mixer_left;
+		rot->pipe->mixer = rot_ctl->mixer_left;
 	}
 
-	if (rot->params_changed || ctl->mdata->mixer_switched) {
-		rot->params_changed = 0;
-		rot_pipe->flags = rot->flags;
-		rot_pipe->src_fmt = mdss_mdp_get_format_params(rot->format);
-		rot_pipe->img_width = rot->img_width;
-		rot_pipe->img_height = rot->img_height;
-		rot_pipe->src = rot->src_rect;
-		rot_pipe->dst = rot->src_rect;
-		rot_pipe->dst.x = 0;
-		rot_pipe->dst.y = 0;
-		rot_pipe->params_changed++;
+	if (rot->params_changed || rot_ctl->mdata->mixer_switched) {
+		ret = __mdss_mdp_rotator_to_pipe(rot, rot_pipe);
+		if (ret) {
+			pr_err("rotator session=%x to pipe=%d failed %d\n",
+					rot->session_id, rot_pipe->num, ret);
+			goto error;
+		}
 	}
 
-	ret = mdss_mdp_smp_reserve(rot->pipe);
-	if (ret) {
-		pr_err("unable to mdss_mdp_smp_reserve rot data\n");
-		goto error;
-	}
-
-	ret = mdss_mdp_pipe_queue_data(rot->pipe, src_data);
+	ret = mdss_mdp_pipe_queue_data(rot_pipe, src_data);
 	if (ret) {
 		pr_err("unable to queue rot data\n");
-		mdss_mdp_smp_unreserve(rot->pipe);
 		goto error;
 	}
 
-	ret = mdss_mdp_rotator_kickoff(ctl, rot, dst_data);
+	ret = mdss_mdp_rotator_kickoff(rot_ctl, rot, dst_data);
 
 	return ret;
 error:
-	if (ctl->shared_lock)
-		mutex_unlock(ctl->shared_lock);
+	if (orig_ctl->shared_lock)
+		mutex_unlock(orig_ctl->shared_lock);
 	return ret;
 }
 
@@ -367,6 +392,45 @@
 	return ret;
 }
 
+/*
+ * Try to reserve hardware resources for rotator session if possible, if this
+ * is not possible we may still have a chance to reuse existing pipes used by
+ * other sessions at a later point.
+ */
+static int __mdss_mdp_rotator_pipe_reserve(struct mdss_mdp_rotator_session *rot)
+{
+	int ret;
+
+	if (!rot->pipe) {
+		rot->pipe = mdss_mdp_rotator_pipe_alloc();
+		if (rot->pipe) {
+			pr_debug("reserved rotator pipe=%d\n", rot->pipe->num);
+			list_add_tail(&rot->head, &rotator_queue);
+		} else {
+			/*
+			 * if rotator queue is not empty means that we'll be
+			 * able to reuse existing rotator pipes for this rotator
+			 * session, otherwise it means that there are no DMA
+			 * pipes available so we should abort now
+			 */
+			if (list_empty(&rotator_queue)) {
+				pr_err("unable to reserve rot pipe\n");
+				return -ENODEV;
+			}
+
+			pr_debug("unable to get rot pipe but some in queue\n");
+			return 0;
+		}
+	}
+
+	ret = __mdss_mdp_rotator_to_pipe(rot, rot->pipe);
+	if (ret)
+		pr_err("rotator session=%x to pipe=%d failed %d\n",
+				rot->session_id, rot->pipe->num, ret);
+
+	return ret;
+}
+
 int mdss_mdp_rotator_setup(struct msm_fb_data_type *mfd,
 			   struct mdp_overlay *req)
 {
@@ -391,14 +455,14 @@
 
 	if (req->id == MSMFB_NEW_REQUEST) {
 		rot = mdss_mdp_rotator_session_alloc();
-		rot->pid = current->tgid;
-		list_add(&rot->list, &mdp5_data->rot_proc_list);
-
 		if (!rot) {
 			pr_err("unable to allocate rotator session\n");
 			ret = -ENOMEM;
 			goto rot_err;
 		}
+
+		rot->pid = current->tgid;
+		list_add(&rot->list, &mdp5_data->rot_proc_list);
 	} else if (req->id & MDSS_MDP_ROT_SESSION_MASK) {
 		rot = mdss_mdp_rotator_session_get(req->id);
 
@@ -526,15 +590,22 @@
 
 	rot->params_changed++;
 
+	ret = __mdss_mdp_rotator_pipe_reserve(rot);
+	if (!ret && rot->next)
+		ret = __mdss_mdp_rotator_pipe_reserve(rot->next);
+
+	if (ret)
+		goto rot_err;
+
 	req->id = rot->session_id;
 
  rot_err:
-	mutex_unlock(&rotator_lock);
 	if (ret) {
 		pr_err("Unable to setup rotator session\n");
-		if (rot)
-			mdss_mdp_rotator_release(rot);
+		if (rot && (req->id == MSMFB_NEW_REQUEST))
+			mdss_mdp_rotator_finish(rot);
 	}
+	mutex_unlock(&rotator_lock);
 	return ret;
 }
 
@@ -560,6 +631,9 @@
 		list_del(&rot->head);
 	}
 
+	if (!list_empty(&rot->list))
+		list_del(&rot->list);
+
 	rot_sync_pt_data = rot->rot_sync_pt_data;
 	commit_work = rot->commit_work;
 	memset(rot, 0, sizeof(*rot));
@@ -568,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)
@@ -616,6 +690,7 @@
 			    struct msmfb_overlay_data *req)
 {
 	struct mdss_mdp_rotator_session *rot;
+	struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
 	int ret;
 	u32 flgs;
 
@@ -635,6 +710,9 @@
 		goto dst_buf_fail;
 	}
 
+	if (!mfd->panel_info->cont_splash_enabled)
+		mdss_iommu_attach(mdp5_data->mdata);
+
 	mdss_mdp_overlay_free_buf(&rot->src_buf);
 	ret = mdss_mdp_overlay_get_buf(mfd, &rot->src_buf, &req->data, 1, flgs);
 	if (ret) {
@@ -671,8 +749,6 @@
 		mdss_mdp_overlay_free_buf(&rot->dst_buf);
 
 		rot->pid = 0;
-		if (!list_empty(&rot->list))
-			list_del_init(&rot->list);
 		ret = mdss_mdp_rotator_finish(rot);
 	}
 	mutex_unlock(&rotator_lock);
diff --git a/drivers/video/msm/mdss/mdss_mdp_splash_logo.c b/drivers/video/msm/mdss/mdss_mdp_splash_logo.c
new file mode 100644
index 0000000..77f6554
--- /dev/null
+++ b/drivers/video/msm/mdss/mdss_mdp_splash_logo.c
@@ -0,0 +1,623 @@
+/* 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.
+ *
+ */
+
+#define pr_fmt(fmt)	"%s: " fmt, __func__
+
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/kthread.h>
+#include <linux/memblock.h>
+#include <linux/bootmem.h>
+#include <linux/iommu.h>
+#include <linux/fb.h>
+
+#include "mdss_fb.h"
+#include "mdss_mdp.h"
+#include "splash.h"
+#include "mdss_mdp_splash_logo.h"
+
+#define INVALID_PIPE_INDEX 0xFFFF
+#define MAX_FRAME_DONE_COUNT_WAIT 2
+
+static int mdss_mdp_splash_alloc_memory(struct msm_fb_data_type *mfd,
+							uint32_t size)
+{
+	int rc;
+	struct msm_fb_splash_info *sinfo;
+	unsigned long buf_size = size;
+	struct mdss_data_type *mdata;
+
+	if (!mfd || !size)
+		return -EINVAL;
+
+	mdata = mfd_to_mdata(mfd);
+	sinfo = &mfd->splash_info;
+
+	if (!mdata || !mdata->iclient || sinfo->splash_buffer)
+		return -EINVAL;
+
+	sinfo->ion_handle = ion_alloc(mdata->iclient, size, SZ_4K,
+				ION_HEAP(ION_SYSTEM_HEAP_ID), 0);
+	if (IS_ERR_OR_NULL(sinfo->ion_handle)) {
+		pr_err("ion memory allocation failed\n");
+		rc = PTR_RET(sinfo->ion_handle);
+		goto end;
+	}
+
+	rc = ion_map_iommu(mdata->iclient, sinfo->ion_handle,
+			mdss_get_iommu_domain(MDSS_IOMMU_DOMAIN_UNSECURE),
+			0, SZ_4K, 0, (unsigned long *)&sinfo->iova,
+				(unsigned long *)&buf_size, 0, 0);
+	if (rc) {
+		pr_err("ion memory map failed\n");
+		goto imap_err;
+	}
+
+	sinfo->splash_buffer = ion_map_kernel(mdata->iclient,
+						sinfo->ion_handle);
+	if (IS_ERR_OR_NULL(sinfo->splash_buffer)) {
+		pr_err("ion kernel memory mapping failed\n");
+		rc = IS_ERR(sinfo->splash_buffer);
+		goto kmap_err;
+	}
+
+	return rc;
+
+kmap_err:
+	ion_unmap_iommu(mdata->iclient, sinfo->ion_handle,
+			mdss_get_iommu_domain(MDSS_IOMMU_DOMAIN_UNSECURE), 0);
+imap_err:
+	ion_free(mdata->iclient, sinfo->ion_handle);
+end:
+	return rc;
+}
+
+static void mdss_mdp_splash_free_memory(struct msm_fb_data_type *mfd)
+{
+	struct msm_fb_splash_info *sinfo;
+	struct mdss_data_type *mdata;
+
+	if (!mfd)
+		return;
+
+	sinfo = &mfd->splash_info;
+	mdata = mfd_to_mdata(mfd);
+
+	if (!mdata || !mdata->iclient || !sinfo->ion_handle)
+		return;
+
+	ion_unmap_kernel(mdata->iclient, sinfo->ion_handle);
+
+	ion_unmap_iommu(mdata->iclient, sinfo->ion_handle,
+			mdss_get_iommu_domain(MDSS_IOMMU_DOMAIN_UNSECURE), 0);
+
+	ion_free(mdata->iclient, sinfo->ion_handle);
+	sinfo->splash_buffer = NULL;
+}
+
+static int mdss_mdp_splash_iommu_attach(struct msm_fb_data_type *mfd)
+{
+	struct iommu_domain *domain;
+	struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
+	int rc;
+
+	/*
+	 * iommu dynamic attach for following conditions.
+	 * 1. it is still not attached
+	 * 2. MDP hardware version supports the feature
+	 * 3. configuration is with valid splash buffer
+	 */
+	if (is_mdss_iommu_attached() ||
+		!mfd->panel_info->cont_splash_enabled ||
+		!mdss_mdp_iommu_dyn_attach_supported(mdp5_data->mdata) ||
+		!mdp5_data->splash_mem_addr ||
+		!mdp5_data->splash_mem_size) {
+		pr_debug("dynamic attach is not supported\n");
+		return -EPERM;
+	}
+
+	domain = msm_get_iommu_domain(mdss_get_iommu_domain(
+						MDSS_IOMMU_DOMAIN_UNSECURE));
+	if (!domain) {
+		pr_debug("mdss iommu domain get failed\n");
+		return -EINVAL;
+	}
+
+	rc = iommu_map(domain, mdp5_data->splash_mem_addr,
+				mdp5_data->splash_mem_addr,
+				mdp5_data->splash_mem_size, IOMMU_READ);
+	if (rc) {
+		pr_debug("iommu memory mapping failed rc=%d\n", rc);
+	} else {
+		rc = mdss_iommu_attach(mdss_res);
+		if (rc) {
+			pr_debug("mdss iommu attach failed\n");
+			iommu_unmap(domain, mdp5_data->splash_mem_addr,
+						mdp5_data->splash_mem_size);
+		} else {
+			mfd->splash_info.iommu_dynamic_attached = true;
+		}
+	}
+
+	return rc;
+}
+
+static void mdss_mdp_splash_unmap_splash_mem(struct msm_fb_data_type *mfd)
+{
+	struct iommu_domain *domain;
+	struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
+
+	if (mfd->splash_info.iommu_dynamic_attached) {
+		domain = msm_get_iommu_domain(mdss_get_iommu_domain(
+						MDSS_IOMMU_DOMAIN_UNSECURE));
+		if (!domain) {
+			pr_err("mdss iommu domain get failed\n");
+			return;
+		}
+
+		iommu_unmap(domain, mdp5_data->splash_mem_addr,
+						mdp5_data->splash_mem_size);
+		mfd->splash_info.iommu_dynamic_attached = false;
+	}
+}
+
+void mdss_mdp_release_splash_pipe(struct msm_fb_data_type *mfd)
+{
+	struct msm_fb_splash_info *sinfo;
+
+	if (!mfd || !mfd->splash_info.splash_pipe_allocated)
+		return;
+
+	sinfo = &mfd->splash_info;
+
+	if (sinfo->pipe_ndx[0] != INVALID_PIPE_INDEX)
+		mdss_mdp_overlay_release(mfd, sinfo->pipe_ndx[0]);
+	if (sinfo->pipe_ndx[1] != INVALID_PIPE_INDEX)
+		mdss_mdp_overlay_release(mfd, sinfo->pipe_ndx[1]);
+	sinfo->splash_pipe_allocated = false;
+}
+
+int mdss_mdp_splash_cleanup(struct msm_fb_data_type *mfd,
+					bool use_borderfill)
+{
+	struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
+	struct mdss_mdp_ctl *ctl = mdp5_data->ctl;
+	int rc = 0;
+
+	if (!mfd || !mdp5_data)
+		return -EINVAL;
+
+	if (mfd->splash_info.iommu_dynamic_attached ||
+			!mfd->panel_info->cont_splash_enabled)
+		goto end;
+
+	if (use_borderfill && mdp5_data->handoff) {
+		/*
+		 * Set up border-fill on the handed off pipes.
+		 * This is needed to ensure that there are no memory
+		 * accesses prior to attaching iommu during continuous
+		 * splash screen case. However, for command mode
+		 * displays, this is not necessary since the panels can
+		 * refresh from their internal memory if no data is sent
+		 * out on the dsi lanes.
+		 */
+		if (mdp5_data->handoff && ctl && ctl->is_video_mode) {
+			rc = mdss_mdp_display_commit(ctl, NULL);
+			if (!IS_ERR_VALUE(rc)) {
+				mdss_mdp_display_wait4comp(ctl);
+			} else {
+				/*
+				 * Since border-fill setup failed, we
+				 * need to ensure that we turn off the
+				 * MDP timing generator before attaching
+				 * iommu
+				 */
+				pr_err("failed to set BF at handoff\n");
+				mdp5_data->handoff = false;
+			}
+		}
+	}
+
+	if (rc || mdp5_data->handoff) {
+		/* Add all the handed off pipes to the cleanup list */
+		mdss_mdp_handoff_cleanup_pipes(mfd, MDSS_MDP_PIPE_TYPE_RGB);
+		mdss_mdp_handoff_cleanup_pipes(mfd, MDSS_MDP_PIPE_TYPE_VIG);
+		mdss_mdp_handoff_cleanup_pipes(mfd, MDSS_MDP_PIPE_TYPE_DMA);
+	}
+
+	mdss_mdp_ctl_splash_finish(ctl, mdp5_data->handoff);
+
+	if (mdp5_data->splash_mem_addr) {
+		/* Give back the reserved memory to the system */
+		memblock_free(mdp5_data->splash_mem_addr,
+					mdp5_data->splash_mem_size);
+		free_bootmem_late(mdp5_data->splash_mem_addr,
+				 mdp5_data->splash_mem_size);
+	}
+
+	mdss_mdp_footswitch_ctrl_splash(0);
+	if (!is_mdss_iommu_attached()) {
+		rc = mdss_iommu_attach(mdss_res);
+		if (rc)
+			pr_err("iommu attach failed rc=%d\n", rc);
+	}
+
+end:
+	return rc;
+}
+
+static struct mdss_mdp_pipe *mdss_mdp_splash_get_pipe(
+					struct msm_fb_data_type *mfd,
+					struct mdp_overlay *req)
+{
+	struct mdss_mdp_pipe *pipe;
+	int ret;
+	struct mdss_mdp_data *buf;
+	uint32_t image_size = SPLASH_IMAGE_WIDTH * SPLASH_IMAGE_HEIGHT
+						* SPLASH_IMAGE_BPP;
+
+	ret = mdss_mdp_overlay_pipe_setup(mfd, req, &pipe);
+	if (ret)
+		return NULL;
+
+	if (mdss_mdp_pipe_map(pipe)) {
+		pr_err("unable to map base pipe\n");
+		return NULL;
+	}
+
+	buf = &pipe->back_buf;
+	buf->p[0].addr = mfd->splash_info.iova;
+	buf->p[0].len = image_size;
+	buf->num_planes = 1;
+	mdss_mdp_pipe_unmap(pipe);
+
+	return pipe;
+}
+
+static int mdss_mdp_splash_kickoff(struct msm_fb_data_type *mfd,
+				struct mdss_mdp_img_rect *src_rect,
+				struct mdss_mdp_img_rect *dest_rect)
+{
+	struct mdss_mdp_pipe *pipe;
+	struct fb_info *fbi;
+	struct mdp_overlay req;
+	struct mdss_overlay_private *mdp5_data;
+	struct mdss_data_type *mdata;
+	struct mdss_mdp_mixer *mixer;
+	int ret;
+	bool use_single_pipe = false;
+	struct msm_fb_splash_info *sinfo;
+
+	if (!mfd)
+		return -EINVAL;
+
+	fbi = mfd->fbi;
+	mdp5_data = mfd_to_mdp5_data(mfd);
+	mdata = mfd_to_mdata(mfd);
+	sinfo = &mfd->splash_info;
+
+	if (!mdp5_data || !mdp5_data->ctl)
+		return -EINVAL;
+
+	if (mutex_lock_interruptible(&mdp5_data->ov_lock))
+		return -EINVAL;
+
+	ret = mdss_mdp_overlay_start(mfd);
+	if (ret) {
+		pr_err("unable to start overlay %d (%d)\n", mfd->index, ret);
+		goto end;
+	}
+
+	mixer = mdss_mdp_mixer_get(mdp5_data->ctl, MDSS_MDP_MIXER_MUX_LEFT);
+	if (!mixer) {
+		pr_err("unable to retrieve mixer\n");
+		ret = -EINVAL;
+		goto end;
+	}
+
+	memset(&req, 0, sizeof(struct mdp_overlay));
+	/*
+	 * use single pipe for
+	 * 1. split display disabled
+	 * 2. splash image is only on one side of panel
+	 */
+	use_single_pipe =
+		!mfd->split_display ||
+		(mfd->split_display &&
+		((dest_rect->x + dest_rect->w) < mfd->split_fb_left ||
+		dest_rect->x > mfd->split_fb_left));
+
+	req.src.width = src_rect->w;
+	if (use_single_pipe)
+		req.src_rect.w = src_rect->w;
+	else
+		req.src_rect.w = min_t(u16, mixer->width, src_rect->w >> 1);
+	req.dst_rect.w = req.src_rect.w;
+	req.src.height = req.dst_rect.h = req.src_rect.h =
+			src_rect->h;
+	req.src.format = SPLASH_IMAGE_FORMAT;
+	req.id = MSMFB_NEW_REQUEST;
+	req.z_order = MDSS_MDP_STAGE_0;
+	req.alpha = 0xff;
+	req.transp_mask = MDP_TRANSP_NOP;
+	req.dst_rect.x = dest_rect->x;
+	req.dst_rect.y = dest_rect->y;
+
+	pipe = mdss_mdp_splash_get_pipe(mfd, &req);
+	if (!pipe) {
+		pr_err("unable to allocate base pipe\n");
+		ret = -EINVAL;
+		goto end;
+	}
+
+	sinfo->pipe_ndx[0] = pipe->ndx;
+
+	if (!use_single_pipe) {
+		req.id = MSMFB_NEW_REQUEST;
+		req.src_rect.x = src_rect->x + min_t(u16, mixer->width,
+					src_rect->w - req.src_rect.w);
+		req.dst_rect.x = mixer->width;
+		pipe = mdss_mdp_splash_get_pipe(mfd, &req);
+		if (!pipe) {
+			pr_err("unable to allocate right base pipe\n");
+			mdss_mdp_overlay_release(mfd, sinfo->pipe_ndx[0]);
+			ret = -EINVAL;
+			goto end;
+		}
+		sinfo->pipe_ndx[1] = pipe->ndx;
+	}
+	mutex_unlock(&mdp5_data->ov_lock);
+
+	ret = mfd->mdp.kickoff_fnc(mfd, NULL);
+	if (ret) {
+		pr_err("error in displaying image\n");
+		mdss_mdp_overlay_release(mfd, sinfo->pipe_ndx[0] |
+					sinfo->pipe_ndx[1]);
+	}
+
+	return ret;
+end:
+	sinfo->pipe_ndx[0] = INVALID_PIPE_INDEX;
+	sinfo->pipe_ndx[1] = INVALID_PIPE_INDEX;
+	mutex_unlock(&mdp5_data->ov_lock);
+	return ret;
+}
+
+static int mdss_mdp_display_splash_image(struct msm_fb_data_type *mfd)
+{
+	int rc = 0;
+	struct fb_info *fbi;
+	uint32_t image_len = SPLASH_IMAGE_WIDTH * SPLASH_IMAGE_HEIGHT
+						* SPLASH_IMAGE_BPP;
+	struct mdss_mdp_img_rect src_rect, dest_rect;
+	struct msm_fb_splash_info *sinfo;
+
+	if (!mfd || !mfd->fbi) {
+		pr_err("invalid input parameter\n");
+		rc = -EINVAL;
+		goto end;
+	}
+
+	fbi = mfd->fbi;
+	sinfo = &mfd->splash_info;
+
+	if (SPLASH_IMAGE_WIDTH > fbi->var.xres ||
+		  SPLASH_IMAGE_HEIGHT > fbi->var.yres ||
+		  SPLASH_IMAGE_BPP > (fbi->var.bits_per_pixel >> 3)) {
+		pr_err("invalid splash parameter configuration\n");
+		rc = -EINVAL;
+		goto end;
+	}
+
+	sinfo->pipe_ndx[0] = INVALID_PIPE_INDEX;
+	sinfo->pipe_ndx[1] = INVALID_PIPE_INDEX;
+
+	src_rect.x = 0;
+	src_rect.y = 0;
+	dest_rect.w = src_rect.w = SPLASH_IMAGE_WIDTH;
+	dest_rect.h = src_rect.h = SPLASH_IMAGE_HEIGHT;
+	dest_rect.x = (fbi->var.xres >> 1) - (SPLASH_IMAGE_WIDTH >> 1);
+	dest_rect.y = (fbi->var.yres >> 1) - (SPLASH_IMAGE_HEIGHT >> 1);
+
+	rc = mdss_mdp_splash_alloc_memory(mfd, image_len);
+	if (rc) {
+		pr_err("splash buffer allocation failed\n");
+		goto end;
+	}
+
+	memcpy(sinfo->splash_buffer, splash_bgr888_image, image_len);
+
+	rc = mdss_mdp_splash_iommu_attach(mfd);
+	if (rc)
+		pr_debug("iommu dynamic attach failed\n");
+
+	rc = mdss_mdp_splash_kickoff(mfd, &src_rect, &dest_rect);
+	if (rc)
+		pr_err("splash image display failed\n");
+	else
+		sinfo->splash_pipe_allocated = true;
+end:
+	return rc;
+}
+
+static int mdss_mdp_splash_ctl_cb(struct notifier_block *self,
+					unsigned long event, void *data)
+{
+	struct msm_fb_splash_info *sinfo = container_of(self,
+					struct msm_fb_splash_info, notifier);
+	struct msm_fb_data_type *mfd;
+
+	if (!sinfo)
+		goto done;
+
+	mfd = container_of(sinfo, struct msm_fb_data_type, splash_info);
+
+	if (!mfd)
+		goto done;
+
+	if (event != MDP_NOTIFY_FRAME_DONE)
+		goto done;
+
+	if (!sinfo->frame_done_count) {
+		mdss_mdp_splash_unmap_splash_mem(mfd);
+		mdss_mdp_splash_cleanup(mfd, false);
+	/* wait for 2 frame done events before releasing memory */
+	} else if (sinfo->frame_done_count > MAX_FRAME_DONE_COUNT_WAIT &&
+			sinfo->splash_thread) {
+		complete(&sinfo->frame_done);
+		sinfo->splash_thread = NULL;
+	}
+
+	/* increase frame done count after pipes are staged from other client */
+	if (!sinfo->splash_pipe_allocated)
+		sinfo->frame_done_count++;
+done:
+	return NOTIFY_OK;
+}
+
+static int mdss_mdp_splash_thread(void *data)
+{
+	struct msm_fb_data_type *mfd = data;
+	struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
+	int ret = -EINVAL;
+
+	if (!mfd) {
+		pr_err("invalid input parameter\n");
+		goto end;
+	}
+
+	lock_fb_info(mfd->fbi);
+	ret = fb_blank(mfd->fbi, FB_BLANK_UNBLANK);
+	if (ret) {
+		pr_err("can't turn on fb!\n");
+		goto end;
+	}
+	unlock_fb_info(mfd->fbi);
+
+	mfd->bl_updated = true;
+	mutex_lock(&mfd->bl_lock);
+	mdss_fb_set_backlight(mfd, mfd->panel_info->bl_max >> 1);
+	mutex_unlock(&mfd->bl_lock);
+
+	init_completion(&mfd->splash_info.frame_done);
+
+	mfd->splash_info.notifier.notifier_call = mdss_mdp_splash_ctl_cb;
+	mdss_mdp_ctl_notifier_register(mdp5_data->ctl,
+				&mfd->splash_info.notifier);
+
+	ret = mdss_mdp_display_splash_image(mfd);
+	if (ret) {
+		/*
+		 * keep thread alive to release dynamically allocated
+		 * resources
+		 */
+		pr_err("splash image display failed\n");
+	}
+
+	/* wait for second display complete to release splash resources */
+	ret = wait_for_completion_killable(&mfd->splash_info.frame_done);
+
+	mdss_mdp_splash_free_memory(mfd);
+
+	mdss_mdp_ctl_notifier_unregister(mdp5_data->ctl,
+				&mfd->splash_info.notifier);
+end:
+	return ret;
+}
+
+static __ref int mdss_mdp_splash_parse_dt(struct msm_fb_data_type *mfd)
+{
+	struct platform_device *pdev = mfd->pdev;
+	struct mdss_overlay_private *mdp5_mdata = mfd_to_mdp5_data(mfd);
+	int len = 0, rc = 0;
+	u32 offsets[2];
+
+	mfd->splash_info.splash_logo_enabled =
+				of_property_read_bool(pdev->dev.of_node,
+				"qcom,mdss-fb-splash-logo-enabled");
+
+	of_find_property(pdev->dev.of_node, "qcom,memblock-reserve", &len);
+	if (len < 1) {
+		pr_debug("mem reservation for splash screen fb not present\n");
+		rc = -EINVAL;
+		goto error;
+	}
+
+	len = len / sizeof(u32);
+
+	rc = of_property_read_u32_array(pdev->dev.of_node,
+			"qcom,memblock-reserve", offsets, len);
+	if (rc) {
+		pr_debug("error reading mem reserve settings for fb\n");
+		goto error;
+	}
+
+	if (!memblock_is_reserved(offsets[0])) {
+		pr_debug("failed to reserve memory for fb splash\n");
+		rc = -EINVAL;
+		goto error;
+	}
+
+	mdp5_mdata->splash_mem_addr = offsets[0];
+	mdp5_mdata->splash_mem_size = offsets[1];
+	pr_debug("memaddr=%x size=%x\n", mdp5_mdata->splash_mem_addr,
+		mdp5_mdata->splash_mem_size);
+
+error:
+	if (!rc && !mfd->panel_info->cont_splash_enabled &&
+		mdp5_mdata->splash_mem_addr) {
+		pr_debug("mem reservation not reqd if cont splash disabled\n");
+		memblock_free(mdp5_mdata->splash_mem_addr,
+					mdp5_mdata->splash_mem_size);
+		free_bootmem_late(mdp5_mdata->splash_mem_addr,
+				 mdp5_mdata->splash_mem_size);
+	} else if (rc && mfd->panel_info->cont_splash_enabled) {
+		pr_err("no rsvd mem found in DT for splash screen\n");
+	} else {
+		rc = 0;
+	}
+
+	return rc;
+}
+
+int mdss_mdp_splash_init(struct msm_fb_data_type *mfd)
+{
+	int rc;
+
+	if (!mfd) {
+		rc = -EINVAL;
+		goto end;
+	}
+
+	rc = mdss_mdp_splash_parse_dt(mfd);
+	if (rc) {
+		pr_err("splash memory reserve failed\n");
+		goto end;
+	}
+
+	if (!mfd->splash_info.splash_logo_enabled) {
+		rc = -EINVAL;
+		goto end;
+	}
+
+	mfd->splash_info.splash_thread = kthread_run(mdss_mdp_splash_thread,
+							mfd, "mdss_fb_splash");
+
+	if (IS_ERR(mfd->splash_info.splash_thread)) {
+		pr_err("unable to start splash thread %d\n", mfd->index);
+		mfd->splash_info.splash_thread = NULL;
+	}
+
+end:
+	return rc;
+}
diff --git a/drivers/video/msm/mdss/mdss_mdp_splash_logo.h b/drivers/video/msm/mdss/mdss_mdp_splash_logo.h
new file mode 100644
index 0000000..0a4e83b
--- /dev/null
+++ b/drivers/video/msm/mdss/mdss_mdp_splash_logo.h
@@ -0,0 +1,43 @@
+/* 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.
+ *
+ */
+#ifndef MDSS_MDP_SPLASH_LOGO
+#define MDSS_MDP_SPLASH_LOGO
+
+#include <linux/types.h>
+#include <linux/notifier.h>
+#include <linux/kthread.h>
+#include <linux/completion.h>
+
+struct msm_fb_splash_info {
+	struct task_struct	*splash_thread;
+	bool			splash_logo_enabled;
+	bool			iommu_dynamic_attached;
+	struct notifier_block	notifier;
+	uint32_t		frame_done_count;
+	struct completion	frame_done;
+
+	struct ion_handle	*ion_handle;
+	dma_addr_t		iova;
+	void			*splash_buffer;
+	int			pipe_ndx[2];
+	bool			splash_pipe_allocated;
+};
+
+struct msm_fb_data_type;
+
+void mdss_mdp_release_splash_pipe(struct msm_fb_data_type *mfd);
+int mdss_mdp_splash_cleanup(struct msm_fb_data_type *mfd,
+				 bool use_borderfill);
+int mdss_mdp_splash_init(struct msm_fb_data_type *mfd);
+
+#endif
diff --git a/drivers/video/msm/mdss/mdss_mdp_util.c b/drivers/video/msm/mdss/mdss_mdp_util.c
index c3e1916..69506d4 100644
--- a/drivers/video/msm/mdss/mdss_mdp_util.c
+++ b/drivers/video/msm/mdss/mdss_mdp_util.c
@@ -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
@@ -257,6 +257,27 @@
 	else
 		*res_rect = (struct mdss_mdp_img_rect){l, t, (r-l), (b-t)};
 }
+
+void mdss_mdp_crop_rect(struct mdss_mdp_img_rect *src_rect,
+	struct mdss_mdp_img_rect *dst_rect,
+	const struct mdss_mdp_img_rect *sci_rect)
+{
+	struct mdss_mdp_img_rect res;
+	mdss_mdp_intersect_rect(&res, dst_rect, sci_rect);
+
+	if (res.w && res.h) {
+		if ((res.w != dst_rect->w) || (res.h != dst_rect->h)) {
+			src_rect->x = src_rect->x + (res.x - dst_rect->x);
+			src_rect->y = src_rect->y + (res.y - dst_rect->y);
+			src_rect->w = res.w;
+			src_rect->h = res.h;
+		}
+		*dst_rect = (struct mdss_mdp_img_rect)
+			{(res.x - sci_rect->x), (res.y - sci_rect->y),
+			res.w, res.h};
+	}
+}
+
 int mdss_mdp_get_rau_strides(u32 w, u32 h,
 			       struct mdss_mdp_format_params *fmt,
 			       struct mdss_mdp_plane_sizes *ps)
@@ -592,9 +613,9 @@
 
 int mdss_mdp_calc_phase_step(u32 src, u32 dst, u32 *out_phase)
 {
-	u32 unit, residue;
+	u32 unit, residue, result;
 
-	if (dst == 0)
+	if (src == 0 || dst == 0)
 		return -EINVAL;
 
 	unit = 1 << PHASE_STEP_SHIFT;
@@ -602,8 +623,13 @@
 
 	/* check if overflow is possible */
 	if (src > dst) {
-		residue = *out_phase & (unit - 1);
-		if (residue && ((residue * dst) < (unit - residue)))
+		residue = *out_phase - unit;
+		result = (residue * dst) + residue;
+
+		while (result > (unit + (unit >> 1)))
+			result -= unit;
+
+		if ((result > residue) && (result < unit))
 			return -EOVERFLOW;
 	}
 
diff --git a/drivers/video/msm/mdss/mdss_mdp_wb.c b/drivers/video/msm/mdss/mdss_mdp_wb.c
index 5789341..aa17472 100644
--- a/drivers/video/msm/mdss/mdss_mdp_wb.c
+++ b/drivers/video/msm/mdss/mdss_mdp_wb.c
@@ -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
@@ -51,7 +51,8 @@
 	REGISTERED,
 	IN_FREE_QUEUE,
 	IN_BUSY_QUEUE,
-	WITH_CLIENT
+	WITH_CLIENT,
+	WB_BUFFER_READY,
 };
 
 struct mdss_mdp_wb_data {
@@ -60,11 +61,14 @@
 	struct msmfb_data buf_info;
 	struct mdss_mdp_data buf_data;
 	int state;
+	bool user_alloc;
 };
 
 static DEFINE_MUTEX(mdss_mdp_wb_buf_lock);
 static struct mdss_mdp_wb mdss_mdp_wb_info;
 
+static void mdss_mdp_wb_free_node(struct mdss_mdp_wb_data *node);
+
 #ifdef DEBUG_WRITEBACK
 /* for debugging: writeback output buffer to allocated memory */
 static inline
@@ -284,6 +288,7 @@
 		struct mdss_mdp_wb_data *node, *temp;
 		list_for_each_entry_safe(node, temp, &wb->register_queue,
 					 registered_entry) {
+			mdss_mdp_wb_free_node(node);
 			list_del(&node->registered_entry);
 			kfree(node);
 		}
@@ -400,12 +405,24 @@
 	struct mdss_mdp_img_data *buf;
 	int ret;
 
+	if (!list_empty(&wb->register_queue)) {
+		list_for_each_entry(node, &wb->register_queue, registered_entry)
+			if ((node->buf_info.memory_id == data->memory_id) &&
+				    (node->buf_info.offset == data->offset)) {
+				pr_debug("found node fd=%x off=%x addr=%x\n",
+						data->memory_id, data->offset,
+						node->buf_data.p[0].addr);
+				return node;
+			}
+	}
+
 	node = kzalloc(sizeof(struct mdss_mdp_wb_data), GFP_KERNEL);
 	if (node == NULL) {
 		pr_err("out of memory\n");
 		return NULL;
 	}
 
+	node->user_alloc = true;
 	node->buf_data.num_planes = 1;
 	buf = &node->buf_data.p[0];
 	if (wb->is_secure)
@@ -433,11 +450,28 @@
 	return NULL;
 }
 
+static void mdss_mdp_wb_free_node(struct mdss_mdp_wb_data *node)
+{
+	struct mdss_mdp_img_data *buf;
+
+	if (node->user_alloc) {
+		buf = &node->buf_data.p[0];
+		pr_debug("free user node mem_id=%d offset=%u addr=0x%x\n",
+				node->buf_info.memory_id,
+				node->buf_info.offset,
+				buf->addr);
+
+		mdss_mdp_put_img(&node->buf_data.p[0]);
+		node->user_alloc = false;
+	}
+}
+
 static int mdss_mdp_wb_queue(struct msm_fb_data_type *mfd,
 				struct msmfb_data *data, int local)
 {
 	struct mdss_mdp_wb *wb = mfd_to_wb(mfd);
 	struct mdss_mdp_wb_data *node = NULL;
+	struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
 	int ret = 0;
 
 	if (!wb) {
@@ -447,19 +481,46 @@
 
 	pr_debug("fb%d queue\n", wb->fb_ndx);
 
+	if (!mfd->panel_info->cont_splash_enabled)
+		mdss_iommu_attach(mdp5_data->mdata);
+
 	mutex_lock(&wb->lock);
 	if (local)
 		node = get_local_node(wb, data);
 	if (node == NULL)
 		node = get_user_node(mfd, data);
 
-	if (!node || node->state == IN_BUSY_QUEUE ||
-	    node->state == IN_FREE_QUEUE) {
-		pr_err("memory not registered or Buffer already with us\n");
-		ret = -EINVAL;
+	if (!node) {
+		pr_err("memory not registered\n");
+		ret = -ENOENT;
 	} else {
-		list_add_tail(&node->active_entry, &wb->free_queue);
-		node->state = IN_FREE_QUEUE;
+		struct mdss_mdp_img_data *buf = &node->buf_data.p[0];
+
+		switch (node->state) {
+		case IN_FREE_QUEUE:
+			pr_err("node 0x%pa was already queueued before\n",
+					&buf->addr);
+			ret = -EINVAL;
+			break;
+		case IN_BUSY_QUEUE:
+			pr_err("node 0x%pa still in busy state\n", &buf->addr);
+			ret = -EBUSY;
+			break;
+		case WB_BUFFER_READY:
+			pr_debug("node 0x%pa re-queueded without dequeue\n",
+				&buf->addr);
+			list_del(&node->active_entry);
+		case WITH_CLIENT:
+		case REGISTERED:
+			list_add_tail(&node->active_entry, &wb->free_queue);
+			node->state = IN_FREE_QUEUE;
+			break;
+		default:
+			pr_err("Invalid node 0x%pa state %d\n",
+				&buf->addr, node->state);
+			ret = -EINVAL;
+			break;
+		}
 	}
 	mutex_unlock(&wb->lock);
 
@@ -529,6 +590,8 @@
 	if (!ctl->power_on)
 		return 0;
 
+	memset(&wb_args, 0, sizeof(wb_args));
+
 	mutex_lock(&mdss_mdp_wb_buf_lock);
 	if (wb) {
 		mutex_lock(&wb->lock);
@@ -569,6 +632,7 @@
 	if (wb && node) {
 		mutex_lock(&wb->lock);
 		list_add_tail(&node->active_entry, &wb->busy_queue);
+		node->state = WB_BUFFER_READY;
 		mutex_unlock(&wb->lock);
 		wake_up(&wb->wait_q);
 	}
@@ -607,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);
@@ -830,3 +847,22 @@
 	return mdss_mdp_wb_set_secure(mfd, enable);
 }
 EXPORT_SYMBOL(msm_fb_writeback_set_secure);
+
+/**
+ * msm_fb_writeback_iommu_ref() - Power ON/OFF mdp clock
+ * @enable - true/false to Power ON/OFF mdp clock
+ *
+ * Call to enable mdp clock at start of mdp_mmap/mdp_munmap API and
+ * to disable mdp clock at end of these API's to ensure iommu is in
+ * proper state while driver map/un-map any buffers.
+ */
+int msm_fb_writeback_iommu_ref(struct fb_info *info, int enable)
+{
+	if (enable)
+		mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+	else
+		mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+
+	return 0;
+}
+EXPORT_SYMBOL(msm_fb_writeback_iommu_ref);
diff --git a/drivers/video/msm/mdss/mdss_panel.h b/drivers/video/msm/mdss/mdss_panel.h
index 65275db..c5ac72e 100644
--- a/drivers/video/msm/mdss/mdss_panel.h
+++ b/drivers/video/msm/mdss/mdss_panel.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2008-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
@@ -127,6 +127,11 @@
 				 - 1 clock enable
  * @MDSS_EVENT_ENABLE_PARTIAL_UPDATE: Event to update ROI of the panel.
  * @MDSS_EVENT_DSI_CMDLIST_KOFF: acquire dsi_mdp_busy lock before kickoff.
+ * @MDSS_EVENT_DSI_ULPS_CTRL:	Event to configure Ultra Lower Power Saving
+ *				mode for the DSI data and clock lanes. The
+ *				event arguments can have one of these values:
+ *				- 0: Disable ULPS mode
+ *				- 1: Enable ULPS mode
  */
 enum mdss_intf_events {
 	MDSS_EVENT_RESET = 1,
@@ -145,6 +150,7 @@
 	MDSS_EVENT_PANEL_CLK_CTRL,
 	MDSS_EVENT_DSI_CMDLIST_KOFF,
 	MDSS_EVENT_ENABLE_PARTIAL_UPDATE,
+	MDSS_EVENT_DSI_ULPS_CTRL,
 };
 
 struct lcd_panel_info {
@@ -227,9 +233,14 @@
 	u32  init_delay;
 };
 
+struct edp_panel_info {
+	char frame_rate;	/* fps */
+};
+
 enum dynamic_fps_update {
 	DFPS_SUSPEND_RESUME_MODE,
 	DFPS_IMMEDIATE_CLK_UPDATE_MODE,
+	DFPS_IMMEDIATE_PORCH_UPDATE_MODE,
 };
 
 enum lvds_mode {
@@ -263,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;
@@ -272,6 +294,7 @@
 	u32 type;
 	u32 wait_cycle;
 	u32 pdest;
+	u32 brightness_max;
 	u32 bl_max;
 	u32 bl_min;
 	u32 fb_num;
@@ -294,6 +317,7 @@
 	int pwm_period;
 	u32 mode_gpio_state;
 	bool dynamic_fps;
+	bool ulps_feature_enabled;
 	char dfps_update;
 	int new_fps;
 
@@ -303,11 +327,13 @@
 	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;
 	struct mipi_panel_info mipi;
 	struct lvds_panel_info lvds;
+	struct edp_panel_info edp;
 };
 
 struct mdss_panel_data {
@@ -348,6 +374,9 @@
 	case MIPI_CMD_PANEL:
 		frame_rate = panel_info->mipi.frame_rate;
 		break;
+	case EDP_PANEL:
+		frame_rate = panel_info->edp.frame_rate;
+		break;
 	case WRITEBACK_PANEL:
 		frame_rate = DEFAULT_FRAME_RATE;
 		break;
diff --git a/drivers/video/msm/mdss/mdss_qpic.c b/drivers/video/msm/mdss/mdss_qpic.c
index fa6bd3d..54b837a 100644
--- a/drivers/video/msm/mdss/mdss_qpic.c
+++ b/drivers/video/msm/mdss/mdss_qpic.c
@@ -368,7 +368,7 @@
 		phys_addr += block_len;
 		len -= block_len;
 	}
-	ret = wait_for_completion_interruptible_timeout(
+	ret = wait_for_completion_timeout(
 		&qpic_res->qpic_endpt.completion,
 		msecs_to_jiffies(100 * 4));
 	if (ret <= 0)
diff --git a/drivers/video/msm/mdss/mhl_sii8334.c b/drivers/video/msm/mdss/mhl_sii8334.c
index ab01566..c5d5366 100644
--- a/drivers/video/msm/mdss/mhl_sii8334.c
+++ b/drivers/video/msm/mdss/mhl_sii8334.c
@@ -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
@@ -193,6 +193,8 @@
 			enum mhl_st_type to_mode, bool hpd_off);
 static void mhl_init_reg_settings(struct mhl_tx_ctrl *mhl_ctrl,
 				  bool mhl_disc_en);
+static int mhl_gpio_config(struct mhl_tx_ctrl *mhl_ctrl, int on);
+static int mhl_vreg_config(struct mhl_tx_ctrl *mhl_ctrl, uint8_t on);
 
 int mhl_i2c_reg_read(struct i2c_client *client,
 			    uint8_t slave_addr_index, uint8_t reg_offset)
@@ -359,12 +361,18 @@
 	int timeout;
 
 	pr_debug("%s:%u\n", __func__, __LINE__);
+
+	if (mhl_ctrl->mhl_mode) {
+		pr_debug("%s: already in mhl mode\n", __func__);
+		return 0;
+	}
+
 	INIT_COMPLETION(mhl_ctrl->rgnd_done);
 	/*
 	 * after toggling reset line and enabling disc
 	 * tx can take a while to generate intr
 	 */
-	timeout = wait_for_completion_interruptible_timeout
+	timeout = wait_for_completion_timeout
 		(&mhl_ctrl->rgnd_done, HZ * 3);
 	if (!timeout) {
 		/*
@@ -374,7 +382,64 @@
 		pr_warn("%s:%u timedout\n", __func__, __LINE__);
 		return -ENODEV;
 	}
-	return mhl_ctrl->mhl_mode ? 0 : 1;
+
+	return 0;
+}
+
+static int mhl_sii_config(struct mhl_tx_ctrl *mhl_ctrl, bool on)
+{
+	int rc = 0;
+	struct i2c_client *client = NULL;
+
+	if (!mhl_ctrl) {
+		pr_err("%s: ctrl is NULL\n", __func__);
+		return -EINVAL;
+	}
+
+	client = mhl_ctrl->i2c_handle;
+
+	if (on) {
+		rc = mhl_vreg_config(mhl_ctrl, 1);
+		if (rc) {
+			pr_err("%s: vreg init failed [%d]\n",
+				__func__, rc);
+			return -ENODEV;
+		}
+
+		rc = mhl_gpio_config(mhl_ctrl, 1);
+		if (rc) {
+			pr_err("%s: gpio init failed [%d]\n",
+				__func__, rc);
+			return -ENODEV;
+		}
+
+		rc = request_threaded_irq(mhl_ctrl->i2c_handle->irq, NULL,
+			&mhl_tx_isr, IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+			client->dev.driver->name, mhl_ctrl);
+		if (rc) {
+			pr_err("%s: request_threaded_irq failed, status: %d\n",
+			       __func__, rc);
+			return -ENODEV;
+		} else {
+			mhl_ctrl->irq_req_done = true;
+		}
+	} else {
+		free_irq(mhl_ctrl->i2c_handle->irq, mhl_ctrl);
+		mhl_gpio_config(mhl_ctrl, 0);
+		mhl_vreg_config(mhl_ctrl, 0);
+		mhl_ctrl->irq_req_done = false;
+	}
+
+	return rc;
+}
+
+static void mhl_sii_disc_intr_work(struct work_struct *work)
+{
+	struct mhl_tx_ctrl *mhl_ctrl = NULL;
+
+	mhl_ctrl = container_of(work, struct mhl_tx_ctrl, mhl_intr_work);
+
+	mhl_sii_config(mhl_ctrl, false);
 }
 
 /*  USB_HANDSHAKING FUNCTIONS */
@@ -383,29 +448,8 @@
 {
 	int rc;
 	struct mhl_tx_ctrl *mhl_ctrl = data;
-	struct i2c_client *client = mhl_ctrl->i2c_handle;
 	unsigned long flags;
 
-	if (!mhl_ctrl->irq_req_done) {
-		rc = request_threaded_irq(mhl_ctrl->i2c_handle->irq, NULL,
-					  &mhl_tx_isr,
-					  IRQF_TRIGGER_LOW | IRQF_ONESHOT,
-					  client->dev.driver->name, mhl_ctrl);
-		if (rc) {
-			pr_err("request_threaded_irq failed, status: %d\n",
-			       rc);
-			return -EINVAL;
-		} else {
-			pr_debug("request_threaded_irq succeeded\n");
-			mhl_ctrl->irq_req_done = true;
-		}
-	} else {
-		enable_irq(client->irq);
-	}
-
-	/* wait for i2c interrupt line to be activated */
-	msleep(100);
-
 	if (id) {
 		/* When MHL cable is disconnected we get a sii8334
 		 * mhl_disconnect interrupt which is handled separately.
@@ -425,6 +469,19 @@
 		mhl_ctrl->notify_ctx = ctx;
 	}
 
+	flush_work(&mhl_ctrl->mhl_intr_work);
+
+	if (!mhl_ctrl->irq_req_done) {
+		rc = mhl_sii_config(mhl_ctrl, true);
+		if (rc) {
+			pr_err("%s: Failed to config vreg/gpio\n", __func__);
+			return rc;
+		}
+
+		/* wait for i2c interrupt line to be activated */
+		msleep(100);
+	}
+
 	if (!mhl_ctrl->disc_enabled) {
 		spin_lock_irqsave(&mhl_ctrl->lock, flags);
 		mhl_ctrl->tx_powered_off = false;
@@ -439,16 +496,24 @@
 		mhl_init_reg_settings(mhl_ctrl, true);
 		/* allow tx to enable dev disc after D3 state */
 		msleep(100);
-		rc = mhl_sii_wait_for_rgnd(mhl_ctrl);
+		if (mhl_sii_wait_for_rgnd(mhl_ctrl)) {
+			pr_err("%s: discovery timeout\n", __func__);
+
+			mhl_sii_config(mhl_ctrl, false);
+
+			return -EAGAIN;
+		}
 	} else {
 		if (mhl_ctrl->cur_state == POWER_STATE_D3) {
-			rc = mhl_sii_wait_for_rgnd(mhl_ctrl);
+			mhl_sii_wait_for_rgnd(mhl_ctrl);
 		} else {
 			/* in MHL mode */
 			pr_debug("%s:%u\n", __func__, __LINE__);
-			rc = 0;
 		}
 	}
+
+	rc = mhl_ctrl->mhl_mode ? 0 : 1;
+
 	pr_debug("%s: ret result: %s\n", __func__, rc ? "usb" : " mhl");
 	return rc;
 }
@@ -796,6 +861,7 @@
 				 rc ? "failed" : "passed");
 		}
 		mhl_ctrl->cur_state = POWER_STATE_D3;
+		mhl_ctrl->mhl_mode = 0;
 		break;
 	default:
 		break;
@@ -1030,13 +1096,8 @@
 		mhl_msm_connection(mhl_ctrl);
 	} else if (status & BIT3) {
 		pr_debug("%s: uUSB-a type dev detct\n", __func__);
-
-		/* Short RGND */
-		MHL_SII_REG_NAME_MOD(REG_DISC_STAT2, BIT0 | BIT1, 0x00);
-		mhl_msm_disconnection(mhl_ctrl);
 		power_supply_changed(&mhl_ctrl->mhl_psy);
-		if (mhl_ctrl->notify_usb_online)
-			mhl_ctrl->notify_usb_online(mhl_ctrl->notify_ctx, 0);
+		mhl_drive_hpd(mhl_ctrl, HPD_DOWN);
 		return 0;
 	}
 
@@ -1052,6 +1113,9 @@
 		power_supply_changed(&mhl_ctrl->mhl_psy);
 		if (mhl_ctrl->notify_usb_online)
 			mhl_ctrl->notify_usb_online(mhl_ctrl->notify_ctx, 0);
+
+		queue_work(mhl_ctrl->mhl_workq, &mhl_ctrl->mhl_intr_work);
+
 		return 0;
 	}
 
@@ -1274,7 +1338,7 @@
 
 	INIT_COMPLETION(mhl_ctrl->msc_cmd_done);
 	MHL_SII_REG_NAME_WR(REG_CBUS_PRI_START, start_bit);
-	timeout = wait_for_completion_interruptible_timeout
+	timeout = wait_for_completion_timeout
 		(&mhl_ctrl->msc_cmd_done, msecs_to_jiffies(T_ABORT_NEXT));
 	if (!timeout) {
 		pr_err("%s: cbus_command_send timed out!\n", __func__);
@@ -1466,6 +1530,27 @@
 	int rc = -EINVAL;
 
 	pr_debug("%s\n", __func__);
+
+	if (!enable) {
+		regulator_disable(reg_8941_vdda);
+		regulator_put(reg_8941_vdda);
+		reg_8941_vdda = NULL;
+
+		regulator_disable(reg_8941_smps3a);
+		regulator_put(reg_8941_smps3a);
+		reg_8941_smps3a = NULL;
+
+		regulator_disable(reg_8941_l02);
+		regulator_put(reg_8941_l02);
+		reg_8941_l02 = NULL;
+
+		regulator_disable(reg_8941_l24);
+		regulator_put(reg_8941_l24);
+		reg_8941_l24 = NULL;
+
+		return 0;
+	}
+
 	if (!reg_8941_l24) {
 		reg_8941_l24 = regulator_get(&client->dev,
 			"avcc_18");
@@ -1707,26 +1792,6 @@
 	}
 
 	/*
-	 * Regulator init
-	 */
-	rc = mhl_vreg_config(mhl_ctrl, 1);
-	if (rc) {
-		pr_err("%s: vreg init failed [%d]\n",
-			__func__, rc);
-		goto failed_probe;
-	}
-
-	/*
-	 * GPIO init
-	 */
-	rc = mhl_gpio_config(mhl_ctrl, 1);
-	if (rc) {
-		pr_err("%s: gpio init failed [%d]\n",
-			__func__, rc);
-		goto failed_probe;
-	}
-
-	/*
 	 * Other initializations
 	 * such tx specific
 	 */
@@ -1738,6 +1803,9 @@
 	spin_lock_init(&mhl_ctrl->lock);
 	mhl_ctrl->msc_send_workqueue = create_singlethread_workqueue
 		("mhl_msc_cmd_queue");
+	mhl_ctrl->mhl_workq = create_singlethread_workqueue("mhl_workq");
+
+	INIT_WORK(&mhl_ctrl->mhl_intr_work, mhl_sii_disc_intr_work);
 
 	mhl_ctrl->input = input_allocate_device();
 	if (mhl_ctrl->input) {
@@ -1865,9 +1933,7 @@
 failed_probe_pwr:
 	power_supply_unregister(&mhl_ctrl->mhl_psy);
 failed_probe:
-	free_irq(mhl_ctrl->i2c_handle->irq, mhl_ctrl);
-	mhl_gpio_config(mhl_ctrl, 0);
-	mhl_vreg_config(mhl_ctrl, 0);
+	mhl_sii_config(mhl_ctrl, false);
 	/* do not deep-free */
 	if (mhl_info)
 		devm_kfree(&client->dev, mhl_info);
@@ -1894,9 +1960,10 @@
 		return -EINVAL;
 	}
 
-	free_irq(mhl_ctrl->i2c_handle->irq, mhl_ctrl);
-	mhl_gpio_config(mhl_ctrl, 0);
-	mhl_vreg_config(mhl_ctrl, 0);
+	mhl_sii_config(mhl_ctrl, false);
+
+	destroy_workqueue(mhl_ctrl->mhl_workq);
+
 	if (mhl_ctrl->mhl_info)
 		devm_kfree(&client->dev, mhl_ctrl->mhl_info);
 	if (mhl_ctrl->pdata)
@@ -1918,19 +1985,30 @@
 {
 	struct mhl_tx_ctrl *mhl_ctrl = i2c_get_clientdata(client);
 
-	if (mhl_ctrl->irq_req_done) {
-		enable_irq_wake(client->irq);
-		disable_irq(client->irq);
+	pr_debug("%s\n", __func__);
+
+	if (!mhl_ctrl) {
+		pr_err("%s: invalid ctrl data\n", __func__);
+		return 0;
 	}
+
+	if (mhl_ctrl->mhl_mode)	{
+		mhl_ctrl->mhl_mode = 0;
+
+		power_supply_changed(&mhl_ctrl->mhl_psy);
+		if (mhl_ctrl->notify_usb_online)
+			mhl_ctrl->notify_usb_online(mhl_ctrl->notify_ctx, 0);
+
+		mhl_sii_config(mhl_ctrl, false);
+	}
+
 	return 0;
 }
 
 static int mhl_i2c_resume_sub(struct i2c_client *client)
 {
-	struct mhl_tx_ctrl *mhl_ctrl = i2c_get_clientdata(client);
+	pr_debug("%s\n", __func__);
 
-	if (mhl_ctrl->irq_req_done)
-		disable_irq_wake(client->irq);
 	return 0;
 }
 #endif /* defined(CONFIG_PM) || defined(CONFIG_PM_SLEEP) */
diff --git a/drivers/video/msm/mdss/msm_mdss_io_8974.c b/drivers/video/msm/mdss/msm_mdss_io_8974.c
index a63275b..34e383e 100644
--- a/drivers/video/msm/mdss/msm_mdss_io_8974.c
+++ b/drivers/video/msm/mdss/msm_mdss_io_8974.c
@@ -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
@@ -64,6 +64,16 @@
 		goto mdss_dsi_clk_err;
 	}
 
+	if (ctrl_pdata->panel_data.panel_info.type == MIPI_CMD_PANEL) {
+		ctrl_pdata->mmss_misc_ahb_clk = clk_get(dev, "core_mmss_clk");
+		if (IS_ERR(ctrl_pdata->mmss_misc_ahb_clk)) {
+			rc = PTR_ERR(ctrl_pdata->mmss_misc_ahb_clk);
+			pr_err("%s: Unable to get mmss misc ahb clk. rc=%d\n",
+				__func__, rc);
+			goto mdss_dsi_clk_err;
+		}
+	}
+
 	ctrl_pdata->byte_clk = clk_get(dev, "byte_clk");
 	if (IS_ERR(ctrl_pdata->byte_clk)) {
 		rc = PTR_ERR(ctrl_pdata->byte_clk);
@@ -105,6 +115,8 @@
 		clk_put(ctrl_pdata->esc_clk);
 	if (ctrl_pdata->pixel_clk)
 		clk_put(ctrl_pdata->pixel_clk);
+	if (ctrl_pdata->mmss_misc_ahb_clk)
+		clk_put(ctrl_pdata->mmss_misc_ahb_clk);
 	if (ctrl_pdata->axi_clk)
 		clk_put(ctrl_pdata->axi_clk);
 	if (ctrl_pdata->ahb_clk)
@@ -247,10 +259,12 @@
 	return 0;
 }
 
-int mdss_dsi_enable_bus_clocks(struct mdss_dsi_ctrl_pdata *ctrl_pdata)
+static int mdss_dsi_bus_clk_start(struct mdss_dsi_ctrl_pdata *ctrl_pdata)
 {
 	int rc = 0;
 
+	pr_debug("%s: ndx=%d\n", __func__, ctrl_pdata->ndx);
+
 	rc = clk_prepare_enable(ctrl_pdata->mdp_core_clk);
 	if (rc) {
 		pr_err("%s: failed to enable mdp_core_clock. rc=%d\n",
@@ -273,18 +287,32 @@
 		goto error;
 	}
 
+	if (ctrl_pdata->mmss_misc_ahb_clk) {
+		rc = clk_prepare_enable(ctrl_pdata->mmss_misc_ahb_clk);
+		if (rc) {
+			pr_err("%s: failed to enable mmss misc ahb clk.rc=%d\n",
+				__func__, rc);
+			clk_disable_unprepare(ctrl_pdata->axi_clk);
+			clk_disable_unprepare(ctrl_pdata->ahb_clk);
+			clk_disable_unprepare(ctrl_pdata->mdp_core_clk);
+			goto error;
+		}
+	}
+
 error:
 	return rc;
 }
 
-void mdss_dsi_disable_bus_clocks(struct mdss_dsi_ctrl_pdata *ctrl_pdata)
+static void mdss_dsi_bus_clk_stop(struct mdss_dsi_ctrl_pdata *ctrl_pdata)
 {
+	if (ctrl_pdata->mmss_misc_ahb_clk)
+		clk_disable_unprepare(ctrl_pdata->mmss_misc_ahb_clk);
 	clk_disable_unprepare(ctrl_pdata->axi_clk);
 	clk_disable_unprepare(ctrl_pdata->ahb_clk);
 	clk_disable_unprepare(ctrl_pdata->mdp_core_clk);
 }
 
-static int mdss_dsi_clk_prepare(struct mdss_dsi_ctrl_pdata *ctrl_pdata)
+static int mdss_dsi_link_clk_prepare(struct mdss_dsi_ctrl_pdata *ctrl_pdata)
 {
 	int rc = 0;
 
@@ -316,7 +344,7 @@
 	return rc;
 }
 
-static void mdss_dsi_clk_unprepare(struct mdss_dsi_ctrl_pdata *ctrl_pdata)
+static void mdss_dsi_link_clk_unprepare(struct mdss_dsi_ctrl_pdata *ctrl_pdata)
 {
 	if (!ctrl_pdata) {
 		pr_err("%s: Invalid input data\n", __func__);
@@ -328,7 +356,7 @@
 	clk_unprepare(ctrl_pdata->esc_clk);
 }
 
-static int mdss_dsi_clk_set_rate(struct mdss_dsi_ctrl_pdata *ctrl_pdata)
+static int mdss_dsi_link_clk_set_rate(struct mdss_dsi_ctrl_pdata *ctrl_pdata)
 {
 	u32 esc_clk_rate = 19200000;
 	int rc = 0;
@@ -369,7 +397,7 @@
 	return rc;
 }
 
-static int mdss_dsi_clk_enable(struct mdss_dsi_ctrl_pdata *ctrl_pdata)
+static int mdss_dsi_link_clk_enable(struct mdss_dsi_ctrl_pdata *ctrl_pdata)
 {
 	int rc = 0;
 
@@ -378,10 +406,7 @@
 		return -EINVAL;
 	}
 
-	if (ctrl_pdata->mdss_dsi_clk_on) {
-		pr_info("%s: mdss_dsi_clks already ON\n", __func__);
-		return 0;
-	}
+	pr_debug("%s: ndx=%d\n", __func__, ctrl_pdata->ndx);
 
 	rc = clk_enable(ctrl_pdata->esc_clk);
 	if (rc) {
@@ -401,8 +426,6 @@
 		goto pixel_clk_err;
 	}
 
-	ctrl_pdata->mdss_dsi_clk_on = 1;
-
 	return rc;
 
 pixel_clk_err:
@@ -413,80 +436,240 @@
 	return rc;
 }
 
-static void mdss_dsi_clk_disable(struct mdss_dsi_ctrl_pdata *ctrl_pdata)
+static void mdss_dsi_link_clk_disable(struct mdss_dsi_ctrl_pdata *ctrl_pdata)
 {
 	if (!ctrl_pdata) {
 		pr_err("%s: Invalid input data\n", __func__);
 		return;
 	}
 
-	if (ctrl_pdata->mdss_dsi_clk_on == 0) {
-		pr_info("%s: mdss_dsi_clks already OFF\n", __func__);
-		return;
-	}
+	pr_debug("%s: ndx=%d\n", __func__, ctrl_pdata->ndx);
 
 	clk_disable(ctrl_pdata->esc_clk);
 	clk_disable(ctrl_pdata->pixel_clk);
 	clk_disable(ctrl_pdata->byte_clk);
-
-	ctrl_pdata->mdss_dsi_clk_on = 0;
 }
 
-int mdss_dsi_clk_ctrl(struct mdss_dsi_ctrl_pdata *ctrl, int enable)
+static int mdss_dsi_link_clk_start(struct mdss_dsi_ctrl_pdata *ctrl)
 {
 	int rc = 0;
 
-	mutex_lock(&ctrl->mutex);
+	rc = mdss_dsi_link_clk_set_rate(ctrl);
+	if (rc) {
+		pr_err("%s: failed to set clk rates. rc=%d\n",
+			__func__, rc);
+		goto error;
+	}
+
+	rc = mdss_dsi_link_clk_prepare(ctrl);
+	if (rc) {
+		pr_err("%s: failed to prepare clks. rc=%d\n",
+			__func__, rc);
+		goto error;
+	}
+
+	rc = mdss_dsi_link_clk_enable(ctrl);
+	if (rc) {
+		pr_err("%s: failed to enable clks. rc=%d\n",
+			__func__, rc);
+		mdss_dsi_link_clk_unprepare(ctrl);
+		goto error;
+	}
+
+error:
+	return rc;
+}
+
+static void mdss_dsi_link_clk_stop(struct mdss_dsi_ctrl_pdata *ctrl)
+{
+	mdss_dsi_link_clk_disable(ctrl);
+	mdss_dsi_link_clk_unprepare(ctrl);
+}
+
+static int __mdss_dsi_update_clk_cnt(u32 *clk_cnt, int enable)
+{
+	int changed = 0;
+
 	if (enable) {
-		if (ctrl->clk_cnt == 0) {
-			rc = mdss_dsi_enable_bus_clocks(ctrl);
-			if (rc) {
-				pr_err("%s: failed to enable bus clks. rc=%d\n",
-					__func__, rc);
-				goto error;
-			}
+		if (*clk_cnt == 0)
+			changed++;
+		(*clk_cnt)++;
+	} else {
+		if (*clk_cnt != 0) {
+			(*clk_cnt)--;
+			if (*clk_cnt == 0)
+				changed++;
+		} else {
+			pr_debug("%s: clk cnt already zero\n", __func__);
+		}
+	}
 
-			rc = mdss_dsi_clk_set_rate(ctrl);
-			if (rc) {
-				pr_err("%s: failed to set clk rates. rc=%d\n",
-					__func__, rc);
-				mdss_dsi_disable_bus_clocks(ctrl);
-				goto error;
-			}
+	return changed;
+}
 
-			rc = mdss_dsi_clk_prepare(ctrl);
-			if (rc) {
-				pr_err("%s: failed to prepare clks. rc=%d\n",
-					__func__, rc);
-				mdss_dsi_disable_bus_clocks(ctrl);
-				goto error;
-			}
+static int mdss_dsi_clk_ctrl_sub(struct mdss_dsi_ctrl_pdata *ctrl,
+	u8 clk_type, int enable)
+{
+	int rc = 0;
 
-			rc = mdss_dsi_clk_enable(ctrl);
+	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);
+
+	if (enable) {
+		if (clk_type & DSI_BUS_CLKS) {
+			rc = mdss_dsi_bus_clk_start(ctrl);
 			if (rc) {
-				pr_err("%s: failed to enable clks. rc=%d\n",
-					__func__, rc);
-				mdss_dsi_clk_unprepare(ctrl);
-				mdss_dsi_disable_bus_clocks(ctrl);
+				pr_err("Failed to start bus clocks. rc=%d\n",
+					rc);
 				goto error;
 			}
 		}
-		ctrl->clk_cnt++;
+		if (clk_type & DSI_LINK_CLKS) {
+			rc = mdss_dsi_link_clk_start(ctrl);
+			if (rc) {
+				pr_err("Failed to start link clocks. rc=%d\n",
+					rc);
+				if (clk_type & DSI_BUS_CLKS)
+					mdss_dsi_bus_clk_stop(ctrl);
+				goto error;
+			}
+		}
 	} else {
-		if (ctrl->clk_cnt) {
-			ctrl->clk_cnt--;
-			if (ctrl->clk_cnt == 0) {
-				mdss_dsi_clk_disable(ctrl);
-				mdss_dsi_clk_unprepare(ctrl);
-				mdss_dsi_disable_bus_clocks(ctrl);
+		if (clk_type & DSI_LINK_CLKS)
+			mdss_dsi_link_clk_stop(ctrl);
+		if (clk_type & DSI_BUS_CLKS)
+			mdss_dsi_bus_clk_stop(ctrl);
+	}
+
+error:
+	return rc;
+}
+
+static DEFINE_MUTEX(dsi_clk_lock); /* per system */
+
+bool __mdss_dsi_clk_enabled(struct mdss_dsi_ctrl_pdata *ctrl, u8 clk_type)
+{
+	bool bus_enabled = true;
+	bool link_enabled = true;
+
+	mutex_lock(&dsi_clk_lock);
+	if (clk_type & DSI_BUS_CLKS)
+		bus_enabled = ctrl->bus_clk_cnt ? true : false;
+	if (clk_type & DSI_LINK_CLKS)
+		link_enabled = ctrl->link_clk_cnt ? true : false;
+	mutex_unlock(&dsi_clk_lock);
+
+	return bus_enabled && link_enabled;
+}
+
+int mdss_dsi_clk_ctrl(struct mdss_dsi_ctrl_pdata *ctrl,
+	u8 clk_type, int enable)
+{
+	int rc = 0;
+	int changed = 0, m_changed = 0;
+	struct mdss_dsi_ctrl_pdata *mctrl = NULL;
+
+	if (!ctrl) {
+		pr_err("%s: Invalid arg\n", __func__);
+		return -EINVAL;
+	}
+
+	/*
+	 * In broadcast mode, we need to enable clocks for the
+	 * master controller as well when enabling clocks for the
+	 * slave controller
+	 */
+	if (mdss_dsi_is_slave_ctrl(ctrl)) {
+		mctrl = mdss_dsi_get_master_ctrl();
+		if (!mctrl)
+			pr_warn("%s: Unable to get master control\n", __func__);
+	}
+
+	pr_debug("%s++: ndx=%d clk_type=%d bus_clk_cnt=%d link_clk_cnt=%d",
+		__func__, ctrl->ndx, clk_type, ctrl->bus_clk_cnt,
+		ctrl->link_clk_cnt);
+	pr_debug("%s++: mctrl=%s m_bus_clk_cnt=%d m_link_clk_cnt=%d\n, enable=%d\n",
+		__func__, mctrl ? "yes" : "no", mctrl ? mctrl->bus_clk_cnt : -1,
+		mctrl ? mctrl->link_clk_cnt : -1, enable);
+
+	mutex_lock(&dsi_clk_lock);
+	if (clk_type & DSI_BUS_CLKS) {
+		changed = __mdss_dsi_update_clk_cnt(&ctrl->bus_clk_cnt,
+			enable);
+		if (changed && mctrl)
+			m_changed = __mdss_dsi_update_clk_cnt(
+				&mctrl->bus_clk_cnt, enable);
+	}
+
+	if (clk_type & DSI_LINK_CLKS) {
+		changed += __mdss_dsi_update_clk_cnt(&ctrl->link_clk_cnt,
+			enable);
+		if (changed && mctrl)
+			m_changed += __mdss_dsi_update_clk_cnt(
+				&mctrl->link_clk_cnt, enable);
+	}
+
+	if (changed) {
+		if (enable && m_changed) {
+			rc = mdss_dsi_clk_ctrl_sub(mctrl, clk_type, enable);
+			if (rc) {
+				pr_err("Failed to start mctrl clocks. rc=%d\n",
+					rc);
+				goto error_mctrl_start;
+			}
+		}
+
+		rc = mdss_dsi_clk_ctrl_sub(ctrl, clk_type, enable);
+		if (rc) {
+			pr_err("Failed to %s ctrl clocks. rc=%d\n",
+				(enable ? "start" : "stop"), rc);
+			goto error_ctrl;
+		}
+
+		if (!enable && m_changed) {
+			rc = mdss_dsi_clk_ctrl_sub(mctrl, clk_type, enable);
+			if (rc) {
+				pr_err("Failed to stop mctrl clocks. rc=%d\n",
+					rc);
+				goto error_mctrl_stop;
 			}
 		}
 	}
-	pr_debug("%s: ctrl ndx=%d enabled=%d clk_cnt=%d\n",
-			__func__, ctrl->ndx, enable, ctrl->clk_cnt);
+	goto no_error;
 
-error:
-	mutex_unlock(&ctrl->mutex);
+error_mctrl_stop:
+	mdss_dsi_clk_ctrl_sub(ctrl, clk_type, enable ? 0 : 1);
+error_ctrl:
+	if (enable && m_changed)
+		mdss_dsi_clk_ctrl_sub(mctrl, clk_type, 0);
+error_mctrl_start:
+	if (clk_type & DSI_BUS_CLKS) {
+		if (mctrl)
+			__mdss_dsi_update_clk_cnt(&mctrl->bus_clk_cnt,
+				enable ? 0 : 1);
+		__mdss_dsi_update_clk_cnt(&ctrl->bus_clk_cnt, enable ? 0 : 1);
+	}
+	if (clk_type & DSI_LINK_CLKS) {
+		if (mctrl)
+			__mdss_dsi_update_clk_cnt(&mctrl->link_clk_cnt,
+				enable ? 0 : 1);
+		__mdss_dsi_update_clk_cnt(&ctrl->link_clk_cnt, enable ? 0 : 1);
+	}
+
+no_error:
+	mutex_unlock(&dsi_clk_lock);
+	pr_debug("%s++: ndx=%d clk_type=%d bus_clk_cnt=%d link_clk_cnt=%d changed=%d",
+		__func__, ctrl->ndx, clk_type, ctrl->bus_clk_cnt,
+		ctrl->link_clk_cnt, changed);
+	pr_debug("%s++: mctrl=%s m_bus_clk_cnt=%d m_link_clk_cnt=%d\n, m_changed=%d, enable=%d\n",
+		__func__, mctrl ? "yes" : "no", mctrl ? mctrl->bus_clk_cnt : -1,
+		mctrl ? mctrl->link_clk_cnt : -1, m_changed, enable);
+
 	return rc;
 }
 
@@ -502,75 +685,54 @@
 	wmb();
 }
 
-void mdss_dsi_phy_enable(struct mdss_dsi_ctrl_pdata *ctrl, int on)
+void mdss_dsi_phy_disable(struct mdss_dsi_ctrl_pdata *ctrl)
 {
-	static struct mdss_dsi_ctrl_pdata *left_ctrl;
+	struct mdss_dsi_ctrl_pdata *ctrl0 = NULL;
 
 	if (ctrl == NULL) {
 		pr_err("%s: Invalid input data\n", __func__);
 		return;
 	}
 
-	if (!left_ctrl
-		&& ctrl->shared_pdata.broadcast_enable)
-		if ((ctrl->panel_data).panel_info.pdest
-						== DISPLAY_1)
-			left_ctrl = ctrl;
-
-	if (on) {
-		MIPI_OUTP(ctrl->ctrl_base + 0x03cc, 0x03);
-		wmb();
-		usleep(100);
-		MIPI_OUTP(ctrl->ctrl_base + 0x0220, 0x006);
-		wmb();
-		usleep(100);
-		MIPI_OUTP(ctrl->ctrl_base + 0x0268, 0x001);
-		wmb();
-		usleep(100);
-		MIPI_OUTP(ctrl->ctrl_base + 0x0268, 0x000);
-		wmb();
-		usleep(100);
-		MIPI_OUTP(ctrl->ctrl_base + 0x0220, 0x007);
-		wmb();
-		MIPI_OUTP(ctrl->ctrl_base + 0x03cc, 0x01);
-		wmb();
-		usleep(100);
-
-		/* MMSS_DSI_0_PHY_DSIPHY_CTRL_0 */
-		MIPI_OUTP(ctrl->ctrl_base + 0x0470, 0x07e);
-		MIPI_OUTP(ctrl->ctrl_base + 0x0470, 0x06e);
-		MIPI_OUTP(ctrl->ctrl_base + 0x0470, 0x06c);
-		MIPI_OUTP(ctrl->ctrl_base + 0x0470, 0x064);
-		MIPI_OUTP(ctrl->ctrl_base + 0x0470, 0x065);
-		MIPI_OUTP(ctrl->ctrl_base + 0x0470, 0x075);
-		MIPI_OUTP(ctrl->ctrl_base + 0x0470, 0x077);
-		MIPI_OUTP(ctrl->ctrl_base + 0x0470, 0x07f);
-		wmb();
-	} else {
-		if (left_ctrl &&
-			(ctrl->panel_data.panel_info.pdest
-						== DISPLAY_1))
-			return;
-
-		if (left_ctrl &&
-			(ctrl->panel_data.panel_info.pdest
-						== DISPLAY_2)) {
-			MIPI_OUTP(left_ctrl->ctrl_base + 0x0220, 0x006);
-			MIPI_OUTP(left_ctrl->ctrl_base + 0x0470, 0x000);
-			MIPI_OUTP(left_ctrl->ctrl_base + 0x0598, 0x000);
-		}
-		MIPI_OUTP(ctrl->ctrl_base + 0x0220, 0x006);
-		MIPI_OUTP(ctrl->ctrl_base + 0x0470, 0x000);
-		MIPI_OUTP(ctrl->ctrl_base + 0x0598, 0x000);
-		wmb();
+	/*
+	 * In dual-dsi configuration, the phy should be disabled for the
+	 * first controller only when the second controller is disabled.
+	 * This is true regardless of whether broadcast mode is enabled
+	 * or not.
+	 */
+	if ((ctrl->ndx == DSI_CTRL_0) &&
+		mdss_dsi_get_ctrl_by_index(DSI_CTRL_1)) {
+		pr_debug("%s: Dual dsi detected. skipping config for ctrl%d\n",
+			__func__, ctrl->ndx);
+		return;
 	}
+
+	if (ctrl->ndx == DSI_CTRL_1) {
+		ctrl0 = mdss_dsi_get_ctrl_by_index(DSI_CTRL_0);
+		if (ctrl0) {
+			MIPI_OUTP(ctrl0->phy_io.base + 0x0170, 0x000);
+			MIPI_OUTP(ctrl0->phy_io.base + 0x0298, 0x000);
+		} else {
+			pr_warn("%s: Unable to get control%d\n",
+				__func__, DSI_CTRL_0);
+		}
+	}
+
+	MIPI_OUTP(ctrl->phy_io.base + 0x0170, 0x000);
+	MIPI_OUTP(ctrl->phy_io.base + 0x0298, 0x000);
+
+	/*
+	 * Wait for the registers writes to complete in order to
+	 * ensure that the phy is completely disabled
+	 */
+	wmb();
 }
 
 void mdss_dsi_phy_init(struct mdss_panel_data *pdata)
 {
 	struct mdss_dsi_phy_ctrl *pd;
 	int i, off, ln, offset;
-	struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
+	struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL, *temp_ctrl = NULL;
 
 	ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
 				panel_data);
@@ -578,67 +740,75 @@
 		pr_err("%s: Invalid input data\n", __func__);
 		return;
 	}
+	temp_ctrl = ctrl_pdata;
 
 	pd = &(((ctrl_pdata->panel_data).panel_info.mipi).dsi_phy_db);
 
 	/* Strength ctrl 0 */
-	MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x0484, pd->strength[0]);
+	MIPI_OUTP((ctrl_pdata->phy_io.base) + 0x0184, pd->strength[0]);
 
-	/* phy regulator ctrl settings. Both the DSI controller
-	   have one regulator */
-	if ((ctrl_pdata->panel_data).panel_info.pdest == DISPLAY_1)
-		off = 0x0580;
-	else
-		off = 0x0580 - 0x600;
+	/*
+	 * Phy regulator ctrl settings.
+	 * In dual dsi configuration, the second controller also uses
+	 * the regulators of the first controller, irrespective of whether
+	 * broadcast mode is enabled or not.
+	 */
+	if (ctrl_pdata->ndx == DSI_CTRL_1) {
+		temp_ctrl = mdss_dsi_get_ctrl_by_index(DSI_CTRL_0);
+		if (!temp_ctrl) {
+			pr_err("%s: Unable to get master ctrl\n", __func__);
+			return;
+		}
+	}
 
 	/* Regulator ctrl 0 */
-	MIPI_OUTP((ctrl_pdata->ctrl_base) + off + (4 * 0), 0x0);
+	MIPI_OUTP((temp_ctrl->phy_io.base) + 0x280, 0x0);
 	/* Regulator ctrl - CAL_PWR_CFG */
-	MIPI_OUTP((ctrl_pdata->ctrl_base) + off + (4 * 6), pd->regulator[6]);
+	MIPI_OUTP((temp_ctrl->phy_io.base) + 0x298, pd->regulator[6]);
 
 	/* Regulator ctrl - TEST */
-	MIPI_OUTP((ctrl_pdata->ctrl_base) + off + (4 * 5), pd->regulator[5]);
+	MIPI_OUTP((temp_ctrl->phy_io.base) + 0x294, pd->regulator[5]);
 	/* Regulator ctrl 3 */
-	MIPI_OUTP((ctrl_pdata->ctrl_base) + off + (4 * 3), pd->regulator[3]);
+	MIPI_OUTP((temp_ctrl->phy_io.base) + 0x28c, pd->regulator[3]);
 	/* Regulator ctrl 2 */
-	MIPI_OUTP((ctrl_pdata->ctrl_base) + off + (4 * 2), pd->regulator[2]);
+	MIPI_OUTP((temp_ctrl->phy_io.base) + 0x288, pd->regulator[2]);
 	/* Regulator ctrl 1 */
-	MIPI_OUTP((ctrl_pdata->ctrl_base) + off + (4 * 1), pd->regulator[1]);
+	MIPI_OUTP((temp_ctrl->phy_io.base) + 0x284, pd->regulator[1]);
 	/* Regulator ctrl 0 */
-	MIPI_OUTP((ctrl_pdata->ctrl_base) + off + (4 * 0), pd->regulator[0]);
+	MIPI_OUTP((temp_ctrl->phy_io.base) + 0x280, pd->regulator[0]);
 	/* Regulator ctrl 4 */
-	MIPI_OUTP((ctrl_pdata->ctrl_base) + off + (4 * 4), pd->regulator[4]);
+	MIPI_OUTP((temp_ctrl->phy_io.base) + 0x290, pd->regulator[4]);
 
 	/* LDO ctrl 0 */
 	if ((ctrl_pdata->panel_data).panel_info.pdest == DISPLAY_1)
-		MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x4dc, 0x00);
+		MIPI_OUTP((ctrl_pdata->phy_io.base) + 0x1dc, 0x00);
 	else
-		MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x4dc, 0x00);
+		MIPI_OUTP((ctrl_pdata->phy_io.base) + 0x1dc, 0x00);
 
-	off = 0x0440;	/* phy timing ctrl 0 - 11 */
+	off = 0x0140;	/* phy timing ctrl 0 - 11 */
 	for (i = 0; i < 12; i++) {
-		MIPI_OUTP((ctrl_pdata->ctrl_base) + off, pd->timing[i]);
+		MIPI_OUTP((ctrl_pdata->phy_io.base) + off, pd->timing[i]);
 		wmb();
 		off += 4;
 	}
 
 	/* MMSS_DSI_0_PHY_DSIPHY_CTRL_1 */
-	MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x0474, 0x00);
+	MIPI_OUTP((ctrl_pdata->phy_io.base) + 0x0174, 0x00);
 	/* MMSS_DSI_0_PHY_DSIPHY_CTRL_0 */
-	MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x0470, 0x5f);
+	MIPI_OUTP((ctrl_pdata->phy_io.base) + 0x0170, 0x5f);
 	wmb();
 
 	/* Strength ctrl 1 */
-	MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x0488, pd->strength[1]);
+	MIPI_OUTP((ctrl_pdata->phy_io.base) + 0x0188, pd->strength[1]);
 	wmb();
 
 	/* 4 lanes + clk lane configuration */
 	/* lane config n * (0 - 4) & DataPath setup */
 	for (ln = 0; ln < 5; ln++) {
-		off = 0x0300 + (ln * 0x40);
+		off = (ln * 0x40);
 		for (i = 0; i < 9; i++) {
 			offset = i + (ln * 9);
-			MIPI_OUTP((ctrl_pdata->ctrl_base) + off,
+			MIPI_OUTP((ctrl_pdata->phy_io.base) + off,
 							pd->lanecfg[offset]);
 			wmb();
 			off += 4;
@@ -646,19 +816,19 @@
 	}
 
 	/* MMSS_DSI_0_PHY_DSIPHY_CTRL_0 */
-	MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x0470, 0x5f);
+	MIPI_OUTP((ctrl_pdata->phy_io.base) + 0x0170, 0x5f);
 	wmb();
 
 	/* DSI_0_PHY_DSIPHY_GLBL_TEST_CTRL */
 	if ((ctrl_pdata->panel_data).panel_info.pdest == DISPLAY_1)
-		MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x04d4, 0x01);
+		MIPI_OUTP((ctrl_pdata->phy_io.base) + 0x01d4, 0x01);
 	else
-		MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x04d4, 0x00);
+		MIPI_OUTP((ctrl_pdata->phy_io.base) + 0x01d4, 0x00);
 	wmb();
 
-	off = 0x04b4;	/* phy BIST ctrl 0 - 5 */
+	off = 0x01b4;	/* phy BIST ctrl 0 - 5 */
 	for (i = 0; i < 6; i++) {
-		MIPI_OUTP((ctrl_pdata->ctrl_base) + off, pd->bistctrl[i]);
+		MIPI_OUTP((ctrl_pdata->phy_io.base) + off, pd->bistctrl[i]);
 		wmb();
 		off += 4;
 	}
@@ -675,6 +845,8 @@
 		clk_put(edp_drv->ahb_clk);
 	if (edp_drv->link_clk)
 		clk_put(edp_drv->link_clk);
+	if (edp_drv->mdp_core_clk)
+		clk_put(edp_drv->mdp_core_clk);
 }
 
 int mdss_edp_clk_init(struct mdss_edp_drv_pdata *edp_drv)
@@ -709,6 +881,14 @@
 		goto mdss_edp_clk_err;
 	}
 
+	/* need mdss clock to receive irq */
+	edp_drv->mdp_core_clk = clk_get(dev, "mdp_core_clk");
+	if (IS_ERR(edp_drv->mdp_core_clk)) {
+		pr_err("%s: Can't find mdp_core_clk", __func__);
+		edp_drv->mdp_core_clk = NULL;
+		goto mdss_edp_clk_err;
+	}
+
 	return 0;
 
 mdss_edp_clk_err:
@@ -736,7 +916,16 @@
 		goto c1;
 	}
 
+	/* need mdss clock to receive irq */
+	ret = clk_enable(edp_drv->mdp_core_clk);
+	if (ret) {
+		pr_err("%s: Failed to enable mdp_core_clk\n", __func__);
+		goto c0;
+	}
+
 	return 0;
+c0:
+	clk_disable(edp_drv->ahb_clk);
 c1:
 	clk_disable(edp_drv->aux_clk);
 c2:
@@ -748,6 +937,7 @@
 {
 	clk_disable(edp_drv->aux_clk);
 	clk_disable(edp_drv->ahb_clk);
+	clk_disable(edp_drv->mdp_core_clk);
 }
 
 int mdss_edp_clk_enable(struct mdss_edp_drv_pdata *edp_drv)
@@ -791,11 +981,18 @@
 		pr_err("%s: Failed to enable link clk\n", __func__);
 		goto c1;
 	}
+	ret = clk_enable(edp_drv->mdp_core_clk);
+	if (ret) {
+		pr_err("%s: Failed to enable mdp_core_clk\n", __func__);
+		goto c0;
+	}
 
 	edp_drv->clk_on = 1;
 
 	return 0;
 
+c0:
+	clk_disable(edp_drv->link_clk);
 c1:
 	clk_disable(edp_drv->ahb_clk);
 c2:
@@ -817,6 +1014,7 @@
 	clk_disable(edp_drv->pixel_clk);
 	clk_disable(edp_drv->ahb_clk);
 	clk_disable(edp_drv->link_clk);
+	clk_disable(edp_drv->mdp_core_clk);
 
 	edp_drv->clk_on = 0;
 }
@@ -825,10 +1023,11 @@
 {
 	int ret;
 
+	/* ahb clock should be prepared first */
 	ret = clk_prepare(edp_drv->ahb_clk);
 	if (ret) {
 		pr_err("%s: Failed to prepare ahb clk\n", __func__);
-		goto c1;
+		goto c3;
 	}
 	ret = clk_prepare(edp_drv->aux_clk);
 	if (ret) {
@@ -836,16 +1035,26 @@
 		goto c2;
 	}
 
+	/* need mdss clock to receive irq */
+	ret = clk_prepare(edp_drv->mdp_core_clk);
+	if (ret) {
+		pr_err("%s: Failed to prepare mdp_core clk\n", __func__);
+		goto c1;
+	}
+
 	return 0;
 c1:
-	clk_unprepare(edp_drv->ahb_clk);
+	clk_unprepare(edp_drv->aux_clk);
 c2:
+	clk_unprepare(edp_drv->ahb_clk);
+c3:
 	return ret;
 
 }
 
 void mdss_edp_unprepare_aux_clocks(struct mdss_edp_drv_pdata *edp_drv)
 {
+	clk_unprepare(edp_drv->mdp_core_clk);
 	clk_unprepare(edp_drv->aux_clk);
 	clk_unprepare(edp_drv->ahb_clk);
 }
@@ -854,7 +1063,7 @@
 {
 	int ret;
 
-	/* ahb clock should be first one to enable */
+	/* ahb clock should be prepared first */
 	ret = clk_prepare(edp_drv->ahb_clk);
 	if (ret) {
 		pr_err("%s: Failed to prepare ahb clk\n", __func__);
@@ -875,8 +1084,15 @@
 		pr_err("%s: Failed to prepare link clk\n", __func__);
 		goto c1;
 	}
+	ret = clk_prepare(edp_drv->mdp_core_clk);
+	if (ret) {
+		pr_err("%s: Failed to prepare mdp_core clk\n", __func__);
+		goto c0;
+	}
 
 	return 0;
+c0:
+	clk_unprepare(edp_drv->link_clk);
 c1:
 	clk_unprepare(edp_drv->pixel_clk);
 c2:
@@ -889,6 +1105,7 @@
 
 void mdss_edp_unprepare_clocks(struct mdss_edp_drv_pdata *edp_drv)
 {
+	clk_unprepare(edp_drv->mdp_core_clk);
 	clk_unprepare(edp_drv->aux_clk);
 	clk_unprepare(edp_drv->pixel_clk);
 	clk_unprepare(edp_drv->link_clk);
diff --git a/drivers/video/msm/mdss/splash.h b/drivers/video/msm/mdss/splash.h
new file mode 100644
index 0000000..dc8a473
--- /dev/null
+++ b/drivers/video/msm/mdss/splash.h
@@ -0,0 +1,5279 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#ifndef __SPLASH_H_
+#define __SPLASH_H_
+
+#define SPLASH_IMAGE_WIDTH	113
+#define SPLASH_IMAGE_HEIGHT	124
+#define SPLASH_IMAGE_FORMAT	MDP_BGR_888
+#define SPLASH_IMAGE_BPP	3
+
+char splash_bgr888_image[] = {
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x08,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x08, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x08, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x10,
+	0x29, 0x19, 0x31, 0x31,
+	0x29, 0x31, 0x31, 0x29, 0x08, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x08, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x08,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08,
+	0x08, 0x10, 0x31, 0x31,
+	0x29, 0x4a, 0x52, 0x4a, 0x6b, 0x5a, 0x73, 0x4a, 0x52, 0x4a, 0x10, 0x29,
+	0x19, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x08, 0x08,
+	0x10, 0x31, 0x31, 0x29, 0x6b, 0x5a, 0x73, 0x6b, 0x7b, 0x73, 0x6b, 0x5a,
+	0x4a, 0x31, 0x31, 0x29,
+	0x3a, 0x10, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x10, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x08,
+	0x08, 0x10, 0x10, 0x21, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x10, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x08, 0x08, 0x10, 0x31, 0x31, 0x29, 0x6b, 0x5a, 0x4a, 0x6b, 0x5a,
+	0x73, 0x3a, 0x31, 0x4a,
+	0x31, 0x31, 0x29, 0x10, 0x29, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x08,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x08, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x10, 0x31, 0x31, 0x29, 0x3a, 0x31,
+	0x4a, 0x31, 0x31, 0x29,
+	0x10, 0x29, 0x19, 0x08, 0x08, 0x10, 0x08, 0x08, 0x10, 0x00, 0x00, 0x00,
+	0x08, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x08, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x10, 0x10, 0x21, 0x00,
+	0x00, 0x00, 0x00, 0x08,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x10, 0x08, 0x08,
+	0x10, 0x08, 0x08, 0x10,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x08, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x08, 0x00, 0x00,
+	0x08, 0x08, 0x10, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x08, 0x08, 0x10, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x08, 0x08,
+	0x10, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x21,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x08,
+	0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x08, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x08,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x08, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x10, 0x21, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x08, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x08, 0x00, 0x00, 0x08, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x08, 0x08, 0x10, 0x00,
+	0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x08, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x21, 0x00, 0x08, 0x08, 0x10,
+	0x08, 0x08, 0x10, 0x10,
+	0x29, 0x19, 0x10, 0x29, 0x19, 0x08, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x08, 0x08,
+	0x10, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x10, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x08, 0x08, 0x10, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x08, 0x10,
+	0x4a, 0x52, 0x4a, 0x08,
+	0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x08, 0x10,
+	0x00, 0x00, 0x00, 0x08,
+	0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x08, 0x10, 0x31, 0x31, 0x29, 0x08,
+	0x08, 0x10, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x08, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x10, 0x29, 0x19, 0x4a, 0x52, 0x4a, 0x3a, 0x31, 0x4a,
+	0x08, 0x00, 0x00, 0x08,
+	0x08, 0x10, 0x4a, 0x52, 0x4a, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08,
+	0x08, 0x10, 0x00, 0x00,
+	0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x4a,
+	0x52, 0x4a, 0x9c, 0xa5, 0x94, 0x9c, 0x7b, 0x94, 0x08, 0x08, 0x10, 0x08,
+	0x08, 0x10, 0x10, 0x29,
+	0x19, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08,
+	0x10, 0x10, 0x21, 0x00,
+	0x08, 0x08, 0x10, 0x6b, 0x7b, 0x73, 0x9c, 0x7b, 0x94, 0x9c, 0xa5, 0x94,
+	0xce, 0xad, 0xad, 0xa5,
+	0xb5, 0xb5, 0x31, 0x31, 0x29, 0x08, 0x08, 0x10, 0x10, 0x29, 0x19, 0x08,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x10, 0x00, 0x00, 0x00, 0x08, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x08, 0x00, 0x00, 0x4a,
+	0x52, 0x4a, 0xa5, 0x9c, 0xad, 0xce, 0xad, 0xad, 0xce, 0xde, 0xce, 0x9c,
+	0x7b, 0x94, 0x10, 0x29,
+	0x19, 0x3a, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x08, 0x08, 0x10, 0x9c, 0x7b, 0x94, 0x9c, 0xa5, 0x94, 0xa5, 0xb5, 0xb5,
+	0xa5, 0xb5, 0xb5, 0xce,
+	0xde, 0xce, 0xc5, 0xad, 0xd6, 0x9c, 0xa5, 0x94, 0x3a, 0x10, 0x21, 0x00,
+	0x00, 0x00, 0x08, 0x08,
+	0x10, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x08, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x08,
+	0x08, 0x10, 0x9c, 0x7b, 0x94, 0xce, 0xad, 0xad, 0xce, 0xe6, 0xef, 0xce,
+	0xe6, 0xef, 0xe6, 0xde,
+	0xde, 0xa5, 0x9c, 0xad, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x08, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x6b, 0x5a, 0x73, 0xce, 0xde, 0xce, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xde, 0xce, 0x6b,
+	0x7b, 0x73, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x21, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x10, 0x29, 0x19, 0xef, 0xf7, 0xe6, 0xef, 0xf7, 0xff, 0x9c,
+	0xa5, 0x94, 0xce, 0xde,
+	0xce, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x08, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x10, 0x21, 0x00, 0xce, 0xde, 0xce, 0xff, 0xf7, 0xff,
+	0xff, 0xf7, 0xff, 0x9c,
+	0xa5, 0x94, 0x00, 0x00, 0x00, 0x31, 0x31, 0x29, 0xef, 0xf7, 0xe6, 0xff,
+	0xf7, 0xff, 0xef, 0xde,
+	0xef, 0x08, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x08,
+	0x00, 0x00, 0x08, 0x00, 0x00, 0x4a, 0x52, 0x4a, 0xff, 0xf7, 0xff, 0x10,
+	0x29, 0x19, 0x08, 0x08,
+	0x10, 0x4a, 0x52, 0x4a, 0xce, 0xad, 0xad, 0xff, 0xff, 0xff, 0x4a, 0x52,
+	0x4a, 0x08, 0x08, 0x10,
+	0x00, 0x00, 0x00, 0x08, 0x08, 0x10, 0x08, 0x08, 0x10, 0xce, 0xad, 0xad,
+	0xef, 0xf7, 0xff, 0xce,
+	0xde, 0xce, 0x00, 0x00, 0x00, 0x08, 0x08, 0x10, 0x9c, 0x7b, 0x94, 0x31,
+	0x31, 0x29, 0xef, 0xf7,
+	0xe6, 0xff, 0xff, 0xff, 0x4a, 0x52, 0x4a, 0x00, 0x00, 0x00, 0x08, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x08, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6b, 0x5a, 0x73, 0xef,
+	0xf7, 0xe6, 0x00, 0x00,
+	0x00, 0x08, 0x00, 0x00, 0x6b, 0x7b, 0x73, 0x08, 0x08, 0x10, 0xff, 0xff,
+	0xff, 0x6b, 0x7b, 0x73,
+	0x08, 0x08, 0x10, 0x31, 0x31, 0x29, 0x4a, 0x52, 0x4a, 0x08, 0x08, 0x10,
+	0xce, 0xde, 0xce, 0xff,
+	0xff, 0xff, 0x10, 0x29, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x31,
+	0x31, 0x29, 0x4a, 0x52,
+	0x4a, 0xa5, 0xb5, 0xb5, 0xff, 0xff, 0xff, 0x9c, 0x7b, 0x94, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x08, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x4a,
+	0x52, 0x4a, 0xe6, 0xde,
+	0xde, 0x08, 0x08, 0x10, 0x00, 0x00, 0x00, 0x31, 0x31, 0x29, 0x08, 0x08,
+	0x10, 0xff, 0xff, 0xff,
+	0x4a, 0x52, 0x4a, 0x08, 0x00, 0x00, 0x08, 0x08, 0x10, 0x00, 0x00, 0x00,
+	0x08, 0x08, 0x10, 0x9c,
+	0x7b, 0x94, 0xff, 0xff, 0xff, 0x3a, 0x10, 0x21, 0x08, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x08, 0x08,
+	0x10, 0x08, 0x08, 0x10, 0x6b, 0x5a, 0x73, 0xff, 0xff, 0xff, 0xa5, 0xb5,
+	0xb5, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x08, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x4a, 0x52,
+	0x4a, 0xef, 0xf7, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0xe6, 0xde, 0xde, 0x08, 0x31, 0x5a, 0x10, 0x7b, 0x9c, 0x10, 0x7b, 0x9c,
+	0x10, 0x7b, 0x9c, 0x10,
+	0x52, 0x7b, 0x31, 0x31, 0x29, 0xef, 0xf7, 0xff, 0x08, 0x08, 0x10, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9c, 0xa5, 0x94, 0xff, 0xff,
+	0xff, 0xa5, 0x9c, 0xad,
+	0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x10, 0x21, 0x00, 0x08,
+	0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x08, 0x00,
+	0x00, 0x08, 0x08, 0x10, 0xff, 0xf7, 0xff, 0x4a, 0x52, 0x4a, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x08, 0x31, 0x5a, 0x00, 0x84, 0xbd, 0x08, 0xad, 0xd6, 0x00, 0xbd, 0xef,
+	0x00, 0xbd, 0xef, 0x00,
+	0x9c, 0xd6, 0x08, 0xa5, 0xad, 0x08, 0xad, 0xd6, 0x10, 0xce, 0xce, 0x6b,
+	0x7b, 0x9c, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0xef, 0xf7,
+	0xff, 0xff, 0xff, 0xff,
+	0x6b, 0x5a, 0x4a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0xce, 0xde, 0xce, 0xff, 0xf7,
+	0xff, 0x10, 0x29, 0x19,
+	0x10, 0x5a, 0x9c, 0x00, 0x9c, 0xd6, 0x19, 0x94, 0xce, 0x00, 0xbd, 0xf7,
+	0x10, 0xc5, 0xef, 0x08,
+	0xad, 0xd6, 0x08, 0xad, 0xd6, 0x08, 0xad, 0xd6, 0x08, 0xad, 0xd6, 0x10,
+	0xc5, 0xef, 0x00, 0xbd,
+	0xef, 0x08, 0xa5, 0xad, 0x08, 0x31, 0x5a, 0x10, 0x29, 0x19, 0xff, 0xf7,
+	0xff, 0xff, 0xff, 0xff,
+	0xe6, 0xde, 0xde, 0x08, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x08,
+	0x08, 0x10, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6b, 0x5a,
+	0x73, 0xef, 0xf7, 0xe6,
+	0x19, 0x7b, 0xbd, 0x19, 0x7b, 0xbd, 0x08, 0xad, 0xd6, 0x00, 0xbd, 0xef,
+	0x10, 0xc5, 0xef, 0x00,
+	0xbd, 0xef, 0x10, 0xc5, 0xef, 0x10, 0xc5, 0xef, 0x3a, 0xde, 0xef, 0x19,
+	0xbd, 0xf7, 0x3a, 0xde,
+	0xef, 0x3a, 0xde, 0xef, 0x10, 0xc5, 0xef, 0x10, 0xc5, 0xef, 0x08, 0xad,
+	0xd6, 0x19, 0x94, 0xce,
+	0xa5, 0xb5, 0xb5, 0x4a, 0x5a, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x08, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x08, 0x08, 0x10,
+	0x10, 0x7b, 0x9c, 0x00, 0x84, 0xbd, 0x08, 0xad, 0xd6, 0x08, 0xad, 0xd6,
+	0x08, 0xad, 0xef, 0x10,
+	0xc5, 0xef, 0x08, 0xad, 0xd6, 0x10, 0xc5, 0xef, 0x10, 0xe6, 0xef, 0x19,
+	0xbd, 0xf7, 0x3a, 0xde,
+	0xef, 0x3a, 0xde, 0xef, 0x10, 0xc5, 0xef, 0x10, 0xe6, 0xef, 0x10, 0xe6,
+	0xef, 0x10, 0xc5, 0xef,
+	0x10, 0xe6, 0xef, 0x19, 0xbd, 0xf7, 0x08, 0xad, 0xd6, 0x08, 0x31, 0x3a,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x08, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x08, 0x08, 0x10,
+	0x10, 0x7b, 0x9c, 0x00, 0x84, 0xbd, 0x19, 0x94, 0xce, 0x00, 0x9c, 0xd6,
+	0x10, 0xc5, 0xef, 0x08,
+	0xad, 0xef, 0x10, 0xc5, 0xef, 0x10, 0xc5, 0xef, 0x10, 0xc5, 0xef, 0x10,
+	0xc5, 0xef, 0x6b, 0xe6,
+	0xef, 0x3a, 0xde, 0xef, 0x10, 0xe6, 0xef, 0x10, 0xe6, 0xef, 0x10, 0xc5,
+	0xef, 0x10, 0xe6, 0xef,
+	0x10, 0xc5, 0xef, 0x10, 0xe6, 0xef, 0x10, 0xc5, 0xef, 0x19, 0xbd, 0xf7,
+	0x19, 0x7b, 0xbd, 0x00,
+	0x00, 0x00, 0x10, 0x21, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x08, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x08, 0x31, 0x5a, 0x00, 0x84, 0xbd, 0x00, 0x84, 0xbd, 0x00, 0x9c, 0xd6,
+	0x08, 0xad, 0xef, 0x08,
+	0xad, 0xef, 0x10, 0xc5, 0xef, 0x00, 0xbd, 0xef, 0x10, 0xc5, 0xef, 0x10,
+	0xc5, 0xef, 0x10, 0xe6,
+	0xef, 0x3a, 0xde, 0xef, 0x19, 0xbd, 0xf7, 0x19, 0xbd, 0xf7, 0x10, 0xe6,
+	0xef, 0x10, 0xc5, 0xef,
+	0x10, 0xe6, 0xef, 0x19, 0xbd, 0xf7, 0x00, 0x84, 0xbd, 0x10, 0x7b, 0x9c,
+	0x00, 0xbd, 0xef, 0x10,
+	0x73, 0x7b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08,
+	0x08, 0x10, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x10, 0x52, 0x7b, 0x19, 0x7b, 0xbd, 0x00, 0x9c, 0xd6,
+	0x19, 0x94, 0xce, 0x08,
+	0xad, 0xef, 0x08, 0xad, 0xef, 0x10, 0xc5, 0xef, 0x08, 0xad, 0xd6, 0x10,
+	0xe6, 0xef, 0x19, 0xbd,
+	0xf7, 0x6b, 0xe6, 0xef, 0x19, 0xbd, 0xf7, 0x10, 0xe6, 0xef, 0x10, 0xe6,
+	0xef, 0x10, 0xe6, 0xef,
+	0x10, 0xc5, 0xef, 0x00, 0x9c, 0xd6, 0x00, 0x84, 0xbd, 0x00, 0x9c, 0xd6,
+	0x19, 0x94, 0xce, 0x00,
+	0x9c, 0xd6, 0x10, 0x52, 0x7b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x10, 0x08, 0x31, 0x5a,
+	0x08, 0xa5, 0xad, 0x08,
+	0xad, 0xef, 0x00, 0xbd, 0xef, 0x10, 0xc5, 0xef, 0x10, 0xc5, 0xef, 0x10,
+	0xc5, 0xef, 0x10, 0xc5,
+	0xef, 0x10, 0xe6, 0xef, 0x19, 0xbd, 0xf7, 0x10, 0xe6, 0xef, 0x10, 0xc5,
+	0xef, 0x10, 0xc5, 0xef,
+	0x19, 0xbd, 0xf7, 0x10, 0x7b, 0x9c, 0x00, 0x84, 0xbd, 0x19, 0x94, 0xce,
+	0x08, 0xad, 0xd6, 0x00,
+	0x9c, 0xd6, 0x19, 0x94, 0xce, 0x08, 0x31, 0x3a, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x08, 0x08,
+	0x10, 0x31, 0x31, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08,
+	0x10, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x08, 0x31, 0x3a, 0x10,
+	0x52, 0x7b, 0x10, 0x7b, 0x9c, 0x08, 0xad, 0xef, 0x08, 0xad, 0xef, 0x10,
+	0xc5, 0xef, 0x10, 0xc5,
+	0xef, 0x3a, 0xde, 0xef, 0x10, 0xe6, 0xef, 0x10, 0xc5, 0xef, 0x10, 0xe6,
+	0xef, 0x08, 0xad, 0xd6,
+	0x10, 0x5a, 0x9c, 0x10, 0x5a, 0x9c, 0x00, 0x9c, 0xd6, 0x19, 0x94, 0xce,
+	0x00, 0x9c, 0xd6, 0x00,
+	0x9c, 0xd6, 0x19, 0x7b, 0xbd, 0x19, 0x7b, 0xbd, 0x08, 0x08, 0x10, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x08, 0x08, 0x10, 0x9c, 0x7b, 0x73, 0x6b, 0x5a, 0x73, 0x10, 0x29,
+	0x19, 0x00, 0x00, 0x00,
+	0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x08,
+	0x08, 0x10, 0x73, 0xa5, 0xad, 0x10, 0x52, 0x7b, 0x10, 0x52, 0x7b, 0x00,
+	0x84, 0xbd, 0x08, 0xa5,
+	0xad, 0x08, 0xad, 0xd6, 0x19, 0x94, 0xce, 0x00, 0x84, 0xbd, 0x10, 0x73,
+	0x7b, 0x10, 0x5a, 0x9c,
+	0x00, 0x84, 0xbd, 0x00, 0x9c, 0xd6, 0x00, 0x9c, 0xd6, 0x00, 0x9c, 0xd6,
+	0x00, 0x9c, 0xd6, 0x00,
+	0x84, 0xbd, 0x3a, 0xa5, 0xce, 0xce, 0xad, 0xad, 0xce, 0xde, 0xce, 0x6b,
+	0x5a, 0x73, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4a, 0x52, 0x4a, 0x6b, 0x7b,
+	0x9c, 0x9c, 0x7b, 0x73,
+	0x31, 0x31, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x31, 0x31, 0x29, 0xc5, 0xad, 0xd6, 0x52, 0xa5, 0xa5, 0x10,
+	0x5a, 0x9c, 0x10, 0x7b,
+	0x9c, 0x19, 0x94, 0xce, 0x08, 0xad, 0xd6, 0x08, 0xad, 0xd6, 0x19, 0x94,
+	0xce, 0x00, 0x9c, 0xd6,
+	0x00, 0x9c, 0xd6, 0x00, 0x84, 0xbd, 0x00, 0x84, 0xbd, 0x19, 0x94, 0xce,
+	0x00, 0x84, 0xbd, 0x19,
+	0x7b, 0xbd, 0xce, 0xad, 0xad, 0xce, 0xde, 0xce, 0xce, 0xde, 0xce, 0xa5,
+	0xb5, 0xb5, 0xa5, 0xb5,
+	0xb5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x21,
+	0x00, 0x6b, 0x7b, 0x73,
+	0x9c, 0x7b, 0x94, 0x6b, 0x7b, 0x73, 0x08, 0x08, 0x10, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x08, 0x08, 0x10, 0x4a, 0x52, 0x4a, 0xa5, 0xd6, 0xad, 0xc5,
+	0xad, 0xd6, 0x4a, 0x7b,
+	0x9c, 0x10, 0x5a, 0x9c, 0x00, 0x84, 0xbd, 0x00, 0x9c, 0xd6, 0x00, 0x84,
+	0xbd, 0x00, 0x9c, 0xd6,
+	0x19, 0x94, 0xce, 0x00, 0x84, 0xbd, 0x19, 0x94, 0xce, 0x00, 0x84, 0xbd,
+	0x19, 0x7b, 0xbd, 0x73,
+	0xa5, 0xad, 0xa5, 0xb5, 0xb5, 0xc5, 0xad, 0xd6, 0xa5, 0xb5, 0xb5, 0xe6,
+	0xde, 0xde, 0xce, 0xde,
+	0xce, 0xce, 0xad, 0xad, 0x10, 0x29, 0x19, 0x08, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x4a, 0x52, 0x4a, 0x6b, 0x7b, 0x73, 0x31, 0x31, 0x29, 0x08, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x08,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3a, 0x31, 0x4a, 0xce,
+	0xad, 0xad, 0xce, 0xde,
+	0xce, 0xa5, 0xb5, 0xb5, 0x73, 0xa5, 0xad, 0x10, 0x73, 0x7b, 0x10, 0x5a,
+	0x9c, 0x10, 0x7b, 0x9c,
+	0x10, 0x5a, 0xbd, 0x10, 0x7b, 0x9c, 0x10, 0x5a, 0x9c, 0x10, 0x5a, 0x9c,
+	0x19, 0x7b, 0xbd, 0xa5,
+	0xb5, 0xb5, 0xa5, 0xb5, 0xb5, 0xc5, 0xad, 0xd6, 0xa5, 0xd6, 0xad, 0xef,
+	0xde, 0xef, 0xef, 0xf7,
+	0xe6, 0xff, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xa5, 0x9c, 0xad, 0x08, 0x08,
+	0x10, 0x08, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x08, 0x10, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x08,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x4a,
+	0x52, 0x4a, 0xe6, 0xde,
+	0xde, 0xc5, 0xad, 0xd6, 0xa5, 0xb5, 0xb5, 0xce, 0xad, 0xad, 0x9c, 0xad,
+	0xce, 0x52, 0xa5, 0xa5,
+	0x10, 0x5a, 0x9c, 0x10, 0x7b, 0x9c, 0x10, 0x5a, 0x9c, 0x52, 0xa5, 0xa5,
+	0x73, 0xa5, 0xad, 0xc5,
+	0xad, 0xd6, 0xa5, 0xb5, 0xb5, 0xce, 0xde, 0xce, 0xce, 0xde, 0xce, 0xef,
+	0xde, 0xef, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xf7, 0xff, 0xef, 0xf7, 0xff, 0xef, 0xf7,
+	0xe6, 0x08, 0x08, 0x10,
+	0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x08, 0x00, 0x00, 0x08,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0xef, 0xf7,
+	0xe6, 0xef, 0xf7, 0xe6, 0xce, 0xde, 0xce, 0xce, 0xde, 0xce, 0xa5, 0xb5,
+	0xb5, 0xce, 0xde, 0xce,
+	0xce, 0xad, 0xad, 0xce, 0xde, 0xce, 0xa5, 0xb5, 0xb5, 0xce, 0xde, 0xce,
+	0xce, 0xad, 0xad, 0xc5,
+	0xad, 0xd6, 0xa5, 0xd6, 0xad, 0xce, 0xad, 0xad, 0xce, 0xde, 0xce, 0xe6,
+	0xde, 0xde, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff,
+	0xa5, 0xb5, 0xb5, 0x08, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x08, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x08, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08,
+	0x00, 0x00, 0x08, 0x08,
+	0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x10, 0x10, 0x21, 0x00, 0x00,
+	0x00, 0x00, 0x9c, 0xa5,
+	0x94, 0xff, 0xf7, 0xff, 0xff, 0xf7, 0xff, 0xef, 0xf7, 0xe6, 0xc5, 0xad,
+	0xd6, 0xa5, 0xb5, 0xb5,
+	0xce, 0xad, 0xad, 0xc5, 0xad, 0xd6, 0xa5, 0xb5, 0xb5, 0xce, 0xad, 0xad,
+	0xc5, 0xad, 0xd6, 0xa5,
+	0xd6, 0xad, 0xc5, 0xad, 0xd6, 0xce, 0xde, 0xce, 0xef, 0xde, 0xef, 0xef,
+	0xf7, 0xe6, 0xff, 0xf7,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x31, 0x31, 0x29, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x08, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x10, 0x08, 0x08, 0x10, 0x08,
+	0x08, 0x10, 0x10, 0x29,
+	0x19, 0xef, 0xde, 0xef, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xef, 0xf7, 0xe6,
+	0xc5, 0xad, 0xd6, 0xa5, 0xd6, 0xad, 0xa5, 0xb5, 0xb5, 0xce, 0xde, 0xce,
+	0xa5, 0xb5, 0xb5, 0xce,
+	0xde, 0xce, 0xce, 0xad, 0xad, 0xce, 0xde, 0xce, 0xef, 0xf7, 0xe6, 0xef,
+	0xf7, 0xff, 0xff, 0xf7,
+	0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe6, 0xde, 0xde,
+	0x08, 0x08, 0x10, 0x08,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x10, 0x21,
+	0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08,
+	0x00, 0x00, 0x08, 0x00,
+	0x00, 0xe6, 0xde, 0xde, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7,
+	0xff, 0xff, 0xff, 0xff,
+	0xef, 0xf7, 0xe6, 0xe6, 0xde, 0xde, 0xce, 0xad, 0xad, 0xc5, 0xad, 0xd6,
+	0xa5, 0xb5, 0xb5, 0xce,
+	0xad, 0xad, 0xce, 0xde, 0xce, 0xce, 0xe6, 0xef, 0xff, 0xf7, 0xff, 0xff,
+	0xf7, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xef, 0xf7, 0xe6,
+	0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff,
+	0xff, 0xff, 0xff, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x10, 0x00, 0x00, 0x00, 0x08,
+	0x00, 0x00, 0x08, 0x08,
+	0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x4a, 0x52, 0x4a, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xef, 0xf7, 0xe6,
+	0xe6, 0xde, 0xde, 0xef,
+	0xf7, 0xe6, 0xce, 0xe6, 0xef, 0xff, 0xf7, 0xff, 0xff, 0xf7, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff,
+	0xff, 0xef, 0xf7, 0xe6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7,
+	0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xa5, 0x9c, 0xad, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x08, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08,
+	0x00, 0x00, 0x08, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0xff, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff,
+	0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xef,
+	0xf7, 0xe6, 0xff, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7,
+	0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xef, 0xf7, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xe6, 0xde, 0xde, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x08, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x4a, 0x52, 0x4a, 0xef, 0xf7, 0xe6, 0xff, 0xff,
+	0xff, 0xef, 0xf7, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff,
+	0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff,
+	0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff,
+	0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x08,
+	0x08, 0x10, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x08, 0x08, 0x10, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x08, 0x00, 0x00, 0x08, 0x08, 0x10, 0xce, 0xde, 0xce, 0xef, 0xde,
+	0xef, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef,
+	0xf7, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff,
+	0xef, 0xf7, 0xe6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xef, 0xf7, 0xe6, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xe6, 0xef,
+	0xf7, 0xff, 0x31, 0x31,
+	0x29, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x08, 0x10, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x08, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x10, 0xce, 0xad,
+	0xad, 0xef, 0xf7, 0xe6,
+	0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff,
+	0xff, 0xff, 0xff, 0xef,
+	0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xef,
+	0xf7, 0xe6, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xe6, 0xff, 0xff,
+	0xff, 0xef, 0xf7, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff,
+	0xff, 0xff, 0xff, 0xef,
+	0xf7, 0xe6, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xef, 0xf7, 0xe6, 0xef,
+	0xde, 0xef, 0xef, 0xf7,
+	0xe6, 0x9c, 0xa5, 0x94, 0x08, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x21, 0x00,
+	0x00, 0x00, 0x00, 0x08,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08,
+	0x00, 0x00, 0x08, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x31, 0x31,
+	0x29, 0xa5, 0xb5, 0xb5,
+	0xce, 0xde, 0xce, 0xef, 0xf7, 0xe6, 0xef, 0xf7, 0xff, 0xff, 0xf7, 0xff,
+	0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xef, 0xf7, 0xe6, 0xef, 0xf7, 0xe6, 0xef, 0xde, 0xef, 0xef,
+	0xf7, 0xe6, 0xe6, 0xde,
+	0xde, 0xce, 0xe6, 0xef, 0xff, 0xf7, 0xff, 0xef, 0xf7, 0xe6, 0xff, 0xf7,
+	0xff, 0xef, 0xf7, 0xe6,
+	0xff, 0xff, 0xff, 0xef, 0xf7, 0xe6, 0xef, 0xf7, 0xff, 0xef, 0xf7, 0xe6,
+	0xef, 0xf7, 0xe6, 0xef,
+	0xde, 0xef, 0xce, 0xe6, 0xef, 0xe6, 0xde, 0xde, 0xe6, 0xde, 0xde, 0xce,
+	0xde, 0xce, 0xce, 0xde,
+	0xce, 0xe6, 0xde, 0xde, 0xce, 0xad, 0xad, 0x08, 0x08, 0x10, 0x00, 0x00,
+	0x00, 0x10, 0x21, 0x00,
+	0x00, 0x00, 0x00, 0x08, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x08, 0x08, 0x10, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08,
+	0x10, 0x6b, 0x5a, 0x4a,
+	0x73, 0xa5, 0xad, 0xce, 0xad, 0xad, 0xc5, 0xad, 0xd6, 0xe6, 0xde, 0xde,
+	0xe6, 0xde, 0xde, 0xff,
+	0xf7, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xe6, 0xef,
+	0xde, 0xef, 0xce, 0xde,
+	0xce, 0xef, 0xde, 0xef, 0xef, 0xf7, 0xe6, 0xef, 0xf7, 0xe6, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xef, 0xde, 0xef,
+	0xce, 0xde, 0xce, 0xc5,
+	0xad, 0xd6, 0xce, 0xde, 0xce, 0xce, 0xad, 0xad, 0xce, 0xde, 0xce, 0xa5,
+	0xb5, 0xb5, 0xc5, 0xad,
+	0xd6, 0xa5, 0xb5, 0xb5, 0xc5, 0xad, 0xd6, 0xef, 0xf7, 0xff, 0x4a, 0x52,
+	0x4a, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x08, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x08, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x08, 0x10, 0x00, 0x00,
+	0x00, 0x10, 0x29, 0x19,
+	0x6b, 0x5a, 0x73, 0xce, 0xad, 0xad, 0xce, 0xde, 0xce, 0xce, 0xde, 0xce,
+	0xef, 0xf7, 0xe6, 0xef,
+	0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xef, 0xf7,
+	0xff, 0xef, 0xde, 0xef, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf7,
+	0xff, 0xff, 0xff, 0xff,
+	0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff,
+	0xf7, 0xff, 0xef, 0xf7, 0xe6, 0xe6, 0xde, 0xde, 0xce, 0xde, 0xce, 0xc5,
+	0xad, 0xd6, 0xce, 0xde,
+	0xce, 0xce, 0xad, 0xad, 0xce, 0xde, 0xce, 0xa5, 0xb5, 0xb5, 0xce, 0xde,
+	0xce, 0xff, 0xf7, 0xff,
+	0x31, 0x31, 0x29, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x4a, 0x52, 0x4a,
+	0x31, 0x31, 0x29, 0x08,
+	0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x08, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x08, 0x00, 0x00,
+	0x08, 0x08, 0x10, 0xa5, 0x9c, 0xad, 0xce, 0xde, 0xce, 0xce, 0xe6, 0xef,
+	0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef,
+	0xf7, 0xff, 0xff, 0xf7,
+	0xff, 0xef, 0xf7, 0xe6, 0xef, 0xf7, 0xe6, 0xef, 0xf7, 0xff, 0xff, 0xff,
+	0xff, 0xef, 0xf7, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xef, 0xf7, 0xe6, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff,
+	0xff, 0xce, 0xe6, 0xef, 0xe6, 0xde, 0xde, 0xce, 0xde, 0xce, 0xc5, 0xad,
+	0xd6, 0xce, 0xad, 0xad,
+	0xe6, 0xde, 0xde, 0xff, 0xf7, 0xff, 0x08, 0x08, 0x10, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x08,
+	0x08, 0x10, 0x31, 0x31, 0x29, 0x3a, 0x10, 0x21, 0x08, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x08, 0x08, 0x10, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x10, 0x31, 0x31,
+	0x29, 0x00, 0x00, 0x00,
+	0x10, 0x21, 0x00, 0x6b, 0x5a, 0x73, 0xce, 0xde, 0xce, 0xff, 0xf7, 0xff,
+	0xff, 0xff, 0xff, 0xff,
+	0xf7, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff,
+	0xff, 0xef, 0xf7, 0xe6, 0xff, 0xff, 0xff, 0xff, 0xf7, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xef,
+	0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7,
+	0xe6, 0xce, 0xde, 0xce,
+	0xce, 0xde, 0xce, 0x9c, 0xad, 0xce, 0xef, 0xf7, 0xe6, 0xa5, 0x9c, 0xad,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x10, 0x3a, 0x31, 0x4a, 0x10,
+	0x29, 0x19, 0x08, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x08, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4a, 0x52,
+	0x4a, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x08, 0x08, 0x10, 0xe6, 0xde, 0xde, 0xef, 0xf7, 0xe6,
+	0xff, 0xf7, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xe6, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xef, 0xf7,
+	0xe6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7,
+	0xff, 0xff, 0xff, 0xff,
+	0xef, 0xf7, 0xe6, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff,
+	0xef, 0xf7, 0xe6, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xf7, 0xff, 0xef,
+	0xf7, 0xff, 0xff, 0xff,
+	0xff, 0xef, 0xf7, 0xe6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7,
+	0xe6, 0xff, 0xf7, 0xff,
+	0xef, 0xf7, 0xff, 0xef, 0xde, 0xef, 0xce, 0xe6, 0xad, 0xc5, 0xad, 0xd6,
+	0xff, 0xff, 0xff, 0x10,
+	0x29, 0x19, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x31, 0x31,
+	0x29, 0x08, 0x08, 0x10, 0x00, 0x00, 0x00, 0x10, 0x21, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x29,
+	0x19, 0x08, 0x08, 0x10,
+	0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6b, 0x5a, 0x73, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xef,
+	0xf7, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xef, 0xf7,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff,
+	0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7,
+	0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xde, 0xef,
+	0xce, 0xde, 0xce, 0xce,
+	0xde, 0xce, 0xce, 0xad, 0xad, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,
+	0x21, 0x00, 0x08, 0x08,
+	0x10, 0x08, 0x08, 0x10, 0x4a, 0x52, 0x4a, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x08, 0x08, 0x10, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00,
+	0x00, 0x4a, 0x52, 0x4a,
+	0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0xef, 0xf7, 0xe6,
+	0xef, 0xf7, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff,
+	0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xe6,
+	0xff, 0xff, 0xff, 0xef,
+	0xf7, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xef,
+	0xf7, 0xe6, 0xff, 0xff,
+	0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xe6, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff,
+	0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xe6,
+	0xff, 0xff, 0xff, 0xef,
+	0xde, 0xef, 0xce, 0xde, 0xce, 0xef, 0xf7, 0xff, 0x08, 0x08, 0x10, 0x00,
+	0x00, 0x00, 0x3a, 0x10,
+	0x21, 0x31, 0x31, 0x29, 0x31, 0x31, 0x29, 0x08, 0x08, 0x10, 0x10, 0x29,
+	0x19, 0x00, 0x00, 0x00,
+	0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x10, 0x29, 0x19,
+	0x3a, 0x10, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9c, 0x7b, 0x94,
+	0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xef, 0xf7,
+	0xe6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7,
+	0xff, 0xff, 0xff, 0xff,
+	0xef, 0xf7, 0xe6, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xf7, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7,
+	0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xe6, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xef,
+	0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf7, 0xff, 0xff, 0xff, 0xff, 0x4a,
+	0x52, 0x4a, 0x00, 0x00,
+	0x00, 0x10, 0x29, 0x19, 0x4a, 0x52, 0x4a, 0x31, 0x31, 0x29, 0x08, 0x08,
+	0x10, 0x3a, 0x31, 0x4a,
+	0x08, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x08,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x08, 0x00, 0x00,
+	0x4a, 0x52, 0x4a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x10,
+	0xef, 0xf7, 0xe6, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef,
+	0xf7, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xe6, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff,
+	0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf7, 0xff, 0xff, 0xff, 0xff,
+	0xef, 0xf7, 0xff, 0xff,
+	0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xe6, 0xff,
+	0xff, 0xff, 0xef, 0xf7,
+	0xff, 0xef, 0xf7, 0xe6, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xf7, 0xff,
+	0xff, 0xff, 0xff, 0xef, 0xf7, 0xe6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xef, 0xf7, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xce, 0xde,
+	0xce, 0x3a, 0x10, 0x21, 0x10, 0x29, 0x19, 0x3a, 0x31, 0x4a, 0x3a, 0x10,
+	0x21, 0x10, 0x21, 0x00,
+	0x08, 0x08, 0x10, 0x31, 0x31, 0x29, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x08,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x08, 0x08, 0x10, 0x3a, 0x10, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x9c, 0x7b, 0x94, 0xef,
+	0xf7, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xe6, 0xde, 0xde, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff,
+	0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xef, 0xf7, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xe6, 0xff, 0xff, 0xff, 0xef,
+	0xf7, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x08, 0x08, 0x10, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x4a, 0x52, 0x4a, 0x08, 0x08, 0x10,
+	0x00, 0x00, 0x00, 0x08,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x4a, 0x52, 0x4a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x08, 0x08, 0x10, 0xef,
+	0xf7, 0xe6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef,
+	0xf7, 0xe6, 0xff, 0xff,
+	0xff, 0xef, 0xf7, 0xe6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xe6, 0xef, 0xef, 0xf7, 0xe6,
+	0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xe6, 0xff, 0xff, 0xff, 0xef,
+	0xf7, 0xff, 0xff, 0xff,
+	0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff,
+	0xef, 0xf7, 0xe6, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff,
+	0xef, 0xf7, 0xff, 0xff,
+	0xf7, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0x3a, 0x10, 0x21, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x31, 0x31, 0x29,
+	0x08, 0x08, 0x10, 0x08,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x10, 0x00, 0x00, 0x00, 0x08,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x31, 0x31, 0x29, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x4a,
+	0x52, 0x4a, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff,
+	0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7,
+	0xff, 0xff, 0xff, 0xff,
+	0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf7, 0xff, 0xe6, 0xde, 0xde,
+	0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xef, 0xf7, 0xe6, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff,
+	0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xef, 0xf7, 0xe6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff,
+	0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x4a, 0x52,
+	0x4a, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x08, 0x08, 0x10, 0x31,
+	0x31, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x31, 0x31, 0x29, 0x08, 0x08, 0x10,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0xe6, 0xde, 0xde, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xef, 0xf7,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xe6,
+	0xe6, 0xde, 0xde, 0xef,
+	0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xf7,
+	0xff, 0xef, 0xf7, 0xe6, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff,
+	0xff, 0xef, 0xf7, 0xe6,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xef, 0xf7, 0xff, 0xef,
+	0xf7, 0xe6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xf7, 0xff, 0xef, 0xf7,
+	0xe6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7,
+	0xff, 0x9c, 0x7b, 0x94,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00,
+	0x08, 0x00, 0x00, 0x08,
+	0x08, 0x10, 0x10, 0x29, 0x19, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4a, 0x52, 0x4a,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x10, 0x29, 0x19, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef,
+	0xf7, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xe6, 0xff, 0xff, 0xff, 0xef, 0xf7,
+	0xe6, 0xff, 0xff, 0xff,
+	0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xe6, 0xff, 0xff, 0xff,
+	0xef, 0xf7, 0xe6, 0xce,
+	0xe6, 0xef, 0xff, 0xff, 0xff, 0xff, 0xf7, 0xff, 0xef, 0xf7, 0xe6, 0xff,
+	0xff, 0xff, 0xef, 0xf7,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff,
+	0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xe6, 0xff, 0xff, 0xff,
+	0xef, 0xf7, 0xe6, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff,
+	0xff, 0xff, 0xef, 0xf7,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff,
+	0xa5, 0xb5, 0xb5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00,
+	0x08, 0x08, 0x10, 0x00,
+	0x00, 0x00, 0x08, 0x08, 0x10, 0x3a, 0x10, 0x21, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x10, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x31, 0x31, 0x29, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x4a, 0x52, 0x4a, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xf7, 0xff,
+	0xff, 0xff, 0xff, 0xef, 0xf7, 0xe6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xf7, 0xff, 0xef,
+	0xf7, 0xe6, 0xe6, 0xde, 0xde, 0xff, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xf7,
+	0xff, 0xef, 0xf7, 0xe6,
+	0xff, 0xff, 0xff, 0xff, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xe6, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xef, 0xf7, 0xe6,
+	0xff, 0xff, 0xff, 0xce, 0xde, 0xce, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x08, 0x00, 0x00, 0x10, 0x29, 0x19, 0x08, 0x08, 0x10, 0x00,
+	0x00, 0x00, 0x08, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x10, 0x00, 0x00, 0x00, 0x08, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00,
+	0x08, 0x08, 0x10, 0x31,
+	0x31, 0x29, 0x08, 0x08, 0x10, 0x00, 0x00, 0x00, 0xce, 0xad, 0xad, 0xef,
+	0xf7, 0xff, 0xff, 0xff,
+	0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff,
+	0xff, 0xef, 0xf7, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xef, 0xf7, 0xff, 0xff,
+	0xff, 0xff, 0xef, 0xf7, 0xe6, 0xef, 0xde, 0xef, 0xef, 0xf7, 0xe6, 0xff,
+	0xff, 0xff, 0xef, 0xf7,
+	0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xe6, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff,
+	0xff, 0xff, 0xff, 0xef,
+	0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff,
+	0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xe6, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x10, 0x29, 0x19, 0x08,
+	0x00, 0x00, 0x08, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x08, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x10,
+	0x21, 0x00, 0x3a, 0x31, 0x4a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xce,
+	0xe6, 0xef, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xef, 0xf7, 0xe6,
+	0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff,
+	0xff, 0xf7, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xf7, 0xff, 0xce, 0xe6, 0xef, 0xe6, 0xde, 0xde, 0xef,
+	0xf7, 0xff, 0xef, 0xf7,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xef, 0xf7, 0xe6,
+	0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff,
+	0xff, 0xff, 0xef, 0xf7,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xe6, 0xff, 0xff,
+	0xff, 0xef, 0xf7, 0xff,
+	0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x3a,
+	0x31, 0x4a, 0x08, 0x08,
+	0x10, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00,
+	0x00, 0x08, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00,
+	0x08, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x08, 0x08, 0x10, 0x4a, 0x52, 0x4a, 0x00, 0x00, 0x00, 0x08,
+	0x00, 0x00, 0xef, 0xf7,
+	0xe6, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xef, 0xf7, 0xe6,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xef, 0xf7, 0xe6, 0xff, 0xff, 0xff, 0xe6, 0xde, 0xde, 0xe6,
+	0xde, 0xde, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xef, 0xf7, 0xff, 0xff,
+	0xff, 0xff, 0xef, 0xf7, 0xe6, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xe6, 0xff, 0xf7, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xef, 0xf7, 0xe6, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08,
+	0x00, 0x00, 0x4a, 0x52,
+	0x4a, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x08, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x3a, 0x10, 0x21, 0x4a, 0x52, 0x4a, 0x00,
+	0x00, 0x00, 0x08, 0x08,
+	0x10, 0xef, 0xf7, 0xe6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7,
+	0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xe6, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xef,
+	0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce,
+	0xe6, 0xef, 0xe6, 0xde,
+	0xde, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff,
+	0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xe6, 0xff,
+	0xff, 0xff, 0xff, 0xff,
+	0xff, 0xef, 0xf7, 0xe6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xef, 0xf7, 0xff,
+	0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff,
+	0xff, 0xf7, 0xff, 0xff,
+	0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08,
+	0x00, 0x00, 0x08, 0x00,
+	0x00, 0x10, 0x29, 0x19, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x08, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x08, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x08,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x10, 0x3a, 0x31, 0x4a, 0x6b,
+	0x7b, 0x73, 0x08, 0x00,
+	0x00, 0x10, 0x29, 0x19, 0xff, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xef,
+	0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff,
+	0xff, 0xff, 0xe6, 0xde,
+	0xde, 0xef, 0xf7, 0xe6, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xef, 0xf7, 0xe6,
+	0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf7, 0xff, 0xef, 0xf7, 0xe6,
+	0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xef, 0xf7, 0xe6, 0xff, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7,
+	0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xe6, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xef, 0xf7, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x10, 0x29, 0x19, 0x08, 0x08, 0x10, 0x08, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x08, 0x00, 0x00,
+	0x08, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x10,
+	0x29, 0x19, 0x6b, 0x5a,
+	0x73, 0x08, 0x00, 0x00, 0x10, 0x29, 0x19, 0xff, 0xf7, 0xff, 0xff, 0xff,
+	0xff, 0xef, 0xf7, 0xe6,
+	0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xef,
+	0xf7, 0xe6, 0xff, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xe6, 0xff,
+	0xff, 0xff, 0xff, 0xff,
+	0xff, 0xe6, 0xde, 0xde, 0xe6, 0xde, 0xde, 0xff, 0xff, 0xff, 0xef, 0xf7,
+	0xe6, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xef,
+	0xf7, 0xff, 0xff, 0xff,
+	0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xef, 0xf7, 0xe6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x08,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x08, 0x08, 0x10, 0x31, 0x31, 0x29, 0x08, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x08, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x08, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x08, 0x00,
+	0x00, 0x31, 0x31, 0x29, 0x08, 0x00, 0x00, 0x31, 0x31, 0x29, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xef, 0xf7, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xf7,
+	0xff, 0xef, 0xf7, 0xff, 0xe6, 0xde, 0xde, 0xef, 0xf7, 0xe6, 0xef, 0xf7,
+	0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xef,
+	0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xe6, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff,
+	0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff,
+	0xff, 0xff, 0xff, 0xef,
+	0xf7, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xe6, 0xe6, 0xde, 0xde, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x10, 0x10, 0x29, 0x19, 0x08, 0x08,
+	0x10, 0x08, 0x00, 0x00,
+	0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x08, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x08, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3a, 0x31, 0x4a, 0x31, 0x31,
+	0x29, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff,
+	0xef, 0xf7, 0xe6, 0xff,
+	0xff, 0xff, 0xff, 0xf7, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe6, 0xde, 0xde, 0xce, 0xe6,
+	0xef, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff,
+	0xff, 0xff, 0xff, 0xef,
+	0xf7, 0xe6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xe6, 0xff,
+	0xff, 0xff, 0xef, 0xf7,
+	0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xe6, 0xef, 0xf7, 0xff, 0xff, 0xf7,
+	0xff, 0xff, 0xff, 0xff,
+	0xef, 0xf7, 0xe6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff,
+	0xff, 0xf7, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xa5,
+	0xb5, 0xb5, 0x00, 0x00,
+	0x00, 0x10, 0x21, 0x00, 0x3a, 0x31, 0x4a, 0x10, 0x29, 0x19, 0x3a, 0x08,
+	0x00, 0x08, 0x08, 0x10,
+	0x08, 0x08, 0x10, 0x31, 0x31, 0x29, 0x31, 0x31, 0x29, 0x10, 0x29, 0x19,
+	0x08, 0x08, 0x10, 0x00,
+	0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x10, 0x10,
+	0x7b, 0x9c, 0x10, 0xc5,
+	0xef, 0x10, 0xc5, 0xef, 0x10, 0x7b, 0x9c, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x4a, 0x52, 0x4a,
+	0xef, 0xf7, 0xe6, 0xff, 0xf7, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xef,
+	0xf7, 0xe6, 0xff, 0xf7,
+	0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe6, 0xde,
+	0xde, 0xef, 0xf7, 0xe6,
+	0xff, 0xf7, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xe6,
+	0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xf7, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xef,
+	0xf7, 0xe6, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0x6b, 0x5a,
+	0x4a, 0x08, 0x08, 0x10, 0x08, 0x08, 0x10, 0x08, 0x00, 0x00, 0x08, 0x00,
+	0x00, 0x08, 0x08, 0x10,
+	0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x08, 0x10, 0x00, 0x00, 0x00,
+	0x3a, 0x10, 0x21, 0x6b,
+	0x5a, 0x73, 0x10, 0x29, 0x19, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19,
+	0x94, 0xce, 0x08, 0xad,
+	0xef, 0x19, 0xbd, 0xf7, 0x00, 0xbd, 0xf7, 0x19, 0xbd, 0xf7, 0x08, 0xad,
+	0xd6, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x4a, 0x5a, 0x73, 0xef, 0xf7, 0xe6, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xef,
+	0xf7, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xe6, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7,
+	0xff, 0xe6, 0xde, 0xde,
+	0xef, 0xde, 0xef, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xef,
+	0xf7, 0xff, 0xff, 0xff,
+	0xff, 0xef, 0xf7, 0xe6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7,
+	0xff, 0xff, 0xff, 0xff,
+	0xef, 0xf7, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xf7, 0xff, 0xff, 0xff, 0xff,
+	0xef, 0xf7, 0xe6, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xe6, 0xef, 0xce,
+	0xe6, 0xef, 0xce, 0xe6,
+	0xef, 0x08, 0x10, 0x42, 0x10, 0x29, 0x19, 0x08, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x31, 0x31, 0x29, 0x4a, 0x52, 0x4a, 0x08, 0x08, 0x10, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19,
+	0x7b, 0xbd, 0x00, 0x9c,
+	0xd6, 0x10, 0xc5, 0xef, 0x00, 0xbd, 0xf7, 0x19, 0xbd, 0xf7, 0x00, 0xbd,
+	0xf7, 0x19, 0xbd, 0xf7,
+	0x00, 0x9c, 0xd6, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x4a, 0x52, 0x4a,
+	0xef, 0xde, 0xef, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xef, 0xf7,
+	0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7,
+	0xe6, 0xff, 0xff, 0xff,
+	0xe6, 0xde, 0xde, 0xef, 0xf7, 0xe6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xef, 0xf7, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef,
+	0xf7, 0xe6, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xef, 0xf7, 0xff, 0xef, 0xf7, 0xff, 0x08, 0xad, 0xd6, 0x19,
+	0xbd, 0xf7, 0x00, 0xbd,
+	0xef, 0x10, 0xc5, 0xef, 0x10, 0xc5, 0xef, 0x08, 0x08, 0x10, 0x08, 0x08,
+	0x10, 0x08, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x08, 0x08, 0x10, 0x31, 0x31, 0x29, 0x10, 0x29, 0x19, 0x3a,
+	0x10, 0x21, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x84,
+	0xbd, 0x08, 0xad, 0xd6, 0x08, 0xad, 0xef, 0x08, 0xad, 0xef, 0x10, 0xc5,
+	0xef, 0x00, 0xbd, 0xf7,
+	0x10, 0xc5, 0xef, 0x00, 0xbd, 0xf7, 0x19, 0x7b, 0xbd, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x31,
+	0x31, 0x29, 0xe6, 0xde, 0xde, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff,
+	0xff, 0xff, 0xef, 0xf7,
+	0xe6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xce, 0xe6, 0xef, 0xef, 0xf7, 0xe6, 0xef, 0xf7, 0xff,
+	0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xef, 0xf7, 0xe6, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xef, 0xf7, 0xe6,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xe6, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xef,
+	0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xe6, 0xef, 0x08,
+	0xad, 0xef, 0x00, 0xbd,
+	0xf7, 0x10, 0xe6, 0xef, 0x10, 0xc5, 0xef, 0x10, 0xe6, 0xef, 0x08, 0x08,
+	0x10, 0x08, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x08,
+	0x00, 0x00, 0x08, 0x00, 0x00, 0x10, 0x29, 0x19, 0x10, 0x29, 0x19, 0x00,
+	0x00, 0x00, 0x00, 0x84,
+	0xbd, 0x10, 0xe6, 0xef, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x19, 0x7b,
+	0xbd, 0x00, 0x9c, 0xd6, 0x08, 0xad, 0xef, 0x10, 0xc5, 0xef, 0x19, 0xbd,
+	0xf7, 0x00, 0xbd, 0xf7,
+	0x08, 0xad, 0xef, 0x19, 0xbd, 0xf7, 0x00, 0xbd, 0xef, 0x10, 0xc5, 0xef,
+	0x10, 0x5a, 0x9c, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x29, 0x19, 0xce, 0xde, 0xce, 0xff,
+	0xf7, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7,
+	0xe6, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe6, 0xde, 0xde, 0xef, 0xde, 0xef,
+	0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xef, 0xf7,
+	0xe6, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xef,
+	0xf7, 0xe6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xce,
+	0xe6, 0xef, 0x00, 0x9c,
+	0xd6, 0x19, 0xbd, 0xf7, 0x00, 0xbd, 0xf7, 0x10, 0xc5, 0xef, 0x08, 0xad,
+	0xd6, 0x08, 0x08, 0x10,
+	0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x08, 0x08, 0x10, 0x00,
+	0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x08, 0x10, 0x08, 0x00, 0x00, 0x08,
+	0x08, 0x10, 0x08, 0x31,
+	0x3a, 0x10, 0xc5, 0xef, 0x10, 0xc5, 0xef, 0x10, 0xc5, 0xef, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x84,
+	0xbd, 0x19, 0x94, 0xce, 0x08, 0xad, 0xef, 0x08, 0xad, 0xef, 0x08, 0xad,
+	0xef, 0x00, 0xbd, 0xef,
+	0x19, 0xbd, 0xf7, 0x19, 0xbd, 0xf7, 0x00, 0xbd, 0xf7, 0x19, 0xbd, 0xf7,
+	0x10, 0xc5, 0xef, 0x00,
+	0xbd, 0xef, 0x08, 0x31, 0x3a, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x9c, 0xa5,
+	0x94, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff,
+	0xef, 0xf7, 0xe6, 0xef,
+	0xf7, 0xe6, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xe6, 0xff, 0xff, 0xff, 0xef,
+	0xf7, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xef, 0xf7, 0xff,
+	0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xce, 0xe6,
+	0xef, 0x08, 0xad, 0xd6, 0x00, 0xbd, 0xef, 0x19, 0xbd, 0xf7, 0x00, 0xbd,
+	0xef, 0x19, 0x94, 0xce,
+	0x08, 0x08, 0x10, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x08, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x19, 0x94, 0xce, 0x10, 0xc5, 0xef, 0x00, 0xbd, 0xef, 0x10, 0xc5,
+	0xef, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x84, 0xbd, 0x00,
+	0x84, 0xbd, 0x19, 0x94, 0xce, 0x08, 0xad, 0xef, 0x00, 0x84, 0xbd, 0x19,
+	0x94, 0xce, 0x00, 0x84,
+	0xbd, 0x08, 0xad, 0xd6, 0x00, 0x9c, 0xd6, 0x08, 0xad, 0xef, 0x10, 0xc5,
+	0xef, 0x19, 0xbd, 0xf7,
+	0x19, 0xbd, 0xf7, 0x00, 0xbd, 0xf7, 0x00, 0xbd, 0xef, 0x19, 0xbd, 0xf7,
+	0x00, 0xbd, 0xf7, 0x00,
+	0xbd, 0xf7, 0x10, 0xc5, 0xef, 0x08, 0xad, 0xd6, 0x08, 0x08, 0x10, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x4a, 0x52, 0x4a, 0xff, 0xf7, 0xff, 0xff, 0xff,
+	0xff, 0xef, 0xf7, 0xe6,
+	0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xef, 0xf7, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xef, 0xf7,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff,
+	0xff, 0xef, 0xf7, 0xe6,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xef, 0xf7, 0xff, 0xff,
+	0xff, 0xff, 0xef, 0xf7, 0xe6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef,
+	0xf7, 0xe6, 0xef, 0xde,
+	0xef, 0x9c, 0xde, 0xd6, 0x08, 0xad, 0xef, 0x08, 0xad, 0xef, 0x10, 0xc5,
+	0xef, 0x08, 0xad, 0xef,
+	0x00, 0x84, 0xbd, 0x08, 0x31, 0x3a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x08, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x21, 0x00, 0x00, 0x00, 0x00, 0x08,
+	0x00, 0x00, 0x08, 0x00,
+	0x00, 0x10, 0x5a, 0x9c, 0x08, 0xad, 0xd6, 0x00, 0xbd, 0xef, 0x10, 0xc5,
+	0xef, 0x10, 0xc5, 0xef,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x19,
+	0x94, 0xce, 0x08, 0xad, 0xef, 0x08, 0xad, 0xd6, 0x08, 0xad, 0xef, 0x08,
+	0xad, 0xef, 0x08, 0xad,
+	0xef, 0x08, 0xad, 0xef, 0x08, 0xad, 0xef, 0x08, 0xad, 0xef, 0x10, 0xc5,
+	0xef, 0x00, 0xbd, 0xf7,
+	0x19, 0xbd, 0xf7, 0x00, 0xbd, 0xef, 0x00, 0xbd, 0xf7, 0x19, 0xbd, 0xf7,
+	0x10, 0xc5, 0xef, 0x00,
+	0xbd, 0xf7, 0x19, 0xbd, 0xf7, 0x10, 0xc5, 0xef, 0x00, 0xbd, 0xf7, 0x19,
+	0x7b, 0xbd, 0x00, 0x00,
+	0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x31, 0x31,
+	0x29, 0xce, 0xe6, 0xef,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff,
+	0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff,
+	0xff, 0xff, 0xef, 0xf7,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xe6,
+	0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf7, 0xff, 0xff,
+	0xff, 0xff, 0xce, 0xe6,
+	0xef, 0xce, 0xad, 0xad, 0x9c, 0xad, 0xce, 0x19, 0x94, 0xce, 0x08, 0xad,
+	0xef, 0x00, 0xbd, 0xef,
+	0x19, 0x94, 0xce, 0x00, 0x9c, 0xd6, 0x10, 0x5a, 0x9c, 0x08, 0x08, 0x10,
+	0x00, 0x00, 0x00, 0x08,
+	0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x10, 0x00,
+	0x00, 0x00, 0x08, 0x08,
+	0x10, 0x10, 0x73, 0x7b, 0x00, 0x9c, 0xd6, 0x00, 0xbd, 0xef, 0x10, 0xc5,
+	0xef, 0x08, 0xad, 0xef,
+	0x00, 0xbd, 0xf7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x84, 0xbd, 0x00, 0x9c, 0xd6, 0x08, 0xad, 0xef, 0x10, 0xc5, 0xef, 0x08,
+	0xad, 0xef, 0x10, 0xc5,
+	0xef, 0x08, 0xad, 0xef, 0x10, 0xc5, 0xef, 0x19, 0xbd, 0xf7, 0x19, 0xbd,
+	0xf7, 0x19, 0xbd, 0xf7,
+	0x00, 0xbd, 0xf7, 0x10, 0xc5, 0xef, 0x19, 0xbd, 0xf7, 0x00, 0xbd, 0xf7,
+	0x19, 0xbd, 0xf7, 0x00,
+	0xbd, 0xf7, 0x10, 0xc5, 0xef, 0x08, 0xad, 0xef, 0x19, 0xbd, 0xf7, 0x00,
+	0xbd, 0xef, 0x10, 0xce,
+	0xce, 0x08, 0x31, 0x3a, 0x08, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x08, 0x08, 0x10, 0xce, 0xde, 0xce, 0xff, 0xf7, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xf7, 0xff, 0xff, 0xff,
+	0xff, 0xef, 0xf7, 0xe6, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xe6, 0xff, 0xff,
+	0xff, 0xef, 0xf7, 0xff,
+	0xff, 0xf7, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff,
+	0xff, 0xff, 0xef, 0xf7,
+	0xe6, 0xc5, 0xad, 0xd6, 0xce, 0xde, 0xce, 0x9c, 0xad, 0xce, 0x08, 0xad,
+	0xd6, 0x08, 0xad, 0xef,
+	0x08, 0xad, 0xef, 0x08, 0xad, 0xef, 0x00, 0x9c, 0xd6, 0x19, 0x7b, 0xbd,
+	0x10, 0x7b, 0x9c, 0x08,
+	0x31, 0x5a, 0x08, 0x31, 0x3a, 0x08, 0x08, 0x10, 0x08, 0x31, 0x3a, 0x08,
+	0x31, 0x3a, 0x10, 0x5a,
+	0x9c, 0x00, 0x84, 0xbd, 0x00, 0x9c, 0xd6, 0x19, 0x94, 0xce, 0x00, 0xbd,
+	0xef, 0x08, 0xad, 0xef,
+	0x10, 0xc5, 0xef, 0x19, 0xbd, 0xf7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x19, 0x7b, 0xbd, 0x19, 0x94, 0xce, 0x08, 0xad, 0xef, 0x08,
+	0xad, 0xef, 0x00, 0xbd,
+	0xef, 0x19, 0xbd, 0xf7, 0x10, 0xc5, 0xef, 0x00, 0xbd, 0xf7, 0x10, 0xc5,
+	0xef, 0x00, 0xbd, 0xf7,
+	0x00, 0xbd, 0xef, 0x19, 0xbd, 0xf7, 0x08, 0xad, 0xef, 0x00, 0xbd, 0xf7,
+	0x19, 0xbd, 0xf7, 0x00,
+	0xbd, 0xef, 0x19, 0xbd, 0xf7, 0x00, 0xbd, 0xf7, 0x19, 0xbd, 0xf7, 0x00,
+	0xbd, 0xf7, 0x10, 0xc5,
+	0xef, 0x00, 0xbd, 0xf7, 0x19, 0x94, 0xce, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x08, 0x00, 0x00,
+	0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9c, 0x7b, 0x94,
+	0xff, 0xff, 0xff, 0xef,
+	0xf7, 0xe6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff,
+	0xff, 0xff, 0xef, 0xf7,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xf7, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xef,
+	0xf7, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xe6, 0xff, 0xf7, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xa5, 0xb5, 0xb5, 0xce, 0xde, 0xce, 0x9c, 0xad,
+	0xce, 0x19, 0x94, 0xce,
+	0x08, 0xad, 0xd6, 0x10, 0xc5, 0xef, 0x08, 0xad, 0xd6, 0x00, 0x9c, 0xd6,
+	0x00, 0x9c, 0xd6, 0x00,
+	0x84, 0xbd, 0x00, 0x84, 0xbd, 0x00, 0x84, 0xbd, 0x00, 0x84, 0xbd, 0x19,
+	0x7b, 0xbd, 0x00, 0x84,
+	0xbd, 0x00, 0x84, 0xbd, 0x00, 0x84, 0xbd, 0x08, 0xad, 0xef, 0x08, 0xad,
+	0xef, 0x10, 0xc5, 0xef,
+	0x19, 0xbd, 0xf7, 0x08, 0xad, 0xef, 0x00, 0xbd, 0xef, 0x08, 0xad, 0xef,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x84, 0xbd, 0x08, 0xad, 0xd6, 0x08,
+	0xad, 0xef, 0x10, 0xc5,
+	0xef, 0x19, 0xbd, 0xf7, 0x00, 0xbd, 0xf7, 0x08, 0xad, 0xef, 0x19, 0xbd,
+	0xf7, 0x00, 0xbd, 0xf7,
+	0x19, 0xbd, 0xf7, 0x19, 0xbd, 0xf7, 0x00, 0xbd, 0xf7, 0x19, 0xbd, 0xf7,
+	0x00, 0xbd, 0xef, 0x19,
+	0xbd, 0xf7, 0x00, 0xbd, 0xf7, 0x10, 0xc5, 0xef, 0x08, 0xad, 0xef, 0x00,
+	0xbd, 0xf7, 0x19, 0xbd,
+	0xf7, 0x00, 0xbd, 0xf7, 0x10, 0xc5, 0xef, 0x00, 0xbd, 0xef, 0x10, 0x52,
+	0x7b, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x6b,
+	0x7b, 0x73, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xef, 0xf7,
+	0xe6, 0xef, 0xf7, 0xff,
+	0xff, 0xff, 0xff, 0xef, 0xf7, 0xe6, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff,
+	0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff,
+	0xff, 0xff, 0xef, 0xf7,
+	0xe6, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xe6, 0xce, 0xad, 0xad, 0xce, 0xde,
+	0xce, 0xa5, 0xb5, 0xb5,
+	0x00, 0x9c, 0xd6, 0x08, 0xad, 0xef, 0x08, 0xad, 0xef, 0x08, 0xad, 0xef,
+	0x19, 0x94, 0xce, 0x00,
+	0x9c, 0xd6, 0x19, 0x94, 0xce, 0x00, 0x84, 0xbd, 0x19, 0x94, 0xce, 0x00,
+	0x84, 0xbd, 0x00, 0x84,
+	0xbd, 0x00, 0x84, 0xbd, 0x19, 0x94, 0xce, 0x08, 0xad, 0xef, 0x08, 0xad,
+	0xef, 0x19, 0xbd, 0xf7,
+	0x00, 0xbd, 0xf7, 0x00, 0xbd, 0xf7, 0x19, 0xbd, 0xf7, 0x10, 0xc5, 0xef,
+	0x10, 0xc5, 0xef, 0x19,
+	0x94, 0xce, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x7b, 0xbd, 0x19,
+	0x94, 0xce, 0x08, 0xad,
+	0xef, 0x08, 0xad, 0xef, 0x10, 0xc5, 0xef, 0x00, 0xbd, 0xf7, 0x19, 0xbd,
+	0xf7, 0x00, 0xbd, 0xf7,
+	0x19, 0xbd, 0xf7, 0x00, 0xbd, 0xef, 0x00, 0xbd, 0xf7, 0x10, 0xc5, 0xef,
+	0x00, 0xbd, 0xf7, 0x08,
+	0xad, 0xef, 0x10, 0xc5, 0xef, 0x00, 0xbd, 0xf7, 0x19, 0xbd, 0xf7, 0x00,
+	0xbd, 0xf7, 0x19, 0xbd,
+	0xf7, 0x00, 0xbd, 0xf7, 0x19, 0xbd, 0xf7, 0x10, 0xc5, 0xef, 0x10, 0xc5,
+	0xef, 0x08, 0xad, 0xd6,
+	0x08, 0x08, 0x10, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0xce, 0xde, 0xce, 0xff, 0xff, 0xff, 0xef,
+	0xf7, 0xe6, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xe6, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xef,
+	0xf7, 0xe6, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xf7, 0xff, 0xef, 0xf7, 0xff, 0xce, 0xde,
+	0xce, 0xc5, 0xad, 0xd6,
+	0xa5, 0xb5, 0xb5, 0x19, 0x94, 0xce, 0x00, 0x9c, 0xd6, 0x08, 0xad, 0xd6,
+	0x08, 0xad, 0xef, 0x08,
+	0xad, 0xef, 0x08, 0xad, 0xef, 0x00, 0x9c, 0xd6, 0x00, 0x9c, 0xd6, 0x00,
+	0x9c, 0xd6, 0x00, 0x9c,
+	0xd6, 0x19, 0x94, 0xce, 0x08, 0xad, 0xef, 0x08, 0xad, 0xd6, 0x08, 0xad,
+	0xef, 0x19, 0xbd, 0xf7,
+	0x00, 0xbd, 0xef, 0x19, 0xbd, 0xf7, 0x10, 0xc5, 0xef, 0x00, 0xbd, 0xf7,
+	0x10, 0xc5, 0xef, 0x08,
+	0xad, 0xef, 0x08, 0xad, 0xef, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x84, 0xbd, 0x00, 0x9c,
+	0xd6, 0x08, 0xad, 0xd6, 0x08, 0xad, 0xef, 0x19, 0xbd, 0xf7, 0x19, 0xbd,
+	0xf7, 0x00, 0xbd, 0xef,
+	0x19, 0xbd, 0xf7, 0x00, 0xbd, 0xef, 0x19, 0xbd, 0xf7, 0x19, 0xbd, 0xf7,
+	0x00, 0xbd, 0xf7, 0x19,
+	0xbd, 0xf7, 0x00, 0xbd, 0xf7, 0x19, 0xbd, 0xf7, 0x00, 0xbd, 0xf7, 0x10,
+	0xc5, 0xef, 0x00, 0xbd,
+	0xf7, 0x10, 0xc5, 0xef, 0x19, 0xbd, 0xf7, 0x00, 0xbd, 0xf7, 0x00, 0xbd,
+	0xf7, 0x19, 0xbd, 0xf7,
+	0x00, 0xbd, 0xef, 0x19, 0x7b, 0xbd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x08, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6b, 0x5a, 0x73, 0xff,
+	0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xef, 0xf7, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef,
+	0xf7, 0xe6, 0xff, 0xff,
+	0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7,
+	0xe6, 0xce, 0xde, 0xce,
+	0xa5, 0xb5, 0xb5, 0x9c, 0xad, 0xce, 0x00, 0x84, 0xbd, 0x00, 0x9c, 0xd6,
+	0x08, 0xad, 0xef, 0x10,
+	0xc5, 0xef, 0x08, 0xad, 0xef, 0x08, 0xad, 0xd6, 0x08, 0xad, 0xef, 0x19,
+	0x94, 0xce, 0x08, 0xad,
+	0xef, 0x19, 0x94, 0xce, 0x08, 0xad, 0xef, 0x08, 0xad, 0xd6, 0x08, 0xad,
+	0xef, 0x00, 0xbd, 0xef,
+	0x10, 0xc5, 0xef, 0x00, 0xbd, 0xf7, 0x19, 0xbd, 0xf7, 0x08, 0xad, 0xef,
+	0x19, 0xbd, 0xf7, 0x00,
+	0xbd, 0xf7, 0x10, 0xc5, 0xef, 0x08, 0xad, 0xef, 0x08, 0xad, 0xd6, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x10, 0x7b, 0xe6, 0x08, 0xad, 0xd6, 0x08, 0xad, 0xef, 0x00, 0xbd,
+	0xef, 0x00, 0xbd, 0xf7,
+	0x19, 0xbd, 0xf7, 0x00, 0xbd, 0xef, 0x19, 0xbd, 0xf7, 0x00, 0xbd, 0xf7,
+	0x00, 0xbd, 0xf7, 0x08,
+	0xad, 0xef, 0x10, 0xc5, 0xef, 0x00, 0xbd, 0xf7, 0x19, 0xbd, 0xf7, 0x08,
+	0xad, 0xef, 0x00, 0xbd,
+	0xf7, 0x19, 0xbd, 0xf7, 0x08, 0xad, 0xef, 0x10, 0xc5, 0xef, 0x00, 0xbd,
+	0xf7, 0x19, 0xbd, 0xf7,
+	0x10, 0xc5, 0xef, 0x10, 0xe6, 0xef, 0x00, 0xbd, 0xef, 0x08, 0x31, 0x3a,
+	0x00, 0x00, 0x00, 0x08,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4a,
+	0x52, 0x4a, 0xff, 0xff,
+	0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xef, 0xf7, 0xe6, 0xff,
+	0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xf7, 0xff,
+	0xe6, 0xde, 0xde, 0xc5, 0xad, 0xd6, 0x29, 0x5a, 0x4a, 0x00, 0x84, 0xbd,
+	0x19, 0x94, 0xce, 0x08,
+	0xad, 0xd6, 0x08, 0xad, 0xef, 0x10, 0xc5, 0xef, 0x08, 0xad, 0xef, 0x00,
+	0xbd, 0xef, 0x08, 0xad,
+	0xef, 0x08, 0xad, 0xef, 0x08, 0xad, 0xd6, 0x08, 0xad, 0xef, 0x08, 0xad,
+	0xef, 0x08, 0xad, 0xef,
+	0x19, 0xbd, 0xf7, 0x08, 0xad, 0xef, 0x00, 0xbd, 0xef, 0x19, 0xbd, 0xf7,
+	0x00, 0xbd, 0xf7, 0x00,
+	0xbd, 0xef, 0x19, 0xbd, 0xf7, 0x00, 0xbd, 0xf7, 0x19, 0xbd, 0xf7, 0x19,
+	0xbd, 0xf7, 0x00, 0xbd,
+	0xef, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x19, 0x94, 0xce, 0x08, 0xad, 0xd6, 0x08, 0xad,
+	0xef, 0x19, 0xbd, 0xf7,
+	0x19, 0xbd, 0xf7, 0x00, 0xbd, 0xef, 0x19, 0xbd, 0xf7, 0x00, 0xbd, 0xf7,
+	0x10, 0xc5, 0xef, 0x19,
+	0xbd, 0xf7, 0x00, 0xbd, 0xf7, 0x19, 0xbd, 0xf7, 0x00, 0xbd, 0xf7, 0x10,
+	0xc5, 0xef, 0x19, 0xbd,
+	0xf7, 0x00, 0xbd, 0xf7, 0x19, 0xbd, 0xf7, 0x00, 0xbd, 0xf7, 0x19, 0xbd,
+	0xf7, 0x00, 0xbd, 0xf7,
+	0x10, 0xc5, 0xef, 0x08, 0xad, 0xef, 0x00, 0xbd, 0xf7, 0x10, 0xc5, 0xef,
+	0x08, 0xad, 0xd6, 0x08,
+	0x08, 0x10, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x9c, 0xa5,
+	0x94, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xf7,
+	0xff, 0xef, 0xf7, 0xe6,
+	0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xf7, 0xff, 0xef, 0xf7, 0xe6,
+	0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xef, 0xf7,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7,
+	0xe6, 0xff, 0xf7, 0xff,
+	0xef, 0xf7, 0xff, 0xce, 0xde, 0xce, 0x4a, 0x52, 0x4a, 0x08, 0x31, 0x5a,
+	0x00, 0x84, 0xbd, 0x00,
+	0x9c, 0xd6, 0x08, 0xad, 0xef, 0x08, 0xad, 0xef, 0x19, 0xbd, 0xf7, 0x10,
+	0xc5, 0xef, 0x08, 0xad,
+	0xef, 0x10, 0xc5, 0xef, 0x08, 0xad, 0xef, 0x00, 0xbd, 0xef, 0x10, 0xc5,
+	0xef, 0x08, 0xad, 0xef,
+	0x00, 0xbd, 0xef, 0x10, 0xc5, 0xef, 0x19, 0xbd, 0xf7, 0x00, 0xbd, 0xf7,
+	0x19, 0xbd, 0xf7, 0x00,
+	0xbd, 0xf7, 0x19, 0xbd, 0xf7, 0x00, 0xbd, 0xef, 0x19, 0xbd, 0xf7, 0x00,
+	0xbd, 0xef, 0x00, 0xbd,
+	0xf7, 0x10, 0xc5, 0xef, 0x08, 0xad, 0xef, 0x08, 0xad, 0xef, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9c, 0xd6, 0x19, 0x94,
+	0xce, 0x19, 0xbd, 0xf7,
+	0x00, 0xbd, 0xf7, 0x00, 0xbd, 0xf7, 0x19, 0xbd, 0xf7, 0x00, 0xbd, 0xf7,
+	0x08, 0xad, 0xef, 0x19,
+	0xbd, 0xf7, 0x00, 0xbd, 0xf7, 0x19, 0xbd, 0xf7, 0x08, 0xad, 0xef, 0x10,
+	0xc5, 0xef, 0x00, 0xbd,
+	0xf7, 0x00, 0xbd, 0xf7, 0x19, 0xbd, 0xf7, 0x00, 0xbd, 0xef, 0x19, 0xbd,
+	0xf7, 0x00, 0xbd, 0xf7,
+	0x08, 0xad, 0xef, 0x19, 0xbd, 0xf7, 0x00, 0xbd, 0xf7, 0x19, 0xbd, 0xf7,
+	0x10, 0xc5, 0xef, 0x10,
+	0xc5, 0xef, 0x10, 0x5a, 0x9c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x9c, 0x7b,
+	0x94, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xef,
+	0xf7, 0xff, 0xff, 0xf7, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xef,
+	0xf7, 0xe6, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x4a, 0x52, 0x4a, 0x08, 0x00, 0x00,
+	0x08, 0x31, 0x5a, 0x00,
+	0x84, 0xbd, 0x19, 0x94, 0xce, 0x08, 0xad, 0xef, 0x10, 0xc5, 0xef, 0x08,
+	0xad, 0xef, 0x19, 0xbd,
+	0xf7, 0x00, 0xbd, 0xef, 0x19, 0xbd, 0xf7, 0x10, 0xc5, 0xef, 0x00, 0xbd,
+	0xf7, 0x19, 0xbd, 0xf7,
+	0x00, 0xbd, 0xef, 0x19, 0xbd, 0xf7, 0x08, 0xad, 0xef, 0x10, 0xc5, 0xef,
+	0x00, 0xbd, 0xf7, 0x19,
+	0xbd, 0xf7, 0x08, 0xad, 0xef, 0x10, 0xc5, 0xef, 0x00, 0xbd, 0xf7, 0x19,
+	0xbd, 0xf7, 0x00, 0xbd,
+	0xf7, 0x19, 0xbd, 0xf7, 0x19, 0xbd, 0xf7, 0x00, 0xbd, 0xef, 0x19, 0xbd,
+	0xf7, 0x19, 0xbd, 0xf7,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x94,
+	0xce, 0x00, 0x9c, 0xd6,
+	0x08, 0xad, 0xef, 0x10, 0xc5, 0xef, 0x19, 0xbd, 0xf7, 0x00, 0xbd, 0xef,
+	0x19, 0xbd, 0xf7, 0x00,
+	0xbd, 0xf7, 0x00, 0xbd, 0xef, 0x19, 0xbd, 0xf7, 0x00, 0xbd, 0xef, 0x19,
+	0xbd, 0xf7, 0x00, 0xbd,
+	0xf7, 0x19, 0xbd, 0xf7, 0x10, 0xc5, 0xef, 0x08, 0xad, 0xef, 0x00, 0xbd,
+	0xf7, 0x19, 0xbd, 0xf7,
+	0x00, 0xbd, 0xef, 0x19, 0xbd, 0xf7, 0x00, 0xbd, 0xf7, 0x10, 0xc5, 0xef,
+	0x08, 0xad, 0xef, 0x00,
+	0xbd, 0xf7, 0x10, 0xc5, 0xef, 0x08, 0xad, 0xd6, 0x10, 0x73, 0x7b, 0xe6,
+	0xde, 0xde, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7,
+	0xff, 0xff, 0xff, 0xff,
+	0xef, 0xf7, 0xe6, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff,
+	0xef, 0xf7, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef,
+	0xf7, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xe6, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xef, 0xf7, 0xe6, 0x31, 0x31, 0x29, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x10,
+	0x52, 0x7b, 0x00, 0x84, 0xbd, 0x08, 0xad, 0xd6, 0x08, 0xad, 0xef, 0x08,
+	0xad, 0xef, 0x00, 0xbd,
+	0xf7, 0x19, 0xbd, 0xf7, 0x00, 0xbd, 0xf7, 0x19, 0xbd, 0xf7, 0x08, 0xad,
+	0xef, 0x19, 0xbd, 0xf7,
+	0x00, 0xbd, 0xf7, 0x19, 0xbd, 0xf7, 0x00, 0xbd, 0xf7, 0x19, 0xbd, 0xf7,
+	0x00, 0xbd, 0xf7, 0x19,
+	0xbd, 0xf7, 0x00, 0xbd, 0xef, 0x19, 0xbd, 0xf7, 0x00, 0xbd, 0xf7, 0x19,
+	0xbd, 0xf7, 0x00, 0xbd,
+	0xef, 0x19, 0xbd, 0xf7, 0x00, 0xbd, 0xef, 0x00, 0xbd, 0xf7, 0x19, 0xbd,
+	0xf7, 0x00, 0xbd, 0xf7,
+	0x00, 0xbd, 0xef, 0x08, 0xad, 0xef, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x84, 0xbd,
+	0x00, 0x9c, 0xd6, 0x10, 0xc5, 0xef, 0x00, 0xbd, 0xf7, 0x08, 0xad, 0xef,
+	0x19, 0xbd, 0xf7, 0x00,
+	0xbd, 0xef, 0x19, 0xbd, 0xf7, 0x10, 0xc5, 0xef, 0x00, 0xbd, 0xf7, 0x19,
+	0xbd, 0xf7, 0x00, 0xbd,
+	0xf7, 0x10, 0xc5, 0xef, 0x00, 0xbd, 0xf7, 0x19, 0xbd, 0xf7, 0x00, 0xbd,
+	0xf7, 0x19, 0xbd, 0xf7,
+	0x00, 0xbd, 0xef, 0x19, 0xbd, 0xf7, 0x00, 0xbd, 0xf7, 0x19, 0xbd, 0xf7,
+	0x00, 0xbd, 0xf7, 0x19,
+	0xbd, 0xf7, 0x10, 0xc5, 0xef, 0x08, 0xad, 0xd6, 0x10, 0xc5, 0xef, 0x19,
+	0x94, 0xce, 0x9c, 0xad,
+	0xce, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xe6, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xef, 0xf7, 0xe6, 0xff,
+	0xf7, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xef,
+	0xf7, 0xe6, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff,
+	0xef, 0xf7, 0xff, 0xef, 0xde, 0xef, 0x08, 0x08, 0x10, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x10, 0x52, 0x7b, 0x00, 0x84, 0xbd, 0x19, 0x94, 0xce, 0x08,
+	0xad, 0xef, 0x08, 0xad,
+	0xef, 0x10, 0xc5, 0xef, 0x00, 0xbd, 0xf7, 0x08, 0xad, 0xef, 0x10, 0xc5,
+	0xef, 0x00, 0xbd, 0xf7,
+	0x00, 0xbd, 0xf7, 0x10, 0xc5, 0xef, 0x00, 0xbd, 0xf7, 0x10, 0xc5, 0xef,
+	0x00, 0xbd, 0xf7, 0x10,
+	0xc5, 0xef, 0x00, 0xbd, 0xf7, 0x19, 0xbd, 0xf7, 0x00, 0xbd, 0xf7, 0x08,
+	0xad, 0xef, 0x10, 0xc5,
+	0xef, 0x00, 0xbd, 0xf7, 0x19, 0xbd, 0xf7, 0x08, 0xad, 0xef, 0x10, 0xc5,
+	0xef, 0x00, 0xbd, 0xf7,
+	0x10, 0xc5, 0xef, 0x08, 0xad, 0xef, 0x08, 0xad, 0xef, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x84, 0xbd,
+	0x00, 0x84, 0xbd, 0x08, 0xad, 0xef, 0x08, 0xad, 0xef, 0x19, 0xbd, 0xf7,
+	0x00, 0xbd, 0xf7, 0x00,
+	0xbd, 0xf7, 0x19, 0xbd, 0xf7, 0x00, 0xbd, 0xf7, 0x08, 0xad, 0xef, 0x19,
+	0xbd, 0xf7, 0x00, 0xbd,
+	0xef, 0x19, 0xbd, 0xf7, 0x08, 0xad, 0xef, 0x19, 0xbd, 0xf7, 0x00, 0xbd,
+	0xf7, 0x10, 0xc5, 0xef,
+	0x00, 0xbd, 0xf7, 0x19, 0xbd, 0xf7, 0x00, 0xbd, 0xf7, 0x10, 0xc5, 0xef,
+	0x00, 0xbd, 0xf7, 0x10,
+	0xc5, 0xef, 0x00, 0xbd, 0xf7, 0x19, 0xbd, 0xf7, 0x00, 0xbd, 0xf7, 0x10,
+	0xc5, 0xef, 0x08, 0xad,
+	0xd6, 0x10, 0x7b, 0x9c, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xef, 0xf7, 0xff,
+	0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff,
+	0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xe6, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xef, 0xf7, 0xe6, 0xff, 0xff,
+	0xff, 0xef, 0xf7, 0xff,
+	0xff, 0xff, 0xff, 0x9c, 0xa5, 0x94, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x08,
+	0x00, 0x00, 0x08, 0x08, 0x10, 0x10, 0x52, 0x7b, 0x00, 0x84, 0xbd, 0x08,
+	0xad, 0xd6, 0x00, 0xbd,
+	0xef, 0x10, 0xc5, 0xef, 0x08, 0xad, 0xef, 0x19, 0xbd, 0xf7, 0x00, 0xbd,
+	0xf7, 0x19, 0xbd, 0xf7,
+	0x00, 0xbd, 0xf7, 0x10, 0xc5, 0xef, 0x08, 0xad, 0xef, 0x19, 0xbd, 0xf7,
+	0x08, 0xad, 0xef, 0x19,
+	0xbd, 0xf7, 0x00, 0xbd, 0xf7, 0x10, 0xc5, 0xef, 0x00, 0xbd, 0xf7, 0x19,
+	0xbd, 0xf7, 0x00, 0xbd,
+	0xf7, 0x19, 0xbd, 0xf7, 0x00, 0xbd, 0xf7, 0x19, 0xbd, 0xf7, 0x00, 0xbd,
+	0xf7, 0x19, 0xbd, 0xf7,
+	0x08, 0xad, 0xef, 0x08, 0xad, 0xef, 0x19, 0x94, 0xce, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x84, 0xbd, 0x19, 0x94, 0xce, 0x08, 0xad, 0xef, 0x08, 0xad, 0xef,
+	0x00, 0xbd, 0xef, 0x19,
+	0xbd, 0xf7, 0x00, 0xbd, 0xef, 0x19, 0xbd, 0xf7, 0x00, 0xbd, 0xef, 0x19,
+	0xbd, 0xf7, 0x00, 0xbd,
+	0xf7, 0x19, 0xbd, 0xf7, 0x00, 0xbd, 0xf7, 0x19, 0xbd, 0xf7, 0x00, 0xbd,
+	0xf7, 0x10, 0xc5, 0xef,
+	0x00, 0xbd, 0xf7, 0x19, 0xbd, 0xf7, 0x00, 0xbd, 0xef, 0x19, 0xbd, 0xf7,
+	0x08, 0xad, 0xef, 0x00,
+	0xbd, 0xf7, 0x19, 0xbd, 0xf7, 0x08, 0xad, 0xef, 0x10, 0xc5, 0xef, 0x00,
+	0xbd, 0xef, 0x10, 0xc5,
+	0xef, 0x08, 0xad, 0xd6, 0x00, 0x84, 0xbd, 0x10, 0x52, 0x7b, 0xef, 0xf7,
+	0xe6, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xef, 0xf7,
+	0xff, 0xff, 0xf7, 0xff, 0xef, 0xf7, 0xff, 0xff, 0xf7, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xf7, 0xff,
+	0xce, 0xde, 0xce, 0x08, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x52, 0x7b, 0x00,
+	0x84, 0xbd, 0x19, 0x94,
+	0xce, 0x08, 0xad, 0xef, 0x08, 0xad, 0xef, 0x19, 0xbd, 0xf7, 0x00, 0xbd,
+	0xf7, 0x19, 0xbd, 0xf7,
+	0x00, 0xbd, 0xef, 0x19, 0xbd, 0xf7, 0x19, 0xbd, 0xf7, 0x00, 0xbd, 0xf7,
+	0x19, 0xbd, 0xf7, 0x00,
+	0xbd, 0xf7, 0x00, 0xbd, 0xf7, 0x19, 0xbd, 0xf7, 0x08, 0xad, 0xef, 0x19,
+	0xbd, 0xf7, 0x00, 0xbd,
+	0xef, 0x19, 0xbd, 0xf7, 0x00, 0xbd, 0xef, 0x19, 0xbd, 0xf7, 0x00, 0xbd,
+	0xef, 0x19, 0xbd, 0xf7,
+	0x08, 0xad, 0xef, 0x08, 0xad, 0xd6, 0x00, 0x9c, 0xd6, 0x19, 0x7b, 0xbd,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x84, 0xbd, 0x19, 0x94, 0xce, 0x00, 0xbd, 0xf7,
+	0x19, 0xbd, 0xf7, 0x19,
+	0xbd, 0xf7, 0x00, 0xbd, 0xef, 0x19, 0xbd, 0xf7, 0x00, 0xbd, 0xf7, 0x19,
+	0xbd, 0xf7, 0x00, 0xbd,
+	0xef, 0x00, 0xbd, 0xf7, 0x10, 0xc5, 0xef, 0x00, 0xbd, 0xf7, 0x10, 0xc5,
+	0xef, 0x08, 0xad, 0xef,
+	0x19, 0xbd, 0xf7, 0x00, 0xbd, 0xf7, 0x10, 0xc5, 0xef, 0x08, 0xad, 0xef,
+	0x00, 0xbd, 0xf7, 0x19,
+	0xbd, 0xf7, 0x19, 0xbd, 0xf7, 0x00, 0xbd, 0xf7, 0x19, 0xbd, 0xf7, 0x00,
+	0xbd, 0xf7, 0x19, 0xbd,
+	0xf7, 0x00, 0xbd, 0xef, 0x08, 0xad, 0xd6, 0x08, 0xad, 0xd6, 0x10, 0x52,
+	0x7b, 0x3a, 0x31, 0x4a,
+	0xef, 0xf7, 0xe6, 0xef, 0xf7, 0xe6, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xe6,
+	0xff, 0xff, 0xff, 0xef,
+	0xf7, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xe6, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xef, 0xf7, 0xe6, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xce, 0xde, 0xce,
+	0x08, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x08,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x10, 0x08, 0x08, 0x10, 0x10,
+	0x52, 0x7b, 0x00, 0x84,
+	0xbd, 0x00, 0x9c, 0xd6, 0x10, 0xc5, 0xef, 0x08, 0xad, 0xef, 0x00, 0xbd,
+	0xf7, 0x10, 0xc5, 0xef,
+	0x00, 0xbd, 0xf7, 0x19, 0xbd, 0xf7, 0x00, 0xbd, 0xef, 0x00, 0xbd, 0xf7,
+	0x19, 0xbd, 0xf7, 0x00,
+	0xbd, 0xef, 0x19, 0xbd, 0xf7, 0x00, 0xbd, 0xef, 0x19, 0xbd, 0xf7, 0x00,
+	0xbd, 0xf7, 0x00, 0xbd,
+	0xf7, 0x19, 0xbd, 0xf7, 0x00, 0xbd, 0xf7, 0x19, 0xbd, 0xf7, 0x00, 0xbd,
+	0xef, 0x08, 0xad, 0xef,
+	0x08, 0xad, 0xef, 0x19, 0x94, 0xce, 0x19, 0x94, 0xce, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x19, 0x7b, 0xbd, 0x00, 0x84, 0xbd, 0x08, 0xad, 0xef,
+	0x10, 0xc5, 0xef, 0x00,
+	0xbd, 0xef, 0x08, 0xad, 0xef, 0x19, 0xbd, 0xf7, 0x00, 0xbd, 0xf7, 0x19,
+	0xbd, 0xf7, 0x00, 0xbd,
+	0xef, 0x19, 0xbd, 0xf7, 0x00, 0xbd, 0xf7, 0x19, 0xbd, 0xf7, 0x08, 0xad,
+	0xef, 0x19, 0xbd, 0xf7,
+	0x00, 0xbd, 0xf7, 0x19, 0xbd, 0xf7, 0x00, 0xbd, 0xf7, 0x19, 0xbd, 0xf7,
+	0x00, 0xbd, 0xf7, 0x19,
+	0xbd, 0xf7, 0x00, 0xbd, 0xf7, 0x10, 0xc5, 0xef, 0x00, 0xbd, 0xf7, 0x10,
+	0xc5, 0xef, 0x00, 0xbd,
+	0xf7, 0x10, 0xc5, 0xef, 0x08, 0xad, 0xef, 0x08, 0xad, 0xd6, 0x00, 0x9c,
+	0xd6, 0x10, 0x7b, 0x9c,
+	0x08, 0x31, 0x5a, 0x00, 0x00, 0x00, 0x4a, 0x5a, 0x73, 0xce, 0xde, 0xce,
+	0xef, 0xf7, 0xe6, 0xff,
+	0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xef, 0xf7,
+	0xe6, 0xef, 0xf7, 0xff, 0xef, 0xf7, 0xe6, 0xa5, 0xb5, 0xb5, 0x6b, 0x5a,
+	0x73, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x08,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08,
+	0x31, 0x3a, 0x10, 0x52,
+	0x7b, 0x19, 0x7b, 0xbd, 0x00, 0x9c, 0xd6, 0x08, 0xad, 0xef, 0x10, 0xc5,
+	0xef, 0x19, 0xbd, 0xf7,
+	0x08, 0xad, 0xef, 0x10, 0xc5, 0xef, 0x00, 0xbd, 0xf7, 0x19, 0xbd, 0xf7,
+	0x08, 0xad, 0xef, 0x10,
+	0xc5, 0xef, 0x00, 0xbd, 0xf7, 0x19, 0xbd, 0xf7, 0x00, 0xbd, 0xf7, 0x19,
+	0xbd, 0xf7, 0x00, 0xbd,
+	0xef, 0x19, 0xbd, 0xf7, 0x08, 0xad, 0xef, 0x10, 0xc5, 0xef, 0x08, 0xad,
+	0xef, 0x08, 0xad, 0xef,
+	0x19, 0x94, 0xce, 0x00, 0x9c, 0xd6, 0x19, 0x7b, 0xbd, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x84, 0xbd, 0x00, 0x9c, 0xd6,
+	0x19, 0x94, 0xce, 0x08,
+	0xad, 0xef, 0x08, 0xad, 0xef, 0x10, 0xc5, 0xef, 0x08, 0xad, 0xef, 0x00,
+	0xbd, 0xf7, 0x10, 0xc5,
+	0xef, 0x08, 0xad, 0xef, 0x00, 0xbd, 0xf7, 0x10, 0xc5, 0xef, 0x00, 0xbd,
+	0xf7, 0x19, 0xbd, 0xf7,
+	0x00, 0xbd, 0xf7, 0x00, 0xbd, 0xf7, 0x10, 0xc5, 0xef, 0x08, 0xad, 0xef,
+	0x00, 0xbd, 0xf7, 0x19,
+	0xbd, 0xf7, 0x00, 0xbd, 0xef, 0x19, 0xbd, 0xf7, 0x08, 0xad, 0xef, 0x19,
+	0xbd, 0xf7, 0x08, 0xad,
+	0xef, 0x19, 0xbd, 0xf7, 0x00, 0xbd, 0xf7, 0x08, 0xad, 0xef, 0x08, 0xad,
+	0xd6, 0x19, 0x94, 0xce,
+	0x00, 0x84, 0xbd, 0x10, 0x52, 0x7b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x08, 0x08, 0x10, 0x10, 0x29, 0x19, 0x31, 0x31, 0x29, 0x31,
+	0x31, 0x29, 0x08, 0x08,
+	0x10, 0x08, 0x08, 0x10, 0x08, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x08, 0x00, 0x00, 0x08,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x08, 0x31,
+	0x3a, 0x10, 0x52, 0x7b, 0x00, 0x84, 0xbd, 0x00, 0x9c, 0xd6, 0x08, 0xad,
+	0xef, 0x10, 0xc5, 0xef,
+	0x08, 0xad, 0xef, 0x19, 0xbd, 0xf7, 0x00, 0xbd, 0xf7, 0x19, 0xbd, 0xf7,
+	0x00, 0xbd, 0xf7, 0x19,
+	0xbd, 0xf7, 0x00, 0xbd, 0xf7, 0x19, 0xbd, 0xf7, 0x00, 0xbd, 0xef, 0x19,
+	0xbd, 0xf7, 0x08, 0xad,
+	0xef, 0x10, 0xc5, 0xef, 0x08, 0xad, 0xef, 0x10, 0xc5, 0xef, 0x08, 0xad,
+	0xef, 0x00, 0x84, 0xbd,
+	0x19, 0x94, 0xce, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x84, 0xbd,
+	0x19, 0x94, 0xce, 0x00,
+	0x9c, 0xd6, 0x00, 0x9c, 0xd6, 0x08, 0xad, 0xef, 0x08, 0xad, 0xd6, 0x08,
+	0xad, 0xef, 0x08, 0xad,
+	0xef, 0x08, 0xad, 0xef, 0x08, 0xad, 0xef, 0x19, 0xbd, 0xf7, 0x08, 0xad,
+	0xef, 0x08, 0xad, 0xef,
+	0x19, 0xbd, 0xf7, 0x08, 0xad, 0xef, 0x00, 0xbd, 0xf7, 0x19, 0xbd, 0xf7,
+	0x00, 0xbd, 0xf7, 0x19,
+	0xbd, 0xf7, 0x00, 0xbd, 0xef, 0x19, 0xbd, 0xf7, 0x00, 0xbd, 0xf7, 0x19,
+	0xbd, 0xf7, 0x00, 0xbd,
+	0xf7, 0x00, 0xbd, 0xf7, 0x19, 0xbd, 0xf7, 0x10, 0xc5, 0xef, 0x08, 0xad,
+	0xef, 0x08, 0xad, 0xef,
+	0x00, 0x9c, 0xd6, 0x10, 0x5a, 0x9c, 0x10, 0x52, 0x7b, 0x08, 0x31, 0x3a,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x08, 0x10, 0x08, 0x00, 0x00, 0x08,
+	0x08, 0x10, 0x00, 0x00,
+	0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x08, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x08, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x08, 0x31, 0x5a, 0x10, 0x5a, 0x9c, 0x00, 0x84, 0xbd, 0x19, 0x94,
+	0xce, 0x08, 0xad, 0xef,
+	0x08, 0xad, 0xef, 0x00, 0xbd, 0xf7, 0x00, 0xbd, 0xf7, 0x19, 0xbd, 0xf7,
+	0x00, 0xbd, 0xf7, 0x10,
+	0xc5, 0xef, 0x00, 0xbd, 0xf7, 0x19, 0xbd, 0xf7, 0x08, 0xad, 0xef, 0x10,
+	0xc5, 0xef, 0x00, 0xbd,
+	0xef, 0x08, 0xad, 0xef, 0x08, 0xad, 0xef, 0x19, 0x94, 0xce, 0x00, 0x9c,
+	0xd6, 0x00, 0x84, 0xbd,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x10, 0x7b, 0x9c, 0x00,
+	0x84, 0xbd, 0x00, 0x84, 0xbd, 0x19, 0x94, 0xce, 0x00, 0x84, 0xbd, 0x19,
+	0x94, 0xce, 0x00, 0x9c,
+	0xd6, 0x19, 0x94, 0xce, 0x00, 0x9c, 0xd6, 0x08, 0xad, 0xd6, 0x08, 0xad,
+	0xef, 0x08, 0xad, 0xd6,
+	0x08, 0xad, 0xef, 0x08, 0xad, 0xef, 0x10, 0xc5, 0xef, 0x08, 0xad, 0xef,
+	0x10, 0xc5, 0xef, 0x08,
+	0xad, 0xef, 0x19, 0xbd, 0xf7, 0x00, 0xbd, 0xf7, 0x00, 0xbd, 0xef, 0x19,
+	0xbd, 0xf7, 0x00, 0xbd,
+	0xef, 0x10, 0xc5, 0xef, 0x19, 0xbd, 0xf7, 0x08, 0xad, 0xef, 0x00, 0xbd,
+	0xf7, 0x08, 0xad, 0xd6,
+	0x19, 0x94, 0xce, 0x00, 0x84, 0xbd, 0x10, 0x7b, 0x9c, 0x10, 0x52, 0x7b,
+	0x08, 0x31, 0x5a, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x08, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x08, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x10, 0x00,
+	0x00, 0x00, 0x08, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x08, 0x31, 0x3a, 0x10, 0x52, 0x7b, 0x00, 0x84,
+	0xbd, 0x00, 0x84, 0xbd,
+	0x08, 0xad, 0xd6, 0x08, 0xad, 0xef, 0x19, 0xbd, 0xf7, 0x10, 0xc5, 0xef,
+	0x00, 0xbd, 0xf7, 0x10,
+	0xc5, 0xef, 0x08, 0xad, 0xef, 0x19, 0xbd, 0xf7, 0x08, 0xad, 0xef, 0x00,
+	0xbd, 0xf7, 0x08, 0xad,
+	0xef, 0x19, 0x94, 0xce, 0x08, 0xad, 0xd6, 0x00, 0x9c, 0xd6, 0x00, 0x9c,
+	0xd6, 0x10, 0x5a, 0x9c,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x5a, 0x9c, 0x10, 0x5a, 0x9c, 0x10,
+	0x5a, 0x9c, 0x00, 0x84,
+	0xbd, 0x19, 0x7b, 0xbd, 0x00, 0x84, 0xbd, 0x00, 0x84, 0xbd, 0x19, 0x94,
+	0xce, 0x00, 0x84, 0xbd,
+	0x19, 0x94, 0xce, 0x00, 0x9c, 0xd6, 0x19, 0x94, 0xce, 0x08, 0xad, 0xef,
+	0x19, 0x94, 0xce, 0x08,
+	0xad, 0xef, 0x10, 0xc5, 0xef, 0x08, 0xad, 0xef, 0x00, 0xbd, 0xef, 0x19,
+	0xbd, 0xf7, 0x00, 0xbd,
+	0xef, 0x19, 0xbd, 0xf7, 0x08, 0xad, 0xef, 0x00, 0xbd, 0xf7, 0x10, 0xc5,
+	0xef, 0x08, 0xad, 0xef,
+	0x08, 0xad, 0xef, 0x00, 0x84, 0xbd, 0x00, 0x84, 0xbd, 0x10, 0x5a, 0x9c,
+	0x10, 0x52, 0x7b, 0x08,
+	0x31, 0x3a, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x10, 0x08, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x08,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x31, 0x5a, 0x10, 0x52,
+	0x7b, 0x00, 0x84, 0xbd,
+	0x00, 0x84, 0xbd, 0x19, 0x94, 0xce, 0x08, 0xad, 0xd6, 0x08, 0xad, 0xef,
+	0x19, 0xbd, 0xf7, 0x08,
+	0xad, 0xef, 0x08, 0xad, 0xef, 0x10, 0xc5, 0xef, 0x08, 0xad, 0xef, 0x00,
+	0xbd, 0xef, 0x08, 0xad,
+	0xef, 0x19, 0x94, 0xce, 0x08, 0xad, 0xef, 0x00, 0x84, 0xbd, 0x00, 0x84,
+	0xbd, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x10, 0x73, 0x7b, 0x10, 0x5a, 0x9c, 0x10, 0x7b,
+	0x9c, 0x10, 0x5a, 0xbd,
+	0x00, 0x84, 0xbd, 0x10, 0x7b, 0x9c, 0x00, 0x84, 0xbd, 0x00, 0x84, 0xbd,
+	0x00, 0x84, 0xbd, 0x00,
+	0x84, 0xbd, 0x00, 0x84, 0xbd, 0x19, 0x94, 0xce, 0x00, 0x9c, 0xd6, 0x08,
+	0xad, 0xef, 0x08, 0xad,
+	0xef, 0x08, 0xad, 0xef, 0x10, 0xc5, 0xef, 0x08, 0xad, 0xef, 0x08, 0xad,
+	0xef, 0x08, 0xad, 0xef,
+	0x08, 0xad, 0xd6, 0x19, 0x94, 0xce, 0x00, 0x84, 0xbd, 0x10, 0x5a, 0x9c,
+	0x10, 0x52, 0x7b, 0x10,
+	0x52, 0x7b, 0x08, 0x31, 0x3a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x08, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x10, 0x21, 0x00, 0x08,
+	0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x10, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x31,
+	0x3a, 0x10, 0x52, 0x7b,
+	0x10, 0x5a, 0x9c, 0x00, 0x84, 0xbd, 0x00, 0x84, 0xbd, 0x08, 0xad, 0xef,
+	0x08, 0xad, 0xd6, 0x08,
+	0xad, 0xef, 0x08, 0xad, 0xef, 0x10, 0xc5, 0xef, 0x08, 0xad, 0xef, 0x08,
+	0xad, 0xef, 0x19, 0x94,
+	0xce, 0x00, 0x9c, 0xd6, 0x00, 0x84, 0xbd, 0x19, 0x7b, 0xbd, 0x10, 0x5a,
+	0x9c, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x10, 0x5a, 0x9c, 0x10, 0x52, 0x7b, 0x10, 0x5a, 0x9c,
+	0x10, 0x5a, 0x9c, 0x10,
+	0x5a, 0x9c, 0x10, 0x5a, 0x9c, 0x10, 0x7b, 0x9c, 0x00, 0x84, 0xbd, 0x00,
+	0x84, 0xbd, 0x19, 0x94,
+	0xce, 0x00, 0x9c, 0xd6, 0x19, 0x94, 0xce, 0x00, 0x9c, 0xd6, 0x08, 0xad,
+	0xef, 0x08, 0xad, 0xd6,
+	0x19, 0x94, 0xce, 0x00, 0x84, 0xbd, 0x00, 0x84, 0xbd, 0x10, 0x5a, 0x9c,
+	0x10, 0x52, 0x7b, 0x10,
+	0x52, 0x7b, 0x08, 0x31, 0x5a, 0x08, 0x08, 0x10, 0x08, 0x08, 0x10, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x08, 0x31, 0x3a,
+	0x08, 0x31, 0x5a, 0x10, 0x5a, 0x9c, 0x10, 0x5a, 0x9c, 0x19, 0x7b, 0xbd,
+	0x00, 0x84, 0xbd, 0x00,
+	0x9c, 0xd6, 0x08, 0xad, 0xd6, 0x19, 0x94, 0xce, 0x00, 0x9c, 0xd6, 0x19,
+	0x94, 0xce, 0x00, 0x9c,
+	0xd6, 0x00, 0x84, 0xbd, 0x00, 0x84, 0xbd, 0x00, 0x84, 0xbd, 0x10, 0x5a,
+	0x9c, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x10, 0x52, 0x7b, 0x10, 0x52, 0x7b, 0x10, 0x5a, 0x9c, 0x10,
+	0x5a, 0x9c, 0x10, 0x5a,
+	0x9c, 0x10, 0x5a, 0x9c, 0x10, 0x7b, 0x9c, 0x00, 0x84, 0xbd, 0x19, 0x7b,
+	0xbd, 0x00, 0x84, 0xbd,
+	0x19, 0x7b, 0xbd, 0x00, 0x84, 0xbd, 0x00, 0x84, 0xbd, 0x10, 0x5a, 0x9c,
+	0x10, 0x52, 0x7b, 0x10,
+	0x52, 0x7b, 0x08, 0x31, 0x5a, 0x08, 0x31, 0x5a, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x08, 0x31, 0x5a, 0x10, 0x5a, 0x9c, 0x10, 0x7b, 0x9c,
+	0x00, 0x84, 0xbd, 0x00,
+	0x84, 0xbd, 0x19, 0x7b, 0xbd, 0x00, 0x84, 0xbd, 0x00, 0x84, 0xbd, 0x00,
+	0x84, 0xbd, 0x00, 0x84,
+	0xbd, 0x19, 0x7b, 0xbd, 0x10, 0x7b, 0x9c, 0x10, 0x5a, 0x9c, 0x10, 0x52,
+	0x7b, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x08, 0x31, 0x5a, 0x10, 0x52, 0x7b, 0x10, 0x52, 0x7b, 0x10, 0x5a,
+	0x9c, 0x10, 0x73, 0x7b,
+	0x10, 0x5a, 0x9c, 0x10, 0x5a, 0x9c, 0x10, 0x5a, 0x9c, 0x10, 0x52, 0x7b,
+	0x10, 0x52, 0x7b, 0x10,
+	0x52, 0x7b, 0x08, 0x31, 0x5a, 0x08, 0x31, 0x3a, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x31, 0x5a, 0x08, 0x31, 0x5a,
+	0x10, 0x52, 0x7b, 0x10,
+	0x5a, 0x9c, 0x10, 0x5a, 0x9c, 0x10, 0x7b, 0x9c, 0x10, 0x5a, 0x9c, 0x00,
+	0x84, 0xbd, 0x00, 0x84,
+	0xbd, 0x10, 0x7b, 0x9c, 0x10, 0x5a, 0x9c, 0x10, 0x5a, 0x9c, 0x08, 0x31,
+	0x5a, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x31,
+	0x5a, 0x10, 0x52, 0x7b,
+	0x08, 0x31, 0x5a, 0x10, 0x52, 0x7b, 0x10, 0x52, 0x7b, 0x08, 0x31, 0x5a,
+	0x10, 0x52, 0x7b, 0x08,
+	0x31, 0x5a, 0x08, 0x31, 0x5a, 0x08, 0x31, 0x3a, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x08, 0x31, 0x5a, 0x08,
+	0x31, 0x5a, 0x10, 0x52, 0x7b, 0x10, 0x5a, 0x9c, 0x10, 0x5a, 0x9c, 0x10,
+	0x5a, 0x9c, 0x10, 0x5a,
+	0x9c, 0x10, 0x5a, 0x9c, 0x10, 0x52, 0x7b, 0x10, 0x52, 0x7b, 0x08, 0x31,
+	0x5a, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x31, 0x5a, 0x08, 0x31, 0x5a,
+	0x08, 0x31, 0x5a, 0x08,
+	0x31, 0x5a, 0x08, 0x31, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x31, 0x3a, 0x08, 0x31, 0x5a, 0x08,
+	0x31, 0x5a, 0x10, 0x52,
+	0x7b, 0x08, 0x31, 0x5a, 0x08, 0x31, 0x5a, 0x08, 0x31, 0x3a, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+};
+
+#endif
diff --git a/drivers/video/msm/vidc/common/dec/vdec.c b/drivers/video/msm/vidc/common/dec/vdec.c
old mode 100644
new mode 100755
index ec27b00..0958e07
--- a/drivers/video/msm/vidc/common/dec/vdec.c
+++ b/drivers/video/msm/vidc/common/dec/vdec.c
@@ -42,7 +42,9 @@
 #define ERR(x...) pr_err(x)
 
 #define VID_DEC_NAME "msm_vidc_dec"
-
+#ifdef KW_TAINT_ANALYSIS	51
+	extern void * get_tainted_stuff();
+#endif
 static char *node_name[2] = {"", "_sec"};
 static struct vid_dec_dev *vid_dec_device_p;
 static dev_t vid_dec_dev_num;
@@ -897,6 +899,12 @@
 	vcd_meta_buffer->offset = meta_buffers->offset;
 	vcd_meta_buffer->pmem_fd_iommu = meta_buffers->pmem_fd_iommu;
 
+	if (meta_buffers->count > MAX_META_BUFFERS) {
+		ERR("meta buffers maximum count reached, count = %d",
+			meta_buffers->count);
+		return false;
+	}
+
 	if (!vcd_get_ion_status()) {
 		pr_err("PMEM Not available\n");
 		return false;
@@ -1102,6 +1110,12 @@
 	vcd_h264_mv_buffer->pmem_fd = mv_data->pmem_fd;
 	vcd_h264_mv_buffer->offset = mv_data->offset;
 
+	if (mv_data->count > MAX_MV_BUFFERS) {
+		ERR("MV buffers maximum count reached, count = %d",
+			mv_data->count);
+		return false;
+	}
+
 	if (!vcd_get_ion_status()) {
 		pr_err("PMEM not available\n");
 		return false;
@@ -1736,7 +1750,11 @@
 	unsigned long kernel_vaddr, phy_addr, len;
 	unsigned long ker_vaddr;
 	u32 result = true;
+	#ifdef KW_TAINT_ANALYSIS
+    void __user *arg = (void __user *) get_tainted_stuff();
+	#else
 	void __user *arg = (void __user *)u_arg;
+	#endif
 	int rc = 0;
 	size_t ion_len;
 
diff --git a/drivers/video/msm/vidc/common/enc/venc.c b/drivers/video/msm/vidc/common/enc/venc.c
old mode 100644
new mode 100755
index 823626a..ee9c48b
--- a/drivers/video/msm/vidc/common/enc/venc.c
+++ b/drivers/video/msm/vidc/common/enc/venc.c
@@ -45,7 +45,9 @@
 
 #define INFO(x...) printk(KERN_INFO x)
 #define ERR(x...) printk(KERN_ERR x)
-
+#ifdef KW_TAINT_ANALYSIS
+	extern void * get_tainted_stuff();
+#endif
 static struct vid_enc_dev *vid_enc_device_p;
 static dev_t vid_enc_dev_num;
 static struct class *vid_enc_class;
@@ -840,7 +842,11 @@
 {
 	struct video_client_ctx *client_ctx = NULL;
 	struct venc_ioctl_msg venc_msg;
+	#ifdef KW_TAINT_ANALYSIS
+	void __user *arg = (void __user *)get_tainted_stuff();;
+	#else
 	void __user *arg = (void __user *)u_arg;
+	#endif
 	u32 result = true;
 	int result_read = -1;
 
diff --git a/fs/ext4/ext4_jbd2.c b/fs/ext4/ext4_jbd2.c
index aca1790..d0b8f98 100644
--- a/fs/ext4/ext4_jbd2.c
+++ b/fs/ext4/ext4_jbd2.c
@@ -109,10 +109,10 @@
 
 	if (ext4_handle_valid(handle)) {
 		err = jbd2_journal_dirty_metadata(handle, bh);
-		if (err) {
-			/* Errors can only happen if there is a bug */
-			handle->h_err = err;
-			__ext4_journal_stop(where, line, handle);
+		/* Errors can only happen if there is a bug */
+		if (WARN_ON_ONCE(err)) {
+			ext4_journal_abort_handle(where, line, __func__, bh,
+						  handle, err);
 		}
 	} else {
 		if (inode)
diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index e1fb1d5..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);
 }
 
@@ -4105,6 +4106,7 @@
 		ext4_commit_super(sb, 1);
 
 		jbd2_journal_clear_err(journal);
+		jbd2_journal_update_sb_errno(journal);
 	}
 }
 
diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c
index e88748e..6c27436 100644
--- a/fs/ext4/xattr.c
+++ b/fs/ext4/xattr.c
@@ -1267,6 +1267,8 @@
 				    s_min_extra_isize) {
 					tried_min_extra_isize++;
 					new_extra_isize = s_min_extra_isize;
+					kfree(is); is = NULL;
+					kfree(bs); bs = NULL;
 					goto retry;
 				}
 				error = -1;
diff --git a/fs/fat/cache.c b/fs/fat/cache.c
index 1cc7038..bab81ca 100644
--- a/fs/fat/cache.c
+++ b/fs/fat/cache.c
@@ -294,8 +294,9 @@
 	if (ret < 0)
 		return ret;
 	else if (ret == FAT_ENT_EOF) {
-		fat_fs_error(sb, "%s: request beyond EOF (i_pos %lld)",
-			     __func__, MSDOS_I(inode)->i_pos);
+		fat_fs_error_ratelimit(sb,
+				       "%s: request beyond EOF (i_pos %lld)",
+				       __func__, MSDOS_I(inode)->i_pos);
 		return -EIO;
 	}
 	return dclus;
diff --git a/fs/fat/fat.h b/fs/fat/fat.h
index 341f753..8db494d 100644
--- a/fs/fat/fat.h
+++ b/fs/fat/fat.h
@@ -329,10 +329,14 @@
 /* fat/misc.c */
 extern __printf(3, 4) __cold
 void __fat_fs_error(struct super_block *sb, int report, const char *fmt, ...);
-#define fat_fs_error(sb, fmt, args...)		\
-	__fat_fs_error(sb, 1, fmt , ## args)
 #define fat_fs_error_ratelimit(sb, fmt, args...) \
 	__fat_fs_error(sb, __ratelimit(&MSDOS_SB(sb)->ratelimit), fmt , ## args)
+/*
+ * If removable devices with a fat fs are removed without a unmount, further
+ * accesses to the device by applications causes a large number of error prints
+ * & in some cases leads to watchdog bark.
+ */
+#define fat_fs_error(sb, fmt, args...)	fat_fs_error_ratelimit(sb, fmt, ## args)
 __printf(3, 4) __cold
 void fat_msg(struct super_block *sb, const char *level, const char *fmt, ...);
 extern int fat_clusters_flush(struct super_block *sb);
diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index 6b83222..837a6e3 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -692,6 +692,8 @@
 		lock_page(newpage);
 		put_page(newpage);
 
+		lru_cache_add_file(newpage);
+
 		/* finally release the old page and swap pointers */
 		unlock_page(oldpage);
 		page_cache_release(oldpage);
diff --git a/fs/jbd2/journal.c b/fs/jbd2/journal.c
index 1afb701..9956ac6 100644
--- a/fs/jbd2/journal.c
+++ b/fs/jbd2/journal.c
@@ -1340,7 +1340,7 @@
  * Update a journal's errno.  Write updated superblock to disk waiting for IO
  * to complete.
  */
-static void jbd2_journal_update_sb_errno(journal_t *journal)
+void jbd2_journal_update_sb_errno(journal_t *journal)
 {
 	journal_superblock_t *sb = journal->j_superblock;
 
@@ -1352,6 +1352,7 @@
 
 	jbd2_write_superblock(journal, WRITE_SYNC);
 }
+EXPORT_SYMBOL(jbd2_journal_update_sb_errno);
 
 /*
  * Read the superblock for a given journal, performing initial
diff --git a/include/linux/Kbuild b/include/linux/Kbuild
index 4640d3b..6d18d0f 100755
--- a/include/linux/Kbuild
+++ b/include/linux/Kbuild
@@ -146,6 +146,7 @@
 header-y += genetlink.h
 header-y += gfs2_ondisk.h
 header-y += gigaset_dev.h
+header-y += hbtp_input.h
 header-y += hdlc.h
 header-y += hdlcdrv.h
 header-y += hdreg.h
diff --git a/include/linux/android_alarm.h b/include/linux/android_alarm.h
index b017caa..65227ad 100644
--- a/include/linux/android_alarm.h
+++ b/include/linux/android_alarm.h
@@ -71,7 +71,7 @@
 void alarm_start_range(struct alarm *alarm, ktime_t start, ktime_t end);
 int alarm_try_to_cancel(struct alarm *alarm);
 int alarm_cancel(struct alarm *alarm);
-void set_power_on_alarm(long secs);
+void set_power_on_alarm(long secs, bool enable);
 ktime_t alarm_get_elapsed_realtime(void);
 
 /* set rtc while preserving elapsed realtime */
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/blk_types.h b/include/linux/blk_types.h
index 130d0fd..3f62354 100644
--- a/include/linux/blk_types.h
+++ b/include/linux/blk_types.h
@@ -95,6 +95,12 @@
 #define BIO_FS_INTEGRITY 9	/* fs owns integrity data, not block layer */
 #define BIO_QUIET	10	/* Make BIO Quiet */
 #define BIO_MAPPED_INTEGRITY 11/* integrity metadata has been remapped */
+/*
+ * Added for Req based dm which need to perform post processing. This flag
+ * ensures blk_update_request does not free the bios or request, this is done
+ * at the dm level
+ */
+#define BIO_DONTFREE 12
 #define bio_flagged(bio, flag)	((bio)->bi_flags & (1 << (flag)))
 
 /*
@@ -176,6 +182,8 @@
 	 REQ_SANITIZE)
 #define REQ_CLONE_MASK		REQ_COMMON_MASK
 
+#define MMC_REQ_NOREINSERT_MASK (REQ_URGENT | REQ_FUA | REQ_FLUSH)
+
 #define REQ_RAHEAD		(1 << __REQ_RAHEAD)
 #define REQ_THROTTLED		(1 << __REQ_THROTTLED)
 
diff --git a/include/linux/devfreq.h b/include/linux/devfreq.h
index d00847a..3ab25c3 100644
--- a/include/linux/devfreq.h
+++ b/include/linux/devfreq.h
@@ -52,8 +52,9 @@
  */
 #define DEVFREQ_FLAG_LEAST_UPPER_BOUND		0x1
 
-#define DEVFREQ_FLAG_FAST_HINT	0x2
-#define DEVFREQ_FLAG_SLOW_HINT	0x4
+#define DEVFREQ_FLAG_FAST_HINT			0x2
+#define DEVFREQ_FLAG_SLOW_HINT			0x4
+#define DEVFREQ_FLAG_WAKEUP_MAXFREQ		0x8
 
 /**
  * struct devfreq_governor_data - mapping to per device governor data
@@ -227,6 +228,9 @@
  *			the governor may consider slowing the frequency down.
  *			Specify 0 to use the default. Valid value = 0 to 100.
  *			downdifferential < upthreshold must hold.
+ * @simple_scaling:	Setting this flag will scale the clocks up only if the
+ *			load is above @upthreshold and will scale the clocks
+ *			down only if the load is below @downdifferential.
  *
  * If the fed devfreq_simple_ondemand_data pointer is NULL to the governor,
  * the governor uses the default values.
@@ -234,6 +238,7 @@
 struct devfreq_simple_ondemand_data {
 	unsigned int upthreshold;
 	unsigned int downdifferential;
+	unsigned int simple_scaling;
 };
 #endif
 
diff --git a/include/linux/device-mapper.h b/include/linux/device-mapper.h
index 98f34b8..546871b 100644
--- a/include/linux/device-mapper.h
+++ b/include/linux/device-mapper.h
@@ -510,5 +510,6 @@
 void dm_requeue_unmapped_request(struct request *rq);
 void dm_kill_unmapped_request(struct request *rq, int error);
 int dm_underlying_device_busy(struct request_queue *q);
+void dm_end_request(struct request *clone, int error);
 
 #endif	/* _LINUX_DEVICE_MAPPER_H */
diff --git a/include/linux/diagchar.h b/include/linux/diagchar.h
index d525e84..f78d418 100644
--- a/include/linux/diagchar.h
+++ b/include/linux/diagchar.h
@@ -119,10 +119,10 @@
 /* This needs to be modified manually now, when we add
  a new RANGE of SSIDs to the msg_mask_tbl */
 #define MSG_MASK_TBL_CNT		24
-#define EVENT_LAST_ID			0x09CB
+#define EVENT_LAST_ID			0x09F6
 
 #define MSG_SSID_0			0
-#define MSG_SSID_0_LAST			97
+#define MSG_SSID_0_LAST			101
 #define MSG_SSID_1			500
 #define MSG_SSID_1_LAST			506
 #define MSG_SSID_2			1000
@@ -138,7 +138,7 @@
 #define MSG_SSID_7			4600
 #define MSG_SSID_7_LAST			4614
 #define MSG_SSID_8			5000
-#define MSG_SSID_8_LAST			5030
+#define MSG_SSID_8_LAST			5031
 #define MSG_SSID_9			5500
 #define MSG_SSID_9_LAST			5516
 #define MSG_SSID_10			6000
@@ -154,7 +154,7 @@
 #define MSG_SSID_15			8000
 #define MSG_SSID_15_LAST		8000
 #define MSG_SSID_16			8500
-#define MSG_SSID_16_LAST		8523
+#define MSG_SSID_16_LAST		8524
 #define MSG_SSID_17			9000
 #define MSG_SSID_17_LAST		9008
 #define MSG_SSID_18			9500
@@ -166,7 +166,7 @@
 #define MSG_SSID_21			10300
 #define MSG_SSID_21_LAST		10300
 #define MSG_SSID_22			10350
-#define MSG_SSID_22_LAST		10374
+#define MSG_SSID_22_LAST		10377
 #define MSG_SSID_23			0xC000
 #define MSG_SSID_23_LAST		0xC063
 
@@ -182,6 +182,7 @@
 	MSG_LVL_LOW,
 	MSG_LVL_ERROR,
 	MSG_LVL_LOW,
+	MSG_LVL_LOW,
 	MSG_LVL_MED,
 	MSG_LVL_MED,
 	MSG_LVL_HIGH,
@@ -280,7 +281,7 @@
 	MSG_LVL_LOW,
 	MSG_LVL_LOW,
 	MSG_LVL_LOW|MSG_LVL_MED|MSG_LVL_HIGH|MSG_LVL_ERROR|MSG_LVL_FATAL,
-	MSG_LVL_MED,
+	MSG_LVL_LOW,
 	MSG_LVL_LOW|MSG_LVL_MED|MSG_LVL_HIGH|MSG_LVL_ERROR|MSG_LVL_FATAL,
 	MSG_LVL_LOW,
 	MSG_LVL_MED,
@@ -292,6 +293,10 @@
 	MSG_LVL_LOW,
 	MSG_LVL_LOW|MSG_LVL_MED|MSG_LVL_HIGH|MSG_LVL_ERROR|MSG_LVL_FATAL,
 	MSG_LVL_MED,
+	MSG_LVL_HIGH,
+	MSG_LVL_LOW,
+	MSG_LVL_HIGH,
+	MSG_LVL_HIGH
 };
 
 static const uint32_t msg_bld_masks_1[] = {
@@ -321,7 +326,8 @@
 	MSG_LVL_MED,
 	MSG_LVL_MED,
 	MSG_LVL_MED,
-	MSG_LVL_MED,
+	MSG_LVL_MED|MSG_MASK_5|MSG_MASK_6|MSG_MASK_7|
+			MSG_MASK_8|MSG_MASK_9|MSG_MASK_10,
 	MSG_LVL_MED,
 	MSG_LVL_MED,
 	MSG_LVL_MED
@@ -439,6 +445,7 @@
 	MSG_LVL_MED,
 	MSG_LVL_MED,
 	MSG_LVL_MED,
+	MSG_LVL_MED,
 	MSG_LVL_MED
 };
 
@@ -632,6 +639,7 @@
 	MSG_LVL_LOW,
 	MSG_LVL_LOW,
 	MSG_LVL_LOW,
+	MSG_LVL_LOW,
 };
 
 static const uint32_t msg_bld_masks_17[] =  {
@@ -722,13 +730,16 @@
 	MSG_LVL_LOW,
 	MSG_LVL_LOW,
 	MSG_LVL_LOW,
+	MSG_LVL_LOW,
+	MSG_LVL_LOW,
+	MSG_LVL_LOW,
 	MSG_LVL_LOW
 };
 
 /* LOG CODES */
 static const uint32_t log_code_last_tbl[] = {
 	0x0,	/* EQUIP ID 0 */
-	0x182F,	/* EQUIP ID 1 */
+	0x184A,	/* EQUIP ID 1 */
 	0x0,	/* EQUIP ID 2 */
 	0x0,	/* EQUIP ID 3 */
 	0x4910,	/* EQUIP ID 4 */
diff --git a/include/linux/hbtp_input.h b/include/linux/hbtp_input.h
new file mode 100644
index 0000000..2c3798e
--- /dev/null
+++ b/include/linux/hbtp_input.h
@@ -0,0 +1,46 @@
+#ifndef _HBTP_INPUT_H
+#define _HBTP_INPUT_H
+
+#include <linux/input.h>
+
+#define HBTP_MAX_FINGER		10
+
+struct hbtp_input_touch {
+	bool active;
+	__s32 tool;
+	__s32 x;
+	__s32 y;
+	__s32 pressure;
+	__s32 major;
+	__s32 minor;
+	__s32 orientation;
+};
+
+struct hbtp_input_mt {
+	__s32 num_touches;
+	struct hbtp_input_touch touches[HBTP_MAX_FINGER];
+};
+
+struct hbtp_input_absinfo {
+	bool  active;
+	__u16 code;
+	__s32 minimum;
+	__s32 maximum;
+};
+
+enum hbtp_afe_power_cmd {
+	HBTP_AFE_POWER_ON,
+	HBTP_AFE_POWER_OFF,
+};
+
+/* ioctl */
+#define HBTP_INPUT_IOCTL_BASE	'T'
+#define HBTP_SET_ABSPARAM	_IOW(HBTP_INPUT_IOCTL_BASE, 201, \
+					struct hbtp_input_absinfo *)
+#define HBTP_SET_TOUCHDATA	_IOW(HBTP_INPUT_IOCTL_BASE, 202, \
+					struct hbtp_input_mt)
+#define HBTP_SET_POWERSTATE	_IOW(HBTP_INPUT_IOCTL_BASE, 203, \
+					enum hbtp_afe_power_cmd)
+
+#endif	/* _HBTP_INPUT_H */
+
diff --git a/arch/arm/boot/dts/msm8926-qrd.dts b/include/linux/i2c/i2c-qup.h
similarity index 62%
copy from arch/arm/boot/dts/msm8926-qrd.dts
copy to include/linux/i2c/i2c-qup.h
index 8ee8828..a950864 100644
--- a/arch/arm/boot/dts/msm8926-qrd.dts
+++ b/include/linux/i2c/i2c-qup.h
@@ -1,4 +1,5 @@
-/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+/*
+ * 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
@@ -10,12 +11,13 @@
  * GNU General Public License for more details.
  */
 
-/dts-v1/;
-/include/ "msm8926.dtsi"
-/include/ "msm8226-qrd.dtsi"
+#ifndef __I2C_QUP_H__
+#define __I2C_QUP_H__
 
-/ {
-	model = "Qualcomm MSM 8926 QRD";
-	compatible = "qcom,msm8926-qrd", "qcom,msm8926", "qcom,qrd";
-	qcom,board-id = <11 0>;
-};
+#ifdef CONFIG_I2C_QUP
+int __init qup_i2c_init_driver(void);
+#else
+static inline int __init qup_i2c_init_driver(void) { return 0; }
+#endif
+
+#endif /* __I2C_QUP_H__ */
diff --git a/include/linux/input.h b/include/linux/input.h
index 558178b..77fc253 100644
--- a/include/linux/input.h
+++ b/include/linux/input.h
@@ -850,6 +850,7 @@
 #define SW_HPHL_OVERCURRENT    0x0e  /* set = over current on left hph */
 #define SW_HPHR_OVERCURRENT    0x0f  /* set = over current on right hph */
 #define SW_UNSUPPORT_INSERT	0x10  /* set = unsupported device inserted */
+#define SW_MICROPHONE2_INSERT   0x11  /* set = inserted */
 #define SW_MAX			0x20
 #define SW_CNT			(SW_MAX+1)
 
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/jbd2.h b/include/linux/jbd2.h
index 912c30a..2ed66ef 100644
--- a/include/linux/jbd2.h
+++ b/include/linux/jbd2.h
@@ -1091,6 +1091,7 @@
 extern int	   jbd2_journal_recover    (journal_t *journal);
 extern int	   jbd2_journal_wipe       (journal_t *, int);
 extern int	   jbd2_journal_skip_recovery	(journal_t *);
+extern void	   jbd2_journal_update_sb_errno(journal_t *);
 extern void	   jbd2_journal_update_sb_log_tail	(journal_t *, tid_t,
 				unsigned long, int);
 extern void	   __jbd2_journal_abort_hard	(journal_t *);
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/mfd/wcd9xxx/core-resource.h b/include/linux/mfd/wcd9xxx/core-resource.h
index 442496e..b45cf6a 100644
--- a/include/linux/mfd/wcd9xxx/core-resource.h
+++ b/include/linux/mfd/wcd9xxx/core-resource.h
@@ -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
@@ -67,6 +67,8 @@
 				unsigned short, u8);
 	int (*codec_bulk_read) (struct wcd9xxx_core_resource *,
 				unsigned short, int, u8 *);
+	int (*codec_bulk_write) (struct wcd9xxx_core_resource *,
+				unsigned short, int, u8 *);
 
 	/* Pointer to parent container data structure */
 	void *parent;
@@ -80,6 +82,8 @@
 	int (*codec_read)(struct wcd9xxx_core_resource *, unsigned short),
 	int (*codec_write)(struct wcd9xxx_core_resource *, unsigned short, u8),
 	int (*codec_bulk_read) (struct wcd9xxx_core_resource *, unsigned short,
+							int, u8 *),
+	int (*codec_bulk_write) (struct wcd9xxx_core_resource *, unsigned short,
 							int, u8 *));
 
 extern void wcd9xxx_core_res_deinit(
diff --git a/include/linux/mfd/wcd9xxx/core.h b/include/linux/mfd/wcd9xxx/core.h
index 85be7c3..a8e792b 100644
--- a/include/linux/mfd/wcd9xxx/core.h
+++ b/include/linux/mfd/wcd9xxx/core.h
@@ -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
@@ -133,6 +133,7 @@
 	u16 grph;				/* slimbus group handle */
 	unsigned long ch_mask;
 	wait_queue_head_t dai_wait;
+	bool bus_down_in_recovery;
 };
 
 #define WCD9XXX_CH(xport, xshift) \
diff --git a/include/linux/mfd/wcd9xxx/wcd9xxx-slimslave.h b/include/linux/mfd/wcd9xxx/wcd9xxx-slimslave.h
index 066a423..263552b 100644
--- a/include/linux/mfd/wcd9xxx/wcd9xxx-slimslave.h
+++ b/include/linux/mfd/wcd9xxx/wcd9xxx-slimslave.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, 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
@@ -112,5 +112,6 @@
 int wcd9xxx_rx_vport_validation(u32 port_id,
 				struct list_head *codec_dai_list);
 int wcd9xxx_tx_vport_validation(u32 vtable, u32 port_id,
-				struct wcd9xxx_codec_dai_data *codec_dai);
+				struct wcd9xxx_codec_dai_data *codec_dai,
+				u32 num_codec_dais);
 #endif /* __WCD9310_SLIMSLAVE_H_ */
diff --git a/include/linux/mhl_8334.h b/include/linux/mhl_8334.h
index 71dec42..42ee81e 100644
--- a/include/linux/mhl_8334.h
+++ b/include/linux/mhl_8334.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
@@ -155,6 +155,8 @@
 	struct list_head list_cmd;
 	struct input_dev *input;
 	struct workqueue_struct *msc_send_workqueue;
+	struct workqueue_struct *mhl_workq;
+	struct work_struct mhl_intr_work;
 	u16 *rcp_key_code_tbl;
 	size_t rcp_key_code_tbl_len;
 	struct scrpd_struct scrpd;
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index 43aebb5..7d51070 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -94,6 +94,7 @@
 	u8			raw_erased_mem_count;	/* 181 */
 	u8			raw_ext_csd_structure;	/* 194 */
 	u8			raw_card_type;		/* 196 */
+	u8			raw_drive_strength;	/* 197 */
 	u8			out_of_int_time;	/* 198 */
 	u8			raw_s_a_timeout;		/* 217 */
 	u8			raw_hc_erase_gap_size;	/* 221 */
@@ -352,6 +353,10 @@
 #define MMC_QUIRK_INAND_DATA_TIMEOUT  (1<<8)    /* For incorrect data timeout */
 /* To avoid eMMC device getting broken permanently due to HPI feature */
 #define MMC_QUIRK_BROKEN_HPI (1 << 11)
+ /* Skip data-timeout advertised by card */
+#define MMC_QUIRK_BROKEN_DATA_TIMEOUT	(1<<12)
+
+#define MMC_QUIRK_CACHE_DISABLE (1 << 14)       /* prevent cache enable */
 
 	unsigned int		erase_size;	/* erase size in sectors */
  	unsigned int		erase_shift;	/* if erase unit is power 2 */
@@ -449,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 bff056d..2ed8a05 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -197,6 +197,12 @@
 	void *handler_priv;
 };
 
+enum dev_state {
+	DEV_SUSPENDING = 1,
+	DEV_SUSPENDED,
+	DEV_RESUMED,
+};
+
 struct mmc_host {
 	struct device		*parent;
 	struct device		class_dev;
@@ -418,9 +424,12 @@
 		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;
+	enum dev_state dev_status;
 	unsigned long		private[0] ____cacheline_aligned;
 };
 
diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
index 764beec..b626915 100644
--- a/include/linux/mmc/mmc.h
+++ b/include/linux/mmc/mmc.h
@@ -303,6 +303,7 @@
 #define EXT_CSD_REV			192	/* RO */
 #define EXT_CSD_STRUCTURE		194	/* RO */
 #define EXT_CSD_CARD_TYPE		196	/* RO */
+#define EXT_CSD_DRIVE_STRENGTH		197	/* RO */
 #define EXT_CSD_OUT_OF_INTERRUPT_TIME	198	/* RO */
 #define EXT_CSD_PART_SWITCH_TIME        199     /* RO */
 #define EXT_CSD_PWR_CL_52_195		200	/* RO */
diff --git a/include/linux/mmc/sdhci.h b/include/linux/mmc/sdhci.h
index 08ca341..9bdf508 100644
--- a/include/linux/mmc/sdhci.h
+++ b/include/linux/mmc/sdhci.h
@@ -113,39 +113,37 @@
  * be called twice.
  */
 #define SDHCI_QUIRK2_SLOW_INT_CLR			(1<<2)
-/* Ignore CMD CRC errors for tuning commands */
-#define SDHCI_QUIRK2_IGNORE_CMDCRC_FOR_TUNING		(1<<3)
 /*
  * If the base clock can be scalable, then there should be no further
  * clock dividing as the input clock itself will be scaled down to
  * required frequency.
  */
-#define SDHCI_QUIRK2_ALWAYS_USE_BASE_CLOCK		(1<<4)
+#define SDHCI_QUIRK2_ALWAYS_USE_BASE_CLOCK		(1<<3)
 /*
  * Dont use the max_discard_to in sdhci driver so that the maximum discard
  * unit gets picked by the mmc queue. Otherwise, it takes a long time for
  * secure discard kind of operations to complete.
  */
-#define SDHCI_QUIRK2_USE_MAX_DISCARD_SIZE		(1<<5)
+#define SDHCI_QUIRK2_USE_MAX_DISCARD_SIZE		(1<<4)
 /*
  * Ignore data timeout error for R1B commands as there will be no
  * data associated and the busy timeout value for these commands
  * could be lager than the maximum timeout value that controller
  * can handle.
  */
-#define SDHCI_QUIRK2_IGNORE_DATATOUT_FOR_R1BCMD		(1<<6)
+#define SDHCI_QUIRK2_IGNORE_DATATOUT_FOR_R1BCMD		(1<<5)
 /*
  * The preset value registers are not properly initialized by
  * some hardware and hence preset value must not be enabled for
  * such controllers.
  */
-#define SDHCI_QUIRK2_BROKEN_PRESET_VALUE		(1<<7)
+#define SDHCI_QUIRK2_BROKEN_PRESET_VALUE		(1<<6)
 /*
  * Some controllers define the usage of 0xF in data timeout counter
  * register (0x2E) which is actually a reserved bit as per
  * specification.
  */
-#define SDHCI_QUIRK2_USE_RESERVED_MAX_TIMEOUT		(1<<8)
+#define SDHCI_QUIRK2_USE_RESERVED_MAX_TIMEOUT		(1<<7)
 /*
  * This is applicable for controllers that advertize timeout clock
  * value in capabilities register (bit 5-0) as just 50MHz whereas the
@@ -158,8 +156,13 @@
  * will be used in such cases to avoid controller mulplication when timeout is
  * calculated based on the base clock.
  */
-#define SDHCI_QUIRK2_DIVIDE_TOUT_BY_4 (1 << 9)
+#define SDHCI_QUIRK2_DIVIDE_TOUT_BY_4 (1 << 8)
 
+/*
+ * Some SDHC controllers are unable to handle data-end bit error in
+ * 1-bit mode of SDIO.
+ */
+#define SDHCI_QUIRK2_IGN_DATA_END_BIT_ERROR             (1<<9)
 	int irq;		/* Device IRQ */
 	void __iomem *ioaddr;	/* Mapped address */
 
@@ -252,6 +255,9 @@
 	struct mutex ios_mutex;
 	enum sdhci_power_policy power_policy;
 
+	bool irq_enabled; /* host irq status flag */
+	bool async_int_supp;  /* async support to rxv int, when clks are off */
+	bool disable_sdio_irq_deferred; /* status of disabling sdio irq */
 	u32 auto_cmd_err_sts;
 	unsigned long private[0] ____cacheline_aligned;
 };
diff --git a/include/linux/msm_hdmi.h b/include/linux/msm_hdmi.h
new file mode 100644
index 0000000..70fae94
--- /dev/null
+++ b/include/linux/msm_hdmi.h
@@ -0,0 +1,57 @@
+/* include/linux/msm_hdmi.h
+ *
+ * Copyright (c) 2014 The Linux Foundation. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#ifndef _MSM_HDMI_H_
+#define _MSM_HDMI_H_
+
+/*
+ * HDMI cable notify handler sturcture.
+ * link A link for the linked list
+ * status Current status of HDMI cable connection
+ * hpd_notify Callback function to provide cable status
+ */
+struct hdmi_cable_notify {
+	struct list_head link;
+	int status;
+	void (*hpd_notify) (struct hdmi_cable_notify *h);
+};
+
+#ifdef CONFIG_FB_MSM_MDSS_HDMI_PANEL
+/*
+ * Register for HDMI cable connect or disconnect notification.
+ * @param handler callback handler for notification
+ * @return negative value as error otherwise current status of cable
+ */
+int register_hdmi_cable_notification(
+		struct hdmi_cable_notify *handler);
+
+/*
+ * Un-register for HDMI cable connect or disconnect notification.
+ * @param handler callback handler for notification
+ * @return negative value as error
+ */
+int unregister_hdmi_cable_notification(
+		struct hdmi_cable_notify *handler);
+#else
+int register_hdmi_cable_notification(
+		struct hdmi_cable_notify *handler) {
+	return 0;
+}
+
+int unregister_hdmi_cable_notification(
+		struct hdmi_cable_notify *handler) {
+	return 0;
+}
+#endif /* CONFIG_FB_MSM_MDSS_HDMI_PANEL */
+
+#endif /*_MSM_HDMI_H_*/
diff --git a/include/linux/msm_ipa.h b/include/linux/msm_ipa.h
index b2229d3..9368d8f 100644
--- a/include/linux/msm_ipa.h
+++ b/include/linux/msm_ipa.h
@@ -64,6 +64,11 @@
 #define IPA_RESOURCE_NAME_MAX 20
 
 /**
+ * max number of interface properties
+ */
+#define IPA_NUM_PROPS_MAX 20
+
+/**
  * size of the mac address
  */
 #define IPA_MAC_ADDR_SIZE  6
diff --git a/include/linux/msm_kgsl.h b/include/linux/msm_kgsl.h
index f74fcbe..17986b5 100644
--- a/include/linux/msm_kgsl.h
+++ b/include/linux/msm_kgsl.h
@@ -24,6 +24,7 @@
 
 #define KGSL_CONTEXT_NO_FAULT_TOLERANCE 0x00000200
 #define KGSL_CONTEXT_SYNC               0x00000400
+#define KGSL_CONTEXT_PWR_CONSTRAINT     0x00000800
 /* bits [12:15] are reserved for future use */
 #define KGSL_CONTEXT_TYPE_MASK          0x01F00000
 #define KGSL_CONTEXT_TYPE_SHIFT         20
@@ -197,6 +198,7 @@
 	KGSL_PROP_VERSION         = 0x00000008,
 	KGSL_PROP_GPU_RESET_STAT  = 0x00000009,
 	KGSL_PROP_PWRCTRL         = 0x0000000E,
+	KGSL_PROP_PWR_CONSTRAINT  = 0x00000012,
 };
 
 struct kgsl_shadowprop {
@@ -882,6 +884,34 @@
 #define IOCTL_KGSL_SUBMIT_COMMANDS \
 	_IOWR(KGSL_IOC_TYPE, 0x3D, struct kgsl_submit_commands)
 
+/**
+ * struct kgsl_device_constraint - device constraint argument
+ * @context_id: KGSL context ID
+ * @type: type of constraint i.e pwrlevel/none
+ * @data: constraint data
+ * @size: size of the constraint data
+ */
+struct kgsl_device_constraint {
+	unsigned int type;
+	unsigned int context_id;
+	void __user *data;
+	size_t size;
+};
+
+/* Constraint Type*/
+#define KGSL_CONSTRAINT_NONE 0
+#define KGSL_CONSTRAINT_PWRLEVEL 1
+
+/* PWRLEVEL constraint level*/
+/* set to min frequency */
+#define KGSL_CONSTRAINT_PWR_MIN    0
+/* set to max frequency */
+#define KGSL_CONSTRAINT_PWR_MAX    1
+
+struct kgsl_device_constraint_pwrlevel {
+	unsigned int level;
+};
+
 #ifdef __KERNEL__
 #ifdef CONFIG_MSM_KGSL_DRM
 int kgsl_gem_obj_addr(int drm_fd, int handle, unsigned long *start,
diff --git a/include/linux/msm_mdp.h b/include/linux/msm_mdp.h
index 0791545..00eba66 100644
--- a/include/linux/msm_mdp.h
+++ b/include/linux/msm_mdp.h
@@ -1,7 +1,7 @@
 /* include/linux/msm_mdp.h
  *
  * Copyright (C) 2007 Google Incorporated
- * Copyright (c) 2012-2013 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2014 The Linux Foundation. All rights reserved.
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
@@ -79,11 +79,36 @@
 #define MSMFB_WRITEBACK_SET_MIRRORING_HINT _IOW(MSMFB_IOCTL_MAGIC, 167, \
 						unsigned int)
 #define MSMFB_ASYNC_BLIT              _IOW(MSMFB_IOCTL_MAGIC, 168, unsigned int)
-
+#define MSMFB_OVERLAY_PREPARE		_IOWR(MSMFB_IOCTL_MAGIC, 169, \
+						struct mdp_overlay_list)
 #define FB_TYPE_3D_PANEL 0x10101010
 #define MDP_IMGTYPE2_START 0x10000
 #define MSMFB_DRIVER_VERSION	0xF9E8D701
 
+/* HW Revisions for different MDSS targets */
+#define MDSS_GET_MAJOR(rev)		((rev) >> 28)
+#define MDSS_GET_MINOR(rev)		(((rev) >> 16) & 0xFFF)
+#define MDSS_GET_STEP(rev)		((rev) & 0xFFFF)
+#define MDSS_GET_MAJOR_MINOR(rev)	((rev) >> 16)
+
+#define IS_MDSS_MAJOR_MINOR_SAME(rev1, rev2)	\
+	(MDSS_GET_MAJOR_MINOR((rev1)) == MDSS_GET_MAJOR_MINOR((rev2)))
+
+#define MDSS_MDP_REV(major, minor, step)	\
+	((((major) & 0x000F) << 28) |		\
+	 (((minor) & 0x0FFF) << 16) |		\
+	 ((step)   & 0xFFFF))
+
+#define MDSS_MDP_HW_REV_100	MDSS_MDP_REV(1, 0, 0) /* 8974 v1.0 */
+#define MDSS_MDP_HW_REV_101	MDSS_MDP_REV(1, 1, 0) /* 8x26 v1.0 */
+#define MDSS_MDP_HW_REV_101_1	MDSS_MDP_REV(1, 1, 1) /* 8x26 v2.0, 8926 v1.0 */
+#define MDSS_MDP_HW_REV_101_2	MDSS_MDP_REV(1, 1, 2) /* 8926 v2.0 */
+#define MDSS_MDP_HW_REV_102	MDSS_MDP_REV(1, 2, 0) /* 8974 v2.0 */
+#define MDSS_MDP_HW_REV_102_1	MDSS_MDP_REV(1, 2, 1) /* 8974 v3.0 (Pro) */
+#define MDSS_MDP_HW_REV_103	MDSS_MDP_REV(1, 3, 0) /* 8084 v1.0 */
+#define MDSS_MDP_HW_REV_103_1	MDSS_MDP_REV(1, 3, 1) /* 8084 v1.1 */
+#define MDSS_MDP_HW_REV_200	MDSS_MDP_REV(2, 0, 0) /* 8092 v1.0 */
+
 enum {
 	NOTIFY_UPDATE_START,
 	NOTIFY_UPDATE_STOP,
@@ -94,6 +119,7 @@
 	NOTIFY_TYPE_NO_UPDATE,
 	NOTIFY_TYPE_SUSPEND,
 	NOTIFY_TYPE_UPDATE,
+	NOTIFY_TYPE_BL_UPDATE,
 };
 
 enum {
@@ -169,7 +195,7 @@
 #define MDP_BLUR 0x10
 #define MDP_BLEND_FG_PREMULT 0x20000
 #define MDP_IS_FG 0x40000
-#define MDP_SOLID_FILL 0x0000100
+#define MDP_SOLID_FILL 0x00000020
 #define MDP_DEINTERLACE 0x80000000
 #define MDP_SHARPENING  0x40000000
 #define MDP_NO_DMA_BARRIER_START	0x20000000
@@ -422,7 +448,7 @@
 	uint32_t val_region;
 };
 
-#define MDP_SIX_ZONE_TABLE_NUM		384
+#define MDP_SIX_ZONE_LUT_SIZE		384
 
 struct mdp_pa_v2_data {
 	/* Mask bits for PA features */
@@ -431,12 +457,13 @@
 	uint32_t global_sat_adj;
 	uint32_t global_val_adj;
 	uint32_t global_cont_adj;
-	uint32_t *six_zone_curve_p0;
-	uint32_t *six_zone_curve_p1;
-	uint32_t six_zone_thresh;
 	struct mdp_pa_mem_col_cfg skin_cfg;
 	struct mdp_pa_mem_col_cfg sky_cfg;
 	struct mdp_pa_mem_col_cfg fol_cfg;
+	uint32_t six_zone_len;
+	uint32_t six_zone_thresh;
+	uint32_t *six_zone_curve_p0;
+	uint32_t *six_zone_curve_p1;
 };
 
 struct mdp_igc_lut_data {
@@ -810,6 +837,7 @@
 
 #define MDSS_MAX_BL_BRIGHTNESS 255
 #define AD_BL_LIN_LEN 256
+#define AD_BL_ATT_LUT_LEN 33
 
 #define MDSS_AD_MODE_AUTO_BL	0x0
 #define MDSS_AD_MODE_AUTO_STR	0x1
@@ -838,9 +866,13 @@
 	uint16_t frame_h;
 	uint8_t logo_v;
 	uint8_t logo_h;
+	uint32_t alpha;
+	uint32_t alpha_base;
 	uint32_t bl_lin_len;
+	uint32_t bl_att_len;
 	uint32_t *bl_lin;
 	uint32_t *bl_lin_inv;
+	uint32_t *bl_att_lut;
 };
 
 #define MDSS_AD_BL_CTRL_MODE_EN 1
@@ -964,6 +996,8 @@
 	uint8_t rgb_pipes;
 	uint8_t vig_pipes;
 	uint8_t dma_pipes;
+	uint8_t max_smp_cnt;
+	uint8_t smp_per_pipe;
 	uint32_t features;
 };
 
@@ -983,6 +1017,7 @@
 
 #define MDP_MAX_FENCE_FD	32
 #define MDP_BUF_SYNC_FLAG_WAIT	1
+#define MDP_BUF_SYNC_FLAG_RETIRE_FENCE	0x10
 
 struct mdp_buf_sync {
 	uint32_t flags;
@@ -990,6 +1025,7 @@
 	uint32_t session_id;
 	int *acq_fen_fd;
 	int *rel_fen_fd;
+	int *retire_fen_fd;
 };
 
 struct mdp_async_blit_req_list {
@@ -999,22 +1035,32 @@
 };
 
 #define MDP_DISPLAY_COMMIT_OVERLAY	1
-struct mdp_buf_fence {
-	uint32_t flags;
-	uint32_t acq_fen_fd_cnt;
-	int acq_fen_fd[MDP_MAX_FENCE_FD];
-	int rel_fen_fd[MDP_MAX_FENCE_FD];
-};
-
 
 struct mdp_display_commit {
 	uint32_t flags;
 	uint32_t wait_for_finish;
 	struct fb_var_screeninfo var;
-	struct mdp_buf_fence buf_fence;
 	struct mdp_rect roi;
 };
 
+/**
+* struct mdp_overlay_list - argument for ioctl MSMFB_OVERLAY_PREPARE
+* @num_overlays:	Number of overlay layers as part of the frame.
+* @overlay_list:	Pointer to a list of overlay structures identifying
+*			the layers as part of the frame
+* @flags:		Flags can be used to extend behavior.
+* @processed_overlays:	Output parameter indicating how many pipes were
+*			successful. If there are no errors this number should
+*			match num_overlays. Otherwise it will indicate the last
+*			successful index for overlay that couldn't be set.
+*/
+struct mdp_overlay_list {
+	uint32_t num_overlays;
+	struct mdp_overlay **overlay_list;
+	uint32_t flags;
+	uint32_t processed_overlays;
+};
+
 struct mdp_page_protection {
 	uint32_t page_protection;
 };
@@ -1068,6 +1114,7 @@
 int msm_fb_writeback_stop(struct fb_info *info);
 int msm_fb_writeback_terminate(struct fb_info *info);
 int msm_fb_writeback_set_secure(struct fb_info *info, int enable);
+int msm_fb_writeback_iommu_ref(struct fb_info *info, int enable);
 #endif
 
 #endif /*_MSM_MDP_H_*/
diff --git a/include/linux/msm_vidc_dec.h b/include/linux/msm_vidc_dec.h
index 35279bf..b09fc2d 100644
--- a/include/linux/msm_vidc_dec.h
+++ b/include/linux/msm_vidc_dec.h
@@ -58,6 +58,8 @@
 #define VDEC_MSG_EVT_HW_ERROR	(VDEC_MSG_BASE + 14)
 #define VDEC_MSG_EVT_INFO_CONFIG_CHANGED	(VDEC_MSG_BASE + 15)
 #define VDEC_MSG_EVT_INFO_FIELD_DROPPED	(VDEC_MSG_BASE + 16)
+#define VDEC_MSG_EVT_HW_OVERLOAD	(VDEC_MSG_BASE + 17)
+#define VDEC_MSG_EVT_MAX_CLIENTS	(VDEC_MSG_BASE + 18)
 
 /*Buffer flags bits masks.*/
 #define VDEC_BUFFERFLAG_EOS	0x00000001
diff --git a/include/linux/msm_vidc_enc.h b/include/linux/msm_vidc_enc.h
index dcc2353..36625a7 100644
--- a/include/linux/msm_vidc_enc.h
+++ b/include/linux/msm_vidc_enc.h
@@ -45,7 +45,8 @@
 #define VEN_MSG_RESUME	9
 #define VEN_MSG_STOP_READING_MSG	10
 #define VEN_MSG_LTRUSE_FAILED	    11
-
+#define VEN_MSG_HW_OVERLOAD	12
+#define VEN_MSG_MAX_CLIENTS	13
 
 /*Buffer flags bits masks*/
 #define VEN_BUFFLAG_EOS	0x00000001
@@ -59,6 +60,7 @@
 #define VEN_EXTRADATA_QCOMFILLER    0x002
 #define VEN_EXTRADATA_SLICEINFO     0x100
 #define VEN_EXTRADATA_LTRINFO       0x200
+#define VEN_EXTRADATA_MBINFO        0x400
 
 /*ENCODER CONFIGURATION CONSTANTS*/
 
diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h
index 6a68b72..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
@@ -615,6 +625,34 @@
  * @NL80211_CMD_CRIT_PROTOCOL_STOP: Indicates the connection reliability can
  *	return back to normal.
  *
+ * @NL80211_CMD_GET_COALESCE: Get currently supported coalesce rules.
+ * @NL80211_CMD_SET_COALESCE: Configure coalesce rules or clear existing rules.
+ *
+ * @NL80211_CMD_CHANNEL_SWITCH: Perform a channel switch by announcing the
+ *	the new channel information (Channel Switch Announcement - CSA)
+ *	in the beacon for some time (as defined in the
+ *	%NL80211_ATTR_CH_SWITCH_COUNT parameter) and then change to the
+ *	new channel. Userspace provides the new channel information (using
+ *	%NL80211_ATTR_WIPHY_FREQ and the attributes determining channel
+ *	width). %NL80211_ATTR_CH_SWITCH_BLOCK_TX may be supplied to inform
+ *	other station that transmission must be blocked until the channel
+ *	switch is complete.
+ *
+ * @NL80211_CMD_VENDOR: Vendor-specified command/event. The command is specified
+ *	by the %NL80211_ATTR_VENDOR_ID attribute and a sub-command in
+ *	%NL80211_ATTR_VENDOR_SUBCMD. Parameter(s) can be transported in
+ *	%NL80211_ATTR_VENDOR_DATA.
+ *	For feature advertisement, the %NL80211_ATTR_VENDOR_DATA attribute is
+ *	used in the wiphy data as a nested attribute containing descriptions
+ *	(&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
  */
@@ -778,6 +816,15 @@
 	NL80211_CMD_CRIT_PROTOCOL_START,
 	NL80211_CMD_CRIT_PROTOCOL_STOP,
 
+	NL80211_CMD_GET_COALESCE,
+	NL80211_CMD_SET_COALESCE,
+
+	NL80211_CMD_CHANNEL_SWITCH,
+
+	NL80211_CMD_VENDOR,
+
+	NL80211_CMD_SET_QOS_MAP,
+
 	/* add new commands above here */
 
 	/* used to define NL80211_CMD_MAX below */
@@ -1380,6 +1427,60 @@
  *	allowed to be used with the first @NL80211_CMD_SET_STATION command to
  *	update a TDLS peer STA entry.
  *
+ * @NL80211_ATTR_COALESCE_RULE: Coalesce rule information.
+ *
+ * @NL80211_ATTR_CH_SWITCH_COUNT: u32 attribute specifying the number of TBTT's
+ *	until the channel switch event.
+ * @NL80211_ATTR_CH_SWITCH_BLOCK_TX: flag attribute specifying that transmission
+ *	must be blocked on the current channel (before the channel switch
+ *	operation).
+ * @NL80211_ATTR_CSA_IES: Nested set of attributes containing the IE information
+ *	for the time while performing a channel switch.
+ * @NL80211_ATTR_CSA_C_OFF_BEACON: Offset of the channel switch counter
+ *	field in the beacons tail (%NL80211_ATTR_BEACON_TAIL).
+ * @NL80211_ATTR_CSA_C_OFF_PRESP: Offset of the channel switch counter
+ *	field in the probe response (%NL80211_ATTR_PROBE_RESP).
+ *
+ * @NL80211_ATTR_RXMGMT_FLAGS: flags for nl80211_send_mgmt(), u32.
+ *	As specified in the &enum nl80211_rxmgmt_flags.
+ *
+ * @NL80211_ATTR_STA_SUPPORTED_CHANNELS: array of supported channels.
+ *
+ * @NL80211_ATTR_STA_SUPPORTED_OPER_CLASSES: array of supported
+ *      supported operating classes.
+ *
+ * @NL80211_ATTR_HANDLE_DFS: A flag indicating whether user space
+ *	controls DFS operation in IBSS mode. If the flag is included in
+ *	%NL80211_CMD_JOIN_IBSS request, the driver will allow use of DFS
+ *	channels and reports radar events to userspace. Userspace is required
+ *	to react to radar events, e.g. initiate a channel switch or leave the
+ *	IBSS network.
+ *
+ * @NL80211_ATTR_VENDOR_ID: The vendor ID, either a 24-bit OUI or, if
+ *	%NL80211_VENDOR_ID_IS_LINUX is set, a special Linux ID (not used yet)
+ * @NL80211_ATTR_VENDOR_SUBCMD: vendor sub-command
+ * @NL80211_ATTR_VENDOR_DATA: data for the vendor command, if any; this
+ *	attribute is also used for vendor command feature advertisement
+ * @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
  */
@@ -1680,6 +1781,42 @@
 
 	NL80211_ATTR_PEER_AID,
 
+	NL80211_ATTR_COALESCE_RULE,
+
+	NL80211_ATTR_CH_SWITCH_COUNT,
+	NL80211_ATTR_CH_SWITCH_BLOCK_TX,
+	NL80211_ATTR_CSA_IES,
+	NL80211_ATTR_CSA_C_OFF_BEACON,
+	NL80211_ATTR_CSA_C_OFF_PRESP,
+
+	NL80211_ATTR_RXMGMT_FLAGS,
+
+	NL80211_ATTR_STA_SUPPORTED_CHANNELS,
+
+	NL80211_ATTR_STA_SUPPORTED_OPER_CLASSES,
+
+	NL80211_ATTR_HANDLE_DFS,
+
+	NL80211_ATTR_SUPPORT_5_MHZ,
+	NL80211_ATTR_SUPPORT_10_MHZ,
+
+	NL80211_ATTR_OPMODE_NOTIF,
+
+	NL80211_ATTR_VENDOR_ID,
+	NL80211_ATTR_VENDOR_SUBCMD,
+	NL80211_ATTR_VENDOR_DATA,
+
+	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,
@@ -3143,4 +3280,40 @@
 /* maximum duration for critical protocol measures */
 #define NL80211_CRIT_PROTO_MAX_DURATION		5000 /* msec */
 
+/*
+ * If this flag is unset, the lower 24 bits are an OUI, if set
+ * a Linux nl80211 vendor ID is used (no such IDs are allocated
+ * yet, so that's not valid so far)
+ */
+#define NL80211_VENDOR_ID_IS_LINUX	0x80000000
+
+/**
+ * struct nl80211_vendor_cmd_info - vendor command data
+ * @vendor_id: If the %NL80211_VENDOR_ID_IS_LINUX flag is clear, then the
+ *	value is a 24-bit OUI; if it is set then a separately allocated ID
+ *	may be used, but no such IDs are allocated yet. New IDs should be
+ *	added to this file when needed.
+ * @subcmd: sub-command ID for the command
+ */
+struct nl80211_vendor_cmd_info {
+	__u32 vendor_id;
+	__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/perf_event.h b/include/linux/perf_event.h
index ddbb6a9..289754e 100644
--- a/include/linux/perf_event.h
+++ b/include/linux/perf_event.h
@@ -254,8 +254,9 @@
 
 				exclude_host   :  1, /* don't count in host   */
 				exclude_guest  :  1, /* don't count in guest  */
+				constraint_duplicate : 1,
 
-				__reserved_1   : 43;
+				__reserved_1   : 42;
 
 	union {
 		__u32		wakeup_events;	  /* wakeup every n events */
@@ -740,6 +741,8 @@
 	int * __percpu			pmu_disable_count;
 	struct perf_cpu_context * __percpu pmu_cpu_context;
 	int				task_ctx_nr;
+	u32                             events_across_hotplug:1,
+					reserved:31;
 
 	/*
 	 * Fully disable/enable this PMU, can be used to protect from the PMI
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/qpnp-revid.h b/include/linux/qpnp-revid.h
index 3cf9f1c..3d271f0 100644
--- a/include/linux/qpnp-revid.h
+++ b/include/linux/qpnp-revid.h
@@ -13,6 +13,13 @@
 #ifndef __QPNP_REVID
 #define __QPNP_REVID
 
+#define PM8226_V2P2_REV1	0x00
+#define PM8226_V2P2_REV2	0x00
+#define PM8226_V2P2_REV3	0x02
+#define PM8226_V2P2_REV4	0x02
+#define PM8226_V2P2_TYPE	0x51
+#define PM8226_V2P2_SUBTYPE	0x04
+
 #define PM8226_V2P1_REV1	0x00
 #define PM8226_V2P1_REV2	0x00
 #define PM8226_V2P1_REV3	0x01
diff --git a/include/linux/qpnp/power-on.h b/include/linux/qpnp/power-on.h
index 772bf62..ae4e731 100644
--- a/include/linux/qpnp/power-on.h
+++ b/include/linux/qpnp/power-on.h
@@ -52,6 +52,7 @@
 int qpnp_pon_system_pwr_off(enum pon_power_off_type type);
 int qpnp_pon_is_warm_reset(void);
 int qpnp_pon_trigger_config(enum pon_trigger_source pon_src, bool enable);
+int qpnp_pon_wd_config(bool enable);
 #else
 static int qpnp_pon_system_pwr_off(enum pon_power_off_type type)
 {
@@ -63,6 +64,10 @@
 {
 	return -ENODEV;
 }
+int qpnp_pon_wd_config(bool enable)
+{
+	return -ENODEV;
+}
 #endif
 
 #endif
diff --git a/include/linux/qpnp/qpnp-adc.h b/include/linux/qpnp/qpnp-adc.h
index 6e711c2..52195c1 100644
--- a/include/linux/qpnp/qpnp-adc.h
+++ b/include/linux/qpnp/qpnp-adc.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
@@ -20,6 +20,7 @@
 
 #include <linux/kernel.h>
 #include <linux/list.h>
+#include <linux/qpnp-revid.h>
 /**
  * enum qpnp_vadc_channels - QPNP AMUX arbiter channels
  */
@@ -190,6 +191,7 @@
  * %CHAN_PATH_SCALING2: ratio of {1, 4}
  * %CHAN_PATH_SCALING3: ratio of {1, 6}
  * %CHAN_PATH_SCALING4: ratio of {1, 20}
+ * %CHAN_PATH_SCALING5: ratio of {1, 8}
  * %CHAN_PATH_NONE: Do not use this pre-scaling ratio type.
  *
  * The pre-scaling is applied for signals to be within the voltage range
@@ -201,6 +203,7 @@
 	PATH_SCALING2,
 	PATH_SCALING3,
 	PATH_SCALING4,
+	PATH_SCALING5,
 	PATH_SCALING_NONE,
 };
 
@@ -220,6 +223,8 @@
  *			btm parameters.
  * %SCALE_QRD_SKUAA_BATT_THERM: Conversion to temperature(decidegC) based on
  *          btm parametersi for SKUAA.
+ * %SCALE_QRD_SKUG_BATT_THERM: Conversion to temperature(decidegC) based on
+ * btm parametersi for SKUG.
  * %SCALE_NONE: Do not use this scaling type.
  */
 enum qpnp_adc_scale_fn_type {
@@ -231,6 +236,7 @@
 	SCALE_THERM_150K_PULLUP,
 	SCALE_QRD_BATT_THERM,
 	SCALE_QRD_SKUAA_BATT_THERM,
+	SCALE_QRD_SKUG_BATT_THERM = 9,
 	SCALE_NONE,
 };
 
@@ -569,12 +575,10 @@
 /**
  * enum qpnp_adc_meas_timer_select - Selects the timer for which
  *	the appropriate polling frequency is set.
- * %ADC_MEAS_TIMER_SELECT1 - Select this timer if the client is USB_ID.
- * %ADC_MEAS_TIMER_SELECT2 - Select this timer if the client is batt_therm.
- * %ADC_MEAS_TIMER_SELECT3 - The timer is added only for completion. It is
- *	not used by kernel space clients and user space clients cannot set
- *	the polling frequency. The driver will set a appropriate polling
- *	frequency to measure the user space clients from qpnp_adc_meas_timer_3.
+ * %ADC_MEAS_TIMER_SELECT1 - Select this timer for measurement polling interval
+ *				for 1 second.
+ * %ADC_MEAS_TIMER_SELECT2 - Select this timer for 500ms measurement interval.
+ * %ADC_MEAS_TIMER_SELECT3 - Select this timer for 5 second interval.
  */
 enum qpnp_adc_meas_timer_select {
 	ADC_MEAS_TIMER_SELECT1 = 0,
@@ -836,6 +840,7 @@
 	enum qpnp_adc_meas_timer_2		meas_interval2;
 	enum qpnp_adc_tm_channel_select		tm_channel_select;
 	enum qpnp_state_request			state_request;
+	enum qpnp_adc_calib_type		calib_type;
 	struct qpnp_vadc_linear_graph	adc_graph[2];
 };
 
@@ -879,6 +884,7 @@
 	enum qpnp_adc_scale_fn_type		adc_scale_fn;
 	enum qpnp_adc_fast_avg_ctl		fast_avg_setup;
 	enum qpnp_adc_hw_settle_time		hw_settle_time;
+	enum qpnp_adc_calib_type		calib_type;
 };
 
 /**
@@ -890,7 +896,8 @@
 	{1, 3},
 	{1, 4},
 	{1, 6},
-	{1, 20}
+	{1, 20},
+	{1, 8}
 };
 
 /**
@@ -998,15 +1005,27 @@
  * @chan_prop - Represent the channel properties of the ADC.
  */
 struct qpnp_adc_amux_properties {
-	uint32_t			amux_channel;
-	uint32_t			decimation;
-	uint32_t			mode_sel;
-	uint32_t			hw_settle_time;
-	uint32_t			fast_avg_setup;
-	enum qpnp_vadc_trigger		trigger_channel;
+	uint32_t				amux_channel;
+	uint32_t				decimation;
+	uint32_t				mode_sel;
+	uint32_t				hw_settle_time;
+	uint32_t				fast_avg_setup;
+	enum qpnp_vadc_trigger			trigger_channel;
 	struct qpnp_vadc_chan_properties	chan_prop[0];
 };
 
+/* SW index's for PMIC type and version used by QPNP VADC and IADC */
+#define QPNP_REV_ID_8941_3_1	1
+#define QPNP_REV_ID_8026_1_0	2
+#define QPNP_REV_ID_8026_2_0	3
+#define QPNP_REV_ID_8110_1_0	4
+#define QPNP_REV_ID_8026_2_1	5
+#define QPNP_REV_ID_8110_2_0	6
+#define QPNP_REV_ID_8026_2_2	7
+#define QPNP_REV_ID_8941_3_0	8
+#define QPNP_REV_ID_8941_2_0	9
+
+
 /* Public API */
 #if defined(CONFIG_SENSORS_QPNP_ADC_VOLTAGE)				\
 			|| defined(CONFIG_SENSORS_QPNP_ADC_VOLTAGE_MODULE)
@@ -1135,6 +1154,23 @@
 			const struct qpnp_vadc_chan_properties *chan_prop,
 			struct qpnp_vadc_result *chan_rslt);
 /**
+ * qpnp_adc_scale_qrd_skug_batt_therm() - Scales the pre-calibrated digital output
+ *		of an ADC to the ADC reference and compensates for the
+ *		gain and offset. Returns the temperature in decidegC.
+ * @dev:	Structure device for qpnp vadc
+ * @adc_code:	pre-calibrated digital ouput of the ADC.
+ * @adc_prop:	adc properties of the pm8xxx adc such as bit resolution,
+ *		reference voltage.
+ * @chan_prop:	individual channel properties to compensate the i/p scaling,
+ *		slope and offset.
+ * @chan_rslt:	physical result to be stored.
+ */
+int32_t qpnp_adc_scale_qrd_skug_batt_therm(struct qpnp_vadc_chip *dev,
+			int32_t adc_code,
+			const struct qpnp_adc_properties *adc_prop,
+			const struct qpnp_vadc_chan_properties *chan_prop,
+			struct qpnp_vadc_result *chan_rslt);
+/**
  * qpnp_adc_scale_batt_id() - Scales the pre-calibrated digital output
  *		of an ADC to the ADC reference and compensates for the
  *		gain and offset.
@@ -1345,9 +1381,16 @@
  * qpnp_vadc_sns_comp_result() - Compensate vbatt readings based on temperature
  * @dev:	Structure device for qpnp vadc
  * @result:	Voltage in uV that needs compensation.
+ * @is_pon_ocv: Whether the reading is from a power on OCV or not
  */
 int32_t qpnp_vbat_sns_comp_result(struct qpnp_vadc_chip *dev,
-						int64_t *result);
+					int64_t *result, bool is_pon_ocv);
+/**
+ * qpnp_adc_get_revid_version() - Obtain the PMIC number and revision.
+ * @dev:	Structure device node.
+ * returns internal mapped PMIC number and revision id.
+ */
+int qpnp_adc_get_revid_version(struct device *dev);
 #else
 static inline int32_t qpnp_vadc_read(struct qpnp_vadc_chip *dev,
 				uint32_t channel,
@@ -1388,6 +1431,12 @@
 			const struct qpnp_vadc_chan_properties *chan_prop,
 			struct qpnp_vadc_result *chan_rslt)
 { return -ENXIO; }
+static inline int32_t qpnp_adc_scale_qrd_skug_batt_therm(
+			struct qpnp_vadc_chip *vadc, int32_t adc_code,
+			const struct qpnp_adc_properties *adc_prop,
+			const struct qpnp_vadc_chan_properties *chan_prop,
+			struct qpnp_vadc_result *chan_rslt)
+{ return -ENXIO; }
 static inline int32_t qpnp_adc_scale_batt_id(struct qpnp_vadc_chip *vadc,
 			int32_t adc_code,
 			const struct qpnp_adc_properties *adc_prop,
@@ -1455,6 +1504,8 @@
 static inline int32_t qpnp_vbat_sns_comp_result(struct qpnp_vadc_chip *dev,
 						int64_t *result)
 { return -ENXIO; }
+static inline int qpnp_adc_get_revid_version(struct device *dev)
+{ return -ENXIO; }
 #endif
 
 /* Public API */
diff --git a/include/linux/qrng.h b/include/linux/qrng.h
index 35708e3..8c09627 100644
--- a/include/linux/qrng.h
+++ b/include/linux/qrng.h
@@ -1,5 +1,5 @@
-#ifndef __QRNG_H_
-#define __QRNG_H_
+#ifndef _QRNG_H_
+#define _QRNG_H_
 
 #include <linux/types.h>
 #include <linux/ioctl.h>
@@ -9,4 +9,4 @@
 #define QRNG_IOCTL_RESET_BUS_BANDWIDTH\
 	_IO(QRNG_IOC_MAGIC, 1)
 
-#endif /* __QRNG_H_ */
+#endif /* _QRNG_H_ */
diff --git a/include/linux/qseecom.h b/include/linux/qseecom.h
index a45c34c..b63b36e 100644
--- a/include/linux/qseecom.h
+++ b/include/linux/qseecom.h
@@ -127,6 +127,8 @@
 
 enum qseecom_key_management_usage_type {
 	QSEOS_KM_USAGE_DISK_ENCRYPTION = 0x01,
+	QSEOS_KM_USAGE_FILE_ENCRYPTION = 0x02,
+	QSEOS_KM_USAGE_MAX
 };
 
 struct qseecom_create_key_req {
@@ -136,6 +138,14 @@
 
 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 {
+	unsigned char current_hash32[QSEECOM_HASH_SIZE];
+	unsigned char new_hash32[QSEECOM_HASH_SIZE];
+	enum qseecom_key_management_usage_type usage;
 };
 
 #define SHA256_DIGEST_LENGTH	(256/8)
@@ -157,11 +167,6 @@
 	int is_activated; /* out */
 };
 
-enum qseecom_buffer_protection {
-	QSEOS_UNPROTECTED_BUFFER,
-	QSEOS_PROTECT_BUFFER,
-	QSEOS_UNPROTECT_PROTECTED_BUFFER,
-};
 
 enum qseecom_bandwidth_request_mode {
 	INACTIVE = 0,
@@ -181,7 +186,6 @@
 	void *resp_buf_ptr; /* in */
 	unsigned int resp_len; /* in */
 	struct qseecom_ion_fd_info ifd_data[MAX_ION_FD]; /* in */
-	enum qseecom_buffer_protection protection_mode; /* in */
 };
 
 #define QSEECOM_IOC_MAGIC    0x97
@@ -250,10 +254,10 @@
 #define QSEECOM_IOCTL_SEND_MODFD_RESP \
 	_IOWR(QSEECOM_IOC_MAGIC, 21, struct qseecom_send_modfd_listener_resp)
 
-#define QSEECOM_IOCTL_UNPROTECT_BUF \
-	_IOWR(QSEECOM_IOC_MAGIC, 22, int)
-
 #define QSEECOM_IOCTL_SET_BUS_SCALING_REQ \
 	_IOWR(QSEECOM_IOC_MAGIC, 23, int)
 
+#define QSEECOM_IOCTL_UPDATE_KEY_USER_INFO_REQ \
+	_IOWR(QSEECOM_IOC_MAGIC, 24, struct qseecom_update_key_userinfo_req)
+
 #endif /* __QSEECOM_H_ */
diff --git a/include/linux/regulator/cpr-regulator.h b/include/linux/regulator/cpr-regulator.h
index 624860e..9d06a8c 100644
--- a/include/linux/regulator/cpr-regulator.h
+++ b/include/linux/regulator/cpr-regulator.h
@@ -1,5 +1,5 @@
 /*
- * 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
@@ -16,41 +16,54 @@
 
 #include <linux/regulator/machine.h>
 
-#define CPR_REGULATOR_DRIVER_NAME	"qti,cpr-regulator"
+#define CPR_REGULATOR_DRIVER_NAME	"qcom,cpr-regulator"
 
-#define CPR_PVS_EFUSE_BITS_MAX		5
-#define CPR_PVS_EFUSE_BINS_MAX		(1 << CPR_PVS_EFUSE_BITS_MAX)
+/**
+ * enum cpr_fuse_corner_enum - CPR fuse corner enum values
+ * %CPR_FUSE_CORNER_SVS:		Lowest voltage for APC
+ * %CPR_FUSE_CORNER_NORMAL:		Normal mode voltage
+ * %CPR_FUSE_CORNER_TURBO:		Turbo mode voltage
+ * %CPR_FUSE_CORNER_SUPER_TURBO:	Super Turbo mode voltage
+ *
+ */
+enum cpr_fuse_corner_enum {
+	CPR_FUSE_CORNER_SVS = 1,
+	CPR_FUSE_CORNER_NORMAL,
+	CPR_FUSE_CORNER_TURBO,
+	CPR_FUSE_CORNER_MAX,
+};
 
 /**
  * enum cpr_corner_enum - CPR corner enum values
- * %CPR_CORNER_SVS:		Lowest voltage for APC
- * %CPR_CORNER_NORMAL:		Normal mode voltage
- * %CPR_CORNER_TURBO:		Turbo mode voltage
- * %CPR_CORNER_SUPER_TURBO:	Super Turbo mode voltage
+ * %CPR_CORNER_1:		Lowest voltage for APC
+ * %CPR_CORNER_2:		Second lowest voltage for APC
+ * %CPR_CORNER_3:		Third lowest voltage for APC
+ * %CPR_CORNER_4:		Forth lowest voltage for APC
+ * %CPR_CORNER_5:		Fifth lowest voltage for APC
+ * %CPR_CORNER_6:		Sixth lowest voltage for APC
+ * %CPR_CORNER_7:		Seventh lowest voltage for APC
+ * %CPR_CORNER_8:		Eighth lowest voltage for APC
+ * %CPR_CORNER_9:		Ninth lowest voltage for APC
+ * %CPR_CORNER_10:		Tenth lowest voltage for APC
+ * %CPR_CORNER_11:		Eleventh lowest voltage for APC
+ * %CPR_CORNER_12:		Twelfth lowest voltage for APC
  *
  * These should be used in regulator_set_voltage() for CPR
  * regulator as if they had units of uV.
  */
 enum cpr_corner_enum {
-	CPR_CORNER_SVS = 1,
-	CPR_CORNER_NORMAL,
-	CPR_CORNER_TURBO,
-	CPR_CORNER_MAX,
-};
-
-/**
- * enum pvs_process_enum - PVS process enum values
- * %APC_PVS_NO:		No PVS
- * %APC_PVS_SLOW:	Slow PVS process
- * %APC_PVS_NOM:	Nominal PVS process
- * %APC_PVS_FAST:	Fast PVS process
- */
-enum apc_pvs_process_enum {
-	APC_PVS_NO,
-	APC_PVS_SLOW,
-	APC_PVS_NOM,
-	APC_PVS_FAST,
-	NUM_APC_PVS,
+	CPR_CORNER_1 = 1,
+	CPR_CORNER_2,
+	CPR_CORNER_3,
+	CPR_CORNER_4,
+	CPR_CORNER_5,
+	CPR_CORNER_6,
+	CPR_CORNER_7,
+	CPR_CORNER_8,
+	CPR_CORNER_9,
+	CPR_CORNER_10,
+	CPR_CORNER_11,
+	CPR_CORNER_12,
 };
 
 /**
@@ -60,12 +73,15 @@
  * %VDD_MX_VMIN_APC_SLOW_CORNER_CEILING:
  *					Equal to slow speed corner ceiling
  * %VDD_MX_VMIN_MX_VMAX:		Equal to specified vdd-mx-vmax voltage
+ * %VDD_MX_VMIN_APC_CORNER_MAP:		Equal to the APC corner mapped MX
+ *					voltage
  */
 enum vdd_mx_vmin_method {
 	VDD_MX_VMIN_APC,
 	VDD_MX_VMIN_APC_CORNER_CEILING,
 	VDD_MX_VMIN_APC_SLOW_CORNER_CEILING,
 	VDD_MX_VMIN_MX_VMAX,
+	VDD_MX_VMIN_APC_CORNER_MAP,
 };
 
 #ifdef CONFIG_MSM_CPR_REGULATOR
diff --git a/include/linux/regulator/fan53555.h b/include/linux/regulator/fan53555.h
new file mode 100644
index 0000000..bb22419
--- /dev/null
+++ b/include/linux/regulator/fan53555.h
@@ -0,0 +1,66 @@
+/*
+ * fan53555.h - Fairchild Regulator FAN53555 Driver
+ *
+ * Copyright (C) 2012 Marvell Technology Ltd.
+ * Yunfan Zhang <yfzhang@marvell.com>
+ *
+ * This package is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#ifndef __FAN53555_H__
+
+/* VSEL ID */
+enum {
+	FAN53555_VSEL_ID_0 = 0,
+	FAN53555_VSEL_ID_1,
+};
+
+/* Transition slew rate limiting from a low to high voltage.
+ * -----------------------
+ *   Bin |Slew Rate(mV/uS)
+ * ------|----------------
+ *   000 |    64.00
+ * ------|----------------
+ *   001 |    32.00
+ * ------|----------------
+ *   010 |    16.00
+ * ------|----------------
+ *   011 |     8.00
+ * ------|----------------
+ *   100 |     4.00
+ * ------|----------------
+ *   101 |     2.00
+ * ------|----------------
+ *   110 |     1.00
+ * ------|----------------
+ *   111 |     0.50
+ * -----------------------
+ */
+enum {
+	FAN53555_SLEW_RATE_64MV = 0,
+	FAN53555_SLEW_RATE_32MV,
+	FAN53555_SLEW_RATE_16MV,
+	FAN53555_SLEW_RATE_8MV,
+	FAN53555_SLEW_RATE_4MV,
+	FAN53555_SLEW_RATE_2MV,
+	FAN53555_SLEW_RATE_1MV,
+	FAN53555_SLEW_RATE_0_5MV,
+};
+
+struct fan53555_platform_data {
+	struct regulator_init_data *regulator;
+	unsigned int slew_rate;
+	/* Sleep VSEL ID */
+	unsigned int sleep_vsel_id;
+};
+
+#ifdef CONFIG_REGULATOR_FAN53555
+int __init fan53555_regulator_init(void);
+#else
+static inline int __init fan53555_regulator_init(void) { return 0; }
+#endif
+
+#endif /* __FAN53555_H__ */
diff --git a/include/linux/regulator/onsemi-ncp6335d.h b/include/linux/regulator/onsemi-ncp6335d.h
index 98a5fea..399742f 100644
--- a/include/linux/regulator/onsemi-ncp6335d.h
+++ b/include/linux/regulator/onsemi-ncp6335d.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, 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
@@ -26,4 +26,10 @@
 	bool sleep_enable;
 };
 
+#ifdef CONFIG_REGULATOR_ONSEMI_NCP6335D
+int __init ncp6335d_regulator_init(void);
+#else
+static inline int __init ncp6335d_regulator_init(void) { return 0; }
+#endif
+
 #endif
diff --git a/include/linux/remote_spinlock.h b/include/linux/remote_spinlock.h
index e39846f..49d19ed 100644
--- a/include/linux/remote_spinlock.h
+++ b/include/linux/remote_spinlock.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2009, 2011, 2013 The Linux Foundation.
+/* Copyright (c) 2008-2009, 2011, 2013-2014 The Linux Foundation.
  * All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
@@ -83,6 +83,11 @@
 				0; }) \
 		: 0; \
 	})
+#define remote_spin_lock_rlock_id(lock, tid) \
+	_remote_spin_lock_rlock_id(&((lock)->remote), tid)
+
+#define remote_spin_unlock_rlock(lock) \
+	_remote_spin_unlock_rlock(&((lock)->remote))
 
 #define remote_spin_release(lock, pid) \
 	_remote_spin_release(&((lock)->remote), pid)
diff --git a/include/linux/sensors.h b/include/linux/sensors.h
index 3520034..96d2aa6 100644
--- a/include/linux/sensors.h
+++ b/include/linux/sensors.h
@@ -47,9 +47,37 @@
 #define SENSOR_TYPE_STEP_COUNTER		19
 #define SENSOR_TYPE_GEOMAGNETIC_ROTATION_VECTOR	20
 
+/**
+ * struct sensors_classdev - hold the sensor general parameters and APIs
+ * @dev:		The device to register.
+ * @node:		The list for the all the sensor drivers.
+ * @name:		Name of this sensor.
+ * @vendor:		The vendor of the hardware part.
+ * @handle:		The handle that identifies this sensors.
+ * @type:		The sensor type.
+ * @max_range:		The maximum range of this sensor's value in SI units.
+ * @resolution:		The smallest difference between two values reported by
+ *			this sensor.
+ * @sensor_power:	The rough estimate of this sensor's power consumption
+ *			in mA.
+ * @min_delay:		This value depends on the trigger mode:
+ *			continuous: minimum period allowed in microseconds
+ *			on-change : 0
+ *			one-shot :-1
+ *			special : 0, unless otherwise noted
+ * @fifo_reserved_event_count:	The number of events reserved for this sensor
+ *				in the batch mode FIFO.
+ * @fifo_max_event_count:	The maximum number of events of this sensor
+ *				that could be batched.
+ * @enabled:		Store the sensor driver enable status.
+ * @delay_msec:		Store the sensor driver delay value. The data unit is
+ *			millisecond.
+ * @sensors_enable:	The handle for enable and disable sensor.
+ * @sensors_poll_delay:	The handle for set the sensor polling delay time.
+ */
 struct sensors_classdev {
 	struct device		*dev;
-	struct list_head	 node;
+	struct list_head	node;
 	const char		*name;
 	const char		*vendor;
 	int			version;
@@ -61,6 +89,13 @@
 	int			min_delay;
 	int			fifo_reserved_event_count;
 	int			fifo_max_event_count;
+	unsigned int		enabled;
+	unsigned int		delay_msec;
+	/* enable and disable the sensor handle*/
+	int	(*sensors_enable)(struct sensors_classdev *sensors_cdev,
+					unsigned int enabled);
+	int	(*sensors_poll_delay)(struct sensors_classdev *sensors_cdev,
+					unsigned int delay_msec);
 };
 
 extern int sensors_classdev_register(struct device *parent,
diff --git a/include/linux/slimbus/slimbus.h b/include/linux/slimbus/slimbus.h
index c940091..7a7b3eb 100644
--- a/include/linux/slimbus/slimbus.h
+++ b/include/linux/slimbus/slimbus.h
@@ -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
@@ -525,6 +525,8 @@
  * @port_xfer_status: Called by framework when client calls get_xfer_status
  *	API. Returns how much buffer is actually processed and the port
  *	errors (e.g. overflow/underflow) if any.
+ * @xfer_user_msg: Send user message to specified logical address. Underlying
+ *	controller has to support sending user messages. Returns error if any.
  */
 struct slim_controller {
 	struct device		dev;
@@ -567,10 +569,13 @@
 	int			(*framer_handover)(struct slim_controller *ctrl,
 				struct slim_framer *new_framer);
 	int			(*port_xfer)(struct slim_controller *ctrl,
-				u8 pn, u8 *iobuf, u32 len,
+				u8 pn, phys_addr_t iobuf, u32 len,
 				struct completion *comp);
 	enum slim_port_err	(*port_xfer_status)(struct slim_controller *ctr,
-				u8 pn, u8 **done_buf, u32 *done_len);
+				u8 pn, phys_addr_t *done_buf, u32 *done_len);
+	int			(*xfer_user_msg)(struct slim_controller *ctrl,
+				u8 la, u8 mt, u8 mc,
+				struct slim_ele_access *msg, u8 *buf, u8 len);
 };
 #define to_slim_controller(d) container_of(d, struct slim_controller, dev)
 
@@ -586,6 +591,9 @@
  * @device_down: This callback is called when device reports absent, or the
  *		bus goes down. Device will report present when bus is up and
  *		device_up callback will be called again when that happens
+ * @reset_device: This callback is called after framer is booted.
+ *		Driver should do the needful to reset the device,
+ *		so that device acquires sync and be operational.
  * @driver: Slimbus device drivers should initialize name and owner field of
  *	this structure
  * @id_table: List of slimbus devices supported by this driver
@@ -600,6 +608,8 @@
 	int				(*device_up)(struct slim_device *sldev);
 	int				(*device_down)
 						(struct slim_device *sldev);
+	int				(*reset_device)
+						(struct slim_device *sldev);
 
 	struct device_driver		driver;
 	const struct slim_device_id	*id_table;
@@ -629,6 +639,10 @@
  *  @driver: Device's driver. Pointer to access routines.
  *  @ctrl: Slimbus controller managing the bus hosting this device.
  *  @laddr: 1-byte Logical address of this device.
+ *  @reported: Flag to indicate whether this device reported present. The flag
+ *	is set when device reports present, and is reset when it reports
+ *	absent. This flag alongwith notified flag below is used to call
+ *	device_up, or device_down callbacks for driver of this device.
  *  @mark_define: List of channels pending definition/activation.
  *  @mark_suspend: List of channels pending suspend.
  *  @mark_removal: List of channels pending removal.
@@ -652,6 +666,7 @@
 	struct slim_driver	*driver;
 	struct slim_controller	*ctrl;
 	u8			laddr;
+	bool			reported;
 	struct list_head	mark_define;
 	struct list_head	mark_suspend;
 	struct list_head	mark_removal;
@@ -734,6 +749,20 @@
 extern int slim_xfer_msg(struct slim_controller *ctrl,
 			struct slim_device *sbdev, struct slim_ele_access *msg,
 			u16 mc, u8 *rbuf, const u8 *wbuf, u8 len);
+
+/*
+ * User message:
+ * slim_user_msg: Send user message that is interpreted by destination device
+ * @sb: Client handle sending the message
+ * @la: Destination device for this user message
+ * @mt: Message Type (Soruce-referred, or Destination-referred)
+ * @mc: Message Code
+ * @msg: Message structure (start offset, number of bytes) to be sent
+ * @buf: data buffer to be sent
+ * @len: data buffer size in bytes
+ */
+extern int slim_user_msg(struct slim_device *sb, u8 la, u8 mt, u8 mc,
+				struct slim_ele_access *msg, u8 *buf, u8 len);
 /* end of message apis */
 
 /* Port management for manager device APIs */
@@ -773,8 +802,8 @@
  * Client will call slim_port_get_xfer_status to get error and/or number of
  * bytes transferred if used asynchronously.
  */
-extern int slim_port_xfer(struct slim_device *sb, u32 ph, u8 *iobuf, u32 len,
-				struct completion *comp);
+extern int slim_port_xfer(struct slim_device *sb, u32 ph, phys_addr_t iobuf,
+				u32 len, struct completion *comp);
 
 /*
  * slim_port_get_xfer_status: Poll for port transfers, or get transfer status
@@ -796,7 +825,7 @@
  * processed from the multiple transfers.
  */
 extern enum slim_port_err slim_port_get_xfer_status(struct slim_device *sb,
-			u32 ph, u8 **done_buf, u32 *done_len);
+			u32 ph, phys_addr_t *done_buf, u32 *done_len);
 
 /*
  * slim_connect_src: Connect source port to channel.
@@ -1036,6 +1065,16 @@
 void slim_report_absent(struct slim_device *sbdev);
 
 /*
+ * slim_framer_booted: This function is called by controller after the active
+ * framer has booted (using Bus Reset sequence, or after it has shutdown and has
+ * come back up). Components, devices on the bus may be in undefined state,
+ * and this function triggers their drivers to do the needful
+ * to bring them back in Reset state so that they can acquire sync, report
+ * present and be operational again.
+ */
+void slim_framer_booted(struct slim_controller *ctrl);
+
+/*
  * slim_msg_response: Deliver Message response received from a device to the
  *	framework.
  * @ctrl: Controller handle
diff --git a/include/linux/smsc_hub.h b/include/linux/smsc_hub.h
index 9c0afc0..c87f21b 100644
--- a/include/linux/smsc_hub.h
+++ b/include/linux/smsc_hub.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 software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
@@ -14,6 +14,7 @@
 #ifndef __LINUX_SMSC3503_H__
 #define __LINUX_SMSC3503_H__
 
+#define SMSC3502_ID	3502
 #define SMSC3503_ID	3503
 #define SMSC4604_ID	4604
 #define SMSC3503_I2C_ADDR	0x08
@@ -52,6 +53,7 @@
 	int hub_reset;
 	int refclk_gpio;
 	int int_gpio;
+	int xo_clk_gpio;
 };
 
 #endif
diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h
index fa702ae..9d13091 100644
--- a/include/linux/spi/spi.h
+++ b/include/linux/spi/spi.h
@@ -588,6 +588,26 @@
 	list_del(&t->transfer_list);
 }
 
+/**
+ * spi_message_init_with_transfers - Initialize spi_message and append transfers
+ * @m: spi_message to be initialized
+ * @xfers: An array of spi transfers
+ * @num_xfers: Number of items in the xfer array
+ *
+ * This function initializes the given spi_message and adds each spi_transfer in
+ * the given array to the message.
+ */
+static inline void
+spi_message_init_with_transfers(struct spi_message *m,
+struct spi_transfer *xfers, unsigned int num_xfers)
+{
+	unsigned int i;
+
+	spi_message_init(m);
+	for (i = 0; i < num_xfers; ++i)
+		spi_message_add_tail(&xfers[i], m);
+}
+
 /* It's fine to embed message and transaction structures in other data
  * structures so long as you don't free them while they're in use.
  */
@@ -680,6 +700,30 @@
 	return spi_sync(spi, &m);
 }
 
+/**
+ * spi_sync_transfer - synchronous SPI data transfer
+ * @spi: device with which data will be exchanged
+ * @xfers: An array of spi_transfers
+ * @num_xfers: Number of items in the xfer array
+ * Context: can sleep
+ *
+ * Does a synchronous SPI data transfer of the given spi_transfer array.
+ *
+ * For more specific semantics see spi_sync().
+ *
+ * It returns zero on success, else a negative error code.
+ */
+static inline int
+spi_sync_transfer(struct spi_device *spi, struct spi_transfer *xfers,
+	unsigned int num_xfers)
+{
+	struct spi_message msg;
+
+	spi_message_init_with_transfers(&msg, xfers, num_xfers);
+
+	return spi_sync(spi, &msg);
+}
+
 /* this copies txbuf and rxbuf data; for small transfers only! */
 extern int spi_write_then_read(struct spi_device *spi,
 		const void *txbuf, unsigned n_tx,
diff --git a/include/linux/tick.h b/include/linux/tick.h
index dc15221..78ae909 100644
--- a/include/linux/tick.h
+++ b/include/linux/tick.h
@@ -92,7 +92,16 @@
 #  ifdef CONFIG_TICK_ONESHOT
 extern struct cpumask *tick_get_broadcast_oneshot_mask(void);
 #  endif
+#else
+static inline struct tick_device *tick_get_broadcast_device(void)
+{
+	return NULL;
+}
 
+static inline struct cpumask *tick_get_broadcast_mask(void)
+{
+	return NULL;
+}
 # endif /* BROADCAST */
 
 # ifdef CONFIG_TICK_ONESHOT
@@ -109,6 +118,10 @@
 static inline int tick_check_oneshot_change(int allow_nohz) { return 0; }
 static inline void tick_check_idle(int cpu) { }
 static inline int tick_oneshot_mode_active(void) { return 0; }
+static inline struct cpumask *tick_get_broadcast_oneshot_mask(void)
+{
+	return NULL;
+}
 # endif
 
 #else /* CONFIG_GENERIC_CLOCKEVENTS */
diff --git a/include/linux/usb/Kbuild b/include/linux/usb/Kbuild
index 087d163..fe4d6da 100644
--- a/include/linux/usb/Kbuild
+++ b/include/linux/usb/Kbuild
@@ -1,4 +1,5 @@
 header-y += audio.h
+header-y += ccid_bridge.h
 header-y += cdc.h
 header-y += ch9.h
 header-y += ch11.h
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/ccid_bridge.h b/include/linux/usb/ccid_bridge.h
new file mode 100644
index 0000000..1d1b895
--- /dev/null
+++ b/include/linux/usb/ccid_bridge.h
@@ -0,0 +1,64 @@
+#ifndef __UAPI_USB_CCID_BRIDGE_H
+#define __UAPI_USB_CCID_BRIDGE_H
+
+#include <linux/ioctl.h>
+
+/**
+ * struct usb_ccid_data - Used to receive the CCID class descriptor,
+ *        clock rates and data rates supported by the device.
+ * @length: The length of the buffer.
+ * @data: The buffer as it is returned by the device for GET_DESCRIPTOR,
+ *        GET_CLOCK_FREQUENCIES and GET_DATA_RATES requests.
+ */
+struct usb_ccid_data {
+	uint8_t length;
+	void *data;
+};
+
+/**
+ * struct usb_ccid_abort - Used to abort an already sent command.
+ * @seq: The sequence number of the command.
+ * @slot: The slot of the IC, on which the command is sent.
+ */
+struct usb_ccid_abort {
+	uint8_t seq;
+	uint8_t slot;
+};
+
+#define USB_CCID_NOTIFY_SLOT_CHANGE_EVENT 1
+#define USB_CCID_HARDWARE_ERROR_EVENT 2
+#define USB_CCID_RESUME_EVENT 3
+/**
+ * struct usb_ccid_event - Used to receive notify slot change or hardware
+ *        error event.
+ * @notify: If the event is USB_CCID_NOTIFY_SLOT_CHANGE_EVENT, slot_icc_state
+ *        has the information about the current slots state.
+ * @error: If the event is USB_CCID_HARDWARE_ERROR_EVENT, error has
+ *        information about the hardware error condition.
+ */
+struct usb_ccid_event {
+	uint8_t event;
+	union {
+		struct {
+			uint8_t slot_icc_state;
+		} notify;
+
+		struct {
+			uint8_t slot;
+			uint8_t seq;
+			uint8_t error_code;
+		} error;
+	} u;
+};
+
+#define USB_CCID_GET_CLASS_DESC _IOWR('C', 0, struct usb_ccid_data)
+
+#define USB_CCID_GET_CLOCK_FREQUENCIES _IOWR('C', 1, struct usb_ccid_data)
+
+#define USB_CCID_GET_DATA_RATES _IOWR('C', 2, struct usb_ccid_data)
+
+#define USB_CCID_ABORT _IOW('C', 3, struct usb_ccid_abort)
+
+#define USB_CCID_GET_EVENT _IOR('C', 4, struct usb_ccid_event)
+
+#endif /* __UAPI_USB_CCID_BRIDGE_H */
diff --git a/include/linux/usb/hcd.h b/include/linux/usb/hcd.h
index 4fb20f6..ac0428d 100644
--- a/include/linux/usb/hcd.h
+++ b/include/linux/usb/hcd.h
@@ -212,7 +212,8 @@
 #define	HCD_MEMORY	0x0001		/* HC regs use memory (else I/O) */
 #define	HCD_LOCAL_MEM	0x0002		/* HC needs local memory */
 #define	HCD_SHARED	0x0004		/* Two (or more) usb_hcds share HW */
-#define	HCD_OLD_ENUM	0x0008		/* HC supports short enumeration */
+#define	HCD_RT_OLD_ENUM	0x0008		/* HC supports short enumeration
+					   on root port */
 #define	HCD_USB11	0x0010		/* USB 1.1 */
 #define	HCD_USB2	0x0020		/* USB 2.0 */
 #define	HCD_USB3	0x0040		/* USB 3.0 */
@@ -351,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 dcc786d..9dbac1c 100644
--- a/include/linux/usb/msm_ext_chg.h
+++ b/include/linux/usb/msm_ext_chg.h
@@ -6,6 +6,8 @@
 #define USB_CHG_BLOCK_ULPI	1
 #define USB_CHG_BLOCK_QSCRATCH	2
 
+#define USB_REQUEST_5V		1
+#define USB_REQUEST_9V		2
 /**
  * struct msm_usb_chg_info - MSM USB charger block details.
  * @chg_block_type: The type of charger block. QSCRATCH/ULPI.
@@ -28,4 +30,13 @@
 /* Vote against USB hardware low power mode */
 #define MSM_USB_EXT_CHG_BLOCK_LPM _IOW('M', 1, int)
 
+/* To tell kernel about voltage being voted */
+#define MSM_USB_EXT_CHG_VOLTAGE_INFO _IOW('M', 2, int)
+
+/* 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 045a58b..4ecacc7 100644
--- a/include/linux/usb/msm_hsusb.h
+++ b/include/linux/usb/msm_hsusb.h
@@ -2,7 +2,7 @@
  *
  * Copyright (C) 2008 Google, Inc.
  * Author: Brian Swetland <swetland@google.com>
- * Copyright (c) 2009-2013, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2009-2014, The Linux Foundation. All rights reserved.
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
@@ -346,6 +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: 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;
@@ -462,6 +466,8 @@
 	bool ext_chg_active;
 	struct completion ext_chg_wait;
 	int ui_enabled;
+	bool pm_done;
+	struct qpnp_vadc_chip	*vadc_dev;
 };
 
 struct ci13xxx_platform_data {
@@ -520,6 +526,7 @@
 	bool use_sec_phy;
 	bool no_selective_suspend;
 	int resume_gpio;
+	bool is_uicc;
 };
 
 /**
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 bfafe00..f760672 100644
--- a/include/linux/videodev2.h
+++ b/include/linux/videodev2.h
@@ -708,6 +708,7 @@
 #define V4L2_QCOM_BUF_INPUT_UNSUPPORTED 0x200000
 #define V4L2_QCOM_BUF_FLAG_EOS          0x2000
 #define V4L2_QCOM_BUF_FLAG_READONLY     0x400000
+#define V4L2_MSM_BUF_FLAG_MBAFF         0x800000
 
 /*
  *	O V E R L A Y   P R E V I E W
@@ -1823,25 +1824,30 @@
 #define V4L2_CID_MPEG_VIDC_VIDEO_EXTRADATA \
 		(V4L2_CID_MPEG_MSM_VIDC_BASE + 25)
 enum v4l2_mpeg_vidc_extradata {
-	V4L2_MPEG_VIDC_EXTRADATA_NONE,
-	V4L2_MPEG_VIDC_EXTRADATA_MB_QUANTIZATION,
-	V4L2_MPEG_VIDC_EXTRADATA_INTERLACE_VIDEO,
-	V4L2_MPEG_VIDC_EXTRADATA_VC1_FRAMEDISP,
-	V4L2_MPEG_VIDC_EXTRADATA_VC1_SEQDISP,
-	V4L2_MPEG_VIDC_EXTRADATA_TIMESTAMP,
-	V4L2_MPEG_VIDC_EXTRADATA_S3D_FRAME_PACKING,
-	V4L2_MPEG_VIDC_EXTRADATA_FRAME_RATE,
-	V4L2_MPEG_VIDC_EXTRADATA_PANSCAN_WINDOW,
-	V4L2_MPEG_VIDC_EXTRADATA_RECOVERY_POINT_SEI,
-	V4L2_MPEG_VIDC_EXTRADATA_CLOSED_CAPTION_UD,
-	V4L2_MPEG_VIDC_EXTRADATA_AFD_UD,
-	V4L2_MPEG_VIDC_EXTRADATA_MULTISLICE_INFO,
-	V4L2_MPEG_VIDC_EXTRADATA_NUM_CONCEALED_MB,
-	V4L2_MPEG_VIDC_EXTRADATA_METADATA_FILLER,
-	V4L2_MPEG_VIDC_INDEX_EXTRADATA_INPUT_CROP,
-	V4L2_MPEG_VIDC_INDEX_EXTRADATA_DIGITAL_ZOOM,
-	V4L2_MPEG_VIDC_INDEX_EXTRADATA_ASPECT_RATIO,
-	V4L2_MPEG_VIDC_EXTRADATA_MPEG2_SEQDISP
+	V4L2_MPEG_VIDC_EXTRADATA_NONE = 0,
+	V4L2_MPEG_VIDC_EXTRADATA_MB_QUANTIZATION = 1,
+	V4L2_MPEG_VIDC_EXTRADATA_INTERLACE_VIDEO = 2,
+	V4L2_MPEG_VIDC_EXTRADATA_VC1_FRAMEDISP = 3,
+	V4L2_MPEG_VIDC_EXTRADATA_VC1_SEQDISP = 4,
+	V4L2_MPEG_VIDC_EXTRADATA_TIMESTAMP = 5,
+	V4L2_MPEG_VIDC_EXTRADATA_S3D_FRAME_PACKING = 6,
+	V4L2_MPEG_VIDC_EXTRADATA_FRAME_RATE = 7,
+	V4L2_MPEG_VIDC_EXTRADATA_PANSCAN_WINDOW = 8,
+	V4L2_MPEG_VIDC_EXTRADATA_RECOVERY_POINT_SEI = 9,
+	V4L2_MPEG_VIDC_EXTRADATA_CLOSED_CAPTION_UD = 10,
+	V4L2_MPEG_VIDC_EXTRADATA_AFD_UD = 11,
+	V4L2_MPEG_VIDC_EXTRADATA_MULTISLICE_INFO = 12,
+	V4L2_MPEG_VIDC_EXTRADATA_NUM_CONCEALED_MB = 13,
+	V4L2_MPEG_VIDC_EXTRADATA_METADATA_FILLER = 14,
+	V4L2_MPEG_VIDC_INDEX_EXTRADATA_INPUT_CROP = 15,
+	V4L2_MPEG_VIDC_INDEX_EXTRADATA_DIGITAL_ZOOM = 16,
+	V4L2_MPEG_VIDC_INDEX_EXTRADATA_ASPECT_RATIO = 17,
+	V4L2_MPEG_VIDC_EXTRADATA_MPEG2_SEQDISP = 18,
+	V4L2_MPEG_VIDC_EXTRADATA_FRAME_QP = 19,
+	V4L2_MPEG_VIDC_EXTRADATA_FRAME_BITS_INFO = 20,
+	V4L2_MPEG_VIDC_EXTRADATA_LTR = 21,
+	V4L2_MPEG_VIDC_EXTRADATA_METADATA_MBI = 22,
+	V4L2_MPEG_VIDC_EXTRADATA_STREAM_USERDATA = 23,
 };
 
 #define V4L2_CID_MPEG_VIDC_SET_PERF_LEVEL (V4L2_CID_MPEG_MSM_VIDC_BASE + 26)
@@ -1906,6 +1912,41 @@
 
 #define V4L2_CID_MPEG_VIDC_VIDEO_VP8_MIN_QP (V4L2_CID_MPEG_MSM_VIDC_BASE + 36)
 #define V4L2_CID_MPEG_VIDC_VIDEO_VP8_MAX_QP (V4L2_CID_MPEG_MSM_VIDC_BASE + 37)
+#define V4L2_CID_MPEG_VIDC_VIDEO_CONCEAL_COLOR \
+		(V4L2_CID_MPEG_MSM_VIDC_BASE + 38)
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_LTRMODE \
+		(V4L2_CID_MPEG_MSM_VIDC_BASE + 39)
+
+enum v4l2_mpeg_vidc_video_ltrmode {
+	V4L2_MPEG_VIDC_VIDEO_LTR_MODE_DISABLE = 0,
+	V4L2_MPEG_VIDC_VIDEO_LTR_MODE_MANUAL = 1,
+	V4L2_MPEG_VIDC_VIDEO_LTR_MODE_PERIODIC = 2
+};
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_LTRCOUNT \
+		(V4L2_CID_MPEG_MSM_VIDC_BASE + 40)
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_USELTRFRAME \
+		(V4L2_CID_MPEG_MSM_VIDC_BASE + 41)
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_MARKLTRFRAME \
+		(V4L2_CID_MPEG_MSM_VIDC_BASE + 42)
+
+#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)
@@ -2472,6 +2513,8 @@
 		(V4L2_EVENT_MSM_VIDC_START + 6)
 #define V4L2_EVENT_MSM_VIDC_RELEASE_UNQUEUED_BUFFER \
 		(V4L2_EVENT_MSM_VIDC_START + 7)
+#define V4L2_EVENT_MSM_VIDC_HW_OVERLOAD (V4L2_EVENT_MSM_VIDC_START + 8)
+#define V4L2_EVENT_MSM_VIDC_MAX_CLIENTS (V4L2_EVENT_MSM_VIDC_START + 9)
 
 /* Payload for V4L2_EVENT_VSYNC */
 struct v4l2_event_vsync {
diff --git a/include/linux/vmalloc.h b/include/linux/vmalloc.h
index 7675a5c..500421f 100644
--- a/include/linux/vmalloc.h
+++ b/include/linux/vmalloc.h
@@ -136,6 +136,12 @@
 extern __init void vm_area_add_early(struct vm_struct *vm);
 extern __init void vm_area_register_early(struct vm_struct *vm, size_t align);
 extern __init int vm_area_check_early(struct vm_struct *vm);
+#ifdef CONFIG_ENABLE_VMALLOC_SAVING
+extern void mark_vmalloc_reserved_area(void *addr, unsigned long size);
+#else
+static inline void mark_vmalloc_reserved_area(void *addr, unsigned long size)
+{ };
+#endif
 
 #ifdef CONFIG_SMP
 # ifdef CONFIG_MMU
diff --git a/include/linux/wcnss_wlan.h b/include/linux/wcnss_wlan.h
index 39357e0..8836e4a 100644
--- a/include/linux/wcnss_wlan.h
+++ b/include/linux/wcnss_wlan.h
@@ -41,6 +41,7 @@
 #define HAVE_WCNSS_RESET_INTR 1
 #define HAVE_WCNSS_CAL_DOWNLOAD 1
 #define HAVE_WCNSS_RX_BUFF_COUNT 1
+#define WLAN_MAC_ADDR_SIZE (6)
 
 struct device *wcnss_wlan_get_device(void);
 struct resource *wcnss_wlan_get_memory_map(struct device *dev);
@@ -64,6 +65,7 @@
 int wcnss_free_power_on_lock(char *driver_name);
 unsigned int wcnss_get_serial_number(void);
 void wcnss_flush_delayed_boot_votes(void);
+int wcnss_get_wlan_mac_address(char mac_addr[WLAN_MAC_ADDR_SIZE]);
 void wcnss_allow_suspend(void);
 void wcnss_prevent_suspend(void);
 int wcnss_hardware_type(void);
@@ -75,6 +77,7 @@
 void wcnss_riva_log_debug_regs(void);
 void wcnss_pronto_log_debug_regs(void);
 int wcnss_device_ready(void);
+int wcnss_device_is_shutdown(void);
 void wcnss_riva_dump_pmic_regs(void);
 int wcnss_xo_auto_detect_enabled(void);
 u32 wcnss_get_wlan_rx_buff_count(void);
@@ -86,7 +89,11 @@
 {
 }
 #endif
-
+int wcnss_set_wlan_unsafe_channel(
+				u16 *unsafe_ch_list, u16 ch_count);
+int wcnss_get_wlan_unsafe_channel(
+				u16 *unsafe_ch_list, u16 buffer_size,
+				u16 *ch_count);
 #define wcnss_wlan_get_drvdata(dev) dev_get_drvdata(dev)
 #define wcnss_wlan_set_drvdata(dev, data) dev_set_drvdata((dev), (data))
 /* WLAN driver uses these names */
diff --git a/include/media/msm/vidc_init.h b/include/media/msm/vidc_init.h
index bcc0370..9c9a270 100644
--- a/include/media/msm/vidc_init.h
+++ b/include/media/msm/vidc_init.h
@@ -20,6 +20,7 @@
 #define VIDC_MAX_NUM_CLIENTS 4
 #define MAX_VIDEO_NUM_OF_BUFF 100
 #define MAX_META_BUFFERS 32
+#define MAX_MV_BUFFERS 32
 
 enum buffer_dir {
 	BUFFER_TYPE_INPUT,
diff --git a/include/media/msm_cam_sensor.h b/include/media/msm_cam_sensor.h
index a01dd9a..46cec76 100644
--- a/include/media/msm_cam_sensor.h
+++ b/include/media/msm_cam_sensor.h
@@ -47,6 +47,7 @@
 #define MAX_EEPROM_NAME 32
 
 #define MAX_AF_ITERATIONS 3
+#define MAX_NUMBER_OF_STEPS 47
 
 enum flash_type {
 	LED_FLASH = 1,
@@ -93,6 +94,8 @@
 	SENSOR_GPIO_VANA,
 	SENSOR_GPIO_VDIG,
 	SENSOR_GPIO_VAF,
+	SENSOR_GPIO_FL_EN,
+	SENSOR_GPIO_FL_NOW,
 	SENSOR_GPIO_MAX,
 };
 
@@ -220,6 +223,8 @@
 struct msm_sensor_power_setting_array {
 	struct msm_sensor_power_setting *power_setting;
 	uint16_t size;
+	struct msm_sensor_power_setting *power_down_setting;
+	uint16_t size_down;
 };
 
 struct msm_sensor_id_info_t {
@@ -227,13 +232,21 @@
 	uint16_t sensor_id;
 };
 
-struct msm_camera_sensor_slave_info {
-	uint16_t slave_addr;
-	enum msm_camera_i2c_reg_addr_type addr_type;
-	struct msm_sensor_id_info_t sensor_id_info;
-	struct msm_sensor_power_setting_array power_setting_array;
+enum msm_sensor_camera_id_t {
+	CAMERA_0,
+	CAMERA_1,
+	CAMERA_2,
+	CAMERA_3,
+	MAX_CAMERAS,
 };
 
+enum cci_i2c_master_t {
+	MASTER_0,
+	MASTER_1,
+	MASTER_MAX,
+};
+
+
 struct msm_camera_i2c_reg_array {
 	uint16_t reg_addr;
 	uint16_t reg_data;
@@ -317,10 +330,20 @@
 	uint8_t csi_phy_sel;
 };
 
+enum camb_position_t {
+	BACK_CAMERA_B,
+	FRONT_CAMERA_B,
+	INVALID_CAMERA_B,
+};
+
 struct msm_sensor_info_t {
-	char sensor_name[MAX_SENSOR_NAME];
-	int32_t    session_id;
-	int32_t     subdev_id[SUB_MODULE_MAX];
+	char     sensor_name[MAX_SENSOR_NAME];
+	int32_t  session_id;
+	int32_t  subdev_id[SUB_MODULE_MAX];
+	uint8_t  is_mount_angle_valid;
+	uint32_t sensor_mount_angle;
+	int modes_supported;
+	enum camb_position_t position;
 };
 
 struct camera_vreg_t {
@@ -332,14 +355,10 @@
 	uint32_t delay;
 };
 
-enum camb_position_t {
-	BACK_CAMERA_B,
-	FRONT_CAMERA_B,
-};
-
 enum camerab_mode_t {
 	CAMERA_MODE_2D_B = (1<<0),
-	CAMERA_MODE_3D_B = (1<<1)
+	CAMERA_MODE_3D_B = (1<<1),
+	CAMERA_MODE_INVALID = (1<<2),
 };
 
 struct msm_sensor_init_params {
@@ -351,6 +370,19 @@
 	uint32_t            sensor_mount_angle;
 };
 
+struct msm_camera_sensor_slave_info {
+	char sensor_name[32];
+	char eeprom_name[32];
+	char actuator_name[32];
+	enum msm_sensor_camera_id_t camera_id;
+	uint16_t slave_addr;
+	enum msm_camera_i2c_reg_addr_type addr_type;
+	struct msm_sensor_id_info_t sensor_id_info;
+	struct msm_sensor_power_setting_array power_setting_array;
+	uint8_t  is_init_params_valid;
+	struct msm_sensor_init_params sensor_init_params;
+};
+
 struct sensorb_cfg_data {
 	int cfgtype;
 	union {
@@ -381,6 +413,7 @@
 	CFG_EEPROM_GET_CAL_DATA,
 	CFG_EEPROM_READ_CAL_DATA,
 	CFG_EEPROM_WRITE_DATA,
+	CFG_EEPROM_GET_MM_INFO,
 };
 
 struct eeprom_get_t {
@@ -397,6 +430,12 @@
 	uint32_t num_bytes;
 };
 
+struct eeprom_get_mm_t {
+	uint32_t mm_support;
+	uint32_t mm_compression;
+	uint32_t mm_size;
+};
+
 struct msm_eeprom_cfg_data {
 	enum eeprom_cfg_type_t cfgtype;
 	uint8_t is_supported;
@@ -405,6 +444,7 @@
 		struct eeprom_get_t get_data;
 		struct eeprom_read_t read_data;
 		struct eeprom_write_t write_data;
+		struct eeprom_get_mm_t get_mm_data;
 	} cfg;
 };
 
@@ -441,6 +481,7 @@
 	CFG_SET_ACTUATOR_INFO,
 	CFG_SET_DEFAULT_FOCUS,
 	CFG_MOVE_FOCUS,
+	CFG_SET_POSITION,
 };
 
 enum actuator_type {
@@ -458,9 +499,18 @@
 	MSM_ACTUATOR_WORD_ADDR,
 };
 
+enum msm_actuator_i2c_operation {
+	MSM_ACT_WRITE = 0,
+	MSM_ACT_POLL,
+};
+
 struct reg_settings_t {
 	uint16_t reg_addr;
+	enum msm_actuator_addr_type addr_type;
 	uint16_t reg_data;
+	enum msm_actuator_data_type data_type;
+	enum msm_actuator_i2c_operation i2c_operation;
+	uint32_t delay;
 };
 
 struct region_params_t {
@@ -482,6 +532,7 @@
 	int8_t sign_dir;
 	int16_t dest_step_pos;
 	int32_t num_steps;
+	uint16_t curr_lens_pos;
 	struct damping_params_t *ringing_params;
 };
 
@@ -537,6 +588,13 @@
 	ACTUATOR_WEB_CAM_2,
 };
 
+
+struct msm_actuator_set_position_t {
+	uint16_t number_of_steps;
+	uint16_t pos[MAX_NUMBER_OF_STEPS];
+	uint16_t delay[MAX_NUMBER_OF_STEPS];
+};
+
 struct msm_actuator_cfg_data {
 	int cfgtype;
 	uint8_t is_af_supported;
@@ -544,6 +602,7 @@
 		struct msm_actuator_move_params_t move;
 		struct msm_actuator_set_info_t set_info;
 		struct msm_actuator_get_info_t get_info;
+		struct msm_actuator_set_position_t setpos;
 		enum af_camera_name cam_name;
 	} cfg;
 };
@@ -575,6 +634,20 @@
 	uint32_t flash_current[2];
 };
 
+/* sensor init structures and enums */
+enum msm_sensor_init_cfg_type_t {
+	CFG_SINIT_PROBE,
+	CFG_SINIT_PROBE_DONE,
+	CFG_SINIT_PROBE_WAIT_DONE,
+};
+
+struct sensor_init_cfg_data {
+	enum msm_sensor_init_cfg_type_t cfgtype;
+	union {
+		void *setting;
+	} cfg;
+};
+
 #define VIDIOC_MSM_SENSOR_CFG \
 	_IOWR('V', BASE_VIDIOC_PRIVATE + 1, struct sensorb_cfg_data)
 
@@ -585,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)
@@ -602,6 +675,9 @@
 #define VIDIOC_MSM_SENSOR_GET_AF_STATUS \
 	_IOWR('V', BASE_VIDIOC_PRIVATE + 9, uint32_t)
 
+#define VIDIOC_MSM_SENSOR_INIT_CFG \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 10, struct sensor_init_cfg_data)
+
 #define MSM_V4L2_PIX_FMT_META v4l2_fourcc('M', 'E', 'T', 'A') /* META */
 
 #endif /* __LINUX_MSM_CAM_SENSOR_H */
diff --git a/include/media/msm_media_info.h b/include/media/msm_media_info.h
index ddf9c8e..d46b505 100644
--- a/include/media/msm_media_info.h
+++ b/include/media/msm_media_info.h
@@ -79,6 +79,18 @@
 	COLOR_FMT_NV21,
 };
 
+static inline unsigned int VENUS_EXTRADATA_SIZE(int width, int height)
+{
+	(void)height;
+	(void)width;
+
+	/*
+	 * In the future, calculate the size based on the w/h but just
+	 * hardcode it for now since 8K satisfies all current usecases.
+	 */
+	return 8 * 1024;
+}
+
 static inline unsigned int VENUS_Y_STRIDE(int color_fmt, int width)
 {
 	unsigned int alignment, stride = 0;
@@ -158,8 +170,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 = VENUS_EXTRADATA_SIZE(width, height);
+	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 +187,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/msm_vidc.h b/include/media/msm_vidc.h
index bc85ebb..bbde6ef 100644
--- a/include/media/msm_vidc.h
+++ b/include/media/msm_vidc.h
@@ -7,8 +7,8 @@
 #include <linux/videodev2.h>
 
 enum core_id {
-	MSM_VIDC_CORE_0 = 0,
-	MSM_VIDC_CORE_1,      /* for Q6 core */
+	MSM_VIDC_CORE_VENUS = 0,
+	MSM_VIDC_CORE_Q6,
 	MSM_VIDC_CORES_MAX,
 };
 
@@ -60,6 +60,7 @@
 int msm_vidc_s_fmt(void *instance, struct v4l2_format *f);
 int msm_vidc_g_fmt(void *instance, struct v4l2_format *f);
 int msm_vidc_s_ctrl(void *instance, struct v4l2_control *a);
+int msm_vidc_s_ext_ctrl(void *instance, struct v4l2_ext_controls *a);
 int msm_vidc_g_ctrl(void *instance, struct v4l2_control *a);
 int msm_vidc_reqbufs(void *instance, struct v4l2_requestbuffers *b);
 int msm_vidc_prepare_buf(void *instance, struct v4l2_buffer *b);
@@ -95,6 +96,16 @@
 		int *domain_num, int *partition_num);
 void *msm_vidc_smem_get_client(void *instance);
 #endif
+
+struct msm_vidc_extradata_header {
+	unsigned int size;
+	unsigned int:32; /** Keeping binary compatibility */
+	unsigned int:32; /* with firmware and OpenMAX IL **/
+	unsigned int type; /* msm_vidc_extradata_type */
+	unsigned int data_size;
+	unsigned char data[1];
+};
+
 struct msm_vidc_interlace_payload {
 	unsigned int format;
 };
@@ -160,6 +171,18 @@
 	unsigned int fpa_repetition_period;
 	unsigned int fpa_extension_flag;
 };
+struct msm_vidc_frame_qp_payload {
+	unsigned int frame_qp;
+};
+struct msm_vidc_frame_bits_info_payload {
+	unsigned int frame_bits;
+	unsigned int header_bits;
+};
+
+struct msm_vidc_stream_userdata_payload {
+	unsigned int type;
+	unsigned int data[1];
+};
 
 enum msm_vidc_extradata_type {
 	EXTRADATA_NONE = 0x00000000,
@@ -173,11 +196,16 @@
 	EXTRADATA_PANSCAN_WINDOW = 0x00000008,
 	EXTRADATA_RECOVERY_POINT_SEI = 0x00000009,
 	EXTRADATA_MPEG2_SEQDISP = 0x0000000D,
+	EXTRADATA_STREAM_USERDATA = 0x0000000E,
+	EXTRADATA_FRAME_QP = 0x0000000F,
+	EXTRADATA_FRAME_BITS_INFO = 0x00000010,
 	EXTRADATA_MULTISLICE_INFO = 0x7F100000,
 	EXTRADATA_NUM_CONCEALED_MB = 0x7F100001,
 	EXTRADATA_INDEX = 0x7F100002,
 	EXTRADATA_ASPECT_RATIO = 0x7F100003,
 	EXTRADATA_METADATA_FILLER = 0x7FE00002,
+	MSM_VIDC_EXTRADATA_METADATA_LTR = 0x7F100004,
+	EXTRADATA_METADATA_MBI = 0x7F100005,
 };
 enum msm_vidc_interlace_type {
 	INTERLACE_FRAME_PROGRESSIVE = 0x01,
@@ -192,4 +220,9 @@
 	FRAME_RECONSTRUCTION_APPROXIMATELY_CORRECT = 0x02,
 };
 
+enum msm_vidc_userdata_type {
+	MSM_VIDC_USERDATA_TYPE_FRAME = 0x1,
+	MSM_VIDC_USERDATA_TYPE_TOP_FIELD = 0x2,
+	MSM_VIDC_USERDATA_TYPE_BOTTOM_FIELD = 0x3,
+};
 #endif
diff --git a/include/media/msmb_camera.h b/include/media/msmb_camera.h
index 62e7b27..a4f5a01 100644
--- a/include/media/msmb_camera.h
+++ b/include/media/msmb_camera.h
@@ -36,6 +36,7 @@
 #define MSM_CAMERA_SUBDEV_LED_FLASH    11
 #define MSM_CAMERA_SUBDEV_STROBE_FLASH 12
 #define MSM_CAMERA_SUBDEV_BUF_MNGR     13
+#define MSM_CAMERA_SUBDEV_SENSOR_INIT  14
 
 #define MSM_MAX_CAMERA_SENSORS  5
 
diff --git a/include/media/msmb_generic_buf_mgr.h b/include/media/msmb_generic_buf_mgr.h
index efcb425..237380f 100644
--- a/include/media/msmb_generic_buf_mgr.h
+++ b/include/media/msmb_generic_buf_mgr.h
@@ -20,4 +20,10 @@
 #define VIDIOC_MSM_BUF_MNGR_BUF_DONE \
 	_IOWR('V', BASE_VIDIOC_PRIVATE + 35, struct msm_buf_mngr_info)
 
+#define VIDIOC_MSM_BUF_MNGR_INIT \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 36, struct msm_buf_mngr_info)
+
+#define VIDIOC_MSM_BUF_MNGR_DEINIT \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 37, struct msm_buf_mngr_info)
+
 #endif
diff --git a/include/media/msmb_isp.h b/include/media/msmb_isp.h
index 568a3fa..3828221 100644
--- a/include/media/msmb_isp.h
+++ b/include/media/msmb_isp.h
@@ -1,3 +1,14 @@
+/* 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.
+ */
 #ifndef __MSMB_ISP__
 #define __MSMB_ISP__
 
@@ -228,6 +239,7 @@
 	VFE_READ_DMI_32BIT,
 	VFE_READ_DMI_64BIT,
 	GET_SOC_HW_VER,
+	GET_MAX_CLK_RATE,
 };
 
 struct msm_vfe_cfg_cmd2 {
@@ -301,15 +313,16 @@
 	ISP_WM_BUS_OVERFLOW = 4,
 	ISP_STATS_OVERFLOW  = 5,
 	ISP_CAMIF_ERROR     = 6,
-	ISP_SOF             = 7,
-	ISP_EOF             = 8,
-	ISP_EVENT_MAX       = 9
+	ISP_BUF_DONE        = 9,
+	ISP_EVENT_MAX       = 10
 };
 
 #define ISP_EVENT_OFFSET          8
 #define ISP_EVENT_BASE            (V4L2_EVENT_PRIVATE_START)
 #define ISP_BUF_EVENT_BASE        (ISP_EVENT_BASE + (1 << ISP_EVENT_OFFSET))
 #define ISP_STATS_EVENT_BASE      (ISP_EVENT_BASE + (2 << ISP_EVENT_OFFSET))
+#define ISP_SOF_EVENT_BASE        (ISP_EVENT_BASE + (3 << ISP_EVENT_OFFSET))
+#define ISP_EOF_EVENT_BASE        (ISP_EVENT_BASE + (4 << ISP_EVENT_OFFSET))
 #define ISP_EVENT_REG_UPDATE      (ISP_EVENT_BASE + ISP_REG_UPDATE)
 #define ISP_EVENT_START_ACK       (ISP_EVENT_BASE + ISP_START_ACK)
 #define ISP_EVENT_STOP_ACK        (ISP_EVENT_BASE + ISP_STOP_ACK)
@@ -317,8 +330,9 @@
 #define ISP_EVENT_WM_BUS_OVERFLOW (ISP_EVENT_BASE + ISP_WM_BUS_OVERFLOW)
 #define ISP_EVENT_STATS_OVERFLOW  (ISP_EVENT_BASE + ISP_STATS_OVERFLOW)
 #define ISP_EVENT_CAMIF_ERROR     (ISP_EVENT_BASE + ISP_CAMIF_ERROR)
-#define ISP_EVENT_SOF             (ISP_EVENT_BASE + ISP_SOF)
-#define ISP_EVENT_EOF             (ISP_EVENT_BASE + ISP_EOF)
+#define ISP_EVENT_SOF             (ISP_SOF_EVENT_BASE)
+#define ISP_EVENT_EOF             (ISP_EOF_EVENT_BASE)
+#define ISP_EVENT_BUF_DONE        (ISP_EVENT_BASE + ISP_BUF_DONE)
 #define ISP_EVENT_BUF_DIVERT      (ISP_BUF_EVENT_BASE)
 #define ISP_EVENT_STATS_NOTIFY    (ISP_STATS_EVENT_BASE)
 #define ISP_EVENT_COMP_STATS_NOTIFY (ISP_EVENT_STATS_NOTIFY + MSM_ISP_STATS_MAX)
diff --git a/include/media/msmb_pproc.h b/include/media/msmb_pproc.h
index ed4ffa2..df9f9e7 100644
--- a/include/media/msmb_pproc.h
+++ b/include/media/msmb_pproc.h
@@ -229,6 +229,12 @@
 #define VIDIOC_MSM_CPP_QUEUE_BUF \
 	_IOWR('V', BASE_VIDIOC_PRIVATE + 14, struct msm_camera_v4l2_ioctl_t)
 
+#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/media/radio-iris.h b/include/media/radio-iris.h
index d28a8c0..518dfb1 100644
--- a/include/media/radio-iris.h
+++ b/include/media/radio-iris.h
@@ -32,6 +32,50 @@
 #include <linux/mutex.h>
 #include <linux/atomic.h>
 #include "radio-iris-commands.h"
+const unsigned char MIN_TX_TONE_VAL = 0x00;
+const unsigned char MAX_TX_TONE_VAL = 0x07;
+const unsigned char MIN_HARD_MUTE_VAL = 0x00;
+const unsigned char MAX_HARD_MUTE_VAL = 0x03;
+const unsigned char MIN_SRCH_MODE = 0x00;
+const unsigned char MAX_SRCH_MODE = 0x09;
+const unsigned char MIN_SCAN_DWELL = 0x00;
+const unsigned char MAX_SCAN_DWELL = 0x0F;
+const unsigned char MIN_SIG_TH = 0x00;
+const unsigned char MAX_SIG_TH = 0x03;
+const unsigned char MIN_PTY = 0X00;
+const unsigned char MAX_PTY = 0x1F;
+const unsigned short MIN_PI = 0x0000;
+const unsigned short MAX_PI = 0xFFFF;
+const unsigned char MIN_SRCH_STATIONS_CNT = 0x00;
+const unsigned char MAX_SRCH_STATIONS_CNT = 0x14;
+const unsigned char MIN_CHAN_SPACING = 0x00;
+const unsigned char MAX_CHAN_SPACING = 0x02;
+const unsigned char MIN_EMPHASIS = 0x00;
+const unsigned char MAX_EMPHASIS = 0x01;
+const unsigned char MIN_RDS_STD = 0x00;
+const unsigned char MAX_RDS_STD = 0x02;
+const unsigned char MIN_ANTENNA_VAL = 0x00;
+const unsigned char MAX_ANTENNA_VAL = 0x01;
+const unsigned char MIN_TX_PS_REPEAT_CNT = 0x01;
+const unsigned char MAX_TX_PS_REPEAT_CNT = 0x0F;
+const unsigned char MIN_SOFT_MUTE = 0x00;
+const unsigned char MAX_SOFT_MUTE = 0x01;
+const unsigned char MIN_PEEK_ACCESS_LEN = 0x01;
+const unsigned char MAX_PEEK_ACCESS_LEN = 0xF9;
+const unsigned char MIN_RESET_CNTR = 0x00;
+const unsigned char MAX_RESET_CNTR = 0x01;
+const unsigned char MIN_HLSI = 0x00;
+const unsigned char MAX_HLSI = 0x02;
+const unsigned char MIN_NOTCH_FILTER = 0x00;
+const unsigned char MAX_NOTCH_FILTER = 0x02;
+const unsigned char MIN_INTF_DET_OUT_LW_TH = 0x00;
+const unsigned char MAX_INTF_DET_OUT_LW_TH = 0xFF;
+const unsigned char MIN_INTF_DET_OUT_HG_TH = 0x00;
+const unsigned char MAX_INTF_DET_OUT_HG_TH = 0xFF;
+const signed char MIN_SINR_TH = -128;
+const signed char MAX_SINR_TH = 127;
+const unsigned char MIN_SINR_SAMPLES = 0x01;
+const unsigned char MAX_SINR_SAMPLES = 0xFF;
 
 /* ---- HCI Packet structures ---- */
 #define RADIO_HCI_COMMAND_HDR_SIZE sizeof(struct radio_hci_command_hdr)
@@ -630,6 +674,7 @@
 	FM_TURNING_OFF,
 	FM_RECV_TURNING_ON,
 	FM_TRANS_TURNING_ON,
+	FM_MAX_NO_STATES,
 };
 
 enum emphasis_type {
@@ -828,4 +873,209 @@
 int hci_fm_do_calibration(__u8 *arg, struct radio_hci_dev *hdev);
 int hci_fm_do_calibration(__u8 *arg, struct radio_hci_dev *hdev);
 
+static inline int is_valid_tone(int tone)
+{
+	if ((tone >= MIN_TX_TONE_VAL) &&
+		(tone <= MAX_TX_TONE_VAL))
+		return 1;
+	else
+		return 0;
+}
+
+static inline int is_valid_hard_mute(int hard_mute)
+{
+	if ((hard_mute >= MIN_HARD_MUTE_VAL) &&
+		(hard_mute <= MAX_HARD_MUTE_VAL))
+		return 1;
+	else
+		return 0;
+}
+
+static inline int is_valid_srch_mode(int srch_mode)
+{
+	if ((srch_mode >= MIN_SRCH_MODE) &&
+		(srch_mode <= MAX_SRCH_MODE))
+		return 1;
+	else
+		return 0;
+}
+
+static inline int is_valid_scan_dwell_prd(int scan_dwell_prd)
+{
+	if ((scan_dwell_prd >= MIN_SCAN_DWELL) &&
+		(scan_dwell_prd <= MAX_SCAN_DWELL))
+		return 1;
+	else
+		return 0;
+}
+
+static inline int is_valid_sig_th(int sig_th)
+{
+	if ((sig_th >= MIN_SIG_TH) &&
+		(sig_th <= MAX_SIG_TH))
+		return 1;
+	else
+		return 0;
+}
+
+static inline int is_valid_pty(int pty)
+{
+	if ((pty >= MIN_PTY) &&
+		(pty <= MAX_PTY))
+		return 1;
+	else
+		return 0;
+}
+
+static inline int is_valid_pi(int pi)
+{
+	if ((pi >= MIN_PI) &&
+		(pi <= MAX_PI))
+		return 1;
+	else
+		return 0;
+}
+
+static inline int is_valid_srch_station_cnt(int cnt)
+{
+	if ((cnt >= MIN_SRCH_STATIONS_CNT) &&
+		(cnt <= MAX_SRCH_STATIONS_CNT))
+		return 1;
+	else
+		return 0;
+}
+
+static inline int is_valid_chan_spacing(int spacing)
+{
+	if ((spacing >= MIN_CHAN_SPACING) &&
+		(spacing <= MAX_CHAN_SPACING))
+		return 1;
+	else
+		return 0;
+}
+
+static inline int is_valid_emphasis(int emphasis)
+{
+	if ((emphasis >= MIN_EMPHASIS) &&
+		(emphasis <= MAX_EMPHASIS))
+		return 1;
+	else
+		return 0;
+}
+
+static inline int is_valid_rds_std(int rds_std)
+{
+	if ((rds_std >= MIN_RDS_STD) &&
+		(rds_std <= MAX_RDS_STD))
+		return 1;
+	else
+		return 0;
+}
+
+static inline int is_valid_antenna(int antenna_type)
+{
+	if ((antenna_type >= MIN_ANTENNA_VAL) &&
+		(antenna_type <= MAX_ANTENNA_VAL))
+		return 1;
+	else
+		return 0;
+}
+
+static inline int is_valid_ps_repeat_cnt(int cnt)
+{
+	if ((cnt >= MIN_TX_PS_REPEAT_CNT) &&
+		(cnt <= MAX_TX_PS_REPEAT_CNT))
+		return 1;
+	else
+		return 0;
+}
+
+static inline int is_valid_soft_mute(int soft_mute)
+{
+	if ((soft_mute >= MIN_SOFT_MUTE) &&
+		(soft_mute <= MAX_SOFT_MUTE))
+		return 1;
+	else
+		return 0;
+}
+
+static inline int is_valid_peek_len(int len)
+{
+	if ((len >= MIN_PEEK_ACCESS_LEN) &&
+		(len <= MAX_PEEK_ACCESS_LEN))
+		return 1;
+	else
+		return 0;
+}
+
+static inline int is_valid_reset_cntr(int cntr)
+{
+	if ((cntr >= MIN_RESET_CNTR) &&
+		(cntr <= MAX_RESET_CNTR))
+		return 1;
+	else
+		return 0;
+}
+
+static inline int is_valid_hlsi(int hlsi)
+{
+	if ((hlsi >= MIN_HLSI) &&
+		(hlsi <= MAX_HLSI))
+		return 1;
+	else
+		return 0;
+}
+
+static inline int is_valid_notch_filter(int filter)
+{
+	if ((filter >= MIN_NOTCH_FILTER) &&
+		(filter <= MAX_NOTCH_FILTER))
+		return 1;
+	else
+		return 0;
+}
+
+static inline int is_valid_intf_det_low_th(int th)
+{
+	if ((th >= MIN_INTF_DET_OUT_LW_TH) &&
+		(th <= MAX_INTF_DET_OUT_LW_TH))
+		return 1;
+	else
+		return 0;
+}
+
+static inline int is_valid_intf_det_hgh_th(int th)
+{
+	if ((th >= MIN_INTF_DET_OUT_HG_TH) &&
+		(th <= MAX_INTF_DET_OUT_HG_TH))
+		return 1;
+	else
+		return 0;
+}
+
+static inline int is_valid_sinr_th(int th)
+{
+	if ((th >= MIN_SINR_TH) &&
+		(th <= MAX_SINR_TH))
+		return 1;
+	else
+		return 0;
+}
+
+static inline int is_valid_sinr_samples(int samples_cnt)
+{
+	if ((samples_cnt >= MIN_SINR_SAMPLES) &&
+		(samples_cnt <= MAX_SINR_SAMPLES))
+		return 1;
+	else
+		return 0;
+}
+
+static inline int is_valid_fm_state(int state)
+{
+	if ((state >= 0) && (state < FM_MAX_NO_STATES))
+		return 1;
+	else
+		return 0;
+}
 #endif /* __RADIO_HCI_CORE_H */
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 7932ba1..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
  */
@@ -524,6 +526,10 @@
  * @capability: station capability
  * @ext_capab: extended capabilities of the station
  * @ext_capab_len: number of extended capabilities
+ * @supported_channels: supported channels in IEEE 802.11 format
+ * @supported_channels_len: number of supported channels
+ * @supported_oper_classes: supported oper classes in IEEE 802.11 format
+ * @supported_oper_classes_len: number of supported operating classes
  */
 struct station_parameters {
 	u8 *supported_rates;
@@ -542,6 +548,10 @@
 	u16 capability;
 	u8 *ext_capab;
 	u8 ext_capab_len;
+	const u8 *supported_channels;
+	u8 supported_channels_len;
+	const u8 *supported_oper_classes;
+	u8 supported_oper_classes_len;
 };
 
 /**
@@ -1255,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)
@@ -1277,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;
@@ -1399,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
@@ -1589,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);
@@ -1773,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);
 
@@ -1790,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);
+
 };
 
 /*
@@ -2038,6 +2106,34 @@
 };
 
 /**
+ * enum wiphy_vendor_command_flags - validation flags for vendor commands
+ * @WIPHY_VENDOR_CMD_NEED_WDEV: vendor command requires wdev
+ * @WIPHY_VENDOR_CMD_NEED_NETDEV: vendor command requires netdev
+ * @WIPHY_VENDOR_CMD_NEED_RUNNING: interface/wdev must be up & running
+ *	(must be combined with %_WDEV or %_NETDEV)
+ */
+enum wiphy_vendor_command_flags {
+	WIPHY_VENDOR_CMD_NEED_WDEV = BIT(0),
+	WIPHY_VENDOR_CMD_NEED_NETDEV = BIT(1),
+	WIPHY_VENDOR_CMD_NEED_RUNNING = BIT(2),
+};
+
+/**
+ * struct wiphy_vendor_command - vendor command definition
+ * @info: vendor command identifying information, as used in nl80211
+ * @flags: flags, see &enum wiphy_vendor_command_flags
+ * @doit: callback for the operation, note that wdev is %NULL if the
+ *	flags didn't ask for a wdev and non-%NULL otherwise; the data
+ *	pointer may be %NULL if userspace provided no data at all
+ */
+struct wiphy_vendor_command {
+	struct nl80211_vendor_cmd_info info;
+	u32 flags;
+	int (*doit)(struct wiphy *wiphy, struct wireless_dev *wdev,
+		    void *data, int data_len);
+};
+
+/**
  * struct wiphy - wireless hardware description
  * @reg_notifier: the driver's regulatory notification callback,
  *	note that if your driver uses wiphy_apply_custom_regulatory()
@@ -2136,6 +2232,16 @@
  *	supports for ACL.
  * @country_ie_pref: country IE processing preferences specified
  *	by enum nl80211_country_ie_pref
+ *
+ * @vendor_commands: array of vendor commands supported by the hardware
+ * @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 */
@@ -2240,6 +2346,12 @@
 	const struct iw_handler_def *wext;
 #endif
 
+	const struct wiphy_vendor_command *vendor_commands;
+	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)));
 };
 
@@ -2660,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
@@ -3120,6 +3234,121 @@
  */
 void wiphy_rfkill_stop_polling(struct wiphy *wiphy);
 
+/**
+ * DOC: Vendor commands
+ *
+ * Occasionally, there are special protocol or firmware features that
+ * can't be implemented very openly. For this and similar cases, the
+ * vendor command functionality allows implementing the features with
+ * (typically closed-source) userspace and firmware, using nl80211 as
+ * the configuration mechanism.
+ *
+ * A driver supporting vendor commands must register them as an array
+ * in struct wiphy, with handlers for each one, each command has an
+ * OUI and sub command ID to identify it.
+ *
+ * Note that this feature should not be (ab)used to implement protocol
+ * features that could openly be shared across drivers. In particular,
+ * it must never be required to use vendor commands to implement any
+ * "normal" functionality that higher-level userspace like connection
+ * managers etc. need.
+ */
+
+struct sk_buff *__cfg80211_alloc_reply_skb(struct wiphy *wiphy,
+					   enum nl80211_commands cmd,
+					   enum nl80211_attrs attr,
+					   int approxlen);
+
+struct sk_buff *__cfg80211_alloc_event_skb(struct wiphy *wiphy,
+					   enum nl80211_commands cmd,
+					   enum nl80211_attrs attr,
+					   int vendor_event_idx,
+					   int approxlen, gfp_t gfp);
+
+void __cfg80211_send_event_skb(struct sk_buff *skb, gfp_t gfp);
+
+/**
+ * cfg80211_vendor_cmd_alloc_reply_skb - allocate vendor command reply
+ * @wiphy: the wiphy
+ * @approxlen: an upper bound of the length of the data that will
+ *	be put into the skb
+ *
+ * This function allocates and pre-fills an skb for a reply to
+ * a vendor command. Since it is intended for a reply, calling
+ * it outside of a vendor command's doit() operation is invalid.
+ *
+ * The returned skb is pre-filled with some identifying data in
+ * a way that any data that is put into the skb (with skb_put(),
+ * nla_put() or similar) will end up being within the
+ * %NL80211_ATTR_VENDOR_DATA attribute, so all that needs to be done
+ * with the skb is adding data for the corresponding userspace tool
+ * which can then read that data out of the testdata attribute. You
+ * must not modify the skb in any other way.
+ *
+ * When done, call cfg80211_vendor_cmd_reply() with the skb and return
+ * its error code as the result of the doit() operation.
+ *
+ * Return: An allocated and pre-filled skb. %NULL if any errors happen.
+ */
+static inline struct sk_buff *
+cfg80211_vendor_cmd_alloc_reply_skb(struct wiphy *wiphy, int approxlen)
+{
+	return __cfg80211_alloc_reply_skb(wiphy, NL80211_CMD_VENDOR,
+					  NL80211_ATTR_VENDOR_DATA, approxlen);
+}
+
+/**
+ * cfg80211_vendor_cmd_reply - send the reply skb
+ * @skb: The skb, must have been allocated with
+ *	cfg80211_vendor_cmd_alloc_reply_skb()
+ *
+ * Since calling this function will usually be the last thing
+ * before returning from the vendor command doit() you should
+ * return the error code.  Note that this function consumes the
+ * skb regardless of the return value.
+ *
+ * Return: An error code or 0 on success.
+ */
+int cfg80211_vendor_cmd_reply(struct sk_buff *skb);
+
+/**
+ * cfg80211_vendor_event_alloc - allocate vendor-specific event skb
+ * @wiphy: the wiphy
+ * @event_idx: index of the vendor event in the wiphy's vendor_events
+ * @approxlen: an upper bound of the length of the data that will
+ *	be put into the skb
+ * @gfp: allocation flags
+ *
+ * This function allocates and pre-fills an skb for an event on the
+ * vendor-specific multicast group.
+ *
+ * When done filling the skb, call cfg80211_vendor_event() with the
+ * skb to send the event.
+ *
+ * Return: An allocated and pre-filled skb. %NULL if any errors happen.
+ */
+static inline struct sk_buff *
+cfg80211_vendor_event_alloc(struct wiphy *wiphy, int approxlen,
+			    int event_idx, gfp_t gfp)
+{
+	return __cfg80211_alloc_event_skb(wiphy, NL80211_CMD_VENDOR,
+					  NL80211_ATTR_VENDOR_DATA,
+					  event_idx, approxlen, gfp);
+}
+
+/**
+ * cfg80211_vendor_event - send the event
+ * @skb: The skb, must have been allocated with cfg80211_vendor_event_alloc()
+ * @gfp: allocation flags
+ *
+ * This function sends the given @skb, which must have been allocated
+ * by cfg80211_vendor_event_alloc(), as an event. It always consumes it.
+ */
+static inline void cfg80211_vendor_event(struct sk_buff *skb, gfp_t gfp)
+{
+	__cfg80211_send_event_skb(skb, gfp);
+}
+
 #ifdef CONFIG_NL80211_TESTMODE
 /**
  * DOC: Test mode
@@ -3153,8 +3382,12 @@
  * When done, call cfg80211_testmode_reply() with the skb and return
  * its error code as the result of the @testmode_cmd operation.
  */
-struct sk_buff *cfg80211_testmode_alloc_reply_skb(struct wiphy *wiphy,
-						  int approxlen);
+static inline struct sk_buff *
+cfg80211_testmode_alloc_reply_skb(struct wiphy *wiphy, int approxlen)
+{
+	return __cfg80211_alloc_reply_skb(wiphy, NL80211_CMD_TESTMODE,
+					  NL80211_ATTR_TESTDATA, approxlen);
+}
 
 /**
  * cfg80211_testmode_reply - send the reply skb
@@ -3167,7 +3400,10 @@
  * Note that this function consumes the skb regardless of the
  * return value.
  */
-int cfg80211_testmode_reply(struct sk_buff *skb);
+static inline int cfg80211_testmode_reply(struct sk_buff *skb)
+{
+	return cfg80211_vendor_cmd_reply(skb);
+}
 
 /**
  * cfg80211_testmode_alloc_event_skb - allocate testmode event
@@ -3188,8 +3424,13 @@
  * When done filling the skb, call cfg80211_testmode_event() with the
  * skb to send the event.
  */
-struct sk_buff *cfg80211_testmode_alloc_event_skb(struct wiphy *wiphy,
-						  int approxlen, gfp_t gfp);
+static inline struct sk_buff *
+cfg80211_testmode_alloc_event_skb(struct wiphy *wiphy, int approxlen, gfp_t gfp)
+{
+	return __cfg80211_alloc_event_skb(wiphy, NL80211_CMD_TESTMODE,
+					  NL80211_ATTR_TESTDATA, -1,
+					  approxlen, gfp);
+}
 
 /**
  * cfg80211_testmode_event - send the event
@@ -3201,7 +3442,10 @@
  * by cfg80211_testmode_alloc_event_skb(), as an event. It always
  * consumes it.
  */
-void cfg80211_testmode_event(struct sk_buff *skb, gfp_t gfp);
+static inline void cfg80211_testmode_event(struct sk_buff *skb, gfp_t gfp)
+{
+	__cfg80211_send_event_skb(skb, gfp);
+}
 
 #define CFG80211_TESTMODE_CMD(cmd)	.testmode_cmd = (cmd),
 #define CFG80211_TESTMODE_DUMP(cmd)	.testmode_dump = (cmd),
@@ -3555,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/net/ipv6.h b/include/net/ipv6.h
index e4170a2..a5a9e4d 100644
--- a/include/net/ipv6.h
+++ b/include/net/ipv6.h
@@ -252,6 +252,14 @@
 		atomic_dec(&fl->users);
 }
 
+extern void icmpv6_notify(struct sk_buff *skb, u8 type, u8 code, __be32 info);
+
+int icmpv6_push_pending_frames(struct sock *sk, struct flowi6 *fl6,
+			       struct icmp6hdr *thdr, int len);
+
+struct dst_entry *icmpv6_route_lookup(struct net *net, struct sk_buff *skb,
+				      struct sock *sk, struct flowi6 *fl6);
+
 extern int 			ip6_ra_control(struct sock *sk, int sel);
 
 extern int			ipv6_parse_hopopts(struct sk_buff *skb);
@@ -294,6 +302,18 @@
 	return __ipv6_addr_src_scope(__ipv6_addr_type(addr));
 }
 
+static inline bool __ipv6_addr_needs_scope_id(int type)
+{
+	return type & IPV6_ADDR_LINKLOCAL ||
+	       (type & IPV6_ADDR_MULTICAST &&
+		(type & (IPV6_ADDR_LOOPBACK|IPV6_ADDR_LINKLOCAL)));
+}
+
+static inline __u32 ipv6_iface_scope_id(const struct in6_addr *addr, int iface)
+{
+	return __ipv6_addr_needs_scope_id(__ipv6_addr_type(addr)) ? iface : 0;
+}
+
 static inline int ipv6_addr_cmp(const struct in6_addr *a1, const struct in6_addr *a2)
 {
 	return memcmp(a1, a2, sizeof(struct in6_addr));
diff --git a/include/net/ping.h b/include/net/ping.h
index 682b5ae..b1717ae 100644
--- a/include/net/ping.h
+++ b/include/net/ping.h
@@ -13,6 +13,7 @@
 #ifndef _PING_H
 #define _PING_H
 
+#include <net/icmp.h>
 #include <net/netns/hash.h>
 
 /* PING_HTABLE_SIZE must be power of 2 */
@@ -28,6 +29,18 @@
  */
 #define GID_T_MAX (((gid_t)~0U) >> 1)
 
+/* Compatibility glue so we can support IPv6 when it's compiled as a module */
+struct pingv6_ops {
+	int (*ipv6_recv_error)(struct sock *sk, struct msghdr *msg, int len);
+	int (*datagram_recv_ctl)(struct sock *sk, struct msghdr *msg,
+				 struct sk_buff *skb);
+	int (*icmpv6_err_convert)(u8 type, u8 code, int *err);
+	void (*ipv6_icmp_error)(struct sock *sk, struct sk_buff *skb, int err,
+				__be16 port, u32 info, u8 *payload);
+	int (*ipv6_chk_addr)(struct net *net, const struct in6_addr *addr,
+			     struct net_device *dev, int strict);
+};
+
 struct ping_table {
 	struct hlist_nulls_head	hash[PING_HTABLE_SIZE];
 	rwlock_t		lock;
@@ -39,10 +52,40 @@
 };
 
 extern struct proto ping_prot;
+extern struct ping_table ping_table;
+#if IS_ENABLED(CONFIG_IPV6)
+extern struct pingv6_ops pingv6_ops;
+#endif
 
+struct pingfakehdr {
+	struct icmphdr icmph;
+	struct iovec *iov;
+	sa_family_t family;
+	__wsum wcheck;
+};
 
-extern void ping_rcv(struct sk_buff *);
-extern void ping_err(struct sk_buff *, u32 info);
+int  ping_get_port(struct sock *sk, unsigned short ident);
+void ping_hash(struct sock *sk);
+void ping_unhash(struct sock *sk);
+
+int  ping_init_sock(struct sock *sk);
+void ping_close(struct sock *sk, long timeout);
+int  ping_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len);
+void ping_err(struct sk_buff *skb, int offset, u32 info);
+void ping_v4_err(struct sk_buff *skb, u32 info);
+int  ping_getfrag(void *from, char *to, int offset, int fraglen, int odd,
+		  struct sk_buff *);
+
+int  ping_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
+		  size_t len, int noblock, int flags, int *addr_len);
+int  ping_common_sendmsg(int family, struct msghdr *msg, size_t len,
+			 void *user_icmph, size_t icmph_len);
+int  ping_v4_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
+		     size_t len);
+int  ping_v6_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
+		     size_t len);
+int  ping_queue_rcv_skb(struct sock *sk, struct sk_buff *skb);
+void ping_rcv(struct sk_buff *skb);
 
 #ifdef CONFIG_PROC_FS
 extern int __init ping_proc_init(void);
@@ -50,6 +93,7 @@
 #endif
 
 void __init ping_init(void);
-
+int  __init pingv6_init(void);
+void pingv6_exit(void);
 
 #endif /* _PING_H */
diff --git a/include/net/tcp.h b/include/net/tcp.h
index 50660b3..dce56a6 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -131,6 +131,8 @@
 						 * most likely due to retrans in 3WHS.
 						 */
 
+#define TCP_DELACK_SEG          1       /*Number of full MSS to receive before Acking RFC2581*/
+
 #define TCP_RESOURCE_PROBE_INTERVAL ((unsigned)(HZ/2U)) /* Maximal interval between probes
 					                 * for local resources.
 					                 */
@@ -253,6 +255,10 @@
 extern int sysctl_tcp_thin_linear_timeouts;
 extern int sysctl_tcp_thin_dupack;
 
+/* sysctl variables for controlling various tcp parameters */
+extern int sysctl_tcp_delack_seg;
+extern int sysctl_tcp_use_userconfig;
+
 extern atomic_long_t tcp_memory_allocated;
 extern struct percpu_counter tcp_sockets_allocated;
 extern int tcp_memory_pressure;
@@ -346,6 +352,10 @@
 			       struct pipe_inode_info *pipe, size_t len,
 			       unsigned int flags);
 
+extern int tcp_use_userconfig_sysctl_handler(struct ctl_table *, int,
+                                         void __user *, size_t *, loff_t *);
+extern int tcp_proc_delayed_ack_control(struct ctl_table *, int,
+                void __user *, size_t *, loff_t *);
 static inline void tcp_dec_quickack_mode(struct sock *sk,
 					 const unsigned int pkts)
 {
diff --git a/include/net/transp_v6.h b/include/net/transp_v6.h
index 498433d..48b42ea 100644
--- a/include/net/transp_v6.h
+++ b/include/net/transp_v6.h
@@ -11,6 +11,7 @@
 extern struct proto udpv6_prot;
 extern struct proto udplitev6_prot;
 extern struct proto tcpv6_prot;
+extern struct proto pingv6_prot;
 
 struct flowi6;
 
@@ -21,6 +22,8 @@
 extern void				ipv6_frag_exit(void);
 
 /* transport protocols */
+extern int				pingv6_init(void);
+extern void				pingv6_exit(void);
 extern int				rawv6_init(void);
 extern void				rawv6_exit(void);
 extern int				udpv6_init(void);
diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h
index 7c6a558..6a54bb4 100644
--- a/include/scsi/scsi_device.h
+++ b/include/scsi/scsi_device.h
@@ -152,7 +152,10 @@
 	unsigned no_read_disc_info:1;	/* Avoid READ_DISC_INFO cmds */
 	unsigned no_read_capacity_16:1; /* Avoid READ_CAPACITY_16 cmds */
 	unsigned is_visible:1;	/* is the device visible in sysfs */
+	unsigned use_rpm_auto:1; /* Enable runtime PM auto suspend */
 
+#define SCSI_DEFAULT_AUTOSUSPEND_DELAY  -1
+	int autosuspend_delay;
 	DECLARE_BITMAP(supported_events, SDEV_EVT_MAXBITS); /* supported events */
 	struct list_head event_list;	/* asserted events */
 	struct work_struct event_work;
diff --git a/include/sound/Kbuild b/include/sound/Kbuild
index 60847b0..aeccfed 100644
--- a/include/sound/Kbuild
+++ b/include/sound/Kbuild
@@ -13,3 +13,4 @@
 header-y += compress_offload.h
 header-y += lsm_params.h
 header-y += voice_params.h
+header-y += voice_svc.h
diff --git a/include/sound/apr_audio-v2.h b/include/sound/apr_audio-v2.h
index 2c969cd..3b8b1cc 100644
--- a/include/sound/apr_audio-v2.h
+++ b/include/sound/apr_audio-v2.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
@@ -579,6 +579,15 @@
 	/* Clients must set this field to zero.*/
 } __packed;
 
+#define ASM_PARAM_ID_AAC_STEREO_MIX_COEFF_SELECTION_FLAG_V2 (0x00010DD8)
+
+struct asm_aac_stereo_mix_coeff_selection_param_v2 {
+	struct apr_hdr          hdr;
+	u32                     param_id;
+	u32                     param_size;
+	u32                     aac_stereo_mix_coeff_flag;
+} __packed;
+
 /* Allows a client to connect the desired stream to
  * the desired AFE port through the stream router
  *
@@ -2255,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
@@ -6874,6 +6884,7 @@
 #define Q6AFE_LPASS_IBIT_CLK_1_P024_MHZ		 0xFA000
 #define Q6AFE_LPASS_IBIT_CLK_768_KHZ		 0xBB800
 #define Q6AFE_LPASS_IBIT_CLK_512_KHZ		 0x7D000
+#define Q6AFE_LPASS_IBIT_CLK_256_KHZ		 0x3E800
 #define Q6AFE_LPASS_IBIT_CLK_DISABLE		     0x0
 
 /* Supported LPASS CLK sources */
diff --git a/include/sound/jack.h b/include/sound/jack.h
index 8e8c133..4a88c22 100644
--- a/include/sound/jack.h
+++ b/include/sound/jack.h
@@ -47,6 +47,9 @@
 	SND_JACK_OC_HPHL	= 0x0000040,
 	SND_JACK_OC_HPHR	= 0x0000080,
 	SND_JACK_UNSUPPORTED	= 0x0000100,
+	SND_JACK_MICROPHONE2    = 0x0000200,
+	SND_JACK_ANC_HEADPHONE = SND_JACK_HEADPHONE | SND_JACK_MICROPHONE |
+				 SND_JACK_MICROPHONE2,
 	/* Kept separate from switches to facilitate implementation */
 	SND_JACK_BTN_0		= 0x4000000,
 	SND_JACK_BTN_1		= 0x2000000,
diff --git a/include/sound/q6asm-v2.h b/include/sound/q6asm-v2.h
index a78c333..07199e0 100644
--- a/include/sound/q6asm-v2.h
+++ b/include/sound/q6asm-v2.h
@@ -72,6 +72,7 @@
 #define SYNC_IO_MODE	0x0001
 #define ASYNC_IO_MODE	0x0002
 #define COMPRESSED_IO	0x0040
+#define COMPRESSED_STREAM_IO	0x0080
 #define NT_MODE        0x0400
 
 #define NO_TIMESTAMP    0xFF00
@@ -179,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);
@@ -399,4 +401,8 @@
 int q6asm_send_meta_data(struct audio_client *ac, uint32_t initial_samples,
 		uint32_t trailing_samples);
 
+/* Send the stream meta data to remove initial and trailing silence */
+int q6asm_stream_send_meta_data(struct audio_client *ac, uint32_t stream_id,
+		uint32_t initial_samples, uint32_t trailing_samples);
+
 #endif /* __Q6_ASM_H__ */
diff --git a/include/sound/q6lsm.h b/include/sound/q6lsm.h
index 34eba81..8f06f20c 100644
--- a/include/sound/q6lsm.h
+++ b/include/sound/q6lsm.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2014, 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
@@ -47,6 +47,8 @@
 	uint16_t	user_sensitivity;
 	uint16_t	kw_sensitivity;
 	bool		started;
+	dma_addr_t	lsm_cal_phy_addr;
+	uint32_t	lsm_cal_size;
 };
 
 struct lsm_stream_cmd_open_tx {
@@ -123,10 +125,9 @@
 int q6lsm_open(struct lsm_client *client);
 int q6lsm_start(struct lsm_client *client, bool wait);
 int q6lsm_stop(struct lsm_client *client, bool wait);
-int q6lsm_snd_model_buf_alloc(struct lsm_client *client, uint32_t len);
+int q6lsm_snd_model_buf_alloc(struct lsm_client *client, size_t len);
 int q6lsm_snd_model_buf_free(struct lsm_client *client);
 int q6lsm_close(struct lsm_client *client);
-int q6lsm_unmap_cal_blocks(void);
 int q6lsm_register_sound_model(struct lsm_client *client,
 			       enum lsm_detection_mode mode, u16 minkeyword,
 			       u16 minuser, bool detectfailure);
diff --git a/include/sound/voice_svc.h b/include/sound/voice_svc.h
new file mode 100644
index 0000000..7045018
--- /dev/null
+++ b/include/sound/voice_svc.h
@@ -0,0 +1,46 @@
+#ifndef __VOICE_SVC_H__
+#define __VOICE_SVC_H__
+
+#include <linux/types.h>
+#include <linux/ioctl.h>
+
+#define VOICE_SVC_DRIVER_NAME "voice_svc"
+
+#define VOICE_SVC_MVM_STR "MVM"
+#define VOICE_SVC_CVS_STR "CVS"
+#define MAX_APR_SERVICE_NAME_LEN  64
+
+struct voice_svc_register {
+    char svc_name[MAX_APR_SERVICE_NAME_LEN];
+    __u32 src_port;
+    __u8 reg_flag;
+};
+
+struct voice_svc_cmd_response {
+    __u32 src_port;
+    __u32 dest_port;
+    __u32 token;
+    __u32 opcode;
+    __u32 payload_size;
+    __u8 payload[0];
+};
+
+struct voice_svc_cmd_request {
+    char svc_name[MAX_APR_SERVICE_NAME_LEN];
+    __u32 src_port;
+    __u32 dest_port;
+    __u32 token;
+    __u32 opcode;
+    __u32 payload_size;
+    __u8 payload[0];
+};
+
+#define VOICE_SVC_MAGIC 'N'
+
+#define SNDRV_VOICE_SVC_REGISTER_SVC    _IOWR(VOICE_SVC_MAGIC, \
+                    0x01, struct voice_svc_register)
+#define SNDRV_VOICE_SVC_CMD_RESPONSE    _IOWR(VOICE_SVC_MAGIC, \
+                    0x02, struct voice_svc_cmd_response)
+#define SNDRV_VOICE_SVC_CMD_REQUEST    _IOWR(VOICE_SVC_MAGIC, \
+                    0x03, struct voice_svc_cmd_request)
+#endif
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/include/trace/events/ice40.h b/include/trace/events/ice40.h
new file mode 100644
index 0000000..c0649a8
--- /dev/null
+++ b/include/trace/events/ice40.h
@@ -0,0 +1,310 @@
+/*
+ * 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.
+ */
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM ice40
+
+#if !defined(_TRACE_ICE40_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_ICE40_H
+
+#include <linux/tracepoint.h>
+#include <linux/usb.h>
+
+TRACE_EVENT(ice40_reg_write,
+
+	TP_PROTO(u8 addr, u8 val, u8 cmd0, u8 cmd1, int ret),
+
+	TP_ARGS(addr, val, cmd0, cmd1, ret),
+
+	TP_STRUCT__entry(
+		__field(u8, addr)
+		__field(u8, val)
+		__field(u8, cmd0)
+		__field(u8, cmd1)
+		__field(int, ret)
+	),
+
+	TP_fast_assign(
+		__entry->addr = addr;
+		__entry->val = val;
+		__entry->cmd0 = cmd0;
+		__entry->cmd1 = cmd1;
+		__entry->ret = ret;
+	),
+
+	TP_printk("addr = %x val = %x cmd0 = %x cmd1 = %x ret = %d",
+			__entry->addr, __entry->val, __entry->cmd0,
+			__entry->cmd1, __entry->ret)
+);
+
+TRACE_EVENT(ice40_reg_read,
+
+	TP_PROTO(u8 addr, u8 cmd0, int ret),
+
+	TP_ARGS(addr, cmd0, ret),
+
+	TP_STRUCT__entry(
+		__field(u8, addr)
+		__field(u8, cmd0)
+		__field(int, ret)
+	),
+
+	TP_fast_assign(
+		__entry->addr = addr;
+		__entry->cmd0 = cmd0;
+		__entry->ret = ret;
+	),
+
+	TP_printk("addr = %x cmd0 = %x ret = %x", __entry->addr,
+			__entry->cmd0, __entry->ret)
+);
+
+TRACE_EVENT(ice40_hub_control,
+
+	TP_PROTO(u16 req, u16 val, u16 index, u16 len, int ret),
+
+	TP_ARGS(req, val, index, len, ret),
+
+	TP_STRUCT__entry(
+		__field(u16, req)
+		__field(u16, val)
+		__field(u16, index)
+		__field(u16, len)
+		__field(int, ret)
+	),
+
+	TP_fast_assign(
+		__entry->req = req;
+		__entry->val = val;
+		__entry->index = index;
+		__entry->len = len;
+		__entry->ret = ret;
+	),
+
+	TP_printk("req = %x val = %x index = %x len = %x ret = %d",
+			__entry->req, __entry->val, __entry->index,
+			__entry->len, __entry->ret)
+);
+
+TRACE_EVENT(ice40_ep0,
+
+	TP_PROTO(const char *state),
+
+	TP_ARGS(state),
+
+	TP_STRUCT__entry(
+		__string(state, state)
+	),
+
+	TP_fast_assign(
+		__assign_str(state, state);
+	),
+
+	TP_printk("ep0 state: %s", __get_str(state))
+);
+
+TRACE_EVENT(ice40_urb_enqueue,
+
+	TP_PROTO(struct urb *urb),
+
+	TP_ARGS(urb),
+
+	TP_STRUCT__entry(
+		__field(u16, epnum)
+		__field(u8, dir)
+		__field(u8, type)
+		__field(u32, len)
+	),
+
+	TP_fast_assign(
+		__entry->epnum = usb_pipeendpoint(urb->pipe);
+		__entry->dir = usb_urb_dir_in(urb);
+		__entry->type = usb_pipebulk(urb->pipe);
+		__entry->len = urb->transfer_buffer_length;
+	),
+
+	TP_printk("URB_LOG: E: ep %d %s %s len %d", __entry->epnum,
+			__entry->dir ? "In" : "Out",
+			__entry->type ? "Bulk" : "ctrl",
+			__entry->len)
+);
+
+TRACE_EVENT(ice40_urb_dequeue,
+
+	TP_PROTO(struct urb *urb),
+
+	TP_ARGS(urb),
+
+	TP_STRUCT__entry(
+		__field(u16, epnum)
+		__field(u8, dir)
+		__field(u8, type)
+		__field(u32, len)
+		__field(int, reason)
+	),
+
+	TP_fast_assign(
+		__entry->epnum = usb_pipeendpoint(urb->pipe);
+		__entry->dir = usb_urb_dir_in(urb);
+		__entry->type = usb_pipebulk(urb->pipe);
+		__entry->len = urb->transfer_buffer_length;
+		__entry->reason = urb->unlinked;
+	),
+
+	TP_printk("URB_LOG: D: ep %d %s %s len %d reason %d",
+			__entry->epnum,
+			__entry->dir ? "In" : "Out",
+			__entry->type ? "Bulk" : "ctrl",
+			__entry->len, __entry->reason)
+);
+
+TRACE_EVENT(ice40_urb_done,
+
+	TP_PROTO(struct urb *urb, int result),
+
+	TP_ARGS(urb, result),
+
+	TP_STRUCT__entry(
+		__field(int, result)
+		__field(u16, epnum)
+		__field(u8, dir)
+		__field(u8, type)
+		__field(u32, len)
+		__field(u32, actual)
+	),
+
+	TP_fast_assign(
+		__entry->result = result;
+		__entry->epnum = usb_pipeendpoint(urb->pipe);
+		__entry->dir = usb_urb_dir_in(urb);
+		__entry->type = usb_pipebulk(urb->pipe);
+		__entry->len = urb->transfer_buffer_length;
+		__entry->actual = urb->actual_length;
+	),
+
+	TP_printk("URB_LOG: C: ep %d %s %s len %d actual %d result %d",
+			__entry->epnum, __entry->dir ? "In" : "Out",
+			__entry->type ? "Bulk" : "ctrl", __entry->len,
+			__entry->actual, __entry->result)
+);
+
+TRACE_EVENT(ice40_bus_suspend,
+
+	TP_PROTO(u8 status),
+
+	TP_ARGS(status),
+
+	TP_STRUCT__entry(
+		__field(u8, status)
+	),
+
+	TP_fast_assign(
+		__entry->status = status;
+	),
+
+	TP_printk("bus_suspend status %d", __entry->status)
+);
+
+TRACE_EVENT(ice40_bus_resume,
+
+	TP_PROTO(u8 status),
+
+	TP_ARGS(status),
+
+	TP_STRUCT__entry(
+		__field(u8, status)
+	),
+
+	TP_fast_assign(
+		__entry->status = status;
+	),
+
+	TP_printk("bus_resume status %d", __entry->status)
+);
+
+TRACE_EVENT(ice40_setup,
+
+	TP_PROTO(const char *token, int ret),
+
+	TP_ARGS(token, ret),
+
+	TP_STRUCT__entry(
+		__string(token, token)
+		__field(int, ret)
+	),
+
+	TP_fast_assign(
+		__assign_str(token, token);
+		__entry->ret = ret;
+	),
+
+	TP_printk("Trace: SETUP %s ret %d",
+		__get_str(token), __entry->ret)
+);
+
+TRACE_EVENT(ice40_in,
+
+	TP_PROTO(u16 ep, const char *token, u8 len, u8 expected, int ret),
+
+	TP_ARGS(ep, token, len, expected, ret),
+
+	TP_STRUCT__entry(
+		__field(u16, ep)
+		__string(token, token)
+		__field(u8, len)
+		__field(u8, expected)
+		__field(int, ret)
+	),
+
+	TP_fast_assign(
+		__entry->ep = ep;
+		__assign_str(token, token);
+		__entry->len = len;
+		__entry->expected = expected;
+		__entry->ret = ret;
+	),
+
+	TP_printk("Trace: %d IN %s len %d expected %d ret %d",
+			__entry->ep, __get_str(token),
+			__entry->len, __entry->expected,
+			__entry->ret)
+);
+
+TRACE_EVENT(ice40_out,
+
+	TP_PROTO(u16 ep, const char *token, u8 len, int ret),
+
+	TP_ARGS(ep, token, len, ret),
+
+	TP_STRUCT__entry(
+		__field(u16, ep)
+		__string(token, token)
+		__field(u8, len)
+		__field(int, ret)
+	),
+
+	TP_fast_assign(
+		__entry->ep = ep;
+		__assign_str(token, token);
+		__entry->len = len;
+		__entry->ret = ret;
+	),
+
+	TP_printk("Trace: %d OUT %s len %d ret %d",
+			__entry->ep, __get_str(token),
+			__entry->len, __entry->ret)
+);
+#endif /* if !defined(_TRACE_ICE40_H) || defined(TRACE_HEADER_MULTI_READ) */
+
+/* This part must be outside protection */
+#include <trace/define_trace.h>
diff --git a/kernel/events/core.c b/kernel/events/core.c
index aafa4c1..7dd822b 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -1194,6 +1194,28 @@
 	return 0;
 }
 
+#ifdef CONFIG_SMP
+static void perf_retry_remove(struct perf_event *event)
+{
+	int up_ret;
+	/*
+	 * CPU was offline. Bring it online so we can
+	 * gracefully exit a perf context.
+	 */
+	up_ret = cpu_up(event->cpu);
+	if (!up_ret)
+		/* Try the remove call once again. */
+		cpu_function_call(event->cpu, __perf_remove_from_context,
+				  event);
+	else
+		pr_err("Failed to bring up CPU: %d, ret: %d\n",
+		       event->cpu, up_ret);
+}
+#else
+static void perf_retry_remove(struct perf_event *event)
+{
+}
+#endif
 
 /*
  * Remove the event from a task's (or a CPU's) list of events.
@@ -1208,19 +1230,22 @@
  * When called from perf_event_exit_task, it's OK because the
  * context has been detached from its task.
  */
-static void perf_remove_from_context(struct perf_event *event)
+static void __ref perf_remove_from_context(struct perf_event *event)
 {
 	struct perf_event_context *ctx = event->ctx;
 	struct task_struct *task = ctx->task;
+	int ret;
 
 	lockdep_assert_held(&ctx->mutex);
 
 	if (!task) {
 		/*
-		 * Per cpu events are removed via an smp call and
-		 * the removal is always successful.
+		 * Per cpu events are removed via an smp call
 		 */
-		cpu_function_call(event->cpu, __perf_remove_from_context, event);
+		ret = cpu_function_call(event->cpu, __perf_remove_from_context,
+					event);
+		if (ret == -ENXIO)
+			perf_retry_remove(event);
 		return;
 	}
 
@@ -2934,6 +2959,14 @@
 	struct perf_event *event = file->private_data;
 	struct task_struct *owner;
 
+	/*
+	 * Event can be in state OFF because of a constraint check.
+	 * Change to ACTIVE so that it gets cleaned up correctly.
+	 */
+	if ((event->state == PERF_EVENT_STATE_OFF) &&
+	    event->attr.constraint_duplicate)
+		event->state = PERF_EVENT_STATE_ACTIVE;
+
 	file->private_data = NULL;
 
 	rcu_read_lock();
@@ -5171,6 +5204,7 @@
 	.read		= perf_swevent_read,
 
 	.event_idx	= perf_swevent_event_idx,
+	.events_across_hotplug = 1,
 };
 
 #ifdef CONFIG_EVENT_TRACING
@@ -5265,6 +5299,7 @@
 	.read		= perf_swevent_read,
 
 	.event_idx	= perf_swevent_event_idx,
+	.events_across_hotplug = 1,
 };
 
 static inline void perf_tp_register(void)
@@ -5492,6 +5527,7 @@
 	.read		= cpu_clock_event_read,
 
 	.event_idx	= perf_swevent_event_idx,
+	.events_across_hotplug = 1,
 };
 
 /*
@@ -5572,6 +5608,7 @@
 	.read		= task_clock_event_read,
 
 	.event_idx	= perf_swevent_event_idx,
+	.events_across_hotplug = 1,
 };
 
 static void perf_pmu_nop_void(struct pmu *pmu)
@@ -7029,11 +7066,20 @@
 
 	idx = srcu_read_lock(&pmus_srcu);
 	list_for_each_entry_rcu(pmu, &pmus, entry) {
-		ctx = &per_cpu_ptr(pmu->pmu_cpu_context, cpu)->ctx;
+		/*
+		 * If keeping events across hotplugging is supported, do not
+		 * remove the event list, but keep it alive across CPU hotplug.
+		 * The context is exited via an fd close path when userspace
+		 * is done and the target CPU is online.
+		 */
+		if (!pmu->events_across_hotplug) {
+			ctx = &per_cpu_ptr(pmu->pmu_cpu_context, cpu)->ctx;
 
-		mutex_lock(&ctx->mutex);
-		smp_call_function_single(cpu, __perf_event_exit_context, ctx, 1);
-		mutex_unlock(&ctx->mutex);
+			mutex_lock(&ctx->mutex);
+			smp_call_function_single(cpu, __perf_event_exit_context,
+						 ctx, 1);
+			mutex_unlock(&ctx->mutex);
+		}
 	}
 	srcu_read_unlock(&pmus_srcu, idx);
 }
diff --git a/kernel/events/hw_breakpoint.c b/kernel/events/hw_breakpoint.c
index bb38c4d..98e6903 100644
--- a/kernel/events/hw_breakpoint.c
+++ b/kernel/events/hw_breakpoint.c
@@ -635,6 +635,7 @@
 	.read		= hw_breakpoint_pmu_read,
 
 	.event_idx	= hw_breakpoint_event_idx,
+	.events_across_hotplug = 1,
 };
 
 int __init init_hw_breakpoint(void)
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/power/process.c b/kernel/power/process.c
index 31b6f25..e10e171 100644
--- a/kernel/power/process.c
+++ b/kernel/power/process.c
@@ -35,6 +35,7 @@
 	u64 elapsed_csecs64;
 	unsigned int elapsed_csecs;
 	bool wakeup = false;
+	int sleep_usecs = USEC_PER_MSEC;
 
 	do_gettimeofday(&start);
 
@@ -81,9 +82,12 @@
 
 		/*
 		 * We need to retry, but first give the freezing tasks some
-		 * time to enter the regrigerator.
+		 * time to enter the refrigerator.  Start with an initial
+		 * 1 ms sleep followed by exponential backoff until 8 ms.
 		 */
-		msleep(10);
+		usleep_range(sleep_usecs / 2, sleep_usecs);
+		if (sleep_usecs < 8 * USEC_PER_MSEC)
+			sleep_usecs *= 2;
 	}
 
 	do_gettimeofday(&end);
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/kernel/sched/core.c b/kernel/sched/core.c
index 954a8c4..d9e1f1d 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -1682,9 +1682,12 @@
 {
 	struct rq *rq = task_rq(p);
 
-	if (WARN_ON(rq != this_rq()) ||
-	    WARN_ON(p == current))
+	if (rq != this_rq() || p == current) {
+		printk_sched("%s: Failed to wakeup task %d (%s), rq = %p, this_rq = %p, p = %p, current = %p\n",
+			__func__, task_pid_nr(p), p->comm, rq,
+			this_rq(), p, current);
 		return;
+	}
 
 	lockdep_assert_held(&rq->lock);
 
@@ -6947,6 +6950,7 @@
 
 #ifdef CONFIG_CGROUP_SCHED
 struct task_group root_task_group;
+LIST_HEAD(task_groups);
 #endif
 
 DECLARE_PER_CPU(cpumask_var_t, load_balance_tmpmask);
diff --git a/kernel/sched/rt.c b/kernel/sched/rt.c
index be427c5..3d4b1e2 100644
--- a/kernel/sched/rt.c
+++ b/kernel/sched/rt.c
@@ -560,7 +560,7 @@
 static int do_balance_runtime(struct rt_rq *rt_rq)
 {
 	struct rt_bandwidth *rt_b = sched_rt_bandwidth(rt_rq);
-	struct root_domain *rd = cpu_rq(smp_processor_id())->rd;
+	struct root_domain *rd = rq_of_rt_rq(rt_rq)->rd;
 	int i, weight, more = 0;
 	u64 rt_period;
 
diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h
index c0288a6..34fe64f 100644
--- a/kernel/sched/sched.h
+++ b/kernel/sched/sched.h
@@ -80,7 +80,7 @@
 struct cfs_rq;
 struct rt_rq;
 
-static LIST_HEAD(task_groups);
+extern struct list_head task_groups;
 
 struct cfs_bandwidth {
 #ifdef CONFIG_CFS_BANDWIDTH
diff --git a/kernel/time/alarmtimer.c b/kernel/time/alarmtimer.c
index aa27d39..a2a28a0 100644
--- a/kernel/time/alarmtimer.c
+++ b/kernel/time/alarmtimer.c
@@ -98,6 +98,8 @@
 
 static inline void alarmtimer_rtc_timer_init(void)
 {
+	mutex_init(&power_on_alarm_lock);
+
 	rtc_timer_init(&rtctimer, NULL, NULL);
 }
 
@@ -123,6 +125,7 @@
 static inline int alarmtimer_rtc_interface_setup(void) { return 0; }
 static inline void alarmtimer_rtc_interface_remove(void) { }
 static inline void alarmtimer_rtc_timer_init(void) { }
+void set_power_on_alarm(long secs, bool enable) { }
 #endif
 
 /**
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index 700d2ae..f320017 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -384,7 +384,7 @@
 void tracing_off(void)
 {
 	if (global_trace.buffer)
-		ring_buffer_record_on(global_trace.buffer);
+		ring_buffer_record_off(global_trace.buffer);
 	/*
 	 * This flag is only looked at when buffers haven't been
 	 * allocated yet. We don't really care about the race
diff --git a/lib/Kconfig b/lib/Kconfig
index 8437e36..09f0d8a 100644
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -379,7 +379,7 @@
 	  Implementation is done using GnuPG MPI library
 
 config QMI_ENCDEC
-	bool
+	bool "QMI Encode/Decode Library"
 	help
 	  Library to encode & decode QMI messages from within
 	  the kernel. The kernel drivers encode the C structure into
@@ -388,7 +388,7 @@
 	  and then decode it into a C structure.
 
 config QMI_ENCDEC_DEBUG
-	bool
+	bool "QMI Encode/Decode Library Debug"
 	help
 	  Kernel config option to enable debugging QMI Encode/Decode
 	  library. This will log the information regarding the element
diff --git a/lib/genalloc.c b/lib/genalloc.c
index 604ee09..fd699ca 100644
--- a/lib/genalloc.c
+++ b/lib/genalloc.c
@@ -177,7 +177,7 @@
 	struct gen_pool_chunk *chunk;
 	int nbits = size >> pool->min_alloc_order;
 	int nbytes = sizeof(struct gen_pool_chunk) +
-				(nbits + BITS_PER_BYTE - 1) / BITS_PER_BYTE;
+				BITS_TO_LONGS(nbits) * sizeof(long);
 
 	if (nbytes <= PAGE_SIZE)
 		chunk = kmalloc_node(nbytes, __GFP_ZERO, nid);
@@ -247,7 +247,7 @@
 
 		end_bit = (chunk->end_addr - chunk->start_addr) >> order;
 		nbytes = sizeof(struct gen_pool_chunk) +
-				(end_bit + BITS_PER_BYTE - 1) / BITS_PER_BYTE;
+				BITS_TO_LONGS(end_bit) * sizeof(long);
 		bit = find_next_bit(chunk->bits, end_bit, 0);
 		BUG_ON(bit < end_bit);
 
diff --git a/lib/scatterlist.c b/lib/scatterlist.c
index 6096e89..547a01f 100644
--- a/lib/scatterlist.c
+++ b/lib/scatterlist.c
@@ -228,12 +228,14 @@
 	struct scatterlist *sg, *prv;
 	unsigned int left;
 
+	memset(table, 0, sizeof(*table));
+
+	if (nents == 0)
+		return -EINVAL;
 #ifndef ARCH_HAS_SG_CHAIN
 	BUG_ON(nents > max_ents);
 #endif
 
-	memset(table, 0, sizeof(*table));
-
 	left = nents;
 	prv = NULL;
 	do {
diff --git a/mm/compaction.c b/mm/compaction.c
index 673142d..35bb243 100644
--- a/mm/compaction.c
+++ b/mm/compaction.c
@@ -243,7 +243,6 @@
 {
 	int nr_scanned = 0, total_isolated = 0;
 	struct page *cursor, *valid_page = NULL;
-	unsigned long nr_strict_required = end_pfn - blockpfn;
 	unsigned long flags;
 	bool locked = false;
 
@@ -256,11 +255,12 @@
 
 		nr_scanned++;
 		if (!pfn_valid_within(blockpfn))
-			continue;
+			goto isolate_fail;
+
 		if (!valid_page)
 			valid_page = page;
 		if (!PageBuddy(page))
-			continue;
+			goto isolate_fail;
 
 		/*
 		 * The zone lock must be held to isolate freepages.
@@ -281,12 +281,10 @@
 
 		/* Recheck this is a buddy page under lock */
 		if (!PageBuddy(page))
-			continue;
+			goto isolate_fail;
 
 		/* Found a free page, break it into order-0 pages */
 		isolated = split_free_page(page);
-		if (!isolated && strict)
-			break;
 		total_isolated += isolated;
 		for (i = 0; i < isolated; i++) {
 			list_add(&page->lru, freelist);
@@ -297,7 +295,13 @@
 		if (isolated) {
 			blockpfn += isolated - 1;
 			cursor += isolated - 1;
+			continue;
 		}
+
+isolate_fail:
+		if (strict)
+			break;
+
 	}
 
 	trace_mm_compaction_isolate_freepages(nr_scanned, total_isolated);
@@ -307,7 +311,7 @@
 	 * pages requested were isolated. If there were any failures, 0 is
 	 * returned and CMA will fail.
 	 */
-	if (strict && nr_strict_required > total_isolated)
+	if (strict && blockpfn < end_pfn)
 		total_isolated = 0;
 
 	if (locked)
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/mm/ksm.c b/mm/ksm.c
index 47c8853..fa73fc6 100644
--- a/mm/ksm.c
+++ b/mm/ksm.c
@@ -189,6 +189,9 @@
 /* Milliseconds ksmd should sleep between batches */
 static unsigned int ksm_thread_sleep_millisecs = 20;
 
+/* Boolean to indicate whether to use deferred timer or not */
+static bool use_deferred_timer;
+
 #define KSM_RUN_STOP	0
 #define KSM_RUN_MERGE	1
 #define KSM_RUN_UNMERGE	2
@@ -1427,6 +1430,41 @@
 	}
 }
 
+static void process_timeout(unsigned long __data)
+{
+	wake_up_process((struct task_struct *)__data);
+}
+
+static signed long __sched deferred_schedule_timeout(signed long timeout)
+{
+	struct timer_list timer;
+	unsigned long expire;
+
+	__set_current_state(TASK_INTERRUPTIBLE);
+	if (timeout < 0) {
+		pr_err("schedule_timeout: wrong timeout value %lx\n",
+							timeout);
+		__set_current_state(TASK_RUNNING);
+		goto out;
+	}
+
+	expire = timeout + jiffies;
+
+	setup_deferrable_timer_on_stack(&timer, process_timeout,
+			(unsigned long)current);
+	mod_timer(&timer, expire);
+	schedule();
+	del_singleshot_timer_sync(&timer);
+
+	/* Remove the timer from the object tracker */
+	destroy_timer_on_stack(&timer);
+
+	timeout = expire - jiffies;
+
+out:
+	return timeout < 0 ? 0 : timeout;
+}
+
 static int ksmd_should_run(void)
 {
 	return (ksm_run & KSM_RUN_MERGE) && !list_empty(&ksm_mm_head.mm_list);
@@ -1446,7 +1484,11 @@
 		try_to_freeze();
 
 		if (ksmd_should_run()) {
-			schedule_timeout_interruptible(
+			if (use_deferred_timer)
+				deferred_schedule_timeout(
+				msecs_to_jiffies(ksm_thread_sleep_millisecs));
+			else
+				schedule_timeout_interruptible(
 				msecs_to_jiffies(ksm_thread_sleep_millisecs));
 		} else {
 			wait_event_freezable(ksm_thread_wait,
@@ -1926,6 +1968,26 @@
 }
 KSM_ATTR(run);
 
+static ssize_t deferred_timer_show(struct kobject *kobj,
+				    struct kobj_attribute *attr, char *buf)
+{
+	return snprintf(buf, 8, "%d\n", use_deferred_timer);
+}
+
+static ssize_t deferred_timer_store(struct kobject *kobj,
+				     struct kobj_attribute *attr,
+				     const char *buf, size_t count)
+{
+	unsigned long enable;
+	int err;
+
+	err = kstrtoul(buf, 10, &enable);
+	use_deferred_timer = enable;
+
+	return count;
+}
+KSM_ATTR(deferred_timer);
+
 static ssize_t pages_shared_show(struct kobject *kobj,
 				 struct kobj_attribute *attr, char *buf)
 {
@@ -1980,6 +2042,7 @@
 	&pages_unshared_attr.attr,
 	&pages_volatile_attr.attr,
 	&full_scans_attr.attr,
+	&deferred_timer_attr.attr,
 	NULL,
 };
 
diff --git a/mm/page-writeback.c b/mm/page-writeback.c
index a5e8dc2..d012c75 100644
--- a/mm/page-writeback.c
+++ b/mm/page-writeback.c
@@ -190,6 +190,18 @@
 		     zone_reclaimable_pages(z) - z->dirty_balance_reserve;
 	}
 	/*
+	 * Unreclaimable memory (kernel memory or anonymous memory
+	 * without swap) can bring down the dirtyable pages below
+	 * the zone's dirty balance reserve and the above calculation
+	 * will underflow.  However we still want to add in nodes
+	 * which are below threshold (negative values) to get a more
+	 * accurate calculation but make sure that the total never
+	 * underflows.
+	 */
+	if ((long)x < 0)
+		x = 0;
+
+	/*
 	 * Make sure that the number of highmem pages is never larger
 	 * than the number of the total dirtyable memory. This can only
 	 * occur in very strange VM situations but we want to make sure
@@ -211,8 +223,8 @@
 {
 	unsigned long x;
 
-	x = global_page_state(NR_FREE_PAGES) + global_reclaimable_pages() -
-	    dirty_balance_reserve;
+	x = global_page_state(NR_FREE_PAGES) + global_reclaimable_pages();
+	x -= min(x, dirty_balance_reserve);
 
 	if (!vm_highmem_is_dirtyable)
 		x -= highmem_dirtyable_memory(x);
@@ -279,9 +291,12 @@
 	 * highmem zone can hold its share of dirty pages, so we don't
 	 * care about vm_highmem_is_dirtyable here.
 	 */
-	return zone_page_state(zone, NR_FREE_PAGES) +
-	       zone_reclaimable_pages(zone) -
-	       zone->dirty_balance_reserve;
+	unsigned long nr_pages = zone_page_state(zone, NR_FREE_PAGES) +
+		zone_reclaimable_pages(zone);
+
+	/* don't allow this to underflow */
+	nr_pages -= min(nr_pages, zone->dirty_balance_reserve);
+	return nr_pages;
 }
 
 /**
diff --git a/mm/vmalloc.c b/mm/vmalloc.c
index e174693..2e074aa 100644
--- a/mm/vmalloc.c
+++ b/mm/vmalloc.c
@@ -184,36 +184,6 @@
 	return ret;
 }
 
-#ifdef ENABLE_VMALLOC_SAVING
-int is_vmalloc_addr(const void *x)
-{
-	struct rb_node *n;
-	struct vmap_area *va;
-	int ret = 0;
-
-	spin_lock(&vmap_area_lock);
-
-	for (n = rb_first(vmap_area_root); n; rb_next(n)) {
-		va = rb_entry(n, struct vmap_area, rb_node);
-		if (x >= va->va_start && x < va->va_end) {
-			ret = 1;
-			break;
-		}
-	}
-
-	spin_unlock(&vmap_area_lock);
-	return ret;
-}
-#else
-int is_vmalloc_addr(const void *x)
-{
-	unsigned long addr = (unsigned long)x;
-
-	return addr >= VMALLOC_START && addr < VMALLOC_END;
-}
-#endif
-EXPORT_SYMBOL(is_vmalloc_addr);
-
 int is_vmalloc_or_module_addr(const void *x)
 {
 	/*
@@ -302,6 +272,47 @@
 
 static unsigned long vmap_area_pcpu_hole;
 
+#ifdef CONFIG_ENABLE_VMALLOC_SAVING
+#define POSSIBLE_VMALLOC_START	PAGE_OFFSET
+
+#define VMALLOC_BITMAP_SIZE	((VMALLOC_END - PAGE_OFFSET) >> \
+					PAGE_SHIFT)
+#define VMALLOC_TO_BIT(addr)	((addr - PAGE_OFFSET) >> PAGE_SHIFT)
+#define BIT_TO_VMALLOC(i)	(PAGE_OFFSET + i * PAGE_SIZE)
+
+DECLARE_BITMAP(possible_areas, VMALLOC_BITMAP_SIZE);
+
+void mark_vmalloc_reserved_area(void *x, unsigned long size)
+{
+	unsigned long addr = (unsigned long)x;
+
+	bitmap_set(possible_areas, VMALLOC_TO_BIT(addr), size >> PAGE_SHIFT);
+}
+
+int is_vmalloc_addr(const void *x)
+{
+	unsigned long addr = (unsigned long)x;
+
+	if (addr < POSSIBLE_VMALLOC_START || addr >= VMALLOC_END)
+		return 0;
+
+	if (test_bit(VMALLOC_TO_BIT(addr), possible_areas))
+		return 0;
+
+	return 1;
+}
+#else
+int is_vmalloc_addr(const void *x)
+{
+	unsigned long addr = (unsigned long)x;
+
+	return addr >= VMALLOC_START && addr < VMALLOC_END;
+}
+#endif
+EXPORT_SYMBOL(is_vmalloc_addr);
+
+
+
 static struct vmap_area *__find_vmap_area(unsigned long addr)
 {
 	struct rb_node *n = vmap_area_root.rb_node;
diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c
index a225089..f378b38 100644
--- a/net/core/flow_dissector.c
+++ b/net/core/flow_dissector.c
@@ -35,7 +35,7 @@
 		struct iphdr _iph;
 ip:
 		iph = skb_header_pointer(skb, nhoff, sizeof(_iph), &_iph);
-		if (!iph)
+		if (!iph || iph->ihl < 5)
 			return false;
 
 		if (ip_is_fragment(iph))
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/af_inet.c b/net/ipv4/af_inet.c
index f20b5cc..b848d6f 100644
--- a/net/ipv4/af_inet.c
+++ b/net/ipv4/af_inet.c
@@ -1559,7 +1559,7 @@
 
 static const struct net_protocol icmp_protocol = {
 	.handler =	icmp_rcv,
-	.err_handler =	ping_err,
+	.err_handler =	ping_v4_err,
 	.no_policy =	1,
 	.netns_ok =	1,
 };
diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c
index 2cb2bf8..2e109ff 100644
--- a/net/ipv4/icmp.c
+++ b/net/ipv4/icmp.c
@@ -788,7 +788,7 @@
 	if (iph->protocol == IPPROTO_ICMP &&
 	    iph->ihl >= 5 &&
 	    pskb_may_pull(skb, (iph->ihl<<2)+8)) {
-		ping_err(skb, icmp_hdr(skb)->un.gateway);
+		ping_v4_err(skb, icmp_hdr(skb)->un.gateway);
 	}
 
 out:
diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c
index fd7a3f6..cfaaf13 100644
--- a/net/ipv4/netfilter/arp_tables.c
+++ b/net/ipv4/netfilter/arp_tables.c
@@ -271,6 +271,11 @@
 	local_bh_disable();
 	addend = xt_write_recseq_begin();
 	private = table->private;
+	/*
+	 * Ensure we load private-> members after we've fetched the base
+	 * pointer.
+	 */
+	smp_read_barrier_depends();
 	table_base = private->entries[smp_processor_id()];
 
 	e = get_entry(table_base, private->hook_entry[hook]);
diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c
index 24e556e..ed1468a 100644
--- a/net/ipv4/netfilter/ip_tables.c
+++ b/net/ipv4/netfilter/ip_tables.c
@@ -327,6 +327,11 @@
 	addend = xt_write_recseq_begin();
 	private = table->private;
 	cpu        = smp_processor_id();
+	/*
+	 * Ensure we load private-> members after we've fetched the base
+	 * pointer.
+	 */
+	smp_read_barrier_depends();
 	table_base = private->entries[cpu];
 	jumpstack  = (struct ipt_entry **)private->jumpstack[cpu];
 	stackptr   = per_cpu_ptr(private->stackptr, cpu);
diff --git a/net/ipv4/ping.c b/net/ipv4/ping.c
index 50009c7..a8d7ed0 100644
--- a/net/ipv4/ping.c
+++ b/net/ipv4/ping.c
@@ -33,7 +33,6 @@
 #include <linux/netdevice.h>
 #include <net/snmp.h>
 #include <net/ip.h>
-#include <net/ipv6.h>
 #include <net/icmp.h>
 #include <net/protocol.h>
 #include <linux/skbuff.h>
@@ -46,8 +45,18 @@
 #include <net/inet_common.h>
 #include <net/checksum.h>
 
+#if IS_ENABLED(CONFIG_IPV6)
+#include <linux/in6.h>
+#include <linux/icmpv6.h>
+#include <net/addrconf.h>
+#include <net/ipv6.h>
+#include <net/transp_v6.h>
+#endif
 
-static struct ping_table ping_table;
+
+struct ping_table ping_table;
+struct pingv6_ops pingv6_ops;
+EXPORT_SYMBOL_GPL(pingv6_ops);
 
 static u16 ping_port_rover;
 
@@ -57,6 +66,7 @@
 	pr_debug("hash(%d) = %d\n", num, res);
 	return res;
 }
+EXPORT_SYMBOL_GPL(ping_hash);
 
 static inline struct hlist_nulls_head *ping_hashslot(struct ping_table *table,
 					     struct net *net, unsigned num)
@@ -64,7 +74,7 @@
 	return &table->hash[ping_hashfn(net, num, PING_HTABLE_MASK)];
 }
 
-static int ping_v4_get_port(struct sock *sk, unsigned short ident)
+int ping_get_port(struct sock *sk, unsigned short ident)
 {
 	struct hlist_nulls_node *node;
 	struct hlist_nulls_head *hlist;
@@ -102,6 +112,10 @@
 		ping_portaddr_for_each_entry(sk2, node, hlist) {
 			isk2 = inet_sk(sk2);
 
+			/* BUG? Why is this reuse and not reuseaddr? ping.c
+			 * doesn't turn off SO_REUSEADDR, and it doesn't expect
+			 * that other ping processes can steal its packets.
+			 */
 			if ((isk2->inet_num == ident) &&
 			    (sk2 != sk) &&
 			    (!sk2->sk_reuse || !sk->sk_reuse))
@@ -124,17 +138,18 @@
 	write_unlock_bh(&ping_table.lock);
 	return 1;
 }
+EXPORT_SYMBOL_GPL(ping_get_port);
 
-static void ping_v4_hash(struct sock *sk)
+void ping_hash(struct sock *sk)
 {
-	pr_debug("ping_v4_hash(sk->port=%u)\n", inet_sk(sk)->inet_num);
+	pr_debug("ping_hash(sk->port=%u)\n", inet_sk(sk)->inet_num);
 	BUG(); /* "Please do not press this button again." */
 }
 
-static void ping_v4_unhash(struct sock *sk)
+void ping_unhash(struct sock *sk)
 {
 	struct inet_sock *isk = inet_sk(sk);
-	pr_debug("ping_v4_unhash(isk=%p,isk->num=%u)\n", isk, isk->inet_num);
+	pr_debug("ping_unhash(isk=%p,isk->num=%u)\n", isk, isk->inet_num);
 	if (sk_hashed(sk)) {
 		write_lock_bh(&ping_table.lock);
 		hlist_nulls_del(&sk->sk_nulls_node);
@@ -145,31 +160,61 @@
 		write_unlock_bh(&ping_table.lock);
 	}
 }
+EXPORT_SYMBOL_GPL(ping_unhash);
 
-static struct sock *ping_v4_lookup(struct net *net, __be32 saddr, __be32 daddr,
-				   u16 ident, int dif)
+static struct sock *ping_lookup(struct net *net, struct sk_buff *skb, u16 ident)
 {
 	struct hlist_nulls_head *hslot = ping_hashslot(&ping_table, net, ident);
 	struct sock *sk = NULL;
 	struct inet_sock *isk;
 	struct hlist_nulls_node *hnode;
+	int dif = skb->dev->ifindex;
 
-	pr_debug("try to find: num = %d, daddr = %pI4, dif = %d\n",
-		 (int)ident, &daddr, dif);
+	if (skb->protocol == htons(ETH_P_IP)) {
+		pr_debug("try to find: num = %d, daddr = %pI4, dif = %d\n",
+			 (int)ident, &ip_hdr(skb)->daddr, dif);
+#if IS_ENABLED(CONFIG_IPV6)
+	} else if (skb->protocol == htons(ETH_P_IPV6)) {
+		pr_debug("try to find: num = %d, daddr = %pI6c, dif = %d\n",
+			 (int)ident, &ipv6_hdr(skb)->daddr, dif);
+#endif
+	}
+
 	read_lock_bh(&ping_table.lock);
 
 	ping_portaddr_for_each_entry(sk, hnode, hslot) {
 		isk = inet_sk(sk);
 
-		pr_debug("found: %p: num = %d, daddr = %pI4, dif = %d\n", sk,
-			 (int)isk->inet_num, &isk->inet_rcv_saddr,
-			 sk->sk_bound_dev_if);
-
 		pr_debug("iterate\n");
 		if (isk->inet_num != ident)
 			continue;
-		if (isk->inet_rcv_saddr && isk->inet_rcv_saddr != daddr)
-			continue;
+
+		if (skb->protocol == htons(ETH_P_IP) &&
+		    sk->sk_family == AF_INET) {
+			pr_debug("found: %p: num=%d, daddr=%pI4, dif=%d\n", sk,
+				 (int) isk->inet_num, &isk->inet_rcv_saddr,
+				 sk->sk_bound_dev_if);
+
+			if (isk->inet_rcv_saddr &&
+			    isk->inet_rcv_saddr != ip_hdr(skb)->daddr)
+				continue;
+#if IS_ENABLED(CONFIG_IPV6)
+		} else if (skb->protocol == htons(ETH_P_IPV6) &&
+			   sk->sk_family == AF_INET6) {
+			struct ipv6_pinfo *np = inet6_sk(sk);
+
+			pr_debug("found: %p: num=%d, daddr=%pI6c, dif=%d\n", sk,
+				 (int) isk->inet_num,
+				 &inet6_sk(sk)->rcv_saddr,
+				 sk->sk_bound_dev_if);
+
+			if (!ipv6_addr_any(&np->rcv_saddr) &&
+			    !ipv6_addr_equal(&np->rcv_saddr,
+					     &ipv6_hdr(skb)->daddr))
+				continue;
+#endif
+		}
+
 		if (sk->sk_bound_dev_if && sk->sk_bound_dev_if != dif)
 			continue;
 
@@ -198,7 +243,7 @@
 }
 
 
-static int ping_init_sock(struct sock *sk)
+int ping_init_sock(struct sock *sk)
 {
 	struct net *net = sock_net(sk);
 	gid_t group = current_egid();
@@ -224,8 +269,9 @@
 
 	return -EACCES;
 }
+EXPORT_SYMBOL_GPL(ping_init_sock);
 
-static void ping_close(struct sock *sk, long timeout)
+void ping_close(struct sock *sk, long timeout)
 {
 	pr_debug("ping_close(sk=%p,sk->num=%u)\n",
 		 inet_sk(sk), inet_sk(sk)->inet_num);
@@ -233,36 +279,122 @@
 
 	sk_common_release(sk);
 }
+EXPORT_SYMBOL_GPL(ping_close);
 
+/* Checks the bind address and possibly modifies sk->sk_bound_dev_if. */
+int ping_check_bind_addr(struct sock *sk, struct inet_sock *isk,
+			 struct sockaddr *uaddr, int addr_len) {
+	struct net *net = sock_net(sk);
+	if (sk->sk_family == AF_INET) {
+		struct sockaddr_in *addr = (struct sockaddr_in *) uaddr;
+		int chk_addr_ret;
+
+		if (addr_len < sizeof(*addr))
+			return -EINVAL;
+
+		pr_debug("ping_check_bind_addr(sk=%p,addr=%pI4,port=%d)\n",
+			 sk, &addr->sin_addr.s_addr, ntohs(addr->sin_port));
+
+		chk_addr_ret = inet_addr_type(net, addr->sin_addr.s_addr);
+
+		if (addr->sin_addr.s_addr == htonl(INADDR_ANY))
+			chk_addr_ret = RTN_LOCAL;
+
+		if ((sysctl_ip_nonlocal_bind == 0 &&
+		    isk->freebind == 0 && isk->transparent == 0 &&
+		     chk_addr_ret != RTN_LOCAL) ||
+		    chk_addr_ret == RTN_MULTICAST ||
+		    chk_addr_ret == RTN_BROADCAST)
+			return -EADDRNOTAVAIL;
+
+#if IS_ENABLED(CONFIG_IPV6)
+	} else if (sk->sk_family == AF_INET6) {
+		struct sockaddr_in6 *addr = (struct sockaddr_in6 *) uaddr;
+		int addr_type, scoped, has_addr;
+		struct net_device *dev = NULL;
+
+		if (addr_len < sizeof(*addr))
+			return -EINVAL;
+
+		pr_debug("ping_check_bind_addr(sk=%p,addr=%pI6c,port=%d)\n",
+			 sk, addr->sin6_addr.s6_addr, ntohs(addr->sin6_port));
+
+		addr_type = ipv6_addr_type(&addr->sin6_addr);
+		scoped = __ipv6_addr_needs_scope_id(addr_type);
+		if ((addr_type != IPV6_ADDR_ANY &&
+		     !(addr_type & IPV6_ADDR_UNICAST)) ||
+		    (scoped && !addr->sin6_scope_id))
+			return -EINVAL;
+
+		rcu_read_lock();
+		if (addr->sin6_scope_id) {
+			dev = dev_get_by_index_rcu(net, addr->sin6_scope_id);
+			if (!dev) {
+				rcu_read_unlock();
+				return -ENODEV;
+			}
+		}
+		has_addr = pingv6_ops.ipv6_chk_addr(net, &addr->sin6_addr, dev,
+						    scoped);
+		rcu_read_unlock();
+
+		if (!(isk->freebind || isk->transparent || has_addr ||
+		      addr_type == IPV6_ADDR_ANY))
+			return -EADDRNOTAVAIL;
+
+		if (scoped)
+			sk->sk_bound_dev_if = addr->sin6_scope_id;
+#endif
+	} else {
+		return -EAFNOSUPPORT;
+	}
+	return 0;
+}
+
+void ping_set_saddr(struct sock *sk, struct sockaddr *saddr)
+{
+	if (saddr->sa_family == AF_INET) {
+		struct inet_sock *isk = inet_sk(sk);
+		struct sockaddr_in *addr = (struct sockaddr_in *) saddr;
+		isk->inet_rcv_saddr = isk->inet_saddr = addr->sin_addr.s_addr;
+#if IS_ENABLED(CONFIG_IPV6)
+	} else if (saddr->sa_family == AF_INET6) {
+		struct sockaddr_in6 *addr = (struct sockaddr_in6 *) saddr;
+		struct ipv6_pinfo *np = inet6_sk(sk);
+		np->rcv_saddr = np->saddr = addr->sin6_addr;
+#endif
+	}
+}
+
+void ping_clear_saddr(struct sock *sk, int dif)
+{
+	sk->sk_bound_dev_if = dif;
+	if (sk->sk_family == AF_INET) {
+		struct inet_sock *isk = inet_sk(sk);
+		isk->inet_rcv_saddr = isk->inet_saddr = 0;
+#if IS_ENABLED(CONFIG_IPV6)
+	} else if (sk->sk_family == AF_INET6) {
+		struct ipv6_pinfo *np = inet6_sk(sk);
+		memset(&np->rcv_saddr, 0, sizeof(np->rcv_saddr));
+		memset(&np->saddr, 0, sizeof(np->saddr));
+#endif
+	}
+}
 /*
  * We need our own bind because there are no privileged id's == local ports.
  * Moreover, we don't allow binding to multi- and broadcast addresses.
  */
 
-static int ping_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len)
+int ping_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len)
 {
-	struct sockaddr_in *addr = (struct sockaddr_in *)uaddr;
 	struct inet_sock *isk = inet_sk(sk);
 	unsigned short snum;
-	int chk_addr_ret;
 	int err;
+	int dif = sk->sk_bound_dev_if;
 
-	if (addr_len < sizeof(struct sockaddr_in))
-		return -EINVAL;
-
-	pr_debug("ping_v4_bind(sk=%p,sa_addr=%08x,sa_port=%d)\n",
-		 sk, addr->sin_addr.s_addr, ntohs(addr->sin_port));
-
-	chk_addr_ret = inet_addr_type(sock_net(sk), addr->sin_addr.s_addr);
-	if (addr->sin_addr.s_addr == htonl(INADDR_ANY))
-		chk_addr_ret = RTN_LOCAL;
-
-	if ((sysctl_ip_nonlocal_bind == 0 &&
-	    isk->freebind == 0 && isk->transparent == 0 &&
-	     chk_addr_ret != RTN_LOCAL) ||
-	    chk_addr_ret == RTN_MULTICAST ||
-	    chk_addr_ret == RTN_BROADCAST)
-		return -EADDRNOTAVAIL;
+	err = ping_check_bind_addr(sk, isk, uaddr, addr_len);
+	if (err)
+		return err;
 
 	lock_sock(sk);
 
@@ -271,42 +403,50 @@
 		goto out;
 
 	err = -EADDRINUSE;
-	isk->inet_rcv_saddr = isk->inet_saddr = addr->sin_addr.s_addr;
-	snum = ntohs(addr->sin_port);
-	if (ping_v4_get_port(sk, snum) != 0) {
-		isk->inet_saddr = isk->inet_rcv_saddr = 0;
+	ping_set_saddr(sk, uaddr);
+	snum = ntohs(((struct sockaddr_in *)uaddr)->sin_port);
+	if (ping_get_port(sk, snum) != 0) {
+		ping_clear_saddr(sk, dif);
 		goto out;
 	}
 
-	pr_debug("after bind(): num = %d, daddr = %pI4, dif = %d\n",
+	pr_debug("after bind(): num = %d, dif = %d\n",
 		 (int)isk->inet_num,
-		 &isk->inet_rcv_saddr,
 		 (int)sk->sk_bound_dev_if);
 
 	err = 0;
-	if (isk->inet_rcv_saddr)
+	if ((sk->sk_family == AF_INET && isk->inet_rcv_saddr) ||
+	    (sk->sk_family == AF_INET6 &&
+	     !ipv6_addr_any(&inet6_sk(sk)->rcv_saddr)))
 		sk->sk_userlocks |= SOCK_BINDADDR_LOCK;
+
 	if (snum)
 		sk->sk_userlocks |= SOCK_BINDPORT_LOCK;
 	isk->inet_sport = htons(isk->inet_num);
 	isk->inet_daddr = 0;
 	isk->inet_dport = 0;
+
+#if IS_ENABLED(CONFIG_IPV6)
+	if (sk->sk_family == AF_INET6)
+		memset(&inet6_sk(sk)->daddr, 0, sizeof(inet6_sk(sk)->daddr));
+#endif
+
 	sk_dst_reset(sk);
 out:
 	release_sock(sk);
 	pr_debug("ping_v4_bind -> %d\n", err);
 	return err;
 }
+EXPORT_SYMBOL_GPL(ping_bind);
 
 /*
  * Is this a supported type of ICMP message?
  */
 
-static inline int ping_supported(int type, int code)
+static inline int ping_supported(int family, int type, int code)
 {
-	if (type == ICMP_ECHO && code == 0)
-		return 1;
-	return 0;
+	return (family == AF_INET && type == ICMP_ECHO && code == 0) ||
+	       (family == AF_INET6 && type == ICMPV6_ECHO_REQUEST && code == 0);
 }
 
 /*
@@ -314,30 +454,44 @@
  * sort of error condition.
  */
 
-static int ping_queue_rcv_skb(struct sock *sk, struct sk_buff *skb);
-
-void ping_err(struct sk_buff *skb, u32 info)
+void ping_err(struct sk_buff *skb, int offset, u32 info)
 {
-	struct iphdr *iph = (struct iphdr *)skb->data;
-	struct icmphdr *icmph = (struct icmphdr *)(skb->data+(iph->ihl<<2));
+	int family;
+	struct icmphdr *icmph;
 	struct inet_sock *inet_sock;
-	int type = icmph->type;
-	int code = icmph->code;
+	int type;
+	int code;
 	struct net *net = dev_net(skb->dev);
 	struct sock *sk;
 	int harderr;
 	int err;
 
+	if (skb->protocol == htons(ETH_P_IP)) {
+		struct iphdr *iph = (struct iphdr *)skb->data;
+		offset = iph->ihl << 2;
+		family = AF_INET;
+		type = icmp_hdr(skb)->type;
+		code = icmp_hdr(skb)->code;
+		icmph = (struct icmphdr *)(skb->data + offset);
+	} else if (skb->protocol == htons(ETH_P_IPV6)) {
+		family = AF_INET6;
+		type = icmp6_hdr(skb)->icmp6_type;
+		code = icmp6_hdr(skb)->icmp6_code;
+		icmph = (struct icmphdr *) (skb->data + offset);
+	} else {
+		BUG();
+	}
+
 	/* We assume the packet has already been checked by icmp_unreach */
 
-	if (!ping_supported(icmph->type, icmph->code))
+	if (!ping_supported(family, icmph->type, icmph->code))
 		return;
 
-	pr_debug("ping_err(type=%04x,code=%04x,id=%04x,seq=%04x)\n", type,
-		 code, ntohs(icmph->un.echo.id), ntohs(icmph->un.echo.sequence));
+	pr_debug("ping_err(proto=0x%x,type=%d,code=%d,id=%04x,seq=%04x)\n",
+		 skb->protocol, type, code, ntohs(icmph->un.echo.id),
+		 ntohs(icmph->un.echo.sequence));
 
-	sk = ping_v4_lookup(net, iph->daddr, iph->saddr,
-			    ntohs(icmph->un.echo.id), skb->dev->ifindex);
+	sk = ping_lookup(net, skb, ntohs(icmph->un.echo.id));
 	if (sk == NULL) {
 		pr_debug("no socket, dropping\n");
 		return;	/* No socket for error */
@@ -348,70 +502,85 @@
 	harderr = 0;
 	inet_sock = inet_sk(sk);
 
-	switch (type) {
-	default:
-	case ICMP_TIME_EXCEEDED:
-		err = EHOSTUNREACH;
-		break;
-	case ICMP_SOURCE_QUENCH:
-		/* This is not a real error but ping wants to see it.
-		 * Report it with some fake errno. */
-		err = EREMOTEIO;
-		break;
-	case ICMP_PARAMETERPROB:
-		err = EPROTO;
-		harderr = 1;
-		break;
-	case ICMP_DEST_UNREACH:
-		if (code == ICMP_FRAG_NEEDED) { /* Path MTU discovery */
-			if (inet_sock->pmtudisc != IP_PMTUDISC_DONT) {
-				err = EMSGSIZE;
-				harderr = 1;
-				break;
+	if (skb->protocol == htons(ETH_P_IP)) {
+		switch (type) {
+		default:
+		case ICMP_TIME_EXCEEDED:
+			err = EHOSTUNREACH;
+			break;
+		case ICMP_SOURCE_QUENCH:
+			/* This is not a real error but ping wants to see it.
+			 * Report it with some fake errno. */
+			err = EREMOTEIO;
+			break;
+		case ICMP_PARAMETERPROB:
+			err = EPROTO;
+			harderr = 1;
+			break;
+		case ICMP_DEST_UNREACH:
+			if (code == ICMP_FRAG_NEEDED) { /* Path MTU discovery */
+				if (inet_sock->pmtudisc != IP_PMTUDISC_DONT) {
+					err = EMSGSIZE;
+					harderr = 1;
+					break;
+				}
+				goto out;
 			}
-			goto out;
+			err = EHOSTUNREACH;
+			if (code <= NR_ICMP_UNREACH) {
+				harderr = icmp_err_convert[code].fatal;
+				err = icmp_err_convert[code].errno;
+			}
+			break;
+		case ICMP_REDIRECT:
+			/* See ICMP_SOURCE_QUENCH */
+			err = EREMOTEIO;
+			break;
 		}
-		err = EHOSTUNREACH;
-		if (code <= NR_ICMP_UNREACH) {
-			harderr = icmp_err_convert[code].fatal;
-			err = icmp_err_convert[code].errno;
-		}
-		break;
-	case ICMP_REDIRECT:
-		/* See ICMP_SOURCE_QUENCH */
-		err = EREMOTEIO;
-		break;
+#if IS_ENABLED(CONFIG_IPV6)
+	} else if (skb->protocol == htons(ETH_P_IPV6)) {
+		harderr = pingv6_ops.icmpv6_err_convert(type, code, &err);
+#endif
 	}
 
 	/*
 	 *      RFC1122: OK.  Passes ICMP errors back to application, as per
 	 *	4.1.3.3.
 	 */
-	if (!inet_sock->recverr) {
+	if ((family == AF_INET && !inet_sock->recverr) ||
+	    (family == AF_INET6 && !inet6_sk(sk)->recverr)) {
 		if (!harderr || sk->sk_state != TCP_ESTABLISHED)
 			goto out;
 	} else {
-		ip_icmp_error(sk, skb, err, 0 /* no remote port */,
-			 info, (u8 *)icmph);
+		if (family == AF_INET) {
+			ip_icmp_error(sk, skb, err, 0 /* no remote port */,
+				      info, (u8 *)icmph);
+#if IS_ENABLED(CONFIG_IPV6)
+		} else if (family == AF_INET6) {
+			pingv6_ops.ipv6_icmp_error(sk, skb, err, 0,
+						   info, (u8 *)icmph);
+#endif
+		}
 	}
 	sk->sk_err = err;
 	sk->sk_error_report(sk);
 out:
 	sock_put(sk);
 }
+EXPORT_SYMBOL_GPL(ping_err);
+
+void ping_v4_err(struct sk_buff *skb, u32 info)
+{
+	ping_err(skb, 0, info);
+}
 
 /*
- *	Copy and checksum an ICMP Echo packet from user space into a buffer.
+ *	Copy and checksum an ICMP Echo packet from user space into a buffer
+ *	starting from the payload.
  */
 
-struct pingfakehdr {
-	struct icmphdr icmph;
-	struct iovec *iov;
-	__wsum wcheck;
-};
-
-static int ping_getfrag(void *from, char * to,
-			int offset, int fraglen, int odd, struct sk_buff *skb)
+int ping_getfrag(void *from, char *to,
+		 int offset, int fraglen, int odd, struct sk_buff *skb)
 {
 	struct pingfakehdr *pfh = (struct pingfakehdr *)from;
 
@@ -422,20 +591,33 @@
 			    pfh->iov, 0, fraglen - sizeof(struct icmphdr),
 			    &pfh->wcheck))
 			return -EFAULT;
-
-		return 0;
+	} else if (offset < sizeof(struct icmphdr)) {
+			BUG();
+	} else {
+		if (csum_partial_copy_fromiovecend
+				(to, pfh->iov, offset - sizeof(struct icmphdr),
+				 fraglen, &pfh->wcheck))
+			return -EFAULT;
 	}
-	if (offset < sizeof(struct icmphdr))
-		BUG();
-	if (csum_partial_copy_fromiovecend
-			(to, pfh->iov, offset - sizeof(struct icmphdr),
-			 fraglen, &pfh->wcheck))
-		return -EFAULT;
+
+#if IS_ENABLED(CONFIG_IPV6)
+	/* For IPv6, checksum each skb as we go along, as expected by
+	 * icmpv6_push_pending_frames. For IPv4, accumulate the checksum in
+	 * wcheck, it will be finalized in ping_v4_push_pending_frames.
+	 */
+	if (pfh->family == AF_INET6) {
+		skb->csum = pfh->wcheck;
+		skb->ip_summed = CHECKSUM_NONE;
+		pfh->wcheck = 0;
+	}
+#endif
+
 	return 0;
 }
+EXPORT_SYMBOL_GPL(ping_getfrag);
 
-static int ping_push_pending_frames(struct sock *sk, struct pingfakehdr *pfh,
-				    struct flowi4 *fl4)
+static int ping_v4_push_pending_frames(struct sock *sk, struct pingfakehdr *pfh,
+				       struct flowi4 *fl4)
 {
 	struct sk_buff *skb = skb_peek(&sk->sk_write_queue);
 
@@ -447,24 +629,9 @@
 	return ip_push_pending_frames(sk, fl4);
 }
 
-static int ping_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
-			size_t len)
-{
-	struct net *net = sock_net(sk);
-	struct flowi4 fl4;
-	struct inet_sock *inet = inet_sk(sk);
-	struct ipcm_cookie ipc;
-	struct icmphdr user_icmph;
-	struct pingfakehdr pfh;
-	struct rtable *rt = NULL;
-	struct ip_options_data opt_copy;
-	int free = 0;
-	__be32 saddr, daddr, faddr;
-	u8  tos;
-	int err;
-
-	pr_debug("ping_sendmsg(sk=%p,sk->num=%u)\n", inet, inet->inet_num);
-
+int ping_common_sendmsg(int family, struct msghdr *msg, size_t len,
+			void *user_icmph, size_t icmph_len) {
+	u8 type, code;
 
 	if (len > 0xFFFF)
 		return -EMSGSIZE;
@@ -479,15 +646,53 @@
 
 	/*
 	 *	Fetch the ICMP header provided by the userland.
-	 *	iovec is modified!
+	 *	iovec is modified! The ICMP header is consumed.
 	 */
-
-	if (memcpy_fromiovec((u8 *)&user_icmph, msg->msg_iov,
-			     sizeof(struct icmphdr)))
+	if (memcpy_fromiovec(user_icmph, msg->msg_iov, icmph_len))
 		return -EFAULT;
-	if (!ping_supported(user_icmph.type, user_icmph.code))
+
+	if (family == AF_INET) {
+		type = ((struct icmphdr *) user_icmph)->type;
+		code = ((struct icmphdr *) user_icmph)->code;
+#if IS_ENABLED(CONFIG_IPV6)
+	} else if (family == AF_INET6) {
+		type = ((struct icmp6hdr *) user_icmph)->icmp6_type;
+		code = ((struct icmp6hdr *) user_icmph)->icmp6_code;
+#endif
+	} else {
+		BUG();
+	}
+
+	if (!ping_supported(family, type, code))
 		return -EINVAL;
 
+	return 0;
+}
+EXPORT_SYMBOL_GPL(ping_common_sendmsg);
+
+int ping_v4_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
+		    size_t len)
+{
+	struct net *net = sock_net(sk);
+	struct flowi4 fl4;
+	struct inet_sock *inet = inet_sk(sk);
+	struct ipcm_cookie ipc;
+	struct icmphdr user_icmph;
+	struct pingfakehdr pfh;
+	struct rtable *rt = NULL;
+	struct ip_options_data opt_copy;
+	int free = 0;
+	__be32 saddr, daddr, faddr;
+	u8  tos;
+	int err;
+
+	pr_debug("ping_v4_sendmsg(sk=%p,sk->num=%u)\n", inet, inet->inet_num);
+
+	err = ping_common_sendmsg(AF_INET, msg, len, &user_icmph,
+				  sizeof(user_icmph));
+	if (err)
+		return err;
+
 	/*
 	 *	Get and verify the address.
 	 */
@@ -593,13 +798,14 @@
 	pfh.icmph.un.echo.sequence = user_icmph.un.echo.sequence;
 	pfh.iov = msg->msg_iov;
 	pfh.wcheck = 0;
+	pfh.family = AF_INET;
 
 	err = ip_append_data(sk, &fl4, ping_getfrag, &pfh, len,
 			0, &ipc, &rt, msg->msg_flags);
 	if (err)
 		ip_flush_pending_frames(sk);
 	else
-		err = ping_push_pending_frames(sk, &pfh, &fl4);
+		err = ping_v4_push_pending_frames(sk, &pfh, &fl4);
 	release_sock(sk);
 
 out:
@@ -620,11 +826,13 @@
 	goto out;
 }
 
-static int ping_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
-			size_t len, int noblock, int flags, int *addr_len)
+int ping_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
+		 size_t len, int noblock, int flags, int *addr_len)
 {
 	struct inet_sock *isk = inet_sk(sk);
-	struct sockaddr_in *sin = (struct sockaddr_in *)msg->msg_name;
+	int family = sk->sk_family;
+	struct sockaddr_in *sin;
+	struct sockaddr_in6 *sin6;
 	struct sk_buff *skb;
 	int copied, err;
 
@@ -634,11 +842,22 @@
 	if (flags & MSG_OOB)
 		goto out;
 
-	if (addr_len)
-		*addr_len = sizeof(*sin);
+	if (addr_len) {
+		if (family == AF_INET)
+			*addr_len = sizeof(*sin);
+		else if (family == AF_INET6 && addr_len)
+			*addr_len = sizeof(*sin6);
+	}
 
-	if (flags & MSG_ERRQUEUE)
-		return ip_recv_error(sk, msg, len);
+	if (flags & MSG_ERRQUEUE) {
+		if (family == AF_INET) {
+			return ip_recv_error(sk, msg, len);
+#if IS_ENABLED(CONFIG_IPV6)
+		} else if (family == AF_INET6) {
+			return pingv6_ops.ipv6_recv_error(sk, msg, len);
+#endif
+		}
+	}
 
 	skb = skb_recv_datagram(sk, flags, noblock, &err);
 	if (!skb)
@@ -657,15 +876,41 @@
 
 	sock_recv_timestamp(msg, sk, skb);
 
-	/* Copy the address. */
-	if (sin) {
+	/* Copy the address and add cmsg data. */
+	if (family == AF_INET) {
+		sin = (struct sockaddr_in *) msg->msg_name;
 		sin->sin_family = AF_INET;
 		sin->sin_port = 0 /* skb->h.uh->source */;
 		sin->sin_addr.s_addr = ip_hdr(skb)->saddr;
 		memset(sin->sin_zero, 0, sizeof(sin->sin_zero));
+
+		if (isk->cmsg_flags)
+			ip_cmsg_recv(msg, skb);
+
+#if IS_ENABLED(CONFIG_IPV6)
+	} else if (family == AF_INET6) {
+		struct ipv6_pinfo *np = inet6_sk(sk);
+		struct ipv6hdr *ip6 = ipv6_hdr(skb);
+		sin6 = (struct sockaddr_in6 *) msg->msg_name;
+		sin6->sin6_family = AF_INET6;
+		sin6->sin6_port = 0;
+		sin6->sin6_addr = ip6->saddr;
+
+		sin6->sin6_flowinfo = 0;
+		if (np->sndflow)
+			sin6->sin6_flowinfo =
+				*(__be32 *)ip6 & IPV6_FLOWINFO_MASK;
+
+		sin6->sin6_scope_id = ipv6_iface_scope_id(&sin6->sin6_addr,
+							  IP6CB(skb)->iif);
+
+		if (inet6_sk(sk)->rxopt.all)
+			pingv6_ops.datagram_recv_ctl(sk, msg, skb);
+#endif
+	} else {
+		BUG();
 	}
-	if (isk->cmsg_flags)
-		ip_cmsg_recv(msg, skb);
+
 	err = copied;
 
 done:
@@ -674,8 +919,9 @@
 	pr_debug("ping_recvmsg -> %d\n", err);
 	return err;
 }
+EXPORT_SYMBOL_GPL(ping_recvmsg);
 
-static int ping_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
+int ping_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
 {
 	pr_debug("ping_queue_rcv_skb(sk=%p,sk->num=%d,skb=%p)\n",
 		 inet_sk(sk), inet_sk(sk)->inet_num, skb);
@@ -686,6 +932,7 @@
 	}
 	return 0;
 }
+EXPORT_SYMBOL_GPL(ping_queue_rcv_skb);
 
 
 /*
@@ -696,10 +943,7 @@
 {
 	struct sock *sk;
 	struct net *net = dev_net(skb->dev);
-	struct iphdr *iph = ip_hdr(skb);
 	struct icmphdr *icmph = icmp_hdr(skb);
-	__be32 saddr = iph->saddr;
-	__be32 daddr = iph->daddr;
 
 	/* We assume the packet has already been checked by icmp_rcv */
 
@@ -709,8 +953,7 @@
 	/* Push ICMP header back */
 	skb_push(skb, skb->data - (u8 *)icmph);
 
-	sk = ping_v4_lookup(net, saddr, daddr, ntohs(icmph->un.echo.id),
-			    skb->dev->ifindex);
+	sk = ping_lookup(net, skb, ntohs(icmph->un.echo.id));
 	if (sk != NULL) {
 		pr_debug("rcv on socket %p\n", sk);
 		ping_queue_rcv_skb(sk, skb_get(skb));
@@ -721,6 +964,7 @@
 
 	/* We're called from icmp_rcv(). kfree_skb() is done there. */
 }
+EXPORT_SYMBOL_GPL(ping_rcv);
 
 struct proto ping_prot = {
 	.name =		"PING",
@@ -731,13 +975,13 @@
 	.disconnect =	udp_disconnect,
 	.setsockopt =	ip_setsockopt,
 	.getsockopt =	ip_getsockopt,
-	.sendmsg =	ping_sendmsg,
+	.sendmsg =	ping_v4_sendmsg,
 	.recvmsg =	ping_recvmsg,
 	.bind =		ping_bind,
 	.backlog_rcv =	ping_queue_rcv_skb,
-	.hash =		ping_v4_hash,
-	.unhash =	ping_v4_unhash,
-	.get_port =	ping_v4_get_port,
+	.hash =		ping_hash,
+	.unhash =	ping_unhash,
+	.get_port =	ping_get_port,
 	.obj_size =	sizeof(struct inet_sock),
 };
 EXPORT_SYMBOL(ping_prot);
diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c
index 7a7724d..6bd622f 100644
--- a/net/ipv4/sysctl_net_ipv4.c
+++ b/net/ipv4/sysctl_net_ipv4.c
@@ -36,6 +36,10 @@
 static int ip_ttl_max = 255;
 static int ip_ping_group_range_min[] = { 0, 0 };
 static int ip_ping_group_range_max[] = { GID_T_MAX, GID_T_MAX };
+static int tcp_delack_seg_min = TCP_DELACK_MIN;
+static int tcp_delack_seg_max = 60;
+static int tcp_use_userconfig_min;
+static int tcp_use_userconfig_max = 1;
 
 /* Update system visible IP port range */
 static void set_local_port_range(int range[2])
@@ -699,6 +703,25 @@
 		.proc_handler	= proc_dointvec_minmax,
 		.extra1		= &zero
 	},
+	{
+		.procname	= "tcp_delack_seg",
+		.data		= &sysctl_tcp_delack_seg,
+		.maxlen		= sizeof(sysctl_tcp_delack_seg),
+		.mode		= 0644,
+		.proc_handler = tcp_proc_delayed_ack_control,
+		.extra1		= &tcp_delack_seg_min,
+		.extra2		= &tcp_delack_seg_max,
+	},
+	{
+		.procname       = "tcp_use_userconfig",
+		.data           = &sysctl_tcp_use_userconfig,
+		.maxlen         = sizeof(sysctl_tcp_use_userconfig),
+		.mode           = 0644,
+		.proc_handler   = tcp_use_userconfig_sysctl_handler,
+		.extra1		    = &tcp_use_userconfig_min,
+		.extra2		    = &tcp_use_userconfig_max,
+	},
+
 	{ }
 };
 
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/ipv4/tcp.c b/net/ipv4/tcp.c
index b2b0e99..706899e 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -294,6 +294,12 @@
 EXPORT_SYMBOL(sysctl_tcp_rmem);
 EXPORT_SYMBOL(sysctl_tcp_wmem);
 
+int sysctl_tcp_delack_seg __read_mostly = TCP_DELACK_SEG;
+EXPORT_SYMBOL(sysctl_tcp_delack_seg);
+
+int sysctl_tcp_use_userconfig __read_mostly;
+EXPORT_SYMBOL(sysctl_tcp_use_userconfig);
+
 atomic_long_t tcp_memory_allocated;	/* Current allocated memory. */
 EXPORT_SYMBOL(tcp_memory_allocated);
 
@@ -485,14 +491,12 @@
 			 !tp->urg_data ||
 			 before(tp->urg_seq, tp->copied_seq) ||
 			 !before(tp->urg_seq, tp->rcv_nxt)) {
-			struct sk_buff *skb;
 
 			answ = tp->rcv_nxt - tp->copied_seq;
 
-			/* Subtract 1, if FIN is in queue. */
-			skb = skb_peek_tail(&sk->sk_receive_queue);
-			if (answ && skb)
-				answ -= tcp_hdr(skb)->fin;
+			/* Subtract 1, if FIN was received */
+			if (answ && sock_flag(sk, SOCK_DONE))
+				answ--;
 		} else
 			answ = tp->urg_seq - tp->copied_seq;
 		release_sock(sk);
@@ -1215,8 +1219,11 @@
 		   /* Delayed ACKs frequently hit locked sockets during bulk
 		    * receive. */
 		if (icsk->icsk_ack.blocked ||
-		    /* Once-per-two-segments ACK was not sent by tcp_input.c */
-		    tp->rcv_nxt - tp->rcv_wup > icsk->icsk_ack.rcv_mss ||
+		    /* Once-per-sysctl_tcp_delack_seg segments
+			  * ACK was not sent by tcp_input.c
+			  */
+		    tp->rcv_nxt - tp->rcv_wup > (icsk->icsk_ack.rcv_mss) *
+						sysctl_tcp_delack_seg ||
 		    /*
 		     * If this read emptied read buffer, we send ACK, if
 		     * connection is not bidirectional, user drained
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index 257b617..7c3612b 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -5047,7 +5047,8 @@
 	struct tcp_sock *tp = tcp_sk(sk);
 
 	    /* More than one full frame received... */
-	if (((tp->rcv_nxt - tp->rcv_wup) > inet_csk(sk)->icsk_ack.rcv_mss &&
+	if (((tp->rcv_nxt - tp->rcv_wup) > (inet_csk(sk)->icsk_ack.rcv_mss) *
+					sysctl_tcp_delack_seg &&
 	     /* ... and right edge of window advances far enough.
 	      * (tcp_recvmsg() will send ACK otherwise). Or...
 	      */
diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c
index 34d4a02..d1b4792 100644
--- a/net/ipv4/tcp_timer.c
+++ b/net/ipv4/tcp_timer.c
@@ -34,7 +34,39 @@
 
 static void tcp_write_timer(unsigned long);
 static void tcp_delack_timer(unsigned long);
-static void tcp_keepalive_timer (unsigned long data);
+static void tcp_keepalive_timer(unsigned long data);
+
+/*Function to reset tcp_ack related sysctl on resetting master control */
+void set_tcp_default(void)
+{
+	sysctl_tcp_delack_seg	= TCP_DELACK_SEG;
+}
+
+/*sysctl handler for tcp_ack realted master control */
+int tcp_proc_delayed_ack_control(ctl_table *table, int write,
+			void __user *buffer, size_t *length, loff_t *ppos)
+{
+	int ret = proc_dointvec_minmax(table, write, buffer, length, ppos);
+
+	/* The ret value will be 0 if the input validation is successful
+	 * and the values are written to sysctl table. If not, the stack
+	 * will continue to work with currently configured values
+	 */
+	return ret;
+}
+
+/*sysctl handler for tcp_ack realted master control */
+int tcp_use_userconfig_sysctl_handler(ctl_table *table, int write,
+			void __user *buffer, size_t *length, loff_t *ppos)
+{
+	int ret = proc_dointvec_minmax(table, write, buffer, length, ppos);
+
+	if (write && ret == 0) {
+		if (!sysctl_tcp_use_userconfig)
+			set_tcp_default();
+	}
+	return ret;
+}
 
 void tcp_init_xmit_timers(struct sock *sk)
 {
diff --git a/net/ipv6/Makefile b/net/ipv6/Makefile
index 686934a..753be5d 100644
--- a/net/ipv6/Makefile
+++ b/net/ipv6/Makefile
@@ -7,7 +7,7 @@
 ipv6-objs :=	af_inet6.o anycast.o ip6_output.o ip6_input.o addrconf.o \
 		addrlabel.o \
 		route.o ip6_fib.o ipv6_sockglue.o ndisc.o udp.o udplite.o \
-		raw.o protocol.o icmp.o mcast.o reassembly.o tcp_ipv6.o \
+		raw.o protocol.o icmp.o mcast.o reassembly.o tcp_ipv6.o ping.o \
 		exthdrs.o datagram.o ip6_flowlabel.o inet6_connection_sock.o
 
 ipv6-$(CONFIG_SYSCTL) = sysctl_net_ipv6.o
diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c
index 29625e9..22ebbb9 100644
--- a/net/ipv6/af_inet6.c
+++ b/net/ipv6/af_inet6.c
@@ -49,6 +49,7 @@
 #include <net/udplite.h>
 #include <net/tcp.h>
 #include <net/ipip.h>
+#include <net/ping.h>
 #include <net/protocol.h>
 #include <net/inet_common.h>
 #include <net/route.h>
@@ -1130,6 +1131,9 @@
 	if (err)
 		goto out_unregister_udplite_proto;
 
+	err = proto_register(&pingv6_prot, 1);
+	if (err)
+		goto out_unregister_ping_proto;
 
 	/* We MUST register RAW sockets before we create the ICMP6,
 	 * IGMP6, or NDISC control sockets.
@@ -1225,6 +1229,10 @@
 	if (err)
 		goto ipv6_packet_fail;
 
+	err = pingv6_init();
+	if (err)
+		goto pingv6_fail;
+
 #ifdef CONFIG_SYSCTL
 	err = ipv6_sysctl_register();
 	if (err)
@@ -1237,6 +1245,8 @@
 sysctl_fail:
 	ipv6_packet_cleanup();
 #endif
+pingv6_fail:
+	pingv6_exit();
 ipv6_packet_fail:
 	tcpv6_exit();
 tcpv6_fail:
@@ -1284,6 +1294,8 @@
 	rtnl_unregister_all(PF_INET6);
 out_sock_register_fail:
 	rawv6_exit();
+out_unregister_ping_proto:
+	proto_unregister(&pingv6_prot);
 out_unregister_raw_proto:
 	proto_unregister(&rawv6_prot);
 out_unregister_udplite_proto:
diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c
index 27ac95a..ba0c147 100644
--- a/net/ipv6/icmp.c
+++ b/net/ipv6/icmp.c
@@ -55,6 +55,7 @@
 
 #include <net/ipv6.h>
 #include <net/ip6_checksum.h>
+#include <net/ping.h>
 #include <net/protocol.h>
 #include <net/raw.h>
 #include <net/rawv6.h>
@@ -79,10 +80,22 @@
 	return net->ipv6.icmp_sk[smp_processor_id()];
 }
 
+static void icmpv6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
+		       u8 type, u8 code, int offset, __be32 info)
+{
+	/* icmpv6_notify checks 8 bytes can be pulled, icmp6hdr is 8 bytes */
+	struct icmp6hdr *icmp6 = (struct icmp6hdr *) (skb->data + offset);
+
+	if (!(type & ICMPV6_INFOMSG_MASK))
+		if (icmp6->icmp6_type == ICMPV6_ECHO_REQUEST)
+			ping_err(skb, offset, info);
+}
+
 static int icmpv6_rcv(struct sk_buff *skb);
 
 static const struct inet6_protocol icmpv6_protocol = {
 	.handler	=	icmpv6_rcv,
+	.err_handler	=	icmpv6_err,
 	.flags		=	INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL,
 };
 
@@ -217,7 +230,8 @@
 	return (*op & 0xC0) == 0x80;
 }
 
-static int icmpv6_push_pending_frames(struct sock *sk, struct flowi6 *fl6, struct icmp6hdr *thdr, int len)
+int icmpv6_push_pending_frames(struct sock *sk, struct flowi6 *fl6,
+			       struct icmp6hdr *thdr, int len)
 {
 	struct sk_buff *skb;
 	struct icmp6hdr *icmp6h;
@@ -300,8 +314,8 @@
 static inline void mip6_addr_swap(struct sk_buff *skb) {}
 #endif
 
-static struct dst_entry *icmpv6_route_lookup(struct net *net, struct sk_buff *skb,
-					     struct sock *sk, struct flowi6 *fl6)
+struct dst_entry *icmpv6_route_lookup(struct net *net, struct sk_buff *skb,
+				      struct sock *sk, struct flowi6 *fl6)
 {
 	struct dst_entry *dst, *dst2;
 	struct flowi6 fl2;
@@ -594,7 +608,7 @@
 	icmpv6_xmit_unlock(sk);
 }
 
-static void icmpv6_notify(struct sk_buff *skb, u8 type, u8 code, __be32 info)
+void icmpv6_notify(struct sk_buff *skb, u8 type, u8 code, __be32 info)
 {
 	const struct inet6_protocol *ipprot;
 	int inner_offset;
@@ -687,7 +701,8 @@
 		skb->csum = ~csum_unfold(csum_ipv6_magic(saddr, daddr, skb->len,
 					     IPPROTO_ICMPV6, 0));
 		if (__skb_checksum_complete(skb)) {
-			LIMIT_NETDEBUG(KERN_DEBUG "ICMPv6 checksum failed [%pI6 > %pI6]\n",
+			LIMIT_NETDEBUG(KERN_DEBUG
+				       "ICMPv6 checksum failed [%pI6c > %pI6c]\n",
 				       saddr, daddr);
 			goto discard_it;
 		}
@@ -708,7 +723,7 @@
 		break;
 
 	case ICMPV6_ECHO_REPLY:
-		/* we couldn't care less */
+		ping_rcv(skb);
 		break;
 
 	case ICMPV6_PKT_TOOBIG:
diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c
index e641f8f..c30a20c 100644
--- a/net/ipv6/netfilter/ip6_tables.c
+++ b/net/ipv6/netfilter/ip6_tables.c
@@ -349,6 +349,11 @@
 	local_bh_disable();
 	addend = xt_write_recseq_begin();
 	private = table->private;
+	/*
+	 * Ensure we load private-> members after we've fetched the base
+	 * pointer.
+	 */
+	smp_read_barrier_depends();
 	cpu        = smp_processor_id();
 	table_base = private->entries[cpu];
 	jumpstack  = (struct ip6t_entry **)private->jumpstack[cpu];
diff --git a/net/ipv6/ping.c b/net/ipv6/ping.c
new file mode 100644
index 0000000..f46e315
--- /dev/null
+++ b/net/ipv6/ping.c
@@ -0,0 +1,222 @@
+/*
+ * INET		An implementation of the TCP/IP protocol suite for the LINUX
+ *		operating system.  INET is implemented using the  BSD Socket
+ *		interface as the means of communication with the user level.
+ *
+ *		"Ping" sockets
+ *
+ *		This program is free software; you can redistribute it and/or
+ *		modify it under the terms of the GNU General Public License
+ *		as published by the Free Software Foundation; either version
+ *		2 of the License, or (at your option) any later version.
+ *
+ * Based on ipv4/ping.c code.
+ *
+ * Authors:	Lorenzo Colitti (IPv6 support)
+ *		Vasiliy Kulikov / Openwall (IPv4 implementation, for Linux 2.6),
+ *		Pavel Kankovsky (IPv4 implementation, for Linux 2.4.32)
+ *
+ */
+
+#include <net/addrconf.h>
+#include <net/ipv6.h>
+#include <net/ip6_route.h>
+#include <net/protocol.h>
+#include <net/udp.h>
+#include <net/transp_v6.h>
+#include <net/ping.h>
+#include <linux/module.h>
+
+struct proto pingv6_prot = {
+	.name =		"PINGv6",
+	.owner =	THIS_MODULE,
+	.init =		ping_init_sock,
+	.close =	ping_close,
+	.connect =	ip6_datagram_connect,
+	.disconnect =	udp_disconnect,
+	.setsockopt =	ipv6_setsockopt,
+	.getsockopt =	ipv6_getsockopt,
+	.sendmsg =	ping_v6_sendmsg,
+	.recvmsg =	ping_recvmsg,
+	.bind =		ping_bind,
+	.backlog_rcv =	ping_queue_rcv_skb,
+	.hash =		ping_hash,
+	.unhash =	ping_unhash,
+	.get_port =	ping_get_port,
+	.obj_size =	sizeof(struct raw6_sock),
+};
+EXPORT_SYMBOL_GPL(pingv6_prot);
+
+static struct inet_protosw pingv6_protosw = {
+	.type =      SOCK_DGRAM,
+	.protocol =  IPPROTO_ICMPV6,
+	.prot =      &pingv6_prot,
+	.ops =       &inet6_dgram_ops,
+	.no_check =  UDP_CSUM_DEFAULT,
+	.flags =     INET_PROTOSW_REUSE,
+};
+
+
+/* Compatibility glue so we can support IPv6 when it's compiled as a module */
+int dummy_ipv6_recv_error(struct sock *sk, struct msghdr *msg, int len)
+{
+	return -EAFNOSUPPORT;
+}
+int dummy_datagram_recv_ctl(struct sock *sk, struct msghdr *msg,
+				 struct sk_buff *skb)
+{
+	return -EAFNOSUPPORT;
+}
+int dummy_icmpv6_err_convert(u8 type, u8 code, int *err)
+{
+	return -EAFNOSUPPORT;
+}
+void dummy_ipv6_icmp_error(struct sock *sk, struct sk_buff *skb, int err,
+			    __be16 port, u32 info, u8 *payload) {}
+int dummy_ipv6_chk_addr(struct net *net, const struct in6_addr *addr,
+			struct net_device *dev, int strict)
+{
+	return 0;
+}
+
+int __init pingv6_init(void)
+{
+	pingv6_ops.ipv6_recv_error = ipv6_recv_error;
+	pingv6_ops.datagram_recv_ctl = datagram_recv_ctl;
+	pingv6_ops.icmpv6_err_convert = icmpv6_err_convert;
+	pingv6_ops.ipv6_icmp_error = ipv6_icmp_error;
+	pingv6_ops.ipv6_chk_addr = ipv6_chk_addr;
+	return inet6_register_protosw(&pingv6_protosw);
+}
+
+/* This never gets called because it's not possible to unload the ipv6 module,
+ * but just in case.
+ */
+void pingv6_exit(void)
+{
+	pingv6_ops.ipv6_recv_error = dummy_ipv6_recv_error;
+	pingv6_ops.datagram_recv_ctl = dummy_datagram_recv_ctl;
+	pingv6_ops.icmpv6_err_convert = dummy_icmpv6_err_convert;
+	pingv6_ops.ipv6_icmp_error = dummy_ipv6_icmp_error;
+	pingv6_ops.ipv6_chk_addr = dummy_ipv6_chk_addr;
+	inet6_unregister_protosw(&pingv6_protosw);
+}
+
+int ping_v6_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
+		    size_t len)
+{
+	struct inet_sock *inet = inet_sk(sk);
+	struct ipv6_pinfo *np = inet6_sk(sk);
+	struct icmp6hdr user_icmph;
+	int addr_type;
+	struct in6_addr *daddr;
+	int iif = 0;
+	struct flowi6 fl6;
+	int err;
+	int hlimit;
+	struct dst_entry *dst;
+	struct rt6_info *rt;
+	struct pingfakehdr pfh;
+
+	pr_debug("ping_v6_sendmsg(sk=%p,sk->num=%u)\n", inet, inet->inet_num);
+
+	err = ping_common_sendmsg(AF_INET6, msg, len, &user_icmph,
+				  sizeof(user_icmph));
+	if (err)
+		return err;
+
+	if (msg->msg_name) {
+		struct sockaddr_in6 *u = (struct sockaddr_in6 *) msg->msg_name;
+		if (msg->msg_namelen < sizeof(struct sockaddr_in6) ||
+		    u->sin6_family != AF_INET6) {
+			return -EINVAL;
+		}
+		if (sk->sk_bound_dev_if &&
+		    sk->sk_bound_dev_if != u->sin6_scope_id) {
+			return -EINVAL;
+		}
+		daddr = &(u->sin6_addr);
+		iif = u->sin6_scope_id;
+	} else {
+		if (sk->sk_state != TCP_ESTABLISHED)
+			return -EDESTADDRREQ;
+		daddr = &np->daddr;
+	}
+
+	if (!iif)
+		iif = sk->sk_bound_dev_if;
+
+	addr_type = ipv6_addr_type(daddr);
+	if (__ipv6_addr_needs_scope_id(addr_type) && !iif)
+		return -EINVAL;
+	if (addr_type & IPV6_ADDR_MAPPED)
+		return -EINVAL;
+
+	/* TODO: use ip6_datagram_send_ctl to get options from cmsg */
+
+	memset(&fl6, 0, sizeof(fl6));
+
+	fl6.flowi6_proto = IPPROTO_ICMPV6;
+	fl6.saddr = np->saddr;
+	fl6.daddr = *daddr;
+	fl6.fl6_icmp_type = user_icmph.icmp6_type;
+	fl6.fl6_icmp_code = user_icmph.icmp6_code;
+	security_sk_classify_flow(sk, flowi6_to_flowi(&fl6));
+
+	if (!fl6.flowi6_oif && ipv6_addr_is_multicast(&fl6.daddr))
+		fl6.flowi6_oif = np->mcast_oif;
+	else if (!fl6.flowi6_oif)
+		fl6.flowi6_oif = np->ucast_oif;
+
+	dst = ip6_sk_dst_lookup_flow(sk, &fl6,  daddr, 1);
+	if (IS_ERR(dst))
+		return PTR_ERR(dst);
+	rt = (struct rt6_info *) dst;
+
+	np = inet6_sk(sk);
+	if (!np)
+		return -EBADF;
+
+	if (!fl6.flowi6_oif && ipv6_addr_is_multicast(&fl6.daddr))
+		fl6.flowi6_oif = np->mcast_oif;
+	else if (!fl6.flowi6_oif)
+		fl6.flowi6_oif = np->ucast_oif;
+
+	pfh.icmph.type = user_icmph.icmp6_type;
+	pfh.icmph.code = user_icmph.icmp6_code;
+	pfh.icmph.checksum = 0;
+	pfh.icmph.un.echo.id = inet->inet_sport;
+	pfh.icmph.un.echo.sequence = user_icmph.icmp6_sequence;
+	pfh.iov = msg->msg_iov;
+	pfh.wcheck = 0;
+	pfh.family = AF_INET6;
+
+	if (ipv6_addr_is_multicast(&fl6.daddr))
+		hlimit = np->mcast_hops;
+	else
+		hlimit = np->hop_limit;
+	if (hlimit < 0)
+		hlimit = ip6_dst_hoplimit(dst);
+
+	lock_sock(sk);
+	err = ip6_append_data(sk, ping_getfrag, &pfh, len,
+			      0, hlimit,
+			      np->tclass, NULL, &fl6, rt,
+			      MSG_DONTWAIT, np->dontfrag);
+
+	if (err) {
+		ICMP6_INC_STATS_BH(sock_net(sk), rt->rt6i_idev,
+				   ICMP6_MIB_OUTERRORS);
+		ip6_flush_pending_frames(sk);
+	} else {
+		err = icmpv6_push_pending_frames(sk, &fl6,
+						 (struct icmp6hdr *) &pfh.icmph,
+						 len);
+	}
+	release_sock(sk);
+
+	if (err)
+		return err;
+
+	return len;
+}
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/netfilter/x_tables.c b/net/netfilter/x_tables.c
index 8d987c3..5888e00 100644
--- a/net/netfilter/x_tables.c
+++ b/net/netfilter/x_tables.c
@@ -832,8 +832,13 @@
 		return NULL;
 	}
 
-	table->private = newinfo;
 	newinfo->initial_entries = private->initial_entries;
+	/*
+	 * Ensure contents of newinfo are visible before assigning to
+	 * private.
+	 */
+	smp_wmb();
+	table->private = newinfo;
 
 	/*
 	 * Even though table entries have now been swapped, other CPU's
diff --git a/net/wireless/core.h b/net/wireless/core.h
index 036faee..2e85324 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -69,9 +69,7 @@
 
 	struct mutex sched_scan_mtx;
 
-#ifdef CONFIG_NL80211_TESTMODE
-	struct genl_info *testmode_info;
-#endif
+	struct genl_info *cur_cmd_info;
 
 	struct work_struct conn_work;
 	struct work_struct event_work;
diff --git a/net/wireless/db.txt b/net/wireless/db.txt
index b1efe57..6a77ffc 100644
--- a/net/wireless/db.txt
+++ b/net/wireless/db.txt
@@ -14,19 +14,11 @@
 	(57240 - 63720 @ 2160), (N/A, 0)
 
 
-country AD:
-	(2402 - 2482 @ 40), (N/A, 20)
-	(5170 - 5250 @ 80), (N/A, 20)
-	(5250 - 5330 @ 80), (N/A, 20), DFS
-	(5490 - 5710 @ 80), (N/A, 27), DFS
-	# 60 gHz band channels 1-4, ref: Etsi En 302 567
-	(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
-
 country AE:
 	(2402 - 2482 @ 40), (N/A, 20)
 	(5170 - 5250 @ 80), (3, 17)
 	(5250 - 5330 @ 80), (3, 24), DFS
-	(5490 - 5710 @ 80), (3, 24), DFS
+	(5490 - 5730 @ 80), (3, 24), DFS
 	(5735 - 5835 @ 80), (3, 30)
 
 country AL:
@@ -50,7 +42,7 @@
 	(2402 - 2482 @ 40), (N/A, 20)
 	(5170 - 5250 @ 80), (3, 17)
 	(5250 - 5330 @ 80), (3, 24), DFS
-	(5490 - 5710 @ 80), (3, 24), DFS
+	(5490 - 5730 @ 80), (3, 24), DFS
 	(5735 - 5835 @ 80), (3, 30)
 
 country AS:
@@ -72,7 +64,7 @@
 	(2402 - 2482 @ 40), (N/A, 20)
 	(5170 - 5250 @ 80), (3, 17)
 	(5250 - 5330 @ 80), (3, 24), DFS
-	(5490 - 5710 @ 80), (3, 24), DFS
+	(5490 - 5730 @ 80), (3, 24), DFS
 	(5735 - 5835 @ 80), (3, 30)
 
 country AW:
@@ -126,11 +118,6 @@
 	(5250 - 5330 @ 20), (N/A, 20), DFS
 	(5735 - 5835 @ 20), (N/A, 20)
 
-country BL:
-	(2402 - 2482 @ 40), (N/A, 20)
-	(5170 - 5250 @ 40), (N/A, 18)
-	(5250 - 5330 @ 40), (N/A, 18), DFS
-
 country BM:
 	(2402 - 2472 @ 40), (N/A, 30)
 	(5150 - 5250 @ 80), (6, 17)
@@ -152,7 +139,7 @@
 	(2402 - 2482 @ 40), (N/A, 20)
 	(5170 - 5250 @ 80), (3, 17)
 	(5250 - 5330 @ 80), (3, 24), DFS
-	(5490 - 5710 @ 80), (3, 24), DFS
+	(5490 - 5730 @ 80), (3, 24), DFS
 	(5735 - 5835 @ 80), (3, 30)
 
 country BS:
@@ -176,7 +163,7 @@
 	(2402 - 2472 @ 40), (N/A, 27)
 	(5170 - 5250 @ 80), (3, 17)
 	(5250 - 5330 @ 80), (3, 24), DFS
-	(5490 - 5710 @ 80), (3, 24), DFS
+	(5490 - 5730 @ 80), (3, 24), DFS
 	(5735 - 5835 @ 80), (3, 30)
 
 country CH: DFS-ETSI
@@ -209,14 +196,14 @@
 	(2402 - 2472 @ 40), (N/A, 27)
 	(5170 - 5250 @ 80), (3, 17)
 	(5250 - 5330 @ 80), (3, 24), DFS
-	(5490 - 5710 @ 80), (3, 24), DFS
+	(5490 - 5730 @ 80), (3, 24), DFS
 	(5735 - 5835 @ 80), (3, 30)
 
 country CR:
 	(2402 - 2482 @ 40), (N/A, 20)
 	(5170 - 5250 @ 20), (3, 17)
 	(5250 - 5330 @ 20), (3, 24), DFS
-	(5490 - 5710 @ 20), (3, 24), DFS
+	(5490 - 5730 @ 20), (3, 24), DFS
 	(5735 - 5835 @ 20), (3, 30)
 
 country CY: DFS-ETSI
@@ -279,12 +266,15 @@
 
 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)
 	(5170 - 5250 @ 20), (3, 17)
 	(5250 - 5330 @ 20), (3, 24), DFS
-	(5490 - 5710 @ 20), (3, 24), DFS
+	(5490 - 5730 @ 20), (3, 24), DFS
 	(5735 - 5835 @ 20), (3, 30)
 
 country EE: DFS-ETSI
@@ -308,6 +298,12 @@
 	# 60 gHz band channels 1-4, ref: Etsi En 302 567
 	(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
 
+country ET: DFS-ETSI
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 80), (N/A, 20)
+	(5250 - 5330 @ 80), (N/A, 20), DFS
+	(5490 - 5710 @ 80), (N/A, 27), DFS
+
 country FI: DFS-ETSI
 	(2402 - 2482 @ 40), (N/A, 20)
 	(5170 - 5250 @ 80), (N/A, 20)
@@ -349,7 +345,7 @@
 	(2402 - 2472 @ 40), (3, 30)
 	(5170 - 5250 @ 80), (6, 17)
 	(5250 - 5330 @ 80), (6, 24), DFS
-	(5490 - 5710 @ 80), (6, 24), DFS
+	(5490 - 5730 @ 80), (6, 24), DFS
 	(5735 - 5835 @ 80), (6, 30)
 
 country GP:
@@ -382,21 +378,21 @@
 	(2402 - 2472 @ 40), (3, 30)
 	(5170 - 5250 @ 20), (6, 17)
 	(5250 - 5330 @ 20), (6, 24), DFS
-	(5490 - 5710 @ 20), (6, 24), DFS
+	(5490 - 5730 @ 20), (6, 24), DFS
 	(5735 - 5835 @ 20), (6, 30)
 
 country HN:
 	(2402 - 2482 @ 40), (N/A, 20)
 	(5170 - 5250 @ 80), (6, 17)
 	(5250 - 5330 @ 80), (6, 24), DFS
-	(5490 - 5710 @ 80), (6, 24), DFS
+	(5490 - 5730 @ 80), (6, 24), DFS
 	(5735 - 5835 @ 80), (6, 30)
 
 country HK:
 	(2402 - 2482 @ 40), (N/A, 20)
 	(5170 - 5250 @ 80), (6, 17)
 	(5250 - 5330 @ 80), (6, 24), DFS
-	(5490 - 5710 @ 80), (6, 24), DFS
+	(5490 - 5730 @ 80), (6, 24), DFS
 	(5735 - 5835 @ 80), (6, 30)
 
 country HR: DFS-ETSI
@@ -423,8 +419,8 @@
 
 country ID:
 	# ref: http://www.postel.go.id/content/ID/regulasi/standardisasi/kepdir/bwa%205,8%20ghz.pdf
-	(2402 - 2482 @ 40), (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)
@@ -469,7 +465,7 @@
 	(2402 - 2482 @ 40), (N/A, 20)
 	(5170 - 5250 @ 80), (6, 17)
 	(5250 - 5330 @ 80), (6, 24), DFS
-	(5490 - 5710 @ 80), (6, 24), DFS
+	(5490 - 5730 @ 80), (6, 24), DFS
 	(5735 - 5835 @ 80), (6, 30)
 
 country JP:
@@ -498,6 +494,13 @@
 	(5250 - 5330 @ 80), (N/A, 20), DFS
 	(5490 - 5710 @ 80), (N/A, 27), DFS
 
+country KY:
+        (2402 - 2472 @ 40), (N/A, 27)
+	(5170 - 5250 @ 80), (3, 17)
+	(5250 - 5330 @ 80), (3, 24), DFS
+	(5490 - 5730 @ 80), (3, 24), DFS
+	(5735 - 5835 @ 80), (3, 30)
+
 country KP:
 	(2402 - 2482 @ 20), (N/A, 20)
 	(5170 - 5330 @ 20), (6, 20)
@@ -537,7 +540,7 @@
 	(2402 - 2482 @ 40), (N/A, 20)
 	(5170 - 5250 @ 20), (3, 17)
 	(5250 - 5330 @ 20), (3, 20), DFS
-	(5490 - 5710 @ 20), (3, 20), DFS
+	(5490 - 5730 @ 20), (3, 20), DFS
 	(5735 - 5835 @ 20), (3, 30)
 
 country LT: DFS-ETSI
@@ -634,7 +637,7 @@
 	(2402 - 2472 @ 40), (3, 27)
 	(5170 - 5250 @ 80), (3, 17)
 	(5250 - 5330 @ 80), (3, 24), DFS
-	(5490 - 5710 @ 80), (3, 24), DFS
+	(5490 - 5730 @ 80), (3, 24), DFS
 	(5735 - 5835 @ 80), (3, 30)
 
 country MW:
@@ -681,7 +684,7 @@
 	(2402 - 2482 @ 40), (N/A, 30)
 	(5170 - 5250 @ 80), (6, 17)
 	(5250 - 5330 @ 80), (6, 24), DFS
-	(5490 - 5710 @ 80), (6, 24), DFS
+	(5490 - 5730 @ 80), (6, 24), DFS
 	(5735 - 5835 @ 80), (6, 30)
 
 country OM:
@@ -700,7 +703,7 @@
 	(2402 - 2482 @ 40), (N/A, 20)
 	(5170 - 5250 @ 80), (6, 20)
 	(5250 - 5330 @ 80), (6, 20), DFS
-	(5490 - 5710 @ 80), (6, 27), DFS
+	(5490 - 5730 @ 80), (6, 27), DFS
 	(5735 - 5835 @ 80), (6, 30)
 
 country PF:
@@ -720,7 +723,7 @@
 	(2402 - 2482 @ 40), (N/A, 20)
 	(5170 - 5250 @ 80), (6, 17)
 	(5250 - 5330 @ 80), (6, 24), DFS
-	(5490 - 5710 @ 80), (6, 24), DFS
+	(5490 - 5730 @ 80), (6, 24), DFS
 	(5735 - 5835 @ 80), (6, 30)
 
 country PK:
@@ -747,7 +750,7 @@
 	(2402 - 2472 @ 40), (3, 30)
 	(5170 - 5250 @ 80), (6, 17)
 	(5250 - 5330 @ 80), (6, 24), DFS
-	(5490 - 5710 @ 80), (6, 24), DFS
+	(5490 - 5730 @ 80), (6, 24), DFS
 	(5735 - 5835 @ 80), (6, 30)
 
 country PY:
@@ -819,7 +822,7 @@
 	(2402 - 2482 @ 40), (N/A, 20)
 	(5170 - 5250 @ 80), (6, 17)
 	(5250 - 5330 @ 80), (6, 24), DFS
-	(5490 - 5710 @ 80), (6, 24), DFS
+	(5490 - 5730 @ 80), (6, 24), DFS
 	(5735 - 5835 @ 80), (6, 30)
 
 country SI: DFS-ETSI
@@ -838,6 +841,12 @@
 	# 60 gHz band channels 1-4, ref: Etsi En 302 567
 	(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
 
+country SR: DFS-ETSI
+	(2400 - 2483.5 @ 40), (N/A, 100 mW)
+	(5150 - 5250 @ 80), (N/A, 100 mW), NO-OUTDOOR
+	(5250 - 5350 @ 80), (N/A, 100 mW), NO-OUTDOOR, DFS
+	(5470 - 5725 @ 80), (N/A, 500 mW), DFS
+
 country SV:
 	(2402 - 2482 @ 40), (N/A, 20)
 	(5170 - 5250 @ 20), (3, 17)
@@ -849,22 +858,22 @@
 
 country TW:
 	(2402 - 2472 @ 40), (3, 27)
-	(5270 - 5330 @ 80), (6, 17), DFS
-	(5490 - 5710 @ 80), (6, 30), DFS
+	(5270 - 5330 @ 40), (6, 17), DFS
+	(5490 - 5730 @ 80), (6, 30), DFS
 	(5735 - 5815 @ 80), (6, 30)
 
 country TH:
 	(2402 - 2482 @ 40), (N/A, 20)
 	(5170 - 5250 @ 80), (3, 17)
 	(5250 - 5330 @ 80), (3, 24), DFS
-	(5490 - 5710 @ 80), (3, 24), DFS
+	(5490 - 5730 @ 80), (3, 24), DFS
 	(5735 - 5835 @ 80), (3, 30)
 
 country TT:
 	(2402 - 2482 @ 40), (N/A, 20)
 	(5170 - 5250 @ 40), (3, 17)
 	(5250 - 5330 @ 40), (3, 20), DFS
-	(5490 - 5710 @ 40), (3, 20), DFS
+	(5490 - 5730 @ 40), (3, 20), DFS
 	(5735 - 5835 @ 40), (3, 30)
 
 country TN:
@@ -908,7 +917,7 @@
 	(5170 - 5250 @ 80), (3, 17)
 	(5250 - 5330 @ 80), (3, 24), DFS
 	(5490 - 5600 @ 80), (3, 24), DFS
-	(5650 - 5710 @ 40), (3, 24), DFS
+	(5650 - 5730 @ 40), (3, 24), DFS
 	(5735 - 5835 @ 80), (3, 30)
 	# 60g band
 	# reference: http://cfr.regstoday.com/47cfr15.aspx#47_CFR_15p255
@@ -929,14 +938,14 @@
 	(2402 - 2482 @ 40), (N/A, 20)
 	(5170 - 5250 @ 40), (3, 17)
 	(5250 - 5330 @ 40), (3, 20), DFS
-	(5490 - 5710 @ 40), (3, 20), DFS
+	(5490 - 5730 @ 40), (3, 20), DFS
 	(5735 - 5835 @ 40), (3, 30)
 
 country UZ:
 	(2402 - 2472 @ 40), (3, 27)
 	(5170 - 5250 @ 40), (3, 17)
 	(5250 - 5330 @ 40), (3, 20), DFS
-	(5490 - 5710 @ 40), (3, 20), DFS
+	(5490 - 5730 @ 40), (3, 20), DFS
 	(5735 - 5835 @ 40), (3, 30)
 
 country VE:
@@ -950,7 +959,7 @@
 	(2402 - 2482 @ 40), (N/A, 20)
 	(5170 - 5250 @ 80), (3, 17)
 	(5250 - 5330 @ 80), (3, 24), DFS
-	(5490 - 5710 @ 80), (3, 24), DFS
+	(5490 - 5730 @ 80), (3, 24), DFS
 	(5735 - 5835 @ 80), (3, 30)
 
 country VI:
@@ -960,6 +969,12 @@
 	(5470 - 5725 @ 80), (6, 24), DFS
 	(5725 - 5850 @ 80), (6, 30)
 
+country WS: DFS-ETSI
+	(2402 - 2482 @ 40), (N/A, 20)
+	(5170 - 5250 @ 20), (3, 17)
+	(5250 - 5330 @ 80), (3, 24), DFS
+	(5490 - 5710 @ 80), (3, 24), DFS
+
 country YE:
 	(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 7db02f3..c3adef8 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -223,6 +223,25 @@
 	[NL80211_ATTR_IE_RIC] = { .type = NLA_BINARY,
 				  .len = IEEE80211_MAX_DATA_LEN },
 	[NL80211_ATTR_PEER_AID] = { .type = NLA_U16 },
+	[NL80211_ATTR_STA_SUPPORTED_CHANNELS] = { .type = NLA_BINARY },
+	[NL80211_ATTR_STA_SUPPORTED_OPER_CLASSES] = { .type = NLA_BINARY },
+	[NL80211_ATTR_CH_SWITCH_COUNT] = { .type = NLA_U32 },
+	[NL80211_ATTR_CH_SWITCH_BLOCK_TX] = { .type = NLA_FLAG },
+	[NL80211_ATTR_CSA_IES] = { .type = NLA_NESTED },
+	[NL80211_ATTR_CSA_C_OFF_BEACON] = { .type = NLA_U16 },
+	[NL80211_ATTR_CSA_C_OFF_PRESP] = { .type = NLA_U16 },
+	[NL80211_ATTR_STA_SUPPORTED_CHANNELS] = { .type = NLA_BINARY },
+	[NL80211_ATTR_STA_SUPPORTED_OPER_CLASSES] = { .type = NLA_BINARY },
+	[NL80211_ATTR_HANDLE_DFS] = { .type = NLA_FLAG },
+	[NL80211_ATTR_OPMODE_NOTIF] = { .type = NLA_U8 },
+	[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 */
@@ -936,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);
@@ -1074,6 +1094,44 @@
 		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;
+
+		nested = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA);
+		if (!nested)
+			goto nla_put_failure;
+
+		for (i = 0; i < dev->wiphy.n_vendor_commands; i++) {
+			info = &dev->wiphy.vendor_commands[i].info;
+			if (nla_put(msg, i + 1, sizeof(*info), info))
+				goto nla_put_failure;
+			}
+			nla_nest_end(msg, nested);
+	}
+
+	if (dev->wiphy.n_vendor_events) {
+		const struct nl80211_vendor_cmd_info *info;
+		struct nlattr *nested;
+
+		nested = nla_nest_start(msg,
+			NL80211_ATTR_VENDOR_EVENTS);
+		if (!nested)
+			goto nla_put_failure;
+
+		for (i = 0; i < dev->wiphy.n_vendor_events; i++) {
+			info = &dev->wiphy.vendor_events[i];
+			if (nla_put(msg, i + 1, sizeof(*info), info))
+				goto nla_put_failure;
+		}
+		nla_nest_end(msg, nested);
+	}
+
 	return genlmsg_end(msg, hdr);
 
  nla_put_failure:
@@ -2774,6 +2832,41 @@
 	return ERR_PTR(ret);
 }
 
+static int nl80211_parse_sta_channel_info(struct genl_info *info,
+				      struct station_parameters *params)
+{
+	if (info->attrs[NL80211_ATTR_STA_SUPPORTED_CHANNELS]) {
+		params->supported_channels =
+		     nla_data(info->attrs[NL80211_ATTR_STA_SUPPORTED_CHANNELS]);
+		params->supported_channels_len =
+		     nla_len(info->attrs[NL80211_ATTR_STA_SUPPORTED_CHANNELS]);
+		/*
+		 * Need to include at least one (first channel, number of
+		 * channels) tuple for each subband, and must have proper
+		 * tuples for the rest of the data as well.
+		 */
+		if (params->supported_channels_len < 2)
+			return -EINVAL;
+		if (params->supported_channels_len % 2)
+			return -EINVAL;
+	}
+
+	if (info->attrs[NL80211_ATTR_STA_SUPPORTED_OPER_CLASSES]) {
+		params->supported_oper_classes =
+		 nla_data(info->attrs[NL80211_ATTR_STA_SUPPORTED_OPER_CLASSES]);
+		params->supported_oper_classes_len =
+		  nla_len(info->attrs[NL80211_ATTR_STA_SUPPORTED_OPER_CLASSES]);
+		/*
+		 * The value of the Length field of the Supported Operating
+		 * Classes element is between 2 and 253.
+		 */
+		if (params->supported_oper_classes_len < 2 ||
+		    params->supported_oper_classes_len > 253)
+			return -EINVAL;
+	}
+	return 0;
+}
+
 static struct nla_policy
 nl80211_sta_wme_policy[NL80211_STA_WME_MAX + 1] __read_mostly = {
 	[NL80211_STA_WME_UAPSD_QUEUES] = { .type = NLA_U8 },
@@ -2797,6 +2890,10 @@
 		params->vht_capa =
 			nla_data(info->attrs[NL80211_ATTR_VHT_CAPABILITY]);
 
+	err = nl80211_parse_sta_channel_info(info, params);
+	if (err)
+		return err;
+
 	/* parse WME attributes if present */
 	if (!info->attrs[NL80211_ATTR_STA_WME])
 		return 0;
@@ -3063,6 +3160,10 @@
 		params.plink_action =
 		    nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_ACTION]);
 
+	err = nl80211_parse_sta_channel_info(info, &params);
+	if (err)
+		return err;
+
 	if (!rdev->ops->add_station)
 		return -EOPNOTSUPP;
 
@@ -5166,6 +5267,57 @@
 	return cfg80211_leave_ibss(rdev, dev, false);
 }
 
+static struct sk_buff *
+__cfg80211_alloc_vendor_skb(struct cfg80211_registered_device *rdev,
+			    int approxlen, u32 portid, u32 seq,
+			    enum nl80211_commands cmd,
+			    enum nl80211_attrs attr,
+			    const struct nl80211_vendor_cmd_info *info,
+			    gfp_t gfp)
+{
+	struct sk_buff *skb;
+	void *hdr;
+	struct nlattr *data;
+
+	skb = nlmsg_new(approxlen + 100, gfp);
+	if (!skb)
+		return NULL;
+
+	hdr = nl80211hdr_put(skb, portid, seq, 0, cmd);
+	if (!hdr) {
+		kfree_skb(skb);
+		return NULL;
+	}
+
+	if (nla_put_u32(skb, NL80211_ATTR_WIPHY, rdev->wiphy_idx))
+		goto nla_put_failure;
+
+	if (info) {
+		if (nla_put_u32(skb, NL80211_ATTR_VENDOR_ID,
+				info->vendor_id))
+			goto nla_put_failure;
+		if (nla_put_u32(skb, NL80211_ATTR_VENDOR_SUBCMD,
+				info->subcmd))
+			goto nla_put_failure;
+	}
+
+	data = nla_nest_start(skb, attr);
+
+	((void **)skb->cb)[0] = rdev;
+	((void **)skb->cb)[1] = hdr;
+	((void **)skb->cb)[2] = data;
+
+	return skb;
+
+ nla_put_failure:
+	kfree_skb(skb);
+	return NULL;
+}
+
+static struct genl_multicast_group nl80211_vendor_mcgrp = {
+	.name = "vendor",
+};
+
 #ifdef CONFIG_NL80211_TESTMODE
 static struct genl_multicast_group nl80211_testmode_mcgrp = {
 	.name = "testmode",
@@ -5181,11 +5333,11 @@
 
 	err = -EOPNOTSUPP;
 	if (rdev->ops->testmode_cmd) {
-		rdev->testmode_info = info;
+		rdev->cur_cmd_info = info;
 		err = rdev->ops->testmode_cmd(&rdev->wiphy,
 				nla_data(info->attrs[NL80211_ATTR_TESTDATA]),
 				nla_len(info->attrs[NL80211_ATTR_TESTDATA]));
-		rdev->testmode_info = NULL;
+		rdev->cur_cmd_info = NULL;
 	}
 
 	return err;
@@ -5290,90 +5442,56 @@
 	return err;
 }
 
-static struct sk_buff *
-__cfg80211_testmode_alloc_skb(struct cfg80211_registered_device *rdev,
-			      int approxlen, u32 pid, u32 seq, gfp_t gfp)
-{
-	struct sk_buff *skb;
-	void *hdr;
-	struct nlattr *data;
+#endif
 
-	skb = nlmsg_new(approxlen + 100, gfp);
-	if (!skb)
-		return NULL;
-
-	hdr = nl80211hdr_put(skb, pid, seq, 0, NL80211_CMD_TESTMODE);
-	if (!hdr) {
-		kfree_skb(skb);
-		return NULL;
-	}
-
-	NLA_PUT_U32(skb, NL80211_ATTR_WIPHY, rdev->wiphy_idx);
-	data = nla_nest_start(skb, NL80211_ATTR_TESTDATA);
-
-	((void **)skb->cb)[0] = rdev;
-	((void **)skb->cb)[1] = hdr;
-	((void **)skb->cb)[2] = data;
-
-	return skb;
-
- nla_put_failure:
-	kfree_skb(skb);
-	return NULL;
-}
-
-struct sk_buff *cfg80211_testmode_alloc_reply_skb(struct wiphy *wiphy,
-						  int approxlen)
+struct sk_buff *__cfg80211_alloc_event_skb(struct wiphy *wiphy,
+					   enum nl80211_commands cmd,
+					   enum nl80211_attrs attr,
+					   int vendor_event_idx,
+					   int approxlen, gfp_t gfp)
 {
 	struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
+	const struct nl80211_vendor_cmd_info *info;
 
-	if (WARN_ON(!rdev->testmode_info))
+	switch (cmd) {
+	case NL80211_CMD_TESTMODE:
+		if (WARN_ON(vendor_event_idx != -1))
+			return NULL;
+		info = NULL;
+		break;
+	case NL80211_CMD_VENDOR:
+		if (WARN_ON(vendor_event_idx < 0 ||
+			    vendor_event_idx >= wiphy->n_vendor_events))
+			return NULL;
+		info = &wiphy->vendor_events[vendor_event_idx];
+		break;
+	default:
+		WARN_ON(1);
 		return NULL;
-
-	return __cfg80211_testmode_alloc_skb(rdev, approxlen,
-				rdev->testmode_info->snd_pid,
-				rdev->testmode_info->snd_seq,
-				GFP_KERNEL);
+	}
+	return __cfg80211_alloc_vendor_skb(rdev, approxlen, 0, 0,
+					   cmd, attr, info, gfp);
 }
-EXPORT_SYMBOL(cfg80211_testmode_alloc_reply_skb);
+EXPORT_SYMBOL(__cfg80211_alloc_event_skb);
 
-int cfg80211_testmode_reply(struct sk_buff *skb)
+void __cfg80211_send_event_skb(struct sk_buff *skb, gfp_t gfp)
 {
 	struct cfg80211_registered_device *rdev = ((void **)skb->cb)[0];
 	void *hdr = ((void **)skb->cb)[1];
 	struct nlattr *data = ((void **)skb->cb)[2];
 
-	if (WARN_ON(!rdev->testmode_info)) {
-		kfree_skb(skb);
-		return -EINVAL;
-	}
-
 	nla_nest_end(skb, data);
 	genlmsg_end(skb, hdr);
-	return genlmsg_reply(skb, rdev->testmode_info);
+
+	if (data->nla_type == NL80211_ATTR_VENDOR_DATA)
+		genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), skb, 0,
+			nl80211_vendor_mcgrp.id, gfp);
+	else
+		genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), skb, 0,
+			nl80211_testmode_mcgrp.id, gfp);
 }
-EXPORT_SYMBOL(cfg80211_testmode_reply);
+EXPORT_SYMBOL(__cfg80211_send_event_skb);
 
-struct sk_buff *cfg80211_testmode_alloc_event_skb(struct wiphy *wiphy,
-						  int approxlen, gfp_t gfp)
-{
-	struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
-
-	return __cfg80211_testmode_alloc_skb(rdev, approxlen, 0, 0, gfp);
-}
-EXPORT_SYMBOL(cfg80211_testmode_alloc_event_skb);
-
-void cfg80211_testmode_event(struct sk_buff *skb, gfp_t gfp)
-{
-	void *hdr = ((void **)skb->cb)[1];
-	struct nlattr *data = ((void **)skb->cb)[2];
-
-	nla_nest_end(skb, data);
-	genlmsg_end(skb, hdr);
-	genlmsg_multicast(skb, 0, nl80211_testmode_mcgrp.id, gfp);
-}
-EXPORT_SYMBOL(cfg80211_testmode_event);
-#endif
 
 static int nl80211_connect(struct sk_buff *skb, struct genl_info *info)
 {
@@ -5423,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]);
 
@@ -5447,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]) {
@@ -5586,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;
 
@@ -5604,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]));
 }
@@ -6590,6 +6723,156 @@
 	return rdev->ops->update_ft_ies(&rdev->wiphy, dev, &ft_params);
 }
 
+static int nl80211_vendor_cmd(struct sk_buff *skb, struct genl_info *info)
+{
+	struct cfg80211_registered_device *rdev = info->user_ptr[0];
+	struct net_device *dev = info->user_ptr[1];
+	struct wireless_dev *wdev = dev->ieee80211_ptr;
+	int i, err;
+	u32 vid, subcmd;
+
+	if (!rdev->wiphy.vendor_commands)
+		return -EOPNOTSUPP;
+
+	if (IS_ERR(wdev)) {
+		err = PTR_ERR(wdev);
+		if (err != -EINVAL)
+			return err;
+		wdev = NULL;
+	} else if (wdev->wiphy != &rdev->wiphy) {
+		return -EINVAL;
+	}
+
+	if (!info->attrs[NL80211_ATTR_VENDOR_ID] ||
+	    !info->attrs[NL80211_ATTR_VENDOR_SUBCMD])
+		return -EINVAL;
+
+	vid = nla_get_u32(info->attrs[NL80211_ATTR_VENDOR_ID]);
+	subcmd = nla_get_u32(info->attrs[NL80211_ATTR_VENDOR_SUBCMD]);
+	for (i = 0; i < rdev->wiphy.n_vendor_commands; i++) {
+		const struct wiphy_vendor_command *vcmd;
+		void *data = NULL;
+		int len = 0;
+
+		vcmd = &rdev->wiphy.vendor_commands[i];
+
+		if (vcmd->info.vendor_id != vid || vcmd->info.subcmd != subcmd)
+			continue;
+
+		if (vcmd->flags & (WIPHY_VENDOR_CMD_NEED_WDEV |
+				   WIPHY_VENDOR_CMD_NEED_NETDEV)) {
+			if (!wdev)
+				return -EINVAL;
+			if (vcmd->flags & WIPHY_VENDOR_CMD_NEED_NETDEV &&
+			    !wdev->netdev)
+				return -EINVAL;
+
+			if (vcmd->flags & WIPHY_VENDOR_CMD_NEED_RUNNING) {
+				if (wdev->netdev &&
+				    !netif_running(wdev->netdev))
+					return -ENETDOWN;
+			}
+		} else {
+			wdev = NULL;
+		}
+
+		if (info->attrs[NL80211_ATTR_VENDOR_DATA]) {
+			data = nla_data(info->attrs[NL80211_ATTR_VENDOR_DATA]);
+			len = nla_len(info->attrs[NL80211_ATTR_VENDOR_DATA]);
+		}
+
+		return rdev->wiphy.vendor_commands[i].doit(&rdev->wiphy, wdev,
+							   data, len);
+	}
+
+	return -EOPNOTSUPP;
+}
+
+struct sk_buff *__cfg80211_alloc_reply_skb(struct wiphy *wiphy,
+					   enum nl80211_commands cmd,
+					   enum nl80211_attrs attr,
+					   int approxlen)
+{
+	struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
+
+	if (WARN_ON(!rdev->cur_cmd_info))
+		return NULL;
+
+	return __cfg80211_alloc_vendor_skb(rdev, approxlen,
+					   0,
+					   0,
+					   cmd, attr, NULL, GFP_KERNEL);
+}
+EXPORT_SYMBOL(__cfg80211_alloc_reply_skb);
+
+int cfg80211_vendor_cmd_reply(struct sk_buff *skb)
+{
+	struct cfg80211_registered_device *rdev = ((void **)skb->cb)[0];
+	void *hdr = ((void **)skb->cb)[1];
+	struct nlattr *data = ((void **)skb->cb)[2];
+
+	if (WARN_ON(!rdev->cur_cmd_info)) {
+		kfree_skb(skb);
+		return -EINVAL;
+	}
+
+	nla_nest_end(skb, data);
+	genlmsg_end(skb, hdr);
+	return genlmsg_reply(skb, rdev->cur_cmd_info);
+}
+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
@@ -7194,7 +7477,22 @@
 		.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
 				  NL80211_FLAG_NEED_RTNL,
 	},
-
+	{
+		.cmd = NL80211_CMD_VENDOR,
+		.doit = nl80211_vendor_cmd,
+		.policy = nl80211_policy,
+		.flags = GENL_ADMIN_PERM,
+		.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 = {
@@ -8517,6 +8815,9 @@
 	if (err)
 		goto err_out;
 #endif
+	err = genl_register_mc_group(&nl80211_fam, &nl80211_vendor_mcgrp);
+	if (err)
+		goto err_out;
 
 	err = netlink_register_notifier(&nl80211_netlink_notifier);
 	if (err)
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index b094741..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);
@@ -1184,7 +1195,10 @@
 		       enum nl80211_reg_initiator setby)
 {
 	mutex_lock(&reg_mutex);
-	wiphy_update_regulatory(wiphy, setby);
+	if (last_request)
+		wiphy_update_regulatory(wiphy, last_request->initiator);
+	else
+		wiphy_update_regulatory(wiphy, setby);
 	mutex_unlock(&reg_mutex);
 }
 
@@ -1378,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/scan.c b/net/wireless/scan.c
index 3adfe7f..e40104f 100644
--- a/net/wireless/scan.c
+++ b/net/wireless/scan.c
@@ -1014,8 +1014,6 @@
 		if (wreq->scan_type == IW_SCAN_TYPE_PASSIVE)
 			creq->n_ssids = 0;
 	}
-	for (i = 0; i < IEEE80211_NUM_BANDS; i++)
-		creq->rates[i] = (1 << wiphy->bands[i]->n_bitrates) - 1;
 
 	for (i = 0; i < IEEE80211_NUM_BANDS; i++)
 		if (wiphy->bands[i])
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/net/wireless/wext-core.c b/net/wireless/wext-core.c
old mode 100644
new mode 100755
index af648e0..120e0dc
--- a/net/wireless/wext-core.c
+++ b/net/wireless/wext-core.c
@@ -19,7 +19,9 @@
 #include <net/netlink.h>
 #include <net/wext.h>
 #include <net/net_namespace.h>
-
+#ifdef KW_TAINT_ANALYSIS
+       extern void * get_tainted_stuff();
+#endif
 typedef int (*wext_ioctl_func)(struct net_device *, struct iwreq *,
 			       unsigned int, struct iw_request_info *,
 			       iw_handler);
@@ -1006,8 +1008,13 @@
 
 
 int wext_handle_ioctl(struct net *net, struct ifreq *ifr, unsigned int cmd,
-		      void __user *arg)
+		      void __user *arg_actual)
 {
+	#ifdef KW_TAINT_ANALYSIS
+	void __user *arg = (void __user *)get_tainted_stuff();
+	#else	
+	void __user *arg = (void __user *)arg_actual;
+	#endif
 	struct iw_request_info info = { .cmd = cmd, .flags = 0 };
 	int ret;
 
@@ -1056,7 +1063,11 @@
 int compat_wext_handle_ioctl(struct net *net, unsigned int cmd,
 			     unsigned long arg)
 {
+	#ifdef KW_TAINT_ANALYSIS
+	void __user *argp = (void __user *)get_tainted_stuff();
+	#else
 	void __user *argp = (void __user *)arg;
+	#endif	
 	struct iw_request_info info;
 	struct iwreq iwr;
 	char *colon;
diff --git a/net/x25/af_x25.c b/net/x25/af_x25.c
old mode 100644
new mode 100755
index a306bc6..c143046
--- a/net/x25/af_x25.c
+++ b/net/x25/af_x25.c
@@ -59,7 +59,9 @@
 
 #include <net/x25.h>
 #include <net/compat.h>
-
+#ifdef KW_TAINT_ANALYSIS
+   extern void * get_tainted_stuff();
+#endif
 int sysctl_x25_restart_request_timeout = X25_DEFAULT_T20;
 int sysctl_x25_call_request_timeout    = X25_DEFAULT_T21;
 int sysctl_x25_reset_request_timeout   = X25_DEFAULT_T22;
@@ -1625,7 +1627,7 @@
 
 #ifdef CONFIG_COMPAT
 static int compat_x25_subscr_ioctl(unsigned int cmd,
-		struct compat_x25_subscrip_struct __user *x25_subscr32)
+		struct compat_x25_subscrip_struct __user *x25_subscr32_actual)
 {
 	struct compat_x25_subscrip_struct x25_subscr;
 	struct x25_neigh *nb;
@@ -1633,6 +1635,11 @@
 	int rc = -EINVAL;
 
 	rc = -EFAULT;
+	#ifdef KW_TAINT_ANALYSIS
+	struct compat_x25_subscrip_struct __user *x25_subscr32 = (struct compat_x25_subscrip_struct __user *)get_tainted_stuff();
+	#else
+	struct compat_x25_subscrip_struct __user *x25_subscr32 = x25_subscr32_actual;
+	#endif
 	if (copy_from_user(&x25_subscr, x25_subscr32, sizeof(*x25_subscr32)))
 		goto out;
 
@@ -1675,7 +1682,11 @@
 static int compat_x25_ioctl(struct socket *sock, unsigned int cmd,
 				unsigned long arg)
 {
+	#ifdef KW_TAINT_ANALYSIS
+	void __user *argp = (void __user *)get_tainted_stuff();
+	#else
 	void __user *argp = compat_ptr(arg);
+	#endif	
 	struct sock *sk = sock->sk;
 
 	int rc = -ENOIOCTLCMD;
diff --git a/net/x25/x25_link.c b/net/x25/x25_link.c
old mode 100644
new mode 100755
index 4acacf3..c82fcc2
--- a/net/x25/x25_link.c
+++ b/net/x25/x25_link.c
@@ -31,6 +31,9 @@
 #include <linux/init.h>
 #include <net/x25.h>
 
+#ifdef KW_TAINT_ANALYSIS
+   extern void * get_tainted_stuff();
+#endif
 LIST_HEAD(x25_neigh_list);
 DEFINE_RWLOCK(x25_neigh_list_lock);
 
@@ -338,13 +341,17 @@
 /*
  *	Handle the ioctls that control the subscription functions.
  */
-int x25_subscr_ioctl(unsigned int cmd, void __user *arg)
+int x25_subscr_ioctl(unsigned int cmd, void __user *arg_actual)
 {
 	struct x25_subscrip_struct x25_subscr;
 	struct x25_neigh *nb;
 	struct net_device *dev;
 	int rc = -EINVAL;
-
+	#ifdef KW_TAINT_ANALYSIS
+	void __user *arg = (void __user *)get_tainted_stuff();
+	#else
+	void __user *arg = arg_actual;
+	#endif
 	if (cmd != SIOCX25GSUBSCRIP && cmd != SIOCX25SSUBSCRIP)
 		goto out;
 
diff --git a/net/x25/x25_route.c b/net/x25/x25_route.c
old mode 100644
new mode 100755
index cf63662..7a1778a
--- a/net/x25/x25_route.c
+++ b/net/x25/x25_route.c
@@ -21,7 +21,9 @@
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <net/x25.h>
-
+#ifdef KW_TAINT_ANALYSIS
+   extern void * get_tainted_stuff();
+#endif
 LIST_HEAD(x25_route_list);
 DEFINE_RWLOCK(x25_route_list_lock);
 
@@ -179,12 +181,16 @@
 /*
  *	Handle the ioctls that control the routing functions.
  */
-int x25_route_ioctl(unsigned int cmd, void __user *arg)
+int x25_route_ioctl(unsigned int cmd, void __user *arg_actual)
 {
 	struct x25_route_struct rt;
 	struct net_device *dev;
 	int rc = -EINVAL;
-
+	#ifdef KW_TAINT_ANALYSIS
+	void __user *arg = (void __user *)get_tainted_stuff();
+	#else
+	void __user *arg = arg_actual;
+	#endif
 	if (cmd != SIOCADDRT && cmd != SIOCDELRT)
 		goto out;
 
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index b28b7eb..c868a74 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -3816,6 +3816,11 @@
 	struct lsm_network_audit net = {0,};
 	u32 tsid = task_sid(task);
 
+	if (unlikely(!sksec)) {
+		pr_warn("SELinux: sksec is NULL, socket is already freed\n");
+		return -EINVAL;
+	}
+
 	if (sksec->sid == SECINITSID_KERNEL)
 		return 0;
 
diff --git a/sound/compress_offload/core.c b/sound/compress_offload/core.c
deleted file mode 100644
index 987594a..0000000
--- a/sound/compress_offload/core.c
+++ /dev/null
@@ -1,658 +0,0 @@
-/*
- *  core.c - compress offload core
- *
- *  Copyright (C) 2011 Intel Corporation
- *  Authors:	Vinod Koul <vinod.koul@linux.intel.com>
- *		Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
- *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; version 2 of the License.
- *
- *  This program is distributed in the hope that it will be useful, but
- *  WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- *  General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License along
- *  with this program; if not, write to the Free Software Foundation, Inc.,
- *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
- *
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- *
- */
-#include <linux/file.h>
-#include <linux/fs.h>
-#include <linux/list.h>
-#include <linux/miscdevice.h>
-#include <linux/mm.h>
-#include <linux/mutex.h>
-#include <linux/poll.h>
-#include <linux/slab.h>
-#include <linux/sched.h>
-#include <linux/uio.h>
-#include <linux/uaccess.h>
-#include <sound/snd_compress_params.h>
-#include <sound/compress_offload.h>
-#include <sound/compress_driver.h>
-
-/* TODO:
- * - Integrate with alsa, compressed devices should register as alsa devices
- *	as /dev/snd_compr_xxx
- * - Integrate with ASoC:
- *	Opening compressed path should also start the codec dai
- *   TBD how the cpu dai will be viewed and started.
- *	ASoC should always be optional part
- *	(we should be able to use this framework in non asoc systems
- * - Multiple node representation
- *	driver should be able to register multiple nodes
- * - Version numbering for API
- */
-
-static DEFINE_MUTEX(device_mutex);
-static LIST_HEAD(device_list);
-static LIST_HEAD(misc_list);
-
-/*
- * currently we are using misc device for registration and exposing ioctls
- * this is temporary and will be moved to snd
- * the device should be registered as /dev/snd_compr.....
- */
-
-struct snd_compr_misc {
-	struct miscdevice misc;
-	struct list_head list;
-	struct snd_compr *compr;
-};
-
-struct snd_ioctl_data {
-	struct snd_compr_misc *misc;
-	unsigned long caps;
-	unsigned int minor;
-	struct snd_compr_stream stream;
-};
-
-static struct snd_compr_misc *snd_compr_get_device(unsigned int minor)
-{
-	struct snd_compr_misc *misc;
-
-	list_for_each_entry(misc, &misc_list, list) {
-		if (minor == misc->misc.minor)
-			return misc;
-	}
-	return NULL;
-}
-
-static int snd_compr_open(struct inode *inode, struct file *f)
-{
-	unsigned int minor = iminor(inode);
-	struct snd_compr_misc *misc = snd_compr_get_device(minor);
-	struct snd_ioctl_data *data;
-	struct snd_compr_runtime *runtime;
-	unsigned int direction;
-	int ret;
-
-	mutex_lock(&device_mutex);
-	if (f->f_flags & O_WRONLY)
-		direction = SNDRV_PCM_STREAM_PLAYBACK;
-	else {
-		ret = -ENXIO;
-		goto out;
-	}
-	/* curently only encoded playback is supported, above needs to be
-	 * removed once we have recording support */
-
-	data = kzalloc(sizeof(*data), GFP_KERNEL);
-	if (!data) {
-		ret = -ENOMEM;
-		goto out;
-	}
-	data->misc = misc;
-	data->minor = minor;
-	data->stream.ops = misc->compr->ops;
-	data->stream.direction = direction;
-	data->stream.private_data = misc->compr->private_data;
-	data->stream.device = misc->compr;
-	runtime = kzalloc(sizeof(*runtime), GFP_KERNEL);
-	if (!runtime) {
-		ret = -ENOMEM;
-		kfree(data);
-		goto out;
-	}
-	runtime->state = SNDRV_PCM_STATE_OPEN;
-	init_waitqueue_head(&runtime->sleep);
-	data->stream.runtime = runtime;
-	f->private_data = (void *)data;
-	ret = misc->compr->ops->open(&data->stream);
-	if (ret) {
-		kfree(runtime);
-		kfree(data);
-		goto out;
-	}
-out:
-	mutex_unlock(&device_mutex);
-	return ret;
-}
-
-static int snd_compr_free(struct inode *inode, struct file *f)
-{
-	struct snd_ioctl_data *data = f->private_data;
-	mutex_lock(&device_mutex);
-	data->stream.ops->free(&data->stream);
-	kfree(data->stream.runtime->buffer);
-	kfree(data->stream.runtime);
-	kfree(data);
-	mutex_unlock(&device_mutex);
-	return 0;
-}
-
-static void snd_compr_update_tstamp(struct snd_compr_stream *stream,
-		struct snd_compr_tstamp *tstamp)
-{
-	stream->ops->pointer(stream, tstamp);
-	stream->runtime->hw_pointer = tstamp->copied_bytes;
-}
-
-static size_t snd_compr_calc_avail(struct snd_compr_stream *stream,
-		struct snd_compr_avail *avail)
-{
-	size_t avail_calc;
-
-	snd_compr_update_tstamp(stream, &avail->tstamp);
-	avail_calc = stream->runtime->app_pointer - stream->runtime->hw_pointer;
-	if (avail_calc < 0)
-		avail_calc = stream->runtime->buffer_size + avail_calc;
-	avail->avail = avail_calc;
-	return avail_calc;
-}
-
-static size_t snd_compr_get_avail(struct snd_compr_stream *stream)
-{
-	struct snd_compr_avail avail;
-
-	return snd_compr_calc_avail(stream, &avail);
-}
-
-static int
-snd_compr_ioctl_avail(struct snd_compr_stream *stream, unsigned long arg)
-{
-	struct snd_compr_avail ioctl_avail;
-
-	snd_compr_calc_avail(stream, &ioctl_avail);
-
-	if (copy_to_user((unsigned long __user *)arg, &ioctl_avail, sizeof(ioctl_avail)))
-		return -EFAULT;
-	return 0;
-}
-
-static int snd_compr_write_data(struct snd_compr_stream *stream,
-	       const char __user *buf, size_t count)
-{
-	void *dstn;
-	size_t copy;
-
-	dstn = stream->runtime->buffer + stream->runtime->app_pointer;
-	if (count < stream->runtime->buffer_size - stream->runtime->app_pointer) {
-		if (copy_from_user(dstn, buf, count))
-			return -EFAULT;
-		stream->runtime->app_pointer += count;
-	} else {
-		copy = stream->runtime->buffer_size - stream->runtime->app_pointer;
-		if (copy_from_user(dstn, buf, copy))
-			return -EFAULT;
-		if (copy_from_user(stream->runtime->buffer, buf + copy, count - copy))
-			return -EFAULT;
-		stream->runtime->app_pointer = count - copy;
-	}
-	/* if DSP cares, let it know data has been written */
-	if (stream->ops->ack)
-		stream->ops->ack(stream);
-	return count;
-}
-
-static ssize_t snd_compr_write(struct file *f, const char __user *buf,
-		size_t count, loff_t *offset)
-{
-	struct snd_ioctl_data *data = f->private_data;
-	struct snd_compr_stream *stream;
-	size_t avail;
-	int retval;
-
-	BUG_ON(!data);
-	stream = &data->stream;
-	mutex_lock(&stream->device->lock);
-	/* write is allowed when stream is running or has been steup */
-	if (stream->runtime->state != SNDRV_PCM_STATE_SETUP &&
-			stream->runtime->state != SNDRV_PCM_STATE_RUNNING) {
-		mutex_unlock(&stream->device->lock);
-		return -EPERM;
-	}
-
-	avail = snd_compr_get_avail(stream);
-	/* calculate how much we can write to buffer */
-	if (avail > count)
-		avail = count;
-
-	if (stream->ops->copy)
-		retval = stream->ops->copy(stream, buf, avail);
-	else
-		retval = snd_compr_write_data(stream, buf, avail);
-
-	/* while initiating the stream, write should be called before START
-	 * call, so in setup move state */
-	if (stream->runtime->state == SNDRV_PCM_STATE_SETUP)
-		stream->runtime->state = SNDRV_PCM_STATE_PREPARED;
-
-	mutex_unlock(&stream->device->lock);
-	return retval;
-}
-
-
-static ssize_t snd_compr_read(struct file *f, char __user *buf,
-		size_t count, loff_t *offset)
-{
-	return -ENXIO;
-}
-
-static int snd_compr_mmap(struct file *f, struct vm_area_struct *vma)
-{
-	return -ENXIO;
-}
-
-unsigned int snd_compr_poll(struct file *f, poll_table *wait)
-{
-	struct snd_ioctl_data *data = f->private_data;
-	struct snd_compr_stream *stream;
-	int retval = 0;
-
-	BUG_ON(!data);
-	stream = &data->stream;
-
-	mutex_lock(&stream->device->lock);
-	if (stream->runtime->state != SNDRV_PCM_STATE_RUNNING) {
-		retval = -ENXIO;
-		goto out;
-	}
-	poll_wait(f, &stream->runtime->sleep, wait);
-
-	/* this would change after read is implemented, we would need to
-	 * check for direction here */
-	if (stream->runtime->state != SNDRV_PCM_STATE_RUNNING)
-		retval = POLLOUT | POLLWRNORM;
-out:
-	mutex_unlock(&stream->device->lock);
-	return retval;
-}
-
-void snd_compr_fragment_elapsed(struct snd_compr_stream *stream)
-{
-	size_t avail;
-
-	if (stream->direction !=  SNDRV_PCM_STREAM_PLAYBACK)
-		return;
-	avail = snd_compr_get_avail(stream);
-	if (avail >= stream->runtime->fragment_size)
-		wake_up(&stream->runtime->sleep);
-}
-EXPORT_SYMBOL_GPL(snd_compr_fragment_elapsed);
-
-void snd_compr_frame_elapsed(struct snd_compr_stream *stream)
-{
-	size_t avail;
-
-	if (stream->direction !=  SNDRV_PCM_STREAM_CAPTURE)
-		return;
-	avail = snd_compr_get_avail(stream);
-	if (avail)
-		wake_up(&stream->runtime->sleep);
-}
-EXPORT_SYMBOL_GPL(snd_compr_frame_elapsed);
-
-static int snd_compr_get_caps(struct snd_compr_stream *stream, unsigned long arg)
-{
-	int retval;
-	struct snd_compr_caps caps;
-
-	if (!stream->ops->get_caps)
-		return -ENXIO;
-
-	retval = stream->ops->get_caps(stream, &caps);
-	if (retval)
-		goto out;
-	if (copy_to_user((void __user *)arg, &caps, sizeof(caps)))
-		retval = -EFAULT;
-out:
-	return retval;
-}
-
-static int snd_compr_get_codec_caps(struct snd_compr_stream *stream, unsigned long arg)
-{
-	int retval;
-	struct snd_compr_codec_caps *caps;
-
-	if (!stream->ops->get_codec_caps)
-		return -ENXIO;
-
-	caps = kmalloc(sizeof(*caps), GFP_KERNEL);
-	if (!caps)
-		return -ENOMEM;
-
-	retval = stream->ops->get_codec_caps(stream, caps);
-	if (retval)
-		goto out;
-	if (copy_to_user((void __user *)arg, caps, sizeof(*caps)))
-		retval = -EFAULT;
-
-out:
-	kfree(caps);
-	return retval;
-}
-
-/* revisit this with snd_pcm_preallocate_xxx */
-static int snd_compr_allocate_buffer(struct snd_compr_stream *stream,
-		struct snd_compr_params *params)
-{
-	unsigned int buffer_size;
-	void *buffer;
-
-	buffer_size = params->buffer.fragment_size * params->buffer.fragments;
-	if (stream->ops->copy) {
-		buffer = NULL;
-		/* if copy is defined the driver will be required to copy
-		 * the data from core
-		 */
-	} else {
-		buffer = kmalloc(buffer_size, GFP_KERNEL);
-		if (!buffer)
-			return -ENOMEM;
-	}
-	stream->runtime->fragment_size = params->buffer.fragment_size;
-	stream->runtime->fragments = params->buffer.fragments;
-	stream->runtime->buffer = buffer;
-	stream->runtime->buffer_size = buffer_size;
-	return 0;
-}
-
-static int snd_compr_set_params(struct snd_compr_stream *stream, unsigned long arg)
-{
-	struct snd_compr_params *params;
-	int retval;
-
-	if (stream->runtime->state == SNDRV_PCM_STATE_OPEN) {
-		/*
-		 * we should allow parameter change only when stream has been
-		 * opened not in other cases
-		 */
-		params = kmalloc(sizeof(*params), GFP_KERNEL);
-		if (!params)
-			return -ENOMEM;
-		if (copy_from_user(params, (void __user *)arg, sizeof(*params)))
-			return -EFAULT;
-		retval = snd_compr_allocate_buffer(stream, params);
-		if (retval) {
-			kfree(params);
-			return -ENOMEM;
-		}
-		retval = stream->ops->set_params(stream, params);
-		if (retval)
-			goto out;
-		stream->runtime->state = SNDRV_PCM_STATE_SETUP;
-	} else
-		return -EPERM;
-out:
-	kfree(params);
-	return retval;
-}
-
-static int snd_compr_get_params(struct snd_compr_stream *stream, unsigned long arg)
-{
-	struct snd_compr_params *params;
-	int retval;
-
-	if (!stream->ops->get_params)
-		return -ENXIO;
-
-	params = kmalloc(sizeof(*params), GFP_KERNEL);
-	if (!params)
-		return -ENOMEM;
-	retval = stream->ops->get_params(stream, params);
-	if (retval)
-		goto out;
-	if (copy_to_user((char __user *)arg, params, sizeof(*params)))
-		retval = -EFAULT;
-
-out:
-	kfree(params);
-	return retval;
-}
-
-static int snd_compr_tstamp(struct snd_compr_stream *stream, unsigned long arg)
-{
-	struct snd_compr_tstamp tstamp;
-
-	snd_compr_update_tstamp(stream, &tstamp);
-	if (copy_to_user((struct snd_compr_tstamp __user *)arg, &tstamp, sizeof(tstamp)))
-		return -EFAULT;
-	return 0;
-}
-
-static int snd_compr_pause(struct snd_compr_stream *stream)
-{
-	int retval;
-
-	if (stream->runtime->state == SNDRV_PCM_STATE_PAUSED)
-		return 0;
-	retval = stream->ops->trigger(stream, SNDRV_PCM_TRIGGER_PAUSE_PUSH);
-	if (!retval) {
-		stream->runtime->state = SNDRV_PCM_STATE_PAUSED;
-		wake_up(&stream->runtime->sleep);
-	}
-	return retval;
-}
-
-static int snd_compr_resume(struct snd_compr_stream *stream)
-{
-	int retval;
-
-	if (stream->runtime->state != SNDRV_PCM_STATE_PAUSED)
-		return -EPERM;
-	retval = stream->ops->trigger(stream, SNDRV_PCM_TRIGGER_PAUSE_RELEASE);
-	if (!retval)
-		stream->runtime->state = SNDRV_PCM_STATE_RUNNING;
-	return retval;
-}
-
-static int snd_compr_start(struct snd_compr_stream *stream)
-{
-	int retval;
-
-	if (stream->runtime->state != SNDRV_PCM_STATE_PREPARED)
-		return -EPERM;
-	retval = stream->ops->trigger(stream, SNDRV_PCM_TRIGGER_START);
-	if (!retval)
-		stream->runtime->state = SNDRV_PCM_STATE_RUNNING;
-	return retval;
-}
-
-static int snd_compr_stop(struct snd_compr_stream *stream)
-{
-	int retval;
-
-	if (stream->runtime->state != SNDRV_PCM_STATE_PREPARED)
-		return -EPERM;
-	retval = stream->ops->trigger(stream, SNDRV_PCM_TRIGGER_STOP);
-	if (!retval) {
-		stream->runtime->state = SNDRV_PCM_STATE_SETUP;
-		wake_up(&stream->runtime->sleep);
-	}
-	return retval;
-}
-
-static int snd_compr_drain(struct snd_compr_stream *stream)
-{
-	int retval;
-
-	if (stream->runtime->state != SNDRV_PCM_STATE_PREPARED ||
-			stream->runtime->state != SNDRV_PCM_STATE_PAUSED)
-		return -EPERM;
-	retval = stream->ops->trigger(stream, SND_COMPR_TRIGGER_DRAIN);
-	if (!retval) {
-		stream->runtime->state = SNDRV_PCM_STATE_SETUP;
-		wake_up(&stream->runtime->sleep);
-	}
-	return retval;
-}
-
-static long snd_compr_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
-{
-	struct snd_ioctl_data *data = f->private_data;
-	struct snd_compr_stream *stream;
-	int retval = -ENOTTY;
-
-	BUG_ON(!data);
-	stream = &data->stream;
-	mutex_lock(&stream->device->lock);
-	switch (_IOC_NR(cmd)) {
-	case _IOC_NR(SNDRV_COMPRESS_GET_CAPS):
-		retval = snd_compr_get_caps(stream, arg);
-		break;
-	case _IOC_NR(SNDRV_COMPRESS_GET_CODEC_CAPS):
-		retval = snd_compr_get_codec_caps(stream, arg);
-		break;
-	case _IOC_NR(SNDRV_COMPRESS_SET_PARAMS):
-		retval = snd_compr_set_params(stream, arg);
-		break;
-	case _IOC_NR(SNDRV_COMPRESS_GET_PARAMS):
-		retval = snd_compr_get_params(stream, arg);
-		break;
-	case _IOC_NR(SNDRV_COMPRESS_TSTAMP):
-		retval = snd_compr_tstamp(stream, arg);
-		break;
-	case _IOC_NR(SNDRV_COMPRESS_AVAIL):
-		retval = snd_compr_ioctl_avail(stream, arg);
-	case _IOC_NR(SNDRV_COMPRESS_PAUSE):
-		retval = snd_compr_pause(stream);
-		break;
-	case _IOC_NR(SNDRV_COMPRESS_RESUME):
-		retval = snd_compr_resume(stream);
-		break;
-	case _IOC_NR(SNDRV_COMPRESS_START):
-		retval = snd_compr_start(stream);
-		break;
-	case _IOC_NR(SNDRV_COMPRESS_STOP):
-		retval = snd_compr_stop(stream);
-		break;
-	case _IOC_NR(SNDRV_COMPRESS_DRAIN):
-		cmd = SND_COMPR_TRIGGER_DRAIN;
-		retval = snd_compr_drain(stream);
-		break;
-	}
-	mutex_unlock(&stream->device->lock);
-	return retval;
-}
-
-static const struct file_operations snd_comp_file = {
-	.owner =	THIS_MODULE,
-	.open =		snd_compr_open,
-	.release =	snd_compr_free,
-	.read =		snd_compr_read,
-	.write =	snd_compr_write,
-	.unlocked_ioctl = snd_compr_ioctl,
-	.mmap =		snd_compr_mmap,
-	.poll =		snd_compr_poll,
-};
-
-static int snd_compress_add_device(struct snd_compr *device)
-{
-	int ret;
-
-	struct snd_compr_misc *misc = kzalloc(sizeof(*misc), GFP_KERNEL);
-
-	misc->misc.name = device->name;
-	misc->misc.fops = &snd_comp_file;
-	misc->misc.minor = MISC_DYNAMIC_MINOR;
-	misc->compr = device;
-	ret = misc_register(&misc->misc);
-	if (ret) {
-		pr_err("couldn't register misc device\n");
-		kfree(misc);
-	} else {
-		pr_debug("Got minor %d\n", misc->misc.minor);
-		list_add_tail(&misc->list, &misc_list);
-	}
-	return ret;
-}
-
-static int snd_compress_remove_device(struct snd_compr *device)
-{
-	struct snd_compr_misc *misc, *__misc;
-
-	list_for_each_entry_safe(misc, __misc, &misc_list, list) {
-		if (device == misc->compr) {
-			misc_deregister(&misc->misc);
-			list_del(&device->list);
-			kfree(misc);
-		}
-	}
-	return 0;
-}
-/**
- * snd_compress_register - register compressed device
- *
- * @device: compressed device to register
- */
-int snd_compress_register(struct snd_compr *device)
-{
-	int retval;
-
-	if (device->name == NULL || device->dev == NULL || device->ops == NULL)
-		return -EINVAL;
-	BUG_ON(!device->ops->open);
-	BUG_ON(!device->ops->free);
-	BUG_ON(!device->ops->set_params);
-	BUG_ON(!device->ops->get_params);
-	BUG_ON(!device->ops->trigger);
-	BUG_ON(!device->ops->pointer);
-	BUG_ON(!device->ops->get_caps);
-	BUG_ON(!device->ops->get_codec_caps);
-
-	INIT_LIST_HEAD(&device->list);
-	/* todo register the compressed streams */
-	/* todo integrate with asoc */
-
-	/* register a compressed card  TBD if this needs change */
-
-	pr_debug("Registering compressed device %s\n", device->name);
-	mutex_lock(&device_mutex);
-	/*  register a msic device for now */
-	retval = snd_compress_add_device(device);
-	if (!retval)
-		list_add_tail(&device->list, &device_list);
-	mutex_unlock(&device_mutex);
-	return retval;
-}
-EXPORT_SYMBOL_GPL(snd_compress_register);
-
-int snd_compress_deregister(struct snd_compr *device)
-{
-	pr_debug("Removing compressed device %s\n", device->name);
-	mutex_lock(&device_mutex);
-	snd_compress_remove_device(device);
-	list_del(&device->list);
-	mutex_unlock(&device_mutex);
-	return 0;
-}
-EXPORT_SYMBOL_GPL(snd_compress_deregister);
-
-static int __init snd_compress_init(void)
-{
-	return 0;
-}
-
-static void __exit snd_compress_exit(void)
-{
-}
-
-module_init(snd_compress_init);
-module_exit(snd_compress_exit);
diff --git a/sound/core/jack.c b/sound/core/jack.c
index 9e2e085..6e2dbdb 100644
--- a/sound/core/jack.c
+++ b/sound/core/jack.c
@@ -35,6 +35,7 @@
 	SW_HPHL_OVERCURRENT,
 	SW_HPHR_OVERCURRENT,
 	SW_UNSUPPORT_INSERT,
+	SW_MICROPHONE2_INSERT,
 };
 
 static int snd_jack_dev_free(struct snd_device *device)
diff --git a/sound/soc/codecs/msm8x10-wcd.c b/sound/soc/codecs/msm8x10-wcd.c
index 1962ff0..a5e0bb3 100644
--- a/sound/soc/codecs/msm8x10-wcd.c
+++ b/sound/soc/codecs/msm8x10-wcd.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
@@ -50,6 +50,8 @@
 #define BITS_PER_REG		8
 #define MSM8X10_WCD_TX_PORT_NUMBER	4
 
+#define DAPM_MICBIAS_EXTERNAL_STANDALONE "MIC BIAS External Standalone"
+
 #define MSM8X10_WCD_I2S_MASTER_MODE_MASK	0x08
 #define MSM8X10_DINO_CODEC_BASE_ADDR		0xFE043000
 #define MSM8X10_DINO_CODEC_REG_SIZE		0x200
@@ -165,6 +167,10 @@
 	"cdc-vdda-cp",
 };
 
+static int on_demand_regulator_control(struct on_demand_supply *supply,
+				       bool enable,
+				       u8 shift);
+
 struct msm8x10_wcd_priv {
 	struct snd_soc_codec *codec;
 	u32 adc_count;
@@ -176,7 +182,6 @@
 	/* mbhc module */
 	struct wcd9xxx_mbhc mbhc;
 
-	struct delayed_work hs_detect_work;
 	struct wcd9xxx_mbhc_config *mbhc_cfg;
 
 	/*
@@ -184,6 +189,7 @@
 	 * end of impedance measurement
 	 */
 	struct list_head reg_save_restore;
+	u32 micb_en_count;
 };
 
 static unsigned short rx_digital_gain_reg[] = {
@@ -296,7 +302,6 @@
 			return ret;
 		}
 	}
-	pr_debug("write sucess register = %x val = %x\n", reg, data[1]);
 	return 0;
 }
 
@@ -345,7 +350,6 @@
 			}
 		}
 	}
-	pr_debug("%s: reg 0x%x = 0x%x\n", __func__, reg, *dest);
 	return 0;
 }
 
@@ -395,6 +399,32 @@
 	return temp;
 }
 
+static int __msm8x10_wcd_bulk_write(struct msm8x10_wcd *msm8x10_wcd,
+		unsigned short reg, int count, u8 *buf)
+{
+	int ret = -EINVAL;
+	mutex_lock(&msm8x10_wcd->io_lock);
+	if (MSM8X10_WCD_IS_HELICON_REG(reg))
+		ret = msm8x10_wcd_i2c_write(reg, count, buf);
+	else if (MSM8X10_WCD_IS_DINO_REG(reg))
+		ret = msm8x10_wcd_abh_write_device(msm8x10_wcd, reg,
+						buf, count);
+	if (ret < 0)
+		dev_err(msm8x10_wcd->dev,
+				"%s: codec bulk write failed\n", __func__);
+	mutex_unlock(&msm8x10_wcd->io_lock);
+	return ret;
+}
+
+int msm8x10_wcd_bulk_write(struct wcd9xxx_core_resource *core_res,
+			unsigned short reg, int count, u8 *buf)
+{
+	struct msm8x10_wcd *msm8x10_wcd =
+				(struct msm8x10_wcd *) core_res->parent;
+	return __msm8x10_wcd_bulk_write(msm8x10_wcd, reg, count, buf);
+}
+EXPORT_SYMBOL(msm8x10_wcd_bulk_write);
+
 int msm8x10_wcd_reg_read(struct wcd9xxx_core_resource *core_res,
 				unsigned short reg)
 {
@@ -451,8 +481,8 @@
 				__func__, reg);
 	else
 		dev_dbg(msm8x10_wcd->dev,
-			"%s: Write %x to R%d(0x%x)\n",
-			__func__, val, reg, reg);
+			"%s: Write 0x%x to 0x%x\n",
+			__func__, val, reg);
 
 	return ret;
 }
@@ -488,8 +518,6 @@
 	 * Registers lower than 0x100 are top level registers which can be
 	 * written by the Taiko core driver.
 	 */
-	dev_dbg(codec->dev, "%s: reg 0x%x\n", __func__, reg);
-
 	if ((reg >= MSM8X10_WCD_A_CDC_MBHC_EN_CTL) || (reg < 0x100))
 		return 1;
 
@@ -525,7 +553,7 @@
 			     unsigned int value)
 {
 	int ret;
-	dev_dbg(codec->dev, "%s: Write from reg 0x%x\n", __func__, reg);
+	dev_dbg(codec->dev, "%s: Write to reg 0x%x\n", __func__, reg);
 	if (reg == SND_SOC_NOPM)
 		return 0;
 
@@ -756,6 +784,39 @@
 	return NULL;
 }
 
+static int on_demand_regulator_control(struct on_demand_supply *supply,
+				       bool enable,
+				       u8 shift)
+{
+	int ret = 0;
+
+	if (!supply || !supply->supply)
+		return 0;
+
+	if (enable) {
+		if (atomic_inc_return(&supply->ref) == 1)
+			ret = regulator_enable(supply->supply);
+		if (ret)
+			pr_err("%s: Failed to enable %s\n",
+					__func__,
+					on_demand_supply_name[shift]);
+	} else {
+		if (atomic_read(&supply->ref) == 0) {
+			pr_debug("%s: %s supply has been disabled.\n",
+					__func__, on_demand_supply_name[shift]);
+			return 0;
+		}
+		if (atomic_dec_return(&supply->ref) == 0)
+			ret = regulator_disable(supply->supply);
+		if (ret)
+			pr_err("%s: Failed to disable %s\n",
+					__func__,
+					on_demand_supply_name[shift]);
+	}
+
+	return ret;
+}
+
 static int msm8x10_wcd_codec_enable_on_demand_supply(
 		struct snd_soc_dapm_widget *w,
 		struct snd_kcontrol *kcontrol, int event)
@@ -781,25 +842,14 @@
 
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
-		if (atomic_inc_return(&supply->ref) == 1)
-			ret = regulator_enable(supply->supply);
-		if (ret)
-			dev_err(codec->dev, "%s: Failed to enable %s\n",
-				__func__,
-				on_demand_supply_name[w->shift]);
+		ret = on_demand_regulator_control(supply,
+						  true,
+						  w->shift);
 		break;
 	case SND_SOC_DAPM_POST_PMD:
-		if (atomic_read(&supply->ref) == 0) {
-			dev_dbg(codec->dev, "%s: %s supply has been disabled.\n",
-				 __func__, on_demand_supply_name[w->shift]);
-			goto out;
-		}
-		if (atomic_dec_return(&supply->ref) == 0)
-			ret = regulator_disable(supply->supply);
-			if (ret)
-				dev_err(codec->dev, "%s: Failed to disable %s\n",
-					__func__,
-					on_demand_supply_name[w->shift]);
+		ret = on_demand_regulator_control(supply,
+						  false,
+						  w->shift);
 		break;
 	default:
 		break;
@@ -1150,6 +1200,13 @@
 			  MSM8X10_WCD_A_CDC_TX2_VOL_CTL_GAIN,
 			  -84, 40, digital_gain),
 
+	SOC_SINGLE_TLV("ADC1 Volume", MSM8X10_WCD_A_TX_1_EN, 2,
+					19, 0, analog_gain),
+	SOC_SINGLE_TLV("ADC2 Volume", MSM8X10_WCD_A_TX_2_EN, 2,
+					19, 0, analog_gain),
+	SOC_SINGLE_TLV("ADC3 Volume", MSM8X10_WCD_A_TX_3_EN, 2,
+					19, 0, analog_gain),
+
 	SOC_SINGLE_S8_TLV("IIR1 INP1 Volume",
 			  MSM8X10_WCD_A_CDC_IIR1_GAIN_B1_CTL,
 			  -84, 40, digital_gain),
@@ -1271,6 +1328,10 @@
 	"ZERO", "RX3", "RX2"
 };
 
+static const char * const rx_rdac3_text[] = {
+	"RX1", "RX2"
+};
+
 static const struct soc_enum rx_mix1_inp1_chain_enum =
 	SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_CONN_RX1_B1_CTL, 0, 6, rx_mix1_text);
 
@@ -1312,6 +1373,10 @@
 	SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_CONN_LO_DAC_CTL, 0, 3,
 	rx_rdac4_text);
 
+static const struct soc_enum rx_rdac3_enum  =
+	SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_CONN_HPHR_DAC_CTL, 0, 2,
+	rx_rdac3_text);
+
 static const struct soc_enum adc2_enum =
 	SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(adc2_mux_text), adc2_mux_text);
 
@@ -1345,6 +1410,9 @@
 static const struct snd_kcontrol_new rx_dac4_mux =
 	SOC_DAPM_ENUM("RDAC4 MUX Mux", rx_rdac4_enum);
 
+static const struct snd_kcontrol_new rx_dac3_mux =
+	SOC_DAPM_ENUM("RDAC3 MUX Mux", rx_rdac3_enum);
+
 static const struct snd_kcontrol_new tx_adc2_mux =
 	SOC_DAPM_ENUM("ADC2 MUX Mux", adc2_enum);
 
@@ -1635,6 +1703,11 @@
 
 		/* Always pull up TxFe for TX2 to Micbias */
 		snd_soc_update_bits(codec, micb_int_reg, 0x04, 0x04);
+		snd_soc_update_bits(codec, MSM8X10_WCD_A_MICB_1_CTL,
+					0x80, 0x80);
+		msm8x10_wcd->micb_en_count++;
+		pr_debug("%s micb_en_count : %d", __func__,
+				msm8x10_wcd->micb_en_count);
 		break;
 	case SND_SOC_DAPM_POST_PMU:
 		usleep_range(20000, 20100);
@@ -1642,6 +1715,12 @@
 		wcd9xxx_resmgr_notifier_call(&msm8x10_wcd->resmgr, e_post_on);
 		break;
 	case SND_SOC_DAPM_POST_PMD:
+		if (msm8x10_wcd->micb_en_count > 0)
+			msm8x10_wcd->micb_en_count--;
+		pr_debug("%s micb_en_count : %d", __func__,
+				msm8x10_wcd->micb_en_count);
+		snd_soc_update_bits(codec, MSM8X10_WCD_A_MICB_1_CTL,
+					0x80, 0x00);
 		/* Let MBHC module know so micbias switch to be off */
 		wcd9xxx_resmgr_notifier_call(&msm8x10_wcd->resmgr, e_post_off);
 
@@ -1972,7 +2051,10 @@
 
 	{"DAC1", "Switch", "RX1 CHAIN"},
 	{"HPHL DAC", "Switch", "RX1 CHAIN"},
-	{"HPHR DAC", NULL, "RX2 CHAIN"},
+	{"HPHR DAC", NULL, "RDAC3 MUX"},
+
+	{"RDAC3 MUX", "RX1", "RX1 CHAIN"},
+	{"RDAC3 MUX", "RX2", "RX2 CHAIN"},
 
 	{"LINEOUT", NULL, "LINEOUT PA"},
 	{"SPK_OUT", NULL, "SPK PA"},
@@ -2279,6 +2361,10 @@
 	struct snd_kcontrol *kcontrol, int event)
 {
 	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		snd_soc_update_bits(w->codec, MSM8X10_WCD_A_CDC_ANA_CLK_CTL,
+				0x4, 0x4);
+		break;
 	case SND_SOC_DAPM_POST_PMU:
 		dev_dbg(w->codec->dev,
 			"%s: Sleeping 20ms after enabling EAR PA\n",
@@ -2289,6 +2375,8 @@
 		dev_dbg(w->codec->dev,
 			"%s: Sleeping 20ms after disabling EAR PA\n",
 			__func__);
+		snd_soc_update_bits(w->codec, MSM8X10_WCD_A_CDC_ANA_CLK_CTL,
+				0x4, 0x0);
 		msleep(20);
 		break;
 	}
@@ -2300,7 +2388,8 @@
 	SND_SOC_DAPM_OUTPUT("EAR"),
 
 	SND_SOC_DAPM_PGA_E("EAR PA", MSM8X10_WCD_A_RX_EAR_EN, 4, 0, NULL, 0,
-			msm8x10_wcd_codec_enable_ear_pa, SND_SOC_DAPM_POST_PMU),
+			msm8x10_wcd_codec_enable_ear_pa, SND_SOC_DAPM_PRE_PMU |
+			SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
 
 	SND_SOC_DAPM_MIXER("DAC1", MSM8X10_WCD_A_RX_EAR_EN, 6, 0, dac1_switch,
 		ARRAY_SIZE(dac1_switch)),
@@ -2388,7 +2477,7 @@
 	SND_SOC_DAPM_SUPPLY("HPHL CLK", MSM8X10_WCD_A_CDC_ANA_CLK_CTL,
 		1, 0, NULL, 0),
 	SND_SOC_DAPM_SUPPLY("EAR CLK", MSM8X10_WCD_A_CDC_ANA_CLK_CTL,
-		2, 0, NULL, 0),
+		6, 0, NULL, 0),
 	SND_SOC_DAPM_SUPPLY("LINEOUT CLK", MSM8X10_WCD_A_CDC_ANA_CLK_CTL,
 		3, 0, NULL, 0),
 	SND_SOC_DAPM_SUPPLY("SPK CLK", MSM8X10_WCD_A_CDC_ANA_CLK_CTL,
@@ -2414,6 +2503,8 @@
 		&rx2_mix2_inp1_mux),
 	SND_SOC_DAPM_MUX("RDAC4 MUX", SND_SOC_NOPM, 0, 0,
 		&rx_dac4_mux),
+	SND_SOC_DAPM_MUX("RDAC3 MUX", SND_SOC_NOPM, 0, 0,
+		&rx_dac3_mux),
 
 	SND_SOC_DAPM_SUPPLY("MICBIAS_REGULATOR", SND_SOC_NOPM,
 		ON_DEMAND_MICBIAS, 0,
@@ -2458,6 +2549,11 @@
 		MSM8X10_WCD_A_MICB_1_CTL, 7, 0,
 		msm8x10_wcd_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
 		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MICBIAS_E(DAPM_MICBIAS_EXTERNAL_STANDALONE,
+		MSM8X10_WCD_A_MICB_1_CTL,
+		7, 0, msm8x10_wcd_codec_enable_micbias,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+		SND_SOC_DAPM_POST_PMD),
 
 	SND_SOC_DAPM_ADC_E("ADC1", NULL, MSM8X10_WCD_A_TX_1_EN, 7, 0,
 		msm8x10_wcd_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
@@ -2546,8 +2642,6 @@
 	/* Disable internal biasing path which can cause leakage */
 	MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_BIAS_CURR_CTL_2, 0x04),
 
-	/* Enable pulldown to reduce leakage */
-	MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_MICB_1_CTL, 0x82),
 	MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_TX_COM_BIAS, 0xE0),
 	/* Keep the same default gain settings for TX paths */
 	MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_TX_1_EN, 0x32),
@@ -2686,18 +2780,33 @@
 }
 
 static int msm8x10_wcd_enable_ext_mb_source(struct snd_soc_codec *codec,
-	bool turn_on)
+					    bool turn_on,
+					    bool use_dapm)
 {
 	int ret = 0;
 
-	if (turn_on)
-		ret = snd_soc_dapm_force_enable_pin(&codec->dapm,
-				"MICBIAS_REGULATOR");
-	else
-		ret = snd_soc_dapm_disable_pin(&codec->dapm,
-				"MICBIAS_REGULATOR");
+	if (use_dapm) {
+		if (turn_on)
+			ret = snd_soc_dapm_force_enable_pin(&codec->dapm,
+					"MICBIAS_REGULATOR");
+		else
+			ret = snd_soc_dapm_disable_pin(&codec->dapm,
+					"MICBIAS_REGULATOR");
 
-	snd_soc_dapm_sync(&codec->dapm);
+		snd_soc_dapm_sync(&codec->dapm);
+	} else {
+		struct on_demand_supply *supply;
+		struct msm8x10_wcd_priv *msm8x10_wcd =
+				snd_soc_codec_get_drvdata(codec);
+
+		supply = &msm8x10_wcd->on_demand_list[ON_DEMAND_MICBIAS];
+		if (!supply || !supply->supply || !msm8x10_wcd)
+			return 0;
+
+		ret = on_demand_regulator_control(supply,
+						  turn_on,
+						  ON_DEMAND_MICBIAS);
+	}
 
 	if (ret)
 		dev_err(codec->dev, "%s: Failed to %s external micbias source\n",
@@ -2709,6 +2818,43 @@
 	return ret;
 }
 
+static int msm8x10_wcd_enable_mbhc_micbias(struct snd_soc_codec *codec,
+					   bool enable,
+					   enum wcd9xxx_micbias_num micb_num)
+{
+	int rc;
+	struct msm8x10_wcd_priv *msm8x10_wcd = snd_soc_codec_get_drvdata(codec);
+
+	if (micb_num != MBHC_MICBIAS1) {
+		rc = -EINVAL;
+		goto err;
+	}
+
+	if (enable)
+		rc = snd_soc_dapm_force_enable_pin(&codec->dapm,
+			DAPM_MICBIAS_EXTERNAL_STANDALONE);
+	else {
+		if (msm8x10_wcd->micb_en_count > 0) {
+			msm8x10_wcd->micb_en_count--;
+			pr_debug("%s micb_en_count : %d", __func__,
+					msm8x10_wcd->micb_en_count);
+			return 0;
+		}
+		rc = snd_soc_dapm_disable_pin(&codec->dapm,
+			DAPM_MICBIAS_EXTERNAL_STANDALONE);
+	}
+	snd_soc_dapm_sync(&codec->dapm);
+
+err:
+	if (rc)
+		pr_debug("%s: Failed to force %s micbias", __func__,
+			enable ? "enable" : "disable");
+	else
+		pr_debug("%s: Trying force %s micbias", __func__,
+			enable ? "enable" : "disable");
+	return rc;
+}
+
 static void msm8x10_wcd_micb_internal(struct snd_soc_codec *codec, bool on)
 {
 	snd_soc_update_bits(codec, MSM8X10_WCD_A_MICB_1_INT_RBIAS,
@@ -2959,33 +3105,18 @@
 	.compute_impedance = msm8x10_wcd_compute_impedance,
 };
 
-static void delayed_hs_detect_fn(struct work_struct *work)
-{
-	struct delayed_work *delayed_work;
-	struct msm8x10_wcd_priv *wcd_priv;
-
-	delayed_work = to_delayed_work(work);
-	wcd_priv = container_of(delayed_work, struct msm8x10_wcd_priv,
-				hs_detect_work);
-
-	if (!wcd_priv) {
-		pr_err("%s: Invalid private data for codec\n", __func__);
-		return;
-	}
-
-	wcd9xxx_mbhc_start(&wcd_priv->mbhc, wcd_priv->mbhc_cfg);
-}
-
-
 int msm8x10_wcd_hs_detect(struct snd_soc_codec *codec,
 		    struct wcd9xxx_mbhc_config *mbhc_cfg)
 {
 	struct msm8x10_wcd_priv *wcd = snd_soc_codec_get_drvdata(codec);
 
+	if (!wcd) {
+		dev_err(codec->dev, "%s: Invalid private data for codec\n",
+			__func__);
+		return -EINVAL;
+	}
 	wcd->mbhc_cfg = mbhc_cfg;
-	schedule_delayed_work(&wcd->hs_detect_work,
-			msecs_to_jiffies(5000));
-	return 0;
+	return wcd9xxx_mbhc_start(&wcd->mbhc, wcd->mbhc_cfg);
 }
 EXPORT_SYMBOL_GPL(msm8x10_wcd_hs_detect);
 
@@ -3020,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 */
@@ -3031,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;
@@ -3072,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)
 {
@@ -3152,8 +3305,6 @@
 	msm8x10_wcd = codec->control_data;
 	msm8x10_wcd->pdino_base = ioremap(MSM8X10_DINO_CODEC_BASE_ADDR,
 					  MSM8X10_DINO_CODEC_REG_SIZE);
-	INIT_DELAYED_WORK(&msm8x10_wcd_priv->hs_detect_work,
-			delayed_hs_detect_fn);
 
 	pdata = dev_get_platdata(msm8x10_wcd->dev);
 	if (!pdata) {
@@ -3189,9 +3340,12 @@
 				on_demand_supply_name[ON_DEMAND_MICBIAS]);
 	atomic_set(&msm8x10_wcd_priv->on_demand_list[ON_DEMAND_MICBIAS].ref, 0);
 
+	msm8x10_wcd_priv->micb_en_count = 0;
+
 	ret = wcd9xxx_mbhc_init(&msm8x10_wcd_priv->mbhc,
 				&msm8x10_wcd_priv->resmgr,
-				codec, NULL, &mbhc_cb, &cdc_intr_ids,
+				codec, msm8x10_wcd_enable_mbhc_micbias,
+				&mbhc_cb, &cdc_intr_ids,
 				HELICON_MCLK_CLK_9P6MHZ, true);
 	if (ret) {
 		dev_err(msm8x10_wcd->dev, "%s: Failed to initialize mbhc\n",
@@ -3565,7 +3719,8 @@
 					MSM8X10_WCD_NUM_IRQ_REGS,
 					msm8x10_wcd_reg_read,
 					msm8x10_wcd_reg_write,
-					msm8x10_wcd_bulk_read);
+					msm8x10_wcd_bulk_read,
+					msm8x10_wcd_bulk_write);
 	if (wcd9xxx_core_irq_init(core_res)) {
 		dev_err(msm8x10->dev,
 				"%s: irq initialization failed\n", __func__);
diff --git a/sound/soc/codecs/msm_hdmi_codec_rx.c b/sound/soc/codecs/msm_hdmi_codec_rx.c
index 73c9547e..5223070 100644
--- a/sound/soc/codecs/msm_hdmi_codec_rx.c
+++ b/sound/soc/codecs/msm_hdmi_codec_rx.c
@@ -21,8 +21,6 @@
 
 #define MSM_HDMI_PCM_RATES	SNDRV_PCM_RATE_48000
 
-static int msm_hdmi_audio_codec_return_value;
-
 struct msm_hdmi_audio_codec_rx_data {
 	struct platform_device *hdmi_core_pdev;
 	struct msm_hdmi_audio_codec_ops hdmi_ops;
@@ -86,18 +84,24 @@
 		struct snd_pcm_substream *substream,
 		struct snd_soc_dai *dai)
 {
+	int rv = 0;
 	struct msm_hdmi_audio_codec_rx_data *codec_data =
 			dev_get_drvdata(dai->codec->dev);
 
-	msm_hdmi_audio_codec_return_value =
-		codec_data->hdmi_ops.hdmi_cable_status(
+	rv = codec_data->hdmi_ops.hdmi_cable_status(
 		codec_data->hdmi_core_pdev, 1);
-	if (IS_ERR_VALUE(msm_hdmi_audio_codec_return_value)) {
+	if (IS_ERR_VALUE(rv)) {
 		dev_err(dai->dev,
-			"%s() HDMI core is not ready\n", __func__);
+			"%s() HDMI core is not ready (rv = %d)\n",
+			__func__, rv);
+	} else if (!rv) {
+		dev_err(dai->dev,
+			"%s() HDMI cable is not connected (ret val = %d)\n",
+			__func__, rv);
+		rv = -EAGAIN;
 	}
 
-	return msm_hdmi_audio_codec_return_value;
+	return rv;
 }
 
 static int msm_hdmi_audio_codec_rx_dai_hw_params(
@@ -109,16 +113,23 @@
 	u32 level_shift  = 0; /* 0dB */
 	bool down_mix = 0;
 	u32 num_channels = params_channels(params);
-	int rc = 0;
+	int rv = 0;
 
 	struct msm_hdmi_audio_codec_rx_data *codec_data =
 			dev_get_drvdata(dai->codec->dev);
 
-	/*refer to HDMI spec CEA-861-E: Table 28 Audio InfoFrame Data Byte 4*/
-	if (IS_ERR_VALUE(msm_hdmi_audio_codec_return_value)) {
+	rv = codec_data->hdmi_ops.hdmi_cable_status(
+		codec_data->hdmi_core_pdev, 1);
+	if (IS_ERR_VALUE(rv)) {
 		dev_err(dai->dev,
-			"%s() HDMI core is not ready\n", __func__);
-		return msm_hdmi_audio_codec_return_value;
+			"%s() HDMI core is not ready (rv = %d)\n",
+			__func__, rv);
+		return rv;
+	} else if (!rv) {
+		dev_err(dai->dev,
+			"%s() HDMI cable is not connected (rv = %d)\n",
+			__func__, rv);
+		return -EAGAIN;
 	}
 
 	switch (num_channels) {
@@ -153,16 +164,16 @@
 		__func__, num_channels, params_rate(params),
 		channel_allocation);
 
-	rc = codec_data->hdmi_ops.audio_info_setup(
+	rv = codec_data->hdmi_ops.audio_info_setup(
 			codec_data->hdmi_core_pdev,
 			params_rate(params), num_channels,
 			channel_allocation, level_shift, down_mix);
-	if (IS_ERR_VALUE(rc)) {
+	if (IS_ERR_VALUE(rv)) {
 		dev_err(dai->dev,
 			"%s() HDMI core is not ready\n", __func__);
 	}
 
-	return rc;
+	return rv;
 }
 
 static void msm_hdmi_audio_codec_rx_dai_shutdown(
diff --git a/sound/soc/codecs/wcd9304.c b/sound/soc/codecs/wcd9304.c
index a68722c..aec228a 100644
--- a/sound/soc/codecs/wcd9304.c
+++ b/sound/soc/codecs/wcd9304.c
@@ -1368,7 +1368,7 @@
 			if (wcd9xxx_tx_vport_validation(
 						vport_check_table[dai_id],
 						port_id,
-						sitar_p->dai)) {
+						sitar_p->dai, NUM_CODEC_DAIS)) {
 				dev_dbg(codec->dev, "%s: TX%u is used by other virtual port\n",
 					__func__, port_id + 1);
 				mutex_unlock(&codec->mutex);
diff --git a/sound/soc/codecs/wcd9306.c b/sound/soc/codecs/wcd9306.c
index 4912cf04a..38d7901 100644
--- a/sound/soc/codecs/wcd9306.c
+++ b/sound/soc/codecs/wcd9306.c
@@ -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
@@ -43,6 +43,8 @@
 #define TAPAN_HPH_PA_SETTLE_COMP_OFF 13000
 
 #define DAPM_MICBIAS2_EXTERNAL_STANDALONE "MIC BIAS2 External Standalone"
+#define TAPAN_VALIDATE_RX_SBPORT_RANGE(port) ((port >= 16) && (port <= 20))
+#define TAPAN_CONVERT_RX_SBPORT_ID(port) (port - 16) /* RX1 port ID = 0 */
 
 #define TAPAN_VDD_CX_OPTIMAL_UA 10000
 #define TAPAN_VDD_CX_SLEEP_UA 2000
@@ -514,31 +516,41 @@
 				struct snd_ctl_elem_value *ucontrol)
 {
 	u8 ear_pa_gain;
+	int rc = 0;
 	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
 
 	ear_pa_gain = snd_soc_read(codec, TAPAN_A_RX_EAR_GAIN);
-
 	ear_pa_gain = ear_pa_gain >> 5;
 
-	if (ear_pa_gain == 0x00) {
-		ucontrol->value.integer.value[0] = 0;
-	} else if (ear_pa_gain == 0x04) {
-		ucontrol->value.integer.value[0] = 1;
-	} else  {
+	switch (ear_pa_gain) {
+	case 0:
+	case 1:
+	case 2:
+	case 3:
+	case 4:
+	case 5:
+		ucontrol->value.integer.value[0] = ear_pa_gain;
+		break;
+	case 7:
+		ucontrol->value.integer.value[0] = (ear_pa_gain - 1);
+		break;
+	default:
+		rc = -EINVAL;
 		pr_err("%s: ERROR: Unsupported Ear Gain = 0x%x\n",
-				__func__, ear_pa_gain);
-		return -EINVAL;
+		       __func__, ear_pa_gain);
+		break;
 	}
 
 	dev_dbg(codec->dev, "%s: ear_pa_gain = 0x%x\n", __func__, ear_pa_gain);
 
-	return 0;
+	return rc;
 }
 
 static int tapan_pa_gain_put(struct snd_kcontrol *kcontrol,
 				struct snd_ctl_elem_value *ucontrol)
 {
 	u8 ear_pa_gain;
+	int rc = 0;
 	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
 
 	dev_dbg(codec->dev, "%s: ucontrol->value.integer.value[0]  = %ld\n",
@@ -546,17 +558,24 @@
 
 	switch (ucontrol->value.integer.value[0]) {
 	case 0:
-		ear_pa_gain = 0x00;
-		break;
 	case 1:
-		ear_pa_gain = 0x80;
+	case 2:
+	case 3:
+	case 4:
+	case 5:
+		ear_pa_gain = ucontrol->value.integer.value[0];
+		break;
+	case 6:
+		ear_pa_gain = 0x07;
 		break;
 	default:
-		return -EINVAL;
+		rc = -EINVAL;
+		break;
 	}
-
-	snd_soc_update_bits(codec, TAPAN_A_RX_EAR_GAIN, 0xE0, ear_pa_gain);
-	return 0;
+	if (!rc)
+		snd_soc_update_bits(codec, TAPAN_A_RX_EAR_GAIN,
+				    0xE0, ear_pa_gain << 5);
+	return rc;
 }
 
 static int tapan_get_iir_enable_audio_mixer(
@@ -1017,9 +1036,13 @@
 	return 0;
 }
 
-static const char * const tapan_ear_pa_gain_text[] = {"POS_6_DB", "POS_2_DB"};
+static const char * const tapan_ear_pa_gain_text[] = {"POS_6_DB", "POS_4P5_DB",
+						      "POS_3_DB", "POS_1P5_DB",
+						      "POS_0_DB", "NEG_2P5_DB",
+						      "NEG_12_DB"};
 static const struct soc_enum tapan_ear_pa_gain_enum[] = {
-		SOC_ENUM_SINGLE_EXT(2, tapan_ear_pa_gain_text),
+		SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(tapan_ear_pa_gain_text),
+				    tapan_ear_pa_gain_text),
 };
 
 static const char *const tapan_anc_func_text[] = {"OFF", "ON"};
@@ -1089,17 +1112,17 @@
 	SOC_ENUM_EXT("EAR PA Gain", tapan_ear_pa_gain_enum[0],
 		tapan_pa_gain_get, tapan_pa_gain_put),
 
-	SOC_SINGLE_TLV("HPHL Volume", TAPAN_A_RX_HPH_L_GAIN, 0, 14, 1,
+	SOC_SINGLE_TLV("HPHL Volume", TAPAN_A_RX_HPH_L_GAIN, 0, 20, 1,
 		line_gain),
-	SOC_SINGLE_TLV("HPHR Volume", TAPAN_A_RX_HPH_R_GAIN, 0, 14, 1,
+	SOC_SINGLE_TLV("HPHR Volume", TAPAN_A_RX_HPH_R_GAIN, 0, 20, 1,
 		line_gain),
 
-	SOC_SINGLE_TLV("LINEOUT1 Volume", TAPAN_A_RX_LINE_1_GAIN, 0, 14, 1,
+	SOC_SINGLE_TLV("LINEOUT1 Volume", TAPAN_A_RX_LINE_1_GAIN, 0, 20, 1,
 		line_gain),
-	SOC_SINGLE_TLV("LINEOUT2 Volume", TAPAN_A_RX_LINE_2_GAIN, 0, 14, 1,
+	SOC_SINGLE_TLV("LINEOUT2 Volume", TAPAN_A_RX_LINE_2_GAIN, 0, 20, 1,
 		line_gain),
 
-	SOC_SINGLE_TLV("SPK DRV Volume", TAPAN_A_SPKR_DRV_GAIN, 3, 7, 1,
+	SOC_SINGLE_TLV("SPK DRV Volume", TAPAN_A_SPKR_DRV_GAIN, 3, 8, 1,
 		line_gain),
 
 	SOC_SINGLE_TLV("ADC1 Volume", TAPAN_A_TX_1_EN, 2, 19, 0, analog_gain),
@@ -1321,6 +1344,9 @@
 static const struct soc_enum rx3_mix1_inp2_chain_enum =
 	SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_RX3_B1_CTL, 4, 13, rx_3_4_mix1_text);
 
+static const struct soc_enum rx3_mix1_inp3_chain_enum =
+	SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_RX3_B2_CTL, 0, 13, rx_3_4_mix1_text);
+
 static const struct soc_enum rx4_mix1_inp1_chain_enum =
 	SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_RX4_B1_CTL, 0, 13, rx_3_4_mix1_text);
 
@@ -1419,6 +1445,9 @@
 static const struct snd_kcontrol_new rx3_mix1_inp2_mux =
 	SOC_DAPM_ENUM("RX3 MIX1 INP2 Mux", rx3_mix1_inp2_chain_enum);
 
+static const struct snd_kcontrol_new rx3_mix1_inp3_mux =
+	SOC_DAPM_ENUM("RX3 MIX1 INP3 Mux", rx3_mix1_inp3_chain_enum);
+
 static const struct snd_kcontrol_new rx4_mix1_inp1_mux =
 	SOC_DAPM_ENUM("RX4 MIX1 INP1 Mux", rx4_mix1_inp1_chain_enum);
 
@@ -1484,6 +1513,7 @@
 	u16 tx_mux_ctl_reg;
 	u8 adc_dmic_sel = 0x0;
 	int ret = 0;
+	char *srch = NULL;
 
 	if (ucontrol->value.enumerated.item[0] > e->max - 1)
 		return -EINVAL;
@@ -1502,8 +1532,12 @@
 		ret =  -EINVAL;
 		goto out;
 	}
-
-	ret = kstrtouint(strpbrk(dec_name, "1234"), 10, &decimator);
+	srch = strpbrk(dec_name, "1234");
+	if (srch == NULL) {
+		pr_err("%s: Invalid decimator name %s\n", __func__, dec_name);
+		return -EINVAL;
+	}
+	ret = kstrtouint(srch, 10, &decimator);
 	if (ret < 0) {
 		pr_err("%s: Invalid decimator = %s\n", __func__, dec_name);
 		ret =  -EINVAL;
@@ -1671,7 +1705,7 @@
 			if (wcd9xxx_tx_vport_validation(
 						vtable,
 						port_id,
-						tapan_p->dai)) {
+						tapan_p->dai, NUM_CODEC_DAIS)) {
 				dev_dbg(codec->dev, "%s: TX%u is used by other virtual port\n",
 					__func__, port_id + 1);
 				mutex_unlock(&codec->mutex);
@@ -1867,9 +1901,10 @@
 
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
-		if (w->reg == TAPAN_A_TX_3_EN)
+		if (w->reg == TAPAN_A_TX_3_EN ||
+		    w->reg == TAPAN_A_TX_1_EN)
 			wcd9xxx_resmgr_notifier_call(&tapan->resmgr,
-						WCD9XXX_EVENT_PRE_TX_3_ON);
+						WCD9XXX_EVENT_PRE_TX_1_3_ON);
 		snd_soc_update_bits(codec, adc_reg, 1 << init_bit_shift,
 				1 << init_bit_shift);
 		break;
@@ -1879,9 +1914,10 @@
 
 		break;
 	case SND_SOC_DAPM_POST_PMD:
-		if (w->reg == TAPAN_A_TX_3_EN)
+		if (w->reg == TAPAN_A_TX_3_EN ||
+		    w->reg == TAPAN_A_TX_1_EN)
 			wcd9xxx_resmgr_notifier_call(&tapan->resmgr,
-						WCD9XXX_EVENT_POST_TX_3_OFF);
+						WCD9XXX_EVENT_POST_TX_1_3_OFF);
 		break;
 	}
 	return 0;
@@ -1992,8 +2028,15 @@
 	s32 *dmic_clk_cnt;
 	unsigned int dmic;
 	int ret;
+	char *srch = NULL;
 
-	ret = kstrtouint(strpbrk(w->name, "1234"), 10, &dmic);
+	srch = strpbrk(w->name, "1234");
+	if (srch == NULL) {
+		pr_err("%s: Invalid widget name %s\n", __func__, w->name);
+		return -EINVAL;
+	}
+
+	ret = kstrtouint(srch, 10, &dmic);
 	if (ret < 0) {
 		pr_err("%s: Invalid DMIC line on the codec\n", __func__);
 		return -EINVAL;
@@ -2261,16 +2304,23 @@
 }
 
 /* called under codec_resource_lock acquisition */
-static int tapan_enable_mbhc_micbias(struct snd_soc_codec *codec, bool enable)
+static int tapan_enable_mbhc_micbias(struct snd_soc_codec *codec, bool enable,
+				     enum wcd9xxx_micbias_num micb_num)
 {
 	int rc;
+	const char *micbias;
+
+	if (micb_num == MBHC_MICBIAS2)
+		micbias = DAPM_MICBIAS2_EXTERNAL_STANDALONE;
+	else
+		return -EINVAL;
 
 	if (enable)
 		rc = snd_soc_dapm_force_enable_pin(&codec->dapm,
-					     DAPM_MICBIAS2_EXTERNAL_STANDALONE);
+						   micbias);
 	else
 		rc = snd_soc_dapm_disable_pin(&codec->dapm,
-					     DAPM_MICBIAS2_EXTERNAL_STANDALONE);
+					      micbias);
 	if (!rc)
 		snd_soc_dapm_sync(&codec->dapm);
 	pr_debug("%s: leave ret %d\n", __func__, rc);
@@ -2318,6 +2368,7 @@
 	u16 dec_reset_reg, tx_vol_ctl_reg, tx_mux_ctl_reg;
 	u8 dec_hpf_cut_of_freq;
 	int offset;
+	char *srch = NULL;
 
 	dev_dbg(codec->dev, "%s %d\n", __func__, event);
 
@@ -2333,8 +2384,12 @@
 		ret =  -EINVAL;
 		goto out;
 	}
-
-	ret = kstrtouint(strpbrk(dec_name, "123456789"), 10, &decimator);
+	srch = strpbrk(dec_name, "123456789");
+	if (srch == NULL) {
+		pr_err("%s: Invalid decimator name %s\n", __func__, dec_name);
+		return -EINVAL;
+	}
+	ret = kstrtouint(srch, 10, &decimator);
 	if (ret < 0) {
 		pr_err("%s: Invalid decimator = %s\n", __func__, dec_name);
 		ret =  -EINVAL;
@@ -2464,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)
 {
@@ -3206,6 +3284,8 @@
 }
 
 #define TAPAN_FORMATS (SNDRV_PCM_FMTBIT_S16_LE)
+#define TAPAN_FORMATS_S16_S24_LE (SNDRV_PCM_FMTBIT_S16_LE | \
+				  SNDRV_PCM_FORMAT_S24_LE)
 static int tapan_write(struct snd_soc_codec *codec, unsigned int reg,
 	unsigned int value)
 {
@@ -3276,7 +3356,7 @@
 	dev_dbg(dai->codec->dev, "%s(): substream = %s  stream = %d\n",
 		 __func__, substream->name, substream->stream);
 
-	if (dai->id <= NUM_CODEC_DAIS) {
+	if (dai->id < NUM_CODEC_DAIS) {
 		if (tapan->dai[dai->id].ch_mask) {
 			active = 1;
 			dev_dbg(dai->codec->dev, "%s(): Codec DAI: chmask[%d] = 0x%lx\n",
@@ -3395,7 +3475,7 @@
 {
 	struct tapan_priv *tapan = snd_soc_codec_get_drvdata(dai->codec);
 	struct wcd9xxx *core = dev_get_drvdata(dai->codec->dev->parent);
-	if (!tx_slot && !rx_slot) {
+	if (!tx_slot || !rx_slot) {
 		pr_err("%s: Invalid\n", __func__);
 		return -EINVAL;
 	}
@@ -3613,6 +3693,68 @@
 	return 0;
 }
 
+static void tapan_set_rxsb_port_format(struct snd_pcm_hw_params *params,
+				       struct snd_soc_dai *dai)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	struct tapan_priv *tapan_p = snd_soc_codec_get_drvdata(codec);
+	struct wcd9xxx_codec_dai_data *cdc_dai;
+	struct wcd9xxx_ch *ch;
+	int port;
+	u8 bit_sel;
+	u16 sb_ctl_reg, field_shift;
+
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S16_LE:
+		bit_sel = 0x2;
+		tapan_p->dai[dai->id].bit_width = 16;
+		break;
+	case SNDRV_PCM_FORMAT_S24_LE:
+		bit_sel = 0x0;
+		tapan_p->dai[dai->id].bit_width = 24;
+		break;
+	default:
+		dev_err(codec->dev, "Invalid format %x\n",
+			params_format(params));
+		return;
+	}
+
+	cdc_dai = &tapan_p->dai[dai->id];
+
+	list_for_each_entry(ch, &cdc_dai->wcd9xxx_ch_list, list) {
+		port = wcd9xxx_get_slave_port(ch->ch_num);
+
+		if (IS_ERR_VALUE(port) ||
+		    !TAPAN_VALIDATE_RX_SBPORT_RANGE(port)) {
+			dev_warn(codec->dev,
+				 "%s: invalid port ID %d returned for RX DAI\n",
+				 __func__, port);
+			return;
+		}
+
+		port = TAPAN_CONVERT_RX_SBPORT_ID(port);
+
+		if (port <= 3) {
+			sb_ctl_reg = TAPAN_A_CDC_CONN_RX_SB_B1_CTL;
+			field_shift = port << 1;
+		} else if (port <= 4) {
+			sb_ctl_reg = TAPAN_A_CDC_CONN_RX_SB_B2_CTL;
+			field_shift = (port - 4) << 1;
+		} else { /* should not happen */
+			dev_warn(codec->dev,
+				 "%s: bad port ID %d\n", __func__, port);
+			return;
+		}
+
+		dev_dbg(codec->dev, "%s: sb_ctl_reg %x field_shift %x\n"
+			"bit_sel %x\n", __func__, sb_ctl_reg, field_shift,
+			bit_sel);
+		snd_soc_update_bits(codec, sb_ctl_reg, 0x3 << field_shift,
+				    bit_sel << field_shift);
+	}
+}
+
+
 static int tapan_hw_params(struct snd_pcm_substream *substream,
 			    struct snd_pcm_hw_params *params,
 			    struct snd_soc_dai *dai)
@@ -3725,29 +3867,7 @@
 			snd_soc_update_bits(codec, TAPAN_A_CDC_CLK_I2S_CTL,
 					    0x03, (rx_fs_rate >> 0x05));
 		} else {
-			switch (params_format(params)) {
-			case SNDRV_PCM_FORMAT_S16_LE:
-				snd_soc_update_bits(codec,
-					TAPAN_A_CDC_CONN_RX_SB_B1_CTL,
-					0xFF, 0xAA);
-				snd_soc_update_bits(codec,
-					TAPAN_A_CDC_CONN_RX_SB_B2_CTL,
-					0xFF, 0x2A);
-				tapan->dai[dai->id].bit_width = 16;
-				break;
-			case SNDRV_PCM_FORMAT_S24_LE:
-				snd_soc_update_bits(codec,
-					TAPAN_A_CDC_CONN_RX_SB_B1_CTL,
-					0xFF, 0x00);
-				snd_soc_update_bits(codec,
-					TAPAN_A_CDC_CONN_RX_SB_B2_CTL,
-					0xFF, 0x00);
-				tapan->dai[dai->id].bit_width = 24;
-				break;
-			default:
-				dev_err(codec->dev, "Invalid format\n");
-				break;
-			}
+			tapan_set_rxsb_port_format(params, dai);
 			tapan->dai[dai->id].rate   = params_rate(params);
 		}
 		break;
@@ -3864,7 +3984,7 @@
 		.playback = {
 			.stream_name = "AIF1 Playback",
 			.rates = WCD9306_RATES,
-			.formats = TAPAN_FORMATS,
+			.formats = TAPAN_FORMATS_S16_S24_LE,
 			.rate_max = 192000,
 			.rate_min = 8000,
 			.channels_min = 1,
@@ -3892,7 +4012,7 @@
 		.playback = {
 			.stream_name = "AIF2 Playback",
 			.rates = WCD9306_RATES,
-			.formats = TAPAN_FORMATS,
+			.formats = TAPAN_FORMATS_S16_S24_LE,
 			.rate_min = 8000,
 			.rate_max = 192000,
 			.channels_min = 1,
@@ -3934,7 +4054,7 @@
 		.playback = {
 			.stream_name = "AIF3 Playback",
 			.rates = WCD9306_RATES,
-			.formats = TAPAN_FORMATS,
+			.formats = TAPAN_FORMATS_S16_S24_LE,
 			.rate_min = 8000,
 			.rate_max = 192000,
 			.channels_min = 1,
@@ -4034,6 +4154,7 @@
 
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMU:
+		dai->bus_down_in_recovery = false;
 		(void) tapan_codec_enable_slim_chmask(dai, true);
 		ret = wcd9xxx_cfg_slim_sch_rx(core, &dai->wcd9xxx_ch_list,
 					      dai->rate, dai->bit_width,
@@ -4042,7 +4163,8 @@
 	case SND_SOC_DAPM_POST_PMD:
 		ret = wcd9xxx_close_slim_sch_rx(core, &dai->wcd9xxx_ch_list,
 						dai->grph);
-		ret = tapan_codec_enable_slim_chmask(dai, false);
+		if (!dai->bus_down_in_recovery)
+			ret = tapan_codec_enable_slim_chmask(dai, false);
 		if (ret < 0) {
 			ret = wcd9xxx_disconnect_port(core,
 						      &dai->wcd9xxx_ch_list,
@@ -4057,6 +4179,7 @@
 			pm_runtime_put(core->dev->parent);
 			dev_dbg(codec->dev, "%s: unvote requested", __func__);
 		}
+		dai->bus_down_in_recovery = false;
 		break;
 	}
 	return ret;
@@ -4088,6 +4211,7 @@
 	dai = &tapan_p->dai[w->shift];
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMU:
+		dai->bus_down_in_recovery = false;
 		(void) tapan_codec_enable_slim_chmask(dai, true);
 		ret = wcd9xxx_cfg_slim_sch_tx(core, &dai->wcd9xxx_ch_list,
 					      dai->rate, dai->bit_width,
@@ -4096,7 +4220,8 @@
 	case SND_SOC_DAPM_POST_PMD:
 		ret = wcd9xxx_close_slim_sch_tx(core, &dai->wcd9xxx_ch_list,
 						dai->grph);
-		ret = tapan_codec_enable_slim_chmask(dai, false);
+		if (!dai->bus_down_in_recovery)
+			ret = tapan_codec_enable_slim_chmask(dai, false);
 		if (ret < 0) {
 			ret = wcd9xxx_disconnect_port(core,
 						      &dai->wcd9xxx_ch_list,
@@ -4111,6 +4236,7 @@
 			pm_runtime_put(core->dev->parent);
 			dev_dbg(codec->dev, "%s: unvote requested", __func__);
 		}
+		dai->bus_down_in_recovery = false;
 		break;
 	}
 	return ret;
@@ -4164,6 +4290,23 @@
 	return 0;
 }
 
+static int tapan_codec_iir_mux_event(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = w->codec;
+	pr_debug("%s: event = %d\n", __func__, event);
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		snd_soc_write(codec, w->reg, snd_soc_read(codec, w->reg));
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		snd_soc_write(codec, w->reg, snd_soc_read(codec, w->reg));
+		break;
+	}
+	return 0;
+}
+
 static int tapan_codec_dsm_mux_event(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
@@ -4414,7 +4557,7 @@
 	SND_SOC_DAPM_MUX("RX3 MIX1 INP2", SND_SOC_NOPM, 0, 0,
 		&rx3_mix1_inp2_mux),
 	SND_SOC_DAPM_MUX("RX3 MIX1 INP3", SND_SOC_NOPM, 0, 0,
-		&rx3_mix1_inp2_mux),
+		&rx3_mix1_inp3_mux),
 
 	/* RX1 MIX2 mux inputs */
 	SND_SOC_DAPM_MUX("RX1 MIX2 INP1", SND_SOC_NOPM, 0, 0,
@@ -4443,8 +4586,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,
@@ -4651,7 +4796,10 @@
 		SND_SOC_DAPM_POST_PMD),
 
 	/* Sidetone */
-	SND_SOC_DAPM_MUX("IIR1 INP1 MUX", SND_SOC_NOPM, 0, 0, &iir1_inp1_mux),
+	SND_SOC_DAPM_MUX_E("IIR1 INP1 MUX", TAPAN_A_CDC_IIR1_GAIN_B1_CTL, 0, 0,
+		&iir1_inp1_mux, tapan_codec_iir_mux_event,
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
 	SND_SOC_DAPM_PGA("IIR1", TAPAN_A_CDC_CLK_SD_CTL, 0, 0, NULL, 0),
 
 	/* AUX PGA */
@@ -4752,9 +4900,9 @@
 	struct snd_soc_codec *codec = tapan->codec;
 	struct wcd9xxx_pdata *pdata = tapan->resmgr.pdata;
 	int k1, k2, k3, rc = 0;
-	u8 txfe_bypass = pdata->amic_settings.txfe_enable;
-	u8 txfe_buff = pdata->amic_settings.txfe_buff;
-	u8 flag = pdata->amic_settings.use_pdata;
+	u8 txfe_bypass;
+	u8 txfe_buff;
+	u8 flag;
 	u8 i = 0, j = 0;
 	u8 val_txfe = 0, value = 0;
 	u8 dmic_sample_rate_value = 0;
@@ -4766,6 +4914,9 @@
 		rc = -ENODEV;
 		goto done;
 	}
+	txfe_bypass = pdata->amic_settings.txfe_enable;
+	txfe_buff = pdata->amic_settings.txfe_buff;
+	flag = pdata->amic_settings.use_pdata;
 
 	/* Make sure settings are correct */
 	if ((pdata->micbias.ldoh_v > WCD9XXX_LDOH_3P0_V) ||
@@ -4944,7 +5095,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),
@@ -5493,7 +5644,8 @@
 				mux_wait_us + WCD9XXX_USLEEP_RANGE_MARGIN_US);
 		break;
 	case PA_DISABLE:
-		wcd9xxx_enable_static_pa(mbhc, false);
+		if (!mbhc->hph_pa_dac_state)
+			wcd9xxx_enable_static_pa(mbhc, false);
 		wcd9xxx_restore_registers(codec, &tapan->reg_save_restore);
 		break;
 	}
@@ -5586,6 +5738,7 @@
 	int rco_clk_rate;
 	struct snd_soc_codec *codec;
 	struct tapan_priv *tapan;
+	int count;
 
 	codec = (struct snd_soc_codec *)(wcd9xxx->ssr_priv);
 	tapan = snd_soc_codec_get_drvdata(codec);
@@ -5642,6 +5795,9 @@
 
 	tapan->machine_codec_event_cb(codec, WCD9XXX_CODEC_EVENT_CODEC_UP);
 
+	for (count = 0; count < NUM_CODEC_DAIS; count++)
+		tapan->dai[count].bus_down_in_recovery = true;
+
 	mutex_unlock(&codec->mutex);
 	return ret;
 }
@@ -5665,7 +5821,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/wcd9310.c b/sound/soc/codecs/wcd9310.c
index 725c51f..727a6d6 100644
--- a/sound/soc/codecs/wcd9310.c
+++ b/sound/soc/codecs/wcd9310.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
@@ -2032,7 +2032,7 @@
 			if (wcd9xxx_tx_vport_validation(
 						vtable,
 						port_id,
-						tabla_p->dai)) {
+						tabla_p->dai, NUM_CODEC_DAIS)) {
 				dev_dbg(codec->dev, "%s: TX%u is used by other virtual port\n",
 					__func__, port_id + 1);
 				mutex_unlock(&codec->mutex);
diff --git a/sound/soc/codecs/wcd9320.c b/sound/soc/codecs/wcd9320.c
index f874c43..4c5d327 100644
--- a/sound/soc/codecs/wcd9320.c
+++ b/sound/soc/codecs/wcd9320.c
@@ -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
@@ -48,6 +48,7 @@
 #define TAIKO_HPH_PA_SETTLE_COMP_OFF 13000
 
 #define DAPM_MICBIAS2_EXTERNAL_STANDALONE "MIC BIAS2 External Standalone"
+#define DAPM_MICBIAS3_EXTERNAL_STANDALONE "MIC BIAS3 External Standalone"
 
 /* RX_HPH_CNP_WG_TIME increases by 0.24ms */
 #define TAIKO_WG_TIME_FACTOR_US	240
@@ -1129,6 +1130,24 @@
 static const struct snd_kcontrol_new class_h_dsm_mux =
 	SOC_DAPM_ENUM("CLASS_H_DSM MUX Mux", class_h_dsm_enum);
 
+static const char * const rx1_interpolator_text[] = {
+	"ZERO", "RX1 MIX2"
+};
+static const struct soc_enum rx1_interpolator_enum =
+	SOC_ENUM_SINGLE(TAIKO_A_CDC_CLK_RX_B1_CTL, 0, 2, rx1_interpolator_text);
+
+static const struct snd_kcontrol_new rx1_interpolator =
+	SOC_DAPM_ENUM("RX1 INTERP Mux", rx1_interpolator_enum);
+
+static const char * const rx2_interpolator_text[] = {
+	"ZERO", "RX2 MIX2"
+};
+static const struct soc_enum rx2_interpolator_enum =
+	SOC_ENUM_SINGLE(TAIKO_A_CDC_CLK_RX_B1_CTL, 1, 2, rx2_interpolator_text);
+
+static const struct snd_kcontrol_new rx2_interpolator =
+	SOC_DAPM_ENUM("RX2 INTERP Mux", rx2_interpolator_enum);
+
 static const char *const taiko_conn_mad_text[] = {
 	"ADC_MB", "ADC1", "ADC2", "ADC3", "ADC4", "ADC5", "ADC6", "NOTUSED1",
 	"DMIC1", "DMIC2", "DMIC3", "DMIC4", "DMIC5", "DMIC6", "NOTUSED2",
@@ -1651,6 +1670,21 @@
 	"DEC9", "DEC10", "RX1", "RX2", "RX3", "RX4", "RX5", "RX6", "RX7"
 };
 
+static const char * const iir_inp2_text[] = {
+	"ZERO", "DEC1", "DEC2", "DEC3", "DEC4", "DEC5", "DEC6", "DEC7", "DEC8",
+	"DEC9", "DEC10", "RX1", "RX2", "RX3", "RX4", "RX5", "RX6", "RX7"
+};
+
+static const char * const iir_inp3_text[] = {
+	"ZERO", "DEC1", "DEC2", "DEC3", "DEC4", "DEC5", "DEC6", "DEC7", "DEC8",
+	"DEC9", "DEC10", "RX1", "RX2", "RX3", "RX4", "RX5", "RX6", "RX7"
+};
+
+static const char * const iir_inp4_text[] = {
+	"ZERO", "DEC1", "DEC2", "DEC3", "DEC4", "DEC5", "DEC6", "DEC7", "DEC8",
+	"DEC9", "DEC10", "RX1", "RX2", "RX3", "RX4", "RX5", "RX6", "RX7"
+};
+
 static const struct soc_enum rx_mix1_inp1_chain_enum =
 	SOC_ENUM_SINGLE(TAIKO_A_CDC_CONN_RX1_B1_CTL, 0, 12, rx_mix1_text);
 
@@ -1799,6 +1833,24 @@
 static const struct soc_enum iir2_inp1_mux_enum =
 	SOC_ENUM_SINGLE(TAIKO_A_CDC_CONN_EQ2_B1_CTL, 0, 18, iir_inp1_text);
 
+static const struct soc_enum iir1_inp2_mux_enum =
+	SOC_ENUM_SINGLE(TAIKO_A_CDC_CONN_EQ1_B2_CTL, 0, 18, iir_inp2_text);
+
+static const struct soc_enum iir2_inp2_mux_enum =
+	SOC_ENUM_SINGLE(TAIKO_A_CDC_CONN_EQ2_B2_CTL, 0, 18, iir_inp2_text);
+
+static const struct soc_enum iir1_inp3_mux_enum =
+	SOC_ENUM_SINGLE(TAIKO_A_CDC_CONN_EQ1_B3_CTL, 0, 18, iir_inp3_text);
+
+static const struct soc_enum iir2_inp3_mux_enum =
+	SOC_ENUM_SINGLE(TAIKO_A_CDC_CONN_EQ2_B3_CTL, 0, 18, iir_inp3_text);
+
+static const struct soc_enum iir1_inp4_mux_enum =
+	SOC_ENUM_SINGLE(TAIKO_A_CDC_CONN_EQ1_B4_CTL, 0, 18, iir_inp4_text);
+
+static const struct soc_enum iir2_inp4_mux_enum =
+	SOC_ENUM_SINGLE(TAIKO_A_CDC_CONN_EQ2_B4_CTL, 0, 18, iir_inp4_text);
+
 static const struct snd_kcontrol_new rx_mix1_inp1_mux =
 	SOC_DAPM_ENUM("RX1 MIX1 INP1 Mux", rx_mix1_inp1_chain_enum);
 
@@ -2024,6 +2076,24 @@
 static const struct snd_kcontrol_new iir2_inp1_mux =
 	SOC_DAPM_ENUM("IIR2 INP1 Mux", iir2_inp1_mux_enum);
 
+static const struct snd_kcontrol_new iir1_inp2_mux =
+	SOC_DAPM_ENUM("IIR1 INP2 Mux", iir1_inp2_mux_enum);
+
+static const struct snd_kcontrol_new iir2_inp2_mux =
+	SOC_DAPM_ENUM("IIR2 INP2 Mux", iir2_inp2_mux_enum);
+
+static const struct snd_kcontrol_new iir1_inp3_mux =
+	SOC_DAPM_ENUM("IIR1 INP3 Mux", iir1_inp3_mux_enum);
+
+static const struct snd_kcontrol_new iir2_inp3_mux =
+	SOC_DAPM_ENUM("IIR2 INP3 Mux", iir2_inp3_mux_enum);
+
+static const struct snd_kcontrol_new iir1_inp4_mux =
+	SOC_DAPM_ENUM("IIR1 INP4 Mux", iir1_inp4_mux_enum);
+
+static const struct snd_kcontrol_new iir2_inp4_mux =
+	SOC_DAPM_ENUM("IIR2 INP4 Mux", iir2_inp4_mux_enum);
+
 static const struct snd_kcontrol_new anc1_mux =
 	SOC_DAPM_ENUM("ANC1 MUX Mux", anc1_mux_enum);
 
@@ -2142,7 +2212,7 @@
 				if (wcd9xxx_tx_vport_validation(
 						vtable,
 						port_id,
-						taiko_p->dai)) {
+						taiko_p->dai, NUM_CODEC_DAIS)) {
 					dev_dbg(codec->dev, "%s: TX%u is used by other virtual port\n",
 						__func__, port_id + 1);
 					mutex_unlock(&codec->mutex);
@@ -2823,16 +2893,26 @@
 }
 
 /* called under codec_resource_lock acquisition */
-static int taiko_enable_mbhc_micbias(struct snd_soc_codec *codec, bool enable)
+static int taiko_enable_mbhc_micbias(struct snd_soc_codec *codec, bool enable,
+				     enum wcd9xxx_micbias_num micb_num)
 {
 	int rc;
+	const char *micbias;
+
+	if (micb_num != MBHC_MICBIAS3 &&
+	    micb_num != MBHC_MICBIAS2)
+		return -EINVAL;
+
+	micbias = (micb_num == MBHC_MICBIAS3) ?
+			DAPM_MICBIAS3_EXTERNAL_STANDALONE :
+			DAPM_MICBIAS2_EXTERNAL_STANDALONE;
 
 	if (enable)
 		rc = snd_soc_dapm_force_enable_pin(&codec->dapm,
-					     DAPM_MICBIAS2_EXTERNAL_STANDALONE);
+					     micbias);
 	else
 		rc = snd_soc_dapm_disable_pin(&codec->dapm,
-					     DAPM_MICBIAS2_EXTERNAL_STANDALONE);
+					     micbias);
 	if (!rc)
 		snd_soc_dapm_sync(&codec->dapm);
 	pr_debug("%s: leave ret %d\n", __func__, rc);
@@ -3179,6 +3259,7 @@
 	case SND_SOC_DAPM_POST_PMD:
 		snd_soc_update_bits(codec, TAIKO_A_CDC_CLK_RDAC_CLK_EN_CTL,
 							0x02, 0x00);
+		break;
 	}
 	return 0;
 }
@@ -3681,8 +3762,11 @@
 
 	{"CLASS_H_DSM MUX", "DSM_HPHL_RX1", "RX1 CHAIN"},
 
-	{"RX1 CHAIN", NULL, "RX1 MIX2"},
-	{"RX2 CHAIN", NULL, "RX2 MIX2"},
+	{"RX1 INTERP", NULL, "RX1 MIX2"},
+	{"RX1 CHAIN", NULL, "RX1 INTERP"},
+	{"RX2 INTERP", NULL, "RX2 MIX2"},
+	{"RX2 CHAIN", NULL, "RX2 INTERP"},
+
 	{"RX1 MIX2", NULL, "ANC1 MUX"},
 	{"RX2 MIX2", NULL, "ANC2 MUX"},
 
@@ -4001,6 +4085,120 @@
 	{"IIR2 INP1 MUX", "RX6", "SLIM RX6"},
 	{"IIR2 INP1 MUX", "RX7", "SLIM RX7"},
 
+	{"IIR1", NULL, "IIR1 INP2 MUX"},
+	{"IIR1 INP2 MUX", "DEC1", "DEC1 MUX"},
+	{"IIR1 INP2 MUX", "DEC2", "DEC2 MUX"},
+	{"IIR1 INP2 MUX", "DEC3", "DEC3 MUX"},
+	{"IIR1 INP2 MUX", "DEC4", "DEC4 MUX"},
+	{"IIR1 INP2 MUX", "DEC5", "DEC5 MUX"},
+	{"IIR1 INP2 MUX", "DEC6", "DEC6 MUX"},
+	{"IIR1 INP2 MUX", "DEC7", "DEC7 MUX"},
+	{"IIR1 INP2 MUX", "DEC8", "DEC8 MUX"},
+	{"IIR1 INP2 MUX", "DEC9", "DEC9 MUX"},
+	{"IIR1 INP2 MUX", "DEC10", "DEC10 MUX"},
+	{"IIR1 INP2 MUX", "RX1", "SLIM RX1"},
+	{"IIR1 INP2 MUX", "RX2", "SLIM RX2"},
+	{"IIR1 INP2 MUX", "RX3", "SLIM RX3"},
+	{"IIR1 INP2 MUX", "RX4", "SLIM RX4"},
+	{"IIR1 INP2 MUX", "RX5", "SLIM RX5"},
+	{"IIR1 INP2 MUX", "RX6", "SLIM RX6"},
+	{"IIR1 INP2 MUX", "RX7", "SLIM RX7"},
+
+	{"IIR2", NULL, "IIR2 INP2 MUX"},
+	{"IIR2 INP2 MUX", "DEC1", "DEC1 MUX"},
+	{"IIR2 INP2 MUX", "DEC2", "DEC2 MUX"},
+	{"IIR2 INP2 MUX", "DEC3", "DEC3 MUX"},
+	{"IIR2 INP2 MUX", "DEC4", "DEC4 MUX"},
+	{"IIR2 INP2 MUX", "DEC5", "DEC5 MUX"},
+	{"IIR2 INP2 MUX", "DEC6", "DEC6 MUX"},
+	{"IIR2 INP2 MUX", "DEC7", "DEC7 MUX"},
+	{"IIR2 INP2 MUX", "DEC8", "DEC8 MUX"},
+	{"IIR2 INP2 MUX", "DEC9", "DEC9 MUX"},
+	{"IIR2 INP2 MUX", "DEC10", "DEC10 MUX"},
+	{"IIR2 INP2 MUX", "RX1", "SLIM RX1"},
+	{"IIR2 INP2 MUX", "RX2", "SLIM RX2"},
+	{"IIR2 INP2 MUX", "RX3", "SLIM RX3"},
+	{"IIR2 INP2 MUX", "RX4", "SLIM RX4"},
+	{"IIR2 INP2 MUX", "RX5", "SLIM RX5"},
+	{"IIR2 INP2 MUX", "RX6", "SLIM RX6"},
+	{"IIR2 INP2 MUX", "RX7", "SLIM RX7"},
+
+	{"IIR1", NULL, "IIR1 INP3 MUX"},
+	{"IIR1 INP3 MUX", "DEC1", "DEC1 MUX"},
+	{"IIR1 INP3 MUX", "DEC2", "DEC2 MUX"},
+	{"IIR1 INP3 MUX", "DEC3", "DEC3 MUX"},
+	{"IIR1 INP3 MUX", "DEC4", "DEC4 MUX"},
+	{"IIR1 INP3 MUX", "DEC5", "DEC5 MUX"},
+	{"IIR1 INP3 MUX", "DEC6", "DEC6 MUX"},
+	{"IIR1 INP3 MUX", "DEC7", "DEC7 MUX"},
+	{"IIR1 INP3 MUX", "DEC8", "DEC8 MUX"},
+	{"IIR1 INP3 MUX", "DEC9", "DEC9 MUX"},
+	{"IIR1 INP3 MUX", "DEC10", "DEC10 MUX"},
+	{"IIR1 INP3 MUX", "RX1", "SLIM RX1"},
+	{"IIR1 INP3 MUX", "RX2", "SLIM RX2"},
+	{"IIR1 INP3 MUX", "RX3", "SLIM RX3"},
+	{"IIR1 INP3 MUX", "RX4", "SLIM RX4"},
+	{"IIR1 INP3 MUX", "RX5", "SLIM RX5"},
+	{"IIR1 INP3 MUX", "RX6", "SLIM RX6"},
+	{"IIR1 INP3 MUX", "RX7", "SLIM RX7"},
+
+	{"IIR2", NULL, "IIR2 INP3 MUX"},
+	{"IIR2 INP3 MUX", "DEC1", "DEC1 MUX"},
+	{"IIR2 INP3 MUX", "DEC2", "DEC2 MUX"},
+	{"IIR2 INP3 MUX", "DEC3", "DEC3 MUX"},
+	{"IIR2 INP3 MUX", "DEC4", "DEC4 MUX"},
+	{"IIR2 INP3 MUX", "DEC5", "DEC5 MUX"},
+	{"IIR2 INP3 MUX", "DEC6", "DEC6 MUX"},
+	{"IIR2 INP3 MUX", "DEC7", "DEC7 MUX"},
+	{"IIR2 INP3 MUX", "DEC8", "DEC8 MUX"},
+	{"IIR2 INP3 MUX", "DEC9", "DEC9 MUX"},
+	{"IIR2 INP3 MUX", "DEC10", "DEC10 MUX"},
+	{"IIR2 INP3 MUX", "RX1", "SLIM RX1"},
+	{"IIR2 INP3 MUX", "RX2", "SLIM RX2"},
+	{"IIR2 INP3 MUX", "RX3", "SLIM RX3"},
+	{"IIR2 INP3 MUX", "RX4", "SLIM RX4"},
+	{"IIR2 INP3 MUX", "RX5", "SLIM RX5"},
+	{"IIR2 INP3 MUX", "RX6", "SLIM RX6"},
+	{"IIR2 INP3 MUX", "RX7", "SLIM RX7"},
+
+	{"IIR1", NULL, "IIR1 INP4 MUX"},
+	{"IIR1 INP4 MUX", "DEC1", "DEC1 MUX"},
+	{"IIR1 INP4 MUX", "DEC2", "DEC2 MUX"},
+	{"IIR1 INP4 MUX", "DEC3", "DEC3 MUX"},
+	{"IIR1 INP4 MUX", "DEC4", "DEC4 MUX"},
+	{"IIR1 INP4 MUX", "DEC5", "DEC5 MUX"},
+	{"IIR1 INP4 MUX", "DEC6", "DEC6 MUX"},
+	{"IIR1 INP4 MUX", "DEC7", "DEC7 MUX"},
+	{"IIR1 INP4 MUX", "DEC8", "DEC8 MUX"},
+	{"IIR1 INP4 MUX", "DEC9", "DEC9 MUX"},
+	{"IIR1 INP4 MUX", "DEC10", "DEC10 MUX"},
+	{"IIR1 INP4 MUX", "RX1", "SLIM RX1"},
+	{"IIR1 INP4 MUX", "RX2", "SLIM RX2"},
+	{"IIR1 INP4 MUX", "RX3", "SLIM RX3"},
+	{"IIR1 INP4 MUX", "RX4", "SLIM RX4"},
+	{"IIR1 INP4 MUX", "RX5", "SLIM RX5"},
+	{"IIR1 INP4 MUX", "RX6", "SLIM RX6"},
+	{"IIR1 INP4 MUX", "RX7", "SLIM RX7"},
+
+	{"IIR2", NULL, "IIR2 INP4 MUX"},
+	{"IIR2 INP4 MUX", "DEC1", "DEC1 MUX"},
+	{"IIR2 INP4 MUX", "DEC2", "DEC2 MUX"},
+	{"IIR2 INP4 MUX", "DEC3", "DEC3 MUX"},
+	{"IIR2 INP4 MUX", "DEC4", "DEC4 MUX"},
+	{"IIR2 INP4 MUX", "DEC5", "DEC5 MUX"},
+	{"IIR2 INP4 MUX", "DEC6", "DEC6 MUX"},
+	{"IIR2 INP4 MUX", "DEC7", "DEC7 MUX"},
+	{"IIR2 INP4 MUX", "DEC8", "DEC8 MUX"},
+	{"IIR2 INP4 MUX", "DEC9", "DEC9 MUX"},
+	{"IIR2 INP4 MUX", "DEC10", "DEC10 MUX"},
+	{"IIR2 INP4 MUX", "RX1", "SLIM RX1"},
+	{"IIR2 INP4 MUX", "RX2", "SLIM RX2"},
+	{"IIR2 INP4 MUX", "RX3", "SLIM RX3"},
+	{"IIR2 INP4 MUX", "RX4", "SLIM RX4"},
+	{"IIR2 INP4 MUX", "RX5", "SLIM RX5"},
+	{"IIR2 INP4 MUX", "RX6", "SLIM RX6"},
+	{"IIR2 INP4 MUX", "RX7", "SLIM RX7"},
+
 	{"MIC BIAS1 Internal1", NULL, "LDO_H"},
 	{"MIC BIAS1 Internal2", NULL, "LDO_H"},
 	{"MIC BIAS1 External", NULL, "LDO_H"},
@@ -4013,6 +4211,7 @@
 	{"MIC BIAS3 External", NULL, "LDO_H"},
 	{"MIC BIAS4 External", NULL, "LDO_H"},
 	{DAPM_MICBIAS2_EXTERNAL_STANDALONE, NULL, "LDO_H Standalone"},
+	{DAPM_MICBIAS3_EXTERNAL_STANDALONE, NULL, "LDO_H Standalone"},
 };
 
 static int taiko_readable(struct snd_soc_codec *ssc, unsigned int reg)
@@ -4083,6 +4282,10 @@
 	if (reg == TAIKO_A_RX_HPH_L_STATUS || reg == TAIKO_A_RX_HPH_R_STATUS)
 		return 1;
 
+	/* HPH PA Enable */
+	if (reg == TAIKO_A_RX_HPH_CNP_EN)
+		return 1;
+
 	if (reg == TAIKO_A_MBHC_INSERT_DET_STATUS)
 		return 1;
 
@@ -4157,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;
 }
@@ -4171,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)
@@ -4953,6 +5144,7 @@
 
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMU:
+		dai->bus_down_in_recovery = false;
 		taiko_codec_enable_int_port(dai, codec);
 		(void) taiko_codec_enable_slim_chmask(dai, true);
 		ret = wcd9xxx_cfg_slim_sch_rx(core, &dai->wcd9xxx_ch_list,
@@ -4962,7 +5154,9 @@
 	case SND_SOC_DAPM_POST_PMD:
 		ret = wcd9xxx_close_slim_sch_rx(core, &dai->wcd9xxx_ch_list,
 						dai->grph);
-		ret = taiko_codec_enable_slim_chmask(dai, false);
+		if (!dai->bus_down_in_recovery)
+			ret = taiko_codec_enable_slim_chmask(dai, false);
+
 		if (ret < 0) {
 			ret = wcd9xxx_disconnect_port(core,
 						      &dai->wcd9xxx_ch_list,
@@ -4970,6 +5164,7 @@
 			pr_debug("%s: Disconnect RX port, ret = %d\n",
 				 __func__, ret);
 		}
+		dai->bus_down_in_recovery = false;
 		break;
 	}
 	return ret;
@@ -5019,6 +5214,7 @@
 		snd_soc_update_bits(codec,
 		TAIKO_A_CDC_CLK_TX_CLK_EN_B2_CTL, 0xC, 0xC);
 		taiko_codec_enable_int_port(dai, codec);
+		dai->bus_down_in_recovery = false;
 		(void) taiko_codec_enable_slim_chmask(dai, true);
 		ret = wcd9xxx_cfg_slim_sch_tx(core, &dai->wcd9xxx_ch_list,
 					dai->rate, dai->bit_width,
@@ -5035,6 +5231,8 @@
 		/*Disable V&I sensing*/
 		snd_soc_update_bits(codec, TAIKO_A_SPKR_PROT_EN,
 				0x88, 0x00);
+
+		dai->bus_down_in_recovery = false;
 		break;
 	}
 out_vi:
@@ -5064,9 +5262,11 @@
 		__func__, w->name, event, w->shift);
 
 	dai = &taiko_p->dai[w->shift];
+
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMU:
 		taiko_codec_enable_int_port(dai, codec);
+		dai->bus_down_in_recovery = false;
 		(void) taiko_codec_enable_slim_chmask(dai, true);
 		ret = wcd9xxx_cfg_slim_sch_tx(core, &dai->wcd9xxx_ch_list,
 					      dai->rate, dai->bit_width,
@@ -5075,7 +5275,9 @@
 	case SND_SOC_DAPM_POST_PMD:
 		ret = wcd9xxx_close_slim_sch_tx(core, &dai->wcd9xxx_ch_list,
 						dai->grph);
-		ret = taiko_codec_enable_slim_chmask(dai, false);
+		if (!dai->bus_down_in_recovery)
+			ret = taiko_codec_enable_slim_chmask(dai, false);
+
 		if (ret < 0) {
 			ret = wcd9xxx_disconnect_port(core,
 						      &dai->wcd9xxx_ch_list,
@@ -5083,6 +5285,8 @@
 			pr_debug("%s: Disconnect RX port, ret = %d\n",
 				 __func__, ret);
 		}
+
+		dai->bus_down_in_recovery = false;
 		break;
 	}
 	return ret;
@@ -5135,6 +5339,24 @@
 	return 0;
 }
 
+static int taiko_codec_iir_mux_event(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = w->codec;
+
+	pr_debug("%s: event = %d\n", __func__, event);
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		snd_soc_write(codec, w->reg, snd_soc_read(codec, w->reg));
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		snd_soc_write(codec, w->reg, snd_soc_read(codec, w->reg));
+		break;
+	}
+	return 0;
+}
+
 static int taiko_codec_dsm_mux_event(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
@@ -5310,12 +5532,9 @@
 	SND_SOC_DAPM_MIXER("RX2 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
 	SND_SOC_DAPM_MIXER("RX7 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
 
-	SND_SOC_DAPM_MIXER_E("RX1 MIX2", TAIKO_A_CDC_CLK_RX_B1_CTL, 0, 0, NULL,
-		0, taiko_codec_enable_interpolator, SND_SOC_DAPM_PRE_PMU |
-		SND_SOC_DAPM_POST_PMU),
-	SND_SOC_DAPM_MIXER_E("RX2 MIX2", TAIKO_A_CDC_CLK_RX_B1_CTL, 1, 0, NULL,
-		0, taiko_codec_enable_interpolator, SND_SOC_DAPM_PRE_PMU |
-		SND_SOC_DAPM_POST_PMU),
+	SND_SOC_DAPM_MIXER("RX1 MIX2", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("RX2 MIX2", SND_SOC_NOPM, 0, 0, NULL, 0),
+
 	SND_SOC_DAPM_MIXER_E("RX3 MIX1", TAIKO_A_CDC_CLK_RX_B1_CTL, 2, 0, NULL,
 		0, taiko_codec_enable_interpolator, SND_SOC_DAPM_PRE_PMU |
 		SND_SOC_DAPM_POST_PMU),
@@ -5332,6 +5551,12 @@
 		0, taiko_codec_enable_interpolator, SND_SOC_DAPM_PRE_PMU |
 		SND_SOC_DAPM_POST_PMU),
 
+	SND_SOC_DAPM_MUX_E("RX1 INTERP", TAIKO_A_CDC_CLK_RX_B1_CTL, 0, 0,
+		&rx1_interpolator, taiko_codec_enable_interpolator,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
+	SND_SOC_DAPM_MUX_E("RX2 INTERP", TAIKO_A_CDC_CLK_RX_B1_CTL, 1, 0,
+		&rx2_interpolator, taiko_codec_enable_interpolator,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
 
 	SND_SOC_DAPM_MIXER("RX1 CHAIN", TAIKO_A_CDC_RX1_B6_CTL, 5, 0, NULL, 0),
 	SND_SOC_DAPM_MIXER("RX2 CHAIN", TAIKO_A_CDC_RX2_B6_CTL, 5, 0, NULL, 0),
@@ -5535,6 +5760,10 @@
 			       taiko_codec_enable_micbias,
 			       SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
 			       SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MICBIAS_E(DAPM_MICBIAS3_EXTERNAL_STANDALONE, SND_SOC_NOPM,
+			       7, 0, taiko_codec_enable_micbias,
+			       SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+			       SND_SOC_DAPM_POST_PMD),
 	SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 External", SND_SOC_NOPM, 7, 0,
 			       taiko_codec_enable_micbias,
 			       SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
@@ -5629,10 +5858,40 @@
 		SND_SOC_DAPM_POST_PMD),
 
 	/* Sidetone */
-	SND_SOC_DAPM_MUX("IIR1 INP1 MUX", SND_SOC_NOPM, 0, 0, &iir1_inp1_mux),
+	SND_SOC_DAPM_MUX_E("IIR1 INP1 MUX", TAIKO_A_CDC_IIR1_GAIN_B1_CTL, 0, 0,
+		&iir1_inp1_mux,  taiko_codec_iir_mux_event,
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_MUX_E("IIR1 INP2 MUX", TAIKO_A_CDC_IIR1_GAIN_B2_CTL, 0, 0,
+		&iir1_inp2_mux,  taiko_codec_iir_mux_event,
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_MUX_E("IIR1 INP3 MUX", TAIKO_A_CDC_IIR1_GAIN_B3_CTL, 0, 0,
+		&iir1_inp3_mux,  taiko_codec_iir_mux_event,
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_MUX_E("IIR1 INP4 MUX", TAIKO_A_CDC_IIR1_GAIN_B4_CTL, 0, 0,
+		&iir1_inp4_mux,  taiko_codec_iir_mux_event,
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
 	SND_SOC_DAPM_MIXER("IIR1", TAIKO_A_CDC_CLK_SD_CTL, 0, 0, NULL, 0),
 
-	SND_SOC_DAPM_MUX("IIR2 INP1 MUX", SND_SOC_NOPM, 0, 0, &iir2_inp1_mux),
+	SND_SOC_DAPM_MUX_E("IIR2 INP1 MUX", TAIKO_A_CDC_IIR2_GAIN_B1_CTL, 0, 0,
+		&iir2_inp1_mux,  taiko_codec_iir_mux_event,
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_MUX_E("IIR2 INP2 MUX", TAIKO_A_CDC_IIR2_GAIN_B2_CTL, 0, 0,
+		&iir2_inp2_mux,  taiko_codec_iir_mux_event,
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_MUX_E("IIR2 INP3 MUX", TAIKO_A_CDC_IIR2_GAIN_B3_CTL, 0, 0,
+		&iir2_inp3_mux,  taiko_codec_iir_mux_event,
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_MUX_E("IIR2 INP4 MUX", TAIKO_A_CDC_IIR2_GAIN_B4_CTL, 0, 0,
+		&iir2_inp4_mux,  taiko_codec_iir_mux_event,
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
 	SND_SOC_DAPM_MIXER("IIR2", TAIKO_A_CDC_CLK_SD_CTL, 1, 0, NULL, 0),
 
 	/* AUX PGA */
@@ -6239,6 +6498,9 @@
 
 	/* set MAD input MIC to DMIC1 */
 	{TAIKO_A_CDC_CONN_MAD, 0x0F, 0x08},
+
+	/* set DMIC CLK drive strength to 4mA */
+	{TAIKO_A_HDRIVE_OVERRIDE, 0x07, 0x01},
 };
 
 static void taiko_codec_init_reg(struct snd_soc_codec *codec)
@@ -6466,7 +6728,7 @@
 		__wr(WCD9XXX_A_CDC_MBHC_TIMER_B5_CTL, 0xFF, 0x10);
 		/* Reset MBHC and set it up for STA */
 		__wr(WCD9XXX_A_CDC_MBHC_CLK_CTL, 0xFF, 0x0A);
-		__wr(WCD9XXX_A_CDC_MBHC_EN_CTL, 0xFF, 0x02);
+		snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_EN_CTL, 0x2);
 		__wr(WCD9XXX_A_CDC_MBHC_CLK_CTL, 0xFF, 0x02);
 
 		/* Set HPH_MBHC for zdet */
@@ -6497,7 +6759,8 @@
 		/* Clean up starts */
 		/* Turn off PA ramp generator */
 		snd_soc_write(codec, WCD9XXX_A_CDC_PA_RAMP_B1_CTL, 0x0);
-		wcd9xxx_enable_static_pa(mbhc, false);
+		if (!mbhc->hph_pa_dac_state)
+			wcd9xxx_enable_static_pa(mbhc, false);
 		wcd9xxx_restore_registers(codec, &taiko->reg_save_restore);
 		break;
 	}
@@ -6560,6 +6823,7 @@
 	struct snd_soc_codec *codec;
 	struct taiko_priv *taiko;
 	int rco_clk_rate;
+	int count;
 
 	codec = (struct snd_soc_codec *)(wcd9xxx->ssr_priv);
 	taiko = snd_soc_codec_get_drvdata(codec);
@@ -6567,18 +6831,21 @@
 	snd_soc_card_change_online_state(codec->card, 1);
 
 	mutex_lock(&codec->mutex);
-	if (codec->reg_def_copy) {
-		pr_debug("%s: Update ASOC cache", __func__);
-		kfree(codec->reg_cache);
-		codec->reg_cache = kmemdup(codec->reg_def_copy,
-						codec->reg_size, GFP_KERNEL);
-	}
+
+	taiko_update_reg_defaults(codec);
+	if (wcd9xxx->mclk_rate == TAIKO_MCLK_CLK_12P288MHZ)
+		snd_soc_update_bits(codec, TAIKO_A_CHIP_CTL, 0x06, 0x0);
+	else if (wcd9xxx->mclk_rate == TAIKO_MCLK_CLK_9P6MHZ)
+		snd_soc_update_bits(codec, TAIKO_A_CHIP_CTL, 0x06, 0x2);
+	taiko_codec_init_reg(codec);
 
 	if (spkr_drv_wrnd == 1)
 		snd_soc_update_bits(codec, TAIKO_A_SPKR_DRV_EN, 0x80, 0x80);
 
-	taiko_update_reg_defaults(codec);
-	taiko_codec_init_reg(codec);
+	codec->cache_sync = true;
+	snd_soc_cache_sync(codec);
+	codec->cache_sync = false;
+
 	ret = taiko_handle_pdata(taiko);
 	if (IS_ERR_VALUE(ret))
 		pr_err("%s: bad pdata\n", __func__);
@@ -6613,6 +6880,9 @@
 	if (ret)
 		pr_err("%s: Failed to setup irq: %d\n", __func__, ret);
 
+	for (count = 0; count < NUM_CODEC_DAIS; count++)
+		taiko->dai[count].bus_down_in_recovery = true;
+
 	mutex_unlock(&codec->mutex);
 	return ret;
 }
@@ -6978,6 +7248,11 @@
 {
 	struct platform_device *pdev = to_platform_device(dev);
 	struct taiko_priv *taiko = platform_get_drvdata(pdev);
+
+	if (!taiko) {
+		dev_err(dev, "%s: taiko private data is NULL\n", __func__);
+		return -EINVAL;
+	}
 	dev_dbg(dev, "%s: system resume\n", __func__);
 	/* Notify */
 	wcd9xxx_resmgr_notifier_call(&taiko->resmgr, WCD9XXX_EVENT_POST_RESUME);
diff --git a/sound/soc/codecs/wcd9xxx-common.c b/sound/soc/codecs/wcd9xxx-common.c
index b104a6b..675e378 100644
--- a/sound/soc/codecs/wcd9xxx-common.c
+++ b/sound/soc/codecs/wcd9xxx-common.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
@@ -552,7 +552,13 @@
 				__func__);
 		goto ret;
 	}
-	for (i = 0; i < ARRAY_SIZE(imped_index); i++) {
+	if (imped >= imped_index[ARRAY_SIZE(imped_index) - 1].imped_val) {
+		pr_debug("%s, detected impedance is greater than 32164 Ohm\n",
+				__func__);
+		i = ARRAY_SIZE(imped_index) - 1;
+		goto ret;
+	}
+	for (i = 0; i < ARRAY_SIZE(imped_index) - 1; i++) {
 		if (imped >= imped_index[i].imped_val &&
 			imped < imped_index[i + 1].imped_val)
 			break;
@@ -569,7 +575,7 @@
 	int i  = 0;
 	int index = 0;
 	index = get_impedance_index(imped);
-	if (index > ARRAY_SIZE(imped_index)) {
+	if (index >= ARRAY_SIZE(imped_index)) {
 		pr_err("%s, invalid imped = %d\n", __func__, imped);
 		return;
 	}
@@ -651,6 +657,29 @@
 }
 EXPORT_SYMBOL(wcd9xxx_restore_registers);
 
+static void wcd9xxx_dynamic_bypass_buck_ctrl(struct snd_soc_codec *cdc,
+						bool enable)
+{
+	int i;
+	const struct wcd9xxx_reg_mask_val reg_set[] = {
+		{WCD9XXX_A_BUCK_MODE_3, (0x1 << 3), (enable << 3)},
+		{WCD9XXX_A_BUCK_MODE_5, (0x1 << 1), (enable << 1)},
+		{WCD9XXX_A_BUCK_MODE_5, 0x1, enable}
+	};
+	if (!enable) {
+		snd_soc_update_bits(cdc, WCD9XXX_A_BUCK_MODE_1,
+					(0x1 << 3), 0x00);
+		snd_soc_update_bits(cdc, WCD9XXX_A_BUCK_MODE_4,
+					0xFF, BUCK_VREF_2V);
+	}
+	for (i = 0; i < ARRAY_SIZE(reg_set); i++)
+		snd_soc_update_bits(cdc, reg_set[i].reg, reg_set[i].mask,
+							reg_set[i].val);
+
+	/* 50us sleep is reqd. as per the class H HW design sequence */
+	usleep_range(BUCK_SETTLE_TIME_US, BUCK_SETTLE_TIME_US+10);
+}
+
 static void wcd9xxx_set_buck_mode(struct snd_soc_codec *codec, u8 buck_vref)
 {
 	int i;
@@ -807,6 +836,239 @@
 			 __func__);
 }
 
+static void wcd9xxx_ncp_bypass_enable(struct snd_soc_codec *cdc, bool enable)
+{
+	snd_soc_update_bits(cdc, WCD9XXX_A_NCP_STATIC, 0x10, (enable << 4));
+	/* 50us sleep is reqd. as per the class H HW design sequence */
+	usleep_range(BUCK_SETTLE_TIME_US, BUCK_SETTLE_TIME_US+10);
+}
+
+static void wcd9xxx_clsh_set_Iest(struct snd_soc_codec *codec,
+		u8 value)
+{
+	snd_soc_update_bits(codec, WCD9XXX_A_BUCK_MODE_5,
+				    0x01, (0x01 & 0x03));
+	snd_soc_update_bits(codec, WCD9XXX_A_BUCK_MODE_5,
+				    0xFC, (value << 2));
+}
+
+static void wcd9xxx_clsh_state_hph_ear(struct snd_soc_codec *codec,
+			struct wcd9xxx_clsh_cdc_data *clsh_d,
+			u8 req_state, bool is_enable)
+{
+	int compute_pa = 0;
+
+	dev_dbg(codec->dev, "%s: enter %s\n", __func__,
+			is_enable ? "enable" : "disable");
+
+	if (is_enable) {
+		/*
+		 * The below check condition is required to make sure
+		 * functions inside if condition will execute only once.
+		 */
+		if ((clsh_d->state == WCD9XXX_CLSH_STATE_EAR) ||
+			(req_state == WCD9XXX_CLSH_STATE_EAR)) {
+			wcd9xxx_dynamic_bypass_buck_ctrl(codec, false);
+			wcd9xxx_ncp_bypass_enable(codec, true);
+		}
+		switch (req_state) {
+		case WCD9XXX_CLSH_STATE_HPHL:
+			compute_pa = CLSH_COMPUTE_HPH_L;
+			break;
+		case WCD9XXX_CLSH_STATE_HPHR:
+			compute_pa = CLSH_COMPUTE_HPH_R;
+			break;
+		case WCD9XXX_CLSH_STATE_EAR:
+			compute_pa = CLSH_COMPUTE_EAR;
+			break;
+		default:
+			dev_dbg(codec->dev,
+				"%s:Invalid state:0x%x,enable:0x%x\n",
+				__func__, req_state, is_enable);
+			break;
+		}
+		wcd9xxx_clsh_comp_req(codec, clsh_d, compute_pa, true);
+
+		dev_dbg(codec->dev, "%s: Enabled hph+ear mode clsh\n",
+				__func__);
+	} else {
+		switch (req_state) {
+		case WCD9XXX_CLSH_STATE_HPHL:
+			compute_pa = CLSH_COMPUTE_HPH_L;
+			break;
+		case WCD9XXX_CLSH_STATE_HPHR:
+			compute_pa = CLSH_COMPUTE_HPH_R;
+			break;
+		case WCD9XXX_CLSH_STATE_EAR:
+			compute_pa = CLSH_COMPUTE_EAR;
+			break;
+		default:
+			dev_dbg(codec->dev,
+				"%s:Invalid state:0x%x,enable:0x%x\n",
+				__func__, req_state, is_enable);
+			break;
+		}
+		wcd9xxx_clsh_comp_req(codec, clsh_d, compute_pa, false);
+
+		if (((clsh_d->state & (~req_state)) ==
+				WCD9XXX_CLSH_STATE_EAR) ||
+			(req_state == WCD9XXX_CLSH_STATE_EAR)) {
+			wcd9xxx_ncp_bypass_enable(codec, false);
+			wcd9xxx_dynamic_bypass_buck_ctrl(codec, true);
+		}
+	}
+}
+
+static void wcd9xxx_clsh_state_hph_lo(struct snd_soc_codec *codec,
+			struct wcd9xxx_clsh_cdc_data *clsh_d,
+			u8 req_state, bool is_enable)
+{
+
+	dev_dbg(codec->dev, "%s: enter %s\n", __func__,
+			is_enable ? "enable" : "disable");
+	if (is_enable) {
+		if ((clsh_d->state == WCD9XXX_CLSH_STATE_LO) ||
+			(req_state == WCD9XXX_CLSH_STATE_LO)) {
+			wcd9xxx_dynamic_bypass_buck_ctrl(codec, false);
+			wcd9xxx_enable_buck(codec, clsh_d, true);
+			wcd9xxx_set_fclk_get_ncp(codec, clsh_d,
+						NCP_FCLK_LEVEL_8);
+			if (req_state & WCD9XXX_CLSH_STATE_HPH_ST) {
+				wcd9xxx_ncp_bypass_enable(codec, true);
+				wcd9xxx_enable_clsh_block(codec, clsh_d, true);
+				wcd9xxx_chargepump_request(codec, true);
+				wcd9xxx_enable_anc_delay(codec, true);
+			}
+		}
+		if (req_state == WCD9XXX_CLSH_STATE_HPHL)
+			wcd9xxx_clsh_comp_req(codec, clsh_d,
+						CLSH_COMPUTE_HPH_L, true);
+		if (req_state == WCD9XXX_CLSH_STATE_HPHR)
+			wcd9xxx_clsh_comp_req(codec, clsh_d,
+						CLSH_COMPUTE_HPH_R, true);
+	} else {
+		switch (req_state) {
+		case WCD9XXX_CLSH_STATE_LO:
+			snd_soc_update_bits(codec, WCD9XXX_A_NCP_STATIC,
+						0x20, 0x00);
+			wcd9xxx_dynamic_bypass_buck_ctrl(codec, true);
+			break;
+		case WCD9XXX_CLSH_STATE_HPHL:
+			wcd9xxx_clsh_comp_req(codec, clsh_d,
+						CLSH_COMPUTE_HPH_L, false);
+			break;
+		case WCD9XXX_CLSH_STATE_HPHR:
+			wcd9xxx_clsh_comp_req(codec, clsh_d,
+						CLSH_COMPUTE_HPH_R, false);
+			break;
+		default:
+			dev_dbg(codec->dev,
+				"%s:Invalid state:0x%x,enable:0x%x\n",
+				__func__, req_state, is_enable);
+			break;
+		}
+		if ((req_state == WCD9XXX_CLSH_STATE_LO) ||
+		((clsh_d->state & (~req_state)) == WCD9XXX_CLSH_STATE_LO)) {
+			wcd9xxx_set_fclk_put_ncp(codec, clsh_d,
+						NCP_FCLK_LEVEL_8);
+			wcd9xxx_ncp_bypass_enable(codec, false);
+
+			if (req_state & WCD9XXX_CLSH_STATE_HPH_ST) {
+				usleep_range(BUCK_SETTLE_TIME_US,
+						BUCK_SETTLE_TIME_US + 10);
+				if (clsh_d->buck_mv ==
+						WCD9XXX_CDC_BUCK_MV_1P8) {
+					wcd9xxx_enable_buck(codec, clsh_d,
+								false);
+					wcd9xxx_ncp_bypass_enable(codec, true);
+				} else {
+					/*
+					 *NCP settle time recommended by codec
+					 *specification
+					 */
+					usleep_range(NCP_SETTLE_TIME_US,
+						NCP_SETTLE_TIME_US + 10);
+					wcd9xxx_clsh_set_Iest(codec, 0x02);
+				}
+				snd_soc_update_bits(codec,
+						WCD9XXX_A_BUCK_MODE_1,
+						0x04, 0x00);
+				snd_soc_update_bits(codec,
+						 WCD9XXX_A_BUCK_MODE_4,
+						0xFF, BUCK_VREF_1P8V);
+			}
+		}
+	}
+}
+
+static void wcd9xxx_clsh_state_ear_lo(struct snd_soc_codec *codec,
+			struct wcd9xxx_clsh_cdc_data *clsh_d,
+			u8 req_state, bool is_enable)
+{
+
+	dev_dbg(codec->dev, "%s: enter %s\n", __func__,
+			is_enable ? "enable" : "disable");
+	if (is_enable) {
+		wcd9xxx_dynamic_bypass_buck_ctrl(codec, false);
+		wcd9xxx_enable_buck(codec, clsh_d, true);
+		if (req_state & WCD9XXX_CLSH_STATE_EAR) {
+			wcd9xxx_set_fclk_get_ncp(codec, clsh_d,
+						NCP_FCLK_LEVEL_8);
+			wcd9xxx_ncp_bypass_enable(codec, true);
+			wcd9xxx_enable_clsh_block(codec, clsh_d, true);
+			wcd9xxx_chargepump_request(codec, true);
+			wcd9xxx_enable_anc_delay(codec, true);
+			wcd9xxx_clsh_comp_req(codec, clsh_d,
+						CLSH_COMPUTE_EAR, true);
+		}
+	} else {
+		wcd9xxx_set_fclk_put_ncp(codec, clsh_d, NCP_FCLK_LEVEL_8);
+		wcd9xxx_ncp_bypass_enable(codec, false);
+		if (req_state & WCD9XXX_CLSH_STATE_LO) {
+			snd_soc_update_bits(codec, WCD9XXX_A_NCP_STATIC,
+						0x20, 0x00);
+			wcd9xxx_dynamic_bypass_buck_ctrl(codec, true);
+		} else if (req_state & WCD9XXX_CLSH_STATE_EAR) {
+			wcd9xxx_clsh_comp_req(codec, clsh_d, CLSH_COMPUTE_EAR,
+						false);
+			/*sleep 5ms*/
+			if (clsh_d->buck_mv == WCD9XXX_CDC_BUCK_MV_1P8) {
+				wcd9xxx_enable_buck(codec, clsh_d, false);
+				wcd9xxx_ncp_bypass_enable(codec, true);
+			} else {
+				/* NCP settle time recommended by codec	spec */
+				usleep_range(NCP_SETTLE_TIME_US,
+					     NCP_SETTLE_TIME_US + 10);
+				wcd9xxx_clsh_set_Iest(codec, 0x02);
+			}
+			snd_soc_update_bits(codec, WCD9XXX_A_BUCK_MODE_1,
+						0x04, 0x00);
+			snd_soc_update_bits(codec, WCD9XXX_A_BUCK_MODE_4,
+						0xFF, BUCK_VREF_1P8V);
+		}
+	}
+}
+
+static void wcd9xxx_clsh_state_hph_ear_lo(struct snd_soc_codec *codec,
+			struct wcd9xxx_clsh_cdc_data *clsh_d,
+			u8 req_state, bool is_enable)
+{
+	dev_dbg(codec->dev, "%s: enter %s\n", __func__,
+			is_enable ? "enable" : "disable");
+
+	if (req_state & WCD9XXX_CLSH_STATE_HPHL)
+		wcd9xxx_clsh_comp_req(codec, clsh_d, CLSH_COMPUTE_HPH_L,
+					is_enable);
+
+	if (req_state & WCD9XXX_CLSH_STATE_HPHR)
+		wcd9xxx_clsh_comp_req(codec, clsh_d, CLSH_COMPUTE_HPH_R,
+					is_enable);
+
+	if (req_state & WCD9XXX_CLSH_STATE_EAR)
+		wcd9xxx_clsh_comp_req(codec, clsh_d, CLSH_COMPUTE_EAR,
+					is_enable);
+}
+
 static void wcd9xxx_clsh_state_ear(struct snd_soc_codec *codec,
 			struct wcd9xxx_clsh_cdc_data *clsh_d,
 			u8 req_state, bool is_enable)
@@ -895,10 +1157,20 @@
 	pr_debug("%s: enter %s\n", __func__, is_enable ? "enable" : "disable");
 
 	if (is_enable) {
-		wcd9xxx_clsh_comp_req(codec, clsh_d, CLSH_COMPUTE_HPH_L, true);
-		wcd9xxx_clsh_comp_req(codec, clsh_d, CLSH_COMPUTE_HPH_R, true);
+		if (req_state == WCD9XXX_CLSH_STATE_HPHL)
+			wcd9xxx_clsh_comp_req(codec, clsh_d,
+						CLSH_COMPUTE_HPH_L, true);
+		if (req_state == WCD9XXX_CLSH_STATE_HPHR)
+			wcd9xxx_clsh_comp_req(codec, clsh_d,
+						CLSH_COMPUTE_HPH_R, true);
 	} else {
 		dev_dbg(codec->dev, "%s: stub fallback to hph_st\n", __func__);
+		if (req_state == WCD9XXX_CLSH_STATE_HPHL)
+			wcd9xxx_clsh_comp_req(codec, clsh_d,
+						CLSH_COMPUTE_HPH_L, false);
+		if (req_state == WCD9XXX_CLSH_STATE_HPHR)
+			wcd9xxx_clsh_comp_req(codec, clsh_d,
+						CLSH_COMPUTE_HPH_R, false);
 	}
 }
 
@@ -952,6 +1224,47 @@
 	WARN_ON(1);
 }
 
+/*
+ * Function: wcd9xxx_clsh_is_state_valid
+ * Params: state
+ * Description:
+ * Provides information on valid states of Class H configuration
+ */
+static int wcd9xxx_clsh_is_state_valid(u8 state)
+{
+	switch (state) {
+	case WCD9XXX_CLSH_STATE_IDLE:
+	case WCD9XXX_CLSH_STATE_EAR:
+	case WCD9XXX_CLSH_STATE_HPHL:
+	case WCD9XXX_CLSH_STATE_HPHR:
+	case WCD9XXX_CLSH_STATE_HPH_ST:
+	case WCD9XXX_CLSH_STATE_LO:
+	case WCD9XXX_CLSH_STATE_HPHL_EAR:
+	case WCD9XXX_CLSH_STATE_HPHR_EAR:
+	case WCD9XXX_CLSH_STATE_HPH_ST_EAR:
+	case WCD9XXX_CLSH_STATE_HPHL_LO:
+	case WCD9XXX_CLSH_STATE_HPHR_LO:
+	case WCD9XXX_CLSH_STATE_HPH_ST_LO:
+	case WCD9XXX_CLSH_STATE_EAR_LO:
+	case WCD9XXX_CLSH_STATE_HPHL_EAR_LO:
+	case WCD9XXX_CLSH_STATE_HPHR_EAR_LO:
+	case WCD9XXX_CLSH_STATE_HPH_ST_EAR_LO:
+		return 1;
+	default:
+		break;
+	}
+	return 0;
+}
+
+/*
+ * Function: wcd9xxx_clsh_fsm
+ * Params: codec, cdc_clsh_d, req_state, req_type, clsh_event
+ * Description:
+ * This function handles PRE DAC and POST DAC conditions of different devices
+ * and updates class H configuration of different combination of devices
+ * based on validity of their states. cdc_clsh_d will contain current
+ * class h state information
+ */
 void wcd9xxx_clsh_fsm(struct snd_soc_codec *codec,
 		struct wcd9xxx_clsh_cdc_data *cdc_clsh_d,
 		u8 req_state, bool req_type, u8 clsh_event)
@@ -967,10 +1280,25 @@
 		old_state = cdc_clsh_d->state;
 		new_state = old_state | req_state;
 
-		(*clsh_state_fp[req_state]) (codec, cdc_clsh_d, req_state,
+		if (!wcd9xxx_clsh_is_state_valid(new_state)) {
+			dev_dbg(codec->dev,
+				"%s: classH not a valid new state: %s\n",
+				__func__,
+				state_to_str(new_state, msg0, sizeof(msg0)));
+			return;
+		}
+		if (new_state == old_state) {
+			dev_dbg(codec->dev,
+				"%s: classH already in requested state: %s\n",
+				__func__,
+				state_to_str(new_state, msg0, sizeof(msg0)));
+			return;
+		}
+		(*clsh_state_fp[new_state]) (codec, cdc_clsh_d, req_state,
 					     req_type);
 		cdc_clsh_d->state = new_state;
-		dev_dbg(codec->dev, "%s: ClassH state transition from %s to %s\n",
+		dev_dbg(codec->dev,
+			"%s: ClassH state transition from %s to %s\n",
 			__func__, state_to_str(old_state, msg0, sizeof(msg0)),
 			state_to_str(cdc_clsh_d->state, msg1, sizeof(msg1)));
 
@@ -981,7 +1309,23 @@
 			new_state = old_state & (~req_state);
 
 			if (new_state < NUM_CLSH_STATES) {
-				(*clsh_state_fp[req_state]) (codec, cdc_clsh_d,
+				if (!wcd9xxx_clsh_is_state_valid(old_state)) {
+					dev_dbg(codec->dev,
+						"%s:Invalid old state:%s\n",
+						__func__,
+						state_to_str(old_state, msg0,
+						sizeof(msg0)));
+					return;
+				}
+				if (new_state == old_state) {
+					dev_dbg(codec->dev,
+					"%s: clsH already in old state: %s\n",
+					__func__,
+					state_to_str(new_state, msg0,
+					sizeof(msg0)));
+					return;
+				}
+				(*clsh_state_fp[old_state]) (codec, cdc_clsh_d,
 							     req_state,
 							     req_type);
 				cdc_clsh_d->state = new_state;
@@ -992,7 +1336,7 @@
 						     sizeof(msg1)));
 
 			} else {
-				dev_dbg(codec->dev, "%s: wrong new state = %x\n",
+				dev_dbg(codec->dev, "%s:wrong new state=0x%x\n",
 						__func__, new_state);
 			}
 		} else if (!(cdc_clsh_d->state & WCD9XXX_CLSH_STATE_LO)) {
@@ -1023,6 +1367,23 @@
 	clsh_state_fp[WCD9XXX_CLSH_STATE_HPH_ST] =
 						wcd9xxx_clsh_state_hph_st;
 	clsh_state_fp[WCD9XXX_CLSH_STATE_LO] = wcd9xxx_clsh_state_lo;
+	clsh_state_fp[WCD9XXX_CLSH_STATE_HPHL_EAR] =
+						wcd9xxx_clsh_state_hph_ear;
+	clsh_state_fp[WCD9XXX_CLSH_STATE_HPHR_EAR] =
+						wcd9xxx_clsh_state_hph_ear;
+	clsh_state_fp[WCD9XXX_CLSH_STATE_HPH_ST_EAR] =
+						wcd9xxx_clsh_state_hph_ear;
+	clsh_state_fp[WCD9XXX_CLSH_STATE_HPHL_LO] = wcd9xxx_clsh_state_hph_lo;
+	clsh_state_fp[WCD9XXX_CLSH_STATE_HPHR_LO] = wcd9xxx_clsh_state_hph_lo;
+	clsh_state_fp[WCD9XXX_CLSH_STATE_HPH_ST_LO] =
+						wcd9xxx_clsh_state_hph_lo;
+	clsh_state_fp[WCD9XXX_CLSH_STATE_EAR_LO] = wcd9xxx_clsh_state_ear_lo;
+	clsh_state_fp[WCD9XXX_CLSH_STATE_HPHL_EAR_LO] =
+						wcd9xxx_clsh_state_hph_ear_lo;
+	clsh_state_fp[WCD9XXX_CLSH_STATE_HPHR_EAR_LO] =
+						wcd9xxx_clsh_state_hph_ear_lo;
+	clsh_state_fp[WCD9XXX_CLSH_STATE_HPH_ST_EAR_LO] =
+						wcd9xxx_clsh_state_hph_ear_lo;
 
 }
 EXPORT_SYMBOL_GPL(wcd9xxx_clsh_init);
diff --git a/sound/soc/codecs/wcd9xxx-common.h b/sound/soc/codecs/wcd9xxx-common.h
index 324f6e9..13f91ed 100644
--- a/sound/soc/codecs/wcd9xxx-common.h
+++ b/sound/soc/codecs/wcd9xxx-common.h
@@ -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
@@ -35,7 +35,7 @@
 #define	WCD9XXX_CLSH_STATE_HPHL (0x01 << 1)
 #define	WCD9XXX_CLSH_STATE_HPHR (0x01 << 2)
 #define	WCD9XXX_CLSH_STATE_LO (0x01 << 3)
-#define NUM_CLSH_STATES ((0x01 << 4) - 1)
+#define NUM_CLSH_STATES (0x01 << 4)
 
 #define WCD9XXX_DMIC_SAMPLE_RATE_DIV_2    0x0
 #define WCD9XXX_DMIC_SAMPLE_RATE_DIV_3    0x1
@@ -56,6 +56,34 @@
 #define WCD9XXX_CLSH_STATE_HPH_ST (WCD9XXX_CLSH_STATE_HPHL | \
 						WCD9XXX_CLSH_STATE_HPHR)
 
+#define WCD9XXX_CLSH_STATE_HPHL_EAR (WCD9XXX_CLSH_STATE_HPHL | \
+						WCD9XXX_CLSH_STATE_EAR)
+#define WCD9XXX_CLSH_STATE_HPHR_EAR (WCD9XXX_CLSH_STATE_HPHR | \
+						WCD9XXX_CLSH_STATE_EAR)
+
+#define WCD9XXX_CLSH_STATE_HPH_ST_EAR (WCD9XXX_CLSH_STATE_HPH_ST | \
+						WCD9XXX_CLSH_STATE_EAR)
+
+#define WCD9XXX_CLSH_STATE_HPHL_LO (WCD9XXX_CLSH_STATE_HPHL | \
+						WCD9XXX_CLSH_STATE_LO)
+#define WCD9XXX_CLSH_STATE_HPHR_LO (WCD9XXX_CLSH_STATE_HPHR | \
+						WCD9XXX_CLSH_STATE_LO)
+
+#define WCD9XXX_CLSH_STATE_HPH_ST_LO (WCD9XXX_CLSH_STATE_HPH_ST | \
+						WCD9XXX_CLSH_STATE_LO)
+
+#define WCD9XXX_CLSH_STATE_EAR_LO (WCD9XXX_CLSH_STATE_EAR | \
+						WCD9XXX_CLSH_STATE_LO)
+
+#define WCD9XXX_CLSH_STATE_HPHL_EAR_LO (WCD9XXX_CLSH_STATE_HPHL | \
+						WCD9XXX_CLSH_STATE_EAR | \
+						WCD9XXX_CLSH_STATE_LO)
+#define WCD9XXX_CLSH_STATE_HPHR_EAR_LO (WCD9XXX_CLSH_STATE_HPHR | \
+						WCD9XXX_CLSH_STATE_EAR | \
+						WCD9XXX_CLSH_STATE_LO)
+#define WCD9XXX_CLSH_STATE_HPH_ST_EAR_LO (WCD9XXX_CLSH_STATE_HPH_ST | \
+						WCD9XXX_CLSH_STATE_EAR | \
+						WCD9XXX_CLSH_STATE_LO)
 
 struct wcd9xxx_reg_mask_val {
 	u16	reg;
diff --git a/sound/soc/codecs/wcd9xxx-mbhc.c b/sound/soc/codecs/wcd9xxx-mbhc.c
index 14218d8..8a71891 100644
--- a/sound/soc/codecs/wcd9xxx-mbhc.c
+++ b/sound/soc/codecs/wcd9xxx-mbhc.c
@@ -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
@@ -43,7 +43,7 @@
 
 #define WCD9XXX_JACK_MASK (SND_JACK_HEADSET | SND_JACK_OC_HPHL | \
 			   SND_JACK_OC_HPHR | SND_JACK_LINEOUT | \
-			   SND_JACK_UNSUPPORTED)
+			   SND_JACK_UNSUPPORTED | SND_JACK_MICROPHONE2)
 #define WCD9XXX_JACK_BUTTON_MASK (SND_JACK_BTN_0 | SND_JACK_BTN_1 | \
 				  SND_JACK_BTN_2 | SND_JACK_BTN_3 | \
 				  SND_JACK_BTN_4 | SND_JACK_BTN_5 | \
@@ -64,6 +64,7 @@
 #define STATUS_REL_DETECTION 0x0C
 
 #define HS_DETECT_PLUG_TIME_MS (5 * 1000)
+#define ANC_HPH_DETECT_PLUG_TIME_MS (5 * 1000)
 #define HS_DETECT_PLUG_INERVAL_MS 100
 #define SWCH_REL_DEBOUNCE_TIME_MS 50
 #define SWCH_IRQ_DEBOUNCE_TIME_US 5000
@@ -98,7 +99,7 @@
  * Invalid voltage range for the detection
  * of plug type with current source
  */
-#define WCD9XXX_CS_MEAS_INVALD_RANGE_LOW_MV 110
+#define WCD9XXX_CS_MEAS_INVALD_RANGE_LOW_MV 160
 #define WCD9XXX_CS_MEAS_INVALD_RANGE_HIGH_MV 265
 
 /*
@@ -121,7 +122,7 @@
 #define WCD9XXX_V_CS_HS_MAX 500
 #define WCD9XXX_V_CS_NO_MIC 5
 #define WCD9XXX_MB_MEAS_DELTA_MAX_MV 80
-#define WCD9XXX_CS_MEAS_DELTA_MAX_MV 10
+#define WCD9XXX_CS_MEAS_DELTA_MAX_MV 12
 
 static int impedance_detect_en;
 module_param(impedance_detect_en, int,
@@ -179,12 +180,15 @@
 				    uint32_t *zr);
 static s16 wcd9xxx_get_current_v(struct wcd9xxx_mbhc *mbhc,
 				 const enum wcd9xxx_current_v_idx idx);
-static void wcd9xxx_get_z(struct wcd9xxx_mbhc *mbhc, s16 *dce_z, s16 *sta_z);
+static void wcd9xxx_get_z(struct wcd9xxx_mbhc *mbhc, s16 *dce_z, s16 *sta_z,
+			  struct mbhc_micbias_regs *micb_regs,
+			  bool norel);
+
 static void wcd9xxx_mbhc_calc_thres(struct wcd9xxx_mbhc *mbhc);
 
 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)
@@ -538,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,
@@ -610,13 +614,23 @@
 }
 
 static void wcd9xxx_get_mbhc_micbias_regs(struct wcd9xxx_mbhc *mbhc,
-					struct mbhc_micbias_regs *micbias_regs)
+				enum wcd9xxx_mbhc_micbias_type mb_type)
 {
 	unsigned int cfilt;
 	struct wcd9xxx_micbias_setting *micbias_pdata =
 		mbhc->resmgr->micbias_pdata;
+	struct mbhc_micbias_regs *micbias_regs;
+	enum wcd9xxx_micbias_num mb_num;
 
-	switch (mbhc->mbhc_cfg->micbias) {
+	if (mb_type == MBHC_ANC_MIC_MB) {
+		micbias_regs = &mbhc->mbhc_anc_bias_regs;
+		mb_num = mbhc->mbhc_cfg->anc_micbias;
+	} else {
+		micbias_regs = &mbhc->mbhc_bias_regs;
+		mb_num = mbhc->mbhc_cfg->micbias;
+	}
+
+	switch (mb_num) {
 	case MBHC_MICBIAS1:
 		cfilt = micbias_pdata->bias1_cfilt_sel;
 		micbias_regs->mbhc_reg = WCD9XXX_A_MICB_1_MBHC;
@@ -654,19 +668,31 @@
 	case WCD9XXX_CFILT1_SEL:
 		micbias_regs->cfilt_val = WCD9XXX_A_MICB_CFILT_1_VAL;
 		micbias_regs->cfilt_ctl = WCD9XXX_A_MICB_CFILT_1_CTL;
-		mbhc->mbhc_data.micb_mv = micbias_pdata->cfilt1_mv;
 		break;
 	case WCD9XXX_CFILT2_SEL:
 		micbias_regs->cfilt_val = WCD9XXX_A_MICB_CFILT_2_VAL;
 		micbias_regs->cfilt_ctl = WCD9XXX_A_MICB_CFILT_2_CTL;
-		mbhc->mbhc_data.micb_mv = micbias_pdata->cfilt2_mv;
 		break;
 	case WCD9XXX_CFILT3_SEL:
 		micbias_regs->cfilt_val = WCD9XXX_A_MICB_CFILT_3_VAL;
 		micbias_regs->cfilt_ctl = WCD9XXX_A_MICB_CFILT_3_CTL;
-		mbhc->mbhc_data.micb_mv = micbias_pdata->cfilt3_mv;
 		break;
 	}
+
+	if (mb_type == MBHC_PRIMARY_MIC_MB) {
+		switch (cfilt) {
+		case WCD9XXX_CFILT1_SEL:
+			mbhc->mbhc_data.micb_mv = micbias_pdata->cfilt1_mv;
+			break;
+		case WCD9XXX_CFILT2_SEL:
+			mbhc->mbhc_data.micb_mv = micbias_pdata->cfilt2_mv;
+			break;
+		case WCD9XXX_CFILT3_SEL:
+			mbhc->mbhc_data.micb_mv = micbias_pdata->cfilt3_mv;
+			break;
+		}
+	}
+
 }
 
 static void wcd9xxx_clr_and_turnon_hph_padac(struct wcd9xxx_mbhc *mbhc)
@@ -819,7 +845,8 @@
 
 		if (mbhc->micbias_enable && mbhc->micbias_enable_cb) {
 			pr_debug("%s: Disabling micbias\n", __func__);
-			mbhc->micbias_enable_cb(mbhc->codec, false);
+			mbhc->micbias_enable_cb(mbhc->codec, false,
+						mbhc->mbhc_cfg->micbias);
 			mbhc->micbias_enable = false;
 		}
 		mbhc->zl = mbhc->zr = 0;
@@ -845,7 +872,8 @@
 			if (mbhc->micbias_enable && mbhc->micbias_enable_cb &&
 			    mbhc->hph_status == SND_JACK_HEADSET) {
 				pr_debug("%s: Disabling micbias\n", __func__);
-				mbhc->micbias_enable_cb(mbhc->codec, false);
+				mbhc->micbias_enable_cb(mbhc->codec, false,
+						mbhc->mbhc_cfg->micbias);
 				mbhc->micbias_enable = false;
 			}
 
@@ -855,8 +883,11 @@
 			wcd9xxx_jack_report(mbhc, &mbhc->headset_jack,
 					    0, WCD9XXX_JACK_MASK);
 			mbhc->hph_status &= ~(SND_JACK_HEADSET |
-						SND_JACK_LINEOUT);
+						SND_JACK_LINEOUT |
+						SND_JACK_ANC_HEADPHONE |
+						SND_JACK_UNSUPPORTED);
 		}
+
 		/* Report insertion */
 		mbhc->hph_status |= jack_type;
 
@@ -870,11 +901,15 @@
 			mbhc->update_z = true;
 		} else if (jack_type == SND_JACK_LINEOUT) {
 			mbhc->current_plug = PLUG_TYPE_HIGH_HPH;
+		} else if (jack_type == SND_JACK_ANC_HEADPHONE) {
+			mbhc->polling_active = BUTTON_POLLING_SUPPORTED;
+			mbhc->current_plug = PLUG_TYPE_ANC_HEADPHONE;
 		}
 
 		if (mbhc->micbias_enable && mbhc->micbias_enable_cb) {
 			pr_debug("%s: Enabling micbias\n", __func__);
-			mbhc->micbias_enable_cb(mbhc->codec, true);
+			mbhc->micbias_enable_cb(mbhc->codec, true,
+						mbhc->mbhc_cfg->micbias);
 		}
 
 		if (mbhc->impedance_detect && impedance_detect_en)
@@ -1041,7 +1076,14 @@
 static short wcd9xxx_codec_sta_dce(struct wcd9xxx_mbhc *mbhc, int dce,
 				   bool norel)
 {
-	return __wcd9xxx_codec_sta_dce(mbhc, dce, false, norel);
+	bool override_bypass;
+
+	/* Bypass override if it is already enabled */
+	override_bypass = (snd_soc_read(mbhc->codec,
+					WCD9XXX_A_CDC_MBHC_B1_CTL) &
+			   0x04) ? true : false;
+
+	return __wcd9xxx_codec_sta_dce(mbhc, dce, override_bypass, norel);
 }
 
 static s32 __wcd9xxx_codec_sta_dce_v(struct wcd9xxx_mbhc *mbhc, s8 dce,
@@ -1094,7 +1136,8 @@
 
 /* called only from interrupt which is under codec_resource_lock acquisition */
 static short wcd9xxx_mbhc_setup_hs_polling(struct wcd9xxx_mbhc *mbhc,
-					   bool is_cs_enable)
+				struct mbhc_micbias_regs *mbhc_micb_regs,
+				bool is_cs_enable)
 {
 	struct snd_soc_codec *codec = mbhc->codec;
 	short bias_value;
@@ -1115,7 +1158,7 @@
 	btn_det = WCD9XXX_MBHC_CAL_BTN_DET_PTR(mbhc->mbhc_cfg->calibration);
 	/* Enable external voltage source to micbias if present */
 	if (mbhc->mbhc_cb && mbhc->mbhc_cb->enable_mb_source)
-		mbhc->mbhc_cb->enable_mb_source(codec, true);
+		mbhc->mbhc_cb->enable_mb_source(codec, true, true);
 
 	/*
 	 * setup internal micbias if codec uses internal micbias for
@@ -1132,15 +1175,19 @@
 	snd_soc_update_bits(codec, WCD9XXX_A_CLK_BUFF_EN1, 0x05, 0x01);
 
 	/* Make sure CFILT is in fast mode, save current mode */
-	cfilt_mode = snd_soc_read(codec, mbhc->mbhc_bias_regs.cfilt_ctl);
+	cfilt_mode = snd_soc_read(codec, mbhc_micb_regs->cfilt_ctl);
 	if (mbhc->mbhc_cb && mbhc->mbhc_cb->cfilt_fast_mode)
 		mbhc->mbhc_cb->cfilt_fast_mode(codec, mbhc);
 	else
-		snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.cfilt_ctl,
+		snd_soc_update_bits(codec, mbhc_micb_regs->cfilt_ctl,
 				    0x70, 0x00);
 
 	snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x2, 0x2);
-	snd_soc_write(codec, WCD9XXX_A_MBHC_SCALING_MUX_1, 0x04);
+	snd_soc_write(codec, WCD9XXX_A_MBHC_SCALING_MUX_1,
+		      mbhc->scaling_mux_in);
+	pr_debug("%s:  scaling_mux_input: %d\n", __func__,
+						 mbhc->scaling_mux_in);
+
 	if (mbhc->mbhc_cb && mbhc->mbhc_cb->enable_mux_bias_block)
 		mbhc->mbhc_cb->enable_mux_bias_block(codec);
 	else
@@ -1165,7 +1212,7 @@
 
 	/* don't flip override */
 	bias_value = __wcd9xxx_codec_sta_dce(mbhc, 1, true, true);
-	snd_soc_write(codec, mbhc->mbhc_bias_regs.cfilt_ctl, cfilt_mode);
+	snd_soc_write(codec, mbhc_micb_regs->cfilt_ctl, cfilt_mode);
 	snd_soc_update_bits(codec, WCD9XXX_A_MBHC_HPH, 0x13, 0x00);
 
 	if (mbhc->mbhc_cfg->do_recalibration) {
@@ -1173,7 +1220,7 @@
 		reg = snd_soc_read(codec, WCD9XXX_A_CDC_MBHC_B1_CTL);
 		change = snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_B1_CTL,
 					     0x78, btn_det->mbhc_nsc << 3);
-		wcd9xxx_get_z(mbhc, &dce_z, &sta_z);
+		wcd9xxx_get_z(mbhc, &dce_z, &sta_z, mbhc_micb_regs, true);
 		if (change)
 			snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_B1_CTL, reg);
 		if (dce_z && sta_z) {
@@ -1197,7 +1244,8 @@
 			snd_soc_update_bits(mbhc->codec,
 					    WCD9XXX_A_CDC_MBHC_B1_CTL,
 					    0x78, WCD9XXX_MBHC_NSC_CS << 3);
-			wcd9xxx_get_z(mbhc, &dce_z, NULL);
+			wcd9xxx_get_z(mbhc, &dce_z, NULL, mbhc_micb_regs,
+				      true);
 			snd_soc_write(mbhc->codec, WCD9XXX_A_CDC_MBHC_B1_CTL,
 				      reg);
 			if (dce_z) {
@@ -1253,7 +1301,7 @@
 
 	/* Disable external voltage source to micbias if present */
 	if (mbhc->mbhc_cb && mbhc->mbhc_cb->enable_mb_source)
-		mbhc->mbhc_cb->enable_mb_source(mbhc->codec, false);
+		mbhc->mbhc_cb->enable_mb_source(mbhc->codec, false, true);
 
 	mbhc->polling_active = false;
 	mbhc->mbhc_state = MBHC_STATE_NONE;
@@ -1352,7 +1400,6 @@
 
 		vdce = __wcd9xxx_codec_sta_dce_v(mbhc, true, d->dce,
 						 dce_z, (u32)mb_mv);
-
 		d->_vdces = vdce;
 		if (d->_vdces < no_mic)
 			d->_type = PLUG_TYPE_HEADPHONE;
@@ -1386,14 +1433,6 @@
 		}
 	}
 
-	if (event_state & (1 << MBHC_EVENT_PA_HPHL)) {
-		pr_debug("%s: HPHL PA was ON\n", __func__);
-	} else if (ch != sz && ch > 0) {
-		pr_debug("%s: Invalid, inconsistent HPHL\n", __func__);
-		type = PLUG_TYPE_INVALID;
-		goto exit;
-	}
-
 	delta_thr = ((highhph_cnt == sz) || highhph) ?
 			      WCD9XXX_MB_MEAS_DELTA_MAX_MV :
 			      WCD9XXX_CS_MEAS_DELTA_MAX_MV;
@@ -1445,6 +1484,30 @@
 		}
 	}
 
+	if (type == PLUG_TYPE_HEADSET && dgnd && !dgnd->mic_bias) {
+		/* if plug type is Headphone report as GND_MIC_SWAP */
+		if (dgnd->_type == PLUG_TYPE_HEADPHONE) {
+			pr_debug("%s: GND_MIC_SWAP\n", __func__);
+			type = PLUG_TYPE_GND_MIC_SWAP;
+			/*
+			 * if type is GND_MIC_SWAP we should not check
+			 * HPHL status hence goto exit
+			 */
+			goto exit;
+		} else if (dgnd->_type != PLUG_TYPE_HEADSET && !dmicbias) {
+			pr_debug("%s: Invalid, inconsistent types\n", __func__);
+			type = PLUG_TYPE_INVALID;
+		}
+	}
+
+	if (event_state & (1 << MBHC_EVENT_PA_HPHL)) {
+		pr_debug("%s: HPHL PA was ON\n", __func__);
+	} else if (ch != sz && ch > 0) {
+		pr_debug("%s: Invalid, inconsistent HPHL..\n", __func__);
+		type = PLUG_TYPE_INVALID;
+		goto exit;
+	}
+
 	if (!(event_state & (1UL << MBHC_EVENT_PA_HPHL))) {
 		if (((type == PLUG_TYPE_HEADSET ||
 		      type == PLUG_TYPE_HEADPHONE) && ch != sz)) {
@@ -1453,17 +1516,12 @@
 			type = PLUG_TYPE_INVALID;
 		}
 	}
-	if (type == PLUG_TYPE_HEADSET && dgnd && !dgnd->mic_bias) {
-		if ((dgnd->_vdces + WCD9XXX_CS_GM_SWAP_THRES_MIN_MV <
-		     minv) &&
-		    (dgnd->_vdces + WCD9XXX_CS_GM_SWAP_THRES_MAX_MV >
-		     maxv))
-			type = PLUG_TYPE_GND_MIC_SWAP;
-		else if (dgnd->_type != PLUG_TYPE_HEADSET && !dmicbias) {
-			pr_debug("%s: Invalid, inconsistent types\n", __func__);
-			type = PLUG_TYPE_INVALID;
-		}
-	}
+
+	if (type == PLUG_TYPE_HEADSET &&
+	    (mbhc->mbhc_cfg->micbias_enable_flags &
+	    (1 << MBHC_MICBIAS_ENABLE_REGULAR_HEADSET)))
+		mbhc->micbias_enable = true;
+
 exit:
 	pr_debug("%s: Plug type %d detected\n", __func__, type);
 	return type;
@@ -1551,7 +1609,7 @@
 			continue;
 		}
 
-		if ((i > 0) && (d->_type != dprev->_type)) {
+		if ((i > 0) && (dprev != NULL) && (d->_type != dprev->_type)) {
 			pr_debug("%s: Invalid, inconsistent types\n", __func__);
 			type = PLUG_TYPE_INVALID;
 			goto exit;
@@ -1654,10 +1712,10 @@
 	return 0;
 }
 
-void wcd9xxx_turn_onoff_current_source(struct wcd9xxx_mbhc *mbhc, bool on,
-				       bool highhph)
+void wcd9xxx_turn_onoff_current_source(struct wcd9xxx_mbhc *mbhc,
+				       struct mbhc_micbias_regs *mbhc_micb_regs,
+				       bool on, bool highhph)
 {
-
 	struct snd_soc_codec *codec;
 	struct wcd9xxx_mbhc_btn_detect_cfg *btn_det;
 	const struct wcd9xxx_mbhc_plug_detect_cfg *plug_det =
@@ -1672,7 +1730,7 @@
 		snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_B1_CTL,
 				    0x78, 0x48);
 		/* pull down diode bit to 0 */
-		snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.mbhc_reg,
+		snd_soc_update_bits(codec, mbhc_micb_regs->mbhc_reg,
 				    0x01, 0x00);
 		/*
 		 * Keep the low power insertion/removal
@@ -1687,7 +1745,7 @@
 		 * (INS_DET_ISRC_EN__ENABLE)
 		 * MICB_2_MBHC__SCHT_TRIG_EN to 1
 		 */
-		snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.mbhc_reg,
+		snd_soc_update_bits(codec, mbhc_micb_regs->mbhc_reg,
 				    0xF0, 0xF0);
 		/* Disconnect MBHC Override from MicBias and LDOH */
 		snd_soc_update_bits(codec, WCD9XXX_A_MAD_ANA_CTRL, 0x10, 0x00);
@@ -1696,16 +1754,16 @@
 		/* Connect MBHC Override from MicBias and LDOH */
 		snd_soc_update_bits(codec, WCD9XXX_A_MAD_ANA_CTRL, 0x10, 0x10);
 		/* INS_DET_ISRC_CTL to acdb value */
-		snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.mbhc_reg,
+		snd_soc_update_bits(codec, mbhc_micb_regs->mbhc_reg,
 				    0x60, plug_det->mic_current << 5);
 		if (!highhph) {
 			/* INS_DET_ISRC_EN__ENABLE to 0 */
 			snd_soc_update_bits(codec,
-					    mbhc->mbhc_bias_regs.mbhc_reg,
+					    mbhc_micb_regs->mbhc_reg,
 					    0x80, 0x00);
 			/* MICB_2_MBHC__SCHT_TRIG_EN  to 0 */
 			snd_soc_update_bits(codec,
-					    mbhc->mbhc_bias_regs.mbhc_reg,
+					    mbhc_micb_regs->mbhc_reg,
 					    0x10, 0x00);
 		}
 		/* Nsc to acdb value */
@@ -1732,7 +1790,8 @@
 	rt[0].vddio = false;
 	rt[0].hwvalue = true;
 	rt[0].hphl_status = wcd9xxx_hphl_status(mbhc);
-	rt[0].dce = wcd9xxx_mbhc_setup_hs_polling(mbhc, true);
+	rt[0].dce = wcd9xxx_mbhc_setup_hs_polling(mbhc, &mbhc->mbhc_bias_regs,
+						  true);
 	rt[0].mic_bias = false;
 
 	for (i = 1; i < NUM_DCE_PLUG_INS_DETECT - 1; i++) {
@@ -1744,11 +1803,15 @@
 			wcd9xxx_codec_hphr_gnd_switch(codec, true);
 
 		if (rt[i].mic_bias)
-			wcd9xxx_turn_onoff_current_source(mbhc, false, false);
+			wcd9xxx_turn_onoff_current_source(mbhc,
+							  &mbhc->mbhc_bias_regs,
+							  false, false);
 
 		rt[i].dce = __wcd9xxx_codec_sta_dce(mbhc, 1, !highhph, true);
 		if (rt[i].mic_bias)
-			wcd9xxx_turn_onoff_current_source(mbhc, true, false);
+			wcd9xxx_turn_onoff_current_source(mbhc,
+							  &mbhc->mbhc_bias_regs,
+							  true, false);
 		if (rt[i].swap_gnd)
 			wcd9xxx_codec_hphr_gnd_switch(codec, false);
 	}
@@ -1801,7 +1864,8 @@
 
 	wcd9xxx_mbhc_ctrl_clk_bandgap(mbhc, true);
 	rt[0].hphl_status = wcd9xxx_hphl_status(mbhc);
-	rt[0].dce = wcd9xxx_mbhc_setup_hs_polling(mbhc, false);
+	rt[0].dce = wcd9xxx_mbhc_setup_hs_polling(mbhc, &mbhc->mbhc_bias_regs,
+						  false);
 	rt[0].swap_gnd = false;
 	rt[0].vddio = false;
 	rt[0].hwvalue = true;
@@ -1994,10 +2058,178 @@
 	return 0;
 }
 
+/*
+ * Function to determine whether anc microphone is preset or not.
+ * Return true if anc microphone is detected or false if not detected.
+ */
+static bool wcd9xxx_detect_anc_plug_type(struct wcd9xxx_mbhc *mbhc)
+{
+	struct wcd9xxx_mbhc_detect rt[NUM_DCE_PLUG_INS_DETECT - 1];
+	bool anc_mic_found = true;
+	int i, mb_mv;
+	const struct wcd9xxx_mbhc_plug_type_cfg *plug_type =
+	    WCD9XXX_MBHC_CAL_PLUG_TYPE_PTR(mbhc->mbhc_cfg->calibration);
+	s16 hs_max, dce_z;
+	s16 no_mic;
+	bool override_en;
+	bool timedout;
+	unsigned long timeout, retry = 0;
+	enum wcd9xxx_mbhc_plug_type type;
+	bool cs_enable;
+
+	if (mbhc->mbhc_cfg->anc_micbias != MBHC_MICBIAS3 &&
+	    mbhc->mbhc_cfg->anc_micbias != MBHC_MICBIAS2)
+		return false;
+
+	pr_debug("%s: enter\n", __func__);
+
+	override_en = (snd_soc_read(mbhc->codec, WCD9XXX_A_CDC_MBHC_B1_CTL) &
+		       0x04) ? true : false;
+	cs_enable = ((mbhc->mbhc_cfg->cs_enable_flags &
+		    (1 << MBHC_CS_ENABLE_DET_ANC)) != 0) &&
+		    (!(snd_soc_read(mbhc->codec,
+		       mbhc->mbhc_anc_bias_regs.ctl_reg) & 0x80)) &&
+		     (mbhc->mbhc_cfg->micbias != mbhc->mbhc_cfg->anc_micbias);
+
+	if (cs_enable) {
+		wcd9xxx_turn_onoff_current_source(mbhc,
+						  &mbhc->mbhc_anc_bias_regs,
+						  true, false);
+	} else {
+		if (mbhc->mbhc_cfg->anc_micbias == MBHC_MICBIAS3) {
+			if (mbhc->micbias_enable_cb)
+				mbhc->micbias_enable_cb(mbhc->codec, true,
+						mbhc->mbhc_cfg->anc_micbias);
+			else
+				return false;
+		} else {
+			/* Enable override */
+			if (!override_en)
+				wcd9xxx_turn_onoff_override(mbhc, true);
+		}
+	}
+
+	if (!cs_enable) {
+		hs_max = plug_type->v_hs_max;
+		no_mic = plug_type->v_no_mic;
+		dce_z = mbhc->mbhc_data.dce_z;
+		mb_mv = mbhc->mbhc_data.micb_mv;
+	} else {
+		hs_max = WCD9XXX_V_CS_HS_MAX;
+		no_mic = WCD9XXX_V_CS_NO_MIC;
+		mb_mv = VDDIO_MICBIAS_MV;
+		dce_z = mbhc->mbhc_data.dce_nsc_cs_z;
+	}
+
+	wcd9xxx_mbhc_ctrl_clk_bandgap(mbhc, true);
+
+	timeout = jiffies + msecs_to_jiffies(ANC_HPH_DETECT_PLUG_TIME_MS);
+	anc_mic_found = true;
+
+	while (!(timedout = time_after(jiffies, timeout))) {
+		retry++;
+
+		if (wcd9xxx_swch_level_remove(mbhc)) {
+			pr_debug("%s: Switch level is low\n", __func__);
+			anc_mic_found = false;
+			break;
+		}
+
+		pr_debug("%s: Retry attempt %lu", __func__, retry - 1);
+
+		rt[0].hphl_status = wcd9xxx_hphl_status(mbhc);
+		rt[0].dce = wcd9xxx_mbhc_setup_hs_polling(mbhc,
+						  &mbhc->mbhc_anc_bias_regs,
+						  cs_enable);
+		rt[0]._vdces = __wcd9xxx_codec_sta_dce_v(mbhc, true, rt[0].dce,
+							 dce_z, (u32)mb_mv);
+
+		if (rt[0]._vdces >= no_mic && rt[0]._vdces < hs_max)
+			rt[0]._type = PLUG_TYPE_HEADSET;
+		else if (rt[0]._vdces < no_mic)
+			rt[0]._type = PLUG_TYPE_HEADPHONE;
+		else
+			rt[0]._type = PLUG_TYPE_HIGH_HPH;
+
+		pr_debug("%s: DCE #%d, V %04d, HPHL %d TYPE %d\n",
+				__func__, 0, rt[0]._vdces,
+				rt[0].hphl_status & 0x01,
+				rt[0]._type);
+
+		for (i = 1; i < NUM_DCE_PLUG_INS_DETECT - 1; i++) {
+			rt[i].dce = __wcd9xxx_codec_sta_dce(mbhc, 1,
+							    true, true);
+			rt[i]._vdces = __wcd9xxx_codec_sta_dce_v(mbhc, true,
+							 rt[i].dce, dce_z,
+							 (u32) mb_mv);
+
+			if (rt[i]._vdces >= no_mic && rt[i]._vdces < hs_max)
+				rt[i]._type = PLUG_TYPE_HEADSET;
+			else if (rt[i]._vdces < no_mic)
+				rt[i]._type = PLUG_TYPE_HEADPHONE;
+			else
+				rt[i]._type = PLUG_TYPE_HIGH_HPH;
+
+			rt[i].hphl_status = wcd9xxx_hphl_status(mbhc);
+
+			pr_debug("%s: DCE #%d, V %04d, HPHL %d TYPE %d\n",
+					__func__, i, rt[i]._vdces,
+					rt[i].hphl_status & 0x01,
+					rt[i]._type);
+		}
+
+		/*
+		 * Check for the "type" of all the 4 measurements
+		 * If all 4 measurements have the Type as PLUG_TYPE_HEADSET
+		 * then it is proper mic and declare that the plug has two mics
+		 */
+		for (i = 0; i < NUM_DCE_PLUG_INS_DETECT - 1; i++) {
+			if (i > 0 && (rt[i - 1]._type != rt[i]._type)) {
+				type = PLUG_TYPE_INVALID;
+				break;
+			} else {
+				type = rt[0]._type;
+			}
+		}
+
+		pr_debug("%s: Plug type found in ANC detection :%d",
+			__func__, type);
+
+		if (type != PLUG_TYPE_HEADSET)
+			anc_mic_found = false;
+		if (anc_mic_found || (type == PLUG_TYPE_HEADPHONE &&
+		    mbhc->mbhc_cfg->hw_jack_type == FIVE_POLE_JACK) ||
+		    (type == PLUG_TYPE_HIGH_HPH &&
+		    mbhc->mbhc_cfg->hw_jack_type == SIX_POLE_JACK))
+			break;
+	}
+
+	wcd9xxx_mbhc_ctrl_clk_bandgap(mbhc, false);
+	if (cs_enable) {
+		wcd9xxx_turn_onoff_current_source(mbhc,
+						  &mbhc->mbhc_anc_bias_regs,
+						  false, false);
+	} else {
+		if (mbhc->mbhc_cfg->anc_micbias == MBHC_MICBIAS3) {
+			if (mbhc->micbias_enable_cb)
+				mbhc->micbias_enable_cb(mbhc->codec, false,
+						mbhc->mbhc_cfg->anc_micbias);
+		} else {
+			/* Disable override */
+			if (!override_en)
+				wcd9xxx_turn_onoff_override(mbhc, false);
+		}
+	}
+	pr_debug("%s: leave\n", __func__);
+	return anc_mic_found;
+}
+
 /* called under codec_resource_lock acquisition */
 static void wcd9xxx_find_plug_and_report(struct wcd9xxx_mbhc *mbhc,
 					 enum wcd9xxx_mbhc_plug_type plug_type)
 {
+	bool anc_mic_found = false;
+
 	pr_debug("%s: enter current_plug(%d) new_plug(%d)\n",
 		 __func__, mbhc->current_plug, plug_type);
 
@@ -2023,24 +2255,50 @@
 		wcd9xxx_report_plug(mbhc, 1, SND_JACK_UNSUPPORTED);
 		wcd9xxx_cleanup_hs_polling(mbhc);
 	} else if (plug_type == PLUG_TYPE_HEADSET) {
-		/*
-		 * If Headphone was reported previously, this will
-		 * only report the mic line
-		 */
-		wcd9xxx_report_plug(mbhc, 1, SND_JACK_HEADSET);
+
+		if (mbhc->mbhc_cfg->enable_anc_mic_detect) {
+			/*
+			 * Do not report Headset, because at this point
+			 * it could be a ANC headphone having two mics.
+			 * So, proceed further to detect if there is a
+			 * second mic.
+			 */
+			mbhc->scaling_mux_in = 0x08;
+			anc_mic_found = wcd9xxx_detect_anc_plug_type(mbhc);
+		}
+
+		if (anc_mic_found) {
+			/* Report ANC headphone */
+			wcd9xxx_report_plug(mbhc, 1, SND_JACK_ANC_HEADPHONE);
+		} else {
+			/*
+			 * If Headphone was reported previously, this will
+			 * only report the mic line
+			 */
+			wcd9xxx_report_plug(mbhc, 1, SND_JACK_HEADSET);
+		}
 		/* Button detection required RC oscillator */
 		wcd9xxx_mbhc_ctrl_clk_bandgap(mbhc, true);
+		/*
+		 * sleep so that audio path completely tears down
+		 * before report plug insertion to the user space
+		 */
 		msleep(100);
 
-		/* if PA is already on, switch micbias source to VDDIO */
+		/*
+		 * if PA is already on, switch micbias
+		 * source to VDDIO
+		 */
 		if (mbhc->event_state &
-		    (1 << MBHC_EVENT_PA_HPHL | 1 << MBHC_EVENT_PA_HPHR))
-			__wcd9xxx_switch_micbias(mbhc, 1, false, false);
+		(1 << MBHC_EVENT_PA_HPHL | 1 << MBHC_EVENT_PA_HPHR))
+			__wcd9xxx_switch_micbias(mbhc, 1, false,
+						 false);
 		wcd9xxx_start_hs_polling(mbhc);
 	} else if (plug_type == PLUG_TYPE_HIGH_HPH) {
 		if (mbhc->mbhc_cfg->detect_extn_cable) {
 			/* High impedance device found. Report as LINEOUT*/
-			wcd9xxx_report_plug(mbhc, 1, SND_JACK_LINEOUT);
+			if (mbhc->current_plug == PLUG_TYPE_NONE)
+				wcd9xxx_report_plug(mbhc, 1, SND_JACK_LINEOUT);
 			wcd9xxx_cleanup_hs_polling(mbhc);
 			pr_debug("%s: setup mic trigger for further detection\n",
 				 __func__);
@@ -2084,10 +2342,14 @@
 		     (!(snd_soc_read(mbhc->codec,
 				     mbhc->mbhc_bias_regs.ctl_reg) & 0x80)));
 
+	mbhc->scaling_mux_in = 0x04;
+
 	if (current_source_enable) {
-		wcd9xxx_turn_onoff_current_source(mbhc, true, false);
+		wcd9xxx_turn_onoff_current_source(mbhc, &mbhc->mbhc_bias_regs,
+						  true, false);
 		plug_type = wcd9xxx_codec_cs_get_plug_type(mbhc, false);
-		wcd9xxx_turn_onoff_current_source(mbhc, false, false);
+		wcd9xxx_turn_onoff_current_source(mbhc, &mbhc->mbhc_bias_regs,
+						  false, false);
 	} else {
 		wcd9xxx_turn_onoff_override(mbhc, true);
 		plug_type = wcd9xxx_codec_get_plug_type(mbhc, true);
@@ -2212,7 +2474,8 @@
 		     (!(snd_soc_read(mbhc->codec,
 				     mbhc->mbhc_bias_regs.ctl_reg) & 0x80)));
 	if (cs_enable)
-		wcd9xxx_turn_onoff_current_source(mbhc, true, false);
+		wcd9xxx_turn_onoff_current_source(mbhc, &mbhc->mbhc_bias_regs,
+						  true, false);
 
 	timeout = jiffies + msecs_to_jiffies(HS_DETECT_PLUG_TIME_MS);
 	while (!(timedout = time_after(jiffies, timeout))) {
@@ -2280,7 +2543,8 @@
 	}
 
 	if (cs_enable)
-		wcd9xxx_turn_onoff_current_source(mbhc, false, false);
+		wcd9xxx_turn_onoff_current_source(mbhc, &mbhc->mbhc_bias_regs,
+						  false, false);
 
 	if (timedout)
 		pr_debug("%s: Microphone did not settle in %d seconds\n",
@@ -2311,7 +2575,8 @@
 	u32 mb_mv;
 
 	pr_debug("%s: enter\n", __func__);
-	if (mbhc->current_plug != PLUG_TYPE_HEADSET) {
+	if (mbhc->current_plug != PLUG_TYPE_HEADSET &&
+		mbhc->current_plug != PLUG_TYPE_ANC_HEADPHONE) {
 		pr_debug("%s(): Headset is not inserted, ignore removal\n",
 			 __func__);
 		snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL,
@@ -2328,7 +2593,8 @@
 		     (!(snd_soc_read(codec,
 				     mbhc->mbhc_bias_regs.ctl_reg) & 0x80)));
 	if (cs_enable)
-		wcd9xxx_turn_onoff_current_source(mbhc, true, false);
+		wcd9xxx_turn_onoff_current_source(mbhc, &mbhc->mbhc_bias_regs,
+						  true, false);
 
 	timeout = jiffies + msecs_to_jiffies(FAKE_REMOVAL_MIN_PERIOD_MS);
 	do {
@@ -2359,7 +2625,8 @@
 		  removed ? "" : "not ");
 
 	if (cs_enable)
-		wcd9xxx_turn_onoff_current_source(mbhc, false, false);
+		wcd9xxx_turn_onoff_current_source(mbhc, &mbhc->mbhc_bias_regs,
+						  false, false);
 
 	if (removed) {
 		if (mbhc->mbhc_cfg->detect_extn_cable) {
@@ -2741,8 +3008,8 @@
 	 * headphone detection.
 	 */
 	if (current_source_enable)
-		wcd9xxx_turn_onoff_current_source(mbhc, true,
-						  false);
+		wcd9xxx_turn_onoff_current_source(mbhc, &mbhc->mbhc_bias_regs,
+						  true, false);
 	else
 		wcd9xxx_turn_onoff_override(mbhc, true);
 
@@ -2784,11 +3051,14 @@
 			if (!mbhc->mbhc_cfg->detect_extn_cable &&
 			    retry == NUM_ATTEMPTS_TO_REPORT &&
 			    mbhc->current_plug == PLUG_TYPE_NONE) {
+				WCD9XXX_BCL_LOCK(mbhc->resmgr);
 				wcd9xxx_report_plug(mbhc, 1,
 						    SND_JACK_HEADPHONE);
+				WCD9XXX_BCL_UNLOCK(mbhc->resmgr);
 			}
 		} else if (plug_type == PLUG_TYPE_HEADPHONE) {
 			pr_debug("Good headphone detected, continue polling\n");
+			WCD9XXX_BCL_LOCK(mbhc->resmgr);
 			if (mbhc->mbhc_cfg->detect_extn_cable) {
 				if (mbhc->current_plug != plug_type)
 					wcd9xxx_report_plug(mbhc, 1,
@@ -2797,9 +3067,20 @@
 				wcd9xxx_report_plug(mbhc, 1,
 						    SND_JACK_HEADPHONE);
 			}
+			WCD9XXX_BCL_UNLOCK(mbhc->resmgr);
 		} else if (plug_type == PLUG_TYPE_HIGH_HPH) {
 			pr_debug("%s: High HPH detected, continue polling\n",
 				  __func__);
+			WCD9XXX_BCL_LOCK(mbhc->resmgr);
+			if (mbhc->mbhc_cfg->detect_extn_cable) {
+				if (mbhc->current_plug != plug_type)
+					wcd9xxx_report_plug(mbhc, 1,
+							    SND_JACK_LINEOUT);
+			} else if (mbhc->current_plug == PLUG_TYPE_NONE) {
+				wcd9xxx_report_plug(mbhc, 1,
+						    SND_JACK_HEADPHONE);
+			}
+			WCD9XXX_BCL_UNLOCK(mbhc->resmgr);
 		} else {
 			if (plug_type == PLUG_TYPE_GND_MIC_SWAP) {
 				pt_gnd_mic_swap_cnt++;
@@ -2826,8 +3107,9 @@
 			WCD9XXX_BCL_LOCK(mbhc->resmgr);
 			/* Turn off override/current source */
 			if (current_source_enable)
-				wcd9xxx_turn_onoff_current_source(mbhc, false,
-								  false);
+				wcd9xxx_turn_onoff_current_source(mbhc,
+							  &mbhc->mbhc_bias_regs,
+							  false, false);
 			else
 				wcd9xxx_turn_onoff_override(mbhc, false);
 			/*
@@ -2853,7 +3135,8 @@
 	}
 
 	if (!correction && current_source_enable)
-		wcd9xxx_turn_onoff_current_source(mbhc, false, highhph);
+		wcd9xxx_turn_onoff_current_source(mbhc, &mbhc->mbhc_bias_regs,
+						  false, highhph);
 	else if (!correction)
 		wcd9xxx_turn_onoff_override(mbhc, false);
 
@@ -2895,16 +3178,15 @@
 	if (wcd9xxx_cancel_btn_work(mbhc))
 		pr_debug("%s: button press is canceled\n", __func__);
 
-	/* cancel detect plug */
-	wcd9xxx_cancel_hs_detect_plug(mbhc,
-				      &mbhc->correct_plug_swch);
-
 	insert = !wcd9xxx_swch_level_remove(mbhc);
 	pr_debug("%s: Current plug type %d, insert %d\n", __func__,
 		 mbhc->current_plug, insert);
 	if ((mbhc->current_plug == PLUG_TYPE_NONE) && insert) {
 		mbhc->lpi_enabled = false;
 		wmb();
+		/* cancel detect plug */
+		wcd9xxx_cancel_hs_detect_plug(mbhc,
+				      &mbhc->correct_plug_swch);
 
 		if ((mbhc->current_plug != PLUG_TYPE_NONE) &&
 		    !(snd_soc_read(codec, WCD9XXX_A_MBHC_INSERT_DETECT) &
@@ -2919,6 +3201,9 @@
 	} else if ((mbhc->current_plug != PLUG_TYPE_NONE) && !insert) {
 		mbhc->lpi_enabled = false;
 		wmb();
+		/* cancel detect plug */
+		wcd9xxx_cancel_hs_detect_plug(mbhc,
+				      &mbhc->correct_plug_swch);
 
 		if (mbhc->current_plug == PLUG_TYPE_HEADPHONE) {
 			wcd9xxx_report_plug(mbhc, 0, SND_JACK_HEADPHONE);
@@ -2935,6 +3220,12 @@
 		} else if (mbhc->current_plug == PLUG_TYPE_HIGH_HPH) {
 			wcd9xxx_report_plug(mbhc, 0, SND_JACK_LINEOUT);
 			is_removed = true;
+		} else if (mbhc->current_plug == PLUG_TYPE_ANC_HEADPHONE) {
+			wcd9xxx_pause_hs_polling(mbhc);
+			wcd9xxx_mbhc_ctrl_clk_bandgap(mbhc, false);
+			wcd9xxx_cleanup_hs_polling(mbhc);
+			wcd9xxx_report_plug(mbhc, 0, SND_JACK_ANC_HEADPHONE);
+			is_removed = true;
 		}
 
 		if (is_removed) {
@@ -3095,7 +3386,9 @@
 	return mask;
 }
 
-static void wcd9xxx_get_z(struct wcd9xxx_mbhc *mbhc, s16 *dce_z, s16 *sta_z)
+static void wcd9xxx_get_z(struct wcd9xxx_mbhc *mbhc, s16 *dce_z, s16 *sta_z,
+			  struct mbhc_micbias_regs *micb_regs,
+			  bool norel_detection)
 {
 	s16 reg0, reg1;
 	int change;
@@ -3103,21 +3396,21 @@
 
 	WCD9XXX_BCL_ASSERT_LOCKED(mbhc->resmgr);
 	/* Pull down micbias to ground and disconnect vddio switch */
-	reg0 = snd_soc_read(codec, mbhc->mbhc_bias_regs.ctl_reg);
-	snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.ctl_reg, 0x81, 0x1);
-	reg1 = snd_soc_read(codec, mbhc->mbhc_bias_regs.mbhc_reg);
-	snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.mbhc_reg, 1 << 7, 0);
+	reg0 = snd_soc_read(codec, micb_regs->ctl_reg);
+	snd_soc_update_bits(codec, micb_regs->ctl_reg, 0x81, 0x1);
+	reg1 = snd_soc_read(codec, micb_regs->mbhc_reg);
+	snd_soc_update_bits(codec, micb_regs->mbhc_reg, 1 << 7, 0);
 
 	/* Disconnect override from micbias */
 	change = snd_soc_update_bits(codec, WCD9XXX_A_MAD_ANA_CTRL, 1 << 4,
 				     1 << 0);
 	usleep_range(1000, 1000 + 1000);
 	if (sta_z) {
-		*sta_z = wcd9xxx_codec_sta_dce(mbhc, 0, false);
+		*sta_z = wcd9xxx_codec_sta_dce(mbhc, 0, norel_detection);
 		pr_debug("%s: sta_z 0x%x\n", __func__, *sta_z & 0xFFFF);
 	}
 	if (dce_z) {
-		*dce_z = wcd9xxx_codec_sta_dce(mbhc, 1, false);
+		*dce_z = wcd9xxx_codec_sta_dce(mbhc, 1, norel_detection);
 		pr_debug("%s: dce_z 0x%x\n", __func__, *dce_z & 0xFFFF);
 	}
 
@@ -3126,16 +3419,22 @@
 		snd_soc_update_bits(codec, WCD9XXX_A_MAD_ANA_CTRL, 1 << 4,
 				    1 << 4);
 	/* Disable pull down micbias to ground */
-	snd_soc_write(codec, mbhc->mbhc_bias_regs.mbhc_reg, reg1);
-	snd_soc_write(codec, mbhc->mbhc_bias_regs.ctl_reg, reg0);
+	snd_soc_write(codec, micb_regs->mbhc_reg, reg1);
+	snd_soc_write(codec, micb_regs->ctl_reg, reg0);
 }
 
+/*
+ * This function recalibrates dce_z and sta_z parameters.
+ * No release detection will be false when this function is
+ * used.
+ */
 void wcd9xxx_update_z(struct wcd9xxx_mbhc *mbhc)
 {
 	const u16 sta_z = mbhc->mbhc_data.sta_z;
 	const u16 dce_z = mbhc->mbhc_data.dce_z;
 
-	wcd9xxx_get_z(mbhc, &mbhc->mbhc_data.dce_z, &mbhc->mbhc_data.sta_z);
+	wcd9xxx_get_z(mbhc, &mbhc->mbhc_data.dce_z, &mbhc->mbhc_data.sta_z,
+		      &mbhc->mbhc_bias_regs, false);
 	pr_debug("%s: sta_z 0x%x,dce_z 0x%x -> sta_z 0x%x,dce_z 0x%x\n",
 		 __func__, sta_z & 0xFFFF, dce_z & 0xFFFF,
 		 mbhc->mbhc_data.sta_z & 0xFFFF,
@@ -3149,7 +3448,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;
@@ -3159,6 +3459,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) {
@@ -3204,6 +3506,7 @@
 	pr_debug("%s: enter\n", __func__);
 
 	WCD9XXX_BCL_LOCK(mbhc->resmgr);
+	mutex_lock(&mbhc->mbhc_lock);
 	mbhc_status = snd_soc_read(codec, WCD9XXX_A_CDC_MBHC_B1_STATUS) & 0x3E;
 
 	if (mbhc->mbhc_state == MBHC_STATE_POTENTIAL_RECOVERY) {
@@ -3359,7 +3662,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;
@@ -3376,6 +3679,7 @@
 
  done:
 	pr_debug("%s: leave\n", __func__);
+	mutex_unlock(&mbhc->mbhc_lock);
 	WCD9XXX_BCL_UNLOCK(mbhc->resmgr);
 	return IRQ_HANDLED;
 }
@@ -3582,7 +3886,7 @@
 	 * turn on the external voltage source for Calibration.
 	 */
 	if (mbhc->mbhc_cb && mbhc->mbhc_cb->enable_mb_source)
-		mbhc->mbhc_cb->enable_mb_source(codec, true);
+		mbhc->mbhc_cb->enable_mb_source(codec, true, false);
 
 	cfilt_mode = snd_soc_read(codec, mbhc->mbhc_bias_regs.cfilt_ctl);
 	if (mbhc->mbhc_cb && mbhc->mbhc_cb->cfilt_fast_mode)
@@ -3704,7 +4008,7 @@
 	usleep_range(100, 100);
 
 	if (mbhc->mbhc_cb && mbhc->mbhc_cb->enable_mb_source)
-		mbhc->mbhc_cb->enable_mb_source(codec, false);
+		mbhc->mbhc_cb->enable_mb_source(codec, false, false);
 
 	wcd9xxx_enable_irq(mbhc->resmgr->core_res,
 			   mbhc->intr_ids->dce_est_complete);
@@ -4052,7 +4356,10 @@
 	mbhc->mbhc_cfg = mbhc_cfg;
 
 	/* Get HW specific mbhc registers' address */
-	wcd9xxx_get_mbhc_micbias_regs(mbhc, &mbhc->mbhc_bias_regs);
+	wcd9xxx_get_mbhc_micbias_regs(mbhc, MBHC_PRIMARY_MIC_MB);
+
+	/* Get HW specific mbhc registers' address for anc */
+	wcd9xxx_get_mbhc_micbias_regs(mbhc, MBHC_ANC_MIC_MB);
 
 	/* Put CFILT in fast mode by default */
 	if (mbhc->mbhc_cb && mbhc->mbhc_cb->cfilt_fast_mode)
@@ -4220,6 +4527,7 @@
 	pr_debug("%s: enter event %s(%d)\n", __func__,
 		 wcd9xxx_get_event_string(event), event);
 
+	mutex_lock(&mbhc->mbhc_lock);
 	switch (event) {
 	/* MICBIAS usage change */
 	case WCD9XXX_EVENT_PRE_MICBIAS_1_ON:
@@ -4265,6 +4573,14 @@
 			if (!mbhc->polling_active)
 				wcd9xxx_enable_mbhc_txfe(mbhc, false);
 		}
+		if (mbhc->micbias_enable && mbhc->polling_active &&
+		    !(snd_soc_read(mbhc->codec, mbhc->mbhc_bias_regs.ctl_reg)
+		      & 0x80)) {
+			pr_debug("%s:Micbias turned off by recording, set up again",
+				 __func__);
+			snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.ctl_reg,
+					    0x80, 0x80);
+		}
 		break;
 	/* PA usage change */
 	case WCD9XXX_EVENT_PRE_HPHL_PA_ON:
@@ -4285,7 +4601,7 @@
 			hphlocp_off_report(mbhc, SND_JACK_OC_HPHL);
 		if (!(mbhc->event_state &
 		      (1 << MBHC_EVENT_PA_HPHL | 1 << MBHC_EVENT_PA_HPHR |
-		       1 << MBHC_EVENT_PRE_TX_3_ON)))
+		       1 << MBHC_EVENT_PRE_TX_1_3_ON)))
 			wcd9xxx_switch_micbias(mbhc, 0);
 		break;
 	case WCD9XXX_EVENT_POST_HPHR_PA_OFF:
@@ -4297,7 +4613,7 @@
 			hphrocp_off_report(mbhc, SND_JACK_OC_HPHL);
 		if (!(mbhc->event_state &
 		      (1 << MBHC_EVENT_PA_HPHL | 1 << MBHC_EVENT_PA_HPHR |
-		       1 << MBHC_EVENT_PRE_TX_3_ON)))
+		       1 << MBHC_EVENT_PRE_TX_1_3_ON)))
 			wcd9xxx_switch_micbias(mbhc, 0);
 		break;
 	/* Clock usage change */
@@ -4379,23 +4695,23 @@
 	case WCD9XXX_EVENT_POST_BG_MBHC_ON:
 		/* Not used for now */
 		break;
-	case WCD9XXX_EVENT_PRE_TX_3_ON:
+	case WCD9XXX_EVENT_PRE_TX_1_3_ON:
 		/*
 		 * if polling is ON, mbhc micbias not enabled
 		 *  switch micbias source to VDDIO
 		 */
-		set_bit(MBHC_EVENT_PRE_TX_3_ON, &mbhc->event_state);
+		set_bit(MBHC_EVENT_PRE_TX_1_3_ON, &mbhc->event_state);
 		if (!(snd_soc_read(codec, mbhc->mbhc_bias_regs.ctl_reg)
 		      & 0x80) &&
 		    mbhc->polling_active && !mbhc->mbhc_micbias_switched)
 			wcd9xxx_switch_micbias(mbhc, 1);
 		break;
-	case WCD9XXX_EVENT_POST_TX_3_OFF:
+	case WCD9XXX_EVENT_POST_TX_1_3_OFF:
 		/*
 		 * Switch back to micbias if HPH PA or TX3 path
 		 * is disabled
 		 */
-		clear_bit(MBHC_EVENT_PRE_TX_3_ON, &mbhc->event_state);
+		clear_bit(MBHC_EVENT_PRE_TX_1_3_ON, &mbhc->event_state);
 		if (mbhc->polling_active && mbhc->mbhc_micbias_switched &&
 		    !(mbhc->event_state & (1 << MBHC_EVENT_PA_HPHL |
 		      1 << MBHC_EVENT_PA_HPHR)))
@@ -4405,6 +4721,7 @@
 		WARN(1, "Unknown event %d\n", event);
 		ret = -EINVAL;
 	}
+	mutex_unlock(&mbhc->mbhc_lock);
 
 	pr_debug("%s: leave\n", __func__);
 
@@ -4420,6 +4737,7 @@
 	s16 *z[] = {
 		&l[0], &r[0], &r[1], &l[1], &l[2], &r[2],
 	};
+	bool override_en;
 	struct snd_soc_codec *codec = mbhc->codec;
 	const int mux_wait_us = 25;
 	const struct wcd9xxx_reg_mask_val reg_set_mux[] = {
@@ -4456,7 +4774,10 @@
 
 	wcd9xxx_onoff_ext_mclk(mbhc, true);
 
-	wcd9xxx_turn_onoff_override(mbhc, true);
+	override_en = (snd_soc_read(codec, WCD9XXX_A_CDC_MBHC_B1_CTL) & 0x04) ?
+					true : false;
+	if (!override_en)
+		wcd9xxx_turn_onoff_override(mbhc, true);
 	pr_debug("%s: Setting impedance detection\n", __func__);
 
 	/* Codec specific setup for L0, R0, L1 and R1 measurements */
@@ -4504,7 +4825,8 @@
 
 	wcd9xxx_onoff_ext_mclk(mbhc, false);
 
-	wcd9xxx_turn_onoff_override(mbhc, false);
+	if (!override_en)
+		wcd9xxx_turn_onoff_override(mbhc, false);
 	mbhc->mbhc_cb->compute_impedance(l, r, zl, zr);
 
 	pr_debug("%s: L0: 0x%x(%d), L1: 0x%x(%d), L2: 0x%x(%d)\n",
@@ -4522,10 +4844,8 @@
 int wcd9xxx_mbhc_get_impedance(struct wcd9xxx_mbhc *mbhc, uint32_t *zl,
 			       uint32_t *zr)
 {
-	WCD9XXX_BCL_LOCK(mbhc->resmgr);
 	*zl = mbhc->zl;
 	*zr = mbhc->zr;
-	WCD9XXX_BCL_UNLOCK(mbhc->resmgr);
 
 	if (*zl && *zr)
 		return 0;
@@ -4540,7 +4860,8 @@
  */
 int wcd9xxx_mbhc_init(struct wcd9xxx_mbhc *mbhc, struct wcd9xxx_resmgr *resmgr,
 		      struct snd_soc_codec *codec,
-		      int (*micbias_enable_cb) (struct snd_soc_codec*,  bool),
+		      int (*micbias_enable_cb) (struct snd_soc_codec*,  bool,
+						enum wcd9xxx_micbias_num),
 		      const struct wcd9xxx_mbhc_cb *mbhc_cb,
 		      const struct wcd9xxx_mbhc_intr *mbhc_cdc_intr_ids,
 		      int rco_clk_rate,
@@ -4610,17 +4931,19 @@
 				  wcd9xxx_mbhc_insert_work);
 	}
 
+	mutex_init(&mbhc->mbhc_lock);
+
 	/* Register event notifier */
 	mbhc->nblock.notifier_call = wcd9xxx_event_notify;
 	ret = wcd9xxx_resmgr_register_notifier(mbhc->resmgr, &mbhc->nblock);
 	if (ret) {
 		pr_err("%s: Failed to register notifier %d\n", __func__, ret);
+		mutex_destroy(&mbhc->mbhc_lock);
 		return ret;
 	}
 
 	wcd9xxx_init_debugfs(mbhc);
 
-
 	/* Disable Impedance detection by default for certain codec types */
 	if (mbhc->mbhc_cb &&
 	    mbhc->mbhc_cb->get_cdc_type() == WCD9XXX_CDC_TYPE_HELICON)
@@ -4705,6 +5028,8 @@
 err_insert_irq:
 	wcd9xxx_resmgr_unregister_notifier(mbhc->resmgr, &mbhc->nblock);
 
+	mutex_destroy(&mbhc->mbhc_lock);
+
 	pr_debug("%s: leave ret %d\n", __func__, ret);
 	return ret;
 }
@@ -4726,6 +5051,7 @@
 	wcd9xxx_free_irq(core_res, mbhc->intr_ids->hph_left_ocp, mbhc);
 	wcd9xxx_free_irq(core_res, mbhc->intr_ids->hph_right_ocp, mbhc);
 
+	mutex_destroy(&mbhc->mbhc_lock);
 	wcd9xxx_resmgr_unregister_notifier(mbhc->resmgr, &mbhc->nblock);
 	wcd9xxx_cleanup_debugfs(mbhc);
 }
diff --git a/sound/soc/codecs/wcd9xxx-mbhc.h b/sound/soc/codecs/wcd9xxx-mbhc.h
index 98f73fc..91edaca 100644
--- a/sound/soc/codecs/wcd9xxx-mbhc.h
+++ b/sound/soc/codecs/wcd9xxx-mbhc.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
@@ -78,6 +78,12 @@
 	PLUG_TYPE_HEADPHONE,
 	PLUG_TYPE_HIGH_HPH,
 	PLUG_TYPE_GND_MIC_SWAP,
+	PLUG_TYPE_ANC_HEADPHONE,
+};
+
+enum wcd9xxx_mbhc_micbias_type {
+	MBHC_PRIMARY_MIC_MB,
+	MBHC_ANC_MIC_MB,
 };
 
 enum wcd9xxx_micbias_num {
@@ -88,6 +94,12 @@
 	MBHC_MICBIAS4,
 };
 
+enum hw_jack_type {
+	FOUR_POLE_JACK = 0,
+	FIVE_POLE_JACK,
+	SIX_POLE_JACK,
+};
+
 enum wcd9xx_mbhc_micbias_enable_bits {
 	MBHC_MICBIAS_ENABLE_THRESHOLD_HEADSET,
 	MBHC_MICBIAS_ENABLE_REGULAR_HEADSET,
@@ -97,6 +109,7 @@
 	MBHC_CS_ENABLE_POLLING,
 	MBHC_CS_ENABLE_INSERTION,
 	MBHC_CS_ENABLE_REMOVAL,
+	MBHC_CS_ENABLE_DET_ANC,
 };
 
 enum wcd9xxx_mbhc_state {
@@ -123,8 +136,8 @@
 enum wcd9xxx_mbhc_event_state {
 	MBHC_EVENT_PA_HPHL,
 	MBHC_EVENT_PA_HPHR,
-	MBHC_EVENT_PRE_TX_3_ON,
-	MBHC_EVENT_POST_TX_3_OFF,
+	MBHC_EVENT_PRE_TX_1_3_ON,
+	MBHC_EVENT_POST_TX_1_3_OFF,
 };
 
 struct wcd9xxx_mbhc_general_cfg {
@@ -217,6 +230,7 @@
 	 */
 	void *calibration;
 	enum wcd9xxx_micbias_num micbias;
+	enum wcd9xxx_micbias_num anc_micbias;
 	int (*mclk_cb_fn) (struct snd_soc_codec*, int, bool);
 	unsigned int mclk_rate;
 	unsigned int gpio;
@@ -232,6 +246,8 @@
 	bool use_int_rbias;
 	bool do_recalibration;
 	bool use_vddio_meas;
+	bool enable_anc_mic_detect;
+	enum hw_jack_type hw_jack_type;
 };
 
 struct wcd9xxx_cfilt_mode {
@@ -266,7 +282,7 @@
 			   enum mbhc_impedance_detect_stages stage);
 	void (*compute_impedance) (s16 *, s16 *, uint32_t *, uint32_t *);
 	void (*enable_mbhc_txfe) (struct snd_soc_codec *, bool);
-	int (*enable_mb_source) (struct snd_soc_codec *, bool);
+	int (*enable_mb_source) (struct snd_soc_codec *, bool, bool);
 	void (*setup_int_rbias) (struct snd_soc_codec *, bool);
 	void (*pull_mb_to_vddio) (struct snd_soc_codec *, bool);
 };
@@ -283,6 +299,8 @@
 	struct mbhc_internal_cal_data mbhc_data;
 
 	struct mbhc_micbias_regs mbhc_bias_regs;
+	struct mbhc_micbias_regs mbhc_anc_bias_regs;
+
 	bool mbhc_micbias_switched;
 
 	u32 hph_status; /* track headhpone status */
@@ -331,7 +349,8 @@
 	struct notifier_block nblock;
 
 	bool micbias_enable;
-	int (*micbias_enable_cb) (struct snd_soc_codec*,  bool);
+	int (*micbias_enable_cb) (struct snd_soc_codec*,  bool,
+				  enum wcd9xxx_micbias_num);
 
 	bool impedance_detect;
 	/* impedance of hphl and hphr */
@@ -340,6 +359,8 @@
 	u32 rco_clk_rate;
 
 	bool update_z;
+
+	u8   scaling_mux_in;
 	/* Holds codec specific interrupt mapping */
 	const struct wcd9xxx_mbhc_intr *intr_ids;
 
@@ -347,6 +368,8 @@
 	struct dentry *debugfs_poke;
 	struct dentry *debugfs_mbhc;
 #endif
+
+	struct mutex mbhc_lock;
 };
 
 #define WCD9XXX_MBHC_CAL_SIZE(buttons, rload) ( \
@@ -409,7 +432,8 @@
 void wcd9xxx_mbhc_stop(struct wcd9xxx_mbhc *mbhc);
 int wcd9xxx_mbhc_init(struct wcd9xxx_mbhc *mbhc, struct wcd9xxx_resmgr *resmgr,
 		      struct snd_soc_codec *codec,
-		      int (*micbias_enable_cb) (struct snd_soc_codec*,  bool),
+		      int (*micbias_enable_cb) (struct snd_soc_codec*,  bool,
+						enum wcd9xxx_micbias_num),
 		      const struct wcd9xxx_mbhc_cb *mbhc_cb,
 		      const struct wcd9xxx_mbhc_intr *mbhc_cdc_intr_ids,
 		      int rco_clk_rate,
diff --git a/sound/soc/codecs/wcd9xxx-resmgr.c b/sound/soc/codecs/wcd9xxx-resmgr.c
index e56b182..4843b51 100644
--- a/sound/soc/codecs/wcd9xxx-resmgr.c
+++ b/sound/soc/codecs/wcd9xxx-resmgr.c
@@ -92,8 +92,8 @@
 
 	"WCD9XXX_EVENT_POST_RESUME",
 
-	"WCD9XXX_EVENT_PRE_TX_3_ON",
-	"WCD9XXX_EVENT_POST_TX_3_OFF",
+	"WCD9XXX_EVENT_PRE_TX_1_3_ON",
+	"WCD9XXX_EVENT_POST_TX_1_3_OFF",
 
 	"WCD9XXX_EVENT_LAST",
 };
diff --git a/sound/soc/codecs/wcd9xxx-resmgr.h b/sound/soc/codecs/wcd9xxx-resmgr.h
index 9f383b6..29896fc 100644
--- a/sound/soc/codecs/wcd9xxx-resmgr.h
+++ b/sound/soc/codecs/wcd9xxx-resmgr.h
@@ -105,8 +105,8 @@
 
 	WCD9XXX_EVENT_POST_RESUME,
 
-	WCD9XXX_EVENT_PRE_TX_3_ON,
-	WCD9XXX_EVENT_POST_TX_3_OFF,
+	WCD9XXX_EVENT_PRE_TX_1_3_ON,
+	WCD9XXX_EVENT_POST_TX_1_3_OFF,
 
 	WCD9XXX_EVENT_LAST,
 };
diff --git a/sound/soc/msm/apq8074.c b/sound/soc/msm/apq8074.c
index 5b12b9c..3a143aa 100644
--- a/sound/soc/msm/apq8074.c
+++ b/sound/soc/msm/apq8074.c
@@ -1812,7 +1812,7 @@
 		.name = "MSM8974 Compr",
 		.stream_name = "COMPR",
 		.cpu_dai_name	= "MultiMedia4",
-		.platform_name  = "msm-compr-dsp",
+		.platform_name  = "msm-compress-dsp",
 		.dynamic = 1,
 		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
 			 SND_SOC_DPCM_TRIGGER_POST},
@@ -1913,9 +1913,24 @@
 	},
 	/* LSM FE */
 	{
-		.name = "Listen Audio Service",
-		.stream_name = "Listen Audio Service",
-		.cpu_dai_name = "LSM",
+		.name = "Listen 1 Audio Service",
+		.stream_name = "Listen 1 Audio Service",
+		.cpu_dai_name = "LSM1",
+		.platform_name = "msm-lsm-client",
+		.dynamic = 1,
+		.trigger = { SND_SOC_DPCM_TRIGGER_POST,
+				 SND_SOC_DPCM_TRIGGER_POST },
+		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+		.ignore_suspend = 1,
+		.ignore_pmdown_time = 1,
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.codec_name = "snd-soc-dummy",
+		.be_id = MSM_FRONTEND_DAI_LSM1,
+	},
+	{
+		.name = "Listen 2 Audio Service",
+		.stream_name = "Listen 2 Audio Service",
+		.cpu_dai_name = "LSM2",
 		.platform_name = "msm-lsm-client",
 		.dynamic = 1,
 		.trigger = { SND_SOC_DPCM_TRIGGER_POST,
@@ -1925,7 +1940,97 @@
 		.ignore_pmdown_time = 1,
 		.codec_dai_name = "snd-soc-dummy-dai",
 		.codec_name = "snd-soc-dummy",
-		.be_id = MSM_FRONTEND_DAI_LSM1,
+		.be_id = MSM_FRONTEND_DAI_LSM2,
+	},
+	{
+		.name = "Listen 3 Audio Service",
+		.stream_name = "Listen 3 Audio Service",
+		.cpu_dai_name = "LSM3",
+		.platform_name = "msm-lsm-client",
+		.dynamic = 1,
+		.trigger = { SND_SOC_DPCM_TRIGGER_POST,
+			     SND_SOC_DPCM_TRIGGER_POST },
+		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+		.ignore_suspend = 1,
+		.ignore_pmdown_time = 1,
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.codec_name = "snd-soc-dummy",
+		.be_id = MSM_FRONTEND_DAI_LSM3,
+	},
+	{
+		.name = "Listen 4 Audio Service",
+		.stream_name = "Listen 4 Audio Service",
+		.cpu_dai_name = "LSM4",
+		.platform_name = "msm-lsm-client",
+		.dynamic = 1,
+		.trigger = { SND_SOC_DPCM_TRIGGER_POST,
+			     SND_SOC_DPCM_TRIGGER_POST },
+		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+		.ignore_suspend = 1,
+		.ignore_pmdown_time = 1,
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.codec_name = "snd-soc-dummy",
+		.be_id = MSM_FRONTEND_DAI_LSM4,
+	},
+	{
+		.name = "Listen 5 Audio Service",
+		.stream_name = "Listen 5 Audio Service",
+		.cpu_dai_name = "LSM5",
+		.platform_name = "msm-lsm-client",
+		.dynamic = 1,
+		.trigger = { SND_SOC_DPCM_TRIGGER_POST,
+			     SND_SOC_DPCM_TRIGGER_POST },
+		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+		.ignore_suspend = 1,
+		.ignore_pmdown_time = 1,
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.codec_name = "snd-soc-dummy",
+		.be_id = MSM_FRONTEND_DAI_LSM5,
+	},
+	{
+		.name = "Listen 6 Audio Service",
+		.stream_name = "Listen 6 Audio Service",
+		.cpu_dai_name = "LSM6",
+		.platform_name = "msm-lsm-client",
+		.dynamic = 1,
+		.trigger = { SND_SOC_DPCM_TRIGGER_POST,
+			     SND_SOC_DPCM_TRIGGER_POST },
+		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+		.ignore_suspend = 1,
+		.ignore_pmdown_time = 1,
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.codec_name = "snd-soc-dummy",
+		.be_id = MSM_FRONTEND_DAI_LSM6,
+	},
+	{
+		.name = "Listen 7 Audio Service",
+		.stream_name = "Listen 7 Audio Service",
+		.cpu_dai_name = "LSM7",
+		.platform_name = "msm-lsm-client",
+		.dynamic = 1,
+		.trigger = { SND_SOC_DPCM_TRIGGER_POST,
+			     SND_SOC_DPCM_TRIGGER_POST },
+		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+		.ignore_suspend = 1,
+		.ignore_pmdown_time = 1,
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.codec_name = "snd-soc-dummy",
+		.be_id = MSM_FRONTEND_DAI_LSM7,
+	},
+	{
+		.name = "Listen 8 Audio Service",
+		.stream_name = "Listen 8 Audio Service",
+		.cpu_dai_name = "LSM8",
+		.platform_name = "msm-lsm-client",
+		.dynamic = 1,
+		.trigger = { SND_SOC_DPCM_TRIGGER_POST,
+			     SND_SOC_DPCM_TRIGGER_POST },
+		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+		.ignore_suspend = 1,
+		.ignore_pmdown_time = 1,
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.codec_name = "snd-soc-dummy",
+		.be_id = MSM_FRONTEND_DAI_LSM8,
 	},
 	/* Backend BT/FM DAI Links */
 	{
diff --git a/sound/soc/msm/msm-compr-q6.c b/sound/soc/msm/msm-compr-q6.c
index 373090e..635f125 100644
--- a/sound/soc/msm/msm-compr-q6.c
+++ b/sound/soc/msm/msm-compr-q6.c
@@ -1179,7 +1179,13 @@
 			char modelId[128];
 			struct snd_dec_dts opt_dts =
 				compr->info.codec_param.codec.dts;
-			int modelIdLength = opt_dts.modelIdLength;
+			unsigned int modelIdLength = opt_dts.modelIdLength;
+			if (modelIdLength >= sizeof(modelId)) {
+				rc = -EINVAL;
+				pr_err("%s: ERROR: modelIdLength is"
+						"invalid\n", __func__);
+				return rc;
+			}
 			if (copy_from_user(modelId, (void *)opt_dts.modelId,
 				modelIdLength))
 				pr_err("%s: ERROR: copy modelId\n", __func__);
@@ -1222,8 +1228,14 @@
 			char modelId[128];
 			struct snd_dec_dts opt_dts =
 				compr->info.codec_param.codec.dts;
-			int modelIdLength = opt_dts.modelIdLength;
+			unsigned int modelIdLength = opt_dts.modelIdLength;
 			pr_debug("SND_AUDIOCODEC_DTS\n");
+			if (modelIdLength >= sizeof(modelId)) {
+				rc = -EINVAL;
+				pr_err("%s: ERROR: modelIdLength is"
+						"invalid\n", __func__);
+				return rc;
+			}
 			if (copy_from_user(modelId, (void *)opt_dts.modelId,
 				modelIdLength))
 				pr_err("%s: ERROR: copy modelId\n", __func__);
diff --git a/sound/soc/msm/msm-dai-fe.c b/sound/soc/msm/msm-dai-fe.c
index 6f94d99..045a6d0 100644
--- a/sound/soc/msm/msm-dai-fe.c
+++ b/sound/soc/msm/msm-dai-fe.c
@@ -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
@@ -25,7 +25,7 @@
 /* Conventional and unconventional sample rate supported */
 static unsigned int supported_sample_rates[] = {
 	8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000,
-	96000, 192000
+	88200, 96000, 176400, 192000
 };
 
 static struct snd_pcm_hw_constraint_list constraints_sample_rates = {
@@ -689,20 +689,6 @@
 		.name = "DTMF_RX_HOSTLESS",
 	},
 	{
-		.capture = {
-			.stream_name = "Listen Audio Service Capture",
-			.aif_name = "LSM_UL_HL",
-			.rates = SNDRV_PCM_RATE_16000,
-			.formats = SNDRV_PCM_FMTBIT_S16_LE,
-			.channels_min = 1,
-			.channels_max = 1,
-			.rate_min = 16000,
-			.rate_max = 16000,
-		},
-		.ops = &msm_fe_dai_ops,
-		.name = "LSM",
-	},
-	{
 		.playback = {
 			.stream_name = "VoLTE Stub Playback",
 			.aif_name = "VOLTE_STUB_DL",
@@ -801,6 +787,142 @@
 		.ops = &msm_fe_dai_ops,
 		.name = "QCHAT",
 	},
+	{
+		.capture = {
+			.stream_name = "Listen 1 Audio Service Capture",
+			.aif_name = "LSM1_UL_HL",
+			.rates = SNDRV_PCM_RATE_16000,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE,
+			.channels_min = 1,
+			.channels_max = 1,
+			.rate_min = 16000,
+			.rate_max = 16000,
+		},
+		.ops = &msm_fe_dai_ops,
+		.name = "LSM1",
+	},
+	{
+		.capture = {
+			.stream_name = "Listen 2 Audio Service Capture",
+			.aif_name = "LSM2_UL_HL",
+			.rates = SNDRV_PCM_RATE_16000,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE,
+			.channels_min = 1,
+			.channels_max = 1,
+			.rate_min = 16000,
+			.rate_max = 16000,
+		},
+		.ops = &msm_fe_dai_ops,
+		.name = "LSM2",
+	},
+	{
+		.capture = {
+			.stream_name = "Listen 3 Audio Service Capture",
+			.aif_name = "LSM3_UL_HL",
+			.rates = SNDRV_PCM_RATE_16000,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE,
+			.channels_min = 1,
+			.channels_max = 1,
+			.rate_min = 16000,
+			.rate_max = 16000,
+		},
+		.ops = &msm_fe_dai_ops,
+		.name = "LSM3",
+	},
+	{
+		.capture = {
+			.stream_name = "Listen 4 Audio Service Capture",
+			.aif_name = "LSM4_UL_HL",
+			.rates = SNDRV_PCM_RATE_16000,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE,
+			.channels_min = 1,
+			.channels_max = 1,
+			.rate_min = 16000,
+			.rate_max = 16000,
+		},
+		.ops = &msm_fe_dai_ops,
+		.name = "LSM4",
+	},
+	{
+		.capture = {
+			.stream_name = "Listen 5 Audio Service Capture",
+			.aif_name = "LSM5_UL_HL",
+			.rates = SNDRV_PCM_RATE_16000,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE,
+			.channels_min = 1,
+			.channels_max = 1,
+			.rate_min = 16000,
+			.rate_max = 16000,
+		},
+		.ops = &msm_fe_dai_ops,
+		.name = "LSM5",
+	},
+	{
+		.capture = {
+			.stream_name = "Listen 6 Audio Service Capture",
+			.aif_name = "LSM6_UL_HL",
+			.rates = SNDRV_PCM_RATE_16000,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE,
+			.channels_min = 1,
+			.channels_max = 1,
+			.rate_min = 16000,
+			.rate_max = 16000,
+		},
+		.ops = &msm_fe_dai_ops,
+		.name = "LSM6",
+	},
+	{
+		.capture = {
+			.stream_name = "Listen 7 Audio Service Capture",
+			.aif_name = "LSM7_UL_HL",
+			.rates = SNDRV_PCM_RATE_16000,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE,
+			.channels_min = 1,
+			.channels_max = 1,
+			.rate_min = 16000,
+			.rate_max = 16000,
+		},
+		.ops = &msm_fe_dai_ops,
+		.name = "LSM7",
+	},
+	{
+		.capture = {
+			.stream_name = "Listen 8 Audio Service Capture",
+			.aif_name = "LSM8_UL_HL",
+			.rates = SNDRV_PCM_RATE_16000,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE,
+			.channels_min = 1,
+			.channels_max = 1,
+			.rate_min = 16000,
+			.rate_max = 16000,
+		},
+		.ops = &msm_fe_dai_ops,
+		.name = "LSM8",
+	},
+	{
+		.playback = {
+			.stream_name = "VoWLAN Playback",
+			.aif_name = "VoWLAN_DL",
+			.rates = SNDRV_PCM_RATE_8000_48000,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE,
+			.channels_min = 1,
+			.channels_max = 2,
+			.rate_min = 8000,
+			.rate_max = 48000,
+		},
+		.capture = {
+			.stream_name = "VoWLAN Capture",
+			.aif_name = "VoWLAN_UL",
+			.rates = SNDRV_PCM_RATE_8000_48000,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE,
+			.channels_min = 1,
+			.channels_max = 2,
+			.rate_min = 8000,
+			.rate_max = 48000,
+		},
+		.ops = &msm_fe_dai_ops,
+		.name = "VoWLAN",
+	},
 };
 
 static __devinit int msm_fe_dai_dev_probe(struct platform_device *pdev)
diff --git a/sound/soc/msm/msm8226.c b/sound/soc/msm/msm8226.c
index b4ae0a4..cc27fc0 100644
--- a/sound/soc/msm/msm8226.c
+++ b/sound/soc/msm/msm8226.c
@@ -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
@@ -32,6 +32,10 @@
 #include "../codecs/wcd9xxx-common.h"
 #include "../codecs/wcd9306.h"
 
+#define SAMPLING_RATE_48KHZ 48000
+#define SAMPLING_RATE_96KHZ 96000
+#define SAMPLING_RATE_192KHZ 192000
+
 #define DRV_NAME "msm8226-asoc-tapan"
 
 #define MSM_SLIM_0_RX_MAX_CHANNELS		2
@@ -82,6 +86,7 @@
 	.read_fw_bin = false,
 	.calibration = NULL,
 	.micbias = MBHC_MICBIAS2,
+	.anc_micbias = MBHC_MICBIAS2,
 	.mclk_cb_fn = msm_snd_enable_codec_ext_clk,
 	.mclk_rate = TAPAN_EXT_CLK_RATE,
 	.gpio = 0,
@@ -93,9 +98,12 @@
 	.swap_gnd_mic = NULL,
 	.cs_enable_flags = (1 << MBHC_CS_ENABLE_POLLING |
 			    1 << MBHC_CS_ENABLE_INSERTION |
-			    1 << MBHC_CS_ENABLE_REMOVAL),
+			    1 << MBHC_CS_ENABLE_REMOVAL |
+			    1 << MBHC_CS_ENABLE_DET_ANC),
 	.do_recalibration = true,
 	.use_vddio_meas = true,
+	.enable_anc_mic_detect = false,
+	.hw_jack_type = FOUR_POLE_JACK,
 };
 
 struct msm_auxpcm_gpio {
@@ -150,6 +158,8 @@
 static int ext_spk_amp_gpio = -1;
 static int vdd_spkr_gpio = -1;
 static int msm_proxy_rx_ch = 2;
+
+static int slim0_rx_sample_rate = SAMPLING_RATE_48KHZ;
 static int slim0_rx_bit_format = SNDRV_PCM_FORMAT_S16_LE;
 
 static inline int param_is_mask(int p)
@@ -384,6 +394,9 @@
 static const char *const slim0_tx_ch_text[] = {"One", "Two", "Three", "Four"};
 static const char *const proxy_rx_ch_text[] = {"One", "Two", "Three", "Four",
 	"Five", "Six", "Seven", "Eight"};
+static char const *rx_bit_format_text[] = {"S16_LE", "S24_LE"};
+static char const *slim0_rx_sample_rate_text[] = {"KHZ_48", "KHZ_96",
+						  "KHZ_192"};
 
 static const struct soc_enum msm_enum[] = {
 	SOC_ENUM_SINGLE_EXT(2, slim0_rx_ch_text),
@@ -395,6 +408,58 @@
 	SOC_ENUM_SINGLE_EXT(2, btsco_rate_text),
 };
 
+static int slim0_rx_sample_rate_get(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	int sample_rate_val = 0;
+
+	switch (slim0_rx_sample_rate) {
+	case SAMPLING_RATE_192KHZ:
+		sample_rate_val = 2;
+		break;
+
+	case SAMPLING_RATE_96KHZ:
+		sample_rate_val = 1;
+		break;
+
+	case SAMPLING_RATE_48KHZ:
+	default:
+		sample_rate_val = 0;
+		break;
+	}
+
+	ucontrol->value.integer.value[0] = sample_rate_val;
+	pr_debug("%s: slim0_rx_sample_rate = %d\n", __func__,
+				slim0_rx_sample_rate);
+
+	return 0;
+}
+
+static int slim0_rx_sample_rate_put(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	pr_debug("%s: ucontrol value = %ld\n", __func__,
+			ucontrol->value.integer.value[0]);
+
+	switch (ucontrol->value.integer.value[0]) {
+	case 2:
+		slim0_rx_sample_rate = SAMPLING_RATE_192KHZ;
+		break;
+	case 1:
+		slim0_rx_sample_rate = SAMPLING_RATE_96KHZ;
+		break;
+	case 0:
+	default:
+		slim0_rx_sample_rate = SAMPLING_RATE_48KHZ;
+		break;
+	}
+
+	pr_debug("%s: slim0_rx_sample_rate = %d\n", __func__,
+			slim0_rx_sample_rate);
+
+	return 0;
+}
+
 static int msm_slim_0_rx_ch_get(struct snd_kcontrol *kcontrol,
 	struct snd_ctl_elem_value *ucontrol)
 {
@@ -721,8 +786,7 @@
 	pr_debug("%s()\n", __func__);
 	param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
 					slim0_rx_bit_format);
-
-	rate->min = rate->max = 48000;
+	rate->min = rate->max = slim0_rx_sample_rate;
 	channels->min = channels->max = msm_slim_0_rx_ch;
 
 	return 0;
@@ -776,6 +840,8 @@
 	SOC_ENUM_SINGLE_EXT(2, slim0_rx_ch_text),
 	SOC_ENUM_SINGLE_EXT(4, slim0_tx_ch_text),
 	SOC_ENUM_SINGLE_EXT(8, proxy_rx_ch_text),
+	SOC_ENUM_SINGLE_EXT(2, rx_bit_format_text),
+	SOC_ENUM_SINGLE_EXT(3, slim0_rx_sample_rate_text),
 };
 
 static const struct snd_kcontrol_new msm_snd_controls[] = {
@@ -791,7 +857,8 @@
 			msm_proxy_rx_ch_get, msm_proxy_rx_ch_put),
 	SOC_ENUM_EXT("SLIM_0_RX Format", msm_snd_enum[3],
 			slim0_rx_bit_format_get, slim0_rx_bit_format_put),
-
+	SOC_ENUM_EXT("SLIM_0_RX SampleRate", msm_snd_enum[4],
+			slim0_rx_sample_rate_get, slim0_rx_sample_rate_put),
 };
 
 static int msm_afe_set_config(struct snd_soc_codec *codec)
@@ -1406,9 +1473,9 @@
 	},
 	/* LSM FE */
 	{
-		.name = "Listen Audio Service",
-		.stream_name = "Listen Audio Service",
-		.cpu_dai_name = "LSM",
+		.name = "Listen 1 Audio Service",
+		.stream_name = "Listen 1 Audio Service",
+		.cpu_dai_name = "LSM1",
 		.platform_name = "msm-lsm-client",
 		.dynamic = 1,
 		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
@@ -1435,6 +1502,157 @@
 		 /* this dainlink has playback support */
 		.be_id = MSM_FRONTEND_DAI_MULTIMEDIA8,
 	},
+	{
+		.name = "Listen 2 Audio Service",
+		.stream_name = "Listen 2 Audio Service",
+		.cpu_dai_name = "LSM2",
+		.platform_name = "msm-lsm-client",
+		.dynamic = 1,
+		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
+			    SND_SOC_DPCM_TRIGGER_POST },
+		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+		.ignore_suspend = 1,
+		.ignore_pmdown_time = 1,
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.codec_name = "snd-soc-dummy",
+		.be_id = MSM_FRONTEND_DAI_LSM2,
+	},
+	{
+		.name = "Listen 3 Audio Service",
+		.stream_name = "Listen 3 Audio Service",
+		.cpu_dai_name = "LSM3",
+		.platform_name = "msm-lsm-client",
+		.dynamic = 1,
+		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
+			    SND_SOC_DPCM_TRIGGER_POST },
+		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+		.ignore_suspend = 1,
+		.ignore_pmdown_time = 1,
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.codec_name = "snd-soc-dummy",
+		.be_id = MSM_FRONTEND_DAI_LSM3,
+	},
+	{
+		.name = "Listen 4 Audio Service",
+		.stream_name = "Listen 4 Audio Service",
+		.cpu_dai_name = "LSM4",
+		.platform_name = "msm-lsm-client",
+		.dynamic = 1,
+		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
+			    SND_SOC_DPCM_TRIGGER_POST },
+		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+		.ignore_suspend = 1,
+		.ignore_pmdown_time = 1,
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.codec_name = "snd-soc-dummy",
+		.be_id = MSM_FRONTEND_DAI_LSM4,
+	},
+	{
+		.name = "Listen 5 Audio Service",
+		.stream_name = "Listen 5 Audio Service",
+		.cpu_dai_name = "LSM5",
+		.platform_name = "msm-lsm-client",
+		.dynamic = 1,
+		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
+			    SND_SOC_DPCM_TRIGGER_POST },
+		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+		.ignore_suspend = 1,
+		.ignore_pmdown_time = 1,
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.codec_name = "snd-soc-dummy",
+		.be_id = MSM_FRONTEND_DAI_LSM5,
+	},
+	{
+		.name = "Listen 6 Audio Service",
+		.stream_name = "Listen 6 Audio Service",
+		.cpu_dai_name = "LSM6",
+		.platform_name = "msm-lsm-client",
+		.dynamic = 1,
+		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
+			    SND_SOC_DPCM_TRIGGER_POST },
+		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+		.ignore_suspend = 1,
+		.ignore_pmdown_time = 1,
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.codec_name = "snd-soc-dummy",
+		.be_id = MSM_FRONTEND_DAI_LSM6,
+	},
+	{
+		.name = "Listen 7 Audio Service",
+		.stream_name = "Listen 7 Audio Service",
+		.cpu_dai_name = "LSM7",
+		.platform_name = "msm-lsm-client",
+		.dynamic = 1,
+		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
+			    SND_SOC_DPCM_TRIGGER_POST },
+		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+		.ignore_suspend = 1,
+		.ignore_pmdown_time = 1,
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.codec_name = "snd-soc-dummy",
+		.be_id = MSM_FRONTEND_DAI_LSM7,
+	},
+	{
+		.name = "Listen 8 Audio Service",
+		.stream_name = "Listen 8 Audio Service",
+		.cpu_dai_name = "LSM8",
+		.platform_name = "msm-lsm-client",
+		.dynamic = 1,
+		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
+			    SND_SOC_DPCM_TRIGGER_POST },
+		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+		.ignore_suspend = 1,
+		.ignore_pmdown_time = 1,
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.codec_name = "snd-soc-dummy",
+		.be_id = MSM_FRONTEND_DAI_LSM8,
+	},
+	{/* hw:x,28 */
+		.name = "INT_HFP_BT Hostless",
+		.stream_name = "INT_HFP_BT Hostless",
+		.cpu_dai_name   = "INT_HFP_BT_HOSTLESS",
+		.platform_name  = "msm-pcm-hostless",
+		.dynamic = 1,
+		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
+			    SND_SOC_DPCM_TRIGGER_POST},
+		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+		.ignore_suspend = 1,
+		/* this dai link has playback support */
+		.ignore_pmdown_time = 1,
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.codec_name = "snd-soc-dummy",
+	},
+	{/* hw:x,29 */
+		.name = "MSM8226 HFP TX",
+		.stream_name = "MultiMedia6",
+		.cpu_dai_name = "MultiMedia6",
+		.platform_name  = "msm-pcm-loopback",
+		.dynamic = 1,
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.codec_name = "snd-soc-dummy",
+		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
+			    SND_SOC_DPCM_TRIGGER_POST},
+		.ignore_suspend = 1,
+		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+		/* this dai link has playback support */
+		.ignore_pmdown_time = 1,
+		.be_id = MSM_FRONTEND_DAI_MULTIMEDIA6,
+	},
+	{/* hw:x,30 */
+		.name = "VoWLAN",
+		.stream_name = "VoWLAN",
+		.cpu_dai_name   = "VoWLAN",
+		.platform_name  = "msm-pcm-voice",
+		.dynamic = 1,
+		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
+			    SND_SOC_DPCM_TRIGGER_POST},
+		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+		.ignore_suspend = 1,
+		.ignore_pmdown_time = 1,
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.codec_name = "snd-soc-dummy",
+		.be_id = MSM_FRONTEND_DAI_VOWLAN,
+	},
 	/* Backend BT/FM DAI Links */
 	{
 		.name = LPASS_BE_INT_BT_SCO_RX,
@@ -2042,6 +2260,8 @@
 	struct msm8226_asoc_mach_data *pdata;
 	int ret;
 	const char *auxpcm_pri_gpio_set = NULL;
+	const char *mbhc_audio_jack_type = NULL;
+	size_t n = strlen("4-pole-jack");
 
 	if (!pdev->dev.of_node) {
 		dev_err(&pdev->dev, "No platform supplied from device tree\n");
@@ -2107,6 +2327,35 @@
 	mbhc_cfg.gpio_level_insert = of_property_read_bool(pdev->dev.of_node,
 					"qcom,headset-jack-type-NC");
 
+	ret = of_property_read_string(pdev->dev.of_node,
+		"qcom,mbhc-audio-jack-type", &mbhc_audio_jack_type);
+	if (ret) {
+		dev_dbg(&pdev->dev, "Looking up %s property in node %s failed",
+			"qcom,mbhc-audio-jack-type",
+			pdev->dev.of_node->full_name);
+		mbhc_cfg.hw_jack_type = FOUR_POLE_JACK;
+		mbhc_cfg.enable_anc_mic_detect = false;
+		dev_dbg(&pdev->dev, "Jack type properties set to default");
+	} else {
+		if (!strncmp(mbhc_audio_jack_type, "4-pole-jack", n)) {
+			mbhc_cfg.hw_jack_type = FOUR_POLE_JACK;
+			mbhc_cfg.enable_anc_mic_detect = false;
+			dev_dbg(&pdev->dev, "This hardware has 4 pole jack");
+		} else if (!strncmp(mbhc_audio_jack_type, "5-pole-jack", n)) {
+			mbhc_cfg.hw_jack_type = FIVE_POLE_JACK;
+			mbhc_cfg.enable_anc_mic_detect = true;
+			dev_dbg(&pdev->dev, "This hardware has 5 pole jack");
+		} else if (!strncmp(mbhc_audio_jack_type, "6-pole-jack", n)) {
+			mbhc_cfg.hw_jack_type = SIX_POLE_JACK;
+			mbhc_cfg.enable_anc_mic_detect = true;
+			dev_dbg(&pdev->dev, "This hardware has 6 pole jack");
+		} else {
+			mbhc_cfg.hw_jack_type = FOUR_POLE_JACK;
+			mbhc_cfg.enable_anc_mic_detect = false;
+			dev_dbg(&pdev->dev, "Unknown value, hence setting to default");
+		}
+	}
+
 	ret = snd_soc_register_card(card);
 	if (ret == -EPROBE_DEFER)
 		goto err;
diff --git a/sound/soc/msm/msm8974.c b/sound/soc/msm/msm8974.c
index 4c3a72e..8aa1e35 100644
--- a/sound/soc/msm/msm8974.c
+++ b/sound/soc/msm/msm8974.c
@@ -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
@@ -46,6 +46,7 @@
 #define BTSCO_RATE_16KHZ 16000
 
 static int slim0_rx_bit_format = SNDRV_PCM_FORMAT_S16_LE;
+static int slim0_tx_bit_format = SNDRV_PCM_FORMAT_S16_LE;
 static int hdmi_rx_bit_format = SNDRV_PCM_FORMAT_S16_LE;
 
 #define SAMPLING_RATE_48KHZ 48000
@@ -117,6 +118,7 @@
 	.read_fw_bin = false,
 	.calibration = NULL,
 	.micbias = MBHC_MICBIAS2,
+	.anc_micbias = MBHC_MICBIAS2,
 	.mclk_cb_fn = msm_snd_enable_codec_ext_clk,
 	.mclk_rate = TAIKO_EXT_CLK_RATE,
 	.gpio = 0,
@@ -128,9 +130,12 @@
 	.swap_gnd_mic = NULL,
 	.cs_enable_flags = (1 << MBHC_CS_ENABLE_POLLING |
 			    1 << MBHC_CS_ENABLE_INSERTION |
-			    1 << MBHC_CS_ENABLE_REMOVAL),
+			    1 << MBHC_CS_ENABLE_REMOVAL |
+			    1 << MBHC_CS_ENABLE_DET_ANC),
 	.do_recalibration = true,
 	.use_vddio_meas = true,
+	.enable_anc_mic_detect = false,
+	.hw_jack_type = SIX_POLE_JACK,
 };
 
 struct msm_auxpcm_gpio {
@@ -1313,6 +1318,8 @@
 			SNDRV_PCM_HW_PARAM_CHANNELS);
 
 	pr_debug("%s()\n", __func__);
+	param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+				   slim0_tx_bit_format);
 	rate->min = rate->max = 48000;
 	channels->min = channels->max = msm_slim_0_tx_ch;
 
@@ -2111,9 +2118,9 @@
 	},
 	/* LSM FE */
 	{
-		.name = "Listen Audio Service",
-		.stream_name = "Listen Audio Service",
-		.cpu_dai_name = "LSM",
+		.name = "Listen 1 Audio Service",
+		.stream_name = "Listen 1 Audio Service",
+		.cpu_dai_name = "LSM1",
 		.platform_name = "msm-lsm-client",
 		.dynamic = 1,
 		.trigger = { SND_SOC_DPCM_TRIGGER_POST,
@@ -2250,6 +2257,111 @@
 		.be_id = MSM_FRONTEND_DAI_MULTIMEDIA6,
 	},
 	{
+		.name = "Listen 2 Audio Service",
+		.stream_name = "Listen 2 Audio Service",
+		.cpu_dai_name = "LSM2",
+		.platform_name = "msm-lsm-client",
+		.dynamic = 1,
+		.trigger = { SND_SOC_DPCM_TRIGGER_POST,
+			     SND_SOC_DPCM_TRIGGER_POST },
+		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+		.ignore_suspend = 1,
+		.ignore_pmdown_time = 1,
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.codec_name = "snd-soc-dummy",
+		.be_id = MSM_FRONTEND_DAI_LSM2,
+	},
+	{
+		.name = "Listen 3 Audio Service",
+		.stream_name = "Listen 3 Audio Service",
+		.cpu_dai_name = "LSM3",
+		.platform_name = "msm-lsm-client",
+		.dynamic = 1,
+		.trigger = { SND_SOC_DPCM_TRIGGER_POST,
+			     SND_SOC_DPCM_TRIGGER_POST },
+		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+		.ignore_suspend = 1,
+		.ignore_pmdown_time = 1,
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.codec_name = "snd-soc-dummy",
+		.be_id = MSM_FRONTEND_DAI_LSM3,
+	},
+	{
+		.name = "Listen 4 Audio Service",
+		.stream_name = "Listen 4 Audio Service",
+		.cpu_dai_name = "LSM4",
+		.platform_name = "msm-lsm-client",
+		.dynamic = 1,
+		.trigger = { SND_SOC_DPCM_TRIGGER_POST,
+			     SND_SOC_DPCM_TRIGGER_POST },
+		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+		.ignore_suspend = 1,
+		.ignore_pmdown_time = 1,
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.codec_name = "snd-soc-dummy",
+		.be_id = MSM_FRONTEND_DAI_LSM4,
+	},
+	{
+		.name = "Listen 5 Audio Service",
+		.stream_name = "Listen 5 Audio Service",
+		.cpu_dai_name = "LSM5",
+		.platform_name = "msm-lsm-client",
+		.dynamic = 1,
+		.trigger = { SND_SOC_DPCM_TRIGGER_POST,
+			     SND_SOC_DPCM_TRIGGER_POST },
+		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+		.ignore_suspend = 1,
+		.ignore_pmdown_time = 1,
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.codec_name = "snd-soc-dummy",
+		.be_id = MSM_FRONTEND_DAI_LSM5,
+	},
+	{
+		.name = "Listen 6 Audio Service",
+		.stream_name = "Listen 6 Audio Service",
+		.cpu_dai_name = "LSM6",
+		.platform_name = "msm-lsm-client",
+		.dynamic = 1,
+		.trigger = { SND_SOC_DPCM_TRIGGER_POST,
+			     SND_SOC_DPCM_TRIGGER_POST },
+		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+		.ignore_suspend = 1,
+		.ignore_pmdown_time = 1,
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.codec_name = "snd-soc-dummy",
+		.be_id = MSM_FRONTEND_DAI_LSM6,
+	},
+	{
+		.name = "Listen 7 Audio Service",
+		.stream_name = "Listen 7 Audio Service",
+		.cpu_dai_name = "LSM7",
+		.platform_name = "msm-lsm-client",
+		.dynamic = 1,
+		.trigger = { SND_SOC_DPCM_TRIGGER_POST,
+			     SND_SOC_DPCM_TRIGGER_POST },
+		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+		.ignore_suspend = 1,
+		.ignore_pmdown_time = 1,
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.codec_name = "snd-soc-dummy",
+		.be_id = MSM_FRONTEND_DAI_LSM7,
+	},
+	{
+		.name = "Listen 8 Audio Service",
+		.stream_name = "Listen 8 Audio Service",
+		.cpu_dai_name = "LSM8",
+		.platform_name = "msm-lsm-client",
+		.dynamic = 1,
+		.trigger = { SND_SOC_DPCM_TRIGGER_POST,
+			     SND_SOC_DPCM_TRIGGER_POST },
+		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+		.ignore_suspend = 1,
+		.ignore_pmdown_time = 1,
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.codec_name = "snd-soc-dummy",
+		.be_id = MSM_FRONTEND_DAI_LSM8,
+	},
+	{
 		.name = LPASS_BE_SLIMBUS_4_TX,
 		.stream_name = "Slimbus4 Capture",
 		.cpu_dai_name = "msm-dai-q6-dev.16393",
@@ -2286,6 +2398,21 @@
 		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
 		.ops = &msm8974_slimbus_2_be_ops,
 	},
+	{
+		.name = "MSM8974 Media9",
+		.stream_name = "MultiMedia9",
+		.cpu_dai_name   = "MultiMedia9",
+		.platform_name  = "msm-pcm-dsp.0",
+		.dynamic = 1,
+		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
+				SND_SOC_DPCM_TRIGGER_POST},
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.codec_name = "snd-soc-dummy",
+		.ignore_suspend = 1,
+		/* this dainlink has playback support */
+		.ignore_pmdown_time = 1,
+		.be_id = MSM_FRONTEND_DAI_MULTIMEDIA9,
+	},
 	/* Backend BT/FM DAI Links */
 	{
 		.name = LPASS_BE_INT_BT_SCO_RX,
@@ -2577,6 +2704,19 @@
 		.be_hw_params_fixup = msm_be_hw_params_fixup,
 		.ignore_suspend = 1,
 	},
+	/* Incall Music 2 BACK END DAI Link */
+	{
+		.name = LPASS_BE_VOICE2_PLAYBACK_TX,
+		.stream_name = "Voice2 Farend Playback",
+		.cpu_dai_name = "msm-dai-q6-dev.32770",
+		.platform_name = "msm-pcm-routing",
+		.codec_name     = "msm-stub-codec.1",
+		.codec_dai_name = "msm-stub-rx",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_VOICE2_PLAYBACK_TX,
+		.be_hw_params_fixup = msm_be_hw_params_fixup,
+		.ignore_suspend = 1,
+	}
 };
 
 static struct snd_soc_dai_link msm8974_hdmi_dai_link[] = {
@@ -2711,6 +2851,8 @@
 	int ret;
 	const char *auxpcm_pri_gpio_set = NULL;
 	const char *prop_name_ult_lo_gpio = "qcom,ext-ult-lo-amp-gpio";
+	const char *mbhc_audio_jack_type = NULL;
+	size_t n = strlen("4-pole-jack");
 	struct resource	*pri_muxsel;
 	struct resource	*sec_muxsel;
 
@@ -2770,6 +2912,34 @@
 	if (ret)
 		goto err;
 
+	ret = of_property_read_string(pdev->dev.of_node,
+		"qcom,mbhc-audio-jack-type", &mbhc_audio_jack_type);
+	if (ret) {
+		dev_dbg(&pdev->dev, "Looking up %s property in node %s failed",
+			"qcom,mbhc-audio-jack-type",
+			pdev->dev.of_node->full_name);
+		mbhc_cfg.hw_jack_type = FOUR_POLE_JACK;
+		mbhc_cfg.enable_anc_mic_detect = false;
+		dev_dbg(&pdev->dev, "Jack type properties set to default");
+	} else {
+		if (!strncmp(mbhc_audio_jack_type, "4-pole-jack", n)) {
+			mbhc_cfg.hw_jack_type = FOUR_POLE_JACK;
+			mbhc_cfg.enable_anc_mic_detect = false;
+			dev_dbg(&pdev->dev, "This hardware has 4 pole jack");
+		} else if (!strncmp(mbhc_audio_jack_type, "5-pole-jack", n)) {
+			mbhc_cfg.hw_jack_type = FIVE_POLE_JACK;
+			mbhc_cfg.enable_anc_mic_detect = true;
+			dev_dbg(&pdev->dev, "This hardware has 5 pole jack");
+		} else if (!strncmp(mbhc_audio_jack_type, "6-pole-jack", n)) {
+			mbhc_cfg.hw_jack_type = SIX_POLE_JACK;
+			mbhc_cfg.enable_anc_mic_detect = true;
+			dev_dbg(&pdev->dev, "This hardware has 6 pole jack");
+		} else {
+			mbhc_cfg.hw_jack_type = FOUR_POLE_JACK;
+			mbhc_cfg.enable_anc_mic_detect = false;
+			dev_dbg(&pdev->dev, "Unknown value, hence setting to default");
+		}
+	}
 	if (of_property_read_bool(pdev->dev.of_node, "qcom,hdmi-audio-rx")) {
 		dev_info(&pdev->dev, "%s(): hdmi audio support present\n",
 				__func__);
diff --git a/sound/soc/msm/msm8x10.c b/sound/soc/msm/msm8x10.c
index c1ba26a..89df806 100644
--- a/sound/soc/msm/msm8x10.c
+++ b/sound/soc/msm/msm8x10.c
@@ -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
@@ -99,11 +99,14 @@
 	.insert_detect = true,
 	.swap_gnd_mic = NULL,
 	.use_int_rbias = false,
+	.micbias_enable_flags = 1 << MBHC_MICBIAS_ENABLE_THRESHOLD_HEADSET |
+				1 << MBHC_MICBIAS_ENABLE_REGULAR_HEADSET,
 	.cs_enable_flags = (1 << MBHC_CS_ENABLE_POLLING |
 			    1 << MBHC_CS_ENABLE_INSERTION |
 			    1 << MBHC_CS_ENABLE_REMOVAL),
 	.do_recalibration = false,
 	.use_vddio_meas = false,
+	.hw_jack_type = FOUR_POLE_JACK,
 };
 
 /*
@@ -284,6 +287,8 @@
 					SNDRV_PCM_HW_PARAM_CHANNELS);
 
 	pr_debug("%s(), channel:%d\n", __func__, msm_pri_mi2s_tx_ch);
+	param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+					msm_sec_mi2s_rx_bit_format);
 	rate->min = rate->max = 48000;
 	channels->min = channels->max = msm_pri_mi2s_tx_ch;
 
@@ -607,21 +612,21 @@
 	btn_high = wcd9xxx_mbhc_cal_btn_det_mp(btn_cfg,
 					       MBHC_BTN_DET_V_BTN_HIGH);
 	btn_low[0] = -50;
-	btn_high[0] = 10;
-	btn_low[1] = 11;
-	btn_high[1] = 52;
-	btn_low[2] = 53;
-	btn_high[2] = 94;
-	btn_low[3] = 95;
-	btn_high[3] = 133;
-	btn_low[4] = 134;
-	btn_high[4] = 171;
-	btn_low[5] = 172;
-	btn_high[5] = 208;
-	btn_low[6] = 209;
-	btn_high[6] = 244;
-	btn_low[7] = 245;
-	btn_high[7] = 330;
+	btn_high[0] = 20;
+	btn_low[1] = 21;
+	btn_high[1] = 61;
+	btn_low[2] = 62;
+	btn_high[2] = 104;
+	btn_low[3] = 105;
+	btn_high[3] = 148;
+	btn_low[4] = 149;
+	btn_high[4] = 189;
+	btn_low[5] = 190;
+	btn_high[5] = 228;
+	btn_low[6] = 229;
+	btn_high[6] = 264;
+	btn_low[7] = 265;
+	btn_high[7] = 500;
 	n_ready = wcd9xxx_mbhc_cal_btn_det_mp(btn_cfg, MBHC_BTN_DET_N_READY);
 	n_ready[0] = 80;
 	n_ready[1] = 68;
@@ -889,6 +894,21 @@
 		.codec_name = "snd-soc-dummy",
 		.be_id = MSM_FRONTEND_DAI_QCHAT,
 	},
+	{/* hw:x,15 */
+		.name = "MSM8X10 Media9",
+		.stream_name = "MultiMedia9",
+		.cpu_dai_name   = "MultiMedia9",
+		.platform_name  = "msm-pcm-dsp.0",
+		.dynamic = 1,
+		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
+			SND_SOC_DPCM_TRIGGER_POST},
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.codec_name = "snd-soc-dummy",
+		.ignore_suspend = 1,
+		/* this dainlink has playback support */
+		.ignore_pmdown_time = 1,
+		.be_id = MSM_FRONTEND_DAI_MULTIMEDIA9
+	},
 	/* Backend I2S DAI Links */
 	{
 		.name = LPASS_BE_SEC_MI2S_RX,
@@ -1034,6 +1054,19 @@
 		.be_hw_params_fixup = msm_be_hw_params_fixup,
 		.ignore_suspend = 1,
 	},
+	/* Incall Music 2 BACK END DAI Link */
+	{
+		.name = LPASS_BE_VOICE2_PLAYBACK_TX,
+		.stream_name = "Voice2 Farend Playback",
+		.cpu_dai_name = "msm-dai-q6-dev.32770",
+		.platform_name = "msm-pcm-routing",
+		.codec_name     = "msm-stub-codec.1",
+		.codec_dai_name = "msm-stub-rx",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_VOICE2_PLAYBACK_TX,
+		.be_hw_params_fixup = msm_be_hw_params_fixup,
+		.ignore_suspend = 1,
+	},
 };
 
 struct snd_soc_card snd_soc_card_msm8x10 = {
@@ -1046,6 +1079,8 @@
 static __devinit int msm8x10_asoc_machine_probe(struct platform_device *pdev)
 {
 	struct snd_soc_card *card = &snd_soc_card_msm8x10;
+	const char *mbhc_audio_jack_type = NULL;
+	size_t n = strlen("4-pole-jack");
 	int ret;
 
 	dev_dbg(&pdev->dev, "%s\n", __func__);
@@ -1083,6 +1118,35 @@
 	mbhc_cfg.use_int_rbias = of_property_read_bool(pdev->dev.of_node,
 						"qcom,mbhc-bias-internal");
 
+	ret = of_property_read_string(pdev->dev.of_node,
+		"qcom,mbhc-audio-jack-type", &mbhc_audio_jack_type);
+	if (ret) {
+		dev_dbg(&pdev->dev, "Looking up %s property in node %s failed",
+			"qcom,mbhc-audio-jack-type",
+			pdev->dev.of_node->full_name);
+		mbhc_cfg.hw_jack_type = FOUR_POLE_JACK;
+		mbhc_cfg.enable_anc_mic_detect = false;
+		dev_dbg(&pdev->dev, "Jack type properties set to default");
+	} else {
+		if (!strncmp(mbhc_audio_jack_type, "4-pole-jack", n)) {
+			mbhc_cfg.hw_jack_type = FOUR_POLE_JACK;
+			mbhc_cfg.enable_anc_mic_detect = false;
+			dev_dbg(&pdev->dev, "This hardware has 4 pole jack");
+		} else if (!strncmp(mbhc_audio_jack_type, "5-pole-jack", n)) {
+			mbhc_cfg.hw_jack_type = FIVE_POLE_JACK;
+			mbhc_cfg.enable_anc_mic_detect = true;
+			dev_dbg(&pdev->dev, "This hardware has 5 pole jack");
+		} else if (!strncmp(mbhc_audio_jack_type, "6-pole-jack", n)) {
+			mbhc_cfg.hw_jack_type = SIX_POLE_JACK;
+			mbhc_cfg.enable_anc_mic_detect = true;
+			dev_dbg(&pdev->dev, "This hardware has 6 pole jack");
+		} else {
+			mbhc_cfg.hw_jack_type = FOUR_POLE_JACK;
+			mbhc_cfg.enable_anc_mic_detect = false;
+			dev_dbg(&pdev->dev, "Unknown value, hence setting to default");
+		}
+	}
+
 	spdev = pdev;
 
 	ret = snd_soc_register_card(card);
diff --git a/sound/soc/msm/qdsp6v2/audio_acdb.c b/sound/soc/msm/qdsp6v2/audio_acdb.c
index 4e04bef..df15c59 100644
--- a/sound/soc/msm/qdsp6v2/audio_acdb.c
+++ b/sound/soc/msm/qdsp6v2/audio_acdb.c
@@ -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
@@ -1151,13 +1151,6 @@
 		result = result2;
 	}
 
-	result2 = q6lsm_unmap_cal_blocks();
-	if (result2 < 0) {
-		pr_err("%s: lsm_unmap_cal_blocks failed, err = %d\n",
-			__func__, result2);
-		result = result2;
-	}
-
 	result2 = q6asm_unmap_cal_blocks();
 	if (result2 < 0) {
 		pr_err("%s: asm_unmap_cal_blocks failed, err = %d\n",
diff --git a/sound/soc/msm/qdsp6v2/audio_ocmem.c b/sound/soc/msm/qdsp6v2/audio_ocmem.c
index 4a25606..5be880d 100644
--- a/sound/soc/msm/qdsp6v2/audio_ocmem.c
+++ b/sound/soc/msm/qdsp6v2/audio_ocmem.c
@@ -536,6 +536,7 @@
 	mutex_unlock(&audio_ocmem_lcl.state_process_lock);
 fail_cmd:
 	pr_debug("%s: exit\n", __func__);
+	audio_ocmem_lcl.buf = NULL;
 	audio_ocmem_lcl.audio_ocmem_running = false;
 	return ret;
 }
@@ -834,6 +835,7 @@
 	ret = ocmem_free(OCMEM_LP_AUDIO, audio_ocmem_lcl.buf);
 	if (ret)
 		pr_err("%s: ocmem_free failed\n", __func__);
+	audio_ocmem_lcl.buf = NULL;
 }
 
 static int lpass_notifier_cb(struct notifier_block *this, unsigned long code,
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-compress-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c
index 7935100..aa4d88d 100644
--- a/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c
@@ -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
@@ -49,8 +49,13 @@
 #define PARTIAL_DRAIN_ACK_EARLY_BY_MSEC	150
 #define MP3_OUTPUT_FRAME_SZ		1152
 #define AAC_OUTPUT_FRAME_SZ		1024
+#define AC3_OUTPUT_FRAME_SZ		1536
+#define EAC3_OUTPUT_FRAME_SZ		1536
 #define DSP_NUM_OUTPUT_FRAME_BUFFERED	2
 
+/* decoder parameter length */
+#define DDP_DEC_MAX_NUM_PARAM		18
+
 /* Default values used if user space does not set */
 #define COMPR_PLAYBACK_MIN_FRAGMENT_SIZE (8 * 1024)
 #define COMPR_PLAYBACK_MAX_FRAGMENT_SIZE (128 * 1024)
@@ -61,11 +66,26 @@
 const DECLARE_TLV_DB_LINEAR(msm_compr_vol_gain, 0,
 				COMPRESSED_LR_VOL_MAX_STEPS);
 
+/*
+ * LSB 8 bits is used as stream id for some DSP
+ * commands for compressed playback.
+ */
+#define STREAM_ID_FROM_TOKEN(i) (i & 0xFF)
+
+/* Stream id switches between 1 and 2 */
+#define NEXT_STREAM_ID(stream_id) ((stream_id & 1) + 1)
+
+#define STREAM_ARRAY_INDEX(stream_id) (stream_id - 1)
+
+#define MAX_NUMBER_OF_STREAMS 2
+
 struct msm_compr_gapless_state {
 	bool set_next_stream_id;
-	int32_t stream_opened[2];
+	int32_t stream_opened[MAX_NUMBER_OF_STREAMS];
 	uint32_t initial_samples_drop;
 	uint32_t trailing_samples_drop;
+	uint32_t gapless_transition;
+	bool use_dsp_gapless_mode;
 };
 
 struct msm_compr_pdata {
@@ -73,6 +93,8 @@
 	struct snd_compr_stream *cstream[MSM_FRONTEND_DAI_MAX];
 	uint32_t volume[MSM_FRONTEND_DAI_MAX][2]; /* For both L & R */
 	struct msm_compr_audio_effects *audio_effects[MSM_FRONTEND_DAI_MAX];
+	bool use_dsp_gapless_mode;
+	struct msm_compr_dec_params *dec_params[MSM_FRONTEND_DAI_MAX];
 };
 
 struct msm_compr_audio {
@@ -88,8 +110,10 @@
 	uint32_t app_pointer;
 	uint32_t buffer_size;
 	uint32_t byte_offset;
-	uint32_t copied_total;
-	uint32_t bytes_received;
+	uint32_t copied_total; /* bytes consumed by DSP */
+	uint32_t bytes_received; /* from userspace */
+	uint32_t bytes_sent; /* to DSP */
+
 	int32_t first_buffer;
 	int32_t last_buffer;
 	int32_t partial_drain_delay;
@@ -102,6 +126,8 @@
 	uint32_t cmd_ack;
 	uint32_t cmd_interrupt;
 	uint32_t drain_ready;
+	uint32_t stream_available;
+	uint32_t next_stream;
 
 	struct msm_compr_gapless_state gapless_state;
 
@@ -117,6 +143,7 @@
 	wait_queue_head_t drain_wait;
 	wait_queue_head_t flush_wait;
 	wait_queue_head_t close_wait;
+	wait_queue_head_t wait_for_stream_avail;
 
 	spinlock_t lock;
 };
@@ -128,6 +155,10 @@
 	struct eq_params equalizer;
 };
 
+struct msm_compr_dec_params {
+	struct snd_dec_ddp ddp_params;
+};
+
 static int msm_compr_set_volume(struct snd_compr_stream *cstream,
 				uint32_t volume_l, uint32_t volume_r)
 {
@@ -136,6 +167,10 @@
 
 	pr_debug("%s: volume_l %d volume_r %d\n",
 		__func__, volume_l, volume_r);
+	if (!cstream || !cstream->runtime) {
+		pr_err("%s: session not active\n", __func__);
+		return -EPERM;
+	}
 	prtd = cstream->runtime->private_data;
 	if (prtd && prtd->audio_client) {
 		if (volume_l != volume_r) {
@@ -155,6 +190,23 @@
 	return rc;
 }
 
+static int msm_compr_send_ddp_cfg(struct audio_client *ac,
+				  struct snd_dec_ddp *ddp)
+{
+	int i, rc;
+	pr_debug("%s\n", __func__);
+	for (i = 0; i < ddp->params_length; i++) {
+		rc = q6asm_ds1_set_endp_params(ac, ddp->params_id[i],
+						ddp->params_value[i]);
+		if (rc) {
+			pr_err("sending params_id: %d failed\n",
+				ddp->params_id[i]);
+			return rc;
+		}
+	}
+	return 0;
+}
+
 static int msm_compr_send_buffer(struct msm_compr_audio *prtd)
 {
 	int buffer_length;
@@ -174,8 +226,9 @@
 
 	pr_debug("%s: bytes_received = %d copied_total = %d\n",
 		__func__, prtd->bytes_received, prtd->copied_total);
-	if (prtd->first_buffer)
-		q6asm_send_meta_data(prtd->audio_client,
+	if (prtd->first_buffer &&  prtd->gapless_state.use_dsp_gapless_mode)
+		q6asm_stream_send_meta_data(prtd->audio_client,
+				prtd->audio_client->stream_id,
 				prtd->gapless_state.initial_samples_drop,
 				prtd->gapless_state.trailing_samples_drop);
 
@@ -208,6 +261,7 @@
 	if (q6asm_async_write(prtd->audio_client, &param) < 0) {
 		pr_err("%s:q6asm_async_write failed\n", __func__);
 	} else {
+		prtd->bytes_sent += buffer_length;
 		if (prtd->first_buffer)
 			prtd->first_buffer = 0;
 	}
@@ -224,6 +278,7 @@
 	uint32_t chan_mode = 0;
 	uint32_t sample_rate = 0;
 	int bytes_available, stream_id;
+	uint32_t stream_index;
 
 	pr_debug("%s opcode =%08x\n", __func__, opcode);
 	switch (opcode) {
@@ -281,8 +336,10 @@
 		spin_unlock(&prtd->lock);
 		break;
 	case ASM_DATA_EVENT_RENDERED_EOS:
-		pr_debug("ASM_DATA_CMDRSP_EOS\n");
 		spin_lock(&prtd->lock);
+		pr_debug("%s: ASM_DATA_CMDRSP_EOS token 0x%x,stream id %d\n",
+			  __func__, token, STREAM_ID_FROM_TOKEN(token));
+		stream_id = STREAM_ID_FROM_TOKEN(token);
 		if (atomic_read(&prtd->eos) &&
 		    !prtd->gapless_state.set_next_stream_id) {
 			pr_debug("ASM_DATA_CMDRSP_EOS wake up\n");
@@ -290,15 +347,26 @@
 			wake_up(&prtd->eos_wait);
 		}
 		atomic_set(&prtd->eos, 0);
-		stream_id = ac->stream_id^1; /*prev stream */
+		stream_index = STREAM_ARRAY_INDEX(stream_id);
+		if (stream_index >= MAX_NUMBER_OF_STREAMS ||
+		    stream_index < 0) {
+			pr_err("%s: Invalid stream index %d", __func__,
+				stream_index);
+			spin_unlock(&prtd->lock);
+			break;
+		}
+
 		if (prtd->gapless_state.set_next_stream_id &&
-		    prtd->gapless_state.stream_opened[stream_id]) {
-			q6asm_stream_cmd_nowait(prtd->audio_client,
-						CMD_CLOSE, stream_id);
+			prtd->gapless_state.stream_opened[stream_index]) {
+			pr_debug("%s: CMD_CLOSE stream_id %d\n",
+				  __func__, stream_id);
+			q6asm_stream_cmd_nowait(ac, CMD_CLOSE, stream_id);
 			atomic_set(&prtd->close, 1);
-			prtd->gapless_state.stream_opened[stream_id] = 0;
+			prtd->gapless_state.stream_opened[stream_index] = 0;
 			prtd->gapless_state.set_next_stream_id = false;
 		}
+		if (prtd->gapless_state.gapless_transition)
+			prtd->gapless_state.gapless_transition = 0;
 		spin_unlock(&prtd->lock);
 		break;
 	case ASM_DATA_EVENT_SR_CM_CHANGE_NOTIFY:
@@ -320,7 +388,7 @@
 
 			spin_lock(&prtd->lock);
 			/* FIXME: A state is a much better way of dealing with this */
-			if (!prtd->copied_total) {
+			if (prtd->bytes_sent == 0) {
 				bytes_available = prtd->bytes_received - prtd->copied_total;
 				if (bytes_available < cstream->runtime->fragment_size) {
 					pr_debug("CMD_RUN_V2 Insufficient data to send. break out\n");
@@ -331,18 +399,39 @@
 			spin_unlock(&prtd->lock);
 			break;
 		case ASM_STREAM_CMD_FLUSH:
-			pr_debug("ASM_STREAM_CMD_FLUSH\n");
+			pr_debug("%s: ASM_STREAM_CMD_FLUSH:", __func__);
+			pr_debug("token 0x%x, stream id %d\n", token,
+				  STREAM_ID_FROM_TOKEN(token));
 			prtd->cmd_ack = 1;
 			wake_up(&prtd->flush_wait);
 			break;
 		case ASM_DATA_CMD_REMOVE_INITIAL_SILENCE:
-			pr_debug("ASM_DATA_CMD_REMOVE_INITIAL_SILENCE\n");
+			pr_debug("%s: ASM_DATA_CMD_REMOVE_INITIAL_SILENCE:",
+				   __func__);
+			pr_debug("token 0x%x, stream id = %d\n", token,
+				  STREAM_ID_FROM_TOKEN(token));
 			break;
 		case ASM_DATA_CMD_REMOVE_TRAILING_SILENCE:
-			pr_debug("ASM_DATA_CMD_REMOVE_TRAILING_SILENCE\n");
+			pr_debug("%s: ASM_DATA_CMD_REMOVE_TRAILING_SILENCE:",
+				  __func__);
+			pr_debug("token = 0x%x,	stream id = %d\n", token,
+				  STREAM_ID_FROM_TOKEN(token));
 			break;
 		case ASM_STREAM_CMD_CLOSE:
-			pr_debug("ASM_DATA_CMD_CLOSE\n");
+			pr_debug("%s: ASM_DATA_CMD_CLOSE:", __func__);
+			pr_debug("token 0x%x, stream id %d\n", token,
+				  STREAM_ID_FROM_TOKEN(token));
+			/*
+			 * wakeup wait for stream avail on stream 3
+			 * after stream 1 ends.
+			 */
+			if (prtd->next_stream) {
+				pr_debug("%s:CLOSE:wakeup wait for stream\n",
+					  __func__);
+				prtd->stream_available = 1;
+				wake_up(&prtd->wait_for_stream_avail);
+				prtd->next_stream = 0;
+			}
 			if (atomic_read(&prtd->close) &&
 			    atomic_read(&prtd->wait_on_close)) {
 				prtd->cmd_ack = 1;
@@ -356,10 +445,12 @@
 		break;
 	}
 	case ASM_SESSION_CMDRSP_GET_SESSIONTIME_V3:
-		pr_debug("ASM_SESSION_CMDRSP_GET_SESSIONTIME_V3\n");
+		pr_debug("%s: ASM_SESSION_CMDRSP_GET_SESSIONTIME_V3\n",
+			  __func__);
 		break;
 	case RESET_EVENTS:
-		pr_err("Received reset events CB, move to error state");
+		pr_err("%s: Received reset events CB, move to error state",
+			__func__);
 		spin_lock(&prtd->lock);
 		snd_compr_fragment_elapsed(cstream);
 		prtd->copied_total = prtd->bytes_received;
@@ -367,7 +458,8 @@
 		spin_unlock(&prtd->lock);
 		break;
 	default:
-		pr_debug("Not Supported Event opcode[0x%x]\n", opcode);
+		pr_debug("%s: Not Supported Event opcode[0x%x]\n",
+			  __func__, opcode);
 		break;
 	}
 }
@@ -384,11 +476,12 @@
 			COMPR_PLAYBACK_MIN_NUM_FRAGMENTS;
 	prtd->compr_cap.max_fragments =
 			COMPR_PLAYBACK_MAX_NUM_FRAGMENTS;
-	prtd->compr_cap.num_codecs = 4;
+	prtd->compr_cap.num_codecs = 5;
 	prtd->compr_cap.codecs[0] = SND_AUDIOCODEC_MP3;
 	prtd->compr_cap.codecs[1] = SND_AUDIOCODEC_AAC;
 	prtd->compr_cap.codecs[2] = SND_AUDIOCODEC_AC3;
 	prtd->compr_cap.codecs[3] = SND_AUDIOCODEC_EAC3;
+	prtd->compr_cap.codecs[4] = SND_AUDIOCODEC_PCM;
 }
 
 static int msm_compr_send_media_format_block(struct snd_compr_stream *cstream,
@@ -398,15 +491,33 @@
 	struct msm_compr_audio *prtd = runtime->private_data;
 	struct asm_aac_cfg aac_cfg;
 	int ret = 0;
+	uint16_t bit_width = 16;
 
 	switch (prtd->codec) {
+	case FORMAT_LINEAR_PCM:
+		pr_debug("SND_AUDIOCODEC_PCM\n");
+		if (prtd->codec_param.codec.format == SNDRV_PCM_FORMAT_S24_LE)
+			bit_width = 24;
+		ret = q6asm_media_format_block_pcm_format_support(
+							prtd->audio_client,
+							prtd->sample_rate,
+							prtd->num_channels,
+							bit_width);
+		if (ret < 0)
+			pr_err("%s: CMD Format block failed\n", __func__);
+
+		break;
 	case FORMAT_MP3:
 		/* no media format block needed */
 		break;
 	case FORMAT_MPEG4_AAC:
 		memset(&aac_cfg, 0x0, sizeof(struct asm_aac_cfg));
 		aac_cfg.aot = AAC_ENC_MODE_EAAC_P;
-		aac_cfg.format = 0x03;
+		if (prtd->codec_param.codec.format ==
+					SND_AUDIOSTREAMFORMAT_MP4ADTS)
+			aac_cfg.format = 0x0;
+		else
+			aac_cfg.format = 0x03;
 		aac_cfg.ch_cfg = prtd->num_channels;
 		aac_cfg.sample_rate = prtd->sample_rate;
 		ret = q6asm_stream_media_format_block_aac(prtd->audio_client,
@@ -433,28 +544,30 @@
 	uint16_t bits_per_sample = 16;
 	int dir = IN, ret = 0;
 	struct audio_client *ac = prtd->audio_client;
-	struct asm_softpause_params softpause = {
-		.enable = SOFT_PAUSE_ENABLE,
-		.period = SOFT_PAUSE_PERIOD,
-		.step = SOFT_PAUSE_STEP,
-		.rampingcurve = SOFT_PAUSE_CURVE_LINEAR,
-	};
+	uint32_t stream_index;
 	struct asm_softvolume_params softvol = {
 		.period = SOFT_VOLUME_PERIOD,
 		.step = SOFT_VOLUME_STEP,
 		.rampingcurve = SOFT_VOLUME_CURVE_LINEAR,
 	};
 
-	pr_debug("%s\n", __func__);
+	pr_debug("%s: stream_id %d\n", __func__, ac->stream_id);
 	ret = q6asm_stream_open_write_v2(ac,
 				prtd->codec, bits_per_sample,
-				ac->stream_id, true/*gapless*/);
+				ac->stream_id,
+				prtd->gapless_state.use_dsp_gapless_mode);
 	if (ret < 0) {
 		pr_err("%s: Session out open failed\n", __func__);
 		 return -ENOMEM;
 	}
 
-	prtd->gapless_state.stream_opened[ac->stream_id] = 1;
+	stream_index = STREAM_ARRAY_INDEX(ac->stream_id);
+	if (stream_index >= MAX_NUMBER_OF_STREAMS || stream_index < 0) {
+		pr_err("%s: Invalid stream index:%d", __func__, stream_index);
+		return -EINVAL;
+	}
+
+	prtd->gapless_state.stream_opened[stream_index] = 1;
 	pr_debug("%s be_id %d\n", __func__, soc_prtd->dai_link->be_id);
 	msm_pcm_routing_reg_phy_stream(soc_prtd->dai_link->be_id,
 				ac->perf_mode,
@@ -465,17 +578,12 @@
 	if (ret < 0)
 		pr_err("%s : Set Volume failed : %d", __func__, ret);
 
-	ret = q6asm_set_softpause(ac, &softpause);
-	if (ret < 0)
-		pr_err("%s: Send SoftPause Param failed ret=%d\n",
-			__func__, ret);
-
 	ret = q6asm_set_softvolume(ac, &softvol);
 	if (ret < 0)
 		pr_err("%s: Send SoftVolume Param failed ret=%d\n",
 			__func__, ret);
 
-	ret = q6asm_set_io_mode(ac, (COMPRESSED_IO | ASYNC_IO_MODE));
+	ret = q6asm_set_io_mode(ac, (COMPRESSED_STREAM_IO | ASYNC_IO_MODE));
 	if (ret < 0) {
 		pr_err("%s: Set IO mode failed\n", __func__);
 		return -EINVAL;
@@ -498,6 +606,7 @@
 	prtd->copied_total = 0;
 	prtd->app_pointer  = 0;
 	prtd->bytes_received = 0;
+	prtd->bytes_sent = 0;
 	prtd->buffer       = ac->port[dir].buf[0].data;
 	prtd->buffer_paddr = ac->port[dir].buf[0].phys;
 	prtd->buffer_size  = runtime->fragments * runtime->fragment_size;
@@ -530,6 +639,17 @@
 		 kzalloc(sizeof(struct msm_compr_audio_effects), GFP_KERNEL);
 	if (!pdata->audio_effects[rtd->dai_link->be_id]) {
 		pr_err("%s: Could not allocate memory for effects\n", __func__);
+		pdata->cstream[rtd->dai_link->be_id] = NULL;
+		kfree(prtd);
+		return -ENOMEM;
+	}
+	pdata->dec_params[rtd->dai_link->be_id] =
+		 kzalloc(sizeof(struct msm_compr_dec_params), GFP_KERNEL);
+	if (!pdata->dec_params[rtd->dai_link->be_id]) {
+		pr_err("%s: Could not allocate memory for dec params\n",
+			__func__);
+		kfree(pdata->audio_effects[rtd->dai_link->be_id]);
+		pdata->cstream[rtd->dai_link->be_id] = NULL;
 		kfree(prtd);
 		return -ENOMEM;
 	}
@@ -538,6 +658,8 @@
 	if (!prtd->audio_client) {
 		pr_err("%s: Could not allocate memory for client\n", __func__);
 		kfree(pdata->audio_effects[rtd->dai_link->be_id]);
+		kfree(pdata->dec_params[rtd->dai_link->be_id]);
+		pdata->cstream[rtd->dai_link->be_id] = NULL;
 		kfree(prtd);
 		return -ENOMEM;
 	}
@@ -547,6 +669,7 @@
 	prtd->session_id = prtd->audio_client->session;
 	prtd->codec = FORMAT_MP3;
 	prtd->bytes_received = 0;
+	prtd->bytes_sent = 0;
 	prtd->copied_total = 0;
 	prtd->byte_offset = 0;
 	prtd->sample_rate = 44100;
@@ -555,7 +678,15 @@
 	prtd->last_buffer = 0;
 	prtd->first_buffer = 1;
 	prtd->partial_drain_delay = 0;
+	prtd->next_stream = 0;
 	memset(&prtd->gapless_state, 0, sizeof(struct msm_compr_gapless_state));
+	/*
+	 * Update the use_dsp_gapless_mode from gapless struture with the value
+	 * part of platform data.
+	 */
+	prtd->gapless_state.use_dsp_gapless_mode = pdata->use_dsp_gapless_mode;
+
+	pr_debug("%s: gapless mode %d", __func__, pdata->use_dsp_gapless_mode);
 
 	spin_lock_init(&prtd->lock);
 
@@ -571,6 +702,7 @@
 	init_waitqueue_head(&prtd->drain_wait);
 	init_waitqueue_head(&prtd->flush_wait);
 	init_waitqueue_head(&prtd->close_wait);
+	init_waitqueue_head(&prtd->wait_for_stream_avail);
 
 	runtime->private_data = prtd;
 	populate_codec_list(prtd);
@@ -599,21 +731,9 @@
 	struct audio_client *ac = prtd->audio_client;
 	int dir = IN, ret = 0, stream_id;
 	unsigned long flags;
+	uint32_t stream_index;
 
 	pr_debug("%s\n", __func__);
-	pdata->cstream[soc_prtd->dai_link->be_id] = NULL;
-	if (cstream->direction == SND_COMPRESS_PLAYBACK) {
-		if (atomic_read(&pdata->audio_ocmem_req) > 1)
-			atomic_dec(&pdata->audio_ocmem_req);
-		else if (atomic_cmpxchg(&pdata->audio_ocmem_req, 1, 0))
-			audio_ocmem_process_req(AUDIO, false);
-
-		msm_pcm_routing_dereg_phy_stream(soc_prtd->dai_link->be_id,
-						SNDRV_PCM_STREAM_PLAYBACK);
-	}
-
-	pr_debug("%s: ocmem_req: %d\n", __func__,
-		atomic_read(&pdata->audio_ocmem_req));
 
 	if (atomic_read(&prtd->eos)) {
 		ret = wait_event_timeout(prtd->eos_wait,
@@ -632,25 +752,46 @@
 
 	spin_lock_irqsave(&prtd->lock, flags);
 	stream_id = ac->stream_id;
-	if (prtd->gapless_state.stream_opened[stream_id^1]) {
+	stream_index = STREAM_ARRAY_INDEX(NEXT_STREAM_ID(stream_id));
+
+	if ((stream_index < MAX_NUMBER_OF_STREAMS && stream_index >= 0) &&
+	    (prtd->gapless_state.stream_opened[stream_index])) {
+		prtd->gapless_state.stream_opened[stream_index] = 0;
 		spin_unlock_irqrestore(&prtd->lock, flags);
-		q6asm_stream_cmd(ac, CMD_CLOSE, stream_id^1);
+		pr_debug(" close stream %d", NEXT_STREAM_ID(stream_id));
+		q6asm_stream_cmd(ac, CMD_CLOSE, NEXT_STREAM_ID(stream_id));
 		spin_lock_irqsave(&prtd->lock, flags);
 	}
-	if (prtd->gapless_state.stream_opened[stream_id]) {
+
+	stream_index = STREAM_ARRAY_INDEX(stream_id);
+	if ((stream_index < MAX_NUMBER_OF_STREAMS && stream_index >= 0) &&
+	    (prtd->gapless_state.stream_opened[stream_index])) {
+		prtd->gapless_state.stream_opened[stream_index] = 0;
 		spin_unlock_irqrestore(&prtd->lock, flags);
+		pr_debug("close stream %d", stream_id);
 		q6asm_stream_cmd(ac, CMD_CLOSE, stream_id);
 		spin_lock_irqsave(&prtd->lock, flags);
 	}
 	spin_unlock_irqrestore(&prtd->lock, flags);
 
-	/* client buf alloc was with stream id 0, so free with the same */
-	ac->stream_id = 0;
+	pdata->cstream[soc_prtd->dai_link->be_id] = NULL;
+	if (cstream->direction == SND_COMPRESS_PLAYBACK) {
+		if (atomic_read(&pdata->audio_ocmem_req) > 1)
+			atomic_dec(&pdata->audio_ocmem_req);
+		else if (atomic_cmpxchg(&pdata->audio_ocmem_req, 1, 0))
+			audio_ocmem_process_req(AUDIO, false);
+		msm_pcm_routing_dereg_phy_stream(soc_prtd->dai_link->be_id,
+						SNDRV_PCM_STREAM_PLAYBACK);
+	}
+
+	pr_debug("%s: ocmem_req: %d\n", __func__,
+		atomic_read(&pdata->audio_ocmem_req));
 	q6asm_audio_client_buf_free_contiguous(dir, ac);
 
 	q6asm_audio_client_free(ac);
 
 	kfree(pdata->audio_effects[soc_prtd->dai_link->be_id]);
+	kfree(pdata->dec_params[soc_prtd->dai_link->be_id]);
 	kfree(prtd);
 
 	return 0;
@@ -699,6 +840,12 @@
 	pr_debug("%s: sample_rate %d\n", __func__, prtd->sample_rate);
 
 	switch (params->codec.id) {
+	case SND_AUDIOCODEC_PCM: {
+		pr_debug("SND_AUDIOCODEC_PCM\n");
+		prtd->codec = FORMAT_LINEAR_PCM;
+		break;
+	}
+
 	case SND_AUDIOCODEC_MP3: {
 		pr_debug("SND_AUDIOCODEC_MP3\n");
 		prtd->codec = FORMAT_MP3;
@@ -715,11 +862,13 @@
 
 	case SND_AUDIOCODEC_AC3: {
 		prtd->codec = FORMAT_AC3;
+		frame_sz = AC3_OUTPUT_FRAME_SZ;
 		break;
 	}
 
 	case SND_AUDIOCODEC_EAC3: {
 		prtd->codec = FORMAT_EAC3;
+		frame_sz = EAC3_OUTPUT_FRAME_SZ;
 		break;
 	}
 
@@ -762,6 +911,45 @@
 	return rc;
 }
 
+static int msm_compr_wait_for_stream_avail(struct msm_compr_audio *prtd,
+				    unsigned long *flags)
+{
+	int rc = 0;
+	pr_debug("next session is already in opened state\n");
+	prtd->next_stream = 1;
+	prtd->cmd_interrupt = 0;
+	spin_unlock_irqrestore(&prtd->lock, *flags);
+	/*
+	 * Wait for stream to be available, or the wait to be interrupted by
+	 * commands like flush or till a timeout of one second.
+	 */
+	rc = wait_event_timeout(prtd->wait_for_stream_avail,
+		prtd->stream_available || prtd->cmd_interrupt, 1 * HZ);
+	pr_err("%s:prtd->stream_available %d, prtd->cmd_interrupt %d rc %d\n",
+		   __func__, prtd->stream_available, prtd->cmd_interrupt, rc);
+
+	spin_lock_irqsave(&prtd->lock, *flags);
+	if (rc == 0) {
+		pr_err("%s: wait_for_stream_avail timed out\n",
+						__func__);
+		rc =  -ETIMEDOUT;
+	} else if (prtd->cmd_interrupt == 1) {
+		/*
+		 * This scenario might not happen as we do not allow
+		 * flush in transition state.
+		 */
+		pr_debug("%s: wait_for_stream_avail interrupted\n", __func__);
+		prtd->cmd_interrupt = 0;
+		prtd->stream_available = 0;
+		rc = -EINTR;
+	} else {
+		prtd->stream_available = 0;
+		rc = 0;
+	}
+	pr_debug("%s : rc = %d",  __func__, rc);
+	return rc;
+}
+
 static int msm_compr_trigger(struct snd_compr_stream *cstream, int cmd)
 {
 	struct snd_compr_runtime *runtime = cstream->runtime;
@@ -775,6 +963,7 @@
 	int bytes_to_write;
 	unsigned long flags;
 	int stream_id;
+	uint32_t stream_index;
 
 	if (cstream->direction != SND_COMPRESS_PLAYBACK) {
 		pr_err("%s: Unsupported stream type\n", __func__);
@@ -801,22 +990,18 @@
 				__func__, rc);
 		break;
 	case SNDRV_PCM_TRIGGER_STOP:
-		pr_debug("%s: SNDRV_PCM_TRIGGER_STOP\n", __func__);
 		spin_lock_irqsave(&prtd->lock, flags);
-
+		pr_debug("%s: SNDRV_PCM_TRIGGER_STOP transition %d\n", __func__,
+					prtd->gapless_state.gapless_transition);
 		stream_id = ac->stream_id;
-		if (prtd->gapless_state.set_next_stream_id &&
-		    prtd->first_buffer) {
-			/*
-			 * Stream just switched for gapless, no buffers sent.
-			 * So seek needs to be applied to previous stream
-			 */
-			pr_debug("Seek previous stream as next stream hasn't started\n");
-			stream_id = stream_id^1;
-			ac->stream_id = stream_id;
-			prtd->first_buffer = 0;
-		}
 		atomic_set(&prtd->start, 0);
+		if (prtd->next_stream) {
+			pr_debug("%s: interrupt next track wait queues\n",
+								__func__);
+			prtd->cmd_interrupt = 1;
+			wake_up(&prtd->wait_for_stream_avail);
+			prtd->next_stream = 0;
+		}
 		if (atomic_read(&prtd->eos)) {
 			pr_debug("%s: interrupt eos wait queues", __func__);
 			prtd->cmd_interrupt = 1;
@@ -831,44 +1016,63 @@
 			atomic_set(&prtd->drain, 0);
 		}
 		prtd->last_buffer = 0;
-		pr_debug("issue CMD_FLUSH\n");
 		prtd->cmd_ack = 0;
-		spin_unlock_irqrestore(&prtd->lock, flags);
-		rc = q6asm_stream_cmd(prtd->audio_client, CMD_FLUSH, stream_id);
-		if (rc < 0) {
-			pr_err("%s: flush cmd failed rc=%d\n",
-			       __func__, rc);
-			return rc;
-		}
-		rc = wait_event_timeout(prtd->flush_wait,
+		if (!prtd->gapless_state.gapless_transition) {
+			pr_debug("issue CMD_FLUSH stream_id %d\n", stream_id);
+			spin_unlock_irqrestore(&prtd->lock, flags);
+			rc = q6asm_stream_cmd(
+				prtd->audio_client, CMD_FLUSH, stream_id);
+			if (rc < 0) {
+				pr_err("%s: flush cmd failed rc=%d\n",
+							__func__, rc);
+				return rc;
+			}
+			rc = wait_event_timeout(prtd->flush_wait,
 					prtd->cmd_ack, 1 * HZ);
-		if (!rc) {
-			rc = -ETIMEDOUT;
-			pr_err("Flush cmd timeout\n");
-		} else
-			rc = 0; /* prtd->cmd_status == OK? 0 : -EPERM */
-
-		spin_lock_irqsave(&prtd->lock, flags);
+			if (!rc) {
+				rc = -ETIMEDOUT;
+				pr_err("Flush cmd timeout\n");
+			} else {
+				rc = 0; /* prtd->cmd_status == OK? 0 : -EPERM*/
+			}
+			spin_lock_irqsave(&prtd->lock, flags);
+		} else {
+			prtd->first_buffer = 0;
+		}
 		/* FIXME. only reset if flush was successful */
 		prtd->byte_offset  = 0;
 		prtd->copied_total = 0;
 		prtd->app_pointer  = 0;
 		prtd->bytes_received = 0;
+		prtd->bytes_sent = 0;
+
 		atomic_set(&prtd->xrun, 0);
 		spin_unlock_irqrestore(&prtd->lock, flags);
 		break;
 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-		pr_debug("SNDRV_PCM_TRIGGER_PAUSE_PUSH\n");
-		q6asm_cmd_nowait(prtd->audio_client, CMD_PAUSE);
-		atomic_set(&prtd->start, 0);
+		pr_debug("SNDRV_PCM_TRIGGER_PAUSE_PUSH transition %d\n",
+				prtd->gapless_state.gapless_transition);
+		if (!prtd->gapless_state.gapless_transition) {
+			pr_debug("issue CMD_PAUSE stream_id %d\n",
+				  ac->stream_id);
+			q6asm_stream_cmd_nowait(ac, CMD_PAUSE, ac->stream_id);
+			atomic_set(&prtd->start, 0);
+		}
 		break;
 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-		pr_debug("SNDRV_PCM_TRIGGER_PAUSE_RELEASE\n");
-		atomic_set(&prtd->start, 1);
-		q6asm_run_nowait(prtd->audio_client, 0, 0, 0);
+		pr_debug("SNDRV_PCM_TRIGGER_PAUSE_RELEASE transition %d\n",
+				   prtd->gapless_state.gapless_transition);
+		if (!prtd->gapless_state.gapless_transition) {
+			atomic_set(&prtd->start, 1);
+			q6asm_run_nowait(prtd->audio_client, 0, 0, 0);
+		}
 		break;
 	case SND_COMPR_TRIGGER_PARTIAL_DRAIN:
 		pr_debug("%s: SND_COMPR_TRIGGER_PARTIAL_DRAIN\n", __func__);
+		if (!prtd->gapless_state.use_dsp_gapless_mode) {
+			pr_debug("%s: set partial drain as drain\n", __func__);
+			cmd = SND_COMPR_TRIGGER_DRAIN;
+		}
 	case SND_COMPR_TRIGGER_DRAIN:
 		pr_debug("%s: SNDRV_COMPRESS_DRAIN\n", __func__);
 		/* Make sure all the data is sent to DSP before sending EOS */
@@ -915,6 +1119,7 @@
 		if ((cmd == SND_COMPR_TRIGGER_PARTIAL_DRAIN) &&
 		    (prtd->gapless_state.set_next_stream_id)) {
 			/* wait for the last buffer to be returned */
+
 			if (prtd->last_buffer) {
 				pr_debug("%s: last buffer drain\n", __func__);
 				rc = msm_compr_drain_buffer(prtd, &flags);
@@ -926,8 +1131,8 @@
 
 			/* send EOS */
 			prtd->cmd_ack = 0;
-			atomic_set(&prtd->eos, 1);
-			q6asm_cmd_nowait(prtd->audio_client, CMD_EOS);
+			pr_debug("issue CMD_EOS stream_id %d\n", ac->stream_id);
+			q6asm_stream_cmd_nowait(ac, CMD_EOS, ac->stream_id);
 			pr_info("PARTIAL DRAIN, do not wait for EOS ack\n");
 
 			/* send a zero length buffer */
@@ -964,12 +1169,14 @@
 			}
 
 			/* move to next stream and reset vars */
-			pr_debug("%s: Moving to next stream in gapless\n", __func__);
-			ac->stream_id ^= 1;
+			pr_debug("%s: Moving to next stream in gapless\n",
+								__func__);
+			ac->stream_id = NEXT_STREAM_ID(ac->stream_id);
 			prtd->byte_offset = 0;
 			prtd->app_pointer  = 0;
 			prtd->first_buffer = 1;
 			prtd->last_buffer = 0;
+			prtd->gapless_state.gapless_transition = 1;
 			/*
 			Don't reset these as these vars map to
 			total_bytes_transferred and total_bytes_available
@@ -991,11 +1198,11 @@
 		   stream can be used for gapless playback
 		*/
 		prtd->gapless_state.set_next_stream_id = false;
-		pr_debug("%s: CMD_EOS\n", __func__);
+		pr_debug("%s:CMD_EOS stream_id %d\n", __func__, ac->stream_id);
 
 		prtd->cmd_ack = 0;
 		atomic_set(&prtd->eos, 1);
-		q6asm_cmd_nowait(prtd->audio_client, CMD_EOS);
+		q6asm_stream_cmd_nowait(ac, CMD_EOS, ac->stream_id);
 
 		spin_unlock_irqrestore(&prtd->lock, flags);
 
@@ -1007,24 +1214,27 @@
 		if (rc < 0)
 			pr_err("%s: EOS wait failed\n", __func__);
 
-		pr_debug("%s: SNDRV_COMPRESS_DRAIN  out of wait for EOS\n", __func__);
+		pr_debug("%s: SNDRV_COMPRESS_DRAIN  out of wait for EOS\n",
+			  __func__);
 
 		if (prtd->cmd_interrupt)
 			rc = -EINTR;
 
 		/*FIXME : what if a flush comes while PC is here */
-		if (rc == 0 && (cmd == SND_COMPR_TRIGGER_PARTIAL_DRAIN)) {
+		if (rc == 0) {
 			/*
 			 * Failed to open second stream in DSP for gapless
 			 * so prepare the current stream in session for gapless playback
 			 */
 			spin_lock_irqsave(&prtd->lock, flags);
-			pr_debug("%s: issue CMD_PAUSE ", __func__);
-			q6asm_cmd_nowait(prtd->audio_client, CMD_PAUSE);
+			pr_debug("%s:issue CMD_PAUSE stream_id %d",
+					  __func__, ac->stream_id);
+			q6asm_stream_cmd_nowait(ac, CMD_PAUSE, ac->stream_id);
 			prtd->cmd_ack = 0;
 			spin_unlock_irqrestore(&prtd->lock, flags);
-			pr_debug("%s: issue CMD_FLUSH", __func__);
-			q6asm_cmd(prtd->audio_client, CMD_FLUSH);
+			pr_debug("%s:issue CMD_FLUSH ac->stream_id %d",
+					      __func__, ac->stream_id);
+			q6asm_stream_cmd(ac, CMD_FLUSH, ac->stream_id);
 			wait_event_timeout(prtd->flush_wait,
 					   prtd->cmd_ack, 1 * HZ / 4);
 
@@ -1036,8 +1246,11 @@
 			in the next avail() ioctl
 			prtd->copied_total = 0;
 			prtd->bytes_received = 0;
+			do not reset prtd->bytes_sent as well as the same
+			session is used for gapless playback
 			*/
 			prtd->byte_offset = 0;
+
 			prtd->app_pointer  = 0;
 			prtd->first_buffer = 1;
 			prtd->last_buffer = 0;
@@ -1049,20 +1262,68 @@
 		prtd->cmd_interrupt = 0;
 		break;
 	case SND_COMPR_TRIGGER_NEXT_TRACK:
+		if (!prtd->gapless_state.use_dsp_gapless_mode) {
+			pr_debug("%s: ignore trigger next track\n", __func__);
+			rc = 0;
+			break;
+		}
 		pr_debug("%s: SND_COMPR_TRIGGER_NEXT_TRACK\n", __func__);
 		spin_lock_irqsave(&prtd->lock, flags);
 		rc = 0;
-		stream_id = ac->stream_id^1; /*next stream in gapless*/
-		if (prtd->gapless_state.stream_opened[stream_id]) {
-			pr_debug("next session is already in opened state\n");
+		/* next stream in gapless */
+		stream_id = NEXT_STREAM_ID(ac->stream_id);
+		/*
+		 * Wait if stream 1 has not completed before honoring next
+		 * track for stream 3. Scenario happens if second clip is
+		 * small and fills in one buffer so next track will be
+		 * called immediately.
+		 */
+		stream_index = STREAM_ARRAY_INDEX(stream_id);
+		if (stream_index >= MAX_NUMBER_OF_STREAMS ||
+		    stream_index < 0) {
+			pr_err("%s: Invalid stream index: %d", __func__,
+				stream_index);
 			spin_unlock_irqrestore(&prtd->lock, flags);
+			rc = -EINVAL;
 			break;
 		}
+
+		if (prtd->gapless_state.stream_opened[stream_index]) {
+			if (prtd->gapless_state.gapless_transition) {
+				rc = msm_compr_wait_for_stream_avail(prtd,
+								    &flags);
+			} else {
+				/*
+				 * If session is already opened break out if
+				 * the state is not gapless transition. This
+				 * is when seek happens after the last buffer
+				 * is sent to the driver. Next track would be
+				 * called again after last buffer is sent.
+				 */
+				pr_debug("next session is in opened state\n");
+				spin_unlock_irqrestore(&prtd->lock, flags);
+				break;
+			}
+		}
 		spin_unlock_irqrestore(&prtd->lock, flags);
+		if (rc < 0) {
+			/*
+			 * if return type EINTR  then reset to zero. Tiny
+			 * compress treats EINTR as error and prevents PARTIAL
+			 * DRAIN. EINTR is not an error. wait for stream avail
+			 * is interrupted by some other command like FLUSH.
+			 */
+			if (rc == -EINTR) {
+				pr_debug("%s: EINTR reset rc to 0\n", __func__);
+				rc = 0;
+			}
+			break;
+		}
+		pr_debug("%s: open_write stream_id %d", __func__, stream_id);
 		rc = q6asm_stream_open_write_v2(prtd->audio_client,
-						prtd->codec, 16,
-						stream_id,
-						true /*gapless*/);
+				prtd->codec, 16,
+				stream_id,
+				prtd->gapless_state.use_dsp_gapless_mode);
 		if (rc < 0) {
 			pr_err("%s: Session out open failed for gapless\n",
 				 __func__);
@@ -1075,7 +1336,7 @@
 			break;
 		}
 		spin_lock_irqsave(&prtd->lock, flags);
-		prtd->gapless_state.stream_opened[stream_id] = 1;
+		prtd->gapless_state.stream_opened[stream_index] = 1;
 		prtd->gapless_state.set_next_stream_id = true;
 		spin_unlock_irqrestore(&prtd->lock, flags);
 		break;
@@ -1226,7 +1487,6 @@
 	 * since the available bytes fits fragment_size, copy the data right away
 	 */
 	spin_lock_irqsave(&prtd->lock, flags);
-
 	prtd->bytes_received += count;
 	if (atomic_read(&prtd->start)) {
 		if (atomic_read(&prtd->xrun)) {
@@ -1315,7 +1575,6 @@
 	prtd = cstream->runtime->private_data;
 	if (!prtd && !prtd->audio_client)
 		return -EINVAL;
-
 	ac = prtd->audio_client;
 	if (metadata->key == SNDRV_COMPRESS_ENCODER_PADDING) {
 		pr_debug("%s, got encoder padding %u", __func__, metadata->value[0]);
@@ -1449,6 +1708,74 @@
 	return 0;
 }
 
+static int msm_compr_dec_params_put(struct snd_kcontrol *kcontrol,
+				    struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_platform *platform = snd_kcontrol_chip(kcontrol);
+	unsigned long fe_id = kcontrol->private_value;
+	struct msm_compr_pdata *pdata = (struct msm_compr_pdata *)
+			snd_soc_platform_get_drvdata(platform);
+	struct msm_compr_dec_params *dec_params = NULL;
+	struct snd_compr_stream *cstream = NULL;
+	struct msm_compr_audio *prtd = NULL;
+	long *values = &(ucontrol->value.integer.value[0]);
+
+	pr_debug("%s\n", __func__);
+	if (fe_id >= MSM_FRONTEND_DAI_MAX) {
+		pr_err("%s Received out of bounds fe_id %lu\n",
+			__func__, fe_id);
+		return -EINVAL;
+	}
+
+	cstream = pdata->cstream[fe_id];
+	dec_params = pdata->dec_params[fe_id];
+
+	if (!cstream || !dec_params) {
+		pr_err("%s: stream or dec_params inactive\n", __func__);
+		return -EINVAL;
+	}
+	prtd = cstream->runtime->private_data;
+	if (!prtd) {
+		pr_err("%s: cannot set dec_params\n", __func__);
+		return -EINVAL;
+	}
+	switch (prtd->codec) {
+	case FORMAT_MP3:
+	case FORMAT_MPEG4_AAC:
+		pr_debug("%s: no runtime parameters for codec: %d\n", __func__,
+			 prtd->codec);
+		break;
+	case FORMAT_AC3:
+	case FORMAT_EAC3: {
+		struct snd_dec_ddp *ddp = &dec_params->ddp_params;
+		int cnt;
+		ddp->params_length = (*values++);
+		if (ddp->params_length > DDP_DEC_MAX_NUM_PARAM) {
+			pr_err("%s: invalid num of params:: %d\n", __func__,
+				ddp->params_length);
+			return -EINVAL;
+		}
+		for (cnt = 0; cnt < ddp->params_length; cnt++) {
+			ddp->params_id[cnt] = *values++;
+			ddp->params_value[cnt] = *values++;
+		}
+		if (msm_compr_send_ddp_cfg(prtd->audio_client, ddp) < 0)
+			pr_err("%s: DDP CMD CFG failed\n", __func__);
+		break;
+	}
+	default:
+		break;
+	}
+	return 0;
+}
+
+static int msm_compr_dec_params_get(struct snd_kcontrol *kcontrol,
+				    struct snd_ctl_elem_value *ucontrol)
+{
+	/* dummy function */
+	return 0;
+}
+
 static int msm_compr_probe(struct snd_soc_platform *platform)
 {
 	struct msm_compr_pdata *pdata;
@@ -1468,9 +1795,17 @@
 		pdata->volume[i][0] = COMPRESSED_LR_VOL_MAX_STEPS;
 		pdata->volume[i][1] = COMPRESSED_LR_VOL_MAX_STEPS;
 		pdata->audio_effects[i] = NULL;
+		pdata->dec_params[i] = NULL;
 		pdata->cstream[i] = NULL;
 	}
 
+	/*
+	 * use_dsp_gapless_mode part of platform data(pdata) is updated from HAL
+	 * through a mixer control before compress driver is opened. The mixer
+	 * control is used to decide if dsp gapless mode needs to be enabled.
+	 * Gapless is disabled by default.
+	 */
+	pdata->use_dsp_gapless_mode = false;
 	return 0;
 }
 
@@ -1494,6 +1829,16 @@
 	return 0;
 }
 
+static int msm_compr_dec_params_info(struct snd_kcontrol *kcontrol,
+				     struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 128;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 0xFFFFFFFF;
+	return 0;
+}
+
 static int msm_compr_add_volume_control(struct snd_soc_pcm_runtime *rtd)
 {
 	const char *mixer_ctl_name = "Compress Playback";
@@ -1580,7 +1925,7 @@
 
 	fe_audio_effects_config_control[0].name = mixer_str;
 	fe_audio_effects_config_control[0].private_value = rtd->dai_link->be_id;
-	pr_debug("Registering new mixer ctl %s", mixer_str);
+	pr_debug("Registering new mixer ctl %s\n", mixer_str);
 	snd_soc_add_platform_controls(rtd->platform,
 				fe_audio_effects_config_control,
 				ARRAY_SIZE(fe_audio_effects_config_control));
@@ -1588,6 +1933,89 @@
 	return 0;
 }
 
+static int msm_compr_gapless_put(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_platform *platform = snd_kcontrol_chip(kcontrol);
+	struct msm_compr_pdata *pdata = (struct msm_compr_pdata *)
+		snd_soc_platform_get_drvdata(platform);
+	pdata->use_dsp_gapless_mode =  ucontrol->value.integer.value[0];
+	pr_debug("%s: value: %ld\n", __func__,
+		ucontrol->value.integer.value[0]);
+
+	return 0;
+}
+
+static int msm_compr_gapless_get(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_platform *platform = snd_kcontrol_chip(kcontrol);
+	struct msm_compr_pdata *pdata =
+		snd_soc_platform_get_drvdata(platform);
+	pr_debug("%s:gapless mode %d\n", __func__, pdata->use_dsp_gapless_mode);
+	ucontrol->value.integer.value[0] = pdata->use_dsp_gapless_mode;
+
+	return 0;
+}
+
+static const struct snd_kcontrol_new msm_compr_gapless_controls[] = {
+	SOC_SINGLE_EXT("Compress Gapless Playback",
+			0, 0, 1, 0,
+			msm_compr_gapless_get,
+			msm_compr_gapless_put),
+};
+
+static int msm_compr_add_dec_runtime_params_control(
+						struct snd_soc_pcm_runtime *rtd)
+{
+	const char *mixer_ctl_name	= "Audio Stream";
+	const char *deviceNo		= "NN";
+	const char *suffix		= "Dec Params";
+	char *mixer_str = NULL;
+	int ctl_len;
+	struct snd_kcontrol_new fe_dec_params_control[1] = {
+		{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "?",
+		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+		.info = msm_compr_dec_params_info,
+		.get = msm_compr_dec_params_get,
+		.put = msm_compr_dec_params_put,
+		.private_value = 0,
+		}
+	};
+
+	if (!rtd) {
+		pr_err("%s NULL rtd\n", __func__);
+		return 0;
+	}
+
+	pr_debug("%s: added new compr FE with name %s, id %d, cpu dai %s, device no %d\n",
+		 __func__, rtd->dai_link->name, rtd->dai_link->be_id,
+		 rtd->dai_link->cpu_dai_name, rtd->pcm->device);
+
+	ctl_len = strlen(mixer_ctl_name) + 1 + strlen(deviceNo) + 1 +
+		  strlen(suffix) + 1;
+	mixer_str = kzalloc(ctl_len, GFP_KERNEL);
+
+	if (!mixer_str) {
+		pr_err("failed to allocate mixer ctrl str of len %d", ctl_len);
+		return 0;
+	}
+
+	snprintf(mixer_str, ctl_len, "%s %d %s", mixer_ctl_name,
+		 rtd->pcm->device, suffix);
+
+	fe_dec_params_control[0].name = mixer_str;
+	fe_dec_params_control[0].private_value = rtd->dai_link->be_id;
+	pr_debug("Registering new mixer ctl %s", mixer_str);
+	snd_soc_add_platform_controls(rtd->platform,
+				      fe_dec_params_control,
+				      ARRAY_SIZE(fe_dec_params_control));
+	kfree(mixer_str);
+	return 0;
+}
+
 static int msm_compr_new(struct snd_soc_pcm_runtime *rtd)
 {
 	int rc;
@@ -1599,6 +2027,10 @@
 	if (rc)
 		pr_err("%s: Could not add Compr Audio Effects Control\n",
 			__func__);
+	rc = msm_compr_add_dec_runtime_params_control(rtd);
+	if (rc)
+		pr_err("%s: Could not add Compr Dec runtime params Control\n",
+			__func__);
 	return 0;
 }
 
@@ -1618,7 +2050,10 @@
 static struct snd_soc_platform_driver msm_soc_platform = {
 	.probe		= msm_compr_probe,
 	.compr_ops	= &msm_compr_ops,
-	.pcm_new = msm_compr_new,
+	.pcm_new	= msm_compr_new,
+	.controls       = msm_compr_gapless_controls,
+	.num_controls   = ARRAY_SIZE(msm_compr_gapless_controls),
+
 };
 
 static __devinit int msm_compr_dev_probe(struct platform_device *pdev)
diff --git a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
index 1434970..8b2c443 100644
--- a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
@@ -57,6 +57,7 @@
 
 struct msm_dai_q6_dai_data {
 	DECLARE_BITMAP(status_mask, STATUS_MAX);
+	DECLARE_BITMAP(hwfree_status, STATUS_MAX);
 	u32 rate;
 	u32 channels;
 	u32 bitwidth;
@@ -1510,6 +1511,11 @@
 			set_bit(STATUS_PORT_STARTED,
 				dai_data->status_mask);
 	}
+	if (!test_bit(STATUS_PORT_STARTED, dai_data->hwfree_status)) {
+		set_bit(STATUS_PORT_STARTED, dai_data->hwfree_status);
+		dev_dbg(dai->dev, "%s: set hwfree_status to started\n",
+				__func__);
+	}
 	return rc;
 }
 
@@ -1525,7 +1531,6 @@
 	struct msm_dai_q6_dai_data *dai_data = &mi2s_dai_config->mi2s_dai_data;
 	struct afe_param_id_i2s_cfg *i2s = &dai_data->port_config.i2s;
 
-
 	dai_data->channels = params_channels(params);
 	switch (dai_data->channels) {
 	case 8:
@@ -1602,10 +1607,14 @@
 	dai_data->port_config.i2s.i2s_cfg_minor_version =
 			AFE_API_VERSION_I2S_CONFIG;
 	dai_data->port_config.i2s.sample_rate = dai_data->rate;
-	if (test_bit(STATUS_PORT_STARTED,
-	    mi2s_dai_data->rx_dai.mi2s_dai_data.status_mask) ||
+	if ((test_bit(STATUS_PORT_STARTED,
+	    mi2s_dai_data->rx_dai.mi2s_dai_data.status_mask) &&
 	    test_bit(STATUS_PORT_STARTED,
-	    mi2s_dai_data->tx_dai.mi2s_dai_data.status_mask)) {
+	    mi2s_dai_data->rx_dai.mi2s_dai_data.hwfree_status)) ||
+	    (test_bit(STATUS_PORT_STARTED,
+	    mi2s_dai_data->tx_dai.mi2s_dai_data.status_mask) &&
+	    test_bit(STATUS_PORT_STARTED,
+	    mi2s_dai_data->tx_dai.mi2s_dai_data.hwfree_status))) {
 		if ((mi2s_dai_data->tx_dai.mi2s_dai_data.rate !=
 		    mi2s_dai_data->rx_dai.mi2s_dai_data.rate) ||
 		   (mi2s_dai_data->rx_dai.mi2s_dai_data.bitwidth !=
@@ -1669,6 +1678,23 @@
 	return 0;
 }
 
+static int msm_dai_q6_mi2s_hw_free(struct snd_pcm_substream *substream,
+		struct snd_soc_dai *dai)
+{
+	struct msm_dai_q6_mi2s_dai_data *mi2s_dai_data =
+			dev_get_drvdata(dai->dev);
+	struct msm_dai_q6_dai_data *dai_data =
+		(substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
+		 &mi2s_dai_data->rx_dai.mi2s_dai_data :
+		 &mi2s_dai_data->tx_dai.mi2s_dai_data);
+
+	if (test_bit(STATUS_PORT_STARTED, dai_data->hwfree_status)) {
+		clear_bit(STATUS_PORT_STARTED, dai_data->hwfree_status);
+		dev_dbg(dai->dev, "%s: clear hwfree_status\n", __func__);
+	}
+	return 0;
+}
+
 static void msm_dai_q6_mi2s_shutdown(struct snd_pcm_substream *substream,
 				     struct snd_soc_dai *dai)
 {
@@ -1696,12 +1722,15 @@
 			dev_err(dai->dev, "fail to close AFE port\n");
 		clear_bit(STATUS_PORT_STARTED, dai_data->status_mask);
 	}
+	if (test_bit(STATUS_PORT_STARTED, dai_data->hwfree_status))
+		clear_bit(STATUS_PORT_STARTED, dai_data->hwfree_status);
 }
 
 static struct snd_soc_dai_ops msm_dai_q6_mi2s_ops = {
 	.startup	= msm_dai_q6_mi2s_startup,
 	.prepare	= msm_dai_q6_mi2s_prepare,
 	.hw_params	= msm_dai_q6_mi2s_hw_params,
+	.hw_free	= msm_dai_q6_mi2s_hw_free,
 	.set_fmt	= msm_dai_q6_mi2s_set_fmt,
 	.shutdown	= msm_dai_q6_mi2s_shutdown,
 };
diff --git a/sound/soc/msm/qdsp6v2/msm-dolby-dap-config.c b/sound/soc/msm/qdsp6v2/msm-dolby-dap-config.c
index 63ac5d3..161904c 100644
--- a/sound/soc/msm/qdsp6v2/msm-dolby-dap-config.c
+++ b/sound/soc/msm/qdsp6v2/msm-dolby-dap-config.c
@@ -211,6 +211,14 @@
 		 DOLBY_ENDDEP_PARAM_VMB_OFFSET},
 		{-320, -320, 144}
 	},
+	{PROXY,	6, DOLBY_ENDP_EXT_SPEAKERS,
+		{DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
+		{DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
+		 DOLBY_ENDDEP_PARAM_VMB_LENGTH},
+		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
+		 DOLBY_ENDDEP_PARAM_VMB_OFFSET},
+		{-320, -320, 144}
+	},
 	{FM, 2, DOLBY_ENDP_HDMI,
 		{DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
 		{DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
@@ -409,7 +417,8 @@
 	for (idx = 0; idx < NUM_DOLBY_ENDP_DEVICE; idx++) {
 		if (dolby_dap_endp_params[idx].device ==
 			dolby_dap_params_states.device) {
-			if (dolby_dap_params_states.device == AUX_DIGITAL) {
+			if (dolby_dap_params_states.device == AUX_DIGITAL ||
+			    dolby_dap_params_states.device == PROXY) {
 				if (dolby_dap_endp_params[idx].device_ch_caps ==
 					device_channels)
 					break;
diff --git a/sound/soc/msm/qdsp6v2/msm-dolby-dap-config.h b/sound/soc/msm/qdsp6v2/msm-dolby-dap-config.h
index 4544fea..14586f4 100644
--- a/sound/soc/msm/qdsp6v2/msm-dolby-dap-config.h
+++ b/sound/soc/msm/qdsp6v2/msm-dolby-dap-config.h
@@ -249,7 +249,7 @@
 #define DOLBY_AUTO_ENDDEP_IDX			(MAX_DOLBY_PARAMS+4)
 
 #define TOTAL_LENGTH_DOLBY_PARAM		745
-#define NUM_DOLBY_ENDP_DEVICE			23
+#define NUM_DOLBY_ENDP_DEVICE			24
 #define DOLBY_VIS_PARAM_HEADER_SIZE		 25
 
 #define DOLBY_INVALID_PORT_ID			-1
diff --git a/sound/soc/msm/qdsp6v2/msm-lsm-client.c b/sound/soc/msm/qdsp6v2/msm-lsm-client.c
index 3f57078..ff82299 100644
--- a/sound/soc/msm/qdsp6v2/msm-lsm-client.c
+++ b/sound/soc/msm/qdsp6v2/msm-lsm-client.c
@@ -170,6 +170,9 @@
 				 */
 				rc = -EFAULT;
 			} else {
+				if (!access_ok(VERIFY_READ, user,
+					sizeof(struct snd_lsm_event_status)))
+					rc = -EFAULT;
 				if (user->payload_size <
 				    event_status->payload_size) {
 					pr_debug("%s: provided %dbytes isn't enough, needs %dbytes\n",
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-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
index 3ddc3e0..08448fe 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
@@ -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
@@ -99,7 +99,7 @@
 /* Conventional and unconventional sample rate supported */
 static unsigned int supported_sample_rates[] = {
 	8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000,
-	96000, 192000
+	88200, 96000, 176400, 192000
 };
 
 static uint32_t in_frame_info[CAPTURE_MAX_NUM_PERIODS][2];
@@ -188,6 +188,7 @@
 		} else {
 			pr_debug("%s: reclaim flushed buf in_count %x\n",
 				__func__, atomic_read(&prtd->in_count));
+			prtd->pcm_irq_pos += prtd->pcm_count;
 			atomic_inc(&prtd->in_count);
 			if (atomic_read(&prtd->in_count) == prtd->periods) {
 				pr_info("%s: reclaimed all bufs\n", __func__);
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
index 91c0744..4893990 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
@@ -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
@@ -59,6 +59,7 @@
 #define INVALID_SESSION -1
 #define SESSION_TYPE_RX 0
 #define SESSION_TYPE_TX 1
+#define MAX_LSM_SESSIONS 8
 
 #define EC_PORT_ID_PRIMARY_MI2S_TX    1
 #define EC_PORT_ID_SECONDARY_MI2S_TX  2
@@ -72,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;
 
@@ -103,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);
@@ -153,12 +158,12 @@
  * If new back-end is defined, add new back-end DAI ID at the end of enum
  */
 
-
+#define SRS_TRUMEDIA_INDEX 2
 union srs_trumedia_params_u {
 	struct srs_trumedia_params srs_params;
 	unsigned short int raw_params[1];
 };
-static union srs_trumedia_params_u msm_srs_trumedia_params[2];
+static union srs_trumedia_params_u msm_srs_trumedia_params[SRS_TRUMEDIA_INDEX];
 static int srs_port_id = -1;
 
 static void srs_send_params(int port_id, unsigned int techs,
@@ -429,7 +434,7 @@
 				path_type,
 				msm_bedais[i].sample_rate,
 				msm_bedais[i].channel,
-				topology, false,
+				topology, perf_mode,
 				bits_per_sample);
 
 			payload.copp_ids[payload.num_copps++] =
@@ -687,6 +692,8 @@
 		session_id = voc_get_session_id(VOICE_SESSION_NAME);
 	else if (val == MSM_FRONTEND_DAI_VOLTE)
 		session_id = voc_get_session_id(VOLTE_SESSION_NAME);
+	else if (val == MSM_FRONTEND_DAI_VOWLAN)
+		session_id = voc_get_session_id(VOWLAN_SESSION_NAME);
 	else if (val == MSM_FRONTEND_DAI_VOICE2)
 		session_id = voc_get_session_id(VOICE2_SESSION_NAME);
 	else if (val == MSM_FRONTEND_DAI_QCHAT)
@@ -722,9 +729,9 @@
 
 			if (voc_get_route_flag(session_id, RX_PATH) &&
 			   voc_get_route_flag(session_id, TX_PATH))
-				voc_enable_cvp(session_id);
+				voc_enable_device(session_id);
 		} else {
-			voc_disable_cvp(session_id);
+			voc_disable_device(session_id);
 		}
 	} else {
 		voc_set_route_flag(session_id, TX_PATH, set);
@@ -733,9 +740,9 @@
 				msm_bedais[reg].port_id, DEV_TX);
 			if (voc_get_route_flag(session_id, RX_PATH) &&
 			   voc_get_route_flag(session_id, TX_PATH))
-				voc_enable_cvp(session_id);
+				voc_enable_device(session_id);
 		} else {
-			voc_disable_cvp(session_id);
+			voc_disable_device(session_id);
 		}
 	}
 }
@@ -1092,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)
 {
@@ -1186,7 +1210,7 @@
 			SRS_PARAM_OFFSET_MASK) >> 16);
 	value = (unsigned short)(ucontrol->value.integer.value[0] &
 			SRS_PARAM_VALUE_MASK);
-	if (offset < max) {
+	if ((offset < max) && (index < SRS_TRUMEDIA_INDEX)) {
 		msm_srs_trumedia_params[index].raw_params[offset] = value;
 		pr_debug("SRS %s: index set... (max %d, requested %d, val %d, paramblockidx %d)",
 			__func__, max, offset, value, index);
@@ -1395,38 +1419,97 @@
 				struct snd_ctl_elem_value *ucontrol)
 {
 	int ec_ref_port_id;
+	struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
+	struct snd_soc_dapm_widget *widget = wlist->widgets[0];
+	int mux = ucontrol->value.enumerated.item[0];
+	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+
 	mutex_lock(&routing_lock);
 	switch (ucontrol->value.integer.value[0]) {
 	case 0:
 		msm_route_ec_ref_rx = 0;
-		ec_ref_port_id = SLIMBUS_0_RX;
+		ec_ref_port_id = AFE_PORT_INVALID;
 		break;
 	case 1:
 		msm_route_ec_ref_rx = 1;
+		ec_ref_port_id = SLIMBUS_0_RX;
+		break;
+	case 2:
+		msm_route_ec_ref_rx = 2;
 		ec_ref_port_id = AFE_PORT_ID_PRIMARY_MI2S_RX;
 		break;
+	case 3:
+		msm_route_ec_ref_rx = 3;
+		ec_ref_port_id = AFE_PORT_ID_PRIMARY_MI2S_TX;
+		break;
+	case 4:
+		msm_route_ec_ref_rx = 4;
+		ec_ref_port_id = AFE_PORT_ID_SECONDARY_MI2S_TX;
+		break;
+	case 5:
+		msm_route_ec_ref_rx = 5;
+		ec_ref_port_id = AFE_PORT_ID_TERTIARY_MI2S_TX;
+		break;
+	case 6:
+		msm_route_ec_ref_rx = 6;
+		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 = 0; /* NONE */
+		pr_err("%s EC ref rx %ld not valid\n",
+			__func__, ucontrol->value.integer.value[0]);
+		ec_ref_port_id = AFE_PORT_INVALID;
 		break;
 	}
 	adm_ec_ref_rx_id(ec_ref_port_id);
 	pr_debug("%s: msm_route_ec_ref_rx = %d\n",
 	    __func__, msm_route_ec_ref_rx);
 	mutex_unlock(&routing_lock);
+	snd_soc_dapm_mux_update_power(widget, kcontrol, 1, mux, e);
 	return 0;
 }
 
-static const char *const ec_ref_rx[] = { "SLIM_RX", "I2S_RX", "PROXY_RX",
-	"NONE" };
+static const char *const ec_ref_rx[] = { "None", "SLIM_RX", "I2S_RX",
+	"PRI_MI2S_TX",
+	"SEC_MI2S_TX", "TERT_MI2S_TX", "QUAT_MI2S_TX", "PROXY_RX"};
 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)
@@ -1475,7 +1558,7 @@
 		msm_route_ext_ec_ref = AFE_PORT_INVALID;
 		break;
 	}
-	if (voc_set_ext_ec_ref(msm_route_ext_ec_ref, state)) {
+	if (!voc_set_ext_ec_ref(msm_route_ext_ec_ref, state)) {
 		mutex_unlock(&routing_lock);
 		snd_soc_dapm_mux_update_power(widget, kcontrol, 1, mux, e);
 	} else {
@@ -2109,6 +2192,9 @@
 	SOC_SINGLE_EXT("VoLTE", MSM_BACKEND_DAI_PRI_I2S_RX,
 	MSM_FRONTEND_DAI_VOLTE, 1, 0, msm_routing_get_voice_mixer,
 	msm_routing_put_voice_mixer),
+	SOC_SINGLE_EXT("VoWLAN", MSM_BACKEND_DAI_PRI_I2S_RX,
+	MSM_FRONTEND_DAI_VOWLAN, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
 	SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_PRI_I2S_RX,
 	MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer,
 	msm_routing_put_voice_mixer),
@@ -2130,6 +2216,9 @@
 	SOC_SINGLE_EXT("VoLTE", MSM_BACKEND_DAI_SEC_I2S_RX,
 	MSM_FRONTEND_DAI_VOLTE, 1, 0, msm_routing_get_voice_mixer,
 	msm_routing_put_voice_mixer),
+	SOC_SINGLE_EXT("VoWLAN", MSM_BACKEND_DAI_SEC_I2S_RX,
+	MSM_FRONTEND_DAI_VOWLAN, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
 	SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_SEC_I2S_RX,
 	MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer,
 	msm_routing_put_voice_mixer),
@@ -2151,6 +2240,9 @@
 	SOC_SINGLE_EXT("VoLTE", MSM_BACKEND_DAI_SECONDARY_MI2S_RX,
 	MSM_FRONTEND_DAI_VOLTE, 1, 0, msm_routing_get_voice_mixer,
 	msm_routing_put_voice_mixer),
+	SOC_SINGLE_EXT("VoWLAN", MSM_BACKEND_DAI_SECONDARY_MI2S_RX,
+	MSM_FRONTEND_DAI_VOWLAN, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
 	SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_SECONDARY_MI2S_RX,
 	MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer,
 	msm_routing_put_voice_mixer),
@@ -2175,6 +2267,9 @@
 	SOC_SINGLE_EXT("VoLTE", MSM_BACKEND_DAI_SLIMBUS_0_RX ,
 	MSM_FRONTEND_DAI_VOLTE, 1, 0, msm_routing_get_voice_mixer,
 	msm_routing_put_voice_mixer),
+	SOC_SINGLE_EXT("VoWLAN", MSM_BACKEND_DAI_SLIMBUS_0_RX ,
+	MSM_FRONTEND_DAI_VOWLAN, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
 	SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_SLIMBUS_0_RX ,
 	MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer,
 	msm_routing_put_voice_mixer),
@@ -2199,6 +2294,9 @@
 	SOC_SINGLE_EXT("VoLTE", MSM_BACKEND_DAI_INT_BT_SCO_RX ,
 	MSM_FRONTEND_DAI_VOLTE, 1, 0, msm_routing_get_voice_mixer,
 	msm_routing_put_voice_mixer),
+	SOC_SINGLE_EXT("VoWLAN", MSM_BACKEND_DAI_INT_BT_SCO_RX ,
+	MSM_FRONTEND_DAI_VOWLAN, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
 	SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_INT_BT_SCO_RX ,
 	MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer,
 	msm_routing_put_voice_mixer),
@@ -2223,6 +2321,9 @@
 	SOC_SINGLE_EXT("VoLTE", MSM_BACKEND_DAI_MI2S_RX,
 	MSM_FRONTEND_DAI_VOLTE, 1, 0, msm_routing_get_voice_mixer,
 	msm_routing_put_voice_mixer),
+	SOC_SINGLE_EXT("VoWLAN", MSM_BACKEND_DAI_MI2S_RX,
+	MSM_FRONTEND_DAI_VOWLAN, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
 	SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_MI2S_RX,
 	MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer,
 	msm_routing_put_voice_mixer),
@@ -2247,6 +2348,9 @@
 	SOC_SINGLE_EXT("VoLTE", MSM_BACKEND_DAI_AFE_PCM_RX,
 	MSM_FRONTEND_DAI_VOLTE, 1, 0, msm_routing_get_voice_mixer,
 	msm_routing_put_voice_mixer),
+	SOC_SINGLE_EXT("VoWLAN", MSM_BACKEND_DAI_AFE_PCM_RX,
+	MSM_FRONTEND_DAI_VOWLAN, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
 	SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_AFE_PCM_RX,
 	MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer,
 	msm_routing_put_voice_mixer),
@@ -2271,6 +2375,9 @@
 	SOC_SINGLE_EXT("VoLTE", MSM_BACKEND_DAI_AUXPCM_RX,
 	MSM_FRONTEND_DAI_VOLTE, 1, 0, msm_routing_get_voice_mixer,
 	msm_routing_put_voice_mixer),
+	SOC_SINGLE_EXT("VoWLAN", MSM_BACKEND_DAI_AUXPCM_RX,
+	MSM_FRONTEND_DAI_VOWLAN, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
 	SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_AUXPCM_RX,
 	MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer,
 	msm_routing_put_voice_mixer),
@@ -2292,6 +2399,9 @@
 	SOC_SINGLE_EXT("VoLTE", MSM_BACKEND_DAI_SEC_AUXPCM_RX,
 	MSM_FRONTEND_DAI_VOLTE, 1, 0, msm_routing_get_voice_mixer,
 	msm_routing_put_voice_mixer),
+	SOC_SINGLE_EXT("VoWLAN", MSM_BACKEND_DAI_SEC_AUXPCM_RX,
+	MSM_FRONTEND_DAI_VOWLAN, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
 	SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_SEC_AUXPCM_RX,
 	MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer,
 	msm_routing_put_voice_mixer),
@@ -2313,6 +2423,9 @@
 	SOC_SINGLE_EXT("VoLTE", MSM_BACKEND_DAI_HDMI_RX,
 	MSM_FRONTEND_DAI_VOLTE, 1, 0, msm_routing_get_voice_mixer,
 	msm_routing_put_voice_mixer),
+	SOC_SINGLE_EXT("VoWLAN", MSM_BACKEND_DAI_HDMI_RX,
+	MSM_FRONTEND_DAI_VOWLAN, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
 	SOC_SINGLE_EXT("Voice Stub", MSM_BACKEND_DAI_HDMI_RX,
 	MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
 	msm_routing_put_voice_stub_mixer),
@@ -2417,6 +2530,33 @@
 	msm_routing_put_voice_mixer),
 };
 
+static const struct snd_kcontrol_new tx_vowlan_mixer_controls[] = {
+	SOC_SINGLE_EXT("PRI_TX_VoWLAN", MSM_BACKEND_DAI_PRI_I2S_TX,
+	MSM_FRONTEND_DAI_VOWLAN, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
+	SOC_SINGLE_EXT("SLIM_0_TX_VoWLAN", MSM_BACKEND_DAI_SLIMBUS_0_TX,
+	MSM_FRONTEND_DAI_VOWLAN, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
+	SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX_VoWLAN",
+	MSM_BACKEND_DAI_INT_BT_SCO_TX, MSM_FRONTEND_DAI_VOWLAN, 1, 0,
+	msm_routing_get_voice_mixer, msm_routing_put_voice_mixer),
+	SOC_SINGLE_EXT("AFE_PCM_TX_VoWLAN", MSM_BACKEND_DAI_AFE_PCM_TX,
+	MSM_FRONTEND_DAI_VOWLAN, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
+	SOC_SINGLE_EXT("AUX_PCM_TX_VoWLAN", MSM_BACKEND_DAI_AUXPCM_TX,
+	MSM_FRONTEND_DAI_VOWLAN, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
+	SOC_SINGLE_EXT("SEC_AUX_PCM_TX_VoWLAN", MSM_BACKEND_DAI_SEC_AUXPCM_TX,
+	MSM_FRONTEND_DAI_VOWLAN, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
+	SOC_SINGLE_EXT("MI2S_TX_VoWLAN", MSM_BACKEND_DAI_MI2S_TX,
+	MSM_FRONTEND_DAI_VOWLAN, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
+	SOC_SINGLE_EXT("PRI_MI2S_TX_VoWLAN", MSM_BACKEND_DAI_PRI_MI2S_TX,
+	MSM_FRONTEND_DAI_VOWLAN, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
+};
+
 static const struct snd_kcontrol_new tx_voip_mixer_controls[] = {
 	SOC_SINGLE_EXT("PRI_TX_Voip", MSM_BACKEND_DAI_PRI_I2S_TX,
 	MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer,
@@ -2610,13 +2750,52 @@
 	0, 1, 0, msm_routing_get_fm_pcmrx_switch_mixer,
 	msm_routing_put_fm_pcmrx_switch_mixer);
 
+static const struct snd_kcontrol_new pri_mi2s_rx_switch_mixer_controls =
+	SOC_SINGLE_EXT("Switch", SND_SOC_NOPM,
+	0, 1, 0, msm_routing_get_switch_mixer,
+	msm_routing_put_switch_mixer);
+
 static const struct soc_enum lsm_mux_enum =
 	SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(mad_audio_mux_text), mad_audio_mux_text);
-static const struct snd_kcontrol_new lsm_mux =
+
+static const struct snd_kcontrol_new lsm1_mux =
 	SOC_DAPM_ENUM_EXT("LSM1 MUX", lsm_mux_enum,
 			  msm_routing_lsm_mux_get,
 			  msm_routing_lsm_mux_put);
 
+static const struct snd_kcontrol_new lsm2_mux =
+	SOC_DAPM_ENUM_EXT("LSM2 MUX", lsm_mux_enum,
+			  msm_routing_lsm_mux_get,
+			  msm_routing_lsm_mux_put);
+static const struct snd_kcontrol_new lsm3_mux =
+	SOC_DAPM_ENUM_EXT("LSM3 MUX", lsm_mux_enum,
+			  msm_routing_lsm_mux_get,
+			  msm_routing_lsm_mux_put);
+
+static const struct snd_kcontrol_new lsm4_mux =
+	SOC_DAPM_ENUM_EXT("LSM4 MUX", lsm_mux_enum,
+			  msm_routing_lsm_mux_get,
+			  msm_routing_lsm_mux_put);
+static const struct snd_kcontrol_new lsm5_mux =
+	SOC_DAPM_ENUM_EXT("LSM5 MUX", lsm_mux_enum,
+			  msm_routing_lsm_mux_get,
+			  msm_routing_lsm_mux_put);
+
+static const struct snd_kcontrol_new lsm6_mux =
+	SOC_DAPM_ENUM_EXT("LSM6 MUX", lsm_mux_enum,
+			  msm_routing_lsm_mux_get,
+			  msm_routing_lsm_mux_put);
+static const struct snd_kcontrol_new lsm7_mux =
+	SOC_DAPM_ENUM_EXT("LSM7 MUX", lsm_mux_enum,
+			  msm_routing_lsm_mux_get,
+			  msm_routing_lsm_mux_put);
+
+static const struct snd_kcontrol_new lsm8_mux =
+	SOC_DAPM_ENUM_EXT("LSM8 MUX", lsm_mux_enum,
+			  msm_routing_lsm_mux_get,
+			  msm_routing_lsm_mux_put);
+
+
 static const char * const lsm_func_text[] = {
 	"None", "AUDIO", "BEACON", "ULTRASOUND", "SWAUDIO",
 };
@@ -2658,6 +2837,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,
@@ -2784,6 +2969,7 @@
 int msm_routing_get_rms_value_control(struct snd_kcontrol *kcontrol,
 				struct snd_ctl_elem_value *ucontrol) {
 	int rc = 0;
+	int be_idx = 0;
 	char *param_value;
 	int *update_param_value;
 	uint32_t param_length = sizeof(uint32_t);
@@ -2793,21 +2979,26 @@
 		pr_err("%s, param memory alloc failed\n", __func__);
 		return -ENOMEM;
 	}
-	rc = adm_get_params(SLIMBUS_0_TX,
-			RMS_MODULEID_APPI_PASSTHRU,
-			RMS_PARAM_FIRST_SAMPLE,
-			param_length + param_payload_len,
-			param_value);
-	if (rc) {
-		pr_err("%s: get parameters failed\n", __func__);
-		kfree(param_value);
-		return -EINVAL;
-	}
-	update_param_value = (int *)param_value;
-	ucontrol->value.integer.value[0] = update_param_value[0];
+	for (be_idx = 0; be_idx < MSM_BACKEND_DAI_MAX; be_idx++)
+		if (msm_bedais[be_idx].port_id == SLIMBUS_0_TX)
+			break;
+	if ((be_idx < MSM_BACKEND_DAI_MAX) && msm_bedais[be_idx].active) {
+		rc = adm_get_params(SLIMBUS_0_TX,
+				RMS_MODULEID_APPI_PASSTHRU,
+				RMS_PARAM_FIRST_SAMPLE,
+				param_length + param_payload_len,
+				param_value);
+		if (rc) {
+			pr_err("%s: get parameters failed\n", __func__);
+			kfree(param_value);
+			return -EINVAL;
+		}
+		update_param_value = (int *)param_value;
+		ucontrol->value.integer.value[0] = update_param_value[0];
 
-	pr_debug("%s: FROM DSP value[0] 0x%x\n",
-		__func__, update_param_value[0]);
+		pr_debug("%s: FROM DSP value[0] 0x%x\n",
+			  __func__, update_param_value[0]);
+	}
 	kfree(param_value);
 	return 0;
 }
@@ -3110,6 +3301,8 @@
 	SND_SOC_DAPM_AIF_OUT("VOICE2_UL", "Voice2 Capture", 0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_IN("VoLTE_DL", "VoLTE Playback", 0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_OUT("VoLTE_UL", "VoLTE Capture", 0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_IN("VoWLAN_DL", "VoWLAN Playback", 0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("VoWLAN_UL", "VoWLAN Capture", 0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_OUT("VOIP_UL", "VoIP Capture", 0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_IN("SLIM0_DL_HL", "SLIMBUS0_HOSTLESS Playback",
 		0, 0, 0, 0),
@@ -3151,13 +3344,30 @@
 	SND_SOC_DAPM_AIF_OUT("PRI_MI2S_UL_HL",
 		"Primary MI2S_TX Hostless Capture",
 		0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_IN("PRI_MI2S_DL_HL",
+		"Primary MI2S_RX Hostless Playback",
+		0, 0, 0, 0),
 
 	SND_SOC_DAPM_AIF_OUT("MI2S_DL_HL", "MI2S_RX_HOSTLESS Playback",
 		0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_IN("DTMF_DL_HL", "DTMF_RX_HOSTLESS Playback",
 		0, 0, 0, 0),
 	/* LSM */
-	SND_SOC_DAPM_AIF_OUT("LSM_UL_HL", "Listen Audio Service Capture",
+	SND_SOC_DAPM_AIF_OUT("LSM1_UL_HL", "Listen 1 Audio Service Capture",
+			     0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("LSM2_UL_HL", "Listen 2 Audio Service Capture",
+			     0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("LSM3_UL_HL", "Listen 3 Audio Service Capture",
+				 0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("LSM4_UL_HL", "Listen 4 Audio Service Capture",
+						 0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("LSM5_UL_HL", "Listen 5 Audio Service Capture",
+				 0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("LSM6_UL_HL", "Listen 6 Audio Service Capture",
+				 0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("LSM7_UL_HL", "Listen 7 Audio Service Capture",
+				 0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("LSM8_UL_HL", "Listen 8 Audio Service Capture",
 			     0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_IN("QCHAT_DL", "QCHAT Playback", 0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_OUT("QCHAT_UL", "QCHAT Capture", 0, 0, 0, 0),
@@ -3243,9 +3453,18 @@
 				&fm_switch_mixer_controls),
 	SND_SOC_DAPM_SWITCH("PCM_RX_DL_HL", SND_SOC_NOPM, 0, 0,
 				&pcm_rx_switch_mixer_controls),
+	SND_SOC_DAPM_SWITCH("PRI_MI2S_RX_DL_HL", SND_SOC_NOPM, 0, 0,
+				&pri_mi2s_rx_switch_mixer_controls),
 
 	/* Mux Definitions */
-	SND_SOC_DAPM_MUX("LSM1 MUX", SND_SOC_NOPM, 0, 0, &lsm_mux),
+	SND_SOC_DAPM_MUX("LSM1 MUX", SND_SOC_NOPM, 0, 0, &lsm1_mux),
+	SND_SOC_DAPM_MUX("LSM2 MUX", SND_SOC_NOPM, 0, 0, &lsm2_mux),
+	SND_SOC_DAPM_MUX("LSM3 MUX", SND_SOC_NOPM, 0, 0, &lsm3_mux),
+	SND_SOC_DAPM_MUX("LSM4 MUX", SND_SOC_NOPM, 0, 0, &lsm4_mux),
+	SND_SOC_DAPM_MUX("LSM5 MUX", SND_SOC_NOPM, 0, 0, &lsm5_mux),
+	SND_SOC_DAPM_MUX("LSM6 MUX", SND_SOC_NOPM, 0, 0, &lsm6_mux),
+	SND_SOC_DAPM_MUX("LSM7 MUX", SND_SOC_NOPM, 0, 0, &lsm7_mux),
+	SND_SOC_DAPM_MUX("LSM8 MUX", SND_SOC_NOPM, 0, 0, &lsm8_mux),
 	SND_SOC_DAPM_MUX("SLIM_0_RX AANC MUX", SND_SOC_NOPM, 0, 0,
 			aanc_slim_0_rx_mux),
 
@@ -3353,6 +3572,9 @@
 	SND_SOC_DAPM_MIXER("VoLTE_Tx Mixer",
 				SND_SOC_NOPM, 0, 0, tx_volte_mixer_controls,
 				ARRAY_SIZE(tx_volte_mixer_controls)),
+	SND_SOC_DAPM_MIXER("VoWLAN_Tx Mixer",
+				SND_SOC_NOPM, 0, 0, tx_vowlan_mixer_controls,
+				ARRAY_SIZE(tx_vowlan_mixer_controls)),
 	SND_SOC_DAPM_MIXER("INTERNAL_BT_SCO_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
 	int_bt_sco_rx_mixer_controls, ARRAY_SIZE(int_bt_sco_rx_mixer_controls)),
 	SND_SOC_DAPM_MIXER("INTERNAL_FM_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
@@ -3410,7 +3632,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[] = {
@@ -3634,6 +3869,7 @@
 	{"PRI_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
 	{"PRI_RX_Voice Mixer", "Voice2", "VOICE2_DL"},
 	{"PRI_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
+	{"PRI_RX_Voice Mixer", "VoWLAN", "VoWLAN_DL"},
 	{"PRI_RX_Voice Mixer", "Voip", "VOIP_DL"},
 	{"PRI_RX_Voice Mixer", "DTMF", "DTMF_DL_HL"},
 	{"PRI_RX_Voice Mixer", "QCHAT", "QCHAT_DL"},
@@ -3642,6 +3878,7 @@
 	{"SEC_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
 	{"SEC_RX_Voice Mixer", "Voice2", "VOICE2_DL"},
 	{"SEC_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
+	{"SEC_RX_Voice Mixer", "VoWLAN", "VoWLAN_DL"},
 	{"SEC_RX_Voice Mixer", "Voip", "VOIP_DL"},
 	{"SEC_RX_Voice Mixer", "DTMF", "DTMF_DL_HL"},
 	{"SEC_RX_Voice Mixer", "QCHAT", "QCHAT_DL"},
@@ -3650,6 +3887,7 @@
 	{"SEC_MI2S_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
 	{"SEC_MI2S_RX_Voice Mixer", "Voice2", "VOICE2_DL"},
 	{"SEC_MI2S_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
+	{"SEC_MI2S_RX_Voice Mixer", "VoWLAN", "VoWLAN_DL"},
 	{"SEC_MI2S_RX_Voice Mixer", "Voip", "VOIP_DL"},
 	{"SEC_MI2S_RX_Voice Mixer", "DTMF", "DTMF_DL_HL"},
 	{"SEC_MI2S_RX_Voice Mixer", "QCHAT", "QCHAT_DL"},
@@ -3658,6 +3896,7 @@
 	{"SLIM_0_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
 	{"SLIM_0_RX_Voice Mixer", "Voice2", "VOICE2_DL"},
 	{"SLIM_0_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
+	{"SLIM_0_RX_Voice Mixer", "VoWLAN", "VoWLAN_DL"},
 	{"SLIM_0_RX_Voice Mixer", "Voip", "VOIP_DL"},
 	{"SLIM_0_RX_Voice Mixer", "DTMF", "DTMF_DL_HL"},
 	{"SLIM_0_RX_Voice Mixer", "Voice Stub", "VOICE_STUB_DL"},
@@ -3667,6 +3906,7 @@
 	{"INTERNAL_BT_SCO_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
 	{"INTERNAL_BT_SCO_RX_Voice Mixer", "Voice2", "VOICE2_DL"},
 	{"INTERNAL_BT_SCO_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
+	{"INTERNAL_BT_SCO_RX_Voice Mixer", "VoWLAN", "VoWLAN_DL"},
 	{"INTERNAL_BT_SCO_RX_Voice Mixer", "Voip", "VOIP_DL"},
 	{"INTERNAL_BT_SCO_RX_Voice Mixer", "DTMF", "DTMF_DL_HL"},
 	{"INTERNAL_BT_SCO_RX_Voice Mixer", "QCHAT", "QCHAT_DL"},
@@ -3675,6 +3915,7 @@
 	{"AFE_PCM_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
 	{"AFE_PCM_RX_Voice Mixer", "Voice2", "VOICE2_DL"},
 	{"AFE_PCM_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
+	{"AFE_PCM_RX_Voice Mixer", "VoWLAN", "VoWLAN_DL"},
 	{"AFE_PCM_RX_Voice Mixer", "Voip", "VOIP_DL"},
 	{"AFE_PCM_RX_Voice Mixer", "DTMF", "DTMF_DL_HL"},
 	{"AFE_PCM_RX_Voice Mixer", "QCHAT", "QCHAT_DL"},
@@ -3683,6 +3924,7 @@
 	{"AUX_PCM_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
 	{"AUX_PCM_RX_Voice Mixer", "Voice2", "VOICE2_DL"},
 	{"AUX_PCM_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
+	{"AUX_PCM_RX_Voice Mixer", "VoWLAN", "VoWLAN_DL"},
 	{"AUX_PCM_RX_Voice Mixer", "Voip", "VOIP_DL"},
 	{"AUX_PCM_RX_Voice Mixer", "DTMF", "DTMF_DL_HL"},
 	{"AUX_PCM_RX_Voice Mixer", "Voice Stub", "VOICE_STUB_DL"},
@@ -3691,6 +3933,7 @@
 
 	{"SEC_AUX_PCM_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
 	{"SEC_AUX_PCM_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
+	{"SEC_AUX_PCM_RX_Voice Mixer", "VoWLAN", "VoWLAN_DL"},
 	{"SEC_AUX_PCM_RX_Voice Mixer", "Voip", "VOIP_DL"},
 	{"SEC_AUX_PCM_RX_Voice Mixer", "DTMF", "DTMF_DL_HL"},
 	{"SEC_AUX_PCM_RX_Voice Mixer", "Voice Stub", "VOICE_STUB_DL"},
@@ -3700,6 +3943,7 @@
 	{"HDMI_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
 	{"HDMI_RX_Voice Mixer", "Voice2", "VOICE2_DL"},
 	{"HDMI_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
+	{"HDMI_RX_Voice Mixer", "VoWLAN", "VoWLAN_DL"},
 	{"HDMI_RX_Voice Mixer", "Voip", "VOIP_DL"},
 	{"HDMI_RX_Voice Mixer", "DTMF", "DTMF_DL_HL"},
 	{"HDMI_RX_Voice Mixer", "QCHAT", "QCHAT_DL"},
@@ -3710,6 +3954,7 @@
 	{"MI2S_RX_Voice Mixer", "Voice2", "VOICE2_DL"},
 	{"MI2S_RX_Voice Mixer", "Voip", "VOIP_DL"},
 	{"MI2S_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
+	{"MI2S_RX_Voice Mixer", "VoWLAN", "VoWLAN_DL"},
 	{"MI2S_RX_Voice Mixer", "Voice Stub", "VOICE_STUB_DL"},
 	{"MI2S_RX_Voice Mixer", "QCHAT", "QCHAT_DL"},
 	{"MI2S_RX", NULL, "MI2S_RX_Voice Mixer"},
@@ -3719,6 +3964,65 @@
 	{"VOC_EXT_EC MUX", "TERT_MI2S_TX" , "TERT_MI2S_TX"},
 	{"VOC_EXT_EC MUX", "QUAT_MI2S_TX" , "QUAT_MI2S_TX"},
 	{"CS-VOICE_UL1", NULL, "VOC_EXT_EC MUX"},
+	{"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"},
@@ -3747,6 +4051,16 @@
 	{"VoLTE_Tx Mixer", "SEC_AUX_PCM_TX_VoLTE", "SEC_AUX_PCM_TX"},
 	{"VoLTE_Tx Mixer", "MI2S_TX_VoLTE", "MI2S_TX"},
 	{"VoLTE_UL", NULL, "VoLTE_Tx Mixer"},
+
+	{"VoWLAN_Tx Mixer", "PRI_TX_VoWLAN", "PRI_I2S_TX"},
+	{"VoWLAN_Tx Mixer", "SLIM_0_TX_VoWLAN", "SLIMBUS_0_TX"},
+	{"VoWLAN_Tx Mixer", "INTERNAL_BT_SCO_TX_VoWLAN", "INT_BT_SCO_TX"},
+	{"VoWLAN_Tx Mixer", "AFE_PCM_TX_VoWLAN", "PCM_TX"},
+	{"VoWLAN_Tx Mixer", "AUX_PCM_TX_VoWLAN", "AUX_PCM_TX"},
+	{"VoWLAN_Tx Mixer", "SEC_AUX_PCM_TX_VoWLAN", "SEC_AUX_PCM_TX"},
+	{"VoWLAN_Tx Mixer", "MI2S_TX_VoWLAN", "MI2S_TX"},
+	{"VoWLAN_UL", NULL, "VoWLAN_Tx Mixer"},
+
 	{"Voip_Tx Mixer", "PRI_TX_Voip", "PRI_I2S_TX"},
 	{"Voip_Tx Mixer", "MI2S_TX_Voip", "MI2S_TX"},
 	{"Voip_Tx Mixer", "SLIM_0_TX_Voip", "SLIMBUS_0_TX"},
@@ -3775,7 +4089,62 @@
 	{"LSM1 MUX", "SLIMBUS_3_TX", "SLIMBUS_3_TX"},
 	{"LSM1 MUX", "SLIMBUS_4_TX", "SLIMBUS_4_TX"},
 	{"LSM1 MUX", "SLIMBUS_5_TX", "SLIMBUS_5_TX"},
-	{"LSM_UL_HL", NULL, "LSM1 MUX"},
+	{"LSM1_UL_HL", NULL, "LSM1 MUX"},
+
+	{"LSM2 MUX", "SLIMBUS_0_TX", "SLIMBUS_0_TX"},
+	{"LSM2 MUX", "SLIMBUS_1_TX", "SLIMBUS_1_TX"},
+	{"LSM2 MUX", "SLIMBUS_3_TX", "SLIMBUS_3_TX"},
+	{"LSM2 MUX", "SLIMBUS_4_TX", "SLIMBUS_4_TX"},
+	{"LSM2 MUX", "SLIMBUS_5_TX", "SLIMBUS_5_TX"},
+	{"LSM2_UL_HL", NULL, "LSM2 MUX"},
+
+
+	{"LSM3 MUX", "SLIMBUS_0_TX", "SLIMBUS_0_TX"},
+	{"LSM3 MUX", "SLIMBUS_1_TX", "SLIMBUS_1_TX"},
+	{"LSM3 MUX", "SLIMBUS_3_TX", "SLIMBUS_3_TX"},
+	{"LSM3 MUX", "SLIMBUS_4_TX", "SLIMBUS_4_TX"},
+	{"LSM3 MUX", "SLIMBUS_5_TX", "SLIMBUS_5_TX"},
+	{"LSM3_UL_HL", NULL, "LSM3 MUX"},
+
+
+	{"LSM4 MUX", "SLIMBUS_0_TX", "SLIMBUS_0_TX"},
+	{"LSM4 MUX", "SLIMBUS_1_TX", "SLIMBUS_1_TX"},
+	{"LSM4 MUX", "SLIMBUS_3_TX", "SLIMBUS_3_TX"},
+	{"LSM4 MUX", "SLIMBUS_4_TX", "SLIMBUS_4_TX"},
+	{"LSM4 MUX", "SLIMBUS_5_TX", "SLIMBUS_5_TX"},
+	{"LSM4_UL_HL", NULL, "LSM4 MUX"},
+
+	{"LSM5 MUX", "SLIMBUS_0_TX", "SLIMBUS_0_TX"},
+	{"LSM5 MUX", "SLIMBUS_1_TX", "SLIMBUS_1_TX"},
+	{"LSM5 MUX", "SLIMBUS_3_TX", "SLIMBUS_3_TX"},
+	{"LSM5 MUX", "SLIMBUS_4_TX", "SLIMBUS_4_TX"},
+	{"LSM5 MUX", "SLIMBUS_5_TX", "SLIMBUS_5_TX"},
+	{"LSM5_UL_HL", NULL, "LSM5 MUX"},
+
+	{"LSM6 MUX", "SLIMBUS_0_TX", "SLIMBUS_0_TX"},
+	{"LSM6 MUX", "SLIMBUS_1_TX", "SLIMBUS_1_TX"},
+	{"LSM6 MUX", "SLIMBUS_3_TX", "SLIMBUS_3_TX"},
+	{"LSM6 MUX", "SLIMBUS_4_TX", "SLIMBUS_4_TX"},
+	{"LSM6 MUX", "SLIMBUS_5_TX", "SLIMBUS_5_TX"},
+	{"LSM6_UL_HL", NULL, "LSM6 MUX"},
+
+
+	{"LSM7 MUX", "SLIMBUS_0_TX", "SLIMBUS_0_TX"},
+	{"LSM7 MUX", "SLIMBUS_1_TX", "SLIMBUS_1_TX"},
+	{"LSM7 MUX", "SLIMBUS_3_TX", "SLIMBUS_3_TX"},
+	{"LSM7 MUX", "SLIMBUS_4_TX", "SLIMBUS_4_TX"},
+	{"LSM7 MUX", "SLIMBUS_5_TX", "SLIMBUS_5_TX"},
+	{"LSM7_UL_HL", NULL, "LSM7 MUX"},
+
+
+	{"LSM8 MUX", "SLIMBUS_0_TX", "SLIMBUS_0_TX"},
+	{"LSM8 MUX", "SLIMBUS_1_TX", "SLIMBUS_1_TX"},
+	{"LSM8 MUX", "SLIMBUS_3_TX", "SLIMBUS_3_TX"},
+	{"LSM8 MUX", "SLIMBUS_4_TX", "SLIMBUS_4_TX"},
+	{"LSM8 MUX", "SLIMBUS_5_TX", "SLIMBUS_5_TX"},
+	{"LSM8_UL_HL", NULL, "LSM8 MUX"},
+
+
 
 	{"QCHAT_Tx Mixer", "PRI_TX_QCHAT", "PRI_I2S_TX"},
 	{"QCHAT_Tx Mixer", "SLIM_0_TX_QCHAT", "SLIMBUS_0_TX"},
@@ -3797,6 +4166,8 @@
 	{"MI2S_UL_HL", NULL, "MI2S_TX"},
 	{"PCM_RX_DL_HL", "Switch", "SLIM0_DL_HL"},
 	{"PCM_RX", NULL, "PCM_RX_DL_HL"},
+	{"PRI_MI2S_RX_DL_HL", "Switch", "PRI_MI2S_DL_HL"},
+	{"PRI_MI2S_RX", NULL, "PRI_MI2S_RX_DL_HL"},
 	{"MI2S_UL_HL", NULL, "TERT_MI2S_TX"},
 	{"SEC_I2S_RX", NULL, "SEC_I2S_DL_HL"},
 	{"PRI_MI2S_UL_HL", NULL, "PRI_MI2S_TX"},
@@ -4054,7 +4425,7 @@
 				path_type,
 				bedai->sample_rate,
 				channels,
-				topology, false,
+				topology, fe_dai_perf_mode[i][session_type],
 				bits_per_sample);
 			}
 
@@ -4114,6 +4485,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));
 
@@ -4177,10 +4552,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/msm-pcm-routing-v2.h b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h
index 54f5e4a..87e44b2 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.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
@@ -79,9 +79,17 @@
 	MSM_FRONTEND_DAI_VOICE_STUB,
 	MSM_FRONTEND_DAI_VOLTE,
 	MSM_FRONTEND_DAI_DTMF_RX,
-	MSM_FRONTEND_DAI_LSM1,
 	MSM_FRONTEND_DAI_VOICE2,
 	MSM_FRONTEND_DAI_QCHAT,
+	MSM_FRONTEND_DAI_LSM1,
+	MSM_FRONTEND_DAI_LSM2,
+	MSM_FRONTEND_DAI_LSM3,
+	MSM_FRONTEND_DAI_LSM4,
+	MSM_FRONTEND_DAI_LSM5,
+	MSM_FRONTEND_DAI_LSM6,
+	MSM_FRONTEND_DAI_LSM7,
+	MSM_FRONTEND_DAI_LSM8,
+	MSM_FRONTEND_DAI_VOWLAN,
 	MSM_FRONTEND_DAI_MAX,
 };
 
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-voice-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-voice-v2.c
index 1074d76..c54d03c 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-voice-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-voice-v2.c
@@ -75,6 +75,14 @@
 		return false;
 }
 
+static bool is_vowlan(struct msm_voice *pvowlan)
+{
+	if (pvowlan == &voice_info[VOWLAN_SESSION_INDEX])
+		return true;
+	else
+		return false;
+}
+
 static uint32_t get_session_id(struct msm_voice *pvoc)
 {
 	uint32_t session_id = 0;
@@ -85,6 +93,8 @@
 		session_id = voc_get_session_id(VOICE2_SESSION_NAME);
 	else if (is_qchat(pvoc))
 		session_id = voc_get_session_id(QCHAT_SESSION_NAME);
+	else if (is_vowlan(pvoc))
+		session_id = voc_get_session_id(VOWLAN_SESSION_NAME);
 	else
 		session_id = voc_get_session_id(VOICE_SESSION_NAME);
 
@@ -134,6 +144,10 @@
 		voice = &voice_info[QCHAT_SESSION_INDEX];
 		pr_debug("%s: Open QCHAT Substream Id=%s\n",
 			 __func__, substream->pcm->id);
+	} else if (!strncmp("VoWLAN", substream->pcm->id, 6)) {
+		voice = &voice_info[VOWLAN_SESSION_INDEX];
+		pr_debug("%s: Open VoWLAN Substream Id=%s\n",
+			 __func__, substream->pcm->id);
 	} else {
 		voice = &voice_info[VOICE_SESSION_INDEX];
 		pr_debug("%s: Open VOICE Substream Id=%s\n",
@@ -391,12 +405,37 @@
 	pr_debug("%s: mute=%d session_id=%#x ramp_duration=%d\n", __func__,
 		mute, session_id, ramp_duration);
 
-	voc_set_tx_mute(session_id, TX_PATH, mute, ramp_duration);
+	ret = voc_set_tx_mute(session_id, TX_PATH, mute, ramp_duration);
 
 done:
 	return ret;
 }
 
+static int msm_voice_tx_device_mute_put(struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_value *ucontrol)
+{
+	int ret = 0;
+	int mute = ucontrol->value.integer.value[0];
+	uint32_t session_id = ucontrol->value.integer.value[1];
+	int ramp_duration = ucontrol->value.integer.value[2];
+
+	if ((mute < 0) || (mute > 1) || (ramp_duration < 0) ||
+	    (ramp_duration > MAX_RAMP_DURATION)) {
+		pr_err(" %s Invalid arguments", __func__);
+
+		ret = -EINVAL;
+		goto done;
+	}
+
+	pr_debug("%s: mute=%d session_id=%#x ramp_duration=%d\n", __func__,
+		 mute, session_id, ramp_duration);
+
+	ret = voc_set_device_mute(session_id, VSS_IVOLUME_DIRECTION_TX,
+				  mute, ramp_duration);
+
+done:
+	return ret;
+}
 
 static int msm_voice_rx_device_mute_put(struct snd_kcontrol *kcontrol,
 					struct snd_ctl_elem_value *ucontrol)
@@ -406,8 +445,8 @@
 	uint32_t session_id = ucontrol->value.integer.value[1];
 	int ramp_duration = ucontrol->value.integer.value[2];
 
-	if ((mute < 0) || (mute > 1) || (ramp_duration < 0)
-		|| (ramp_duration > MAX_RAMP_DURATION)) {
+	if ((mute < 0) || (mute > 1) || (ramp_duration < 0) ||
+	    (ramp_duration > MAX_RAMP_DURATION)) {
 		pr_err(" %s Invalid arguments", __func__);
 
 		ret = -EINVAL;
@@ -415,9 +454,10 @@
 	}
 
 	pr_debug("%s: mute=%d session_id=%#x ramp_duration=%d\n", __func__,
-		mute, session_id, ramp_duration);
+		 mute, session_id, ramp_duration);
 
-	voc_set_rx_device_mute(session_id, mute, ramp_duration);
+	voc_set_device_mute(session_id, VSS_IVOLUME_DIRECTION_RX,
+			    mute, ramp_duration);
 
 done:
 	return ret;
@@ -448,6 +488,7 @@
 	voc_set_tty_mode(voc_get_session_id(VOICE_SESSION_NAME), tty_mode);
 	voc_set_tty_mode(voc_get_session_id(VOICE2_SESSION_NAME), tty_mode);
 	voc_set_tty_mode(voc_get_session_id(VOLTE_SESSION_NAME), tty_mode);
+	voc_set_tty_mode(voc_get_session_id(VOWLAN_SESSION_NAME), tty_mode);
 
 	return 0;
 }
@@ -470,6 +511,8 @@
 static struct snd_kcontrol_new msm_voice_controls[] = {
 	SOC_SINGLE_MULTI_EXT("Voice Rx Device Mute", SND_SOC_NOPM, 0, VSID_MAX,
 				0, 3, NULL, msm_voice_rx_device_mute_put),
+	SOC_SINGLE_MULTI_EXT("Voice Tx Device Mute", SND_SOC_NOPM, 0, VSID_MAX,
+				0, 3, NULL, msm_voice_tx_device_mute_put),
 	SOC_SINGLE_MULTI_EXT("Voice Tx Mute", SND_SOC_NOPM, 0, VSID_MAX,
 				0, 3, NULL, msm_voice_mute_put),
 	SOC_SINGLE_MULTI_EXT("Voice Rx Gain", SND_SOC_NOPM, 0, VSID_MAX, 0, 3,
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-voice-v2.h b/sound/soc/msm/qdsp6v2/msm-pcm-voice-v2.h
index f199be6..62c5732 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-voice-v2.h
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-voice-v2.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
@@ -18,6 +18,7 @@
 	VOLTE_SESSION_INDEX,
 	VOICE2_SESSION_INDEX,
 	QCHAT_SESSION_INDEX,
+	VOWLAN_SESSION_INDEX,
 	VOICE_SESSION_INDEX_MAX,
 };
 
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-voip-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-voip-v2.c
index 97c7b5d..6b32064 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-voip-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-voip-v2.c
@@ -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
@@ -47,8 +47,27 @@
 #define MODE_AMR_WB		0xD
 #define MODE_PCM		0xC
 #define MODE_4GV_NW		0xE
+#define MODE_G711		0xA
+#define MODE_G711A		0xF
 
-#define VOIP_MODE_MAX		MODE_4GV_NW
+enum msm_audio_g711a_frame_type {
+	MVS_G711A_SPEECH_GOOD,
+	MVS_G711A_SID,
+	MVS_G711A_NO_DATA,
+	MVS_G711A_ERASURE
+};
+
+enum msm_audio_g711a_mode {
+	MVS_G711A_MODE_MULAW,
+	MVS_G711A_MODE_ALAW
+};
+
+enum msm_audio_g711_mode {
+	MVS_G711_MODE_MULAW,
+	MVS_G711_MODE_ALAW
+};
+
+#define VOIP_MODE_MAX		MODE_G711A
 #define VOIP_RATE_MAX		23850
 
 enum format {
@@ -86,6 +105,10 @@
 struct voip_frame_hdr {
 	uint32_t timestamp;
 	union {
+		/*
+		 * Bits 0-15: Frame type
+		 * Bits 16-31: Frame rate
+		 */
 		uint32_t frame_type;
 		uint32_t packet_rate;
 	};
@@ -149,7 +172,7 @@
 	uint32_t evrc_max_rate;
 };
 
-static int voip_get_media_type(uint32_t mode,
+static int voip_get_media_type(uint32_t mode, uint32_t rate_type,
 				unsigned int samp_rate,
 				unsigned int *media_type);
 static int voip_get_rate_type(uint32_t mode,
@@ -162,8 +185,6 @@
 				    struct snd_ctl_elem_value *ucontrol);
 static int msm_voip_rate_config_put(struct snd_kcontrol *kcontrol,
 				    struct snd_ctl_elem_value *ucontrol);
-static int msm_voip_rate_config_get(struct snd_kcontrol *kcontrol,
-				    struct snd_ctl_elem_value *ucontrol);
 static int msm_voip_evrc_min_max_rate_config_put(struct snd_kcontrol *kcontrol,
 					 struct snd_ctl_elem_value *ucontrol);
 static int msm_voip_evrc_min_max_rate_config_get(struct snd_kcontrol *kcontrol,
@@ -277,7 +298,7 @@
 	SOC_SINGLE_EXT("Voip Mode Config", SND_SOC_NOPM, 0, VOIP_MODE_MAX, 0,
 		       msm_voip_mode_config_get, msm_voip_mode_config_put),
 	SOC_SINGLE_EXT("Voip Rate Config", SND_SOC_NOPM, 0, VOIP_RATE_MAX, 0,
-		       msm_voip_rate_config_get, msm_voip_rate_config_put),
+		       NULL, msm_voip_rate_config_put),
 	SOC_SINGLE_MULTI_EXT("Voip Evrc Min Max Rate Config", SND_SOC_NOPM,
 			     0, VOC_1_RATE, 0, 2, msm_voip_evrc_min_max_rate_config_get,
 			     msm_voip_evrc_min_max_rate_config_put),
@@ -356,6 +377,81 @@
 			list_add_tail(&buf_node->list, &prtd->out_queue);
 			break;
 		}
+		case MODE_G711:
+		case MODE_G711A:{
+			/* G711 frames are 10ms each, but the DSP works with
+			 * 20ms frames and sends two 10ms frames per buffer.
+			 * Extract the two frames and put them in separate
+			 * buffers.
+			 */
+			/* Remove the first DSP frame info header.
+			 * Header format: G711A
+			 * Bits 0-1: Frame type
+			 * Bits 2-3: Frame rate
+			 *
+			 * Header format: G711
+			 * Bits 2-3: Frame rate
+			 */
+			if (prtd->mode == MODE_G711A)
+				buf_node->frame.frm_hdr.frame_type =
+							(*voc_pkt) & 0x03;
+			buf_node->frame.frm_hdr.timestamp = timestamp;
+			voc_pkt = voc_pkt + DSP_FRAME_HDR_LEN;
+
+			/* There are two frames in the buffer. Length of the
+			 * first frame:
+			 */
+			buf_node->frame.pktlen = (pkt_len -
+						  2 * DSP_FRAME_HDR_LEN) / 2;
+
+			memcpy(&buf_node->frame.voc_pkt[0],
+			       voc_pkt,
+			       buf_node->frame.pktlen);
+			voc_pkt = voc_pkt + buf_node->frame.pktlen;
+
+			list_add_tail(&buf_node->list, &prtd->out_queue);
+
+			/* Get another buffer from the free Q and fill in the
+			 * second frame.
+			 */
+			if (!list_empty(&prtd->free_out_queue)) {
+				buf_node =
+					list_first_entry(&prtd->free_out_queue,
+							 struct voip_buf_node,
+							 list);
+				list_del(&buf_node->list);
+
+				/* Remove the second DSP frame info header.
+				 * Header format:
+				 * Bits 0-1: Frame type
+				 * Bits 2-3: Frame rate
+				 */
+
+				if (prtd->mode == MODE_G711A)
+					buf_node->frame.frm_hdr.frame_type =
+							(*voc_pkt) & 0x03;
+				buf_node->frame.frm_hdr.timestamp = timestamp;
+				voc_pkt = voc_pkt + DSP_FRAME_HDR_LEN;
+
+				/* There are two frames in the buffer. Length
+				 * of the second frame:
+				 */
+				buf_node->frame.pktlen = (pkt_len -
+						2 * DSP_FRAME_HDR_LEN) / 2;
+
+				memcpy(&buf_node->frame.voc_pkt[0],
+				       voc_pkt,
+				       buf_node->frame.pktlen);
+
+				list_add_tail(&buf_node->list,
+					      &prtd->out_queue);
+			} else {
+				/* Drop the second frame */
+				pr_err("%s: UL data dropped, read is slow\n",
+				       __func__);
+			}
+			break;
+		}
 		default: {
 			buf_node->frame.frm_hdr.timestamp = timestamp;
 			buf_node->frame.pktlen = pkt_len;
@@ -385,6 +481,10 @@
 	struct voip_buf_node *buf_node = NULL;
 	struct voip_drv_info *prtd = private_data;
 	unsigned long dsp_flags;
+	uint32_t rate_type;
+	uint32_t frame_rate;
+	u32 pkt_len;
+	u8 *voc_addr = NULL;
 
 	if (prtd->playback_substream == NULL)
 		return;
@@ -408,7 +508,19 @@
 			 * Bits 4-7: Frame type
 			 */
 			*voc_pkt = ((buf_node->frame.frm_hdr.frame_type &
-					0x0F) << 4) | (prtd->rate_type & 0x0F);
+				   0x0F) << 4);
+			frame_rate = (buf_node->frame.frm_hdr.frame_type &
+				     0xFFFF0000) >> 16;
+			if (frame_rate) {
+				if (voip_get_rate_type(prtd->mode, frame_rate,
+						       &rate_type)) {
+					pr_err("%s(): fail at getting rate_type \n",
+						__func__);
+				} else
+					prtd->rate_type = rate_type;
+			}
+			*voc_pkt |= prtd->rate_type & 0x0F;
+
 			voc_pkt = voc_pkt + DSP_FRAME_HDR_LEN;
 			memcpy(voc_pkt,
 				&buf_node->frame.voc_pkt[0],
@@ -438,6 +550,70 @@
 			list_add_tail(&buf_node->list, &prtd->free_in_queue);
 			break;
 		}
+		case MODE_G711:
+		case MODE_G711A:{
+			/* G711 frames are 10ms each but the DSP expects 20ms
+			 * worth of data, so send two 10ms frames per buffer.
+			 */
+			/* Add the first DSP frame info header. Header format:
+			 * Bits 0-1: Frame type
+			 * Bits 2-3: Frame rate
+			 */
+			voc_addr = voc_pkt;
+			voc_pkt = voc_pkt + sizeof(uint32_t);
+
+			*voc_pkt = ((prtd->rate_type  & 0x0F) << 2) |
+				    (buf_node->frame.frm_hdr.frame_type & 0x03);
+			voc_pkt = voc_pkt + DSP_FRAME_HDR_LEN;
+
+			pkt_len = buf_node->frame.pktlen + DSP_FRAME_HDR_LEN;
+
+			memcpy(voc_pkt,
+			       &buf_node->frame.voc_pkt[0],
+			       buf_node->frame.pktlen);
+			voc_pkt = voc_pkt + buf_node->frame.pktlen;
+
+			list_add_tail(&buf_node->list, &prtd->free_in_queue);
+
+			if (!list_empty(&prtd->in_queue)) {
+				/* Get the second buffer. */
+				buf_node = list_first_entry(&prtd->in_queue,
+							struct voip_buf_node,
+							list);
+				list_del(&buf_node->list);
+
+				/* Add the second DSP frame info header.
+				 * Header format:
+				 * Bits 0-1: Frame type
+				 * Bits 2-3: Frame rate
+				 */
+				*voc_pkt = ((prtd->rate_type & 0x0F) << 2) |
+				(buf_node->frame.frm_hdr.frame_type & 0x03);
+				voc_pkt = voc_pkt + DSP_FRAME_HDR_LEN;
+
+				pkt_len = pkt_len + buf_node->frame.pktlen +
+					   DSP_FRAME_HDR_LEN;
+
+				memcpy(voc_pkt,
+				       &buf_node->frame.voc_pkt[0],
+				       buf_node->frame.pktlen);
+
+				list_add_tail(&buf_node->list,
+					      &prtd->free_in_queue);
+			} else {
+				/* Only 10ms worth of data is available, signal
+				 * erasure frame.
+				 */
+				*voc_pkt = ((prtd->rate_type & 0x0F) << 2) |
+					    (MVS_G711A_ERASURE & 0x03);
+
+				pkt_len = pkt_len + DSP_FRAME_HDR_LEN;
+				pr_debug("%s, Only 10ms read, erase 2nd frame\n",
+					 __func__);
+			}
+			*((uint32_t *)voc_addr) = pkt_len;
+			break;
+		}
 		default: {
 			*((uint32_t *)voc_pkt) = buf_node->frame.pktlen;
 			voc_pkt = voc_pkt + sizeof(uint32_t);
@@ -813,10 +989,12 @@
         pr_debug("%s(): mode=%d, playback sample rate=%d, capture sample rate=%d\n",
                   __func__, prtd->mode, prtd->play_samp_rate, prtd->cap_samp_rate);
 
-	if ((runtime->format != FORMAT_S16_LE) && ((prtd->mode == MODE_PCM) ||
-	    (prtd->mode == MODE_AMR) || (prtd->mode == MODE_AMR_WB) ||
+	if ((runtime->format != FORMAT_S16_LE &&
+	     runtime->format != FORMAT_SPECIAL) &&
+	    ((prtd->mode == MODE_AMR) || (prtd->mode == MODE_AMR_WB) ||
 	    (prtd->mode == MODE_IS127) || (prtd->mode == MODE_4GV_NB) ||
-	    (prtd->mode == MODE_4GV_WB) || (prtd->mode == MODE_4GV_NW))) {
+	    (prtd->mode == MODE_4GV_WB) || (prtd->mode == MODE_4GV_NW) ||
+	    (prtd->mode == MODE_G711) || (prtd->mode == MODE_G711A))) {
 		pr_err("%s(): mode:%d and format:%u are not matched\n",
 			__func__, prtd->mode, (uint32_t)runtime->format);
 
@@ -824,21 +1002,19 @@
 		goto done;
 	}
 
-	ret = voip_get_media_type(prtd->mode,
-				  prtd->play_samp_rate,
-				  &media_type);
-	if (ret < 0) {
-		pr_err("%s(): fail at getting media_type, ret=%d\n",
-			__func__, ret);
+	if (runtime->format != FORMAT_S16_LE && (prtd->mode == MODE_PCM)) {
+		pr_err("%s(): mode:%d and format:%u are not matched\n",
+		       __func__, prtd->mode, runtime->format);
 
-		ret = -EINVAL;
+		ret =  -EINVAL;
 		goto done;
 	}
-	pr_debug("%s(): media_type=%d\n", __func__, media_type);
 
 	if ((prtd->mode == MODE_PCM) ||
 	    (prtd->mode == MODE_AMR) ||
-	    (prtd->mode == MODE_AMR_WB)) {
+	    (prtd->mode == MODE_AMR_WB) ||
+	    (prtd->mode == MODE_G711) ||
+	    (prtd->mode == MODE_G711A)) {
 		ret = voip_get_rate_type(prtd->mode,
 					 prtd->rate,
 					 &rate_type);
@@ -893,6 +1069,19 @@
 		pr_debug("%s(): min rate=%d, max rate=%d\n",
 			  __func__, evrc_min_rate_type, evrc_max_rate_type);
 	}
+	ret = voip_get_media_type(prtd->mode,
+				  prtd->rate_type,
+				  prtd->play_samp_rate,
+				  &media_type);
+	if (ret < 0) {
+		pr_err("%s(): fail at getting media_type, ret=%d\n",
+		       __func__, ret);
+
+		ret = -EINVAL;
+		goto done;
+	}
+	pr_debug("%s(): media_type=%d\n", __func__, media_type);
+
 	if ((prtd->play_samp_rate == 8000) &&
 	    (prtd->cap_samp_rate == 8000))
 		voc_config_vocoder(media_type, rate_type,
@@ -1087,30 +1276,43 @@
 	return 0;
 }
 
-static int msm_voip_rate_config_get(struct snd_kcontrol *kcontrol,
-				    struct snd_ctl_elem_value *ucontrol)
-{
-	mutex_lock(&voip_info.lock);
-
-	ucontrol->value.integer.value[0] = voip_info.rate;
-
-	mutex_unlock(&voip_info.lock);
-
-	return 0;
-}
-
 static int msm_voip_rate_config_put(struct snd_kcontrol *kcontrol,
 				    struct snd_ctl_elem_value *ucontrol)
 {
+	int ret = 0;
+	int rate = ucontrol->value.integer.value[0];
+
 	mutex_lock(&voip_info.lock);
 
-	voip_info.rate = ucontrol->value.integer.value[0];
+	if (voip_info.rate != rate) {
+		voip_info.rate = rate;
+		pr_debug("%s: rate=%d\n", __func__, voip_info.rate);
 
-	pr_debug("%s: rate=%d\n", __func__, voip_info.rate);
+		if (voip_info.state == VOIP_STARTED &&
+		   (voip_info.mode == MODE_AMR ||
+		    voip_info.mode == MODE_AMR_WB)) {
+			ret = voip_config_vocoder(
+					voip_info.capture_substream);
+			if (ret) {
+				pr_err("%s:Failed to configure vocoder, ret=%d\n",
+					__func__, ret);
 
+				goto done;
+			}
+
+			ret = voc_update_amr_vocoder_rate(
+					voc_get_session_id(VOIP_SESSION_NAME));
+			if (ret) {
+				pr_err("%s:Failed to update AMR rate, ret=%d\n",
+					__func__, ret);
+			}
+		}
+	}
+
+done:
 	mutex_unlock(&voip_info.lock);
 
-	return 0;
+	return ret;
 }
 
 static int msm_voip_evrc_min_max_rate_config_get(struct snd_kcontrol *kcontrol,
@@ -1256,6 +1458,10 @@
 		}
 		break;
 	}
+	case MODE_G711:
+	case MODE_G711A:
+		*rate_type = rate;
+		break;
 	default:
 		pr_err("wrong mode type.\n");
 		ret = -EINVAL;
@@ -1265,9 +1471,9 @@
 	return ret;
 }
 
-static int voip_get_media_type(uint32_t mode,
-				unsigned int samp_rate,
-				unsigned int *media_type)
+static int voip_get_media_type(uint32_t mode, uint32_t rate_type,
+			       unsigned int samp_rate,
+			       unsigned int *media_type)
 {
 	int ret = 0;
 
@@ -1298,6 +1504,13 @@
 	case MODE_4GV_NW: /* EVRC-NW */
 		*media_type = VSS_MEDIA_ID_4GV_NW_MODEM;
 		break;
+	case MODE_G711:
+	case MODE_G711A:
+		if (rate_type == MVS_G711A_MODE_MULAW)
+			*media_type = VSS_MEDIA_ID_G711_MULAW;
+		else
+			*media_type = VSS_MEDIA_ID_G711_ALAW;
+		break;
 	default:
 		pr_debug(" input mode is not supported\n");
 		ret = -EINVAL;
diff --git a/sound/soc/msm/qdsp6v2/q6adm.c b/sound/soc/msm/qdsp6v2/q6adm.c
index 54b1263..7b10815 100644
--- a/sound/soc/msm/qdsp6v2/q6adm.c
+++ b/sound/soc/msm/qdsp6v2/q6adm.c
@@ -93,6 +93,11 @@
 		sz = sizeof(struct adm_cmd_set_pp_params_inband_v5) +
 			sizeof(struct srs_trumedia_params_GLOBAL);
 		adm_params = kzalloc(sz, GFP_KERNEL);
+		if (!adm_params) {
+			pr_err("%s, adm params memory alloc failed\n",
+				__func__);
+			return -ENOMEM;
+		}
 		adm_params->payload_size =
 			sizeof(struct srs_trumedia_params_GLOBAL) +
 			sizeof(struct adm_param_data_v5);
@@ -117,6 +122,11 @@
 		sz = sizeof(struct adm_cmd_set_pp_params_inband_v5) +
 			sizeof(struct srs_trumedia_params_WOWHD);
 		adm_params = kzalloc(sz, GFP_KERNEL);
+		if (!adm_params) {
+			pr_err("%s, adm params memory alloc failed\n",
+				__func__);
+			return -ENOMEM;
+		}
 		adm_params->payload_size =
 			sizeof(struct srs_trumedia_params_WOWHD) +
 			sizeof(struct adm_param_data_v5);
@@ -142,6 +152,11 @@
 		sz = sizeof(struct adm_cmd_set_pp_params_inband_v5) +
 			sizeof(struct srs_trumedia_params_CSHP);
 		adm_params = kzalloc(sz, GFP_KERNEL);
+		if (!adm_params) {
+			pr_err("%s, adm params memory alloc failed\n",
+				__func__);
+			return -ENOMEM;
+		}
 		adm_params->payload_size =
 			sizeof(struct srs_trumedia_params_CSHP) +
 			sizeof(struct adm_param_data_v5);
@@ -166,6 +181,11 @@
 		sz = sizeof(struct adm_cmd_set_pp_params_inband_v5) +
 			sizeof(struct srs_trumedia_params_HPF);
 		adm_params = kzalloc(sz, GFP_KERNEL);
+		if (!adm_params) {
+			pr_err("%s, adm params memory alloc failed\n",
+				__func__);
+			return -ENOMEM;
+		}
 		adm_params->payload_size =
 			sizeof(struct srs_trumedia_params_HPF) +
 			sizeof(struct adm_param_data_v5);
@@ -186,6 +206,11 @@
 		sz = sizeof(struct adm_cmd_set_pp_params_inband_v5) +
 			sizeof(struct srs_trumedia_params_PEQ);
 		adm_params = kzalloc(sz, GFP_KERNEL);
+		if (!adm_params) {
+			pr_err("%s, adm params memory alloc failed\n",
+				__func__);
+			return -ENOMEM;
+		}
 		adm_params->payload_size =
 				sizeof(struct srs_trumedia_params_PEQ) +
 				sizeof(struct adm_param_data_v5);
@@ -208,6 +233,11 @@
 		sz = sizeof(struct adm_cmd_set_pp_params_inband_v5) +
 			sizeof(struct srs_trumedia_params_HL);
 		adm_params = kzalloc(sz, GFP_KERNEL);
+		if (!adm_params) {
+			pr_err("%s, adm params memory alloc failed\n",
+				__func__);
+			return -ENOMEM;
+		}
 		adm_params->payload_size =
 			sizeof(struct srs_trumedia_params_HL) +
 			sizeof(struct adm_param_data_v5);
@@ -449,6 +479,12 @@
 {
 	uint32_t *payload;
 	int i, index;
+
+	if (data == NULL) {
+		pr_err("%s: data paramter is null\n", __func__);
+		return -EINVAL;
+	}
+
 	payload = data->payload;
 
 	if (data->opcode == RESET_EVENTS) {
@@ -1131,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) {
@@ -1139,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/q6afe.c b/sound/soc/msm/qdsp6v2/q6afe.c
index acb8e70..774a33c 100644
--- a/sound/soc/msm/qdsp6v2/q6afe.c
+++ b/sound/soc/msm/qdsp6v2/q6afe.c
@@ -436,8 +436,9 @@
 	}
 
 	index = q6audio_get_port_index(port_id);
-	if (index < 0) {
-		pr_debug("%s: AFE port index invalid!\n", __func__);
+	if (index < 0 || index > AFE_MAX_PORTS) {
+		pr_debug("%s: AFE port index[%d] invalid!\n",
+				__func__, index);
 		goto done;
 	}
 
@@ -652,8 +653,9 @@
 		goto fail_cmd;
 	}
 	index = q6audio_get_port_index(port_id);
-	if (index < 0) {
-		pr_debug("%s: AFE port index invalid!\n", __func__);
+	if (index < 0 || index > AFE_MAX_PORTS) {
+		pr_debug("%s: AFE port index[%d] invalid!\n",
+				__func__, index);
 		goto fail_cmd;
 	}
 
diff --git a/sound/soc/msm/qdsp6v2/q6asm.c b/sound/soc/msm/qdsp6v2/q6asm.c
index 24f5f3b..4b9d079 100644
--- a/sound/soc/msm/qdsp6v2/q6asm.c
+++ b/sound/soc/msm/qdsp6v2/q6asm.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2014, The Linux Foundation. All rights reserved.
  * Author: Brian Swetland <swetland@google.com>
  *
  * This software is licensed under the terms of the GNU General Public
@@ -81,6 +81,7 @@
 static int q6asm_map_channels(u8 *channel_mapping, uint32_t channels);
 void *q6asm_mmap_apr_reg(void);
 
+static int q6asm_is_valid_session(struct apr_client_data *data, void *priv);
 
 /* for ASM custom topology */
 static struct audio_buffer common_buf[2];
@@ -132,6 +133,10 @@
 static ssize_t audio_output_latency_dbgfs_read(struct file *file,
 				char __user *buf, size_t count, loff_t *ppos)
 {
+	if (out_buffer == NULL) {
+		pr_err("%s: out_buffer is null\n", __func__);
+		return 0;
+	}
 	snprintf(out_buffer, OUT_BUFFER_SIZE, "%ld,%ld,%ld,%ld,%ld,%ld,",\
 		out_cold_tv.tv_sec, out_cold_tv.tv_usec, out_warm_tv.tv_sec,\
 		out_warm_tv.tv_usec, out_cont_tv.tv_sec, out_cont_tv.tv_usec);
@@ -177,6 +182,10 @@
 static ssize_t audio_input_latency_dbgfs_read(struct file *file,
 				char __user *buf, size_t count, loff_t *ppos)
 {
+	if (in_buffer == NULL) {
+		pr_err("%s: in_buffer is null\n", __func__);
+		return 0;
+	}
 	snprintf(in_buffer, IN_BUFFER_SIZE, "%ld,%ld,",\
 				in_cont_tv.tv_sec, in_cont_tv.tv_usec);
 	return  simple_read_from_buffer(buf, IN_BUFFER_SIZE, ppos,
@@ -292,17 +301,38 @@
 static void config_debug_fs_init(void)
 {
 	out_buffer = kmalloc(OUT_BUFFER_SIZE, GFP_KERNEL);
+	if (out_buffer == NULL) {
+		pr_err("%s: kmalloc() for out_buffer failed\n", __func__);
+		goto outbuf_fail;
+	}
+	in_buffer = kmalloc(IN_BUFFER_SIZE, GFP_KERNEL);
+	if (in_buffer == NULL) {
+		pr_err("%s: kmalloc() for in_buffer failed\n", __func__);
+		goto inbuf_fail;
+	}
 	out_dentry = debugfs_create_file("audio_out_latency_measurement_node",\
 				S_IRUGO | S_IWUSR | S_IWGRP,\
 				NULL, NULL, &audio_output_latency_debug_fops);
-	if (IS_ERR(out_dentry))
-		pr_err("debugfs_create_file failed\n");
-	in_buffer = kmalloc(IN_BUFFER_SIZE, GFP_KERNEL);
+	if (IS_ERR(out_dentry)) {
+		pr_err("%s: debugfs_create_file failed\n", __func__);
+		goto file_fail;
+	}
 	in_dentry = debugfs_create_file("audio_in_latency_measurement_node",\
 				S_IRUGO | S_IWUSR | S_IWGRP,\
 				NULL, NULL, &audio_input_latency_debug_fops);
-	if (IS_ERR(in_dentry))
-		pr_err("debugfs_create_file failed\n");
+	if (IS_ERR(in_dentry)) {
+		pr_err("%s: debugfs_create_file failed\n", __func__);
+		goto file_fail;
+	}
+	return;
+file_fail:
+	kfree(in_buffer);
+inbuf_fail:
+	kfree(out_buffer);
+outbuf_fail:
+	in_buffer = NULL;
+	out_buffer = NULL;
+	return;
 }
 #else
 static void config_debug_fs_write(struct audio_buffer *ab)
@@ -335,15 +365,12 @@
 static int q6asm_session_alloc(struct audio_client *ac)
 {
 	int n;
-	mutex_lock(&session_lock);
 	for (n = 1; n <= SESSION_MAX; n++) {
 		if (!session[n]) {
 			session[n] = ac;
-			mutex_unlock(&session_lock);
 			return n;
 		}
 	}
-	mutex_unlock(&session_lock);
 	return -ENOMEM;
 }
 
@@ -351,9 +378,7 @@
 {
 	pr_debug("%s: sessionid[%d]\n", __func__, ac->session);
 	rtac_remove_popp_from_adm_devices(ac->session);
-	mutex_lock(&session_lock);
 	session[ac->session] = 0;
-	mutex_unlock(&session_lock);
 	ac->session = 0;
 	ac->perf_mode = LEGACY_PCM_MODE;
 	ac->fptr_cache_ops = NULL;
@@ -368,67 +393,59 @@
 	struct list_head		*ptr, *next;
 	int				result;
 	int				size = 4096;
+
+	if (!set_custom_topology)
+		return;
+
 	get_asm_custom_topology(&cal_block);
 	if (cal_block.cal_size == 0) {
-		pr_debug("%s: no cal to send addr= 0x%x\n",
-				__func__, cal_block.cal_paddr);
-		goto done;
+		pr_debug("%s: no cal to send addr= 0x%pa\n",
+				__func__, &cal_block.cal_paddr);
+		return;
 	}
 
-	if (set_custom_topology) {
-		if (common_client.mmap_apr == NULL) {
-			common_client.mmap_apr = q6asm_mmap_apr_reg();
-			common_client.apr = common_client.mmap_apr;
-			if (common_client.mmap_apr == NULL) {
-				pr_err("%s: q6asm_mmap_apr_reg failed\n",
-					__func__);
-				result = -EPERM;
-				goto done;
-			}
-		}
-		/* Only call this once */
-		set_custom_topology = 0;
+	common_client.mmap_apr = q6asm_mmap_apr_reg();
+	common_client.apr = common_client.mmap_apr;
+	if (common_client.mmap_apr == NULL) {
+		pr_err("%s: q6asm_mmap_apr_reg failed\n",
+			__func__);
+		result = -EPERM;
+		goto mmap_fail;
+	}
+	/* Only call this once */
+	set_custom_topology = 0;
 
-		/* Use first asm buf to map memory */
-		if (common_client.port[IN].buf == NULL) {
-			pr_err("%s: common buf is NULL\n",
-				__func__);
-			goto done;
-		}
-		common_client.port[IN].buf->phys = cal_block.cal_paddr;
+	/* Use first asm buf to map memory */
+	if (common_client.port[IN].buf == NULL) {
+		pr_err("%s: common buf is NULL\n",
+			__func__);
+		goto err_map;
+	}
+	common_client.port[IN].buf->phys = cal_block.cal_paddr;
 
-		result = q6asm_memory_map_regions(&common_client,
-							IN, size, 1, 1);
-		if (result < 0) {
-			pr_err("%s: mmap did not work! addr = 0x%x, size = %d\n",
-				__func__, cal_block.cal_paddr,
-				cal_block.cal_size);
-			goto done;
-		}
+	result = q6asm_memory_map_regions(&common_client,
+						IN, size, 1, 1);
+	if (result < 0) {
+		pr_err("%s: mmap did not work! addr = 0x%pa, size = %zd\n",
+			__func__, &cal_block.cal_paddr,
+			cal_block.cal_size);
+		goto err_map;
+	}
 
-		list_for_each_safe(ptr, next,
-				&common_client.port[IN].mem_map_handle) {
-			buf_node = list_entry(ptr, struct asm_buffer_node,
-						list);
-			if (buf_node->buf_addr_lsw == cal_block.cal_paddr) {
-				topology_map_handle =  buf_node->mmap_hdl;
-				break;
-			}
-		}
-
-		result = q6asm_mmap_apr_dereg();
-		if (result < 0) {
-			pr_err("%s: q6asm_mmap_apr_dereg failed, err %d\n",
-				__func__, result);
-		} else {
-			common_client.mmap_apr = NULL;
+	list_for_each_safe(ptr, next,
+			&common_client.port[IN].mem_map_handle) {
+		buf_node = list_entry(ptr, struct asm_buffer_node,
+					list);
+		if (buf_node->buf_addr_lsw == cal_block.cal_paddr) {
+			topology_map_handle =  buf_node->mmap_hdl;
+			break;
 		}
 	}
 
 	q6asm_add_hdr_custom_topology(ac, &asm_top.hdr,
 				      APR_PKT_SIZE(APR_HDR_SIZE,
 					sizeof(asm_top)), TRUE);
-
+	atomic_set(&ac->cmd_state, 1);
 	asm_top.hdr.opcode = ASM_CMD_ADD_TOPOLOGIES;
 	asm_top.payload_addr_lsw = cal_block.cal_paddr;
 	asm_top.payload_addr_msw = 0;
@@ -443,7 +460,7 @@
 	if (result < 0) {
 		pr_err("%s: Set topologies failed payload = 0x%x\n",
 			__func__, cal_block.cal_paddr);
-		goto done;
+		goto err_unmap;
 	}
 
 	result = wait_event_timeout(ac->cmd_wait,
@@ -451,10 +468,15 @@
 	if (!result) {
 		pr_err("%s: Set topologies failed after timedout payload = 0x%x\n",
 			__func__, cal_block.cal_paddr);
-		goto done;
+		goto err_unmap;
 	}
-
-done:
+	return;
+err_unmap:
+	q6asm_memory_unmap_regions(ac, IN);
+err_map:
+	q6asm_mmap_apr_dereg();
+	set_custom_topology = 1;
+mmap_fail:
 	return;
 }
 
@@ -654,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;
@@ -701,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;
 	}
@@ -724,6 +751,9 @@
 	struct audio_port_data *port;
 	if (!ac || !ac->session)
 		return;
+
+	mutex_lock(&session_lock);
+
 	pr_debug("%s: Session id %d\n", __func__, ac->session);
 	if (ac->io_mode & SYNC_IO_MODE) {
 		for (loopcnt = 0; loopcnt <= OUT; loopcnt++) {
@@ -740,6 +770,7 @@
 	apr_deregister(ac->apr);
 	ac->apr = NULL;
 	ac->mmap_apr = NULL;
+	rtac_set_asm_handle(ac->session, ac->apr);
 	q6asm_session_free(ac);
 	q6asm_mmap_apr_dereg();
 
@@ -748,6 +779,8 @@
 /*done:*/
 	kfree(ac);
 	ac = NULL;
+	mutex_unlock(&session_lock);
+
 	return;
 }
 
@@ -804,15 +837,21 @@
 	ac = kzalloc(sizeof(struct audio_client), GFP_KERNEL);
 	if (!ac)
 		return NULL;
+
+	mutex_lock(&session_lock);
 	n = q6asm_session_alloc(ac);
-	if (n <= 0)
+	if (n <= 0) {
+		mutex_unlock(&session_lock);
 		goto fail_session;
+	}
 	ac->session = n;
 	ac->cb = cb;
 	ac->priv = priv;
 	ac->io_mode = SYNC_IO_MODE;
 	ac->perf_mode = LEGACY_PCM_MODE;
 	ac->fptr_cache_ops = NULL;
+	/* DSP expects stream id from 1 */
+	ac->stream_id = 1;
 	ac->apr = apr_register("ADSP", "ASM", \
 				(apr_fn)q6asm_callback,\
 				((ac->session) << 8 | 0x0001),\
@@ -820,7 +859,8 @@
 
 	if (ac->apr == NULL) {
 		pr_err("%s Registration with APR failed\n", __func__);
-			goto fail;
+		mutex_unlock(&session_lock);
+		goto fail_apr1;
 	}
 	ac->apr2 = apr_register("ADSP", "ASM", \
 				(apr_fn)q6asm_callback,\
@@ -829,14 +869,18 @@
 
 	if (ac->apr2 == NULL) {
 		pr_err("%s Registration with APR-2 failed\n", __func__);
-			goto fail;
+		mutex_unlock(&session_lock);
+		goto fail_apr2;
 	}
+
 	rtac_set_asm_handle(n, ac->apr);
 
 	pr_debug("%s Registering the common port with APR\n", __func__);
 	ac->mmap_apr = q6asm_mmap_apr_reg();
-	if (ac->mmap_apr == NULL)
-		goto fail;
+	if (ac->mmap_apr == NULL) {
+		mutex_unlock(&session_lock);
+		goto fail_mmap;
+	}
 
 	init_waitqueue_head(&ac->cmd_wait);
 	init_waitqueue_head(&ac->time_wait);
@@ -856,10 +900,15 @@
 
 	pr_debug("%s: session[%d]\n", __func__, ac->session);
 
+	mutex_unlock(&session_lock);
+
 	return ac;
-fail:
-	q6asm_audio_client_free(ac);
-	return NULL;
+fail_mmap:
+	apr_deregister(ac->apr2);
+fail_apr2:
+	apr_deregister(ac->apr);
+fail_apr1:
+	q6asm_session_free(ac);
 fail_session:
 	kfree(ac);
 	return NULL;
@@ -1056,8 +1105,11 @@
 {
 	uint32_t sid = 0;
 	uint32_t dir = 0;
+	uint32_t i = IN;
 	uint32_t *payload;
 	unsigned long dsp_flags;
+	struct asm_buffer_node *buf_node = NULL;
+	struct list_head *ptr, *next;
 
 	struct audio_client *ac = NULL;
 	struct audio_port_data *port;
@@ -1070,13 +1122,34 @@
 	payload = data->payload;
 
 	if (data->opcode == RESET_EVENTS) {
+		struct audio_client *ac_mmap = (struct audio_client *)priv;
+		if (ac_mmap == NULL) {
+			pr_err("%s ac or priv NULL\n", __func__);
+			return -EINVAL;
+		}
 		pr_debug("%s: Reset event is received: %d %d apr[%p]\n",
 				__func__,
 				data->reset_event,
 				data->reset_proc,
 				this_mmap.apr);
+		atomic_set(&this_mmap.ref_cnt, 0);
 		apr_reset(this_mmap.apr);
 		this_mmap.apr = NULL;
+		ac_mmap->mmap_apr = NULL;
+		for (; i <= OUT; i++) {
+			list_for_each_safe(ptr, next,
+				&common_client.port[i].mem_map_handle) {
+				buf_node = list_entry(ptr,
+						struct asm_buffer_node,
+						list);
+				if (buf_node->buf_addr_lsw ==
+				common_client.port[i].buf->phys) {
+					list_del(&buf_node->list);
+					kfree(buf_node);
+				}
+			}
+			pr_debug("%s:Clearing custom topology\n", __func__);
+		}
 		reset_custom_topology_flags();
 		set_custom_topology = 1;
 		topology_map_handle = 0;
@@ -1103,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)) {
@@ -1186,6 +1266,7 @@
 	unsigned long dsp_flags;
 	uint32_t *payload;
 	uint32_t wakeup_flag = 1;
+	int32_t  ret = 0;
 
 
 	if ((ac == NULL) || (data == NULL)) {
@@ -1209,6 +1290,9 @@
 	}
 
 	if (data->opcode == RESET_EVENTS) {
+		if(ac->apr == NULL) {
+		    ac->apr = ac->apr2;
+		}
 		pr_debug("q6asm_callback: Reset event is received: %d %d apr[%p]\n",
 				data->reset_event, data->reset_proc, ac->apr);
 			if (ac->cb)
@@ -1249,11 +1333,10 @@
 		case ASM_SESSION_CMD_REGISTER_FORX_OVERFLOW_EVENTS:
 		case ASM_STREAM_CMD_FLUSH_READBUFS:
 		pr_debug("%s:Payload = [0x%x]\n", __func__, payload[0]);
-		if (token != ac->session) {
-			pr_err("%s:Invalid session[%d] rxed expected[%d]",
-					__func__, token, ac->session);
-			return -EINVAL;
-		}
+		ret = q6asm_is_valid_session(data, priv);
+		if (ret != 0)
+			return ret;
+
 		case ASM_STREAM_CMD_OPEN_READ_V3:
 		case ASM_STREAM_CMD_OPEN_WRITE_V3:
 		case ASM_STREAM_CMD_OPEN_READWRITE_V2:
@@ -1560,11 +1643,10 @@
 	hdr->src_domain = APR_DOMAIN_APPS;
 	hdr->dest_svc = APR_SVC_ASM;
 	hdr->dest_domain = APR_DOMAIN_ADSP;
-	hdr->src_port = ((ac->session << 8) & 0xFF00) | (stream_id+1);
-	hdr->dest_port = ((ac->session << 8) & 0xFF00) | (stream_id+1);
+	hdr->src_port = ((ac->session << 8) & 0xFF00) | (stream_id);
+	hdr->dest_port = ((ac->session << 8) & 0xFF00) | (stream_id);
 	if (cmd_flg) {
 		hdr->token = ac->session;
-		atomic_set(&ac->cmd_state, 1);
 	}
 	hdr->pkt_size  = pkt_size;
 	mutex_unlock(&ac->cmd_lock);
@@ -1601,11 +1683,10 @@
 	hdr->src_domain = APR_DOMAIN_APPS;
 	hdr->dest_svc = APR_SVC_ASM;
 	hdr->dest_domain = APR_DOMAIN_ADSP;
-	hdr->src_port = ((ac->session << 8) & 0xFF00) | (stream_id+1);
-	hdr->dest_port = ((ac->session << 8) & 0xFF00) | (stream_id+1);
+	hdr->src_port = ((ac->session << 8) & 0xFF00) | (stream_id);
+	hdr->dest_port = ((ac->session << 8) & 0xFF00) | (stream_id);
 	if (cmd_flg) {
 		hdr->token = ac->session;
-		atomic_set(&ac->cmd_state, 1);
 	}
 	hdr->pkt_size  = pkt_size;
 	return;
@@ -1649,7 +1730,6 @@
 	hdr->dest_port = 0;
 	if (cmd_flg) {
 		hdr->token = ((ac->session << 8) | 0x0001) ;
-		atomic_set(&ac->cmd_state, 1);
 	}
 	hdr->pkt_size  = pkt_size;
 	mutex_unlock(&ac->cmd_lock);
@@ -1666,7 +1746,6 @@
 	hdr->dest_port = 0;
 	if (cmd_flg) {
 		hdr->token = token;
-		atomic_set(&ac->cmd_state, 1);
 	}
 	hdr->pkt_size  = pkt_size;
 	return;
@@ -1686,6 +1765,7 @@
 	pr_debug("%s:session[%d]", __func__, ac->session);
 
 	q6asm_add_hdr(ac, &open.hdr, sizeof(open), TRUE);
+	atomic_set(&ac->cmd_state, 1);
 	open.hdr.opcode = ASM_STREAM_CMD_OPEN_READ_V3;
 	/* Stream prio : High, provide meta info with encoded frames */
 	open.src_endpointype = ASM_END_POINT_DEVICE_MATRIX;
@@ -1779,7 +1859,18 @@
 		format);
 
 	q6asm_stream_add_hdr(ac, &open.hdr, sizeof(open), TRUE, stream_id);
+	atomic_set(&ac->cmd_state, 1);
+	/*
+	 * Updated the token field with stream/session for compressed playback
+	 * Platform driver must know the the stream with which the command is
+	 * associated
+	 */
+	if (ac->io_mode & COMPRESSED_STREAM_IO)
+		open.hdr.token = ((ac->session << 8) & 0xFFFF00) |
+				 (stream_id & 0xFF);
 
+	pr_debug("%s: token = 0x%x, stream_id  %d, session 0x%x\n",
+		 __func__, open.hdr.token, stream_id, ac->session);
 	open.hdr.opcode = ASM_STREAM_CMD_OPEN_WRITE_V3;
 	open.mode_flags = 0x00;
 	if (ac->perf_mode == ULTRA_LOW_LATENCY_PCM_MODE)
@@ -1886,6 +1977,7 @@
 
 	ac->io_mode |= NT_MODE;
 	q6asm_add_hdr(ac, &open.hdr, sizeof(open), TRUE);
+	atomic_set(&ac->cmd_state, 1);
 	open.hdr.opcode = ASM_STREAM_CMD_OPEN_READWRITE_V2;
 
 	open.mode_flags = BUFFER_META_ENABLE;
@@ -1995,6 +2087,7 @@
 	pr_debug("%s: session[%d]", __func__, ac->session);
 
 	q6asm_add_hdr(ac, &open.hdr, sizeof(open), TRUE);
+	atomic_set(&ac->cmd_state, 1);
 	open.hdr.opcode = ASM_STREAM_CMD_OPEN_LOOPBACK_V2;
 
 	open.mode_flags = 0;
@@ -2037,6 +2130,7 @@
 	}
 	pr_debug("%s session[%d]", __func__, ac->session);
 	q6asm_add_hdr(ac, &run.hdr, sizeof(run), TRUE);
+	atomic_set(&ac->cmd_state, 1);
 
 	run.hdr.opcode = ASM_SESSION_CMD_RUN_V2;
 	run.flags    = flags;
@@ -2074,7 +2168,7 @@
 	}
 	pr_debug("session[%d]", ac->session);
 	q6asm_stream_add_hdr_async(ac, &run.hdr, sizeof(run), TRUE, stream_id);
-
+	atomic_set(&ac->cmd_state, 1);
 	run.hdr.opcode = ASM_SESSION_CMD_RUN_V2;
 	run.flags    = flags;
 	run.time_lsw = lsw_ts;
@@ -2116,6 +2210,7 @@
 		sample_rate, channels, bit_rate, mode, format);
 
 	q6asm_add_hdr(ac, &enc_cfg.hdr, sizeof(enc_cfg), TRUE);
+	atomic_set(&ac->cmd_state, 1);
 
 	enc_cfg.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
 	enc_cfg.encdec.param_id = ASM_PARAM_ID_ENCDEC_ENC_CFG_BLK_V2;
@@ -2156,6 +2251,7 @@
 	pr_debug("%s: Session %d, num_channels = %d\n",
 			 __func__, ac->session, num_channels);
 	q6asm_add_hdr(ac, &chan_map.hdr, sizeof(chan_map), TRUE);
+	atomic_set(&ac->cmd_state, 1);
 	chan_map.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
 	chan_map.encdec.param_id = ASM_PARAM_ID_DEC_OUTPUT_CHAN_MAP;
 	chan_map.encdec.param_size = sizeof(struct asm_dec_out_chan_map_param) -
@@ -2200,6 +2296,7 @@
 			 ac->session, rate, channels);
 
 	q6asm_add_hdr(ac, &enc_cfg.hdr, sizeof(enc_cfg), TRUE);
+	atomic_set(&ac->cmd_state, 1);
 	enc_cfg.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
 	enc_cfg.encdec.param_id = ASM_PARAM_ID_ENCDEC_ENC_CFG_BLK_V2;
 	enc_cfg.encdec.param_size = sizeof(enc_cfg) - sizeof(enc_cfg.hdr) -
@@ -2261,7 +2358,7 @@
 			 ac->session, rate, channels);
 
 	q6asm_add_hdr(ac, &enc_cfg.hdr, sizeof(enc_cfg), TRUE);
-
+	atomic_set(&ac->cmd_state, 1);
 	enc_cfg.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
 	enc_cfg.encdec.param_id = ASM_PARAM_ID_ENCDEC_ENC_CFG_BLK_V2;
 	enc_cfg.encdec.param_size = sizeof(enc_cfg) - sizeof(enc_cfg.hdr) -
@@ -2360,6 +2457,7 @@
 	pr_debug("%s: Session %d\n", __func__, ac->session);
 
 	q6asm_add_hdr(ac, &sbrps.hdr, sizeof(sbrps), TRUE);
+	atomic_set(&ac->cmd_state, 1);
 
 	sbrps.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
 	sbrps.encdec.param_id = ASM_PARAM_ID_AAC_SBR_PS_FLAG;
@@ -2401,6 +2499,7 @@
 			 __func__, ac->session, sce_left, sce_right);
 
 	q6asm_add_hdr(ac, &dual_mono.hdr, sizeof(dual_mono), TRUE);
+	atomic_set(&ac->cmd_state, 1);
 
 	dual_mono.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
 	dual_mono.encdec.param_id = ASM_PARAM_ID_AAC_DUAL_MONO_MAPPING;
@@ -2432,8 +2531,36 @@
 /* Support for selecting stereo mixing coefficients for B family not done */
 int q6asm_cfg_aac_sel_mix_coef(struct audio_client *ac, uint32_t mix_coeff)
 {
-	/* To Be Done */
+	struct asm_aac_stereo_mix_coeff_selection_param_v2 aac_mix_coeff;
+	int rc = 0;
+
+	q6asm_add_hdr(ac, &aac_mix_coeff.hdr, sizeof(aac_mix_coeff), TRUE);
+	atomic_set(&ac->cmd_state, 1);
+	aac_mix_coeff.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
+	aac_mix_coeff.param_id =
+		ASM_PARAM_ID_AAC_STEREO_MIX_COEFF_SELECTION_FLAG_V2;
+	aac_mix_coeff.param_size =
+		sizeof(struct asm_aac_stereo_mix_coeff_selection_param_v2);
+	aac_mix_coeff.aac_stereo_mix_coeff_flag = mix_coeff;
+	pr_debug("%s, mix_coeff = %u", __func__, mix_coeff);
+	rc = apr_send_pkt(ac->apr, (uint32_t *) &aac_mix_coeff);
+	if (rc < 0) {
+		pr_err("%s:Command opcode[0x%x]paramid[0x%x] failed\n",
+			__func__, ASM_STREAM_CMD_SET_ENCDEC_PARAM,
+			ASM_PARAM_ID_AAC_STEREO_MIX_COEFF_SELECTION_FLAG_V2);
+		goto fail_cmd;
+	}
+	rc = wait_event_timeout(ac->cmd_wait,
+		(atomic_read(&ac->cmd_state) == 0), 5*HZ);
+	if (!rc) {
+		pr_err("%s:timeout opcode[0x%x]\n",
+			__func__, aac_mix_coeff.hdr.opcode);
+		rc = -ETIMEDOUT;
+		goto fail_cmd;
+	}
 	return 0;
+fail_cmd:
+	return rc;
 }
 
 int q6asm_enc_cfg_blk_qcelp(struct audio_client *ac, uint32_t frames_per_buf,
@@ -2449,6 +2576,7 @@
 		reduced_rate_level, rate_modulation_cmd);
 
 	q6asm_add_hdr(ac, &enc_cfg.hdr, sizeof(enc_cfg), TRUE);
+	atomic_set(&ac->cmd_state, 1);
 	enc_cfg.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
 	enc_cfg.encdec.param_id = ASM_PARAM_ID_ENCDEC_ENC_CFG_BLK_V2;
 	enc_cfg.encdec.param_size = sizeof(struct asm_v13k_enc_cfg) -
@@ -2490,6 +2618,7 @@
 		frames_per_buf,	min_rate, max_rate, rate_modulation_cmd);
 
 	q6asm_add_hdr(ac, &enc_cfg.hdr, sizeof(enc_cfg), TRUE);
+	atomic_set(&ac->cmd_state, 1);
 	enc_cfg.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
 	enc_cfg.encdec.param_id = ASM_PARAM_ID_ENCDEC_ENC_CFG_BLK_V2;
 	enc_cfg.encdec.param_size = sizeof(struct asm_evrc_enc_cfg) -
@@ -2529,6 +2658,7 @@
 		__func__, ac->session, frames_per_buf, band_mode, dtx_enable);
 
 	q6asm_add_hdr(ac, &enc_cfg.hdr, sizeof(enc_cfg), TRUE);
+	atomic_set(&ac->cmd_state, 1);
 	enc_cfg.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
 	enc_cfg.encdec.param_id = ASM_PARAM_ID_ENCDEC_ENC_CFG_BLK_V2;
 	enc_cfg.encdec.param_size = sizeof(struct asm_amrnb_enc_cfg) -
@@ -2566,6 +2696,7 @@
 		__func__, ac->session, frames_per_buf, band_mode, dtx_enable);
 
 	q6asm_add_hdr(ac, &enc_cfg.hdr, sizeof(enc_cfg), TRUE);
+	atomic_set(&ac->cmd_state, 1);
 	enc_cfg.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
 	enc_cfg.encdec.param_id = ASM_PARAM_ID_ENCDEC_ENC_CFG_BLK_V2;
 	enc_cfg.encdec.param_size = sizeof(struct asm_amrwb_enc_cfg) -
@@ -2606,6 +2737,7 @@
 		channels);
 
 	q6asm_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE);
+	atomic_set(&ac->cmd_state, 1);
 
 	fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
 	fmt.fmt_blk.fmt_blk_size = sizeof(fmt) - sizeof(fmt.hdr) -
@@ -2666,6 +2798,7 @@
 		channels);
 
 	q6asm_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE);
+	atomic_set(&ac->cmd_state, 1);
 
 	fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
 	fmt.fmt_blk.fmt_blk_size = sizeof(fmt) - sizeof(fmt.hdr) -
@@ -2734,7 +2867,18 @@
 		cfg->sample_rate, cfg->ch_cfg);
 
 	q6asm_stream_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE, stream_id);
+	atomic_set(&ac->cmd_state, 1);
+	/*
+	 * Updated the token field with stream/session for compressed playback
+	 * Platform driver must know the the stream with which the command is
+	 * associated
+	 */
+	if (ac->io_mode & COMPRESSED_STREAM_IO)
+		fmt.hdr.token = ((ac->session << 8) & 0xFFFF00) |
+				(stream_id & 0xFF);
 
+	pr_debug("%s: token = 0x%x, stream_id  %d, session 0x%x\n",
+		  __func__, fmt.hdr.token, stream_id, ac->session);
 	fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
 	fmt.fmt_blk.fmt_blk_size = sizeof(fmt) - sizeof(fmt.hdr) -
 					sizeof(fmt.fmt_blk);
@@ -2799,6 +2943,7 @@
 		wma_cfg->ch_mask, wma_cfg->encode_opt);
 
 	q6asm_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE);
+	atomic_set(&ac->cmd_state, 1);
 
 	fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
 	fmt.fmtblk.fmt_blk_size = sizeof(fmt) - sizeof(fmt.hdr) -
@@ -2844,6 +2989,7 @@
 		wmapro_cfg->adv_encode_opt, wmapro_cfg->adv_encode_opt2);
 
 	q6asm_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE);
+	atomic_set(&ac->cmd_state, 1);
 
 	fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
 	fmt.fmtblk.fmt_blk_size = sizeof(fmt) - sizeof(fmt.hdr) -
@@ -2891,6 +3037,7 @@
 		cfg->num_channels);
 
 	q6asm_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE);
+	atomic_set(&ac->cmd_state, 1);
 
 	fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
 	fmt.fmtblk.fmt_blk_size = sizeof(fmt) - sizeof(fmt.hdr) -
@@ -2922,6 +3069,7 @@
 	pr_debug("%s: session[%d]param_id[%d]param_value[%d]", __func__,
 			ac->session, param_id, param_value);
 	q6asm_add_hdr(ac, &ddp_cfg.hdr, sizeof(ddp_cfg), TRUE);
+	atomic_set(&ac->cmd_state, 1);
 	ddp_cfg.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
 	ddp_cfg.encdec.param_id = param_id;
 	ddp_cfg.encdec.param_size = sizeof(struct asm_dec_ddp_endp_param_v2) -
@@ -2982,6 +3130,7 @@
 							mmap_region_cmd;
 	q6asm_add_mmaphdr(ac, &mmap_regions->hdr, cmd_size,
 			TRUE, ((ac->session << 8) | dir));
+	atomic_set(&ac->cmd_state, 1);
 	mmap_regions->hdr.opcode = ASM_CMD_SHARED_MEM_MAP_REGIONS;
 	mmap_regions->mem_pool_id = ADSP_MEMORY_MAP_SHMEM8_4K_POOL;
 	mmap_regions->num_regions = bufcnt & 0x00ff;
@@ -3045,8 +3194,9 @@
 	q6asm_add_mmaphdr(ac, &mem_unmap.hdr,
 			sizeof(struct avs_cmd_shared_mem_unmap_regions),
 			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);
@@ -3058,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",
@@ -3069,10 +3225,19 @@
 	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;
+fail_cmd:
 	list_for_each_safe(ptr, next, &ac->port[dir].mem_map_handle) {
 		buf_node = list_entry(ptr, struct asm_buffer_node,
 						list);
@@ -3082,9 +3247,6 @@
 			break;
 		}
 	}
-
-	rc = 0;
-fail_cmd:
 	return rc;
 }
 
@@ -3143,6 +3305,7 @@
 							mmap_region_cmd;
 	q6asm_add_mmaphdr(ac, &mmap_regions->hdr, cmd_size, TRUE,
 					((ac->session << 8) | dir));
+	atomic_set(&ac->cmd_state, 1);
 	pr_debug("mmap_region=0x%p token=0x%x\n",
 		mmap_regions, ((ac->session << 8) | dir));
 
@@ -3224,9 +3387,11 @@
 	cmd_size = sizeof(struct avs_cmd_shared_mem_unmap_regions);
 	q6asm_add_mmaphdr(ac, &mem_unmap.hdr, cmd_size,
 			TRUE, ((ac->session << 8) | dir));
+	atomic_set(&ac->cmd_state, 1);
 	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);
@@ -3239,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",
@@ -3249,9 +3420,19 @@
 	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;
+
+fail_cmd:
 	list_for_each_safe(ptr, next, &ac->port[dir].mem_map_handle) {
 		buf_node = list_entry(ptr, struct asm_buffer_node,
 						list);
@@ -3261,9 +3442,6 @@
 			break;
 		}
 	}
-	rc = 0;
-
-fail_cmd:
 	return rc;
 }
 
@@ -3281,6 +3459,7 @@
 
 	sz = sizeof(struct asm_volume_ctrl_lr_chan_gain);
 	q6asm_add_hdr_async(ac, &lrgain.hdr, sz, TRUE);
+	atomic_set(&ac->cmd_state, 1);
 	lrgain.hdr.opcode = ASM_STREAM_CMD_SET_PP_PARAMS_V2;
 	lrgain.param.data_payload_addr_lsw = 0;
 	lrgain.param.data_payload_addr_msw = 0;
@@ -3329,6 +3508,7 @@
 
 	sz = sizeof(struct asm_volume_ctrl_mute_config);
 	q6asm_add_hdr_async(ac, &mute.hdr, sz, TRUE);
+	atomic_set(&ac->cmd_state, 1);
 	mute.hdr.opcode = ASM_STREAM_CMD_SET_PP_PARAMS_V2;
 	mute.param.data_payload_addr_lsw = 0;
 	mute.param.data_payload_addr_msw = 0;
@@ -3376,11 +3556,10 @@
 
 	sz = sizeof(struct asm_volume_ctrl_master_gain);
 	q6asm_add_hdr_async(ac, &vol.hdr, sz, TRUE);
+	atomic_set(&ac->cmd_state, 1);
 	vol.hdr.opcode = ASM_STREAM_CMD_SET_PP_PARAMS_V2;
 	vol.param.data_payload_addr_lsw = 0;
 	vol.param.data_payload_addr_msw = 0;
-
-
 	vol.param.mem_map_handle = 0;
 	vol.param.data_payload_size = sizeof(vol) -
 				sizeof(vol.hdr) - sizeof(vol.param);
@@ -3410,6 +3589,7 @@
 fail_cmd:
 	return rc;
 }
+
 int q6asm_set_softpause(struct audio_client *ac,
 			struct asm_softpause_params *pause_param)
 {
@@ -3425,6 +3605,7 @@
 
 	sz = sizeof(struct asm_soft_pause_params);
 	q6asm_add_hdr_async(ac, &softpause.hdr, sz, TRUE);
+	atomic_set(&ac->cmd_state, 1);
 	softpause.hdr.opcode = ASM_STREAM_CMD_SET_PP_PARAMS_V2;
 
 	softpause.param.data_payload_addr_lsw = 0;
@@ -3478,6 +3659,7 @@
 
 	sz = sizeof(struct asm_soft_step_volume_params);
 	q6asm_add_hdr_async(ac, &softvol.hdr, sz, TRUE);
+	atomic_set(&ac->cmd_state, 1);
 	softvol.hdr.opcode = ASM_STREAM_CMD_SET_PP_PARAMS_V2;
 	softvol.param.data_payload_addr_lsw = 0;
 	softvol.param.data_payload_addr_msw = 0;
@@ -3536,6 +3718,7 @@
 	sz = sizeof(struct asm_eq_params);
 	eq_params = (struct msm_audio_eq_stream_config *) eq_p;
 	q6asm_add_hdr(ac, &eq.hdr, sz, TRUE);
+	atomic_set(&ac->cmd_state, 1);
 
 	eq.hdr.opcode = ASM_STREAM_CMD_SET_PP_PARAMS_V2;
 	eq.param.data_payload_addr_lsw = 0;
@@ -3613,6 +3796,11 @@
 		mutex_lock(&port->lock);
 
 		dsp_buf = port->dsp_buf;
+		if (port->buf == NULL) {
+			pr_err("%s buf is NULL\n", __func__);
+			mutex_unlock(&port->lock);
+			return -EINVAL;
+		}
 		ab = &port->buf[dsp_buf];
 
 		pr_debug("%s:session[%d]dsp-buf[%d][%p]cpu_buf[%d][%p]\n",
@@ -3729,14 +3917,15 @@
 	u32 lbuf_addr_lsw;
 	u32 liomode;
 	u32 io_compressed;
+	u32 io_compressed_stream;
 
 	if (!ac || ac->apr == NULL) {
 		pr_err("%s: APR handle NULL\n", __func__);
 		return -EINVAL;
 	}
 
-	q6asm_add_hdr_async(ac, &write.hdr, sizeof(write), FALSE);
-
+	q6asm_stream_add_hdr_async(
+			ac, &write.hdr, sizeof(write), FALSE, ac->stream_id);
 	port = &ac->port[IN];
 	ab = &port->buf[port->dsp_buf];
 
@@ -3750,10 +3939,12 @@
 	write.timestamp_lsw = param->lsw_ts;
 	liomode = (ASYNC_IO_MODE | NT_MODE);
 	io_compressed = (ASYNC_IO_MODE | COMPRESSED_IO);
+	io_compressed_stream = (ASYNC_IO_MODE | COMPRESSED_STREAM_IO);
 
 	if (ac->io_mode == liomode)
 		lbuf_addr_lsw = (write.buf_addr_lsw - 32);
-	else if (ac->io_mode == io_compressed)
+	else if (ac->io_mode == io_compressed ||
+		ac->io_mode == io_compressed_stream)
 		lbuf_addr_lsw = (write.buf_addr_lsw - param->metadata_len);
 	else
 		lbuf_addr_lsw = write.buf_addr_lsw;
@@ -4043,6 +4234,7 @@
 	q6asm_add_hdr_async(ac, &hdr, (sizeof(struct apr_hdr) +
 			    sizeof(struct asm_stream_cmd_set_pp_params_v2) +
 			    params_length), TRUE);
+	atomic_set(&ac->cmd_state, 1);
 	hdr.opcode = ASM_STREAM_CMD_SET_PP_PARAMS_V2;
 	payload_params.data_payload_addr_lsw = 0;
 	payload_params.data_payload_addr_msw = 0;
@@ -4083,6 +4275,17 @@
 		return -EINVAL;
 	}
 	q6asm_stream_add_hdr(ac, &hdr, sizeof(hdr), TRUE, stream_id);
+	atomic_set(&ac->cmd_state, 1);
+	/*
+	 * Updated the token field with stream/session for compressed playback
+	 * Platform driver must know the the stream with which the command is
+	 * associated
+	 */
+	if (ac->io_mode & COMPRESSED_STREAM_IO)
+		hdr.token = ((ac->session << 8) & 0xFFFF00) |
+			    (stream_id & 0xFF);
+	pr_debug("%s: token = 0x%x, stream_id  %d, session 0x%x\n",
+		    __func__, hdr.token, stream_id, ac->session);
 	switch (cmd) {
 	case CMD_PAUSE:
 		pr_debug("%s:CMD_PAUSE\n", __func__);
@@ -4181,6 +4384,18 @@
 		return -EINVAL;
 	}
 	q6asm_stream_add_hdr_async(ac, &hdr, sizeof(hdr), TRUE, stream_id);
+	atomic_set(&ac->cmd_state, 1);
+	/*
+	 * Updated the token field with stream/session for compressed playback
+	 * Platform driver must know the the stream with which the command is
+	 * associated
+	 */
+	if (ac->io_mode & COMPRESSED_STREAM_IO)
+		hdr.token = ((ac->session << 8) & 0xFFFF00) |
+			    (stream_id & 0xFF);
+
+	pr_debug("%s: token = 0x%x, stream_id  %d, session 0x%x\n",
+		      __func__, hdr.token, stream_id, ac->session);
 	switch (cmd) {
 	case CMD_PAUSE:
 		pr_debug("%s:CMD_PAUSE\n", __func__);
@@ -4227,17 +4442,30 @@
 	return __q6asm_cmd_nowait(ac, cmd, stream_id);
 }
 
-int q6asm_send_meta_data(struct audio_client *ac, uint32_t initial_samples,
-		uint32_t trailing_samples)
+int __q6asm_send_meta_data(struct audio_client *ac, uint32_t stream_id,
+			  uint32_t initial_samples, uint32_t trailing_samples)
 {
 	struct asm_data_cmd_remove_silence silence;
 	int rc = 0;
+
 	if (!ac || ac->apr == NULL) {
 		pr_err("APR handle NULL\n");
 		return -EINVAL;
 	}
 	pr_debug("%s session[%d]", __func__, ac->session);
-	q6asm_add_hdr_async(ac, &silence.hdr, sizeof(silence), FALSE);
+	q6asm_stream_add_hdr_async(ac, &silence.hdr, sizeof(silence), FALSE,
+				  stream_id);
+
+	/*
+	 * Updated the token field with stream/session for compressed playback
+	 * Platform driver must know the the stream with which the command is
+	 * associated
+	 */
+	if (ac->io_mode & COMPRESSED_STREAM_IO)
+		silence.hdr.token = ((ac->session << 8) & 0xFFFF00) |
+				    (stream_id & 0xFF);
+	pr_debug("%s: token = 0x%x, stream_id  %d, session 0x%x\n",
+	      __func__, silence.hdr.token, stream_id, ac->session);
 
 	silence.hdr.opcode = ASM_DATA_CMD_REMOVE_INITIAL_SILENCE;
 	silence.num_samples_to_remove    = initial_samples;
@@ -4262,6 +4490,20 @@
 	return -EINVAL;
 }
 
+int q6asm_stream_send_meta_data(struct audio_client *ac, uint32_t stream_id,
+		uint32_t initial_samples, uint32_t trailing_samples)
+{
+	return __q6asm_send_meta_data(ac, stream_id, initial_samples,
+				     trailing_samples);
+}
+
+int q6asm_send_meta_data(struct audio_client *ac, uint32_t initial_samples,
+		uint32_t trailing_samples)
+{
+	return __q6asm_send_meta_data(ac, ac->stream_id, initial_samples,
+				     trailing_samples);
+}
+
 static void q6asm_reset_buf_state(struct audio_client *ac)
 {
 	int cnt = 0;
@@ -4300,6 +4542,7 @@
 	pr_debug("%s:session[%d]enable[%d]\n", __func__,
 						ac->session, enable);
 	q6asm_add_hdr(ac, &tx_overflow.hdr, sizeof(tx_overflow), TRUE);
+	atomic_set(&ac->cmd_state, 1);
 
 	tx_overflow.hdr.opcode = \
 			ASM_SESSION_CMD_REGISTER_FORX_OVERFLOW_EVENTS;
@@ -4365,6 +4608,34 @@
 }
 
 
+static int q6asm_is_valid_session(struct apr_client_data *data, void *priv)
+{
+
+	struct audio_client *ac = (struct audio_client *)priv;
+	uint32_t token = data->token;
+
+	/*
+	 * Some commands for compressed playback has token as session and
+	 * other commands has session|stream. Check for both conditions
+	 * before deciding if the callback was for a invalud session.
+	 */
+	if (ac->io_mode & COMPRESSED_STREAM_IO) {
+		if ((token & 0xFFFFFF00) != ((ac->session << 8) & 0xFFFFFF00)
+						 && (token != ac->session)) {
+			pr_err("%s:Invalid compr session[%d] rxed expected[%d]",
+				 __func__, token, ac->session);
+			return -EINVAL;
+		}
+	} else {
+		if (token != ac->session) {
+			pr_err("%s:Invalid session[%d] rxed expected[%d]",
+				__func__, token, ac->session);
+			return -EINVAL;
+		}
+	}
+	return 0;
+}
+
 static int __init q6asm_init(void)
 {
 	int lcnt;
diff --git a/sound/soc/msm/qdsp6v2/q6core.c b/sound/soc/msm/qdsp6v2/q6core.c
index e9352df..496a5ef 100644
--- a/sound/soc/msm/qdsp6v2/q6core.c
+++ b/sound/soc/msm/qdsp6v2/q6core.c
@@ -41,6 +41,11 @@
 	uint32_t nseg;
 	int i, j;
 
+	if (data == NULL) {
+		pr_err("%s: data argument is null\n", __func__);
+		return -EINVAL;
+	}
+
 	pr_debug("core msg: payload len = %u, apr resp opcode = 0x%X\n",
 		data->payload_size, data->opcode);
 
diff --git a/sound/soc/msm/qdsp6v2/q6lsm.c b/sound/soc/msm/qdsp6v2/q6lsm.c
index 9227b23..61222fe 100644
--- a/sound/soc/msm/qdsp6v2/q6lsm.c
+++ b/sound/soc/msm/qdsp6v2/q6lsm.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2014, Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -35,6 +35,7 @@
 
 #define APR_TIMEOUT	(5 * HZ)
 #define LSM_CAL_SIZE	4096
+#define LSM_ALIGN_BOUNDARY 512
 
 enum {
 	CMD_STATE_CLEARED = 0,
@@ -48,13 +49,11 @@
 	LSM_CONTROL_SESSION = 0x0F,
 };
 
+#define CHECK_SESSION(x) (x < LSM_MIN_SESSION_ID || x > LSM_MAX_SESSION_ID)
 struct lsm_common {
 	void *apr;
 	atomic_t apr_users;
-	uint32_t lsm_cal_addr;
-	uint32_t lsm_cal_size;
-	uint32_t mmap_handle_for_cal;
-	struct lsm_client	common_client;
+	struct lsm_client	common_client[LSM_MAX_SESSION_ID + 1];
 	struct mutex apr_lock;
 };
 
@@ -93,9 +92,9 @@
 	}
 
 	payload = data->payload;
-	pr_debug("%s: Session %d opcode 0x%x token 0x%x payload size %d\n",
-		__func__, client->session,
-		data->opcode, data->token, data->payload_size);
+	pr_debug("%s: Session %d opcode 0x%x token 0x%x payload size %d\n"
+			 "payload [0] = %x\n", __func__, client->session,
+		data->opcode, data->token, data->payload_size, payload[0]);
 
 	if (data->opcode == APR_BASIC_RSP_RESULT) {
 		token = data->token;
@@ -150,13 +149,13 @@
 		}
 	}
 	spin_unlock_irqrestore(&lsm_session_lock, flags);
+	pr_debug("%s: Alloc Session %d", __func__, n);
 	return ret;
 }
 
 static void q6lsm_session_free(struct lsm_client *client)
 {
 	unsigned long flags;
-
 	pr_debug("%s: Freeing session ID %d\n", __func__, client->session);
 	spin_lock_irqsave(&lsm_session_lock, flags);
 	lsm_session[client->session] = LSM_INVALID_SESSION_ID;
@@ -207,13 +206,18 @@
 		kfree(client);
 		return NULL;
 	}
-
-	pr_debug("%s: New client session %d\n", __func__, client->session);
 	client->session = n;
 	client->cb = cb;
 	client->priv = priv;
+	pr_debug("%s:Client session %d\n", __func__, client->session);
+	if (CHECK_SESSION(client->session)) {
+		kfree(client);
+		return NULL;
+	}
+	pr_debug("%s:Client Session %d\n", __func__, client->session);
 	client->apr = apr_register("ADSP", "LSM", q6lsm_callback,
-				   ((client->session) << 8 | 0x0001), client);
+				   ((client->session) << 8 | client->session),
+				   client);
 
 	if (client->apr == NULL) {
 		pr_err("%s: Registration with APR failed\n", __func__);
@@ -239,9 +243,12 @@
 
 void q6lsm_client_free(struct lsm_client *client)
 {
-	if (!client || !client->session)
+	if (!client)
 		return;
-
+	if (CHECK_SESSION(client->session)) {
+		pr_err("%s: Invalid Session %d", __func__, client->session);
+		return;
+	}
 	apr_deregister(client->apr);
 	client->mmap_apr = NULL;
 	q6lsm_session_free(client);
@@ -308,8 +315,8 @@
 	hdr->src_domain = APR_DOMAIN_APPS;
 	hdr->dest_svc = APR_SVC_LSM;
 	hdr->dest_domain = APR_DOMAIN_ADSP;
-	hdr->src_port = ((client->session << 8) & 0xFF00) | 0x01;
-	hdr->dest_port = ((client->session << 8) & 0xFF00) | 0x01;
+	hdr->src_port = ((client->session << 8) & 0xFF00) | client->session;
+	hdr->dest_port = ((client->session << 8) & 0xFF00) | client->session;
 	hdr->pkt_size = pkt_size;
 	if (cmd_flg)
 		hdr->token = client->session;
@@ -331,7 +338,7 @@
 	if (rc)
 		pr_err("%s: Open failed opcode 0x%x, rc %d\n",
 		       __func__, open.hdr.opcode, rc);
-
+	pr_debug("%s: leave %d\n", __func__, rc);
 	return rc;
 }
 
@@ -429,15 +436,15 @@
 
 	q6lsm_add_hdr(client, &cmd.hdr, sizeof(cmd), true);
 	cmd.hdr.opcode = LSM_SESSION_CMD_REGISTER_SOUND_MODEL;
-	cmd.model_addr_lsw = client->sound_model.phys;
-	cmd.model_addr_msw = 0;
+	cmd.model_addr_lsw = lower_32_bits(client->sound_model.phys);
+	cmd.model_addr_msw = upper_32_bits(client->sound_model.phys);
 	cmd.model_size = client->sound_model.size;
 	/* read updated mem_map_handle by q6lsm_mmapcallback */
 	rmb();
 	cmd.mem_map_handle = client->sound_model.mem_map_handle;
 
-	pr_debug("%s: lsw %x, size %d, handle %x\n", __func__,
-		 cmd.model_addr_lsw, cmd.model_size, cmd.mem_map_handle);
+	pr_debug("%s: addr %pa, size %d, handle %x\n", __func__,
+		&client->sound_model.phys, cmd.model_size, cmd.mem_map_handle);
 	rc = q6lsm_apr_send_pkt(client, client->apr, &cmd, true, NULL);
 	if (rc)
 		pr_err("%s: Failed cmd op[0x%x]rc[%d]\n", __func__,
@@ -458,6 +465,8 @@
 		return -EINVAL;
 	}
 	pr_debug("%s: session[%d]", __func__, client->session);
+	if (CHECK_SESSION(client->session))
+		return -EINVAL;
 
 	memset(&cmd, 0, sizeof(cmd));
 	q6lsm_add_hdr(client, &cmd.hdr, sizeof(cmd.hdr), false);
@@ -492,7 +501,7 @@
 }
 
 static int q6lsm_memory_map_regions(struct lsm_client *client,
-				    uint32_t dma_addr_p, uint32_t dma_buf_sz,
+				    dma_addr_t dma_addr_p, uint32_t dma_buf_sz,
 				    uint32_t *mmap_p)
 {
 	struct avs_cmd_shared_mem_map_regions *mmap_regions = NULL;
@@ -502,9 +511,11 @@
 	int rc;
 	int cmd_size = 0;
 
-	pr_debug("%s: dma_addr_p 0x%x, dma_buf_sz %d, mmap_p 0x%p, session %d\n",
-		 __func__, dma_addr_p, dma_buf_sz, mmap_p, client->session);
-
+	pr_debug("%s: dma_addr_p 0x%pa, dma_buf_sz %d, mmap_p 0x%p, session %d\n",
+		__func__, &dma_addr_p, dma_buf_sz, mmap_p,
+		client->session);
+	if (CHECK_SESSION(client->session))
+		return -EINVAL;
 	cmd_size = sizeof(struct avs_cmd_shared_mem_map_regions) +
 		   sizeof(struct avs_shared_map_region_payload);
 
@@ -524,8 +535,8 @@
 		   sizeof(struct avs_cmd_shared_mem_map_regions));
 	mregions = (struct avs_shared_map_region_payload *)payload;
 
-	mregions->shm_addr_lsw = dma_addr_p;
-	mregions->shm_addr_msw = 0;
+	mregions->shm_addr_lsw = lower_32_bits(dma_addr_p);
+	mregions->shm_addr_msw = upper_32_bits(dma_addr_p);
 	mregions->mem_size_bytes = dma_buf_sz;
 
 	rc = q6lsm_apr_send_pkt(client, client->mmap_apr, mmap_region_cmd,
@@ -545,7 +556,8 @@
 	struct avs_cmd_shared_mem_unmap_regions unmap;
 	int rc = 0;
 	int cmd_size = 0;
-
+	if (CHECK_SESSION(client->session))
+		return -EINVAL;
 	cmd_size = sizeof(struct avs_cmd_shared_mem_unmap_regions);
 	q6lsm_add_mmaphdr(client, &unmap.hdr, cmd_size,
 			  true, (client->session << 8));
@@ -569,107 +581,35 @@
 	struct lsm_cmd_set_params params;
 	struct acdb_cal_block lsm_cal;
 
-	pr_debug("%s: enter\n", __func__);
-
+	pr_debug("%s: Session %d\n", __func__, client->session);
+	if (CHECK_SESSION(client->session))
+		return -EINVAL;
 	memset(&lsm_cal, 0, sizeof(lsm_cal));
 	get_lsm_cal(&lsm_cal);
-	if (!lsm_cal.cal_size) {
-		pr_err("%s: Could not get LSM calibration data\n", __func__);
-		rc = -EINVAL;
-		goto bail;
-	}
-
 	/* Cache mmap address, only map once or if new addr */
-	if ((lsm_common.lsm_cal_addr != lsm_cal.cal_paddr) ||
-	    (lsm_cal.cal_size > lsm_common.lsm_cal_size)) {
-		if (lsm_common.lsm_cal_addr != 0) {
-			rc = q6lsm_memory_unmap_regions(client,
-						lsm_common.mmap_handle_for_cal);
-			if (rc)
-				pr_warn("%s: Unmapping %x failed, %d\n",
-					__func__, lsm_common.lsm_cal_addr, rc);
-		}
-
-		rc = q6lsm_memory_map_regions(client, lsm_cal.cal_paddr,
-					      LSM_CAL_SIZE,
-					      &lsm_common.mmap_handle_for_cal);
-		if (rc < 0) {
-			pr_err("%s: Calibration data memory map failed, %d\n",
-			       __func__, rc);
-			goto bail;
-		}
-		lsm_common.lsm_cal_addr = lsm_cal.cal_paddr;
-		lsm_common.lsm_cal_size = LSM_CAL_SIZE;
-		lsm_common.common_client.session = client->session;
-	}
-
+	lsm_common.common_client[client->session].session = client->session;
 	q6lsm_add_hdr(client, &params.hdr, sizeof(params), true);
 	params.hdr.opcode = LSM_SESSION_CMD_SET_PARAMS;
-	params.data_payload_addr_lsw = lsm_cal.cal_paddr;
-	params.data_payload_addr_msw = 0;
-	/* read updated mem_map_handle by q6lsm_mmapcallback */
-	rmb();
-	params.mem_map_handle = lsm_common.mmap_handle_for_cal;
+	params.data_payload_addr_lsw = lower_32_bits(client->lsm_cal_phy_addr);
+	params.data_payload_addr_msw = upper_32_bits(client->lsm_cal_phy_addr);
+	params.mem_map_handle = client->sound_model.mem_map_handle;
 	params.data_payload_size = lsm_cal.cal_size;
-
+	pr_debug("%s: Cal Size = %x", __func__, client->lsm_cal_size);
 	rc = q6lsm_apr_send_pkt(client, client->apr, &params, true, NULL);
 	if (rc)
 		pr_err("%s: Failed set_params opcode 0x%x, rc %d\n",
 		       __func__, params.hdr.opcode, rc);
-bail:
 	return rc;
 }
 
-int q6lsm_unmap_cal_blocks(void)
-{
-	int	result = 0;
-	int	result2 = 0;
-
-	if (lsm_common.mmap_handle_for_cal == 0)
-		goto done;
-
-	if (lsm_common.common_client.mmap_apr == NULL) {
-		lsm_common.common_client.mmap_apr = q6lsm_mmap_apr_reg();
-		if (lsm_common.common_client.mmap_apr == NULL) {
-			pr_err("%s: q6lsm_mmap_apr_reg failed\n",
-				__func__);
-			result = -EPERM;
-			goto done;
-		}
-	}
-
-	result2 = q6lsm_memory_unmap_regions(
-		&lsm_common.common_client,
-		lsm_common.mmap_handle_for_cal);
-	if (result2 < 0) {
-		pr_err("%s: unmap failed, err %d\n",
-			__func__, result2);
-		result = result2;
-	} else {
-		lsm_common.mmap_handle_for_cal = 0;
-	}
-
-	result2 = q6lsm_mmap_apr_dereg();
-	if (result2 < 0) {
-		pr_err("%s: q6lsm_mmap_apr_dereg failed, err %d\n",
-			__func__, result2);
-		result = result2;
-	} else {
-		lsm_common.common_client.mmap_apr = NULL;
-	}
-
-	lsm_common.lsm_cal_addr = 0;
-	lsm_common.lsm_cal_size = 0;
-
-done:
-	return result;
-}
-
 int q6lsm_snd_model_buf_free(struct lsm_client *client)
 {
 	int rc;
 
 	pr_debug("%s: Session id %d\n", __func__, client->session);
+	if (CHECK_SESSION(client->session))
+		return -EINVAL;
+
 	mutex_lock(&client->cmd_lock);
 	rc = q6lsm_memory_unmap_regions(client,
 					client->sound_model.mem_map_handle);
@@ -678,12 +618,16 @@
 
 	if (client->sound_model.data) {
 		ion_unmap_kernel(client->sound_model.client,
-				 client->sound_model.handle);
+						 client->sound_model.handle);
 		ion_free(client->sound_model.client,
-			 client->sound_model.handle);
+				 client->sound_model.handle);
 		ion_client_destroy(client->sound_model.client);
+		client->sound_model.client = NULL;
+		client->sound_model.handle = NULL;
 		client->sound_model.data = NULL;
 		client->sound_model.phys = 0;
+		client->lsm_cal_phy_addr = 0;
+		client->lsm_cal_size = 0;
 	}
 	mutex_unlock(&client->cmd_lock);
 	return rc;
@@ -695,7 +639,7 @@
 	struct lsm_client *client = NULL;
 
 	if (session_id == LSM_CONTROL_SESSION) {
-		client = &lsm_common.common_client;
+		client = &lsm_common.common_client[session_id];
 		goto done;
 	}
 
@@ -724,19 +668,19 @@
 	struct lsm_client *client = NULL;
 
 	if (data->opcode == RESET_EVENTS) {
-		pr_debug("%s: SSR event received 0x%x, event 0x%x, proc 0x%x\n",
-			 __func__, data->opcode, data->reset_event,
-			 data->reset_proc);
-		lsm_common.lsm_cal_addr = 0;
+		sid = (data->token >> 8) & 0x0F;
+		pr_debug("%s: SSR event received 0x%x, event 0x%x,\n"
+			 "proc 0x%x SID 0x%x\n", __func__, data->opcode,
+			 data->reset_event, data->reset_proc, sid);
+		lsm_common.common_client[sid].lsm_cal_phy_addr = 0;
 		return 0;
 	}
 
 	command = payload[0];
 	retcode = payload[1];
-	pr_debug("%s: opcode 0x%x command 0x%x return code 0x%x\n", __func__,
-		 data->opcode, command, retcode);
-
 	sid = (data->token >> 8) & 0x0F;
+	pr_debug("%s: opcode 0x%x command 0x%x return code 0x%x SID 0x%x\n",
+		 __func__, data->opcode, command, retcode, sid);
 	client = q6lsm_get_lsm_client(sid);
 	if (!client) {
 		pr_debug("%s: Session %d already freed\n", __func__, sid);
@@ -774,15 +718,31 @@
 	return 0;
 }
 
-int q6lsm_snd_model_buf_alloc(struct lsm_client *client, uint32_t len)
+int q6lsm_snd_model_buf_alloc(struct lsm_client *client, size_t len)
 {
 	int rc = -EINVAL;
+	struct acdb_cal_block lsm_cal;
+	size_t pad_zero = 0, total_mem = 0;
 
-	if (!client)
+	if (!client || len <= LSM_ALIGN_BOUNDARY)
 		return rc;
-
+	memset(&lsm_cal, 0, sizeof(lsm_cal));
 	mutex_lock(&client->cmd_lock);
+	get_lsm_cal(&lsm_cal);
+	pr_debug("%s:Snd Model len = %d cal size %d", __func__,
+			 len, lsm_cal.cal_size);
+	if (!lsm_cal.cal_paddr) {
+		pr_err("%s: No LSM calibration set for session", __func__);
+		mutex_unlock(&client->cmd_lock);
+		return -EINVAL;
+	}
 	if (!client->sound_model.data) {
+		client->sound_model.size = len;
+		pad_zero = (LSM_ALIGN_BOUNDARY -
+			   (len % LSM_ALIGN_BOUNDARY));
+		total_mem = pad_zero + len + lsm_cal.cal_size;
+		pr_debug("%s: Pad zeros sound model %d Total mem %d\n",
+				 __func__, pad_zero, total_mem);
 		client->sound_model.client =
 		    msm_ion_client_create(UINT_MAX, "lsm_client");
 		if (IS_ERR_OR_NULL(client->sound_model.client)) {
@@ -791,8 +751,8 @@
 			goto fail;
 		}
 		client->sound_model.handle =
-			ion_alloc(client->sound_model.client,
-				  len, SZ_4K, (0x1 << ION_AUDIO_HEAP_ID), 0);
+		ion_alloc(client->sound_model.client,
+			  total_mem, SZ_4K, (0x1 << ION_AUDIO_HEAP_ID), 0);
 		if (IS_ERR_OR_NULL(client->sound_model.handle)) {
 			pr_err("%s: ION memory allocation for AUDIO failed\n",
 			       __func__);
@@ -817,7 +777,13 @@
 			goto fail;
 		}
 		memset(client->sound_model.data, 0, len);
-		client->sound_model.size = len;
+		client->lsm_cal_phy_addr = (pad_zero +
+					    client->sound_model.phys +
+					    client->sound_model.size);
+		client->lsm_cal_size = lsm_cal.cal_size;
+		memcpy((client->sound_model.data + pad_zero +
+			client->sound_model.size),
+			(uint32_t *)lsm_cal.cal_kvaddr, lsm_cal.cal_size);
 	} else {
 		rc = -EBUSY;
 		goto fail;
@@ -825,7 +791,7 @@
 	mutex_unlock(&client->cmd_lock);
 
 	rc = q6lsm_memory_map_regions(client, client->sound_model.phys,
-				      client->sound_model.size,
+				      len,
 				      &client->sound_model.mem_map_handle);
 	if (rc < 0) {
 		pr_err("%s:CMD Memory_map_regions failed\n", __func__);
@@ -882,16 +848,18 @@
 
 static int __init q6lsm_init(void)
 {
+	int i = 0;
 	pr_debug("%s\n", __func__);
 	spin_lock_init(&lsm_session_lock);
 	spin_lock_init(&mmap_lock);
 	mutex_init(&lsm_common.apr_lock);
-
-	lsm_common.common_client.session = LSM_CONTROL_SESSION;
-	init_waitqueue_head(&lsm_common.common_client.cmd_wait);
-	mutex_init(&lsm_common.common_client.cmd_lock);
-	atomic_set(&lsm_common.common_client.cmd_state, CMD_STATE_CLEARED);
-
+	for (; i <= LSM_MAX_SESSION_ID; i++) {
+		lsm_common.common_client[i].session = LSM_CONTROL_SESSION;
+		init_waitqueue_head(&lsm_common.common_client[i].cmd_wait);
+		mutex_init(&lsm_common.common_client[i].cmd_lock);
+		atomic_set(&lsm_common.common_client[i].cmd_state,
+			   CMD_STATE_CLEARED);
+	}
 	return 0;
 }
 
diff --git a/sound/soc/msm/qdsp6v2/q6voice.c b/sound/soc/msm/qdsp6v2/q6voice.c
index c4395c2..1ca9b1a 100644
--- a/sound/soc/msm/qdsp6v2/q6voice.c
+++ b/sound/soc/msm/qdsp6v2/q6voice.c
@@ -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
@@ -29,7 +29,7 @@
 #include "q6voice.h"
 
 
-#define TIMEOUT_MS 200
+#define TIMEOUT_MS 300
 
 
 #define CMD_STATUS_SUCCESS 0
@@ -94,6 +94,8 @@
 static int voice_alloc_oob_mem_table(void);
 static int voice_alloc_and_map_cal_mem(struct voice_data *v);
 static int voice_alloc_and_map_oob_mem(struct voice_data *v);
+static int voc_disable_cvp(uint32_t session_id);
+static int voc_enable_cvp(uint32_t session_id);
 
 static struct voice_data *voice_get_session_by_idx(int idx);
 
@@ -141,6 +143,7 @@
 	case VOLTE_SESSION_VSID:
 	case VOIP_SESSION_VSID:
 	case QCHAT_SESSION_VSID:
+	case VOWLAN_SESSION_VSID:
 	case ALL_SESSION_VSID:
 		ret = true;
 		break;
@@ -234,6 +237,9 @@
 	} else if (session_id ==
 			common.voice[VOC_PATH_QCHAT_PASSIVE].session_id) {
 		session_name = QCHAT_SESSION_NAME;
+	} else if (session_id ==
+			common.voice[VOC_PATH_VOWLAN_PASSIVE].session_id) {
+		session_name = VOWLAN_SESSION_NAME;
 	} else if (session_id == common.voice[VOC_PATH_FULL].session_id) {
 		session_name = VOIP_SESSION_NAME;
 	}
@@ -256,6 +262,9 @@
 		else if (!strncmp(name, "QCHAT session", 13))
 			session_id =
 			common.voice[VOC_PATH_QCHAT_PASSIVE].session_id;
+		else if (!strncmp(name, "VoWLAN session", 14))
+			session_id =
+			common.voice[VOC_PATH_VOWLAN_PASSIVE].session_id;
 		else
 			session_id = common.voice[VOC_PATH_FULL].session_id;
 
@@ -291,6 +300,10 @@
 		v = &common.voice[VOC_PATH_QCHAT_PASSIVE];
 		break;
 
+	case VOWLAN_SESSION_VSID:
+		v = &common.voice[VOC_PATH_VOWLAN_PASSIVE];
+		break;
+
 	case ALL_SESSION_VSID:
 		break;
 
@@ -331,6 +344,10 @@
 		idx = VOC_PATH_QCHAT_PASSIVE;
 		break;
 
+	case VOWLAN_SESSION_VSID:
+		idx = VOC_PATH_VOWLAN_PASSIVE;
+		break;
+
 	case ALL_SESSION_VSID:
 		idx = MAX_VOC_SESSIONS - 1;
 		break;
@@ -375,6 +392,11 @@
 	return (session_id == common.voice[VOC_PATH_QCHAT_PASSIVE].session_id);
 }
 
+static bool is_vowlan_session(u32 session_id)
+{
+	return (session_id == common.voice[VOC_PATH_VOWLAN_PASSIVE].session_id);
+}
+
 static bool is_voc_state_active(int voc_state)
 {
 	if ((voc_state == VOC_RUN) ||
@@ -433,6 +455,7 @@
 	common.voice[VOC_PATH_VOICE2_PASSIVE].session_id = VOICE2_SESSION_VSID;
 	common.voice[VOC_PATH_FULL].session_id = VOIP_SESSION_VSID;
 	common.voice[VOC_PATH_QCHAT_PASSIVE].session_id = QCHAT_SESSION_VSID;
+	common.voice[VOC_PATH_VOWLAN_PASSIVE].session_id = VOWLAN_SESSION_VSID;
 }
 
 static int voice_apr_register(void)
@@ -661,6 +684,10 @@
 				strlcpy(mvm_session_cmd.mvm_session.name,
 				QCHAT_SESSION_VSID_STR,
 				sizeof(mvm_session_cmd.mvm_session.name));
+			} else if (is_vowlan_session(v->session_id)) {
+				strlcpy(mvm_session_cmd.mvm_session.name,
+				VOWLAN_SESSION_VSID_STR,
+				sizeof(mvm_session_cmd.mvm_session.name));
 			} else {
 				strlcpy(mvm_session_cmd.mvm_session.name,
 				"default modem voice",
@@ -753,6 +780,10 @@
 				strlcpy(cvs_session_cmd.cvs_session.name,
 				QCHAT_SESSION_VSID_STR,
 				sizeof(cvs_session_cmd.cvs_session.name));
+			} else if (is_vowlan_session(v->session_id)) {
+				strlcpy(cvs_session_cmd.cvs_session.name,
+				VOWLAN_SESSION_VSID_STR,
+				sizeof(cvs_session_cmd.cvs_session.name));
 			} else {
 			strlcpy(cvs_session_cmd.cvs_session.name,
 				"default modem voice",
@@ -943,6 +974,7 @@
 
 	if (is_voip_session(v->session_id) ||
 	    is_qchat_session(v->session_id) ||
+	    is_volte_session(v->session_id) ||
 	    v->voc_state == VOC_ERROR) {
 		/* Destroy CVS. */
 		pr_debug("%s: CVS destroy session\n", __func__);
@@ -1051,39 +1083,37 @@
 	}
 	mvm_handle = voice_get_mvm_handle(v);
 
-	if (v->tty_mode) {
-		/* send tty mode cmd to mvm */
-		mvm_tty_mode_cmd.hdr.hdr_field = APR_HDR_FIELD(
-						APR_MSG_TYPE_SEQ_CMD,
-						APR_HDR_LEN(APR_HDR_SIZE),
-						APR_PKT_VER);
-		mvm_tty_mode_cmd.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
-						sizeof(mvm_tty_mode_cmd) -
-						APR_HDR_SIZE);
-		pr_debug("%s: pkt size = %d\n",
-			 __func__, mvm_tty_mode_cmd.hdr.pkt_size);
-		mvm_tty_mode_cmd.hdr.src_port =
-				voice_get_idx_for_session(v->session_id);
-		mvm_tty_mode_cmd.hdr.dest_port = mvm_handle;
-		mvm_tty_mode_cmd.hdr.token = 0;
-		mvm_tty_mode_cmd.hdr.opcode = VSS_ISTREAM_CMD_SET_TTY_MODE;
-		mvm_tty_mode_cmd.tty_mode.mode = v->tty_mode;
-		pr_debug("tty mode =%d\n", mvm_tty_mode_cmd.tty_mode.mode);
+	/* send tty mode cmd to mvm */
+	mvm_tty_mode_cmd.hdr.hdr_field = APR_HDR_FIELD(
+					APR_MSG_TYPE_SEQ_CMD,
+					APR_HDR_LEN(APR_HDR_SIZE),
+					APR_PKT_VER);
+	mvm_tty_mode_cmd.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+					sizeof(mvm_tty_mode_cmd) -
+					APR_HDR_SIZE);
+	pr_debug("%s: pkt size = %d\n",
+		 __func__, mvm_tty_mode_cmd.hdr.pkt_size);
+	mvm_tty_mode_cmd.hdr.src_port =
+			voice_get_idx_for_session(v->session_id);
+	mvm_tty_mode_cmd.hdr.dest_port = mvm_handle;
+	mvm_tty_mode_cmd.hdr.token = 0;
+	mvm_tty_mode_cmd.hdr.opcode = VSS_ISTREAM_CMD_SET_TTY_MODE;
+	mvm_tty_mode_cmd.tty_mode.mode = v->tty_mode;
+	pr_debug("tty mode =%d\n", mvm_tty_mode_cmd.tty_mode.mode);
 
-		v->mvm_state = CMD_STATUS_FAIL;
-		ret = apr_send_pkt(apr_mvm, (uint32_t *) &mvm_tty_mode_cmd);
-		if (ret < 0) {
-			pr_err("%s: Error %d sending SET_TTY_MODE\n",
-			       __func__, ret);
-			goto fail;
-		}
-		ret = wait_event_timeout(v->mvm_wait,
-					 (v->mvm_state == CMD_STATUS_SUCCESS),
-					 msecs_to_jiffies(TIMEOUT_MS));
-		if (!ret) {
-			pr_err("%s: wait_event timeout\n", __func__);
-			goto fail;
-		}
+	v->mvm_state = CMD_STATUS_FAIL;
+	ret = apr_send_pkt(apr_mvm, (uint32_t *) &mvm_tty_mode_cmd);
+	if (ret < 0) {
+		pr_err("%s: Error %d sending SET_TTY_MODE\n",
+		       __func__, ret);
+		goto fail;
+	}
+	ret = wait_event_timeout(v->mvm_wait,
+				 (v->mvm_state == CMD_STATUS_SUCCESS),
+				 msecs_to_jiffies(TIMEOUT_MS));
+	if (!ret) {
+		pr_err("%s: wait_event timeout\n", __func__);
+		goto fail;
 	}
 	return 0;
 fail:
@@ -1493,6 +1523,77 @@
 	return ret;
 }
 
+static int voice_config_cvs_vocoder_amr_rate(struct voice_data *v)
+{
+	int ret = 0;
+	void *apr_cvs;
+	u16 cvs_handle;
+	struct cvs_set_amr_enc_rate_cmd cvs_set_amr_rate;
+
+	if (v == NULL) {
+		pr_err("%s: v is NULL\n", __func__);
+
+		ret = -EINVAL;
+		goto done;
+	}
+	apr_cvs = common.apr_q6_cvs;
+
+	if (!apr_cvs) {
+		pr_err("%s: apr_cvs is NULL.\n", __func__);
+
+		ret = -EINVAL;
+		goto done;
+	}
+
+	cvs_handle = voice_get_cvs_handle(v);
+
+	pr_debug("%s: Setting AMR rate. Media Type: %d\n", __func__,
+		 common.mvs_info.media_type);
+
+	cvs_set_amr_rate.hdr.hdr_field =
+			APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+			APR_HDR_LEN(APR_HDR_SIZE),
+			APR_PKT_VER);
+	cvs_set_amr_rate.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+			       sizeof(cvs_set_amr_rate) - APR_HDR_SIZE);
+	cvs_set_amr_rate.hdr.src_port =
+			voice_get_idx_for_session(v->session_id);
+	cvs_set_amr_rate.hdr.dest_port = cvs_handle;
+	cvs_set_amr_rate.hdr.token = 0;
+
+	if (common.mvs_info.media_type == VSS_MEDIA_ID_AMR_NB_MODEM)
+		cvs_set_amr_rate.hdr.opcode =
+				VSS_ISTREAM_CMD_VOC_AMR_SET_ENC_RATE;
+	else if (common.mvs_info.media_type == VSS_MEDIA_ID_AMR_WB_MODEM)
+		cvs_set_amr_rate.hdr.opcode =
+				VSS_ISTREAM_CMD_VOC_AMRWB_SET_ENC_RATE;
+
+	cvs_set_amr_rate.amr_rate.mode = common.mvs_info.rate;
+
+	v->cvs_state = CMD_STATUS_FAIL;
+
+	ret = apr_send_pkt(apr_cvs, (uint32_t *) &cvs_set_amr_rate);
+	if (ret < 0) {
+		pr_err("%s: Error %d sending SET_AMR_RATE\n",
+		       __func__, ret);
+
+		goto done;
+	}
+	ret = wait_event_timeout(v->cvs_wait,
+				 (v->cvs_state == CMD_STATUS_SUCCESS),
+				 msecs_to_jiffies(TIMEOUT_MS));
+	if (!ret) {
+		pr_err("%s: wait_event timeout\n", __func__);
+
+		ret = -EINVAL;
+		goto done;
+	}
+
+	return 0;
+done:
+	return ret;
+}
+
 static int voice_config_cvs_vocoder(struct voice_data *v)
 {
 	int ret = 0;
@@ -1597,80 +1698,13 @@
 
 		break;
 	}
-	case VSS_MEDIA_ID_AMR_NB_MODEM: {
-		struct cvs_set_amr_enc_rate_cmd cvs_set_amr_rate;
-
-		pr_debug("Setting AMR rate\n");
-
-		cvs_set_amr_rate.hdr.hdr_field =
-				APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
-				APR_HDR_LEN(APR_HDR_SIZE),
-				APR_PKT_VER);
-		cvs_set_amr_rate.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
-				       sizeof(cvs_set_amr_rate) - APR_HDR_SIZE);
-		cvs_set_amr_rate.hdr.src_port =
-				voice_get_idx_for_session(v->session_id);
-		cvs_set_amr_rate.hdr.dest_port = cvs_handle;
-		cvs_set_amr_rate.hdr.token = 0;
-		cvs_set_amr_rate.hdr.opcode =
-					VSS_ISTREAM_CMD_VOC_AMR_SET_ENC_RATE;
-		cvs_set_amr_rate.amr_rate.mode = common.mvs_info.rate;
-
-		v->cvs_state = CMD_STATUS_FAIL;
-
-		ret = apr_send_pkt(apr_cvs, (uint32_t *) &cvs_set_amr_rate);
-		if (ret < 0) {
-			pr_err("%s: Error %d sending SET_AMR_RATE\n",
-			       __func__, ret);
-			goto fail;
-		}
-		ret = wait_event_timeout(v->cvs_wait,
-					 (v->cvs_state == CMD_STATUS_SUCCESS),
-					 msecs_to_jiffies(TIMEOUT_MS));
-		if (!ret) {
-			pr_err("%s: wait_event timeout\n", __func__);
-			goto fail;
-		}
-
-		ret = voice_set_dtx(v);
-		if (ret < 0)
-			goto fail;
-
-		break;
-	}
+	case VSS_MEDIA_ID_AMR_NB_MODEM:
 	case VSS_MEDIA_ID_AMR_WB_MODEM: {
-		struct cvs_set_amrwb_enc_rate_cmd cvs_set_amrwb_rate;
-
-		pr_debug("Setting AMR WB rate\n");
-
-		cvs_set_amrwb_rate.hdr.hdr_field =
-				APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
-				APR_HDR_LEN(APR_HDR_SIZE),
-				APR_PKT_VER);
-		cvs_set_amrwb_rate.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
-						sizeof(cvs_set_amrwb_rate) -
-						APR_HDR_SIZE);
-		cvs_set_amrwb_rate.hdr.src_port =
-				voice_get_idx_for_session(v->session_id);
-		cvs_set_amrwb_rate.hdr.dest_port = cvs_handle;
-		cvs_set_amrwb_rate.hdr.token = 0;
-		cvs_set_amrwb_rate.hdr.opcode =
-					VSS_ISTREAM_CMD_VOC_AMRWB_SET_ENC_RATE;
-		cvs_set_amrwb_rate.amrwb_rate.mode = common.mvs_info.rate;
-
-		v->cvs_state = CMD_STATUS_FAIL;
-
-		ret = apr_send_pkt(apr_cvs, (uint32_t *) &cvs_set_amrwb_rate);
-		if (ret < 0) {
-			pr_err("%s: Error %d sending SET_AMRWB_RATE\n",
+		ret = voice_config_cvs_vocoder_amr_rate(v);
+		if (ret) {
+			pr_err("%s: Failed to update vocoder rate. %d\n",
 			       __func__, ret);
-			goto fail;
-		}
-		ret = wait_event_timeout(v->cvs_wait,
-					 (v->cvs_state == CMD_STATUS_SUCCESS),
-					 msecs_to_jiffies(TIMEOUT_MS));
-		if (!ret) {
-			pr_err("%s: wait_event timeout\n", __func__);
+
 			goto fail;
 		}
 
@@ -1697,6 +1731,31 @@
 	return -EINVAL;
 }
 
+int voc_update_amr_vocoder_rate(uint32_t session_id)
+{
+	int ret = 0;
+	struct voice_data *v;
+
+	pr_debug("%s: session_id:%d", __func__, session_id);
+
+	v = voice_get_session(session_id);
+
+	if (v == NULL) {
+		pr_err("%s: v is NULL, session_id:%d\n", __func__,
+		       session_id);
+
+		ret = -EINVAL;
+		goto done;
+	}
+
+	mutex_lock(&v->lock);
+	ret = voice_config_cvs_vocoder_amr_rate(v);
+	mutex_unlock(&v->lock);
+
+done:
+	return ret;
+}
+
 static int voice_send_start_voice_cmd(struct voice_data *v)
 {
 	struct apr_hdr mvm_start_voice_cmd;
@@ -3107,8 +3166,7 @@
 		voice_send_netid_timing_cmd(v);
 	}
 
-	/* enable slowtalk if st_enable is set */
-	if (v->st_enable)
+	if (v->st_enable && !v->tty_mode)
 		voice_send_set_pp_enable_cmd(v,
 					     MODULE_ID_VOICE_MODULE_ST,
 					     v->st_enable);
@@ -3408,6 +3466,10 @@
 	mvm_handle = voice_get_mvm_handle(v);
 	cvp_handle = voice_get_cvp_handle(v);
 
+	/* disable slowtalk if st_enable is set */
+	if (v->st_enable)
+		voice_send_set_pp_enable_cmd(v, MODULE_ID_VOICE_MODULE_ST, 0);
+
 	/* stop playback or recording */
 	v->music_info.force = 1;
 	voice_cvs_stop_playback(v);
@@ -4316,7 +4378,7 @@
 	return ret;
 }
 
-int voc_disable_cvp(uint32_t session_id)
+static int voc_disable_cvp(uint32_t session_id)
 {
 	struct voice_data *v = voice_get_session(session_id);
 	int ret = 0;
@@ -4351,7 +4413,7 @@
 	return ret;
 }
 
-int voc_enable_cvp(uint32_t session_id)
+static int voc_enable_cvp(uint32_t session_id)
 {
 	struct voice_data *v = voice_get_session(session_id);
 	int ret = 0;
@@ -4423,10 +4485,8 @@
 			goto fail;
 		}
 
-		/* Send tty mode if tty device is used */
 		voice_send_tty_mode_cmd(v);
-		/* enable slowtalk */
-		if (v->st_enable)
+		if (v->st_enable && !v->tty_mode)
 			voice_send_set_pp_enable_cmd(v,
 					     MODULE_ID_VOICE_MODULE_ST,
 					     v->st_enable);
@@ -4507,8 +4567,8 @@
 	return ret;
 }
 
-int voc_set_rx_device_mute(uint32_t session_id, uint32_t mute,
-					uint32_t ramp_duration)
+int voc_set_device_mute(uint32_t session_id, uint32_t dir, uint32_t mute,
+			uint32_t ramp_duration)
 {
 	struct voice_data *v = NULL;
 	int ret = 0;
@@ -4518,16 +4578,23 @@
 	while (voice_itr_get_next_session(&itr, &v)) {
 		if (v != NULL) {
 			mutex_lock(&v->lock);
-			v->dev_rx.dev_mute = mute;
-			v->dev_rx.dev_mute_ramp_duration_ms =
+			if (dir == VSS_IVOLUME_DIRECTION_TX) {
+				v->dev_tx.dev_mute = mute;
+				v->dev_tx.dev_mute_ramp_duration_ms =
 							ramp_duration;
+			} else {
+				v->dev_rx.dev_mute = mute;
+				v->dev_rx.dev_mute_ramp_duration_ms =
+							ramp_duration;
+			}
+
 			if (((v->voc_state == VOC_RUN) ||
 				(v->voc_state == VOC_STANDBY)) &&
 				(v->lch_mode == 0))
 				ret = voice_send_device_mute_cmd(v,
-						VSS_IVOLUME_DIRECTION_RX,
-						v->dev_rx.dev_mute,
-						ramp_duration);
+							dir,
+							mute,
+							ramp_duration);
 			mutex_unlock(&v->lock);
 		} else {
 			pr_err("%s: invalid session_id 0x%x\n", __func__,
@@ -4619,8 +4686,8 @@
 				v->st_enable = enable;
 
 			if (v->voc_state == VOC_RUN) {
-				if (module_id ==
-				    MODULE_ID_VOICE_MODULE_ST)
+				if ((module_id == MODULE_ID_VOICE_MODULE_ST) &&
+				    (!v->tty_mode))
 					ret = voice_send_set_pp_enable_cmd(v,
 						MODULE_ID_VOICE_MODULE_ST,
 						enable);
@@ -4843,6 +4910,110 @@
 	return ret;
 }
 
+int voc_disable_device(uint32_t session_id)
+{
+	struct voice_data *v = voice_get_session(session_id);
+	int ret = 0;
+
+	pr_debug("%s: voc state=%d\n", __func__, v->voc_state);
+	if (v == NULL) {
+		pr_err("%s: v is NULL\n", __func__);
+		return -EINVAL;
+	}
+
+	mutex_lock(&v->lock);
+	if (v->voc_state == VOC_RUN) {
+		ret = voice_pause_voice_call(v);
+		if (ret < 0) {
+			pr_err("%s: Pause Voice Call failed for session 0x%x, err %d!\n",
+			       __func__, v->session_id, ret);
+			goto done;
+		}
+		rtac_remove_voice(voice_get_cvs_handle(v));
+		voice_send_cvp_deregister_vol_cal_cmd(v);
+		voice_send_cvp_deregister_cal_cmd(v);
+		voice_send_cvp_deregister_dev_cfg_cmd(v);
+
+		v->voc_state = VOC_CHANGE;
+	} else {
+		pr_debug("%s: called in voc state=%d, No_OP\n",
+			 __func__, v->voc_state);
+	}
+
+	if (common.ec_ref_ext)
+		voc_set_ext_ec_ref(AFE_PORT_INVALID, false);
+done:
+	mutex_unlock(&v->lock);
+
+	return ret;
+}
+
+int voc_enable_device(uint32_t session_id)
+{
+	struct voice_data *v = voice_get_session(session_id);
+	int ret = 0;
+
+	pr_debug("%s: voc state=%d\n", __func__, v->voc_state);
+	if (v == NULL) {
+		pr_err("%s: v is NULL\n", __func__);
+		return -EINVAL;
+	}
+
+	mutex_lock(&v->lock);
+	if (v->voc_state == VOC_CHANGE) {
+		ret = voice_send_tty_mode_cmd(v);
+		if (ret < 0) {
+			pr_err("%s: Sending TTY mode failed, ret=%d\n",
+			       __func__, ret);
+			/* Not a critical error, allow voice call to continue */
+		}
+
+		if (v->tty_mode) {
+			/* disable slowtalk */
+			voice_send_set_pp_enable_cmd(v,
+						     MODULE_ID_VOICE_MODULE_ST,
+						     0);
+		} else {
+			/* restore slowtalk */
+			voice_send_set_pp_enable_cmd(v,
+						     MODULE_ID_VOICE_MODULE_ST,
+						     v->st_enable);
+		}
+
+		ret = voice_send_set_device_cmd(v);
+		if (ret < 0) {
+			pr_err("%s: Set device failed, ret=%d\n",
+			       __func__, ret);
+			goto done;
+		}
+
+		voice_send_cvp_register_dev_cfg_cmd(v);
+		voice_send_cvp_register_cal_cmd(v);
+		voice_send_cvp_register_vol_cal_cmd(v);
+
+		rtac_add_voice(voice_get_cvs_handle(v),
+			       voice_get_cvp_handle(v),
+			       v->dev_rx.port_id, v->dev_tx.port_id,
+			       v->session_id);
+
+		ret = voice_send_start_voice_cmd(v);
+		if (ret < 0) {
+			pr_err("%s: Fail in sending START_VOICE, ret=%d\n",
+			       __func__, ret);
+			goto done;
+		}
+		v->voc_state = VOC_RUN;
+	} else {
+		pr_debug("%s: called in voc state=%d, No_OP\n",
+			 __func__, v->voc_state);
+	}
+
+done:
+	mutex_unlock(&v->lock);
+
+	return ret;
+}
+
 int voc_set_lch(uint32_t session_id, enum voice_lch_mode lch_mode)
 {
 	struct voice_data *v = voice_get_session(session_id);
diff --git a/sound/soc/msm/qdsp6v2/q6voice.h b/sound/soc/msm/qdsp6v2/q6voice.h
index 5c0cf21..c6f3482 100644
--- a/sound/soc/msm/qdsp6v2/q6voice.h
+++ b/sound/soc/msm/qdsp6v2/q6voice.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
@@ -1319,7 +1319,7 @@
 	void *buf;
 };
 
-#define MAX_VOC_SESSIONS 5
+#define MAX_VOC_SESSIONS 6
 
 struct common_data {
 	/* these default values are for all devices */
@@ -1393,21 +1393,25 @@
 #define VOC_PATH_VOLTE_PASSIVE 2
 #define VOC_PATH_VOICE2_PASSIVE 3
 #define VOC_PATH_QCHAT_PASSIVE 4
+#define VOC_PATH_VOWLAN_PASSIVE 5
 
 #define MAX_SESSION_NAME_LEN 32
-#define VOICE_SESSION_NAME  "Voice session"
-#define VOIP_SESSION_NAME   "VoIP session"
-#define VOLTE_SESSION_NAME  "VoLTE session"
-#define VOICE2_SESSION_NAME "Voice2 session"
-#define QCHAT_SESSION_NAME  "QCHAT session"
+#define VOICE_SESSION_NAME   "Voice session"
+#define VOIP_SESSION_NAME    "VoIP session"
+#define VOLTE_SESSION_NAME   "VoLTE session"
+#define VOICE2_SESSION_NAME  "Voice2 session"
+#define QCHAT_SESSION_NAME   "QCHAT session"
+#define VOWLAN_SESSION_NAME  "VoWLAN session"
 
 #define VOICE2_SESSION_VSID_STR "10DC1000"
 #define QCHAT_SESSION_VSID_STR "10803000"
+#define VOWLAN_SESSION_VSID_STR "10002000"
 #define VOICE_SESSION_VSID  0x10C01000
 #define VOICE2_SESSION_VSID 0x10DC1000
 #define VOLTE_SESSION_VSID  0x10C02000
 #define VOIP_SESSION_VSID   0x10004000
 #define QCHAT_SESSION_VSID  0x10803000
+#define VOWLAN_SESSION_VSID 0x10002000
 #define ALL_SESSION_VSID    0xFFFFFFFF
 #define VSID_MAX            ALL_SESSION_VSID
 
@@ -1440,11 +1444,9 @@
 			uint32_t ramp_duration);
 int voc_set_tx_mute(uint32_t session_id, uint32_t dir, uint32_t mute,
 		    uint32_t ramp_duration);
-int voc_set_rx_device_mute(uint32_t session_id, uint32_t mute,
-			   uint32_t ramp_duration);
+int voc_set_device_mute(uint32_t session_id, uint32_t dir, uint32_t mute,
+			uint32_t ramp_duration);
 int voc_get_rx_device_mute(uint32_t session_id);
-int voc_disable_cvp(uint32_t session_id);
-int voc_enable_cvp(uint32_t session_id);
 int voc_set_route_flag(uint32_t session_id, uint8_t path_dir, uint8_t set);
 uint8_t voc_get_route_flag(uint32_t session_id, uint8_t path_dir);
 int voc_enable_dtmf_rx_detection(uint32_t session_id, uint32_t enable);
@@ -1465,5 +1467,8 @@
 int voc_start_record(uint32_t port_id, uint32_t set, uint32_t session_id);
 int voice_get_idx_for_session(u32 session_id);
 int voc_set_ext_ec_ref(uint16_t port_id, bool state);
+int voc_update_amr_vocoder_rate(uint32_t session_id);
+int voc_disable_device(uint32_t session_id);
+int voc_enable_device(uint32_t session_id);
 
 #endif
diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c
index b9af9b6..4792719 100644
--- a/sound/soc/soc-compress.c
+++ b/sound/soc/soc-compress.c
@@ -95,7 +95,7 @@
 	else
 		stream = SNDRV_PCM_STREAM_CAPTURE;
 
-	mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
+	mutex_lock(&fe->card->dpcm_mutex);
 
 	if (platform->driver->compr_ops && platform->driver->compr_ops->open) {
 		ret = platform->driver->compr_ops->open(cstream);
@@ -154,7 +154,7 @@
 	codec_dai->active++;
 	fe->codec->active++;
 
-	mutex_unlock(&fe->card->mutex);
+	mutex_unlock(&fe->card->dpcm_mutex);
 
 	return 0;
 
@@ -166,7 +166,7 @@
 		platform->driver->compr_ops->free(cstream);
 out:
 	fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
-	mutex_unlock(&fe->card->mutex);
+	mutex_unlock(&fe->card->dpcm_mutex);
 	return ret;
 }
 
@@ -273,8 +273,7 @@
 	else
 		stream = SNDRV_PCM_STREAM_CAPTURE;
 
-	mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
-
+	mutex_lock(&fe->card->dpcm_mutex);
 	if (cstream->direction == SND_COMPRESS_PLAYBACK) {
 		cpu_dai->playback_active--;
 		codec_dai->playback_active--;
@@ -323,7 +322,7 @@
 		platform->driver->compr_ops->free(cstream);
 	//cpu_dai->runtime = NULL;
 
-	mutex_unlock(&fe->card->mutex);
+	mutex_unlock(&fe->card->dpcm_mutex);
 	return 0;
 }
 
@@ -393,8 +392,7 @@
 		stream = SNDRV_PCM_STREAM_CAPTURE;
 
 
-	mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
-
+	mutex_lock(&fe->card->dpcm_mutex);
 	if (platform->driver->compr_ops && platform->driver->compr_ops->trigger) {
 		ret = platform->driver->compr_ops->trigger(cstream, cmd);
 		if (ret < 0)
@@ -422,7 +420,7 @@
 
 out:
 	fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
-	mutex_unlock(&fe->card->mutex);
+	mutex_unlock(&fe->card->dpcm_mutex);
 	return ret;
 }
 
@@ -477,7 +475,6 @@
 	struct snd_soc_pcm_runtime *fe = cstream->private_data;
 	struct snd_pcm_substream *fe_substream = fe->pcm->streams[0].substream;
 	struct snd_soc_platform *platform = fe->platform;
-	struct snd_pcm_hw_params *hw_params;
 	int ret = 0, stream;
 
 	if (cstream->direction == SND_COMPRESS_PLAYBACK)
@@ -485,12 +482,7 @@
 	else
 		stream = SNDRV_PCM_STREAM_CAPTURE;
 
-	hw_params = kzalloc(sizeof(*hw_params), GFP_KERNEL);
-	if (hw_params == NULL)
-		return -ENOMEM;
-
-	mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
-
+	mutex_lock(&fe->card->dpcm_mutex);
 	/* first we call set_params for the platform driver
 	 * this should configure the soc side
 	 * if the machine has compressed ops then we call that as well
@@ -535,7 +527,7 @@
 
 out:
 	fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
-	mutex_unlock(&fe->card->mutex);
+	mutex_unlock(&fe->card->dpcm_mutex);
 	return ret;
 }
 
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index 63bbbdd..796d6b4 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -1904,16 +1904,12 @@
 	}
 
 	if (found) {
-		if (widget->platform) {
-			soc_dpcm_runtime_update(widget);
-		} else {
-	  		dapm_mark_dirty(widget, "mux change");
-			dapm_power_widgets(widget->dapm,
-					   SND_SOC_DAPM_STREAM_NOP);
-		}
+		dapm_mark_dirty(widget, "mux change");
+		dapm_power_widgets(widget->dapm,
+			   SND_SOC_DAPM_STREAM_NOP);
 	}
 
-	return 0;
+	return found;
 }
 
 int snd_soc_dapm_mux_update_power(struct snd_soc_dapm_widget *widget,
@@ -1925,6 +1921,8 @@
 	mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_PCM);
 	ret = soc_dapm_mux_update_power(widget, kcontrol, change, mux, e);
 	mutex_unlock(&card->dapm_mutex);
+	if (ret > 0)
+		soc_dpcm_runtime_update(widget);
 	return ret;
 }
 EXPORT_SYMBOL_GPL(snd_soc_dapm_mux_update_power);
@@ -1953,16 +1951,11 @@
 	}
 
 	if (found) {
-	  if (widget->platform) {
-		soc_dpcm_runtime_update(widget);
-	  } else {
 		dapm_mark_dirty(widget, "mixer update");
 		dapm_power_widgets(widget->dapm, SND_SOC_DAPM_STREAM_NOP);
-	  }
-
 	}
 
-	return 0;
+	return found;
 }
 
 int snd_soc_dapm_mixer_update_power(struct snd_soc_dapm_widget *widget,
@@ -1973,6 +1966,8 @@
 	mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_PCM);
 	ret = soc_dapm_mixer_update_power(widget, kcontrol, connect);
 	mutex_unlock(&card->dapm_mutex);
+	if (ret > 0)
+		soc_dpcm_runtime_update(widget);
 	return ret;
 }
 EXPORT_SYMBOL_GPL(snd_soc_dapm_mixer_update_power);
@@ -2107,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;
 	}
 
@@ -2117,6 +2114,7 @@
 		w->force = 0;
 	dapm_mark_dirty(w, "pin configuration");
 
+	mutex_unlock(&dapm->card->dapm_mutex);
 	return 0;
 }
 
@@ -2313,6 +2311,7 @@
 		if (ret < 0) {
 			dev_err(dapm->dev, "Failed to add route %s->%s\n",
 				route->source, route->sink);
+			mutex_unlock(&dapm->card->dapm_mutex);
 			return ret;
 		}
 		route++;
@@ -3022,6 +3021,7 @@
 			dev_err(dapm->dev,
 				"ASoC: Failed to create DAPM control %s: %d\n",
 				widget->name, ret);
+			mutex_unlock(&dapm->card->dapm_mutex);
 			return ret;
 		}
 		widget++;
@@ -3100,9 +3100,11 @@
 {
 	struct snd_soc_dapm_context *pdapm = &rtd->platform->dapm;
 	struct snd_soc_dapm_context *cdapm = &rtd->codec->dapm;
+	struct snd_soc_card *card = rtd->card;
 
 	dev_dbg(rtd->dev, "rtd stream %d event %d\n", stream, event);
 
+	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);
@@ -3110,6 +3112,7 @@
 		widget_stream_event(pdapm, rtd->cpu_dai->capture_aif, event);
 		widget_stream_event(cdapm, rtd->codec_dai->capture_aif, event);
 	}
+	mutex_unlock(&card->dapm_mutex);
 
 	/* do we need to notify any clients that DAPM stream is complete */
 	if (pdapm->stream_event)
@@ -3133,14 +3136,14 @@
 int snd_soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd,
 	const char *stream, int event)
 {
+	struct snd_soc_card *card = rtd->card;
 	struct snd_soc_codec *codec = rtd->codec;
 
 	if (stream == NULL)
 		return 0;
-
-	mutex_lock(&codec->mutex);
+	mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_PCM);
 	soc_dapm_stream_event(&codec->dapm, stream, event);
-	mutex_unlock(&codec->mutex);
+	mutex_unlock(&card->dapm_mutex);
 	return 0;
 }
 
@@ -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;
 }
diff --git a/sound/usb/card.c b/sound/usb/card.c
index f453dbd..d419e2f 100644
--- a/sound/usb/card.c
+++ b/sound/usb/card.c
@@ -205,11 +205,24 @@
 	struct usb_device *dev = chip->dev;
 	struct usb_host_interface *host_iface;
 	struct usb_interface_descriptor *altsd;
+	struct usb_interface *usb_iface;
 	void *control_header;
 	int i, protocol;
 
+	usb_iface = usb_ifnum_to_if(dev, ctrlif);
+	if (!usb_iface) {
+		snd_printk(KERN_ERR "%d:%u : does not exist\n",
+					dev->devnum, ctrlif);
+		return -EINVAL;
+	}
+
 	/* find audiocontrol interface */
-	host_iface = &usb_ifnum_to_if(dev, ctrlif)->altsetting[0];
+	host_iface = &usb_iface->altsetting[0];
+	if (!host_iface) {
+		snd_printk(KERN_ERR "Audio Control interface is not available.");
+		return -EINVAL;
+	}
+
 	control_header = snd_usb_find_csint_desc(host_iface->extra,
 						 host_iface->extralen,
 						 NULL, UAC_HEADER);
@@ -248,8 +261,7 @@
 
 	case UAC_VERSION_2: {
 		struct usb_interface_assoc_descriptor *assoc =
-			usb_ifnum_to_if(dev, ctrlif)->intf_assoc;
-
+						usb_iface->intf_assoc;
 		if (!assoc) {
 			snd_printk(KERN_ERR "Audio class v2 interfaces need an interface association\n");
 			return -EINVAL;
@@ -723,6 +735,11 @@
 	}
 
 	usbaudiosdev = kzalloc(sizeof(*usbaudiosdev), GFP_KERNEL);
+	if (!usbaudiosdev) {
+		pr_err("Usb audio device memory allocation failed.\n");
+		return -ENOMEM;
+	}
+
 	usbaudiosdev->name = "usb_audio";
 
 	err = switch_dev_register(usbaudiosdev);