Merge "ASoC: msm: Add PCM loopback volume control"
diff --git a/Documentation/devicetree/bindings/arm/cpus.txt b/Documentation/devicetree/bindings/arm/cpus.txt
new file mode 100644
index 0000000..6508329
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/cpus.txt
@@ -0,0 +1,78 @@
+* ARM CPUs binding description
+
+The device tree allows to describe the layout of CPUs in a system through
+the "cpus" node, which in turn contains a number of subnodes (ie "cpu")
+defining properties for every cpu.
+
+Bindings for CPU nodes follow the ePAPR standard, available from:
+
+http://devicetree.org
+
+For the ARM architecture every CPU node must contain the following properties:
+
+- device_type:	must be "cpu"
+- reg:		property matching the CPU MPIDR[23:0] register bits
+		reg[31:24] bits must be set to 0
+- compatible:	should be one of:
+		"arm,arm1020"
+		"arm,arm1020e"
+		"arm,arm1022"
+		"arm,arm1026"
+		"arm,arm720"
+		"arm,arm740"
+		"arm,arm7tdmi"
+		"arm,arm920"
+		"arm,arm922"
+		"arm,arm925"
+		"arm,arm926"
+		"arm,arm940"
+		"arm,arm946"
+		"arm,arm9tdmi"
+		"arm,cortex-a5"
+		"arm,cortex-a7"
+		"arm,cortex-a8"
+		"arm,cortex-a9"
+		"arm,cortex-a15"
+		"arm,arm1136"
+		"arm,arm1156"
+		"arm,arm1176"
+		"arm,arm11mpcore"
+		"faraday,fa526"
+		"intel,sa110"
+		"intel,sa1100"
+		"marvell,feroceon"
+		"marvell,mohawk"
+		"marvell,xsc3"
+		"marvell,xscale"
+		"qcom,krait"
+
+Example:
+
+	cpus {
+		#size-cells = <0>;
+		#address-cells = <1>;
+
+		CPU0: cpu@0 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a15";
+			reg = <0x0>;
+		};
+
+		CPU1: cpu@1 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a15";
+			reg = <0x1>;
+		};
+
+		CPU2: cpu@100 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a7";
+			reg = <0x100>;
+		};
+
+		CPU3: cpu@101 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a7";
+			reg = <0x101>;
+		};
+	};
diff --git a/Documentation/devicetree/bindings/arm/msm/cpr-regulator.txt b/Documentation/devicetree/bindings/arm/msm/cpr-regulator.txt
index 439418d..04310ec 100644
--- a/Documentation/devicetree/bindings/arm/msm/cpr-regulator.txt
+++ b/Documentation/devicetree/bindings/arm/msm/cpr-regulator.txt
@@ -12,9 +12,10 @@
 
 Required properties:
 - compatible:			Must be "qcom,cpr-regulator"
-- reg:				Register addresses for RBCPR and efuse
-- reg-names:			Register names. Must be "rbcpr", "pvs_efuse"
-				and "cpr_efuse"
+- reg:				Register addresses for RBCPR, RBCPR clock
+				select, PVS eFuse and CPR eFuse
+- reg-names:			Register names. Must be "rbcpr", "rbcpr_clk",
+				"pvs_efuse" and "cpr_efuse"
 - regulator-name:		A string used to describe the regulator
 - interrupts:			Interrupt line from RBCPR to interrupt controller.
 - regulator-min-microvolt:	Minimum corner value as min constraint, which
diff --git a/Documentation/devicetree/bindings/arm/msm/memory-reserve.txt b/Documentation/devicetree/bindings/arm/msm/memory-reserve.txt
index c1b79ae..6dac1b7 100644
--- a/Documentation/devicetree/bindings/arm/msm/memory-reserve.txt
+++ b/Documentation/devicetree/bindings/arm/msm/memory-reserve.txt
@@ -69,3 +69,20 @@
 This region is assumed to be a part of a separate hole that has been removed
 and this binding specifies the fixed location and size of the region within
 that hole.
+
+
+Some drivers may only wish to reserve memory from the system. Reserved memory
+is still tracked internally by the Linux page allocator. The memory is reserved
+from the buddy allocator at bootup but may be freed back at a later point in
+time with memblock_free and free_bootmem_late.
+
+Required parameters:
+-qcom,memblock-reserve: base and size of block to be reserved. Drivers should
+call memblock_is_reserved before attempting to use the base address to ensure
+the memory was completely reserved.
+
+	qcom,a-driver {
+		compatible = "qcom,a-driver";
+		/* reserve a 4MB region @ 0x200000 for use later */
+		qcom,memblock-reserve = <0x200000 0x400000>;
+	};
diff --git a/Documentation/devicetree/bindings/arm/msm/msm_thermal.txt b/Documentation/devicetree/bindings/arm/msm/msm_thermal.txt
index 23498e5..6ef2b77 100644
--- a/Documentation/devicetree/bindings/arm/msm/msm_thermal.txt
+++ b/Documentation/devicetree/bindings/arm/msm/msm_thermal.txt
@@ -24,6 +24,8 @@
 
 Optional properties
 
+- qcom,freq-control-mask: The cpu mask that will be used to determine if a
+			core can be used for freq control.
 - qcom,core-limit-temp: Threshold temperature to start shutting down cores
 			in degC
 - qcom,core-temp-hysterisis: Degrees C below which the cores will be brought
@@ -77,6 +79,7 @@
 		qcom,limit-temp = <60>;
 		qcom,temp-hysteresis = <10>;
 		qcom,freq-step = <2>;
+		qcom,freq-control-mask = <0xf>
 		qcom,core-limit-temp = <90>;
 		qcom,core-temp-hysterisis = <10>;
 		qcom,core-control-mask = <7>;
diff --git a/Documentation/devicetree/bindings/crypto/msm/qcedev.txt b/Documentation/devicetree/bindings/crypto/msm/qcedev.txt
index 7eb65d2..3ca9080 100644
--- a/Documentation/devicetree/bindings/crypto/msm/qcedev.txt
+++ b/Documentation/devicetree/bindings/crypto/msm/qcedev.txt
@@ -15,8 +15,7 @@
 
 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.
 
 Example:
 
diff --git a/Documentation/devicetree/bindings/crypto/msm/qcrypto.txt b/Documentation/devicetree/bindings/crypto/msm/qcrypto.txt
index 79dc287..01cc798 100644
--- a/Documentation/devicetree/bindings/crypto/msm/qcrypto.txt
+++ b/Documentation/devicetree/bindings/crypto/msm/qcrypto.txt
@@ -15,7 +15,7 @@
 
 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.
 
 Example:
 
diff --git a/Documentation/devicetree/bindings/gpu/adreno.txt b/Documentation/devicetree/bindings/gpu/adreno.txt
index 436dfc7..052feeb 100644
--- a/Documentation/devicetree/bindings/gpu/adreno.txt
+++ b/Documentation/devicetree/bindings/gpu/adreno.txt
@@ -72,6 +72,20 @@
 			   This is used to override faulty hardware readings.
 - qcom,strtstp-sleepwake:  Boolean. Enables use of GPU SLUMBER instead of SLEEP for power savings
 
+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:
+Documentation/devicetree/bindings/coresight/coresight.txt
+
+- coresight-id           Unique integer identifier for the bus.
+- coresight-name         Unique descriptive name of the bus.
+- coresight-nr-inports   Number of input ports on the bus.
+- coresight-outports     List of output port numbers on the bus.
+- coresight-child-list   List of phandles pointing to the children of this
+                         component.
+- coresight-child-ports  List of input port numbers of the children.
+
+
 Example of A330 GPU in MSM8974:
 
 / {
diff --git a/Documentation/devicetree/bindings/i2c/i2c-qup.txt b/Documentation/devicetree/bindings/i2c/i2c-qup.txt
index a7976e8..fd7b635 100644
--- a/Documentation/devicetree/bindings/i2c/i2c-qup.txt
+++ b/Documentation/devicetree/bindings/i2c/i2c-qup.txt
@@ -28,10 +28,18 @@
 		      recovery procedure.
  - qcom,sda-gpio     : I2C data  GPIO number. Required for execution of bus
 		      recovery procedure.
+ - qcom,active-only  : Vote for core clock when the application processor goes
+		      to active state and remove that vote when it goes to idle
+		      state. This flag may improve service time of first i2c
+		      request at the expense of power consumption. 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
+		      bus-scaling driver.
 
 Example:
-	i2c@f9966000 {
-		cell-index = <0>;
+	i2c_3: i2c@f9966000 {
+		cell-index = <3>;
 		compatible = "qcom,i2c-qup";
 		reg = <0xf9966000 0x1000>;
 		reg-names = "qup_phys_addr";
diff --git a/Documentation/devicetree/bindings/iommu/msm_iommu_v0.txt b/Documentation/devicetree/bindings/iommu/msm_iommu_v0.txt
index 706ffe6..c7c6415 100644
--- a/Documentation/devicetree/bindings/iommu/msm_iommu_v0.txt
+++ b/Documentation/devicetree/bindings/iommu/msm_iommu_v0.txt
@@ -13,6 +13,7 @@
 - qcom,iommu-pmu-event-classes: List of event classes supported.
 - qcom,needs-alt-core-clk : boolean to enable the secondary core clock for
   access to the IOMMU configuration registers
+- Bus scaling properties: See msm_bus.txt
 
 - List of sub nodes, one for each of the translation context banks supported.
     Required properties for each sub-node:
diff --git a/Documentation/devicetree/bindings/iommu/msm_iommu_v1.txt b/Documentation/devicetree/bindings/iommu/msm_iommu_v1.txt
index 56f4767..b3f1aef 100644
--- a/Documentation/devicetree/bindings/iommu/msm_iommu_v1.txt
+++ b/Documentation/devicetree/bindings/iommu/msm_iommu_v1.txt
@@ -21,13 +21,17 @@
 - qcom,iommu-pmu-ngroups: Number of Performance Monitor Unit (PMU) groups.
 - qcom,iommu-pmu-ncounters: Number of PMU counters per group.
 - qcom,iommu-pmu-event-classes: List of event classes supported.
+- Bus scaling properties: See msm_bus.txt
 
 - List of sub nodes, one for each of the translation context banks supported.
   Each sub node has the following required properties:
 
   - compatible : "qcom,msm-smmu-v1-ctx"
   - reg : offset and length of the register set for the context bank.
-  - interrupts : should contain the context bank interrupt.
+  - interrupts : should contain the context bank interrupt. If this is
+    a secure context bank, this should be a list of 2 3-tuples where
+    the first is the non-secure interrupt, and the second is the
+    secure interrupt.
   - qcom,iommu-ctx-sids : List of stream identifiers associated with this
     translation context.
   - label : Name of the context bank
diff --git a/Documentation/devicetree/bindings/leds/leds-qpnp.txt b/Documentation/devicetree/bindings/leds/leds-qpnp.txt
index c409ea6..ae1f648 100644
--- a/Documentation/devicetree/bindings/leds/leds-qpnp.txt
+++ b/Documentation/devicetree/bindings/leds/leds-qpnp.txt
@@ -50,7 +50,7 @@
 RGB Led is a tri-colored led, Red, Blue & Green.
 
 Required properties for RGB led:
-- qcom,mode: mode the led should operate in, options 0 = PWM, 1 = LPG
+- qcom,mode: mode the led should operate in, options "pwm" and "lpg"
 - qcom,pwm-channel: pwm channel the led will operate on
 
 Required properties for PWM mode only:
@@ -59,6 +59,8 @@
 Required properties for LPG mode only:
 - qcom,duty-pcts: array of values for duty cycle to go through
 - qcom,start-idx: starting point duty-pcts array
+
+Optional properties for LPG mode only:
 - qcom,pause-lo: pause at low end of cycle
 - qcom,pause-hi: pause at high end of cycle
 - qcom,ramp-step-ms: step between each cycle (ms)
@@ -76,12 +78,28 @@
 - qcom,default-state: default state of the led, should be "on" or "off"
 - qcom,source-sel: select power source, default 1 (enabled)
 - qcom,mode-ctrl: select operation mode, default 0x60 = Mode Sink
+- qcom,mode: mode the led should operate in, options "pwm", "lpg" and "manual"
+
+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,duty-pcts: array of values for duty cycle to go through
+- qcom,start-idx: starting point duty-pcts array
+
+Optional properties for LPG mode only:
+- qcom,pause-lo: pause at low end of cycle
+- qcom,pause-hi: pause at high end of cycle
+- qcom,ramp-step-ms: step between each cycle (ms)
+- qcom,lut-flags: flags to be used in lut configuration
 
 Keypad backlight is a backlight source for buttons. It supports four rows
 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 0 = PWM, 1 = LPG
+- 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,row-src-sel-val: select source for rows. One bit is used for each row.
@@ -89,6 +107,19 @@
 - qcom,row-scan-val: select rows for scanning
 - qcom,row-scan-en: row scan enable
 
+Required properties for PWM mode only:
+- qcom,pwm-us: time the pwm device will modulate at (us)
+
+Required properties for LPG mode only:
+- qcom,duty-pcts: array of values for duty cycle to go through
+- qcom,start-idx: starting point duty-pcts array
+
+Optional properties for LPG mode only:
+- qcom,pause-lo: pause at low end of cycle
+- qcom,pause-hi: pause at high end of cycle
+- qcom,ramp-step-ms: step between each cycle (ms)
+- qcom,lut-flags: flags to be used in lut configuration
+
 Example:
 
 	qcom,leds@a200 {
@@ -105,12 +136,30 @@
 		};
 	};
 
+	qcom,leds@a300 {
+		status = "okay";
+		qcom,led_mpp_pwm {
+			label = "mpp";
+			linux,name = "green";
+			linux,default-trigger = "none";
+			qcom,default-state = "off";
+			qcom,max-current = <40>;
+			qcom,current-setting = <5>;
+			qcom,id = <6>;
+			qcom,mode = "pwm";
+			qcom,source-sel = <8>;
+			qcom,mode-ctrl = <0x60>;
+			qcom,pwm-channel = <0>;
+			qcom,pwm-us = <1000>;
+		};
+	};
+
 	qcom,leds@d000 {
 		status = "okay";
 		qcom,rgb_pwm {
 			label = "rgb";
 			linux,name = "led:rgb_red";
-			qcom,mode = <0>;
+			qcom,mode = "pwm";
 			qcom,pwm-channel = <6>;
 			qcom,pwm-us = <1000>;
 			qcom,duty-ms = <20>;
@@ -128,7 +177,7 @@
 		qcom,rgb_lpg {
 			label = "rgb";
 			linux,name = "led:rgb_blue";
-			qcom,mode = <1>;
+			qcom,mode = "lpg";
 			qcom,pwm-channel = <4>;
 			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 7616505..a2503cd 100644
--- a/Documentation/devicetree/bindings/media/video/msm-cci.txt
+++ b/Documentation/devicetree/bindings/media/video/msm-cci.txt
@@ -130,6 +130,10 @@
    property should contain phandle of respective actuator node
 - qcom,led-flash-src : if LED flash is supported by this sensor, this
    property should contain phandle of respective LED flash node
+- qcom,vdd-cx-supply : should contain regulator from which cx voltage is
+    supplied
+- qcom,vdd-cx-name : should contain names of cx regulator
+
 * Qualcomm MSM ACTUATOR
 
 Required properties:
@@ -191,6 +195,8 @@
                qcom,led-flash-src = <&led_flash0>;
                qcom,mount-angle = <90>;
                qcom,sensor-name = "s5k3l1yx";
+               qcom,vdd-cx-supply = <&pm8841_s2>;
+               qcom,vdd-cx-name = "qcom,vdd-cx";
                cam_vdig-supply = <&pm8941_l3>;
                cam_vana-supply = <&pm8941_l17>;
                cam_vio-supply = <&pm8941_lvs3>;
diff --git a/Documentation/devicetree/bindings/power/qpnp-charger.txt b/Documentation/devicetree/bindings/power/qpnp-charger.txt
index 359ee6c..6e125f2 100644
--- a/Documentation/devicetree/bindings/power/qpnp-charger.txt
+++ b/Documentation/devicetree/bindings/power/qpnp-charger.txt
@@ -41,6 +41,8 @@
 					by default. This can then be overriden
 					writing the the module parameter
 					"charging_disabled".
+- qcom,duty-cycle-100p:			Set this property to enable the 100% duty
+					cycle feature.
 - qcom,use-default-batt-values:		Set this flag to force reporting of
 					battery temperature of 250 decidegree
 					Celsius, state of charge to be 50%
@@ -61,8 +63,12 @@
 					"bpd_thm_id". "bpd_thm" selects the temperature
 					pin, "bpd_id" uses the id pin for battery presence
 					detection, "bpd_thm_id" selects both.
-					If the property is not set the hw default will
+					If the property is not set, the temperatue pin will
 					be used.
+- otg-parent-supply			Specify a phandle to a parent supply regulator
+					for the OTG regulator.
+- boost-parent-supply			Specify a phandle to a parent supply regulator
+					for the boost regulator.
 
 Sub node required structure:
 - A qcom,chg node must be a child of an SPMI node that has specified
@@ -85,6 +91,7 @@
 
 			qcom,usb-chgpth:
 			 - usbin-valid
+
 			qcom,chgr:
 			 - chg-done
 			 - chg-failed
@@ -141,6 +148,16 @@
 			 - limit-error:		Limiting error on SMBB boost.
 			 - boost-pwr-ok:	Status of boost power.
 
+Sub node optional properties:
+			qcom,usb-chgpth:
+			 - regulator-name:	A string used as a descriptive name
+						for the OTG regulator.
+			qcom,boost:
+			 - regulator-min-microvolt:	Minimum boost voltage setting.
+			 - regulator-max-microvolt:	Maximum boost voltage setting.
+			 - regulator-name:	A string used as a descriptive name
+						for the boost regulator.
+
 Example:
 	pm8941-chg {
 		spmi-dev-container;
@@ -148,6 +165,9 @@
 		#address-cells = <1>;
 		#size-cells = <1>;
 
+		otg-parent-supply = <&pm8941_boost>;
+		boost-parent-supply = <&foo_parent_reg>;
+
 		qcom,vddmax-mv = <4200>;
 		qcom,vddsafe-mv = <4200>;
 		qcom,vinmin-mv = <4200>;
@@ -218,7 +238,7 @@
 						"batt-pres";
 		};
 
-		qcom,usb-chgpth@1300 {
+		pm8941_chg_otg: qcom,usb-chgpth@1300 {
 			reg = <0x1300 0x100>;
 			interrupts =	<0 0x13 0x0>,
 					<0 0x13 0x1>,
@@ -238,7 +258,7 @@
 						"coarse-det-dc";
 		};
 
-		qcom,boost@1500 {
+		pm8941_chg_boost: qcom,boost@1500 {
 			reg = <0x1500 0x100>;
 			interrupts =	<0x0 0x15 0x0>,
 					<0x0 0x15 0x1>;
@@ -251,3 +271,15 @@
 			reg = <0x1600 0x100>;
 		};
 	};
+
+In regulator specific device tree file:
+
+	&pm8941_chg_boost {
+		regulator-min-microvolt = <5000000>;
+		regulator-max-microvolt = <5000000>;
+		regulator-name = "8941_smbb_boost";
+	};
+
+	&pm8941_chg_otg {
+		regulator-name = "8941_smbb_otg";
+	};
diff --git a/Documentation/devicetree/bindings/regulator/gdsc-regulator.txt b/Documentation/devicetree/bindings/regulator/gdsc-regulator.txt
index f2cfe34..d58fa90 100644
--- a/Documentation/devicetree/bindings/regulator/gdsc-regulator.txt
+++ b/Documentation/devicetree/bindings/regulator/gdsc-regulator.txt
@@ -15,6 +15,8 @@
  - qcom,retain-mems: Presence denotes a hardware requirement to leave the
 		     forced memory retention signals in the core's clock
 		     branch control register asserted.
+ - qcom,skip-logic-collapse: Presence denotes a requirement to leave power to
+                             the core's logic enabled.
 
 Example:
 	gdsc_oxili_gx: qcom,gdsc@fd8c4024 {
diff --git a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
index 74ea2cd..4c6569e 100644
--- a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
+++ b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
@@ -467,6 +467,12 @@
 
 - qcom,headset-jack-type-NO: Adjust GPIO level based on the headset jack type.
 
+
+* APQ8074 ASoC Machine driver
+
+Required properties:
+- compatible : "qcom,apq8074-audio-taiko"
+
 Example:
 
 sound {
@@ -686,6 +692,9 @@
 		 prim-gpio-prim : Primary AUXPCM shares GPIOs with Primary MI2S
 		 prim-gpio-tert : Primary AUXPCM shares GPIOs with Tertiary MI2S
 
+Optional Properties:
+- qcom,us-euro-gpios : GPIO on which gnd/mic swap signal is coming.
+
 Example:
 
 sound {
@@ -697,4 +706,5 @@
 	qcom,prim-auxpcm-gpio-din  = <&msmgpio 65 0>;
 	qcom,prim-auxpcm-gpio-dout = <&msmgpio 66 0>;
 	qcom,prim-auxpcm-gpio-set = "prim-gpio-prim";
+	qcom,cdc-us-euro-gpios = <&msmgpio 69 0>;
 };
diff --git a/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt b/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
new file mode 100644
index 0000000..20468b2
--- /dev/null
+++ b/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
@@ -0,0 +1,16 @@
+* Universal Flash Storage (UFS) Host Controller
+
+UFSHC nodes are defined to describe on-chip UFS host controllers.
+Each UFS controller instance should have its own node.
+
+Required properties:
+- compatible        : compatible list, contains "jedec,ufs-1.1"
+- interrupts        : <interrupt mapping for UFS host controller IRQ>
+- reg               : <registers mapping>
+
+Example:
+	ufshc@0xfc598000 {
+		compatible = "jedec,ufs-1.1";
+		reg = <0xfc598000 0x800>;
+		interrupts = <0 28 0>;
+	};
diff --git a/Documentation/devicetree/bindings/usb/msm-ehci-hsic.txt b/Documentation/devicetree/bindings/usb/msm-ehci-hsic.txt
index 8ce31d9..a3a9935 100644
--- a/Documentation/devicetree/bindings/usb/msm-ehci-hsic.txt
+++ b/Documentation/devicetree/bindings/usb/msm-ehci-hsic.txt
@@ -40,6 +40,15 @@
   DATA GPIO PAD.
 - qcom,phy-sof-workaround : If present then HSIC PHY has h/w BUGs related to
   SOFs. Software workarounds are required for the same.
+- qcom,pool-64-bit-align: If present then the pool's memory will be aligned
+  to 64 bits
+- qcom,enable_hbm: if present host bus manager is enabled.
+- qcom,disable-park-mode: if present park mode is enabled. Park mode enables executing
+  up to 3 usb packets from each QH.
+- hsic,consider-ipa-handshake: If present then hsic low power mode is
+  depend on suitable handshake with the IPA peer.
+- qcom,ahb-async-bridge-bypass: if present AHB ASYNC bridge will be bypassed such that
+  the bridge on the slave AHB is always used.
 
 - Refer to "Documentation/devicetree/bindings/arm/msm/msm_bus.txt" for
   below optional properties:
@@ -71,6 +80,7 @@
 		hsic,ignore-cal-pad-config;
 		hsic,strobe-pad-offset = <0x2050>;
 		hsic,data-pad-offset = <0x2054>;
+		hsic,consider-ipa-handshake;
 
 		qcom,msm-bus,name = "hsic";
 		qcom,msm-bus,num-cases = <2>;
diff --git a/Documentation/devicetree/bindings/usb/msm-hsusb.txt b/Documentation/devicetree/bindings/usb/msm-hsusb.txt
index de1577d..fbe2d25 100644
--- a/Documentation/devicetree/bindings/usb/msm-hsusb.txt
+++ b/Documentation/devicetree/bindings/usb/msm-hsusb.txt
@@ -121,11 +121,6 @@
 
 Optional properties :
 - qcom,usb2-enable-hsphy2: If present, select second PHY for USB operation.
-- qcom,pool-64-bit-align: If present then the pool's memory will be aligned
-  to 64 bits
-- qcom,enable_hbm: if present host bus manager is enabled.
-- qcom,disable-park-mode: if present park mode is enabled. Park mode enables executing
-  up to 3 usb packets from each QH.
 
 Example MSM HSUSB EHCI controller device node :
 	ehci: qcom,ehci-host@f9a55000 {
diff --git a/Documentation/devicetree/bindings/wcnss/wcnss-wlan.txt b/Documentation/devicetree/bindings/wcnss/wcnss-wlan.txt
index c130b26..d0bbc47 100644
--- a/Documentation/devicetree/bindings/wcnss/wcnss-wlan.txt
+++ b/Documentation/devicetree/bindings/wcnss/wcnss-wlan.txt
@@ -18,8 +18,14 @@
 - qcom,iris-vddpa-supply  : regulator to supply RF PA.
 - qcom,iris-vdddig-supply : regulator to supply RF digital(BT/FM).
 - gpios: gpio numbers to configure 5-wire interface of WLAN connectivity
-- qcom,has_48mhz_xo: boolean flag to determine the usage of 24MHz XO from RF
-- qcom,has_pronto_hw: boolean flag to determine the revId of the WLAN subsystem
+- qcom,has-48mhz-xo: boolean flag to determine the usage of 24MHz XO from RF
+- qcom,has-pronto-hw: boolean flag to determine the revId of the WLAN subsystem
+
+Optional properties:
+- qcom,has-autodetect-xo: boolean flag to determine whether Iris XO auto detect
+should be performed during boot up.
+- qcom,wlan-rx-buff-count: WLAN RX buffer count is a configurable value,
+using a smaller count for this buffer will reduce the memory usage.
 
 Example:
 
@@ -41,6 +47,6 @@
 
         gpios = <&msmgpio 36 0>, <&msmgpio 37 0>, <&msmgpio 38 0>,
                 <&msmgpio 39 0>, <&msmgpio 40 0>;
-        qcom,has_48mhz_xo;
-        qcom,has_pronto_hw;
+        qcom,has-48mhz-xo;
+        qcom,has-pronto-hw;
     };
diff --git a/arch/arm/boot/dts/apq8074-dragonboard.dtsi b/arch/arm/boot/dts/apq8074-dragonboard.dtsi
index ea626c8..8e4f368 100644
--- a/arch/arm/boot/dts/apq8074-dragonboard.dtsi
+++ b/arch/arm/boot/dts/apq8074-dragonboard.dtsi
@@ -11,9 +11,10 @@
  */
 
 /include/ "dsi-panel-sharp-qhd-video.dtsi"
+/include/ "msm8974-camera-sensor-dragonboard.dtsi"
 /include/ "msm8974-leds.dtsi"
 
-/ {
+&soc {
 	serial@f991e000 {
 		status = "ok";
 	};
@@ -92,6 +93,7 @@
 	};
 
 	i2c@f9923000 {
+		status = "ok";
 		atmel_mxt_ts@4a {
 			compatible = "atmel,mxt-ts";
 			reg = <0x4a>;
@@ -538,12 +540,12 @@
 				qcom,cs-out-en;
 				qcom,op-fdbck = <1>;
 				qcom,default-state = "on";
-				qcom,max-current = <25>;
+				qcom,max-current = <20>;
 				qcom,ctrl-delay-us = <0>;
 				qcom,boost-curr-lim = <3>;
 				qcom,cp-sel = <0>;
 				qcom,switch-freq = <2>;
-				qcom,ovp-val = <2>;
+				qcom,ovp-val = <1>;
 				qcom,num-strings = <1>;
 				qcom,id = <0>;
 			};
@@ -554,25 +556,25 @@
 &pm8941_chg {
 	status = "ok";
 
-	qcom,chg-charging-disabled;
+	qcom,charging-disabled;
 
-	qcom,chg-chgr@1000 {
+	qcom,chgr@1000 {
 		status = "ok";
 	};
 
-	qcom,chg-buck@1100 {
+	qcom,buck@1100 {
 		status = "ok";
 	};
 
-	qcom,chg-usb-chgpth@1300 {
+	qcom,usb-chgpth@1300 {
 		status = "ok";
 	};
 
-	qcom,chg-dc-chgpth@1400 {
+	qcom,dc-chgpth@1400 {
 		status = "ok";
 	};
 
-	qcom,chg-boost@1500 {
+	qcom,boost@1500 {
 		status = "ok";
 	};
 
diff --git a/arch/arm/boot/dts/apq8074-v1.dtsi b/arch/arm/boot/dts/apq8074-v1.dtsi
new file mode 100644
index 0000000..c4e7b7c
--- /dev/null
+++ b/arch/arm/boot/dts/apq8074-v1.dtsi
@@ -0,0 +1,48 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/*
+ * As a general rule, only version-specific property overrides should be placed
+ * inside this file. However, device definitions should be placed inside the
+ * msm8974.dtsi file.
+ */
+
+/include/ "msm8974-v1.dtsi"
+
+&soc {
+	qcom,qseecom@a700000 {
+		compatible = "qcom,qseecom";
+		reg = <0x0a700000 0x500000>;
+		reg-names = "secapp-region";
+		qcom,disk-encrypt-pipe-pair = <2>;
+		qcom,hlos-ce-hw-instance = <1>;
+		qcom,qsee-ce-hw-instance = <0>;
+		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>;
+	};
+};
+
+&memory_hole {
+	qcom,memblock-remove = <0x0a700000 0x5800000>; /* Address and size of the hole */
+};
+
+&qseecom {
+	status = "disabled";
+};
+
diff --git a/arch/arm/boot/dts/apq8074-v2.dtsi b/arch/arm/boot/dts/apq8074-v2.dtsi
index 9c93ed4..76eb14b 100644
--- a/arch/arm/boot/dts/apq8074-v2.dtsi
+++ b/arch/arm/boot/dts/apq8074-v2.dtsi
@@ -36,6 +36,10 @@
 				<55 512 3936000 393600>,
 				<55 512 3936000 393600>;
 	};
+
+	sound {
+		compatible = "qcom,apq8074-audio-taiko";
+	};
 };
 
 &memory_hole {
diff --git a/arch/arm/boot/dts/apq8084-smp2p.dtsi b/arch/arm/boot/dts/apq8084-smp2p.dtsi
new file mode 100644
index 0000000..b1d21ff
--- /dev/null
+++ b/arch/arm/boot/dts/apq8084-smp2p.dtsi
@@ -0,0 +1,82 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+&soc {
+	qcom,smp2p-adsp {
+		compatible = "qcom,smp2p";
+		reg = <0xf9011008 0x4>;
+		qcom,remote-pid = <2>;
+		qcom,irq-bitmask = <0x400>;
+		interrupts = <0 158 1>;
+	};
+
+	smp2pgpio_smp2p_7_in: qcom,smp2pgpio-smp2p-7-in {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "smp2p";
+		qcom,remote-pid = <7>;
+		qcom,is-inbound;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	qcom,smp2pgpio_test_smp2p_7_in {
+		compatible = "qcom,smp2pgpio_test_smp2p_7_in";
+		gpios = <&smp2pgpio_smp2p_7_in 0 0>;
+	};
+
+	smp2pgpio_smp2p_7_out: qcom,smp2pgpio-smp2p-7-out {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "smp2p";
+		qcom,remote-pid = <7>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	qcom,smp2pgpio_test_smp2p_7_out {
+		compatible = "qcom,smp2pgpio_test_smp2p_7_out";
+		gpios = <&smp2pgpio_smp2p_7_out 0 0>;
+	};
+
+	smp2pgpio_smp2p_2_in: qcom,smp2pgpio-smp2p-2-in {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "smp2p";
+		qcom,remote-pid = <2>;
+		qcom,is-inbound;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	qcom,smp2pgpio_test_smp2p_2_in {
+		compatible = "qcom,smp2pgpio_test_smp2p_2_in";
+		gpios = <&smp2pgpio_smp2p_2_in 0 0>;
+	};
+
+	smp2pgpio_smp2p_2_out: qcom,smp2pgpio-smp2p-2-out {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "smp2p";
+		qcom,remote-pid = <2>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	qcom,smp2pgpio_test_smp2p_2_out {
+		compatible = "qcom,smp2pgpio_test_smp2p_2_out";
+		gpios = <&smp2pgpio_smp2p_2_out 0 0>;
+	};
+};
diff --git a/arch/arm/boot/dts/apq8084.dtsi b/arch/arm/boot/dts/apq8084.dtsi
index 7a1bbef..c74e59d 100644
--- a/arch/arm/boot/dts/apq8084.dtsi
+++ b/arch/arm/boot/dts/apq8084.dtsi
@@ -20,6 +20,7 @@
 };
 
 /include/ "apq8084-ion.dtsi"
+/include/ "apq8084-smp2p.dtsi"
 
 &soc {
 	#address-cells = <1>;
@@ -201,6 +202,51 @@
 		};
 
 	};
+
+	memory_hole: qcom,msm-mem-hole {
+		compatible = "qcom,msm-mem-hole";
+		qcom,memblock-remove = <0x0dc00000 0x2000000>; /* Address and Size of Hole */
+	};
+
+	qcom,ipc-spinlock@fd484000 {
+		compatible = "qcom,ipc-spinlock-sfpb";
+		reg = <0xfd484000 0x400>;
+		qcom,num-locks = <8>;
+	};
+
+	qcom,smem@fa00000 {
+		compatible = "qcom,smem";
+		reg = <0xfa00000 0x200000>,
+			<0xf9011000 0x1000>,
+			<0xfc428000 0x4000>;
+		reg-names = "smem", "irq-reg-base", "aux-mem1";
+
+		qcom,smd-adsp {
+			compatible = "qcom,smd";
+			qcom,smd-edge = <1>;
+			qcom,smd-irq-offset = <0x8>;
+			qcom,smd-irq-bitmask = <0x100>;
+			qcom,pil-string = "adsp";
+			interrupts = <0 156 1>;
+		};
+
+		qcom,smsm-adsp {
+			compatible = "qcom,smsm";
+			qcom,smsm-edge = <1>;
+			qcom,smsm-irq-offset = <0x8>;
+			qcom,smsm-irq-bitmask = <0x200>;
+			interrupts = <0 157 1>;
+		};
+
+		qcom,smd-rpm {
+			compatible = "qcom,smd";
+			qcom,smd-edge = <15>;
+			qcom,smd-irq-offset = <0x8>;
+			qcom,smd-irq-bitmask = <0x1>;
+			interrupts = <0 168 1>;
+			qcom,irq-no-suspend;
+		};
+	};
 };
 
 /include/ "msm-pma8084.dtsi"
diff --git a/arch/arm/mach-msm/clock-mdss-8226.h b/arch/arm/boot/dts/fsm9900-rumi.dts
similarity index 62%
rename from arch/arm/mach-msm/clock-mdss-8226.h
rename to arch/arm/boot/dts/fsm9900-rumi.dts
index dcf4f92..2b380c7 100644
--- a/arch/arm/mach-msm/clock-mdss-8226.h
+++ b/arch/arm/boot/dts/fsm9900-rumi.dts
@@ -10,13 +10,22 @@
  * GNU General Public License for more details.
  */
 
-#ifndef __ARCH_ARM_MACH_MSM_CLOCK_MDSS_8226
-#define __ARCH_ARM_MACH_MSM_CLOCK_MDSS_8226
+/dts-v1/;
 
-extern struct clk_ops clk_ops_dsi_byte_pll;
-extern struct clk_ops clk_ops_dsi_pixel_pll;
+/include/ "fsm9900.dtsi"
 
-void mdss_clk_ctrl_pre_init(struct clk *ahb_clk);
-void mdss_clk_ctrl_post_init(void);
+/ {
+	model = "Qualcomm FSM9900 Rumi";
+	compatible = "qcom,fsm9900-rumi", "qcom,fsm9900", "qcom-sim";
+	qcom,msm-id = <188 0 0>;
 
-#endif /* __ARCH_ARM_MACH_MSM_CLOCK_MDSS_8226 */
+	aliases {
+		serial0 = &uart0;
+	};
+};
+
+&soc {
+	uart0: serial@f9960000 {
+		status = "ok";
+	};
+};
diff --git a/arch/arm/mach-msm/clock-mdss-8226.h b/arch/arm/boot/dts/fsm9900-sim.dts
similarity index 62%
copy from arch/arm/mach-msm/clock-mdss-8226.h
copy to arch/arm/boot/dts/fsm9900-sim.dts
index dcf4f92..050929e 100644
--- a/arch/arm/mach-msm/clock-mdss-8226.h
+++ b/arch/arm/boot/dts/fsm9900-sim.dts
@@ -10,13 +10,23 @@
  * GNU General Public License for more details.
  */
 
-#ifndef __ARCH_ARM_MACH_MSM_CLOCK_MDSS_8226
-#define __ARCH_ARM_MACH_MSM_CLOCK_MDSS_8226
+/dts-v1/;
 
-extern struct clk_ops clk_ops_dsi_byte_pll;
-extern struct clk_ops clk_ops_dsi_pixel_pll;
+/include/ "fsm9900.dtsi"
 
-void mdss_clk_ctrl_pre_init(struct clk *ahb_clk);
-void mdss_clk_ctrl_post_init(void);
+/ {
+	model = "Qualcomm FSM9900 Simulator";
+	compatible = "qcom,fsm9900-sim", "qcom,fsm9900", "qcom-sim";
+	qcom,msm-id = <188 0 0>;
 
-#endif /* __ARCH_ARM_MACH_MSM_CLOCK_MDSS_8226 */
+	aliases {
+		serial0 = &uart0;
+	};
+};
+
+&soc {
+	uart0: serial@f9960000 {
+		interrupts = <0 116 0>;
+		status = "ok";
+	};
+};
diff --git a/arch/arm/boot/dts/fsm9900.dtsi b/arch/arm/boot/dts/fsm9900.dtsi
new file mode 100644
index 0000000..766db36
--- /dev/null
+++ b/arch/arm/boot/dts/fsm9900.dtsi
@@ -0,0 +1,94 @@
+/* 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/ "skeleton64.dtsi"
+
+/ {
+	model = "Qualcomm FSM9900";
+	compatible = "qcom,fsm9900";
+	interrupt-parent = <&intc>;
+	soc: soc { };
+};
+
+&soc {
+	#address-cells = <1>;
+	#size-cells = <1>;
+	ranges = <0 0 0 0xffffffff>;
+
+	intc: interrupt-controller@f9000000 {
+		compatible = "qcom,msm-qgic2";
+		interrupt-controller;
+		#interrupt-cells = <3>;
+		reg = <0xF9000000 0x1000>,
+		      <0xF9002000 0x1000>;
+	};
+
+	msmgpio: gpio@fd510000 {
+		compatible = "qcom,msm-gpio";
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+		reg = <0xfd510000 0x4000>;
+		ngpio = <142>;
+		interrupts = <0 208 0>;
+		qcom,direct-connect-irqs = <5>;
+	};
+
+	timer {
+		compatible = "arm,armv7-timer";
+		interrupts = <1 2 0 1 3 0>;
+		clock-frequency = <19200000>;
+	};
+
+	serial@f9960000 {
+		compatible = "qcom,msm-lsuart-v14";
+		reg = <0xf9960000 0x1000>;
+		interrupts = <0 104 0>;
+		status = "disabled";
+	};
+
+	cpu-pmu {
+		compatible = "qcom,krait-pmu";
+		qcom,irq-is-percpu;
+		interrupts = <1 7 0xf00>;
+	};
+
+	qcom,msm-imem@fe805000 {
+		compatible = "qcom,msm-imem";
+		reg = <0xfe805000 0x1000>; /* Address and size of IMEM */
+	};
+
+	qcom,cache_erp {
+		compatible = "qcom,cache_erp";
+		interrupts = <1 9 0>, <0 2 0>;
+		interrupt-names = "l1_irq", "l2_irq";
+	};
+
+	qcom,cache_dump {
+		compatible = "qcom,cache_dump";
+		qcom,l1-dump-size = <0x100000>;
+		qcom,l2-dump-size = <0x500000>;
+		qcom,memory-reservation-type = "EBI1";
+		qcom,memory-reservation-size = <0x600000>; /* 6M EBI1 buffer */
+	};
+
+	qcom,ion {
+		compatible = "qcom,msm-ion";
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		qcom,ion-heap@30 { /* SYSTEM HEAP */
+			reg = <30>;
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/mpq8092-regulator.dtsi b/arch/arm/boot/dts/mpq8092-regulator.dtsi
index e6866e5..63896e9 100644
--- a/arch/arm/boot/dts/mpq8092-regulator.dtsi
+++ b/arch/arm/boot/dts/mpq8092-regulator.dtsi
@@ -16,6 +16,14 @@
 &spmi_bus {
 
 	qcom,pma8084@1 {
+		pma8084_s1: regulator@1400 {
+			regulator-min-microvolt = <900000>;
+			regulator-max-microvolt = <900000>;
+			qcom,enable-time = <500>;
+			qcom,pull-down-enable = <1>;
+			qcom,system-load = <100000>;
+			status = "okay";
+		};
 
 		pma8084_s3: regulator@1a00 {
 			regulator-min-microvolt = <1350000>;
@@ -53,19 +61,21 @@
 			status = "okay";
 		};
 
-		pma8084_s7: regulator@2600 {
-			regulator-min-microvolt = <900000>;
-			regulator-max-microvolt = <900000>;
+		pma8084_s8: regulator@2900 {
+			regulator-min-microvolt = <1050000>;
+			regulator-max-microvolt = <1050000>;
 			qcom,enable-time = <500>;
 			qcom,pull-down-enable = <1>;
 			status = "okay";
 		};
 
-		pma8084_s8: regulator@2900 {
+		pma8084_s12: regulator@3500 {
 			regulator-min-microvolt = <900000>;
 			regulator-max-microvolt = <900000>;
 			qcom,enable-time = <500>;
 			qcom,pull-down-enable = <1>;
+			regulator-always-on;
+			qcom,system-load = <100000>;
 			status = "okay";
 		};
 
@@ -82,8 +92,8 @@
 
 		pma8084_l2: regulator@4100 {
 			parent-supply = <&pma8084_s3>;
-			regulator-min-microvolt = <900000>;
-			regulator-max-microvolt = <900000>;
+			regulator-min-microvolt = <1000000>;
+			regulator-max-microvolt = <1000000>;
 			qcom,enable-time = <200>;
 			qcom,pull-down-enable = <1>;
 			status = "okay";
@@ -100,23 +110,14 @@
 
 		pma8084_l4: regulator@4300 {
 			parent-supply = <&pma8084_s3>;
-			regulator-min-microvolt = <1000000>;
-			regulator-max-microvolt = <1000000>;
+			regulator-min-microvolt = <1300000>;
+			regulator-max-microvolt = <1300000>;
 			qcom,enable-time = <200>;
 			qcom,pull-down-enable = <1>;
 			status = "okay";
 		};
 
 		pma8084_l6: regulator@4500 {
-			parent-supply = <&pma8084_s5>;
-			regulator-min-microvolt = <1800000>;
-			regulator-max-microvolt = <1800000>;
-			qcom,enable-time = <200>;
-			qcom,pull-down-enable = <1>;
-			status = "okay";
-		};
-
-		pma8084_l8: regulator@4700 {
 			regulator-min-microvolt = <1800000>;
 			regulator-max-microvolt = <1800000>;
 			qcom,enable-time = <200>;
@@ -133,24 +134,6 @@
 		};
 
 		pma8084_l10: regulator@4900 {
-			regulator-min-microvolt = <2000000>;
-			regulator-max-microvolt = <2000000>;
-			qcom,enable-time = <200>;
-			qcom,pull-down-enable = <1>;
-			status = "okay";
-		};
-
-		pma8084_l11: regulator@4a00 {
-			parent-supply = <&pma8084_s3>;
-			regulator-min-microvolt = <1300000>;
-			regulator-max-microvolt = <1300000>;
-			qcom,enable-time = <200>;
-			qcom,pull-down-enable = <1>;
-			status = "okay";
-		};
-
-		pma8084_l12: regulator@4b00 {
-			parent-supply = <&pma8084_s5>;
 			regulator-min-microvolt = <1800000>;
 			regulator-max-microvolt = <1800000>;
 			qcom,enable-time = <200>;
@@ -158,25 +141,41 @@
 			status = "okay";
 		};
 
-		pma8084_l13: regulator@4c00 {
-			regulator-min-microvolt = <1800000>;
-			regulator-max-microvolt = <2950000>;
+		pma8084_l11: regulator@4a00 {
+			parent-supply = <&pma8084_s3>;
+			regulator-min-microvolt = <1200000>;
+			regulator-max-microvolt = <1200000>;
 			qcom,enable-time = <200>;
 			qcom,pull-down-enable = <1>;
 			status = "okay";
 		};
 
+		pma8084_l12: regulator@4b00 {
+			regulator-min-microvolt = <2500000>;
+			regulator-max-microvolt = <2500000>;
+			qcom,enable-time = <200>;
+			qcom,pull-down-enable = <1>;
+			status = "okay";
+		};
+
+		pma8084_l13: regulator@4c00 {
+			regulator-min-microvolt = <2950000>;
+			regulator-max-microvolt = <2950000>;
+			qcom,enable-time = <200>;
+			qcom,pull-down-enable = <1>;
+			regulator-always-on;
+			status = "okay";
+		};
+
 		pma8084_l14: regulator@4d00 {
-			parent-supply = <&pma8084_s5>;
-			regulator-min-microvolt = <1000000>;
-			regulator-max-microvolt = <1000000>;
+			regulator-min-microvolt = <950000>;
+			regulator-max-microvolt = <950000>;
 			qcom,enable-time = <200>;
 			qcom,pull-down-enable = <1>;
 			status = "okay";
 		};
 
 		pma8084_l15: regulator@4e00 {
-			parent-supply = <&pma8084_s5>;
 			regulator-min-microvolt = <1800000>;
 			regulator-max-microvolt = <1800000>;
 			qcom,enable-time = <200>;
@@ -185,7 +184,7 @@
 		};
 
 		pma8084_l16: regulator@4f00 {
-			parent-supply = <&pma8084_s4>;
+			parent-supply = <&pma8084_s5>;
 			regulator-min-microvolt = <750000>;
 			regulator-max-microvolt = <750000>;
 			qcom,enable-time = <200>;
@@ -198,7 +197,6 @@
 			regulator-max-microvolt = <3150000>;
 			qcom,enable-time = <200>;
 			qcom,pull-down-enable = <1>;
-			regulator-always-on;
 			qcom,system-load = <100000>;
 			status = "okay";
 		};
@@ -212,7 +210,7 @@
 		};
 
 		pma8084_l19: regulator@5200 {
-			parent-supply = <&pma8084_s4>;
+			parent-supply = <&pma8084_s5>;
 			regulator-min-microvolt = <1500000>;
 			regulator-max-microvolt = <1500000>;
 			qcom,enable-time = <200>;
@@ -225,6 +223,7 @@
 			regulator-max-microvolt = <2950000>;
 			qcom,enable-time = <200>;
 			qcom,pull-down-enable = <1>;
+			regulator-always-on;
 			status = "okay";
 		};
 
@@ -233,14 +232,16 @@
 			regulator-max-microvolt = <2950000>;
 			qcom,enable-time = <200>;
 			qcom,pull-down-enable = <1>;
+			regulator-always-on;
 			status = "okay";
 		};
 
 		pma8084_l22: regulator@5500 {
-			regulator-min-microvolt = <2500000>;
-			regulator-max-microvolt = <2500000>;
+			regulator-min-microvolt = <1800000>;
+			regulator-max-microvolt = <1800000>;
 			qcom,enable-time = <200>;
 			qcom,pull-down-enable = <1>;
+			regulator-always-on;
 			status = "okay";
 		};
 
@@ -257,6 +258,31 @@
 			regulator-max-microvolt = <3075000>;
 			qcom,enable-time = <200>;
 			qcom,pull-down-enable = <1>;
+			regulator-always-on;
+			status = "okay";
+		};
+
+		pma8084_l25: regulator@5800 {
+			parent-supply = <&pma8084_s5>;
+			regulator-min-microvolt = <2000000>;
+			regulator-max-microvolt = <2000000>;
+			qcom,enable-time = <200>;
+			qcom,pull-down-enable = <1>;
+			status = "okay";
+		};
+		pma8084_l26: regulator@5900 {
+			regulator-min-microvolt = <1800000>;
+			regulator-max-microvolt = <1800000>;
+			qcom,enable-time = <200>;
+			qcom,pull-down-enable = <1>;
+			status = "okay";
+		};
+		pma8084_l27: regulator@5A00 {
+			parent-supply = <&pma8084_s3>;
+			regulator-min-microvolt = <1000000>;
+			regulator-max-microvolt = <1000000>;
+			qcom,enable-time = <200>;
+			qcom,pull-down-enable = <1>;
 			status = "okay";
 		};
 
@@ -274,6 +300,20 @@
 			status = "okay";
 		};
 
+		pma8084_lvs3: regulator@8200 {
+			parent-supply = <&pma8084_s4>;
+			qcom,enable-time = <200>;
+			qcom,pull-down-enable = <1>;
+			status = "okay";
+		};
+
+		pma8084_lvs4: regulator@8300 {
+			parent-supply = <&pma8084_s4>;
+			qcom,enable-time = <200>;
+			qcom,pull-down-enable = <1>;
+			status = "okay";
+		};
+
 		pma8084_mvs1: regulator@8400 {
 			qcom,enable-time = <200>;
 			qcom,pull-down-enable = <1>;
diff --git a/arch/arm/boot/dts/mpq8092.dtsi b/arch/arm/boot/dts/mpq8092.dtsi
index 4dea9e0..946b54d 100644
--- a/arch/arm/boot/dts/mpq8092.dtsi
+++ b/arch/arm/boot/dts/mpq8092.dtsi
@@ -130,6 +130,15 @@
 		reg = <0xfc580000 0x17c>;
 		interrupts = <0 243 0>;
 	};
+
+	qcom,wdt@f9017000 {
+		compatible = "qcom,msm-watchdog";
+		reg = <0xf9017000 0x1000>;
+		interrupts = <0 3 0>, <0 4 0>;
+		qcom,bark-time = <11000>;
+		qcom,pet-time = <10000>;
+		qcom,ipi-ping;
+	};
 };
 
 &gdsc_venus {
@@ -144,10 +153,6 @@
 	status = "ok";
 };
 
-&gdsc_vfe {
-	status = "ok";
-};
-
 &gdsc_oxili_gx {
 	status = "ok";
 };
diff --git a/arch/arm/boot/dts/msm-iommu-v0.dtsi b/arch/arm/boot/dts/msm-iommu-v0.dtsi
index 35829a7..65075e5 100644
--- a/arch/arm/boot/dts/msm-iommu-v0.dtsi
+++ b/arch/arm/boot/dts/msm-iommu-v0.dtsi
@@ -27,6 +27,13 @@
 						0x10
 						0x12
 						0x80>;
+		qcom,msm-bus,name = "lpass_ebi";
+		qcom,msm-bus,num-cases = <2>;
+		qcom,msm-bus,active-only;
+		qcom,msm-bus,num-paths = <1>;
+		qcom,msm-bus,vectors-KBps =
+				<11 512 0 0>,
+				<11 512 0 1000>;
 		status = "disabled";
 
 		lpass_q6_fw: qcom,iommu-ctx@fd000000 {
@@ -78,6 +85,14 @@
 						0x10
 						0x12
 						0x80>;
+		qcom,msm-bus,name = "copss_ebi";
+		qcom,msm-bus,num-cases = <2>;
+		qcom,msm-bus,active-only;
+		qcom,msm-bus,num-paths = <1>;
+		qcom,msm-bus,vectors-KBps =
+				<88 512 0 0>,
+				<88 512 0 1000>;
+
 		status = "disabled";
 
 		qcom,iommu-ctx@fd010000 {
@@ -161,6 +176,13 @@
 						0x10
 						0x12
 						0x80>;
+		qcom,msm-bus,name = "mdpe_ebi";
+		qcom,msm-bus,num-cases = <2>;
+		qcom,msm-bus,active-only;
+		qcom,msm-bus,num-paths = <1>;
+		qcom,msm-bus,vectors-KBps =
+				<92 512 0 0>,
+				<92 512 0 1000>;
 		status = "disabled";
 
 		qcom,iommu-ctx@fd860000 {
@@ -196,6 +218,13 @@
 						0x10
 						0x12
 						0x80>;
+		qcom,msm-bus,name = "mdps_ebi";
+		qcom,msm-bus,num-cases = <2>;
+		qcom,msm-bus,active-only;
+		qcom,msm-bus,num-paths = <1>;
+		qcom,msm-bus,vectors-KBps =
+				<22 512 0 0>,
+				<22 512 0 1000>;
 		status = "disabled";
 
 		qcom,iommu-ctx@fd870000 {
@@ -232,6 +261,13 @@
 						0x10
 						0x12
 						0x80>;
+		qcom,msm-bus,name = "gfx_ebi";
+		qcom,msm-bus,num-cases = <2>;
+		qcom,msm-bus,active-only;
+		qcom,msm-bus,num-paths = <1>;
+		qcom,msm-bus,vectors-KBps =
+				<26 512 0 0>,
+				<26 512 0 1000>;
 		status = "disabled";
 
 		qcom,iommu-ctx@fd880000 {
@@ -277,6 +313,13 @@
 						0x10
 						0x12
 						0x80>;
+		qcom,msm-bus,name = "vfe_ebi";
+		qcom,msm-bus,num-cases = <2>;
+		qcom,msm-bus,active-only;
+		qcom,msm-bus,num-paths = <1>;
+		qcom,msm-bus,vectors-KBps =
+				<29 512 0 0>,
+				<29 512 0 1000>;
 		status = "disabled";
 
 		qcom,iommu-ctx@fd890000 {
diff --git a/arch/arm/boot/dts/msm-iommu-v1.dtsi b/arch/arm/boot/dts/msm-iommu-v1.dtsi
index ab46861..d497259 100644
--- a/arch/arm/boot/dts/msm-iommu-v1.dtsi
+++ b/arch/arm/boot/dts/msm-iommu-v1.dtsi
@@ -183,7 +183,7 @@
 		qcom,iommu-ctx@fd931000 {
 			compatible = "qcom,msm-smmu-v1-ctx";
 			reg = <0xfd931000 0x1000>;
-			interrupts = <0 47 0>;
+			interrupts = <0 47 0>, <0 46 0>;
 			qcom,iommu-ctx-sids = <1>;
 			label = "mdp_1";
 			qcom,secure-context;
@@ -192,7 +192,7 @@
 		qcom,iommu-ctx@fd932000 {
 			compatible = "qcom,msm-smmu-v1-ctx";
 			reg = <0xfd932000 0x1000>;
-			interrupts = <0 47 0>;
+			interrupts = <0 47 0>, <0 46 0>;
 			qcom,iommu-ctx-sids = <>;
 			label = "mdp_2";
 			qcom,secure-context;
@@ -295,7 +295,7 @@
 		venus_cp: qcom,iommu-ctx@fdc8d000 {
 			compatible = "qcom,msm-smmu-v1-ctx";
 			reg = <0xfdc8d000 0x1000>;
-			interrupts = <0 42 0>;
+			interrupts = <0 42 0>, <0 43 0>;
 			qcom,iommu-ctx-sids = <0x80 0x81 0x82 0x83 0x84 0x85>;
 			label = "venus_cp";
 			qcom,secure-context;
@@ -304,7 +304,7 @@
 		venus_fw: qcom,iommu-ctx@fdc8e000 {
 			compatible = "qcom,msm-smmu-v1-ctx";
 			reg = <0xfdc8e000 0x1000>;
-			interrupts = <0 42 0>;
+			interrupts = <0 42 0>, <0 43 0>;
 			qcom,iommu-ctx-sids = <0xc0 0xc6>;
 			label = "venus_fw";
 			qcom,secure-context;
diff --git a/arch/arm/boot/dts/msm-pm8226.dtsi b/arch/arm/boot/dts/msm-pm8226.dtsi
index d6d919b..fe0000a 100644
--- a/arch/arm/boot/dts/msm-pm8226.dtsi
+++ b/arch/arm/boot/dts/msm-pm8226.dtsi
@@ -125,7 +125,7 @@
 
 			};
 
-			qcom,usb-chgpth@1300 {
+			pm8226_chg_otg: qcom,usb-chgpth@1300 {
 				status = "disabled";
 				reg = <0x1300 0x100>;
 				interrupts =	<0 0x13 0x0>,
@@ -137,7 +137,7 @@
 							"chg-gone";
 			};
 
-			qcom,boost@1500 {
+			pm8226_chg_boost: qcom,boost@1500 {
 				status = "disabled";
 				reg = <0x1500 0x100>;
 				interrupts =	<0x0 0x15 0x0>,
@@ -211,6 +211,18 @@
 			label = "mpp";
 		};
 
+		qcom,leds@a300 {
+			compatible = "qcom,leds-qpnp";
+			reg = <0xa300 0x100>;
+			label = "mpp";
+		};
+
+		qcom,leds@a500 {
+			compatible = "qcom,leds-qpnp";
+			reg = <0xa500 0x100>;
+			label = "mpp";
+		};
+
 		pm8226_gpios: gpios {
 			spmi-dev-container;
 			compatible = "qcom,qpnp-pin";
@@ -403,6 +415,15 @@
 			qcom,adc-vdd-reference = <1800>;
 		};
 
+		qcom,temp-alarm@2400 {
+			compatible = "qcom,qpnp-temp-alarm";
+			reg = <0x2400 0x100>;
+			interrupts = <0x0 0x24 0x0>;
+			label = "pm8226_tz";
+			qcom,channel-num = <8>;
+			qcom,threshold-set = <0>;
+		};
+
 		qcom,pm8226_rtc {
 			spmi-dev-container;
 			compatible = "qcom,qpnp-rtc";
diff --git a/arch/arm/boot/dts/msm-pm8941.dtsi b/arch/arm/boot/dts/msm-pm8941.dtsi
index 34ea33d..85a5608 100644
--- a/arch/arm/boot/dts/msm-pm8941.dtsi
+++ b/arch/arm/boot/dts/msm-pm8941.dtsi
@@ -247,7 +247,7 @@
 
 			};
 
-			qcom,usb-chgpth@1300 {
+			pm8941_chg_otg: qcom,usb-chgpth@1300 {
 				status = "disabled";
 				reg = <0x1300 0x100>;
 				interrupts =	<0 0x13 0x0>,
@@ -269,7 +269,7 @@
 							"dcin-valid";
 			};
 
-			qcom,boost@1500 {
+			pm8941_chg_boost: qcom,boost@1500 {
 				status = "disabled";
 				reg = <0x1500 0x100>;
 				interrupts =	<0x0 0x15 0x0>,
diff --git a/arch/arm/boot/dts/msm8226-cdp.dts b/arch/arm/boot/dts/msm8226-cdp.dts
index b96a9e1..da517eb 100644
--- a/arch/arm/boot/dts/msm8226-cdp.dts
+++ b/arch/arm/boot/dts/msm8226-cdp.dts
@@ -12,8 +12,7 @@
 
 /dts-v1/;
 /include/ "msm8226.dtsi"
-/include/ "dsi-panel-nt35590-720p-video.dtsi"
-/include/ "msm8226-camera-sensor-cdp.dtsi"
+/include/ "msm8226-cdp.dtsi"
 
 / {
 	model = "Qualcomm MSM 8226 CDP";
@@ -23,335 +22,3 @@
 		      <159 1 0>,
 		      <198 1 0>;
 };
-
-&soc {
-	serial@f991f000 {
-		status = "ok";
-	};
-
-	qcom,mdss_dsi_nt35590_720p_video {
-		status = "ok";
-	};
-
-	i2c@f9927000 { /* BLSP1 QUP5 */
-		synaptics@20 {
-			compatible = "synaptics,rmi4";
-			reg = <0x20>;
-			interrupt-parent = <&msmgpio>;
-			interrupts = <17 0x2008>;
-			vdd-supply = <&pm8226_l19>;
-			vcc_i2c-supply = <&pm8226_lvs1>;
-			synaptics,reset-gpio = <&msmgpio 16 0x00>;
-			synaptics,irq-gpio = <&msmgpio 17 0x2008>;
-			synaptics,button-map = <139 102 158>;
-			synaptics,i2c-pull-up;
-			synaptics,reg-en;
-		};
-	};
-
-	gpio_keys {
-		compatible = "gpio-keys";
-		input-name = "gpio-keys";
-
-		camera_focus {
-			label = "camera_focus";
-			gpios = <&msmgpio 108 0x1>;
-			linux,input-type = <1>;
-			linux,code = <0x210>;
-			gpio-key,wakeup;
-			debounce-interval = <15>;
-		};
-
-		camera_snapshot {
-			label = "camera_snapshot";
-			gpios = <&msmgpio 107 0x1>;
-			linux,input-type = <1>;
-			linux,code = <0x2fe>;
-			gpio-key,wakeup;
-			debounce-interval = <15>;
-		};
-
-		vol_up {
-			label = "volume_up";
-			gpios = <&msmgpio 106 0x1>;
-			linux,input-type = <1>;
-			linux,code = <115>;
-			gpio-key,wakeup;
-			debounce-interval = <15>;
-		};
-	};
-
-	spi@f9923000 {
-		ethernet-switch@3 {
-			compatible = "micrel,ks8851";
-			reg = <3>;
-			interrupt-parent = <&msmgpio>;
-			interrupts = <0 115 0>;
-			spi-max-frequency = <4800000>;
-			rst-gpio = <&msmgpio 114 0>;
-			vdd-io-supply = <&pm8226_lvs1>;
-			vdd-phy-supply = <&pm8226_lvs1>;
-		};
-	};
-
-	sound {
-		qcom,audio-routing =
-			"RX_BIAS", "MCLK",
-			"LDO_H", "MCLK",
-			"SPK_OUT", "MCLK",
-			"SPK_OUT", "EXT_VDD_SPKR",
-			"AMIC1", "MIC BIAS1 Internal1",
-			"MIC BIAS1 Internal1", "Handset Mic",
-			"AMIC2", "MIC BIAS2 External",
-			"MIC BIAS2 External", "Headset Mic",
-			"AMIC4", "MIC BIAS2 External",
-			"MIC BIAS2 External", "ANCRight Headset Mic",
-			"AMIC5", "MIC BIAS2 External",
-			"MIC BIAS2 External", "ANCLeft Headset Mic",
-			"DMIC1", "MIC BIAS1 External",
-			"MIC BIAS1 External", "Digital Mic1",
-			"DMIC2", "MIC BIAS1 External",
-			"MIC BIAS1 External", "Digital Mic2",
-			"DMIC3", "MIC BIAS3 External",
-			"MIC BIAS3 External", "Digital Mic3",
-			"DMIC4", "MIC BIAS3 External",
-			"MIC BIAS3 External", "Digital Mic4";
-
-		qcom,cdc-mclk-gpios = <&pm8226_gpios 1 0>;
-		qcom,cdc-vdd-spkr-gpios = <&pm8226_gpios 2 0>;
-		qcom,headset-jack-type-NO;
-	};
-};
-
-&sdcc1 {
-	vdd-supply = <&pm8226_l17>;
-	qcom,vdd-always-on;
-	qcom,vdd-lpm-sup;
-	qcom,vdd-voltage-level = <2950000 2950000>;
-	qcom,vdd-current-level = <800 500000>;
-
-	vdd-io-supply = <&pm8226_l6>;
-	qcom,vdd-io-always-on;
-	qcom,vdd-io-voltage-level = <1800000 1800000>;
-	qcom,vdd-io-current-level = <250 154000>;
-
-	qcom,pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
-	qcom,pad-pull-off = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
-	qcom,pad-drv-on = <0x4 0x4 0x4>; /* 10mA, 10mA, 10mA */
-	qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
-
-	qcom,clk-rates = <400000 25000000 50000000 100000000 200000000>;
-	qcom,sup-voltages = <2950 2950>;
-
-	qcom,bus-speed-mode = "HS200_1p8v", "DDR_1p8v";
-	qcom,nonremovable;
-
-	status = "disabled";
-};
-
-&sdhc_1 {
-	vdd-supply = <&pm8226_l17>;
-	qcom,vdd-always-on;
-	qcom,vdd-lpm-sup;
-	qcom,vdd-voltage-level = <2950000 2950000>;
-	qcom,vdd-current-level = <800 500000>;
-
-	vdd-io-supply = <&pm8226_l6>;
-	qcom,vdd-io-always-on;
-	qcom,vdd-io-voltage-level = <1800000 1800000>;
-	qcom,vdd-io-current-level = <250 154000>;
-
-	qcom,pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
-	qcom,pad-pull-off = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
-	qcom,pad-drv-on = <0x4 0x4 0x4>; /* 10mA, 10mA, 10mA */
-	qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
-
-	qcom,clk-rates = <400000 25000000 50000000 100000000 200000000>;
-	qcom,bus-speed-mode = "HS200_1p8v", "DDR_1p8v";
-	qcom,nonremovable;
-
-	status = "ok";
-};
-
-&sdcc2 {
-	vdd-supply = <&pm8226_l18>;
-	qcom,vdd-voltage-level = <2950000 2950000>;
-	qcom,vdd-current-level = <9000 800000>;
-
-	vdd-io-supply = <&pm8226_l21>;
-	qcom,vdd-io-always-on;
-	qcom,vdd-io-lpm-sup;
-	qcom,vdd-io-voltage-level = <1800000 2950000>;
-	qcom,vdd-io-current-level = <6 22000>;
-
-	qcom,pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
-	qcom,pad-pull-off = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
-	qcom,pad-drv-on = <0x4 0x4 0x4>; /* 10mA, 10mA, 10mA */
-	qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
-
-	qcom,clk-rates = <400000 25000000 50000000 100000000 200000000>;
-	qcom,sup-voltages = <2950 2950>;
-
-	qcom,xpc;
-	qcom,bus-speed-mode = "SDR12", "SDR25", "SDR50", "DDR50", "SDR104";
-	qcom,current-limit = <600>;
-
-	#address-cells = <0>;
-	interrupt-parent = <&sdcc2>;
-	interrupts = <0 1 2>;
-	#interrupt-cells = <1>;
-	interrupt-map-mask = <0xffffffff>;
-	interrupt-map = <0 &intc 0 125 0
-			1 &intc 0 220 0
-			2 &msmgpio 38 0x3>;
-	interrupt-names = "core_irq", "bam_irq", "status_irq";
-	cd-gpios = <&msmgpio 38 0x1>;
-
-	status = "disabled";
-};
-
-&sdhc_2 {
-	vdd-supply = <&pm8226_l18>;
-	qcom,vdd-voltage-level = <2950000 2950000>;
-	qcom,vdd-current-level = <9000 800000>;
-
-	vdd-io-supply = <&pm8226_l21>;
-	qcom,vdd-io-always-on;
-	qcom,vdd-io-lpm-sup;
-	qcom,vdd-io-voltage-level = <1800000 2950000>;
-	qcom,vdd-io-current-level = <6 22000>;
-
-	qcom,pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
-	qcom,pad-pull-off = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
-	qcom,pad-drv-on = <0x4 0x4 0x4>; /* 10mA, 10mA, 10mA */
-	qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
-
-	qcom,clk-rates = <400000 25000000 50000000 100000000 200000000>;
-
-	#address-cells = <0>;
-	interrupt-parent = <&sdhc_2>;
-	interrupts = <0 1 2>;
-	#interrupt-cells = <1>;
-	interrupt-map-mask = <0xffffffff>;
-	interrupt-map = <0 &intc 0 125 0
-			1 &intc 0 221 0
-			2 &msmgpio 38 0x3>;
-	interrupt-names = "hc_irq", "pwr_irq", "status_irq";
-	cd-gpios = <&msmgpio 38 0x1>;
-
-	status = "ok";
-};
-
-&spmi_bus {
-	qcom,pm8226@0 {
-		qcom,leds@a100 {
-			status = "okay";
-			qcom,led_mpp_2 {
-				label = "mpp";
-				linux,name = "button-backlight";
-				linux,default-trigger = "none";
-				qcom,default-state = "off";
-				qcom,max-current = <40>;
-				qcom,current-setting = <5>;
-				qcom,id = <6>;
-				qcom,mode = <2>;
-				qcom,source-sel = <1>;
-				qcom,mode-ctrl = <0x60>;
-			};
-		};
-	};
-
-	qcom,pm8226@1 {
-		qcom,leds@d800 {
-			status = "okay";
-			qcom,wled_0 {
-				label = "wled";
-				linux,name = "wled:backlight";
-				linux,default-trigger = "bkl-trigger";
-				qcom,cs-out-en;
-				qcom,op-fdbck = <1>;
-				qcom,default-state = "on";
-				qcom,max-current = <25>;
-				qcom,ctrl-delay-us = <0>;
-				qcom,boost-curr-lim = <3>;
-				qcom,cp-sel = <0>;
-				qcom,switch-freq = <2>;
-				qcom,ovp-val = <0>;
-				qcom,num-strings = <1>;
-				qcom,id = <0>;
-			};
-		};
-	};
-};
-
-&pm8226_gpios {
-	gpio@c000 { /* GPIO 1 */
-		/* XO_PMIC_CDC_MCLK enable for tapan codec */
-		qcom,mode = <1>;		/* Digital output */
-		qcom,output-type = <0>;	/* CMOS logic */
-		qcom,pull = <5>;		/* QPNP_PIN_PULL_NO*/
-		qcom,vin-sel = <3>;		/* QPNP_PIN_VIN3 */
-		qcom,out-strength = <3>;/* QPNP_PIN_OUT_STRENGTH_HIGH */
-		qcom,src-sel = <2>;		/* QPNP_PIN_SEL_FUNC_1 */
-		qcom,master-en = <1>;	/* Enable GPIO */
-	};
-
-	gpio@c100 { /* GPIO 2 */
-		qcom,mode = <1>;
-		qcom,output-type = <0>;
-		qcom,pull = <5>;
-		qcom,vin-sel = <3>;
-		qcom,out-strength = <3>;
-		qcom,src-sel = <2>;
-		qcom,master-en = <1>;
-	};
-
-	gpio@c200 { /* GPIO 3 */
-	};
-
-	gpio@c300 { /* GPIO 4 */
-	};
-
-	gpio@c400 { /* GPIO 5 */
-	};
-
-	gpio@c500 { /* GPIO 6 */
-	};
-
-	gpio@c600 { /* GPIO 7 */
-	};
-
-	gpio@c700 { /* GPIO 8 */
-	};
-};
-
-&pm8226_mpps {
-	mpp@a000 { /* MPP 1 */
-	};
-
-	mpp@a100 { /* MPP 2 */
-	};
-
-	mpp@a200 { /* MPP 3 */
-	};
-
-	mpp@a300 { /* MPP 4 */
-	};
-
-	mpp@a400 { /* MPP 5 */
-	};
-
-	mpp@a500 { /* MPP 6 */
-	};
-
-	mpp@a600 { /* MPP 7 */
-	};
-
-	mpp@a700 { /* MPP 8 */
-	};
-};
-
-&pm8226_chg {
-	qcom,charging-disabled;
-	qcom,use-default-batt-values;
-};
diff --git a/arch/arm/boot/dts/msm8226-cdp.dtsi b/arch/arm/boot/dts/msm8226-cdp.dtsi
new file mode 100644
index 0000000..01677ff
--- /dev/null
+++ b/arch/arm/boot/dts/msm8226-cdp.dtsi
@@ -0,0 +1,386 @@
+/* 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/ "dsi-panel-nt35590-720p-video.dtsi"
+/include/ "msm8226-camera-sensor-cdp.dtsi"
+
+&soc {
+	serial@f991f000 {
+		status = "ok";
+	};
+
+	qcom,mdss_dsi_nt35590_720p_video {
+		status = "ok";
+	};
+
+	i2c@f9927000 { /* BLSP1 QUP5 */
+		synaptics@20 {
+			compatible = "synaptics,rmi4";
+			reg = <0x20>;
+			interrupt-parent = <&msmgpio>;
+			interrupts = <17 0x2008>;
+			vdd-supply = <&pm8226_l19>;
+			vcc_i2c-supply = <&pm8226_lvs1>;
+			synaptics,reset-gpio = <&msmgpio 16 0x00>;
+			synaptics,irq-gpio = <&msmgpio 17 0x2008>;
+			synaptics,button-map = <139 102 158>;
+			synaptics,i2c-pull-up;
+			synaptics,reg-en;
+		};
+	};
+
+	gpio_keys {
+		compatible = "gpio-keys";
+		input-name = "gpio-keys";
+
+		camera_focus {
+			label = "camera_focus";
+			gpios = <&msmgpio 108 0x1>;
+			linux,input-type = <1>;
+			linux,code = <0x210>;
+			gpio-key,wakeup;
+			debounce-interval = <15>;
+		};
+
+		camera_snapshot {
+			label = "camera_snapshot";
+			gpios = <&msmgpio 107 0x1>;
+			linux,input-type = <1>;
+			linux,code = <0x2fe>;
+			gpio-key,wakeup;
+			debounce-interval = <15>;
+		};
+
+		vol_up {
+			label = "volume_up";
+			gpios = <&msmgpio 106 0x1>;
+			linux,input-type = <1>;
+			linux,code = <115>;
+			gpio-key,wakeup;
+			debounce-interval = <15>;
+		};
+	};
+
+	spi@f9923000 {
+		ethernet-switch@3 {
+			compatible = "micrel,ks8851";
+			reg = <3>;
+			interrupt-parent = <&msmgpio>;
+			interrupts = <0 115 0>;
+			spi-max-frequency = <4800000>;
+			rst-gpio = <&msmgpio 114 0>;
+			vdd-io-supply = <&pm8226_lvs1>;
+			vdd-phy-supply = <&pm8226_lvs1>;
+		};
+	};
+
+	sound {
+		qcom,audio-routing =
+			"RX_BIAS", "MCLK",
+			"LDO_H", "MCLK",
+			"SPK_OUT", "MCLK",
+			"SPK_OUT", "EXT_VDD_SPKR",
+			"AMIC1", "MIC BIAS1 Internal1",
+			"MIC BIAS1 Internal1", "Handset Mic",
+			"AMIC2", "MIC BIAS2 External",
+			"MIC BIAS2 External", "Headset Mic",
+			"AMIC4", "MIC BIAS2 External",
+			"MIC BIAS2 External", "ANCRight Headset Mic",
+			"AMIC5", "MIC BIAS2 External",
+			"MIC BIAS2 External", "ANCLeft Headset Mic",
+			"DMIC1", "MIC BIAS1 External",
+			"MIC BIAS1 External", "Digital Mic1",
+			"DMIC2", "MIC BIAS1 External",
+			"MIC BIAS1 External", "Digital Mic2",
+			"DMIC3", "MIC BIAS3 External",
+			"MIC BIAS3 External", "Digital Mic3",
+			"DMIC4", "MIC BIAS3 External",
+			"MIC BIAS3 External", "Digital Mic4";
+
+		qcom,cdc-mclk-gpios = <&pm8226_gpios 1 0>;
+		qcom,cdc-vdd-spkr-gpios = <&pm8226_gpios 2 0>;
+		qcom,headset-jack-type-NO;
+	};
+};
+
+&sdcc1 {
+	vdd-supply = <&pm8226_l17>;
+	qcom,vdd-always-on;
+	qcom,vdd-lpm-sup;
+	qcom,vdd-voltage-level = <2950000 2950000>;
+	qcom,vdd-current-level = <800 500000>;
+
+	vdd-io-supply = <&pm8226_l6>;
+	qcom,vdd-io-always-on;
+	qcom,vdd-io-voltage-level = <1800000 1800000>;
+	qcom,vdd-io-current-level = <250 154000>;
+
+	qcom,pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+	qcom,pad-pull-off = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+	qcom,pad-drv-on = <0x4 0x4 0x4>; /* 10mA, 10mA, 10mA */
+	qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
+
+	qcom,clk-rates = <400000 25000000 50000000 100000000 200000000>;
+	qcom,sup-voltages = <2950 2950>;
+
+	qcom,bus-speed-mode = "HS200_1p8v", "DDR_1p8v";
+	qcom,nonremovable;
+
+	status = "disabled";
+};
+
+&sdhc_1 {
+	vdd-supply = <&pm8226_l17>;
+	qcom,vdd-always-on;
+	qcom,vdd-lpm-sup;
+	qcom,vdd-voltage-level = <2950000 2950000>;
+	qcom,vdd-current-level = <800 500000>;
+
+	vdd-io-supply = <&pm8226_l6>;
+	qcom,vdd-io-always-on;
+	qcom,vdd-io-voltage-level = <1800000 1800000>;
+	qcom,vdd-io-current-level = <250 154000>;
+
+	qcom,pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+	qcom,pad-pull-off = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+	qcom,pad-drv-on = <0x4 0x4 0x4>; /* 10mA, 10mA, 10mA */
+	qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
+
+	qcom,clk-rates = <400000 25000000 50000000 100000000 200000000>;
+	qcom,bus-speed-mode = "HS200_1p8v", "DDR_1p8v";
+	qcom,nonremovable;
+
+	status = "ok";
+};
+
+&sdcc2 {
+	vdd-supply = <&pm8226_l18>;
+	qcom,vdd-voltage-level = <2950000 2950000>;
+	qcom,vdd-current-level = <9000 800000>;
+
+	vdd-io-supply = <&pm8226_l21>;
+	qcom,vdd-io-always-on;
+	qcom,vdd-io-lpm-sup;
+	qcom,vdd-io-voltage-level = <1800000 2950000>;
+	qcom,vdd-io-current-level = <6 22000>;
+
+	qcom,pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+	qcom,pad-pull-off = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+	qcom,pad-drv-on = <0x4 0x4 0x4>; /* 10mA, 10mA, 10mA */
+	qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
+
+	qcom,clk-rates = <400000 25000000 50000000 100000000 200000000>;
+	qcom,sup-voltages = <2950 2950>;
+
+	qcom,xpc;
+	qcom,bus-speed-mode = "SDR12", "SDR25", "SDR50", "DDR50", "SDR104";
+	qcom,current-limit = <600>;
+
+	#address-cells = <0>;
+	interrupt-parent = <&sdcc2>;
+	interrupts = <0 1 2>;
+	#interrupt-cells = <1>;
+	interrupt-map-mask = <0xffffffff>;
+	interrupt-map = <0 &intc 0 125 0
+			1 &intc 0 220 0
+			2 &msmgpio 38 0x3>;
+	interrupt-names = "core_irq", "bam_irq", "status_irq";
+	cd-gpios = <&msmgpio 38 0x1>;
+
+	status = "disabled";
+};
+
+&sdhc_2 {
+	vdd-supply = <&pm8226_l18>;
+	qcom,vdd-voltage-level = <2950000 2950000>;
+	qcom,vdd-current-level = <9000 800000>;
+
+	vdd-io-supply = <&pm8226_l21>;
+	qcom,vdd-io-always-on;
+	qcom,vdd-io-lpm-sup;
+	qcom,vdd-io-voltage-level = <1800000 2950000>;
+	qcom,vdd-io-current-level = <6 22000>;
+
+	qcom,pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+	qcom,pad-pull-off = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+	qcom,pad-drv-on = <0x4 0x4 0x4>; /* 10mA, 10mA, 10mA */
+	qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
+
+	qcom,clk-rates = <400000 25000000 50000000 100000000 200000000>;
+
+	#address-cells = <0>;
+	interrupt-parent = <&sdhc_2>;
+	interrupts = <0 1 2>;
+	#interrupt-cells = <1>;
+	interrupt-map-mask = <0xffffffff>;
+	interrupt-map = <0 &intc 0 125 0
+			1 &intc 0 221 0
+			2 &msmgpio 38 0x3>;
+	interrupt-names = "hc_irq", "pwr_irq", "status_irq";
+	cd-gpios = <&msmgpio 38 0x1>;
+
+	status = "ok";
+};
+
+&spmi_bus {
+	qcom,pm8226@0 {
+		qcom,leds@a100 {
+			status = "okay";
+			qcom,led_mpp_2 {
+				label = "mpp";
+				linux,name = "button-backlight";
+				linux,default-trigger = "none";
+				qcom,default-state = "off";
+				qcom,max-current = <40>;
+				qcom,current-setting = <5>;
+				qcom,id = <6>;
+				qcom,mode = "manual";
+				qcom,source-sel = <1>;
+				qcom,mode-ctrl = <0x60>;
+			};
+		};
+
+		qcom,leds@a300 {
+			status = "okay";
+			qcom,led_mpp_4 {
+				label = "mpp";
+				linux,name = "green";
+				linux,default-trigger = "none";
+				qcom,default-state = "off";
+				qcom,max-current = <40>;
+				qcom,current-setting = <5>;
+				qcom,id = <6>;
+				qcom,mode = "lpg";
+				qcom,source-sel = <8>;
+				qcom,mode-ctrl = <0x60>;
+				qcom,pwm-channel = <0>;
+				qcom,start-idx = <1>;
+				qcom,duty-pcts = [00 00 00 00 64
+						 64 00 00 00 00];
+			};
+		};
+
+		qcom,leds@a500 {
+			status = "okay";
+			qcom,led_mpp_6 {
+				label = "mpp";
+				linux,name = "red";
+				linux,default-trigger = "none";
+				qcom,default-state = "off";
+				qcom,max-current = <40>;
+				qcom,current-setting = <5>;
+				qcom,id = <6>;
+				qcom,mode-ctrl = <0x60>;
+				qcom,source-sel = <10>;
+				qcom,mode = "lpg";
+				qcom,pwm-channel = <5>;
+				qcom,start-idx = <1>;
+				qcom,duty-pcts = [00 00 00 00 64
+						 64 00 00 00 00];
+			};
+		};
+	};
+
+	qcom,pm8226@1 {
+		qcom,leds@d800 {
+			status = "okay";
+			qcom,wled_0 {
+				label = "wled";
+				linux,name = "wled:backlight";
+				linux,default-trigger = "bkl-trigger";
+				qcom,cs-out-en;
+				qcom,op-fdbck = <1>;
+				qcom,default-state = "on";
+				qcom,max-current = <25>;
+				qcom,ctrl-delay-us = <0>;
+				qcom,boost-curr-lim = <3>;
+				qcom,cp-sel = <0>;
+				qcom,switch-freq = <2>;
+				qcom,ovp-val = <0>;
+				qcom,num-strings = <1>;
+				qcom,id = <0>;
+			};
+		};
+	};
+};
+
+&pm8226_gpios {
+	gpio@c000 { /* GPIO 1 */
+		/* XO_PMIC_CDC_MCLK enable for tapan codec */
+		qcom,mode = <1>;		/* Digital output */
+		qcom,output-type = <0>;	/* CMOS logic */
+		qcom,pull = <5>;		/* QPNP_PIN_PULL_NO*/
+		qcom,vin-sel = <3>;		/* QPNP_PIN_VIN3 */
+		qcom,out-strength = <3>;/* QPNP_PIN_OUT_STRENGTH_HIGH */
+		qcom,src-sel = <2>;		/* QPNP_PIN_SEL_FUNC_1 */
+		qcom,master-en = <1>;	/* Enable GPIO */
+	};
+
+	gpio@c100 { /* GPIO 2 */
+		qcom,mode = <1>;
+		qcom,output-type = <0>;
+		qcom,pull = <5>;
+		qcom,vin-sel = <3>;
+		qcom,out-strength = <3>;
+		qcom,src-sel = <2>;
+		qcom,master-en = <1>;
+	};
+
+	gpio@c200 { /* GPIO 3 */
+	};
+
+	gpio@c300 { /* GPIO 4 */
+	};
+
+	gpio@c400 { /* GPIO 5 */
+	};
+
+	gpio@c500 { /* GPIO 6 */
+	};
+
+	gpio@c600 { /* GPIO 7 */
+	};
+
+	gpio@c700 { /* GPIO 8 */
+	};
+};
+
+&pm8226_mpps {
+	mpp@a000 { /* MPP 1 */
+	};
+
+	mpp@a100 { /* MPP 2 */
+	};
+
+	mpp@a200 { /* MPP 3 */
+	};
+
+	mpp@a300 { /* MPP 4 */
+	};
+
+	mpp@a400 { /* MPP 5 */
+	};
+
+	mpp@a500 { /* MPP 6 */
+	};
+
+	mpp@a600 { /* MPP 7 */
+	};
+
+	mpp@a700 { /* MPP 8 */
+	};
+};
+
+&pm8226_chg {
+	qcom,charging-disabled;
+	qcom,use-default-batt-values;
+};
diff --git a/arch/arm/boot/dts/msm8226-mtp.dts b/arch/arm/boot/dts/msm8226-mtp.dts
index 65b71e9..2881274 100644
--- a/arch/arm/boot/dts/msm8226-mtp.dts
+++ b/arch/arm/boot/dts/msm8226-mtp.dts
@@ -12,8 +12,7 @@
 
 /dts-v1/;
 /include/ "msm8226.dtsi"
-/include/ "dsi-panel-nt35590-720p-video.dtsi"
-/include/ "msm8226-camera-sensor-mtp.dtsi"
+/include/ "msm8226-mtp.dtsi"
 
 / {
 	model = "Qualcomm MSM 8226 MTP";
@@ -23,373 +22,3 @@
 		      <159 8 0>,
 		      <198 8 0>;
 };
-
-&soc {
-	serial@f991f000 {
-		status = "ok";
-	};
-
-	qcom,mdss_dsi_nt35590_720p_video {
-		status = "ok";
-	};
-
-	i2c@f9927000 { /* BLSP1 QUP5 */
-		synaptics@20 {
-			compatible = "synaptics,rmi4";
-			reg = <0x20>;
-			interrupt-parent = <&msmgpio>;
-			interrupts = <17 0x2008>;
-			vdd-supply = <&pm8226_l19>;
-			vcc_i2c-supply = <&pm8226_lvs1>;
-			synaptics,reset-gpio = <&msmgpio 16 0x00>;
-			synaptics,irq-gpio = <&msmgpio 17 0x2008>;
-			synaptics,button-map = <139 102 158>;
-			synaptics,i2c-pull-up;
-			synaptics,reg-en;
-		};
-	};
-
-	gpio_keys {
-		compatible = "gpio-keys";
-		input-name = "gpio-keys";
-
-		camera_focus {
-			label = "camera_focus";
-			gpios = <&msmgpio 108 0x1>;
-			linux,input-type = <1>;
-			linux,code = <0x210>;
-			gpio-key,wakeup;
-			debounce-interval = <15>;
-		};
-
-		camera_snapshot {
-			label = "camera_snapshot";
-			gpios = <&msmgpio 107 0x1>;
-			linux,input-type = <1>;
-			linux,code = <0x2fe>;
-			gpio-key,wakeup;
-			debounce-interval = <15>;
-		};
-
-		vol_up {
-			label = "volume_up";
-			gpios = <&msmgpio 106 0x1>;
-			linux,input-type = <1>;
-			linux,code = <115>;
-			gpio-key,wakeup;
-			debounce-interval = <15>;
-		};
-	};
-
-	spi@f9923000 {
-		ethernet-switch@3 {
-			compatible = "micrel,ks8851";
-			reg = <3>;
-			interrupt-parent = <&msmgpio>;
-			interrupts = <0 115 0>;
-			spi-max-frequency = <4800000>;
-			rst-gpio = <&msmgpio 114 0>;
-			vdd-io-supply = <&pm8226_lvs1>;
-			vdd-phy-supply = <&pm8226_lvs1>;
-		};
-	};
-
-	sound {
-		qcom,audio-routing =
-			"RX_BIAS", "MCLK",
-			"LDO_H", "MCLK",
-			"SPK_OUT", "MCLK",
-			"SPK_OUT", "EXT_VDD_SPKR",
-			"AMIC1", "MIC BIAS1 External",
-			"MIC BIAS1 External", "Handset Mic",
-			"AMIC2", "MIC BIAS2 External",
-			"MIC BIAS2 External", "Headset Mic",
-			"AMIC3", "MIC BIAS1 External",
-			"MIC BIAS1 External", "ANCRight Headset Mic",
-			"AMIC4", "MIC BIAS2 External",
-			"MIC BIAS2 External", "ANCLeft Headset Mic";
-
-		qcom,cdc-mclk-gpios = <&pm8226_gpios 1 0>;
-		qcom,cdc-vdd-spkr-gpios = <&pm8226_gpios 2 0>;
-	};
-};
-
-&sdcc1 {
-	vdd-supply = <&pm8226_l17>;
-	qcom,vdd-always-on;
-	qcom,vdd-lpm-sup;
-	qcom,vdd-voltage-level = <2950000 2950000>;
-	qcom,vdd-current-level = <800 500000>;
-
-	vdd-io-supply = <&pm8226_l6>;
-	qcom,vdd-io-always-on;
-	qcom,vdd-io-voltage-level = <1800000 1800000>;
-	qcom,vdd-io-current-level = <250 154000>;
-
-	qcom,pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
-	qcom,pad-pull-off = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
-	qcom,pad-drv-on = <0x4 0x4 0x4>; /* 10mA, 10mA, 10mA */
-	qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
-
-	qcom,clk-rates = <400000 25000000 50000000 100000000 200000000>;
-	qcom,sup-voltages = <2950 2950>;
-
-	qcom,bus-speed-mode = "HS200_1p8v", "DDR_1p8v";
-	qcom,nonremovable;
-
-	status = "disabled";
-};
-
-&sdhc_1 {
-	vdd-supply = <&pm8226_l17>;
-	qcom,vdd-always-on;
-	qcom,vdd-lpm-sup;
-	qcom,vdd-voltage-level = <2950000 2950000>;
-	qcom,vdd-current-level = <800 500000>;
-
-	vdd-io-supply = <&pm8226_l6>;
-	qcom,vdd-io-always-on;
-	qcom,vdd-io-voltage-level = <1800000 1800000>;
-	qcom,vdd-io-current-level = <250 154000>;
-
-	qcom,pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
-	qcom,pad-pull-off = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
-	qcom,pad-drv-on = <0x4 0x4 0x4>; /* 10mA, 10mA, 10mA */
-	qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
-
-	qcom,clk-rates = <400000 25000000 50000000 100000000 200000000>;
-	qcom,bus-speed-mode = "HS200_1p8v", "DDR_1p8v";
-	qcom,nonremovable;
-
-	status = "ok";
-};
-
-&sdcc2 {
-	vdd-supply = <&pm8226_l18>;
-	qcom,vdd-voltage-level = <2950000 2950000>;
-	qcom,vdd-current-level = <9000 800000>;
-
-	vdd-io-supply = <&pm8226_l21>;
-	qcom,vdd-io-always-on;
-	qcom,vdd-io-lpm-sup;
-	qcom,vdd-io-voltage-level = <1800000 2950000>;
-	qcom,vdd-io-current-level = <6 22000>;
-
-	qcom,pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
-	qcom,pad-pull-off = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
-	qcom,pad-drv-on = <0x4 0x4 0x4>; /* 10mA, 10mA, 10mA */
-	qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
-
-	qcom,clk-rates = <400000 25000000 50000000 100000000 200000000>;
-	qcom,sup-voltages = <2950 2950>;
-
-	qcom,xpc;
-	qcom,bus-speed-mode = "SDR12", "SDR25", "SDR50", "DDR50", "SDR104";
-	qcom,current-limit = <600>; #address-cells = <0>; interrupt-parent = <&sdcc2>;
-	interrupts = <0 1 2>;
-	#interrupt-cells = <1>;
-	interrupt-map-mask = <0xffffffff>;
-	interrupt-map = <0 &intc 0 125 0
-			1 &intc 0 220 0
-			2 &msmgpio 38 0x3>;
-	interrupt-names = "core_irq", "bam_irq", "status_irq";
-	cd-gpios = <&msmgpio 38 0x1>;
-
-	status = "disabled";
-};
-
-&sdhc_2 {
-	vdd-supply = <&pm8226_l18>;
-	qcom,vdd-voltage-level = <2950000 2950000>;
-	qcom,vdd-current-level = <9000 800000>;
-
-	vdd-io-supply = <&pm8226_l21>;
-	qcom,vdd-io-always-on;
-	qcom,vdd-io-lpm-sup;
-	qcom,vdd-io-voltage-level = <1800000 2950000>;
-	qcom,vdd-io-current-level = <6 22000>;
-
-	qcom,pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
-	qcom,pad-pull-off = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
-	qcom,pad-drv-on = <0x4 0x4 0x4>; /* 10mA, 10mA, 10mA */
-	qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
-
-	qcom,clk-rates = <400000 25000000 50000000 100000000 200000000>;
-
-	#address-cells = <0>;
-	interrupt-parent = <&sdhc_2>;
-	interrupts = <0 1 2>;
-	#interrupt-cells = <1>;
-	interrupt-map-mask = <0xffffffff>;
-	interrupt-map = <0 &intc 0 125 0
-			1 &intc 0 221 0
-			2 &msmgpio 38 0x3>;
-	interrupt-names = "hc_irq", "pwr_irq", "status_irq";
-	cd-gpios = <&msmgpio 38 0x1>;
-
-	status = "ok";
-};
-
-&spmi_bus {
-	qcom,pm8226@0 {
-		qcom,leds@a100 {
-			status = "okay";
-			qcom,led_mpp_2 {
-				label = "mpp";
-				linux,name = "button-backlight";
-				linux,default-trigger = "none";
-				qcom,default-state = "off";
-				qcom,max-current = <40>;
-				qcom,current-setting = <5>;
-				qcom,id = <6>;
-				qcom,mode = <2>;
-				qcom,source-sel = <1>;
-				qcom,mode-ctrl = <0x60>;
-			};
-		};
-	};
-
-	qcom,pm8226@1 {
-                qcom,leds@d300 {
-                        status = "okay";
-                };
-
-		qcom,leds@d800 {
-			status = "okay";
-			qcom,wled_0 {
-				label = "wled";
-				linux,name = "wled:backlight";
-				linux,default-trigger = "bkl-trigger";
-				qcom,cs-out-en;
-				qcom,op-fdbck = <1>;
-				qcom,default-state = "on";
-				qcom,max-current = <25>;
-				qcom,ctrl-delay-us = <0>;
-				qcom,boost-curr-lim = <3>;
-				qcom,cp-sel = <0>;
-				qcom,switch-freq = <2>;
-				qcom,ovp-val = <0>;
-				qcom,num-strings = <1>;
-				qcom,id = <0>;
-			};
-		};
-	};
-};
-
-&pm8226_gpios {
-	gpio@c000 { /* GPIO 1 */
-		/* XO_PMIC_CDC_MCLK enable for tapan codec */
-		qcom,mode = <1>;		/* Digital output */
-		qcom,output-type = <0>;	/* CMOS logic */
-		qcom,pull = <5>;		/* QPNP_PIN_PULL_NO*/
-		qcom,vin-sel = <3>;		/* QPNP_PIN_VIN3 */
-		qcom,out-strength = <3>;/* QPNP_PIN_OUT_STRENGTH_HIGH */
-		qcom,src-sel = <2>;		/* QPNP_PIN_SEL_FUNC_1 */
-		qcom,master-en = <1>;	/* Enable GPIO */
-	};
-
-	gpio@c100 { /* GPIO 2 */
-		qcom,mode = <1>;
-		qcom,output-type = <0>;
-		qcom,pull = <5>;
-		qcom,vin-sel = <3>;
-		qcom,out-strength = <3>;
-		qcom,src-sel = <2>;
-		qcom,master-en = <1>;
-	};
-
-	gpio@c200 { /* GPIO 3 */
-	};
-
-	gpio@c300 { /* GPIO 4 */
-	};
-
-	gpio@c400 { /* GPIO 5 */
-	};
-
-	gpio@c500 { /* GPIO 6 */
-	};
-
-	gpio@c600 { /* GPIO 7 */
-	};
-
-	gpio@c700 { /* GPIO 8 */
-	};
-};
-
-&pm8226_mpps {
-	mpp@a000 { /* MPP 1 */
-	};
-
-	mpp@a100 { /* MPP 2 */
-	};
-
-	mpp@a200 { /* MPP 3 */
-	};
-
-	mpp@a300 { /* MPP 4 */
-	};
-
-	mpp@a400 { /* MPP 5 */
-		/* PA_THERM0 config */
-		qcom,mode = <4>; /* AIN input */
-		qcom,invert = <1>; /* Enable MPP */
-		qcom,ain-route = <0>; /* AMUX 5 */
-		qcom,master-en = <1>;
-		qcom,src-sel = <0>; /* Function constant */
-	};
-
-	mpp@a500 { /* MPP 6 */
-	};
-
-	mpp@a600 { /* MPP 7 */
-	};
-
-	mpp@a700 { /* MPP 8 */
-		/* PA_THERM1 config */
-		qcom,mode = <4>; /* AIN input */
-		qcom,invert = <1>; /* Enable MPP */
-		qcom,ain-route = <3>; /* AMUX 8 */
-		qcom,master-en = <1>;
-		qcom,src-sel = <0>; /* Function constant */
-	};
-};
-
-&pm8226_vadc {
-	chan@14 {
-		label = "pa_therm0";
-		reg = <0x14>;
-		qcom,decimation = <0>;
-		qcom,pre-div-channel-scaling = <0>;
-		qcom,calibration-type = "ratiometric";
-		qcom,scale-function = <2>;
-		qcom,hw-settle-time = <2>;
-		qcom,fast-avg-setup = <0>;
-	};
-
-	chan@17 {
-		label = "pa_therm1";
-		reg = <0x17>;
-		qcom,decimation = <0>;
-		qcom,pre-div-channel-scaling = <0>;
-		qcom,calibration-type = "ratiometric";
-		qcom,scale-function = <2>;
-		qcom,hw-settle-time = <2>;
-		qcom,fast-avg-setup = <0>;
-	};
-};
-
-&pm8226_bms {
-	status = "ok";
-};
-
-&pm8226_chg {
-	qcom,charging-disabled;
-};
-
-&slim_msm {
-	tapan_codec {
-		qcom,cdc-micbias1-ext-cap;
-		qcom,cdc-micbias2-ext-cap;
-	};
-};
diff --git a/arch/arm/boot/dts/msm8226-mtp.dtsi b/arch/arm/boot/dts/msm8226-mtp.dtsi
new file mode 100644
index 0000000..9ea9bd7
--- /dev/null
+++ b/arch/arm/boot/dts/msm8226-mtp.dtsi
@@ -0,0 +1,423 @@
+/* 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/ "dsi-panel-nt35590-720p-video.dtsi"
+/include/ "msm8226-camera-sensor-mtp.dtsi"
+
+&soc {
+	serial@f991f000 {
+		status = "ok";
+	};
+
+	qcom,mdss_dsi_nt35590_720p_video {
+		status = "ok";
+	};
+
+	i2c@f9927000 { /* BLSP1 QUP5 */
+		synaptics@20 {
+			compatible = "synaptics,rmi4";
+			reg = <0x20>;
+			interrupt-parent = <&msmgpio>;
+			interrupts = <17 0x2008>;
+			vdd-supply = <&pm8226_l19>;
+			vcc_i2c-supply = <&pm8226_lvs1>;
+			synaptics,reset-gpio = <&msmgpio 16 0x00>;
+			synaptics,irq-gpio = <&msmgpio 17 0x2008>;
+			synaptics,button-map = <139 102 158>;
+			synaptics,i2c-pull-up;
+			synaptics,reg-en;
+		};
+	};
+
+	gpio_keys {
+		compatible = "gpio-keys";
+		input-name = "gpio-keys";
+
+		camera_focus {
+			label = "camera_focus";
+			gpios = <&msmgpio 108 0x1>;
+			linux,input-type = <1>;
+			linux,code = <0x210>;
+			gpio-key,wakeup;
+			debounce-interval = <15>;
+		};
+
+		camera_snapshot {
+			label = "camera_snapshot";
+			gpios = <&msmgpio 107 0x1>;
+			linux,input-type = <1>;
+			linux,code = <0x2fe>;
+			gpio-key,wakeup;
+			debounce-interval = <15>;
+		};
+
+		vol_up {
+			label = "volume_up";
+			gpios = <&msmgpio 106 0x1>;
+			linux,input-type = <1>;
+			linux,code = <115>;
+			gpio-key,wakeup;
+			debounce-interval = <15>;
+		};
+	};
+
+	spi@f9923000 {
+		ethernet-switch@3 {
+			compatible = "micrel,ks8851";
+			reg = <3>;
+			interrupt-parent = <&msmgpio>;
+			interrupts = <0 115 0>;
+			spi-max-frequency = <4800000>;
+			rst-gpio = <&msmgpio 114 0>;
+			vdd-io-supply = <&pm8226_lvs1>;
+			vdd-phy-supply = <&pm8226_lvs1>;
+		};
+	};
+
+	sound {
+		qcom,audio-routing =
+			"RX_BIAS", "MCLK",
+			"LDO_H", "MCLK",
+			"SPK_OUT", "MCLK",
+			"SPK_OUT", "EXT_VDD_SPKR",
+			"AMIC1", "MIC BIAS1 External",
+			"MIC BIAS1 External", "Handset Mic",
+			"AMIC2", "MIC BIAS2 External",
+			"MIC BIAS2 External", "Headset Mic",
+			"AMIC3", "MIC BIAS1 External",
+			"MIC BIAS1 External", "ANCRight Headset Mic",
+			"AMIC4", "MIC BIAS2 External",
+			"MIC BIAS2 External", "ANCLeft Headset Mic";
+
+		qcom,cdc-mclk-gpios = <&pm8226_gpios 1 0>;
+		qcom,cdc-vdd-spkr-gpios = <&pm8226_gpios 2 0>;
+	};
+};
+
+&sdcc1 {
+	vdd-supply = <&pm8226_l17>;
+	qcom,vdd-always-on;
+	qcom,vdd-lpm-sup;
+	qcom,vdd-voltage-level = <2950000 2950000>;
+	qcom,vdd-current-level = <800 500000>;
+
+	vdd-io-supply = <&pm8226_l6>;
+	qcom,vdd-io-always-on;
+	qcom,vdd-io-voltage-level = <1800000 1800000>;
+	qcom,vdd-io-current-level = <250 154000>;
+
+	qcom,pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+	qcom,pad-pull-off = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+	qcom,pad-drv-on = <0x4 0x4 0x4>; /* 10mA, 10mA, 10mA */
+	qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
+
+	qcom,clk-rates = <400000 25000000 50000000 100000000 200000000>;
+	qcom,sup-voltages = <2950 2950>;
+
+	qcom,bus-speed-mode = "HS200_1p8v", "DDR_1p8v";
+	qcom,nonremovable;
+
+	status = "disabled";
+};
+
+&sdhc_1 {
+	vdd-supply = <&pm8226_l17>;
+	qcom,vdd-always-on;
+	qcom,vdd-lpm-sup;
+	qcom,vdd-voltage-level = <2950000 2950000>;
+	qcom,vdd-current-level = <800 500000>;
+
+	vdd-io-supply = <&pm8226_l6>;
+	qcom,vdd-io-always-on;
+	qcom,vdd-io-voltage-level = <1800000 1800000>;
+	qcom,vdd-io-current-level = <250 154000>;
+
+	qcom,pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+	qcom,pad-pull-off = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+	qcom,pad-drv-on = <0x4 0x4 0x4>; /* 10mA, 10mA, 10mA */
+	qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
+
+	qcom,clk-rates = <400000 25000000 50000000 100000000 200000000>;
+	qcom,bus-speed-mode = "HS200_1p8v", "DDR_1p8v";
+	qcom,nonremovable;
+
+	status = "ok";
+};
+
+&sdcc2 {
+	vdd-supply = <&pm8226_l18>;
+	qcom,vdd-voltage-level = <2950000 2950000>;
+	qcom,vdd-current-level = <9000 800000>;
+
+	vdd-io-supply = <&pm8226_l21>;
+	qcom,vdd-io-always-on;
+	qcom,vdd-io-lpm-sup;
+	qcom,vdd-io-voltage-level = <1800000 2950000>;
+	qcom,vdd-io-current-level = <6 22000>;
+
+	qcom,pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+	qcom,pad-pull-off = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+	qcom,pad-drv-on = <0x4 0x4 0x4>; /* 10mA, 10mA, 10mA */
+	qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
+
+	qcom,clk-rates = <400000 25000000 50000000 100000000 200000000>;
+	qcom,sup-voltages = <2950 2950>;
+
+	qcom,xpc;
+	qcom,bus-speed-mode = "SDR12", "SDR25", "SDR50", "DDR50", "SDR104";
+	qcom,current-limit = <600>; #address-cells = <0>; interrupt-parent = <&sdcc2>;
+	interrupts = <0 1 2>;
+	#interrupt-cells = <1>;
+	interrupt-map-mask = <0xffffffff>;
+	interrupt-map = <0 &intc 0 125 0
+			1 &intc 0 220 0
+			2 &msmgpio 38 0x3>;
+	interrupt-names = "core_irq", "bam_irq", "status_irq";
+	cd-gpios = <&msmgpio 38 0x1>;
+
+	status = "disabled";
+};
+
+&sdhc_2 {
+	vdd-supply = <&pm8226_l18>;
+	qcom,vdd-voltage-level = <2950000 2950000>;
+	qcom,vdd-current-level = <9000 800000>;
+
+	vdd-io-supply = <&pm8226_l21>;
+	qcom,vdd-io-always-on;
+	qcom,vdd-io-lpm-sup;
+	qcom,vdd-io-voltage-level = <1800000 2950000>;
+	qcom,vdd-io-current-level = <6 22000>;
+
+	qcom,pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+	qcom,pad-pull-off = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+	qcom,pad-drv-on = <0x4 0x4 0x4>; /* 10mA, 10mA, 10mA */
+	qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
+
+	qcom,clk-rates = <400000 25000000 50000000 100000000 200000000>;
+
+	#address-cells = <0>;
+	interrupt-parent = <&sdhc_2>;
+	interrupts = <0 1 2>;
+	#interrupt-cells = <1>;
+	interrupt-map-mask = <0xffffffff>;
+	interrupt-map = <0 &intc 0 125 0
+			1 &intc 0 221 0
+			2 &msmgpio 38 0x3>;
+	interrupt-names = "hc_irq", "pwr_irq", "status_irq";
+	cd-gpios = <&msmgpio 38 0x1>;
+
+	status = "ok";
+};
+
+&spmi_bus {
+	qcom,pm8226@0 {
+		qcom,leds@a100 {
+			status = "okay";
+			qcom,led_mpp_2 {
+				label = "mpp";
+				linux,name = "button-backlight";
+				linux,default-trigger = "none";
+				qcom,default-state = "off";
+				qcom,max-current = <40>;
+				qcom,current-setting = <5>;
+				qcom,id = <6>;
+				qcom,mode = "manual";
+				qcom,source-sel = <1>;
+				qcom,mode-ctrl = <0x60>;
+			};
+		};
+
+		qcom,leds@a300 {
+			status = "okay";
+			qcom,led_mpp_4 {
+				label = "mpp";
+				linux,name = "green";
+				linux,default-trigger = "none";
+				qcom,default-state = "off";
+				qcom,max-current = <40>;
+				qcom,current-setting = <5>;
+				qcom,id = <6>;
+				qcom,mode = "lpg";
+				qcom,source-sel = <8>;
+				qcom,mode-ctrl = <0x60>;
+				qcom,pwm-channel = <0>;
+				qcom,start-idx = <1>;
+				qcom,duty-pcts = [00 00 00 00 64
+						 64 00 00 00 00];
+			};
+		};
+
+		qcom,leds@a500 {
+			status = "okay";
+			qcom,led_mpp_6 {
+				label = "mpp";
+				linux,name = "red";
+				linux,default-trigger = "none";
+				qcom,default-state = "off";
+				qcom,max-current = <40>;
+				qcom,current-setting = <5>;
+				qcom,id = <6>;
+				qcom,mode-ctrl = <0x60>;
+				qcom,source-sel = <10>;
+				qcom,mode = "lpg";
+				qcom,pwm-channel = <5>;
+				qcom,start-idx = <1>;
+				qcom,duty-pcts = [00 00 00 00 64
+						 64 00 00 00 00];
+			};
+		};
+	};
+
+	qcom,pm8226@1 {
+                qcom,leds@d300 {
+                        status = "okay";
+                };
+
+		qcom,leds@d800 {
+			status = "okay";
+			qcom,wled_0 {
+				label = "wled";
+				linux,name = "wled:backlight";
+				linux,default-trigger = "bkl-trigger";
+				qcom,cs-out-en;
+				qcom,op-fdbck = <1>;
+				qcom,default-state = "on";
+				qcom,max-current = <25>;
+				qcom,ctrl-delay-us = <0>;
+				qcom,boost-curr-lim = <3>;
+				qcom,cp-sel = <0>;
+				qcom,switch-freq = <2>;
+				qcom,ovp-val = <0>;
+				qcom,num-strings = <1>;
+				qcom,id = <0>;
+			};
+		};
+	};
+};
+
+&pm8226_gpios {
+	gpio@c000 { /* GPIO 1 */
+		/* XO_PMIC_CDC_MCLK enable for tapan codec */
+		qcom,mode = <1>;		/* Digital output */
+		qcom,output-type = <0>;	/* CMOS logic */
+		qcom,pull = <5>;		/* QPNP_PIN_PULL_NO*/
+		qcom,vin-sel = <3>;		/* QPNP_PIN_VIN3 */
+		qcom,out-strength = <3>;/* QPNP_PIN_OUT_STRENGTH_HIGH */
+		qcom,src-sel = <2>;		/* QPNP_PIN_SEL_FUNC_1 */
+		qcom,master-en = <1>;	/* Enable GPIO */
+	};
+
+	gpio@c100 { /* GPIO 2 */
+		qcom,mode = <1>;
+		qcom,output-type = <0>;
+		qcom,pull = <5>;
+		qcom,vin-sel = <3>;
+		qcom,out-strength = <3>;
+		qcom,src-sel = <2>;
+		qcom,master-en = <1>;
+	};
+
+	gpio@c200 { /* GPIO 3 */
+	};
+
+	gpio@c300 { /* GPIO 4 */
+	};
+
+	gpio@c400 { /* GPIO 5 */
+	};
+
+	gpio@c500 { /* GPIO 6 */
+	};
+
+	gpio@c600 { /* GPIO 7 */
+	};
+
+	gpio@c700 { /* GPIO 8 */
+	};
+};
+
+&pm8226_mpps {
+	mpp@a000 { /* MPP 1 */
+	};
+
+	mpp@a100 { /* MPP 2 */
+	};
+
+	mpp@a200 { /* MPP 3 */
+	};
+
+	mpp@a300 { /* MPP 4 */
+	};
+
+	mpp@a400 { /* MPP 5 */
+		/* PA_THERM0 config */
+		qcom,mode = <4>; /* AIN input */
+		qcom,invert = <1>; /* Enable MPP */
+		qcom,ain-route = <0>; /* AMUX 5 */
+		qcom,master-en = <1>;
+		qcom,src-sel = <0>; /* Function constant */
+	};
+
+	mpp@a500 { /* MPP 6 */
+	};
+
+	mpp@a600 { /* MPP 7 */
+	};
+
+	mpp@a700 { /* MPP 8 */
+		/* PA_THERM1 config */
+		qcom,mode = <4>; /* AIN input */
+		qcom,invert = <1>; /* Enable MPP */
+		qcom,ain-route = <3>; /* AMUX 8 */
+		qcom,master-en = <1>;
+		qcom,src-sel = <0>; /* Function constant */
+	};
+};
+
+&pm8226_vadc {
+	chan@14 {
+		label = "pa_therm0";
+		reg = <0x14>;
+		qcom,decimation = <0>;
+		qcom,pre-div-channel-scaling = <0>;
+		qcom,calibration-type = "ratiometric";
+		qcom,scale-function = <2>;
+		qcom,hw-settle-time = <2>;
+		qcom,fast-avg-setup = <0>;
+	};
+
+	chan@17 {
+		label = "pa_therm1";
+		reg = <0x17>;
+		qcom,decimation = <0>;
+		qcom,pre-div-channel-scaling = <0>;
+		qcom,calibration-type = "ratiometric";
+		qcom,scale-function = <2>;
+		qcom,hw-settle-time = <2>;
+		qcom,fast-avg-setup = <0>;
+	};
+};
+
+&pm8226_bms {
+	status = "ok";
+};
+
+&pm8226_chg {
+	qcom,charging-disabled;
+};
+
+&slim_msm {
+	tapan_codec {
+		qcom,cdc-micbias1-ext-cap;
+	};
+};
diff --git a/arch/arm/boot/dts/msm8226-qrd.dts b/arch/arm/boot/dts/msm8226-qrd.dts
index aba5c4a..e364de7 100644
--- a/arch/arm/boot/dts/msm8226-qrd.dts
+++ b/arch/arm/boot/dts/msm8226-qrd.dts
@@ -12,8 +12,7 @@
 
 /dts-v1/;
 /include/ "msm8226.dtsi"
-/include/ "dsi-panel-nt35590-720p-video.dtsi"
-/include/ "msm8226-camera-sensor-qrd.dtsi"
+/include/ "msm8226-qrd.dtsi"
 
 / {
 	model = "Qualcomm MSM 8226 QRD";
@@ -23,351 +22,3 @@
 		      <159 11 0>,
 		      <198 11 0>;
 };
-
-&soc {
-	serial@f991f000 {
-		status = "ok";
-	};
-
-	qcom,mdss_dsi_nt35590_720p_video {
-		status = "ok";
-	};
-
-	i2c@f9927000 { /* BLSP1 QUP5 */
-		synaptics@20 {
-			compatible = "synaptics,rmi4";
-			reg = <0x20>;
-			interrupt-parent = <&msmgpio>;
-			interrupts = <17 0x2008>;
-			vdd-supply = <&pm8226_l19>;
-			vcc_i2c-supply = <&pm8226_lvs1>;
-			synaptics,reset-gpio = <&msmgpio 16 0x00>;
-			synaptics,irq-gpio = <&msmgpio 17 0x2008>;
-			synaptics,button-map = <139 102 158>;
-			synaptics,i2c-pull-up;
-			synaptics,reg-en;
-		};
-	};
-
-	gpio_keys {
-		compatible = "gpio-keys";
-		input-name = "gpio-keys";
-
-		camera_focus {
-			label = "camera_focus";
-			gpios = <&msmgpio 108 0x1>;
-			linux,input-type = <1>;
-			linux,code = <0x210>;
-			gpio-key,wakeup;
-			debounce-interval = <15>;
-		};
-
-		camera_snapshot {
-			label = "camera_snapshot";
-			gpios = <&msmgpio 107 0x1>;
-			linux,input-type = <1>;
-			linux,code = <0x2fe>;
-			gpio-key,wakeup;
-			debounce-interval = <15>;
-		};
-
-		vol_up {
-			label = "volume_up";
-			gpios = <&msmgpio 106 0x1>;
-			linux,input-type = <1>;
-			linux,code = <115>;
-			gpio-key,wakeup;
-			debounce-interval = <15>;
-		};
-	};
-
-	spi@f9923000 {
-		ethernet-switch@3 {
-			compatible = "micrel,ks8851";
-			reg = <3>;
-			interrupt-parent = <&msmgpio>;
-			interrupts = <0 115 0>;
-			spi-max-frequency = <4800000>;
-			rst-gpio = <&msmgpio 114 0>;
-			vdd-io-supply = <&pm8226_lvs1>;
-			vdd-phy-supply = <&pm8226_lvs1>;
-		};
-	};
-
-	sound {
-		qcom,audio-routing =
-			"RX_BIAS", "MCLK",
-			"LDO_H", "MCLK",
-			"SPK_OUT", "MCLK",
-			"SPK_OUT", "EXT_VDD_SPKR",
-			"AMIC1", "MIC BIAS1 External",
-			"MIC BIAS1 External", "Handset Mic",
-			"AMIC2", "MIC BIAS2 External",
-			"MIC BIAS2 External", "Headset Mic",
-			"AMIC3", "MIC BIAS1 External",
-			"MIC BIAS1 External", "ANCRight Headset Mic",
-			"AMIC4", "MIC BIAS2 External",
-			"MIC BIAS2 External", "ANCLeft Headset Mic";
-
-		qcom,cdc-mclk-gpios = <&pm8226_gpios 1 0>;
-		qcom,cdc-vdd-spkr-gpios = <&pm8226_gpios 2 0>;
-	};
-};
-
-&sdcc1 {
-	vdd-supply = <&pm8226_l17>;
-	qcom,vdd-always-on;
-	qcom,vdd-lpm-sup;
-	qcom,vdd-voltage-level = <2950000 2950000>;
-	qcom,vdd-current-level = <800 500000>;
-
-	vdd-io-supply = <&pm8226_l6>;
-	qcom,vdd-io-always-on;
-	qcom,vdd-io-voltage-level = <1800000 1800000>;
-	qcom,vdd-io-current-level = <250 154000>;
-
-	qcom,pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
-	qcom,pad-pull-off = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
-	qcom,pad-drv-on = <0x4 0x4 0x4>; /* 10mA, 10mA, 10mA */
-	qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
-
-	qcom,clk-rates = <400000 25000000 50000000 100000000 200000000>;
-	qcom,sup-voltages = <2950 2950>;
-
-	qcom,bus-speed-mode = "HS200_1p8v", "DDR_1p8v";
-	qcom,nonremovable;
-
-	status = "disabled";
-};
-
-&sdhc_1 {
-	vdd-supply = <&pm8226_l17>;
-	qcom,vdd-always-on;
-	qcom,vdd-lpm-sup;
-	qcom,vdd-voltage-level = <2950000 2950000>;
-	qcom,vdd-current-level = <800 500000>;
-
-	vdd-io-supply = <&pm8226_l6>;
-	qcom,vdd-io-always-on;
-	qcom,vdd-io-voltage-level = <1800000 1800000>;
-	qcom,vdd-io-current-level = <250 154000>;
-
-	qcom,pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
-	qcom,pad-pull-off = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
-	qcom,pad-drv-on = <0x4 0x4 0x4>; /* 10mA, 10mA, 10mA */
-	qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
-
-	qcom,clk-rates = <400000 25000000 50000000 100000000 200000000>;
-	qcom,bus-speed-mode = "HS200_1p8v", "DDR_1p8v";
-	qcom,nonremovable;
-
-	status = "ok";
-};
-
-&sdcc2 {
-	vdd-supply = <&pm8226_l18>;
-	qcom,vdd-voltage-level = <2950000 2950000>;
-	qcom,vdd-current-level = <9000 800000>;
-
-	vdd-io-supply = <&pm8226_l21>;
-	qcom,vdd-io-always-on;
-	qcom,vdd-io-lpm-sup;
-	qcom,vdd-io-voltage-level = <1800000 2950000>;
-	qcom,vdd-io-current-level = <6 22000>;
-
-	qcom,pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
-	qcom,pad-pull-off = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
-	qcom,pad-drv-on = <0x4 0x4 0x4>; /* 10mA, 10mA, 10mA */
-	qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
-
-	qcom,clk-rates = <400000 25000000 50000000 100000000 200000000>;
-	qcom,sup-voltages = <2950 2950>;
-
-	qcom,xpc;
-	qcom,bus-speed-mode = "SDR12", "SDR25", "SDR50", "DDR50", "SDR104";
-	qcom,current-limit = <600>;
-
-	#address-cells = <0>;
-	interrupt-parent = <&sdcc2>;
-	interrupts = <0 1 2>;
-	#interrupt-cells = <1>;
-	interrupt-map-mask = <0xffffffff>;
-	interrupt-map = <0 &intc 0 125 0
-			1 &intc 0 220 0
-			2 &msmgpio 38 0x3>;
-	interrupt-names = "core_irq", "bam_irq", "status_irq";
-	cd-gpios = <&msmgpio 38 0x1>;
-
-	status = "disabled";
-};
-
-&sdhc_2 {
-	vdd-supply = <&pm8226_l18>;
-	qcom,vdd-voltage-level = <2950000 2950000>;
-	qcom,vdd-current-level = <9000 800000>;
-
-	vdd-io-supply = <&pm8226_l21>;
-	qcom,vdd-io-always-on;
-	qcom,vdd-io-lpm-sup;
-	qcom,vdd-io-voltage-level = <1800000 2950000>;
-	qcom,vdd-io-current-level = <6 22000>;
-
-	qcom,pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
-	qcom,pad-pull-off = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
-	qcom,pad-drv-on = <0x4 0x4 0x4>; /* 10mA, 10mA, 10mA */
-	qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
-
-	qcom,clk-rates = <400000 25000000 50000000 100000000 200000000>;
-
-	#address-cells = <0>;
-	interrupt-parent = <&sdhc_2>;
-	interrupts = <0 1 2>;
-	#interrupt-cells = <1>;
-	interrupt-map-mask = <0xffffffff>;
-	interrupt-map = <0 &intc 0 125 0
-			1 &intc 0 221 0
-			2 &msmgpio 38 0x3>;
-	interrupt-names = "hc_irq", "pwr_irq", "status_irq";
-	cd-gpios = <&msmgpio 38 0x1>;
-
-	status = "ok";
-};
-
-&spmi_bus {
-	qcom,pm8226@0 {
-		qcom,leds@a100 {
-			status = "okay";
-			qcom,led_mpp_2 {
-				label = "mpp";
-				linux,name = "button-backlight";
-				linux,default-trigger = "none";
-				qcom,default-state = "off";
-				qcom,max-current = <40>;
-				qcom,current-setting = <5>;
-				qcom,id = <6>;
-				qcom,mode = <2>;
-				qcom,source-sel = <1>;
-				qcom,mode-ctrl = <0x60>;
-			};
-		};
-	};
-
-	qcom,pm8226@1 {
-                qcom,leds@d300 {
-                        status = "okay";
-                };
-
-		qcom,leds@d800 {
-			status = "okay";
-			qcom,wled_0 {
-				label = "wled";
-				linux,name = "wled:backlight";
-				linux,default-trigger = "bkl-trigger";
-				qcom,cs-out-en;
-				qcom,op-fdbck = <1>;
-				qcom,default-state = "on";
-				qcom,max-current = <25>;
-				qcom,ctrl-delay-us = <0>;
-				qcom,boost-curr-lim = <3>;
-				qcom,cp-sel = <0>;
-				qcom,switch-freq = <2>;
-				qcom,ovp-val = <0>;
-				qcom,num-strings = <1>;
-				qcom,id = <0>;
-			};
-		};
-
-		qcom,vibrator@c000 {
-			status = "okay";
-			qcom,vib-timeout-ms = <15000>;
-			qcom,vib-vtg-level-mV = <3100>;
-		};
-
-	};
-};
-
-&pm8226_bms {
-	status = "okay";
-	qcom,batt-type = <4>;
-	qcom,max-voltage-uv = <4350000>;
-};
-
-&pm8226_chg {
-	status = "okay";
-	qcom,chg-vddmax-mv = <4350>;
-	qcom,chg-vddsafe-mv = <4350>;
-};
-
-&pm8226_gpios {
-	gpio@c000 { /* GPIO 1 */
-		/* XO_PMIC_CDC_MCLK enable for tapan codec */
-		qcom,mode = <1>;		/* Digital output */
-		qcom,output-type = <0>;	/* CMOS logic */
-		qcom,pull = <5>;		/* QPNP_PIN_PULL_NO*/
-		qcom,vin-sel = <3>;		/* QPNP_PIN_VIN3 */
-		qcom,out-strength = <3>;/* QPNP_PIN_OUT_STRENGTH_HIGH */
-		qcom,src-sel = <2>;		/* QPNP_PIN_SEL_FUNC_1 */
-		qcom,master-en = <1>;	/* Enable GPIO */
-	};
-
-	gpio@c100 { /* GPIO 2 */
-		qcom,mode = <1>;
-		qcom,output-type = <0>;
-		qcom,pull = <5>;
-		qcom,vin-sel = <3>;
-		qcom,out-strength = <3>;
-		qcom,src-sel = <2>;
-		qcom,master-en = <1>;
-	};
-
-	gpio@c200 { /* GPIO 3 */
-	};
-
-	gpio@c300 { /* GPIO 4 */
-	};
-
-	gpio@c400 { /* GPIO 5 */
-	};
-
-	gpio@c500 { /* GPIO 6 */
-	};
-
-	gpio@c600 { /* GPIO 7 */
-	};
-
-	gpio@c700 { /* GPIO 8 */
-	};
-};
-
-&pm8226_mpps {
-	mpp@a000 { /* MPP 1 */
-	};
-
-	mpp@a100 { /* MPP 2 */
-	};
-
-	mpp@a200 { /* MPP 3 */
-	};
-
-	mpp@a300 { /* MPP 4 */
-	};
-
-	mpp@a400 { /* MPP 5 */
-	};
-
-	mpp@a500 { /* MPP 6 */
-	};
-
-	mpp@a600 { /* MPP 7 */
-	};
-
-	mpp@a700 { /* MPP 8 */
-	};
-};
-
-&slim_msm {
-	tapan_codec {
-		qcom,cdc-micbias1-ext-cap;
-	};
-
-};
diff --git a/arch/arm/boot/dts/msm8226-qrd.dtsi b/arch/arm/boot/dts/msm8226-qrd.dtsi
new file mode 100644
index 0000000..1698ac1
--- /dev/null
+++ b/arch/arm/boot/dts/msm8226-qrd.dtsi
@@ -0,0 +1,403 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/include/ "dsi-panel-nt35590-720p-video.dtsi"
+/include/ "msm8226-camera-sensor-qrd.dtsi"
+
+&soc {
+	serial@f991f000 {
+		status = "ok";
+	};
+
+	qcom,mdss_dsi_nt35590_720p_video {
+		status = "ok";
+	};
+
+	i2c@f9927000 { /* BLSP1 QUP5 */
+		synaptics@20 {
+			compatible = "synaptics,rmi4";
+			reg = <0x20>;
+			interrupt-parent = <&msmgpio>;
+			interrupts = <17 0x2008>;
+			vdd-supply = <&pm8226_l19>;
+			vcc_i2c-supply = <&pm8226_lvs1>;
+			synaptics,reset-gpio = <&msmgpio 16 0x00>;
+			synaptics,irq-gpio = <&msmgpio 17 0x2008>;
+			synaptics,button-map = <139 102 158>;
+			synaptics,i2c-pull-up;
+			synaptics,reg-en;
+		};
+	};
+
+	gpio_keys {
+		compatible = "gpio-keys";
+		input-name = "gpio-keys";
+
+		camera_focus {
+			label = "camera_focus";
+			gpios = <&msmgpio 108 0x1>;
+			linux,input-type = <1>;
+			linux,code = <0x210>;
+			gpio-key,wakeup;
+			debounce-interval = <15>;
+		};
+
+		camera_snapshot {
+			label = "camera_snapshot";
+			gpios = <&msmgpio 107 0x1>;
+			linux,input-type = <1>;
+			linux,code = <0x2fe>;
+			gpio-key,wakeup;
+			debounce-interval = <15>;
+		};
+
+		vol_up {
+			label = "volume_up";
+			gpios = <&msmgpio 106 0x1>;
+			linux,input-type = <1>;
+			linux,code = <115>;
+			gpio-key,wakeup;
+			debounce-interval = <15>;
+		};
+	};
+
+	spi@f9923000 {
+		ethernet-switch@3 {
+			compatible = "micrel,ks8851";
+			reg = <3>;
+			interrupt-parent = <&msmgpio>;
+			interrupts = <0 115 0>;
+			spi-max-frequency = <4800000>;
+			rst-gpio = <&msmgpio 114 0>;
+			vdd-io-supply = <&pm8226_lvs1>;
+			vdd-phy-supply = <&pm8226_lvs1>;
+		};
+	};
+
+	sound {
+		qcom,audio-routing =
+			"RX_BIAS", "MCLK",
+			"LDO_H", "MCLK",
+			"SPK_OUT", "MCLK",
+			"SPK_OUT", "EXT_VDD_SPKR",
+			"AMIC1", "MIC BIAS1 External",
+			"MIC BIAS1 External", "Handset Mic",
+			"AMIC2", "MIC BIAS2 External",
+			"MIC BIAS2 External", "Headset Mic",
+			"AMIC3", "MIC BIAS1 External",
+			"MIC BIAS1 External", "ANCRight Headset Mic",
+			"AMIC4", "MIC BIAS2 External",
+			"MIC BIAS2 External", "ANCLeft Headset Mic";
+
+		qcom,cdc-mclk-gpios = <&pm8226_gpios 1 0>;
+		qcom,cdc-vdd-spkr-gpios = <&pm8226_gpios 2 0>;
+		qcom,cdc-us-euro-gpios = <&msmgpio 69 0>;
+	};
+};
+
+&sdcc1 {
+	vdd-supply = <&pm8226_l17>;
+	qcom,vdd-always-on;
+	qcom,vdd-lpm-sup;
+	qcom,vdd-voltage-level = <2950000 2950000>;
+	qcom,vdd-current-level = <800 500000>;
+
+	vdd-io-supply = <&pm8226_l6>;
+	qcom,vdd-io-always-on;
+	qcom,vdd-io-voltage-level = <1800000 1800000>;
+	qcom,vdd-io-current-level = <250 154000>;
+
+	qcom,pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+	qcom,pad-pull-off = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+	qcom,pad-drv-on = <0x4 0x4 0x4>; /* 10mA, 10mA, 10mA */
+	qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
+
+	qcom,clk-rates = <400000 25000000 50000000 100000000 200000000>;
+	qcom,sup-voltages = <2950 2950>;
+
+	qcom,bus-speed-mode = "HS200_1p8v", "DDR_1p8v";
+	qcom,nonremovable;
+
+	status = "disabled";
+};
+
+&sdhc_1 {
+	vdd-supply = <&pm8226_l17>;
+	qcom,vdd-always-on;
+	qcom,vdd-lpm-sup;
+	qcom,vdd-voltage-level = <2950000 2950000>;
+	qcom,vdd-current-level = <800 500000>;
+
+	vdd-io-supply = <&pm8226_l6>;
+	qcom,vdd-io-always-on;
+	qcom,vdd-io-voltage-level = <1800000 1800000>;
+	qcom,vdd-io-current-level = <250 154000>;
+
+	qcom,pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+	qcom,pad-pull-off = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+	qcom,pad-drv-on = <0x4 0x4 0x4>; /* 10mA, 10mA, 10mA */
+	qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
+
+	qcom,clk-rates = <400000 25000000 50000000 100000000 200000000>;
+	qcom,bus-speed-mode = "HS200_1p8v", "DDR_1p8v";
+	qcom,nonremovable;
+
+	status = "ok";
+};
+
+&sdcc2 {
+	vdd-supply = <&pm8226_l18>;
+	qcom,vdd-voltage-level = <2950000 2950000>;
+	qcom,vdd-current-level = <9000 800000>;
+
+	vdd-io-supply = <&pm8226_l21>;
+	qcom,vdd-io-always-on;
+	qcom,vdd-io-lpm-sup;
+	qcom,vdd-io-voltage-level = <1800000 2950000>;
+	qcom,vdd-io-current-level = <6 22000>;
+
+	qcom,pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+	qcom,pad-pull-off = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+	qcom,pad-drv-on = <0x4 0x4 0x4>; /* 10mA, 10mA, 10mA */
+	qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
+
+	qcom,clk-rates = <400000 25000000 50000000 100000000 200000000>;
+	qcom,sup-voltages = <2950 2950>;
+
+	qcom,xpc;
+	qcom,bus-speed-mode = "SDR12", "SDR25", "SDR50", "DDR50", "SDR104";
+	qcom,current-limit = <600>;
+
+	#address-cells = <0>;
+	interrupt-parent = <&sdcc2>;
+	interrupts = <0 1 2>;
+	#interrupt-cells = <1>;
+	interrupt-map-mask = <0xffffffff>;
+	interrupt-map = <0 &intc 0 125 0
+			1 &intc 0 220 0
+			2 &msmgpio 38 0x3>;
+	interrupt-names = "core_irq", "bam_irq", "status_irq";
+	cd-gpios = <&msmgpio 38 0x1>;
+
+	status = "disabled";
+};
+
+&sdhc_2 {
+	vdd-supply = <&pm8226_l18>;
+	qcom,vdd-voltage-level = <2950000 2950000>;
+	qcom,vdd-current-level = <9000 800000>;
+
+	vdd-io-supply = <&pm8226_l21>;
+	qcom,vdd-io-always-on;
+	qcom,vdd-io-lpm-sup;
+	qcom,vdd-io-voltage-level = <1800000 2950000>;
+	qcom,vdd-io-current-level = <6 22000>;
+
+	qcom,pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+	qcom,pad-pull-off = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+	qcom,pad-drv-on = <0x4 0x4 0x4>; /* 10mA, 10mA, 10mA */
+	qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
+
+	qcom,clk-rates = <400000 25000000 50000000 100000000 200000000>;
+
+	#address-cells = <0>;
+	interrupt-parent = <&sdhc_2>;
+	interrupts = <0 1 2>;
+	#interrupt-cells = <1>;
+	interrupt-map-mask = <0xffffffff>;
+	interrupt-map = <0 &intc 0 125 0
+			1 &intc 0 221 0
+			2 &msmgpio 38 0x3>;
+	interrupt-names = "hc_irq", "pwr_irq", "status_irq";
+	cd-gpios = <&msmgpio 38 0x1>;
+
+	status = "ok";
+};
+
+&spmi_bus {
+	qcom,pm8226@0 {
+		qcom,leds@a100 {
+			status = "okay";
+			qcom,led_mpp_2 {
+				label = "mpp";
+				linux,name = "button-backlight";
+				linux,default-trigger = "none";
+				qcom,default-state = "off";
+				qcom,max-current = <40>;
+				qcom,current-setting = <5>;
+				qcom,id = <6>;
+				qcom,mode = "manual";
+				qcom,source-sel = <1>;
+				qcom,mode-ctrl = <0x60>;
+			};
+		};
+
+		qcom,leds@a300 {
+			status = "okay";
+			qcom,led_mpp_4 {
+				label = "mpp";
+				linux,name = "green";
+				linux,default-trigger = "none";
+				qcom,default-state = "off";
+				qcom,max-current = <40>;
+				qcom,current-setting = <5>;
+				qcom,id = <6>;
+				qcom,mode = "lpg";
+				qcom,source-sel = <8>;
+				qcom,mode-ctrl = <0x60>;
+				qcom,pwm-channel = <0>;
+				qcom,start-idx = <1>;
+				qcom,duty-pcts = [00 00 00 00 64
+						 64 00 00 00 00];
+			};
+		};
+
+		qcom,leds@a500 {
+			status = "okay";
+			qcom,led_mpp_6 {
+				label = "mpp";
+				linux,name = "red";
+				linux,default-trigger = "none";
+				qcom,default-state = "off";
+				qcom,max-current = <40>;
+				qcom,current-setting = <5>;
+				qcom,id = <6>;
+				qcom,mode-ctrl = <0x60>;
+				qcom,source-sel = <10>;
+				qcom,mode = "lpg";
+				qcom,pwm-channel = <5>;
+				qcom,start-idx = <1>;
+				qcom,duty-pcts = [00 00 00 00 64
+						 64 00 00 00 00];
+			};
+		};
+	};
+
+	qcom,pm8226@1 {
+                qcom,leds@d300 {
+                        status = "okay";
+                };
+
+		qcom,leds@d800 {
+			status = "okay";
+			qcom,wled_0 {
+				label = "wled";
+				linux,name = "wled:backlight";
+				linux,default-trigger = "bkl-trigger";
+				qcom,cs-out-en;
+				qcom,op-fdbck = <1>;
+				qcom,default-state = "on";
+				qcom,max-current = <25>;
+				qcom,ctrl-delay-us = <0>;
+				qcom,boost-curr-lim = <3>;
+				qcom,cp-sel = <0>;
+				qcom,switch-freq = <2>;
+				qcom,ovp-val = <0>;
+				qcom,num-strings = <1>;
+				qcom,id = <0>;
+			};
+		};
+
+		qcom,vibrator@c000 {
+			status = "okay";
+			qcom,vib-timeout-ms = <15000>;
+			qcom,vib-vtg-level-mV = <3100>;
+		};
+
+	};
+};
+
+&pm8226_bms {
+	status = "okay";
+	qcom,batt-type = <4>;
+	qcom,max-voltage-uv = <4350000>;
+};
+
+&pm8226_chg {
+	status = "okay";
+	qcom,chg-vddmax-mv = <4350>;
+	qcom,chg-vddsafe-mv = <4350>;
+};
+
+&pm8226_gpios {
+	gpio@c000 { /* GPIO 1 */
+		/* XO_PMIC_CDC_MCLK enable for tapan codec */
+		qcom,mode = <1>;		/* Digital output */
+		qcom,output-type = <0>;	/* CMOS logic */
+		qcom,pull = <5>;		/* QPNP_PIN_PULL_NO*/
+		qcom,vin-sel = <3>;		/* QPNP_PIN_VIN3 */
+		qcom,out-strength = <3>;/* QPNP_PIN_OUT_STRENGTH_HIGH */
+		qcom,src-sel = <2>;		/* QPNP_PIN_SEL_FUNC_1 */
+		qcom,master-en = <1>;	/* Enable GPIO */
+	};
+
+	gpio@c100 { /* GPIO 2 */
+		qcom,mode = <1>;
+		qcom,output-type = <0>;
+		qcom,pull = <5>;
+		qcom,vin-sel = <3>;
+		qcom,out-strength = <3>;
+		qcom,src-sel = <2>;
+		qcom,master-en = <1>;
+	};
+
+	gpio@c200 { /* GPIO 3 */
+	};
+
+	gpio@c300 { /* GPIO 4 */
+	};
+
+	gpio@c400 { /* GPIO 5 */
+	};
+
+	gpio@c500 { /* GPIO 6 */
+	};
+
+	gpio@c600 { /* GPIO 7 */
+	};
+
+	gpio@c700 { /* GPIO 8 */
+	};
+};
+
+&pm8226_mpps {
+	mpp@a000 { /* MPP 1 */
+	};
+
+	mpp@a100 { /* MPP 2 */
+	};
+
+	mpp@a200 { /* MPP 3 */
+	};
+
+	mpp@a300 { /* MPP 4 */
+	};
+
+	mpp@a400 { /* MPP 5 */
+	};
+
+	mpp@a500 { /* MPP 6 */
+	};
+
+	mpp@a600 { /* MPP 7 */
+	};
+
+	mpp@a700 { /* MPP 8 */
+	};
+};
+
+&slim_msm {
+	tapan_codec {
+		qcom,cdc-micbias1-ext-cap;
+	};
+
+};
diff --git a/arch/arm/boot/dts/msm8226-regulator.dtsi b/arch/arm/boot/dts/msm8226-regulator.dtsi
index 6aeaf49..f3b9779 100644
--- a/arch/arm/boot/dts/msm8226-regulator.dtsi
+++ b/arch/arm/boot/dts/msm8226-regulator.dtsi
@@ -30,8 +30,9 @@
 	apc_vreg_corner: regulator@f9018000 {
 		status = "okay";
 		compatible = "qcom,cpr-regulator";
-		reg = <0xf9018000 0x1000>, <0xfc4b80b0 8>, <0xfc4bc450 16>;
-		reg-names = "rbcpr", "pvs_efuse", "cpr_efuse";
+		reg = <0xf9018000 0x1000>, <0xf9011064 4>, <0xfc4b80b0 8>,
+			<0xfc4bc450 16>;
+		reg-names = "rbcpr", "rbcpr_clk", "pvs_efuse", "cpr_efuse";
 		interrupts = <0 15 0>;
 		regulator-name = "apc_corner";
 		regulator-min-microvolt = <1>;
@@ -420,3 +421,10 @@
 		};
 	};
 };
+
+&pm8226_chg_boost {
+	regulator-min-microvolt = <5000000>;
+	regulator-max-microvolt = <5000000>;
+	regulator-name = "8226_smbbp_boost";
+};
+
diff --git a/arch/arm/boot/dts/msm8226.dtsi b/arch/arm/boot/dts/msm8226.dtsi
index 9d77312..26e834f 100644
--- a/arch/arm/boot/dts/msm8226.dtsi
+++ b/arch/arm/boot/dts/msm8226.dtsi
@@ -26,7 +26,7 @@
 	memory {
 		secure_mem: secure_region {
 			linux,contiguous-region;
-			reg = <0 0x3800000>;
+			reg = <0 0x6D00000>;
 			label = "secure_mem";
 		};
 
@@ -271,6 +271,7 @@
 		compatible = "qcom,android-usb";
 		reg = <0xfe8050c8 0xc8>;
 		qcom,android-usb-cdrom;
+		qcom,android-usb-swfi-latency = <1>;
 	};
 
 	wcd9xxx_intc: wcd9xxx-irq {
@@ -328,7 +329,7 @@
 
 			qcom,cdc-micbias-ldoh-v = <0x3>;
 			qcom,cdc-micbias-cfilt1-mv = <1800>;
-			qcom,cdc-micbias-cfilt2-mv = <1800>;
+			qcom,cdc-micbias-cfilt2-mv = <2700>;
 			qcom,cdc-micbias-cfilt3-mv = <1800>;
 
 			qcom,cdc-micbias1-cfilt-sel = <0x0>;
@@ -546,7 +547,8 @@
 		qcom,iris-vdddig-supply = <&pm8226_l24>;
 
 		gpios = <&msmgpio 40 0>, <&msmgpio 41 0>, <&msmgpio 42 0>, <&msmgpio 43 0>, <&msmgpio 44 0>;
-		qcom,has_pronto_hw;
+		qcom,has-pronto-hw;
+		qcom,has-autodetect-xo;
 	};
 
 	qcom,msm-adsp-sensors {
@@ -640,6 +642,10 @@
 		rpm-channel-type = <15>; /* SMD_APPS_RPM */
 	};
 
+	qcom,bcl {
+		compatible = "qcom,bcl";
+	};
+
 	sdcc1: qcom,sdcc@f9824000 {
 		cell-index = <1>; /* SDC1 eMMC slot */
 		compatible = "qcom,msm-sdcc";
@@ -869,6 +875,7 @@
 		qcom,limit-temp = <60>;
 		qcom,temp-hysteresis = <10>;
 		qcom,freq-step = <2>;
+		qcom,freq-control-mask = <0xf>;
 	};
 
 	spi_0: spi@f9923000 { /* BLSP1 QUP1 */
@@ -983,8 +990,8 @@
 		qcom,msm-bus,active-only = <0>;
 		qcom,msm-bus,num-paths = <1>;
 		qcom,msm-bus,vectors-KBps =
-				<56 512 0 0>,
-				<56 512 3936000 393600>;
+				<55 512 0 0>,
+				<55 512 3936000 393600>;
 	};
 
         qcom,qcedev@fd400000 {
@@ -1001,8 +1008,8 @@
 		qcom,msm-bus,active-only = <0>;
 		qcom,msm-bus,num-paths = <1>;
 		qcom,msm-bus,vectors-KBps =
-				<56 512 0 0>,
-				<56 512 3936000 393600>;
+				<55 512 0 0>,
+				<55 512 3936000 393600>;
 	};
 };
 
diff --git a/arch/arm/boot/dts/msm8610-camera-sensor-cdp-mtp.dtsi b/arch/arm/boot/dts/msm8610-camera-sensor-cdp-mtp.dtsi
new file mode 100644
index 0000000..d057260
--- /dev/null
+++ b/arch/arm/boot/dts/msm8610-camera-sensor-cdp-mtp.dtsi
@@ -0,0 +1,116 @@
+/*
+ * 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.
+ */
+
+&i2c {
+
+	led_flash0: qcom,led-flash@60 {
+		cell-index = <0>;
+		reg = <0x60>;
+		qcom,slave-id = <0x60 0x00 0x0011>;
+		compatible = "qcom,led-flash";
+		qcom,flash-name = "adp1600";
+		qcom,flash-type = <1>;
+		qcom,gpio-no-mux = <0>;
+		gpios = <&msmgpio 18 0>,
+			<&msmgpio 19 0>;
+		qcom,gpio-flash-en = <0>;
+		qcom,gpio-flash-now = <1>;
+		qcom,gpio-req-tbl-num = <0 1>;
+		qcom,gpio-req-tbl-flags = <0 0>;
+		qcom,gpio-req-tbl-label = "FLASH_EN",
+			"FLASH_NOW";
+	};
+
+	actuator0: qcom,actuator@6e {
+		cell-index = <3>;
+		reg = <0x6c>;
+		compatible = "qcom,actuator";
+		qcom,cci-master = <0>;
+	};
+
+	qcom,camera@6f {
+		compatible = "qcom,ov8825";
+		reg = <0x6f>;
+		qcom,slave-id = <0x6c 0x300a 0x8825>;
+		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 = "ov8825";
+		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,csi-lane-assign = <0xe4>;
+		qcom,csi-lane-mask = <0x3>;
+		qcom,sensor-position = <0>;
+		qcom,sensor-mode = <1>;
+		qcom,cci-master = <0>;
+	};
+
+	qcom,camera@6d {
+		compatible = "qcom,ov9724";
+		reg = <0x6d>;
+		qcom,slave-id = <0x20 0x0 0x9724>;
+		qcom,csiphy-sd-index = <1>;
+		qcom,csid-sd-index = <0>;
+		qcom,mount-angle = <90>;
+		qcom,sensor-name = "ov9724";
+		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,gpio-set-tbl-num = <1 1>;
+		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,sensor-position = <1>;
+		qcom,sensor-mode = <1>;
+		qcom,cci-master = <0>;
+		status = "ok";
+	};
+};
diff --git a/arch/arm/boot/dts/msm8610-camera.dtsi b/arch/arm/boot/dts/msm8610-camera.dtsi
new file mode 100644
index 0000000..b1c94dd
--- /dev/null
+++ b/arch/arm/boot/dts/msm8610-camera.dtsi
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+&soc{
+	qcom,msm-cam@fd8c0000 {
+		compatible = "qcom,msm-cam";
+		reg = <0xfd8C0000 0x10000>;
+		reg-names = "msm-cam";
+	};
+
+	qcom,csiphy@fda00c00 {
+		cell-index = <0>;
+		compatible = "qcom,csiphy";
+		reg = <0xfda00c00 0x1f4>;
+		reg-names = "csiphy";
+		interrupts = <0 78 0>;
+		interrupt-names = "csiphy";
+	};
+
+	qcom,csiphy@fda01000 {
+		cell-index = <1>;
+		compatible = "qcom,csiphy";
+		reg = <0xfda01000 0x1f4>;
+		reg-names = "csiphy";
+		interrupts = <0 79 0>;
+		interrupt-names = "csiphy";
+	};
+
+	qcom,csid@fda00000 {
+		cell-index = <0>;
+		compatible = "qcom,csid";
+		reg = <0xfda00000 0x100>;
+		reg-names = "csid";
+		interrupts = <0 50 0>;
+		interrupt-names = "csid";
+		qcom,csi-vdd-voltage = <1200000>;
+		qcom,mipi-csi-vdd-supply = <&pm8110_l4>;
+	};
+
+	qcom,csid@fda00400 {
+		cell-index = <1>;
+		compatible = "qcom,csid";
+		reg = <0xfda00400 0x100>;
+		reg-names = "csid";
+		interrupts = <0 51 0>;
+		interrupt-names = "csid";
+		qcom,csi-vdd-voltage = <1200000>;
+		qcom,mipi-csi-vdd-supply = <&pm8110_l4>;
+	};
+
+	qcom,ispif@fda00800 {
+		cell-index = <0>;
+		compatible = "qcom,ispif";
+		reg = <0xfda00800 0x200>;
+		reg-names = "ispif";
+		interrupts = <0 52 0>;
+		interrupt-names = "ispif";
+	};
+
+	qcom,vfe@fde00000 {
+		cell-index = <0>;
+		compatible = "qcom,vfe32";
+		reg = <0xfde00000 0x800>;
+		reg-names = "vfe", "vfe_vbif";
+		interrupts = <0 49 0>;
+		interrupt-names = "vfe";
+		vdd-supply = <&gdsc_vfe>;
+	};
+
+};
diff --git a/arch/arm/boot/dts/msm8610-cdp.dts b/arch/arm/boot/dts/msm8610-cdp.dts
index d3fc917..cdad6a7 100644
--- a/arch/arm/boot/dts/msm8610-cdp.dts
+++ b/arch/arm/boot/dts/msm8610-cdp.dts
@@ -14,6 +14,7 @@
 
 /include/ "msm8610.dtsi"
 /include/ "dsi-v2-panel-truly-wvga-video.dtsi"
+/include/ "msm8610-camera-sensor-cdp-mtp.dtsi"
 
 / {
 	model = "Qualcomm MSM 8610 CDP";
@@ -191,6 +192,7 @@
 				qcom,id = <6>;
 				qcom,source-sel = <1>;
 				qcom,mode-ctrl = <0x60>;
+				qcom,mode = "manual";
 			};
 		};
 
@@ -205,6 +207,7 @@
 				qcom,id = <6>;
 				qcom,source-sel = <1>;
 				qcom,mode-ctrl = <0x10>;
+				qcom,mode = "manual";
 			};
 		};
 	};
@@ -229,6 +232,7 @@
 
 	vdd-io-supply = <&pm8110_l6>;
 	qcom,vdd-io-always-on;
+	qcom,vdd-io-lpm-sup;
 	qcom,vdd-io-voltage-level = <1800000 1800000>;
 	qcom,vdd-io-current-level = <200 60000>;
 
@@ -250,8 +254,6 @@
 	qcom,vdd-current-level = <15000 400000>;
 
 	vdd-io-supply = <&pm8110_l21>;
-	qcom,vdd-io-always-on;
-	qcom,vdd-io-lpm-sup;
 	qcom,vdd-io-voltage-level = <1800000 2950000>;
 	qcom,vdd-io-current-level = <200 50000>;
 
diff --git a/arch/arm/boot/dts/msm8610-mdss.dtsi b/arch/arm/boot/dts/msm8610-mdss.dtsi
index 1766422..af0e3e4 100644
--- a/arch/arm/boot/dts/msm8610-mdss.dtsi
+++ b/arch/arm/boot/dts/msm8610-mdss.dtsi
@@ -21,7 +21,7 @@
 			cell-index = <0>;
 			compatible = "qcom,mdss-fb";
 			qcom,memory-reservation-type = "EBI1";
-			qcom,memory-reservation-size = <0x800000>;
+			qcom,memory-reservation-size = <0x300000>;
 		};
 	};
 
diff --git a/arch/arm/boot/dts/msm8610-mtp.dts b/arch/arm/boot/dts/msm8610-mtp.dts
index e1fe66a..222c4cb 100644
--- a/arch/arm/boot/dts/msm8610-mtp.dts
+++ b/arch/arm/boot/dts/msm8610-mtp.dts
@@ -14,6 +14,7 @@
 
 /include/ "msm8610.dtsi"
 /include/ "dsi-v2-panel-truly-wvga-video.dtsi"
+/include/ "msm8610-camera-sensor-cdp-mtp.dtsi"
 
 / {
 	model = "Qualcomm MSM 8610 MTP";
@@ -191,6 +192,7 @@
 				qcom,id = <6>;
 				qcom,source-sel = <1>;
 				qcom,mode-ctrl = <0x60>;
+				qcom,mode = "manual";
 			};
 		};
 
@@ -205,6 +207,7 @@
 				qcom,id = <6>;
 				qcom,source-sel = <1>;
 				qcom,mode-ctrl = <0x10>;
+				qcom,mode = "manual";
 			};
 		};
 	};
@@ -229,6 +232,7 @@
 
 	vdd-io-supply = <&pm8110_l6>;
 	qcom,vdd-io-always-on;
+	qcom,vdd-io-lpm-sup;
 	qcom,vdd-io-voltage-level = <1800000 1800000>;
 	qcom,vdd-io-current-level = <200 60000>;
 
@@ -250,8 +254,6 @@
 	qcom,vdd-current-level = <15000 400000>;
 
 	vdd-io-supply = <&pm8110_l21>;
-	qcom,vdd-io-always-on;
-	qcom,vdd-io-lpm-sup;
 	qcom,vdd-io-voltage-level = <1800000 2950000>;
 	qcom,vdd-io-current-level = <200 50000>;
 
diff --git a/arch/arm/boot/dts/msm8610-regulator.dtsi b/arch/arm/boot/dts/msm8610-regulator.dtsi
index a90f053..2c17780 100644
--- a/arch/arm/boot/dts/msm8610-regulator.dtsi
+++ b/arch/arm/boot/dts/msm8610-regulator.dtsi
@@ -30,8 +30,9 @@
 	apc_vreg_corner: regulator@f9018000 {
 		status = "okay";
 		compatible = "qcom,cpr-regulator";
-		reg = <0xf9018000 0x1000>, <0xfc4b80b0 8>, <0xfc4bc450 16>;
-		reg-names = "rbcpr", "pvs_efuse", "cpr_efuse";
+		reg = <0xf9018000 0x1000>, <0xf9011064 4>, <0xfc4b80b0 8>,
+			<0xfc4bc450 16>;
+		reg-names = "rbcpr", "rbcpr_clk", "pvs_efuse", "cpr_efuse";
 		interrupts = <0 15 0>;
 		regulator-name = "apc_corner";
 		regulator-min-microvolt = <1>;
diff --git a/arch/arm/boot/dts/msm8610.dtsi b/arch/arm/boot/dts/msm8610.dtsi
index 9dbd71d..474f809 100644
--- a/arch/arm/boot/dts/msm8610.dtsi
+++ b/arch/arm/boot/dts/msm8610.dtsi
@@ -33,6 +33,7 @@
 	soc: soc { };
 };
 
+/include/ "msm8610-camera.dtsi"
 /include/ "msm-iommu-v0.dtsi"
 /include/ "msm8610-ion.dtsi"
 /include/ "msm8610-gpu.dtsi"
@@ -472,7 +473,7 @@
                 qcom,i2c-bus-freq = <100000>;
         };
 
-	i2c@f9928000 { /* BLSP1 QUP6 */
+	i2c: i2c@f9928000 { /* BLSP1 QUP6 */
 		cell-index = <6>;
 		compatible = "qcom,i2c-qup";
 		#address-cells = <1>;
@@ -667,7 +668,8 @@
 		qcom,iris-vdddig-supply = <&pm8110_l5>;
 
 		gpios = <&msmgpio 23 0>, <&msmgpio 24 0>, <&msmgpio 25 0>, <&msmgpio 26 0>, <&msmgpio 27 0>;
-		qcom,has_pronto_hw;
+		qcom,has-pronto-hw;
+		qcom,wlan-rx-buff-count = <256>;
 	};
 
 	qcom,mss@fc880000 {
@@ -736,6 +738,7 @@
 		qcom,limit-temp = <60>;
 		qcom,temp-hysteresis = <10>;
 		qcom,freq-step = <2>;
+		qcom,freq-control-mask = <0xf>;
 	};
 
 	qcom,ipc-spinlock@fd484000 {
@@ -812,6 +815,43 @@
 		compatible = "qcom,tz-log";
 		reg = <0x0fe805720 0x1000>;
 	};
+
+	qcom,qcrypto@fd404000 {
+		compatible = "qcom,qcrypto";
+                reg  =  <0xfd400000 0x20000>,
+                        <0xfd404000 0x8000>;
+		reg-names = "crypto-base","crypto-bam-base";
+		interrupts = <0 207 0>;
+		qcom,bam-pipe-pair = <2>;
+		qcom,ce-hw-instance = <1>;
+		qcom,ce-hw-shared;
+		qcom,msm-bus,name = "qcrypto-noc";
+		qcom,msm-bus,num-cases = <2>;
+		qcom,msm-bus,active-only = <0>;
+		qcom,msm-bus,num-paths = <1>;
+		qcom,msm-bus,vectors-KBps =
+				<55 512 0 0>,
+				<55 512 393600 3936000>;
+	};
+
+        qcom,qcedev@fd400000 {
+		compatible = "qcom,qcedev";
+		reg  =  <0xfd400000 0x20000>,
+			<0xfd404000 0x8000>;
+		reg-names = "crypto-base","crypto-bam-base";
+		interrupts = <0 207 0>;
+		qcom,bam-pipe-pair = <1>;
+		qcom,ce-hw-instance = <1>;
+		qcom,ce-hw-shared;
+		qcom,msm-bus,name = "qcedev-noc";
+		qcom,msm-bus,num-cases = <2>;
+		qcom,msm-bus,active-only = <0>;
+		qcom,msm-bus,num-paths = <1>;
+		qcom,msm-bus,vectors-KBps =
+				<55 512 0 0>,
+				<55 512 393600 3936000>;
+	};
+
 };
 
 &gdsc_vfe {
diff --git a/arch/arm/mach-msm/clock-mdss-8226.h b/arch/arm/boot/dts/msm8926-cdp.dts
similarity index 62%
copy from arch/arm/mach-msm/clock-mdss-8226.h
copy to arch/arm/boot/dts/msm8926-cdp.dts
index dcf4f92..7a91d40 100644
--- a/arch/arm/mach-msm/clock-mdss-8226.h
+++ b/arch/arm/boot/dts/msm8926-cdp.dts
@@ -10,13 +10,13 @@
  * GNU General Public License for more details.
  */
 
-#ifndef __ARCH_ARM_MACH_MSM_CLOCK_MDSS_8226
-#define __ARCH_ARM_MACH_MSM_CLOCK_MDSS_8226
 
-extern struct clk_ops clk_ops_dsi_byte_pll;
-extern struct clk_ops clk_ops_dsi_pixel_pll;
+/dts-v1/;
+/include/ "msm8926.dtsi"
+/include/ "msm8226-cdp.dtsi"
 
-void mdss_clk_ctrl_pre_init(struct clk *ahb_clk);
-void mdss_clk_ctrl_post_init(void);
-
-#endif /* __ARCH_ARM_MACH_MSM_CLOCK_MDSS_8226 */
+/ {
+	model = "Qualcomm MSM 8926 CDP";
+	compatible = "qcom,msm8926-cdp", "qcom,msm8926", "qcom,cdp";
+	qcom,msm-id = <200 1 0>;
+};
diff --git a/arch/arm/mach-msm/clock-mdss-8226.h b/arch/arm/boot/dts/msm8926-mtp.dts
similarity index 62%
copy from arch/arm/mach-msm/clock-mdss-8226.h
copy to arch/arm/boot/dts/msm8926-mtp.dts
index dcf4f92..fea925d 100644
--- a/arch/arm/mach-msm/clock-mdss-8226.h
+++ b/arch/arm/boot/dts/msm8926-mtp.dts
@@ -10,13 +10,13 @@
  * GNU General Public License for more details.
  */
 
-#ifndef __ARCH_ARM_MACH_MSM_CLOCK_MDSS_8226
-#define __ARCH_ARM_MACH_MSM_CLOCK_MDSS_8226
 
-extern struct clk_ops clk_ops_dsi_byte_pll;
-extern struct clk_ops clk_ops_dsi_pixel_pll;
+/dts-v1/;
+/include/ "msm8926.dtsi"
+/include/ "msm8226-mtp.dtsi"
 
-void mdss_clk_ctrl_pre_init(struct clk *ahb_clk);
-void mdss_clk_ctrl_post_init(void);
-
-#endif /* __ARCH_ARM_MACH_MSM_CLOCK_MDSS_8226 */
+/ {
+	model = "Qualcomm MSM 8926 MTP";
+	compatible = "qcom,msm8926-mtp", "qcom,msm8926", "qcom,mtp";
+	qcom,msm-id = <200 8 0>;
+};
diff --git a/arch/arm/mach-msm/clock-mdss-8226.h b/arch/arm/boot/dts/msm8926-qrd.dts
similarity index 62%
copy from arch/arm/mach-msm/clock-mdss-8226.h
copy to arch/arm/boot/dts/msm8926-qrd.dts
index dcf4f92..e056b7e 100644
--- a/arch/arm/mach-msm/clock-mdss-8226.h
+++ b/arch/arm/boot/dts/msm8926-qrd.dts
@@ -10,13 +10,12 @@
  * GNU General Public License for more details.
  */
 
-#ifndef __ARCH_ARM_MACH_MSM_CLOCK_MDSS_8226
-#define __ARCH_ARM_MACH_MSM_CLOCK_MDSS_8226
+/dts-v1/;
+/include/ "msm8926.dtsi"
+/include/ "msm8226-qrd.dtsi"
 
-extern struct clk_ops clk_ops_dsi_byte_pll;
-extern struct clk_ops clk_ops_dsi_pixel_pll;
-
-void mdss_clk_ctrl_pre_init(struct clk *ahb_clk);
-void mdss_clk_ctrl_post_init(void);
-
-#endif /* __ARCH_ARM_MACH_MSM_CLOCK_MDSS_8226 */
+/ {
+	model = "Qualcomm MSM 8926 QRD";
+	compatible = "qcom,msm8926-qrd", "qcom,msm8926", "qcom,qrd";
+	qcom,msm-id = <200 11 0>;
+};
diff --git a/arch/arm/mach-msm/clock-mdss-8226.h b/arch/arm/boot/dts/msm8926.dtsi
similarity index 62%
copy from arch/arm/mach-msm/clock-mdss-8226.h
copy to arch/arm/boot/dts/msm8926.dtsi
index dcf4f92..390bcc1 100644
--- a/arch/arm/mach-msm/clock-mdss-8226.h
+++ b/arch/arm/boot/dts/msm8926.dtsi
@@ -10,13 +10,15 @@
  * GNU General Public License for more details.
  */
 
-#ifndef __ARCH_ARM_MACH_MSM_CLOCK_MDSS_8226
-#define __ARCH_ARM_MACH_MSM_CLOCK_MDSS_8226
+/*
+ * Only 8926-specific property overrides should be placed inside this
+ * file. Device definitions should be placed inside the msm8226.dtsi
+ * file.
+ */
 
-extern struct clk_ops clk_ops_dsi_byte_pll;
-extern struct clk_ops clk_ops_dsi_pixel_pll;
+/include/ "msm8226.dtsi"
 
-void mdss_clk_ctrl_pre_init(struct clk *ahb_clk);
-void mdss_clk_ctrl_post_init(void);
-
-#endif /* __ARCH_ARM_MACH_MSM_CLOCK_MDSS_8226 */
+/ {
+	model = "Qualcomm MSM 8926";
+	compatible = "qcom,msm8926";
+};
diff --git a/arch/arm/boot/dts/msm8974-camera-sensor-cdp.dtsi b/arch/arm/boot/dts/msm8974-camera-sensor-cdp.dtsi
index efd9c32..4a9820d 100644
--- a/arch/arm/boot/dts/msm8974-camera-sensor-cdp.dtsi
+++ b/arch/arm/boot/dts/msm8974-camera-sensor-cdp.dtsi
@@ -36,6 +36,8 @@
 		qcom,actuator-src = <&actuator0>;
 		qcom,mount-angle = <90>;
 		qcom,sensor-name = "s5k3l1yx";
+		qcom,vdd-cx-supply = <&pm8841_s2>;
+		qcom,vdd-cx-name = "qcom,vdd-cx";
 		cam_vdig-supply = <&pm8941_l3>;
 		cam_vana-supply = <&pm8941_l17>;
 		cam_vio-supply = <&pm8941_lvs3>;
@@ -77,6 +79,8 @@
 		qcom,mount-angle = <90>;
 		qcom,sensor-name = "imx135";
 		qcom,actuator-src = <&actuator1>;
+		qcom,vdd-cx-supply = <&pm8841_s2>;
+		qcom,vdd-cx-name = "qcom,vdd-cx";
 		cam_vdig-supply = <&pm8941_l3>;
 		cam_vana-supply = <&pm8941_l17>;
 		cam_vio-supply = <&pm8941_lvs3>;
@@ -118,6 +122,8 @@
 		qcom,csid-sd-index = <2>;
 		qcom,mount-angle = <90>;
 		qcom,sensor-name = "ov2720";
+		qcom,vdd-cx-supply = <&pm8841_s2>;
+		qcom,vdd-cx-name = "qcom,vdd-cx";
 		cam_vdig-supply = <&pm8941_l3>;
 		cam_vana-supply = <&pm8941_l17>;
 		cam_vio-supply = <&pm8941_lvs3>;
@@ -153,6 +159,8 @@
 		qcom,csid-sd-index = <0>;
 		qcom,mount-angle = <0>;
 		qcom,sensor-name = "mt9m114";
+		qcom,vdd-cx-supply = <&pm8841_s2>;
+		qcom,vdd-cx-name = "qcom,vdd-cx";
 		cam_vdig-supply = <&pm8941_l3>;
 		cam_vana-supply = <&pm8941_l17>;
 		cam_vio-supply = <&pm8941_lvs3>;
diff --git a/arch/arm/boot/dts/msm8974-camera-sensor-dragonboard.dtsi b/arch/arm/boot/dts/msm8974-camera-sensor-dragonboard.dtsi
new file mode 100644
index 0000000..e84a47d
--- /dev/null
+++ b/arch/arm/boot/dts/msm8974-camera-sensor-dragonboard.dtsi
@@ -0,0 +1,174 @@
+/*
+ * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+&cci {
+
+	actuator0: qcom,actuator@18 {
+		cell-index = <0>;
+		reg = <0x18 0x0>;
+		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@6e {
+		compatible = "qcom,s5k3l1yx";
+		reg = <0x6e 0x0>;
+		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_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>;
+		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 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_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>;
+		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 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@6c {
+		compatible = "qcom,ov2720";
+		reg = <0x6c 0x0>;
+		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_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 0x0>;
+		qcom,slave-id = <0x90 0x0 0x2481>;
+		qcom,csiphy-sd-index = <1>;
+		qcom,csid-sd-index = <0>;
+		qcom,mount-angle = <0>;
+		qcom,sensor-name = "mt9m114";
+		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 16 0>,
+			<&msmgpio 94 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 = <0x3>;
+		qcom,sensor-position = <1>;
+		qcom,sensor-mode = <1>;
+		qcom,cci-master = <0>;
+	};
+};
diff --git a/arch/arm/boot/dts/msm8974-camera-sensor-fluid.dtsi b/arch/arm/boot/dts/msm8974-camera-sensor-fluid.dtsi
index 9cbd45c..f61b83a 100644
--- a/arch/arm/boot/dts/msm8974-camera-sensor-fluid.dtsi
+++ b/arch/arm/boot/dts/msm8974-camera-sensor-fluid.dtsi
@@ -37,6 +37,8 @@
 		qcom,led-flash-src = <&led_flash0>;
 		qcom,mount-angle = <270>;
 		qcom,sensor-name = "s5k3l1yx";
+		qcom,vdd-cx-supply = <&pm8841_s2>;
+		qcom,vdd-cx-name = "qcom,vdd-cx";
 		cam_vdig-supply = <&pm8941_l3>;
 		cam_vana-supply = <&pm8941_l17>;
 		cam_vio-supply = <&pm8941_lvs3>;
@@ -78,6 +80,8 @@
 		qcom,mount-angle = <270>;
 		qcom,sensor-name = "imx135";
 		qcom,actuator-src = <&actuator1>;
+		qcom,vdd-cx-supply = <&pm8841_s2>;
+		qcom,vdd-cx-name = "qcom,vdd-cx";
 		cam_vdig-supply = <&pm8941_l3>;
 		cam_vana-supply = <&pm8941_l17>;
 		cam_vio-supply = <&pm8941_lvs3>;
@@ -119,6 +123,8 @@
 		qcom,csid-sd-index = <2>;
 		qcom,mount-angle = <90>;
 		qcom,sensor-name = "ov2720";
+		qcom,vdd-cx-supply = <&pm8841_s2>;
+		qcom,vdd-cx-name = "qcom,vdd-cx";
 		cam_vdig-supply = <&pm8941_l3>;
 		cam_vana-supply = <&pm8941_l17>;
 		cam_vio-supply = <&pm8941_lvs3>;
@@ -154,6 +160,8 @@
 		qcom,csid-sd-index = <0>;
 		qcom,mount-angle = <0>;
 		qcom,sensor-name = "mt9m114";
+		qcom,vdd-cx-supply = <&pm8841_s2>;
+		qcom,vdd-cx-name = "qcom,vdd-cx";
 		cam_vdig-supply = <&pm8941_l3>;
 		cam_vana-supply = <&pm8941_l17>;
 		cam_vio-supply = <&pm8941_lvs3>;
diff --git a/arch/arm/boot/dts/msm8974-camera-sensor-liquid.dtsi b/arch/arm/boot/dts/msm8974-camera-sensor-liquid.dtsi
index e9d3d75..e0b572e 100644
--- a/arch/arm/boot/dts/msm8974-camera-sensor-liquid.dtsi
+++ b/arch/arm/boot/dts/msm8974-camera-sensor-liquid.dtsi
@@ -36,6 +36,8 @@
 		qcom,csid-sd-index = <0>;
 		qcom,mount-angle = <0>;
 		qcom,sensor-name = "s5k3l1yx";
+		qcom,vdd-cx-supply = <&pm8841_s2>;
+		qcom,vdd-cx-name = "qcom,vdd-cx";
 		cam_vdig-supply = <&pm8941_l3>;
 		cam_vana-supply = <&pm8941_l17>;
 		cam_vio-supply = <&pm8941_lvs2>;
@@ -73,6 +75,8 @@
 		qcom,csid-sd-index = <0>;
 		qcom,mount-angle = <0>;
 		qcom,sensor-name = "imx135";
+		qcom,vdd-cx-supply = <&pm8841_s2>;
+		qcom,vdd-cx-name = "qcom,vdd-cx";
 		qcom,actuator-src = <&actuator1>;
 		cam_vdig-supply = <&pm8941_l3>;
 		cam_vana-supply = <&pm8941_l17>;
@@ -115,6 +119,8 @@
 		qcom,csid-sd-index = <0>;
 		qcom,mount-angle = <180>;
 		qcom,sensor-name = "ov2720";
+		qcom,vdd-cx-supply = <&pm8841_s2>;
+		qcom,vdd-cx-name = "qcom,vdd-cx";
 		cam_vdig-supply = <&pm8941_l3>;
 		cam_vana-supply = <&pm8941_l17>;
 		cam_vio-supply = <&pm8941_lvs2>;
@@ -149,6 +155,8 @@
 		qcom,csiphy-sd-index = <1>;
 		qcom,csid-sd-index = <0>;
 		qcom,mount-angle = <0>;
+		qcom,vdd-cx-supply = <&pm8841_s2>;
+		qcom,vdd-cx-name = "qcom,vdd-cx";
 		qcom,sensor-name = "mt9m114";
 		cam_vdig-supply = <&pm8941_l3>;
 		cam_vana-supply = <&pm8941_l17>;
diff --git a/arch/arm/boot/dts/msm8974-camera-sensor-mtp.dtsi b/arch/arm/boot/dts/msm8974-camera-sensor-mtp.dtsi
index 68af4a6..6ad6213 100644
--- a/arch/arm/boot/dts/msm8974-camera-sensor-mtp.dtsi
+++ b/arch/arm/boot/dts/msm8974-camera-sensor-mtp.dtsi
@@ -37,6 +37,8 @@
 		qcom,led-flash-src = <&led_flash0>;
 		qcom,mount-angle = <90>;
 		qcom,sensor-name = "s5k3l1yx";
+		qcom,vdd-cx-supply = <&pm8841_s2>;
+		qcom,vdd-cx-name = "qcom,vdd-cx";
 		cam_vdig-supply = <&pm8941_l3>;
 		cam_vana-supply = <&pm8941_l17>;
 		cam_vio-supply = <&pm8941_lvs3>;
@@ -77,6 +79,8 @@
 		qcom,csid-sd-index = <0>;
 		qcom,mount-angle = <90>;
 		qcom,sensor-name = "imx135";
+		qcom,vdd-cx-supply = <&pm8841_s2>;
+		qcom,vdd-cx-name = "qcom,vdd-cx";
 		qcom,actuator-src = <&actuator1>;
 		cam_vdig-supply = <&pm8941_l3>;
 		cam_vana-supply = <&pm8941_l17>;
@@ -120,6 +124,8 @@
 		qcom,csid-sd-index = <2>;
 		qcom,mount-angle = <90>;
 		qcom,sensor-name = "ov2720";
+		qcom,vdd-cx-supply = <&pm8841_s2>;
+		qcom,vdd-cx-name = "qcom,vdd-cx";
 		cam_vdig-supply = <&pm8941_l3>;
 		cam_vana-supply = <&pm8941_l17>;
 		cam_vio-supply = <&pm8941_lvs3>;
@@ -155,6 +161,8 @@
 		qcom,csid-sd-index = <0>;
 		qcom,mount-angle = <0>;
 		qcom,sensor-name = "mt9m114";
+		qcom,vdd-cx-supply = <&pm8841_s2>;
+		qcom,vdd-cx-name = "qcom,vdd-cx";
 		cam_vdig-supply = <&pm8941_l3>;
 		cam_vana-supply = <&pm8941_l17>;
 		cam_vio-supply = <&pm8941_lvs3>;
diff --git a/arch/arm/boot/dts/msm8974-fluid.dtsi b/arch/arm/boot/dts/msm8974-fluid.dtsi
index ad5f175..a822af5 100644
--- a/arch/arm/boot/dts/msm8974-fluid.dtsi
+++ b/arch/arm/boot/dts/msm8974-fluid.dtsi
@@ -608,12 +608,6 @@
 	};
 
 	mpp@a400 { /* MPP 5 */
-		/* SPI_ETH config */
-		qcom,mode = <1>; /* DIG_OUT */
-		qcom,output-type = <0>; /* CMOS */
-		qcom,vin-sel = <2>; /* PM8941_S3 1.8V > 1.6V */
-		qcom,src-sel = <0>; /* CONSTANT */
-		qcom,master-en = <1>; /* ENABLE MPP */
 	};
 
 	mpp@a500 { /* MPP 6 */
diff --git a/arch/arm/boot/dts/msm8974-gpu.dtsi b/arch/arm/boot/dts/msm8974-gpu.dtsi
index 669097e..5172a5a 100644
--- a/arch/arm/boot/dts/msm8974-gpu.dtsi
+++ b/arch/arm/boot/dts/msm8974-gpu.dtsi
@@ -51,6 +51,14 @@
 		/* IOMMU Data */
 		iommu = <&kgsl_iommu>;
 
+		/* Trace bus */
+		coresight-id = <67>;
+		coresight-name = "coresight-gfx";
+		coresight-nr-inports = <0>;
+		coresight-outports = <0>;
+		coresight-child-list = <&funnel_mmss>;
+		coresight-child-ports = <7>;
+
 		qcom,gpu-pwrlevels {
 			#address-cells = <1>;
 			#size-cells = <0>;
diff --git a/arch/arm/boot/dts/msm8974-leds.dtsi b/arch/arm/boot/dts/msm8974-leds.dtsi
index b39cc21..5e91f45 100644
--- a/arch/arm/boot/dts/msm8974-leds.dtsi
+++ b/arch/arm/boot/dts/msm8974-leds.dtsi
@@ -18,7 +18,7 @@
 			qcom,rgb_0 {
 				label = "rgb";
 				linux,name = "led:rgb_red";
-				qcom,mode = <0>;
+				qcom,mode = "pwm";
 				qcom,pwm-channel = <6>;
 				qcom,pwm-us = <1000>;
 				qcom,max-current = <12>;
@@ -31,7 +31,7 @@
 			qcom,rgb_1 {
 				label = "rgb";
 				linux,name = "led:rgb_green";
-				qcom,mode = <0>;
+				qcom,mode = "pwm";
 				qcom,pwm-channel = <5>;
 				qcom,pwm-us = <1000>;
 				qcom,max-current = <12>;
@@ -43,7 +43,7 @@
 			qcom,rgb_2 {
 				label = "rgb";
 				linux,name = "led:rgb_blue";
-				qcom,mode = <0>;
+				qcom,mode = "pwm";
 				qcom,pwm-channel = <4>;
 				qcom,pwm-us = <1000>;
 				qcom,max-current = <12>;
@@ -65,10 +65,10 @@
 			pm8941_flash0: qcom,flash_0 {
 				qcom,max-current = <1000>;
 				qcom,default-state = "off";
-				qcom,headroom = <0>;
+				qcom,headroom = <3>;
 				qcom,duration = <1280>;
 				qcom,clamp-curr = <200>;
-				qcom,startup-dly = <1>;
+				qcom,startup-dly = <3>;
 				qcom,safety-timer;
 				label = "flash";
 				linux,default-trigger =
@@ -81,10 +81,10 @@
 			pm8941_flash1: qcom,flash_1 {
 				qcom,max-current = <1000>;
 				qcom,default-state = "off";
-				qcom,headroom = <0>;
+				qcom,headroom = <3>;
 				qcom,duration = <1280>;
 				qcom,clamp-curr = <200>;
-				qcom,startup-dly = <1>;
+				qcom,startup-dly = <3>;
 				qcom,safety-timer;
 				linux,default-trigger =
 					"flash1_trigger";
diff --git a/arch/arm/boot/dts/msm8974-liquid.dtsi b/arch/arm/boot/dts/msm8974-liquid.dtsi
index c2dae28..fa8c240 100644
--- a/arch/arm/boot/dts/msm8974-liquid.dtsi
+++ b/arch/arm/boot/dts/msm8974-liquid.dtsi
@@ -406,6 +406,29 @@
 					<85 512 40000 160000>;
 		};
 	};
+
+        wlan0: qca,wlan {
+                compatible = "qca,ar6004-hsic";
+                qcom,msm-bus,name = "wlan";
+                qca,wifi-chip-pwd-supply = <&ath_chip_pwd_l>;
+                qca,wifi-vddpa-supply = <&pm8941_l19>;
+                qca,wifi-vddio-supply = <&pm8941_l10>;
+                qcom,msm-bus,num-cases = <5>;
+                qcom,msm-bus,active-only = <0>;
+                qcom,msm-bus,num-paths = <1>;
+                qcom,msm-bus,vectors-KBps =
+                        <85 512 0 0>,
+                        <85 512 40000 160000>,
+                        <85 512 40000 320000>,
+                        <85 512 40000 480000>,
+                        <85 512 40000 800000>;
+        };
+
+        wlan_sdio:qca,wlan_sdio {
+                compatible = "qca,ar6004-sdio";
+                qcom,msm-bus,name = "wlan_sdio";
+                qca,wifi-chip-pwd-supply = <&ath_chip_pwd_l>;
+        };
 };
 
 &mdss_fb0 {
@@ -424,10 +447,6 @@
 	qcom,otg-capability;
 };
 
-&pm8941_mvs1 {
-	parent-supply = <&ext_5v>;
-};
-
 &pm8941_mvs2 {
 	parent-supply = <&ext_5v>;
 };
@@ -777,6 +796,7 @@
 
 &pm8941_chg {
 	status = "ok";
+	otg-parent-supply = <&ext_5v>;
 
 	qcom,charging-disabled;
 
diff --git a/arch/arm/boot/dts/msm8974-mtp.dtsi b/arch/arm/boot/dts/msm8974-mtp.dtsi
index 4d28a1d..e798fc0 100644
--- a/arch/arm/boot/dts/msm8974-mtp.dtsi
+++ b/arch/arm/boot/dts/msm8974-mtp.dtsi
@@ -637,13 +637,6 @@
 	};
 
 	mpp@a400 { /* MPP 5 */
-		/* SPI_ETH config */
-		qcom,mode = <1>; /* DIG_OUT */
-		qcom,output-type = <0>; /* CMOS */
-		qcom,vin-sel = <2>; /* PM8941_S3 1.8V > 1.6V */
-		qcom,src-sel = <0>; /* CONSTANT */
-		qcom,out-strength = <1>;  /* QPNP_PIN_OUT_STRENGTH_LOW */
-		qcom,master-en = <1>; /* ENABLE MPP */
 	};
 
 	mpp@a500 { /* MPP 6 */
diff --git a/arch/arm/boot/dts/msm8974-regulator.dtsi b/arch/arm/boot/dts/msm8974-regulator.dtsi
index 35f3993..2114686 100644
--- a/arch/arm/boot/dts/msm8974-regulator.dtsi
+++ b/arch/arm/boot/dts/msm8974-regulator.dtsi
@@ -25,7 +25,7 @@
 		};
 
 		pm8941_mvs1: regulator@8300 {
-			parent-supply = <&pm8941_boost>;
+			parent-supply = <&pm8941_chg_otg>;
 			qcom,enable-time = <1000>;
 			qcom,pull-down-enable = <1>;
 			interrupts = <0x1 0x83 0x2>;
@@ -552,3 +552,17 @@
 		regulator-always-on;
 	};
 };
+
+&pm8941_chg {
+	otg-parent-supply = <&pm8941_boost>;
+};
+
+&pm8941_chg_boost {
+	regulator-min-microvolt = <5000000>;
+	regulator-max-microvolt = <5000000>;
+	regulator-name = "8941_smbb_boost";
+};
+
+&pm8941_chg_otg {
+	regulator-name = "8941_smbb_otg";
+};
diff --git a/arch/arm/boot/dts/msm8974-v2-iommu.dtsi b/arch/arm/boot/dts/msm8974-v2-iommu.dtsi
index b5652d1..64eff43 100644
--- a/arch/arm/boot/dts/msm8974-v2-iommu.dtsi
+++ b/arch/arm/boot/dts/msm8974-v2-iommu.dtsi
@@ -78,7 +78,7 @@
 	venus_sec_pixel: qcom,iommu-ctx@fdc8f000 {
 		compatible = "qcom,msm-smmu-v1-ctx";
 		reg = <0xfdc8f000 0x1000>;
-		interrupts = <0 42 0>;
+		interrupts = <0 42 0>, <0 43 0>;
 		qcom,iommu-ctx-sids = <0x85>;
 		label = "venus_sec_pixel";
 		qcom,secure-context;
@@ -87,7 +87,7 @@
 	venus_sec_non_pixel: qcom,iommu-ctx@fdc90000 {
 		compatible = "qcom,msm-smmu-v1-ctx";
 		reg = <0xfdc90000 0x1000>;
-		interrupts = <0 42 0>;
+		interrupts = <0 42 0>, <0 43 0>;
 		qcom,iommu-ctx-sids = <0x87 0xA0>;
 		label = "venus_sec_non_pixel";
 		qcom,secure-context;
diff --git a/arch/arm/boot/dts/msm8974-v2-mtp.dts b/arch/arm/boot/dts/msm8974-v2-mtp.dts
index 1735515..792a78c 100644
--- a/arch/arm/boot/dts/msm8974-v2-mtp.dts
+++ b/arch/arm/boot/dts/msm8974-v2-mtp.dts
@@ -36,5 +36,5 @@
 };
 
 &pm8941_chg {
-	qcom,bpd-detection = "bpd_id";
+	qcom,bpd-detection = "bpd_thm";
 };
diff --git a/arch/arm/boot/dts/msm8974-v2.dtsi b/arch/arm/boot/dts/msm8974-v2.dtsi
index b37a509..63a31dc 100644
--- a/arch/arm/boot/dts/msm8974-v2.dtsi
+++ b/arch/arm/boot/dts/msm8974-v2.dtsi
@@ -81,7 +81,8 @@
 		<783360 465000000>,
 		<489600 266670000>,
 		<244800 133330000>;
-	qcom,reg-presets = <0x80070 0x11FFF>,
+	qcom,reg-presets = <0x80004 0x1>,
+		<0x80070 0x11FFF>,
 		<0x80074 0xA4>,
 		<0x800A8 0x1FFF>,
 		<0x80124 0x3>,
diff --git a/arch/arm/boot/dts/msm8974.dtsi b/arch/arm/boot/dts/msm8974.dtsi
index a4a3efe..2dfaedb 100644
--- a/arch/arm/boot/dts/msm8974.dtsi
+++ b/arch/arm/boot/dts/msm8974.dtsi
@@ -26,6 +26,35 @@
 		sdhc4 = &sdhc_4; /* SDC4 SDIO slot */
 	};
 
+	cpus {
+		#size-cells = <0>;
+		#address-cells = <1>;
+
+		CPU0: cpu@0 {
+			device_type = "cpu";
+			compatible = "qcom,krait";
+			reg = <0x0>;
+		};
+
+		CPU1: cpu@1 {
+			device_type = "cpu";
+			compatible = "qcom,krait";
+			reg = <0x1>;
+		};
+
+		CPU2: cpu@2 {
+			device_type = "cpu";
+			compatible = "qcom,krait";
+			reg = <0x2>;
+		};
+
+		CPU3: cpu@3 {
+			device_type = "cpu";
+			compatible = "qcom,krait";
+			reg = <0x3>;
+		};
+	};
+
 	memory {
 		secure_mem: secure_region {
 			linux,contiguous-region;
@@ -208,8 +237,8 @@
 		qcom,msm-bus,num-cases = <2>;
 		qcom,msm-bus,num-paths = <1>;
 		qcom,msm-bus,vectors-KBps =
-				<84 512 0 0>,
-				<84 512 500 800>;
+				<86 512 0 0>,
+				<86 512 500 800>;
 	};
 
 	usb_otg: usb@f9a55000 {
@@ -616,7 +645,9 @@
 			elemental-addr = [00 01 A0 00 17 02];
 
 			interrupt-parent = <&wcd9xxx_intc>;
-			interrupts = <0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28>;
+			interrupts = <0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
+				      17 18 19 20 21 22 23 24 25 26 27 28 29
+				      30>;
 
 			qcom,cdc-reset-gpio = <&msmgpio 63 0>;
 
@@ -738,6 +769,7 @@
 		interrupt-names = "qup_err_intr";
 		qcom,i2c-bus-freq = <100000>;
 		qcom,i2c-src-freq = <50000000>;
+		qcom,master-id = <84>;
 	};
 
 	i2c_1: i2c@f9923000 {
@@ -753,6 +785,7 @@
 		qcom,i2c-src-freq = <19200000>;
 		qcom,scl-gpio = <&msmgpio 3 0>;
 		qcom,sda-gpio = <&msmgpio 2 0>;
+		qcom,master-id = <86>;
 		status = "disabled";
 	};
 
@@ -767,6 +800,7 @@
 		interrupt-names = "qup_err_intr";
 		qcom,i2c-bus-freq = <100000>;
 		qcom,i2c-src-freq = <50000000>;
+		qcom,master-id = <86>;
 	};
 
 	spi_0: spi@f9923000 {
@@ -1181,8 +1215,8 @@
 		qcom,iris-vdddig-supply = <&pm8941_l3>;
 
 		gpios = <&msmgpio 36 0>, <&msmgpio 37 0>, <&msmgpio 38 0>, <&msmgpio 39 0>, <&msmgpio 40 0>;
-		qcom,has_48mhz_xo;
-		qcom,has_pronto_hw;
+		qcom,has-48mhz-xo;
+		qcom,has-pronto-hw;
 	};
 
 	qcom,ocmem@fdd00000 {
@@ -1419,6 +1453,7 @@
 		qcom,limit-temp = <60>;
 		qcom,temp-hysteresis = <10>;
 		qcom,freq-step = <2>;
+		qcom,freq-control-mask = <0xf>;
 		qcom,core-limit-temp = <80>;
 		qcom,core-temp-hysteresis = <10>;
 		qcom,core-control-mask = <0xe>;
@@ -1583,6 +1618,7 @@
 
 &gdsc_venus {
 	qcom,clock-names = "core_clk";
+	qcom,skip-logic-collapse;
 	status = "ok";
 };
 
diff --git a/arch/arm/boot/dts/msm9625-coresight.dtsi b/arch/arm/boot/dts/msm9625-coresight.dtsi
index 9b18b72..bde734e 100644
--- a/arch/arm/boot/dts/msm9625-coresight.dtsi
+++ b/arch/arm/boot/dts/msm9625-coresight.dtsi
@@ -34,6 +34,8 @@
 		coresight-id = <1>;
 		coresight-name = "coresight-tpiu";
 		coresight-nr-inports = <1>;
+
+		vdd-supply = <&ext_2p95v>;
 	};
 
 	replicator: replicator@fc31c000 {
diff --git a/arch/arm/boot/dts/msm9625-pm.dtsi b/arch/arm/boot/dts/msm9625-pm.dtsi
index 1d10f8c..673b640 100644
--- a/arch/arm/boot/dts/msm9625-pm.dtsi
+++ b/arch/arm/boot/dts/msm9625-pm.dtsi
@@ -237,40 +237,40 @@
 			<0xff 240>; /* summary_irq_kpss */
 
 		qcom,gpio-parent = <&msmgpio>;
-		qcom,gpio-map = <4  1>,
-			<5  5>,
-			<6  9>,
-			<7  18>,
-			<8  20>,
-			<9  24>,
-			<10  27>,
-			<11  28>,
-			<12  34>,
-			<13  35>,
-			<14  37>,
-			<15  42>,
-			<16  44>,
-			<17  46>,
-			<18  50>,
-			<19  54>,
-			<20  59>,
-			<21  61>,
-			<22  62>,
-			<23  64>,
-			<24  65>,
-			<25  66>,
-			<26  67>,
-			<27  68>,
-			<28  71>,
-			<29  72>,
-			<30  73>,
-			<31  74>,
-			<32  75>,
-			<33  77>,
-			<34  79>,
-			<35  80>,
-			<36  82>,
-			<37  86>;
+		qcom,gpio-map = <4 0>,
+			<5 1>,
+			<6 2>,
+			<7 3>,
+			<8 4>,
+			<9 5>,
+			<10 6>,
+			<11 7>,
+			<12 8>,
+			<13 9>,
+			<14 10>,
+			<15 11>,
+			<16 12>,
+			<17 13>,
+			<18 14>,
+			<19 15>,
+			<20 16>,
+			<21 17>,
+			<22 18>,
+			<23 19>,
+			<24 20>,
+			<25 21>,
+			<26 24>,
+			<27 25>,
+			<28 51>,
+			<29 61>,
+			<30 62>,
+			<31 63>,
+			<32 64>,
+			<33 65>,
+			<34 66>,
+			<35 67>,
+			<36 69>,
+			<37 71>;
 	};
 
 	qcom,pm-8x60 {
diff --git a/arch/arm/boot/dts/msm9625.dtsi b/arch/arm/boot/dts/msm9625.dtsi
index 6e258b5..c865c58 100644
--- a/arch/arm/boot/dts/msm9625.dtsi
+++ b/arch/arm/boot/dts/msm9625.dtsi
@@ -190,6 +190,8 @@
 				<85 512 40000 640000>;
 		qcom,pool-64-bit-align;
 		qcom,enable-hbm;
+		hsic,consider-ipa-handshake;
+		qcom,ahb-async-bridge-bypass;
 	};
 
 	qcom,usbbam@f9a44000 {
@@ -255,7 +257,7 @@
 			qcom,dst-bam-physical-address = <0xf9a04000>;
 			qcom,dst-bam-pipe-index = <3>;
 			qcom,data-fifo-size = <0xD480>;
-			qcom,descriptor-fifo-size = <0x1A80>;
+			qcom,descriptor-fifo-size = <0x3200>;
 			qcom,reset-bam-on-connect;
 		};
 		qcom,pipe4 {
@@ -268,7 +270,7 @@
 			qcom,dst-bam-physical-address = <0xf9a04000>;
 			qcom,dst-bam-pipe-index = <4>;
 			qcom,data-fifo-size = <0xD480>;
-			qcom,descriptor-fifo-size = <0x1A80>;
+			qcom,descriptor-fifo-size = <0x3200>;
 			qcom,reset-bam-on-connect;
 		};
 		qcom,pipe5 {
@@ -281,7 +283,7 @@
 			qcom,dst-bam-physical-address = <0xf9a04000>;
 			qcom,dst-bam-pipe-index = <5>;
 			qcom,data-fifo-size = <0xD480>;
-			qcom,descriptor-fifo-size = <0x1A80>;
+			qcom,descriptor-fifo-size = <0x3200>;
 			qcom,reset-bam-on-connect;
 		};
 		qcom,pipe6 {
@@ -294,7 +296,7 @@
 			qcom,dst-bam-physical-address = <0xf9a04000>;
 			qcom,dst-bam-pipe-index = <6>;
 			qcom,data-fifo-size = <0xD480>;
-			qcom,descriptor-fifo-size = <0x1A80>;
+			qcom,descriptor-fifo-size = <0x3200>;
 			qcom,reset-bam-on-connect;
 		};
 		qcom,pipe7 {
@@ -306,8 +308,8 @@
 			qcom,peer-bam = <2>;
 			qcom,src-bam-physical-address = <0xf9a04000>;
 			qcom,src-bam-pipe-index = <7>;
-			qcom,data-fifo-size = <0xD480>;
-			qcom,descriptor-fifo-size = <0x1A80>;
+			qcom,data-fifo-size = <0xDFE>;
+			qcom,descriptor-fifo-size = <0xB30>;
 			qcom,reset-bam-on-connect;
 		};
 	};
diff --git a/arch/arm/mach-msm/clock-mdss-8226.h b/arch/arm/boot/dts/msmsamarium-ion.dtsi
similarity index 62%
copy from arch/arm/mach-msm/clock-mdss-8226.h
copy to arch/arm/boot/dts/msmsamarium-ion.dtsi
index dcf4f92..ea954b8 100644
--- a/arch/arm/mach-msm/clock-mdss-8226.h
+++ b/arch/arm/boot/dts/msmsamarium-ion.dtsi
@@ -10,13 +10,22 @@
  * GNU General Public License for more details.
  */
 
-#ifndef __ARCH_ARM_MACH_MSM_CLOCK_MDSS_8226
-#define __ARCH_ARM_MACH_MSM_CLOCK_MDSS_8226
+&soc {
+	qcom,ion {
+		compatible = "qcom,msm-ion";
+		#address-cells = <1>;
+		#size-cells = <0>;
 
-extern struct clk_ops clk_ops_dsi_byte_pll;
-extern struct clk_ops clk_ops_dsi_pixel_pll;
+		qcom,ion-heap@30 { /* SYSTEM HEAP */
+			reg = <30>;
+		};
 
-void mdss_clk_ctrl_pre_init(struct clk *ahb_clk);
-void mdss_clk_ctrl_post_init(void);
+		qcom,ion-heap@21 { /* SYSTEM CONTIG HEAP */
+			reg = <21>;
+		};
 
-#endif /* __ARCH_ARM_MACH_MSM_CLOCK_MDSS_8226 */
+		qcom,ion-heap@25 { /* IOMMU HEAP */
+			reg = <25>;
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/msmsamarium-sim.dts b/arch/arm/boot/dts/msmsamarium-sim.dts
new file mode 100644
index 0000000..4acffae
--- /dev/null
+++ b/arch/arm/boot/dts/msmsamarium-sim.dts
@@ -0,0 +1,55 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+
+/include/ "msmsamarium.dtsi"
+
+/ {
+	model = "Qualcomm MSM SAMARIUM SIM";
+	compatible = "qcom,msmsamarium-sim", "qcom,msmsamarium", "qcom,sim";
+	qcom,msm-id = <195 0 0>;
+};
+
+&uartblsp0dm2{
+	status = "ok";
+};
+
+&sdcc1 {
+	qcom,clk-rates = <400000 25000000 50000000 100000000 200000000>;
+	qcom,sup-voltages = <2950 2950>;
+
+	qcom,pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+	qcom,pad-pull-off = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+	qcom,pad-drv-on = <0x4 0x4 0x4>; /* 10mA, 10mA, 10mA */
+	qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
+
+	qcom,bus-speed-mode = "HS200_1p8v", "DDR_1p8v";
+	qcom,nonremovable;
+	status = "ok";
+};
+
+&sdcc2 {
+	qcom,clk-rates = <400000 25000000 50000000 100000000 200000000>;
+	qcom,sup-voltages = <2950 2950>;
+
+	qcom,pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+	qcom,pad-pull-off = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+	qcom,pad-drv-on = <0x4 0x4 0x4>; /* 10mA, 10mA, 10mA */
+	qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
+
+	qcom,xpc;
+	qcom,bus-speed-mode = "SDR12", "SDR25", "SDR50", "DDR50", "SDR104";
+	qcom,current-limit = <800>;
+
+	status = "ok";
+};
diff --git a/arch/arm/boot/dts/msmsamarium.dtsi b/arch/arm/boot/dts/msmsamarium.dtsi
new file mode 100644
index 0000000..81699b6
--- /dev/null
+++ b/arch/arm/boot/dts/msmsamarium.dtsi
@@ -0,0 +1,90 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/include/ "skeleton.dtsi"
+
+/ {
+	model = "Qualcomm MSM SAMARIUM";
+	compatible = "qcom,msmsamarium";
+	interrupt-parent = <&intc>;
+	soc: soc { };
+};
+
+/include/ "msmsamarium-ion.dtsi"
+
+&soc {
+	#address-cells = <1>;
+	#size-cells = <1>;
+	ranges;
+
+	intc: interrupt-controller@f9000000 {
+		compatible = "qcom,msm-qgic2";
+		interrupt-controller;
+		#interrupt-cells = <3>;
+		reg = <0xf9000000 0x1000>,
+		      <0xf9002000 0x1000>;
+	};
+
+	msmgpio: gpio@fd510000 {
+		compatible = "qcom,msm-gpio";
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+		reg = <0xfd510000 0x4000>;
+		ngpio = <145>;
+		interrupts = <0 208 0>;
+		qcom,direct-connect-irqs = <8>;
+	};
+
+	timer {
+		compatible = "arm,armv7-timer";
+		interrupts = <1 2 0 1 3 0>;
+		clock-frequency = <19200000>;
+	};
+
+	uartblsp0dm2: serial@f991f000 {
+		compatible = "qcom,msm-lsuart-v14";
+		reg = <0xf991f000 0x1000>;
+		interrupts = <0 109 0>;
+		status = "disabled";
+	};
+
+	qcom,msm-imem@fe805000 {
+		compatible = "qcom,msm-imem";
+		reg = <0xfe805000 0x1000>; /* Address and size of IMEM */
+	};
+
+	sdcc1: qcom,sdcc@f9824000 {
+		cell-index = <1>; /* SDC1 eMMC slot */
+		compatible = "qcom,msm-sdcc";
+		reg = <0xf9824000 0x800>;
+		reg-names = "core_mem";
+		interrupts = <0 123 0>;
+		interrupt-names = "core_irq";
+
+		qcom,bus-width = <8>;
+		status = "disabled";
+	};
+
+	sdcc2: qcom,sdcc@f98a4000 {
+		cell-index = <2>; /* SDC2 SD card slot */
+		compatible = "qcom,msm-sdcc";
+		reg = <0xf98a4000 0x800>;
+		reg-names = "core_mem";
+		interrupts = <0 125 0>;
+		interrupt-names = "core_irq";
+
+		qcom,bus-width = <4>;
+		status = "disabled";
+	};
+};
diff --git a/arch/arm/configs/apq8084_defconfig b/arch/arm/configs/apq8084_defconfig
index a1fa53c..549bc73 100644
--- a/arch/arm/configs/apq8084_defconfig
+++ b/arch/arm/configs/apq8084_defconfig
@@ -43,10 +43,13 @@
 # CONFIG_MSM_PROC_COMM is not set
 CONFIG_MSM_SMD=y
 CONFIG_MSM_SMD_PKG4=y
+CONFIG_MSM_SMP2P=y
+CONFIG_MSM_SMP2P_TEST=y
 CONFIG_MSM_IPC_LOGGING=y
 CONFIG_MSM_IPC_ROUTER=y
 CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y
 CONFIG_MSM_IPC_ROUTER_SECURITY=y
+CONFIG_MSM_QMI_INTERFACE=y
 # CONFIG_MSM_HW3D is not set
 CONFIG_MSM_RPM_REGULATOR_SMD=y
 CONFIG_MSM_SUBSYSTEM_RESTART=y
diff --git a/arch/arm/configs/fsm9900_defconfig b/arch/arm/configs/fsm9900_defconfig
new file mode 100644
index 0000000..94e18ae
--- /dev/null
+++ b/arch/arm/configs/fsm9900_defconfig
@@ -0,0 +1,261 @@
+# CONFIG_ARM_PATCH_PHYS_VIRT is not set
+CONFIG_EXPERIMENTAL=y
+# CONFIG_SWAP is not set
+CONFIG_SYSVIPC=y
+CONFIG_RCU_FAST_NO_HZ=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_CGROUPS=y
+CONFIG_CGROUP_DEBUG=y
+CONFIG_CGROUP_FREEZER=y
+CONFIG_CGROUP_CPUACCT=y
+CONFIG_RESOURCE_COUNTERS=y
+CONFIG_CGROUP_SCHED=y
+CONFIG_RT_GROUP_SCHED=y
+CONFIG_NAMESPACES=y
+# CONFIG_UTS_NS is not set
+# CONFIG_IPC_NS is not set
+# CONFIG_PID_NS is not set
+CONFIG_RELAY=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_RD_XZ=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_PANIC_TIMEOUT=5
+CONFIG_KALLSYMS_ALL=y
+CONFIG_EMBEDDED=y
+CONFIG_PROFILING=y
+CONFIG_OPROFILE=m
+CONFIG_KPROBES=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_MODVERSIONS=y
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_EFI_PARTITION=y
+CONFIG_IOSCHED_TEST=y
+CONFIG_ARCH_MSM=y
+CONFIG_ARCH_FSM9900=y
+CONFIG_MSM_KRAIT_TBB_ABORT_HANDLER=y
+CONFIG_MSM_MPM_OF=y
+# CONFIG_MSM_STACKED_MEMORY is not set
+CONFIG_CPU_HAS_L2_PMU=y
+# CONFIG_MSM_FIQ_SUPPORT is not set
+# CONFIG_MSM_PROC_COMM is not set
+CONFIG_MSM_SMD=y
+CONFIG_MSM_SMD_PKG4=y
+CONFIG_MSM_IPC_LOGGING=y
+CONFIG_MSM_IPC_ROUTER=y
+CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y
+CONFIG_MSM_IPC_ROUTER_SECURITY=y
+CONFIG_MSM_SUBSYSTEM_RESTART=y
+CONFIG_MSM_SYSMON_COMM=y
+CONFIG_MSM_DIRECT_SCLK_ACCESS=y
+CONFIG_MSM_WATCHDOG_V2=y
+CONFIG_MSM_MEMORY_DUMP=y
+CONFIG_MSM_DLOAD_MODE=y
+CONFIG_MSM_SPM_V2=y
+CONFIG_MSM_L2_SPM=y
+CONFIG_MSM_MULTIMEDIA_USE_ION=y
+CONFIG_MSM_OCMEM=y
+CONFIG_MSM_OCMEM_LOCAL_POWER_CTRL=y
+CONFIG_MSM_OCMEM_DEBUG=y
+CONFIG_MSM_OCMEM_NONSECURE=y
+CONFIG_SENSORS_ADSP=y
+CONFIG_MSM_RTB=y
+CONFIG_MSM_RTB_SEPARATE_CPUS=y
+CONFIG_MSM_CACHE_ERP=y
+CONFIG_MSM_L1_ERR_PANIC=y
+CONFIG_MSM_L1_RECOV_ERR_PANIC=y
+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
+CONFIG_MSM_ENABLE_WDOG_DEBUG_CONTROL=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_SMP=y
+# CONFIG_SMP_ON_UP is not set
+CONFIG_SCHED_MC=y
+CONFIG_ARM_ARCH_TIMER=y
+CONFIG_PREEMPT=y
+CONFIG_AEABI=y
+CONFIG_HIGHMEM=y
+CONFIG_CC_STACKPROTECTOR=y
+CONFIG_CP_ACCESS=y
+CONFIG_USE_OF=y
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_GOV_POWERSAVE=y
+CONFIG_CPU_FREQ_GOV_USERSPACE=y
+CONFIG_CPU_FREQ_GOV_ONDEMAND=y
+CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
+CONFIG_CPU_IDLE=y
+CONFIG_VFP=y
+CONFIG_NEON=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_PM_RUNTIME=y
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_NET_KEY=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_NET_IPIP=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_INET_DIAG is not set
+CONFIG_IPV6=y
+# CONFIG_NET_ACTIVITY_STATS is not set
+# CONFIG_WIRELESS is not set
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_GENLOCK=y
+CONFIG_GENLOCK_MISCDEVICE=y
+CONFIG_SYNC=y
+CONFIG_SW_SYNC=y
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_MD=y
+CONFIG_BLK_DEV_DM=y
+CONFIG_DM_CRYPT=y
+CONFIG_NETDEVICES=y
+CONFIG_DUMMY=y
+CONFIG_MII=y
+CONFIG_TUN=y
+# CONFIG_NET_VENDOR_BROADCOM is not set
+# CONFIG_NET_VENDOR_CHELSIO is not set
+# CONFIG_NET_VENDOR_CIRRUS is not set
+# CONFIG_NET_VENDOR_FARADAY is not set
+# CONFIG_NET_VENDOR_INTEL is not set
+# CONFIG_NET_VENDOR_MARVELL is not set
+# CONFIG_NET_VENDOR_MICREL is not set
+# CONFIG_NET_VENDOR_MICROCHIP is not set
+# CONFIG_MSM_RMNET is not set
+# CONFIG_NET_VENDOR_NATSEMI is not set
+# CONFIG_NET_VENDOR_STMICRO is not set
+# CONFIG_WLAN is not set
+# CONFIG_INPUT_MOUSEDEV is not set
+CONFIG_INPUT_EVDEV=y
+CONFIG_INPUT_EVBUG=m
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_UINPUT=y
+CONFIG_INPUT_GPIO=y
+# CONFIG_SERIO is not set
+# CONFIG_LEGACY_PTYS is not set
+CONFIG_SERIAL_MSM=y
+CONFIG_SERIAL_MSM_CONSOLE=y
+CONFIG_SERIAL_MSM_HSL=y
+CONFIG_SERIAL_MSM_HSL_CONSOLE=y
+CONFIG_HW_RANDOM=y
+CONFIG_HW_RANDOM_MSM=y
+CONFIG_DCC_TTY=y
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_QUP=y
+CONFIG_SPI=y
+CONFIG_SPI_SPIDEV=m
+CONFIG_SPMI=y
+CONFIG_SPMI_MSM_PMIC_ARB=y
+CONFIG_MSM_QPNP_INT=y
+CONFIG_DEBUG_GPIO=y
+CONFIG_GPIO_SYSFS=y
+CONFIG_GPIO_QPNP_PIN=y
+CONFIG_GPIO_QPNP_PIN_DEBUG=y
+CONFIG_SENSORS_EPM_ADC=y
+CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y
+CONFIG_SENSORS_QPNP_ADC_CURRENT=y
+CONFIG_THERMAL=y
+CONFIG_THERMAL_TSENS8974=y
+CONFIG_THERMAL_MONITOR=y
+CONFIG_THERMAL_QPNP=y
+CONFIG_THERMAL_QPNP_ADC_TM=y
+CONFIG_REGULATOR_FIXED_VOLTAGE=y
+CONFIG_REGULATOR_STUB=y
+CONFIG_REGULATOR_QPNP=y
+CONFIG_ION=y
+CONFIG_ION_MSM=y
+CONFIG_USB=y
+CONFIG_USB_SUSPEND=y
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_EHCI_MSM=y
+CONFIG_USB_EHCI_MSM_HSIC=y
+CONFIG_MMC=y
+CONFIG_MMC_PERF_PROFILING=y
+CONFIG_MMC_UNSAFE_RESUME=y
+CONFIG_MMC_CLKGATE=y
+CONFIG_MMC_PARANOID_SD_INIT=y
+CONFIG_MMC_BLOCK_MINORS=32
+# CONFIG_MMC_BLOCK_BOUNCE is not set
+CONFIG_MMC_TEST=m
+CONFIG_MMC_BLOCK_TEST=y
+CONFIG_MMC_SDHCI=y
+CONFIG_MMC_SDHCI_PLTFM=y
+CONFIG_MMC_MSM=y
+CONFIG_MMC_SDHCI_MSM=y
+CONFIG_SWITCH=y
+CONFIG_RTC_CLASS=y
+# CONFIG_RTC_DRV_MSM is not set
+CONFIG_RTC_DRV_QPNP=y
+CONFIG_MSM_SSBI=y
+CONFIG_SPS=y
+CONFIG_SPS_SUPPORT_BAMDMA=y
+CONFIG_SPS_SUPPORT_NDP_BAM=y
+CONFIG_QPNP_PWM=y
+CONFIG_QPNP_POWER_ON=y
+CONFIG_QPNP_CLKDIV=y
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
+CONFIG_EXT4_FS=y
+CONFIG_FUSE_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_TMPFS=y
+CONFIG_PSTORE=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_ASCII=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_PRINTK_TIME=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_LOCKUP_DETECTOR=y
+# CONFIG_DETECT_HUNG_TASK is not set
+CONFIG_SCHEDSTATS=y
+CONFIG_TIMER_STATS=y
+CONFIG_DEBUG_KMEMLEAK=y
+CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF=y
+CONFIG_DEBUG_SPINLOCK=y
+CONFIG_DEBUG_MUTEXES=y
+CONFIG_DEBUG_ATOMIC_SLEEP=y
+CONFIG_DEBUG_STACK_USAGE=y
+CONFIG_DEBUG_INFO=y
+CONFIG_DEBUG_MEMORY_INIT=y
+CONFIG_DEBUG_LIST=y
+CONFIG_FAULT_INJECTION=y
+CONFIG_FAIL_PAGE_ALLOC=y
+CONFIG_FAULT_INJECTION_DEBUG_FS=y
+CONFIG_FAULT_INJECTION_STACKTRACE_FILTER=y
+CONFIG_DEBUG_PAGEALLOC=y
+CONFIG_CPU_FREQ_SWITCH_PROFILER=y
+CONFIG_DYNAMIC_DEBUG=y
+CONFIG_DEBUG_USER=y
+CONFIG_DEBUG_LL=y
+CONFIG_EARLY_PRINTK=y
+CONFIG_PID_IN_CONTEXTIDR=y
+CONFIG_KEYS=y
+CONFIG_CRYPTO_MD4=y
+CONFIG_CRYPTO_SHA256=y
+CONFIG_CRYPTO_ARC4=y
+CONFIG_CRYPTO_TWOFISH=y
+CONFIG_CRYPTO_DEV_QCRYPTO=m
+CONFIG_CRYPTO_DEV_QCE=m
+CONFIG_CRYPTO_DEV_QCEDEV=m
+CONFIG_CRC_CCITT=y
+CONFIG_LIBCRC32C=y
diff --git a/arch/arm/configs/msm8226-perf_defconfig b/arch/arm/configs/msm8226-perf_defconfig
new file mode 100644
index 0000000..7bf54ce
--- /dev/null
+++ b/arch/arm/configs/msm8226-perf_defconfig
@@ -0,0 +1,387 @@
+# CONFIG_ARM_PATCH_PHYS_VIRT is not set
+CONFIG_EXPERIMENTAL=y
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_SYSVIPC=y
+CONFIG_RCU_FAST_NO_HZ=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_CGROUPS=y
+CONFIG_CGROUP_DEBUG=y
+CONFIG_CGROUP_FREEZER=y
+CONFIG_CGROUP_CPUACCT=y
+CONFIG_RESOURCE_COUNTERS=y
+CONFIG_CGROUP_SCHED=y
+CONFIG_RT_GROUP_SCHED=y
+CONFIG_NAMESPACES=y
+# CONFIG_UTS_NS is not set
+# CONFIG_IPC_NS is not set
+# CONFIG_USER_NS is not set
+# CONFIG_PID_NS is not set
+CONFIG_RELAY=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_RD_BZIP2=y
+CONFIG_RD_LZMA=y
+CONFIG_PANIC_TIMEOUT=5
+CONFIG_KALLSYMS_ALL=y
+CONFIG_EMBEDDED=y
+CONFIG_PROFILING=y
+CONFIG_OPROFILE=m
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_MODVERSIONS=y
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_EFI_PARTITION=y
+CONFIG_ARCH_MSM=y
+CONFIG_ARCH_MSM8226=y
+# CONFIG_MSM_STACKED_MEMORY is not set
+CONFIG_CPU_HAS_L2_PMU=y
+# CONFIG_MSM_FIQ_SUPPORT is not set
+# CONFIG_MSM_PROC_COMM is not set
+CONFIG_MSM_SMD=y
+CONFIG_MSM_SMD_PKG4=y
+CONFIG_MSM_BAM_DMUX=y
+CONFIG_MSM_SMP2P=y
+CONFIG_MSM_SMP2P_TEST=y
+CONFIG_MSM_IPC_LOGGING=y
+CONFIG_MSM_IPC_ROUTER=y
+CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y
+CONFIG_MSM_QMI_INTERFACE=y
+CONFIG_MSM_SUBSYSTEM_RESTART=y
+CONFIG_MSM_SYSMON_COMM=y
+CONFIG_MSM_PIL_LPASS_QDSP6V5=y
+CONFIG_MSM_PIL_MSS_QDSP6V5=y
+CONFIG_MSM_PIL_VENUS=y
+CONFIG_MSM_PIL_PRONTO=y
+CONFIG_MSM_TZ_LOG=y
+CONFIG_MSM_DIRECT_SCLK_ACCESS=y
+CONFIG_MSM_WATCHDOG_V2=y
+CONFIG_MSM_MEMORY_DUMP=y
+CONFIG_MSM_DLOAD_MODE=y
+CONFIG_MSM_ADSP_LOADER=m
+CONFIG_MSM_OCMEM=y
+CONFIG_MSM_OCMEM_LOCAL_POWER_CTRL=y
+CONFIG_MSM_OCMEM_DEBUG=y
+CONFIG_MSM_OCMEM_NONSECURE=y
+CONFIG_MSM_OCMEM_POWER_DISABLE=y
+CONFIG_SENSORS_ADSP=y
+CONFIG_MSM_RTB=y
+CONFIG_MSM_RTB_SEPARATE_CPUS=y
+CONFIG_MSM_ENABLE_WDOG_DEBUG_CONTROL=y
+CONFIG_MSM_BOOT_STATS=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_SMP=y
+CONFIG_SCHED_MC=y
+CONFIG_ARM_ARCH_TIMER=y
+CONFIG_PREEMPT=y
+CONFIG_AEABI=y
+CONFIG_HIGHMEM=y
+CONFIG_USE_OF=y
+CONFIG_CPU_IDLE=y
+CONFIG_VFP=y
+CONFIG_NEON=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_PM_AUTOSLEEP=y
+CONFIG_PM_WAKELOCKS=y
+CONFIG_PM_WAKELOCKS_LIMIT=0
+# CONFIG_PM_WAKELOCKS_GC is not set
+CONFIG_PM_RUNTIME=y
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_ROUTE_VERBOSE=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+CONFIG_IPV6=y
+CONFIG_IPV6_PRIVACY=y
+CONFIG_IPV6_ROUTER_PREF=y
+CONFIG_IPV6_ROUTE_INFO=y
+CONFIG_IPV6_OPTIMISTIC_DAD=y
+CONFIG_INET6_AH=y
+CONFIG_INET6_ESP=y
+CONFIG_INET6_IPCOMP=y
+CONFIG_IPV6_MIP6=y
+CONFIG_IPV6_MULTIPLE_TABLES=y
+CONFIG_IPV6_SUBTREES=y
+CONFIG_NETFILTER=y
+CONFIG_NETFILTER_NETLINK_LOG=y
+CONFIG_NF_CONNTRACK=y
+CONFIG_NF_CONNTRACK_EVENTS=y
+CONFIG_NF_CT_PROTO_DCCP=y
+CONFIG_NF_CT_PROTO_SCTP=y
+CONFIG_NF_CT_PROTO_UDPLITE=y
+CONFIG_NF_CONNTRACK_AMANDA=y
+CONFIG_NF_CONNTRACK_FTP=y
+CONFIG_NF_CONNTRACK_H323=y
+CONFIG_NF_CONNTRACK_IRC=y
+CONFIG_NF_CONNTRACK_NETBIOS_NS=y
+CONFIG_NF_CONNTRACK_PPTP=y
+CONFIG_NF_CONNTRACK_SANE=y
+CONFIG_NF_CONNTRACK_SIP=y
+CONFIG_NF_CONNTRACK_TFTP=y
+CONFIG_NF_CT_NETLINK=y
+CONFIG_NETFILTER_TPROXY=y
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y
+CONFIG_NETFILTER_XT_TARGET_CONNMARK=y
+CONFIG_NETFILTER_XT_TARGET_LOG=y
+CONFIG_NETFILTER_XT_TARGET_MARK=y
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y
+CONFIG_NETFILTER_XT_MATCH_COMMENT=y
+CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y
+CONFIG_NETFILTER_XT_MATCH_CONNMARK=y
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y
+CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y
+CONFIG_NETFILTER_XT_MATCH_HELPER=y
+CONFIG_NETFILTER_XT_MATCH_IPRANGE=y
+CONFIG_NETFILTER_XT_MATCH_LENGTH=y
+CONFIG_NETFILTER_XT_MATCH_LIMIT=y
+CONFIG_NETFILTER_XT_MATCH_MAC=y
+CONFIG_NETFILTER_XT_MATCH_MARK=y
+CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y
+CONFIG_NETFILTER_XT_MATCH_POLICY=y
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
+CONFIG_NETFILTER_XT_MATCH_QTAGUID=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA2=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=y
+CONFIG_NETFILTER_XT_MATCH_SOCKET=y
+CONFIG_NETFILTER_XT_MATCH_STATE=y
+CONFIG_NETFILTER_XT_MATCH_STATISTIC=y
+CONFIG_NETFILTER_XT_MATCH_STRING=y
+CONFIG_NETFILTER_XT_MATCH_TIME=y
+CONFIG_NETFILTER_XT_MATCH_U32=y
+CONFIG_NF_CONNTRACK_IPV4=y
+CONFIG_IP_NF_IPTABLES=y
+CONFIG_IP_NF_MATCH_AH=y
+CONFIG_IP_NF_MATCH_ECN=y
+CONFIG_IP_NF_MATCH_TTL=y
+CONFIG_IP_NF_FILTER=y
+CONFIG_IP_NF_TARGET_REJECT=y
+CONFIG_NF_NAT=y
+CONFIG_IP_NF_TARGET_MASQUERADE=y
+CONFIG_IP_NF_TARGET_NETMAP=y
+CONFIG_IP_NF_TARGET_REDIRECT=y
+CONFIG_IP_NF_MANGLE=y
+CONFIG_IP_NF_RAW=y
+CONFIG_IP_NF_ARPTABLES=y
+CONFIG_IP_NF_ARPFILTER=y
+CONFIG_IP_NF_ARP_MANGLE=y
+CONFIG_NF_CONNTRACK_IPV6=y
+CONFIG_IP6_NF_IPTABLES=y
+CONFIG_IP6_NF_FILTER=y
+CONFIG_IP6_NF_TARGET_REJECT=y
+CONFIG_IP6_NF_MANGLE=y
+CONFIG_IP6_NF_RAW=y
+CONFIG_BRIDGE_NF_EBTABLES=y
+CONFIG_BRIDGE_EBT_BROUTE=y
+CONFIG_BRIDGE=y
+CONFIG_NET_SCHED=y
+CONFIG_NET_SCH_HTB=y
+CONFIG_NET_SCH_PRIO=y
+CONFIG_NET_CLS_FW=y
+CONFIG_BT=y
+CONFIG_BT_RFCOMM=y
+CONFIG_BT_RFCOMM_TTY=y
+CONFIG_BT_BNEP=y
+CONFIG_BT_BNEP_MC_FILTER=y
+CONFIG_BT_BNEP_PROTO_FILTER=y
+CONFIG_BT_HIDP=y
+CONFIG_BT_HCISMD=y
+CONFIG_CFG80211=y
+CONFIG_NL80211_TESTMODE=y
+CONFIG_CMA=y
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_MD=y
+CONFIG_BLK_DEV_DM=y
+CONFIG_DM_CRYPT=y
+CONFIG_NETDEVICES=y
+CONFIG_DUMMY=y
+# CONFIG_MSM_RMNET is not set
+CONFIG_MSM_RMNET_BAM=y
+CONFIG_WCNSS_CORE=y
+CONFIG_WCNSS_CORE_PRONTO=y
+CONFIG_WCNSS_MEM_PRE_ALLOC=y
+CONFIG_INPUT_EVDEV=y
+CONFIG_INPUT_EVBUG=m
+CONFIG_KEYBOARD_GPIO=y
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_ATMEL_MXT=y
+CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4=y
+CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_RMI4_DEV=y
+CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE=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_DIAG_CHAR=y
+CONFIG_HW_RANDOM=y
+CONFIG_HW_RANDOM_MSM=y
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_QUP=y
+CONFIG_SPI=y
+CONFIG_SPI_QUP=y
+CONFIG_SPI_SPIDEV=m
+CONFIG_SPMI=y
+CONFIG_MSM_BUS_SCALING=y
+CONFIG_SPMI_MSM_PMIC_ARB=y
+CONFIG_MSM_QPNP_INT=y
+CONFIG_SLIMBUS_MSM_NGD=y
+CONFIG_DEBUG_GPIO=y
+CONFIG_GPIO_SYSFS=y
+CONFIG_GPIO_QPNP_PIN=y
+CONFIG_POWER_SUPPLY=y
+CONFIG_QPNP_CHARGER=y
+CONFIG_QPNP_BMS=y
+CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y
+CONFIG_SENSORS_QPNP_ADC_CURRENT=y
+CONFIG_THERMAL=y
+CONFIG_THERMAL_TSENS8974=y
+CONFIG_THERMAL_MONITOR=y
+CONFIG_THERMAL_QPNP_ADC_TM=y
+CONFIG_WCD9306_CODEC=y
+CONFIG_REGULATOR_STUB=y
+CONFIG_REGULATOR_QPNP=y
+CONFIG_MEDIA_SUPPORT=y
+CONFIG_MEDIA_CONTROLLER=y
+CONFIG_VIDEO_DEV=y
+CONFIG_VIDEO_V4L2_SUBDEV_API=y
+# CONFIG_MSM_CAMERA is not set
+CONFIG_OV8825=y
+CONFIG_MSM_CAMERA_SENSOR=y
+CONFIG_MSM_CPP=y
+CONFIG_MSM_CCI=y
+CONFIG_MSM_CSI30_HEADER=y
+CONFIG_MSM_CSIPHY=y
+CONFIG_MSM_CSID=y
+CONFIG_MSM_ISPIF=y
+CONFIG_MSMB_CAMERA=y
+CONFIG_OV9724=y
+CONFIG_MSMB_JPEG=y
+CONFIG_SWITCH=y
+CONFIG_MSM_WFD=y
+CONFIG_MSM_VIDC_V4L2=y
+CONFIG_VIDEOBUF2_MSM_MEM=y
+CONFIG_V4L_PLATFORM_DRIVERS=y
+CONFIG_RADIO_IRIS=y
+CONFIG_RADIO_IRIS_TRANSPORT=m
+CONFIG_ION=y
+CONFIG_ION_MSM=y
+CONFIG_MSM_KGSL=y
+CONFIG_FB=y
+CONFIG_FB_MSM=y
+# CONFIG_FB_MSM_BACKLIGHT is not set
+CONFIG_FB_MSM_MDSS=y
+CONFIG_FB_MSM_MDSS_WRITEBACK=y
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+# CONFIG_LCD_CLASS_DEVICE is not set
+CONFIG_BACKLIGHT_CLASS_DEVICE=y
+# CONFIG_BACKLIGHT_GENERIC is not set
+CONFIG_SOUND=y
+CONFIG_SND=y
+CONFIG_SND_SOC=y
+CONFIG_SND_SOC_MSM8226=y
+CONFIG_UHID=y
+CONFIG_HID_APPLE=y
+CONFIG_HID_MAGICMOUSE=y
+CONFIG_HID_MICROSOFT=y
+CONFIG_USB_GADGET=y
+CONFIG_USB_GADGET_DEBUG_FILES=y
+CONFIG_USB_GADGET_DEBUG_FS=y
+CONFIG_USB_CI13XXX_MSM=y
+CONFIG_USB_G_ANDROID=y
+CONFIG_MMC=y
+CONFIG_MMC_PERF_PROFILING=y
+CONFIG_MMC_UNSAFE_RESUME=y
+CONFIG_MMC_CLKGATE=y
+CONFIG_MMC_EMBEDDED_SDIO=y
+CONFIG_MMC_PARANOID_SD_INIT=y
+CONFIG_MMC_BLOCK_MINORS=32
+CONFIG_MMC_TEST=m
+CONFIG_MMC_SDHCI=y
+CONFIG_MMC_SDHCI_PLTFM=y
+CONFIG_MMC_MSM=y
+CONFIG_MMC_SDHCI_MSM=y
+CONFIG_MMC_MSM_SPS_SUPPORT=y
+CONFIG_LEDS_QPNP=y
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_RTC_CLASS=y
+# CONFIG_RTC_DRV_MSM is not set
+CONFIG_RTC_DRV_QPNP=y
+CONFIG_STAGING=y
+CONFIG_ANDROID=y
+CONFIG_ANDROID_BINDER_IPC=y
+CONFIG_ASHMEM=y
+CONFIG_ANDROID_LOGGER=y
+CONFIG_ANDROID_RAM_CONSOLE=y
+CONFIG_ANDROID_TIMED_GPIO=y
+CONFIG_ANDROID_LOW_MEMORY_KILLER=y
+CONFIG_SPS=y
+CONFIG_USB_BAM=y
+CONFIG_SPS_SUPPORT_NDP_BAM=y
+CONFIG_QPNP_PWM=y
+CONFIG_QPNP_POWER_ON=y
+CONFIG_MSM_IOMMU=y
+CONFIG_CORESIGHT=y
+CONFIG_CORESIGHT_TMC=y
+CONFIG_CORESIGHT_TPIU=y
+CONFIG_CORESIGHT_FUNNEL=y
+CONFIG_CORESIGHT_REPLICATOR=y
+CONFIG_CORESIGHT_STM=y
+CONFIG_CORESIGHT_HWEVENT=y
+CONFIG_CORESIGHT_ETM=y
+CONFIG_CORESIGHT_EVENT=m
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
+CONFIG_EXT4_FS=y
+CONFIG_FUSE_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_TMPFS=y
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_ASCII=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_PRINTK_TIME=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_SCHEDSTATS=y
+CONFIG_TIMER_STATS=y
+CONFIG_DEBUG_KMEMLEAK=y
+CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF=y
+CONFIG_DEBUG_SPINLOCK=y
+CONFIG_DEBUG_MUTEXES=y
+CONFIG_DEBUG_ATOMIC_SLEEP=y
+CONFIG_DEBUG_STACK_USAGE=y
+CONFIG_DEBUG_INFO=y
+CONFIG_DEBUG_MEMORY_INIT=y
+CONFIG_DEBUG_LIST=y
+CONFIG_FAULT_INJECTION=y
+CONFIG_FAIL_PAGE_ALLOC=y
+CONFIG_FAULT_INJECTION_DEBUG_FS=y
+CONFIG_FAULT_INJECTION_STACKTRACE_FILTER=y
+CONFIG_DEBUG_PAGEALLOC=y
+CONFIG_ENABLE_DEFAULT_TRACERS=y
+CONFIG_DYNAMIC_DEBUG=y
+CONFIG_DEBUG_USER=y
+CONFIG_KEYS=y
+CONFIG_CRYPTO_MD4=y
+CONFIG_CRYPTO_ARC4=y
+CONFIG_CRYPTO_TWOFISH=y
+# CONFIG_CRYPTO_HW is not set
+CONFIG_CRC_CCITT=y
+CONFIG_QPNP_VIBRATOR=y
+CONFIG_QSEECOM=y
+CONFIG_CRYPTO_HW=y
+CONFIG_CRYPTO_DEV_QCRYPTO=m
+CONFIG_CRYPTO_DEV_QCE=y
+CONFIG_CRYPTO_DEV_QCEDEV=m
\ No newline at end of file
diff --git a/arch/arm/configs/msm8226_defconfig b/arch/arm/configs/msm8226_defconfig
index 07a15d9..42becba 100644
--- a/arch/arm/configs/msm8226_defconfig
+++ b/arch/arm/configs/msm8226_defconfig
@@ -205,6 +205,7 @@
 CONFIG_DM_CRYPT=y
 CONFIG_NETDEVICES=y
 CONFIG_DUMMY=y
+CONFIG_TUN=y
 # CONFIG_MSM_RMNET is not set
 CONFIG_MSM_RMNET_BAM=y
 CONFIG_WCNSS_CORE=y
@@ -241,6 +242,7 @@
 CONFIG_GPIO_SYSFS=y
 CONFIG_GPIO_QPNP_PIN=y
 CONFIG_POWER_SUPPLY=y
+CONFIG_BATTERY_BCL=y
 CONFIG_QPNP_CHARGER=y
 CONFIG_QPNP_BMS=y
 CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y
@@ -248,6 +250,7 @@
 CONFIG_THERMAL=y
 CONFIG_THERMAL_TSENS8974=y
 CONFIG_THERMAL_MONITOR=y
+CONFIG_THERMAL_QPNP=y
 CONFIG_THERMAL_QPNP_ADC_TM=y
 CONFIG_WCD9306_CODEC=y
 CONFIG_REGULATOR_STUB=y
@@ -291,6 +294,10 @@
 CONFIG_SND=y
 CONFIG_SND_SOC=y
 CONFIG_SND_SOC_MSM8226=y
+CONFIG_UHID=y
+CONFIG_HID_APPLE=y
+CONFIG_HID_MAGICMOUSE=y
+CONFIG_HID_MICROSOFT=y
 CONFIG_USB_GADGET=y
 CONFIG_USB_GADGET_DEBUG_FILES=y
 CONFIG_USB_GADGET_DEBUG_FS=y
@@ -380,4 +387,4 @@
 CONFIG_CRYPTO_HW=y
 CONFIG_CRYPTO_DEV_QCRYPTO=m
 CONFIG_CRYPTO_DEV_QCE=y
-CONFIG_CRYPTO_DEV_QCEDEV=m
\ No newline at end of file
+CONFIG_CRYPTO_DEV_QCEDEV=m
diff --git a/arch/arm/configs/msm8610-perf_defconfig b/arch/arm/configs/msm8610-perf_defconfig
index ef56fec..a41f9d5 100644
--- a/arch/arm/configs/msm8610-perf_defconfig
+++ b/arch/arm/configs/msm8610-perf_defconfig
@@ -208,6 +208,7 @@
 CONFIG_DM_CRYPT=y
 CONFIG_NETDEVICES=y
 CONFIG_DUMMY=y
+CONFIG_TUN=y
 # CONFIG_MSM_RMNET is not set
 CONFIG_MSM_RMNET_BAM=y
 CONFIG_WCNSS_CORE=y
@@ -245,6 +246,7 @@
 CONFIG_GPIO_SYSFS=y
 CONFIG_GPIO_QPNP_PIN=y
 CONFIG_POWER_SUPPLY=y
+CONFIG_BATTERY_BCL=y
 CONFIG_QPNP_CHARGER=y
 CONFIG_QPNP_BMS=y
 CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y
@@ -273,7 +275,6 @@
 CONFIG_OV9724=y
 CONFIG_MSMB_JPEG=y
 CONFIG_SWITCH=y
-CONFIG_MSM_WFD=y
 CONFIG_MSM_VIDC_V4L2=y
 CONFIG_VIDEOBUF2_MSM_MEM=y
 CONFIG_V4L_PLATFORM_DRIVERS=y
@@ -297,6 +298,10 @@
 CONFIG_SND_SOC=y
 CONFIG_SND_SOC_MSM8226=y
 CONFIG_SND_SOC_MSM8X10=y
+CONFIG_UHID=y
+CONFIG_HID_APPLE=y
+CONFIG_HID_MAGICMOUSE=y
+CONFIG_HID_MICROSOFT=y
 CONFIG_USB_GADGET=y
 CONFIG_USB_GADGET_DEBUG_FILES=y
 CONFIG_USB_GADGET_DEBUG_FS=y
@@ -310,6 +315,7 @@
 CONFIG_MMC_PARANOID_SD_INIT=y
 CONFIG_MMC_BLOCK_MINORS=32
 CONFIG_MMC_TEST=m
+CONFIG_MMC_BLOCK_TEST=y
 CONFIG_MMC_SDHCI=y
 CONFIG_MMC_SDHCI_PLTFM=y
 CONFIG_MMC_MSM=y
@@ -352,7 +358,6 @@
 CONFIG_DEBUG_INFO=y
 CONFIG_DEBUG_MEMORY_INIT=y
 CONFIG_ENABLE_DEFAULT_TRACERS=y
-CONFIG_DYNAMIC_DEBUG=y
 CONFIG_DEBUG_USER=y
 CONFIG_KEYS=y
 CONFIG_CRYPTO_MD4=y
@@ -361,4 +366,5 @@
 # CONFIG_CRYPTO_HW is not set
 CONFIG_CRC_CCITT=y
 CONFIG_QPNP_VIBRATOR=y
-CONFIG_QSEECOM=y
\ No newline at end of file
+CONFIG_QSEECOM=y
+CONFIG_IOSCHED_TEST=y
diff --git a/arch/arm/configs/msm8610_defconfig b/arch/arm/configs/msm8610_defconfig
index e4497e1..fe77fc4 100644
--- a/arch/arm/configs/msm8610_defconfig
+++ b/arch/arm/configs/msm8610_defconfig
@@ -206,6 +206,7 @@
 CONFIG_DM_CRYPT=y
 CONFIG_NETDEVICES=y
 CONFIG_DUMMY=y
+CONFIG_TUN=y
 # CONFIG_MSM_RMNET is not set
 CONFIG_MSM_RMNET_BAM=y
 CONFIG_WCNSS_CORE=y
@@ -243,6 +244,7 @@
 CONFIG_GPIO_SYSFS=y
 CONFIG_GPIO_QPNP_PIN=y
 CONFIG_POWER_SUPPLY=y
+CONFIG_BATTERY_BCL=y
 CONFIG_QPNP_CHARGER=y
 CONFIG_QPNP_BMS=y
 CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y
@@ -294,6 +296,10 @@
 CONFIG_SND_SOC=y
 CONFIG_SND_SOC_MSM8226=y
 CONFIG_SND_SOC_MSM8X10=y
+CONFIG_UHID=y
+CONFIG_HID_APPLE=y
+CONFIG_HID_MAGICMOUSE=y
+CONFIG_HID_MICROSOFT=y
 CONFIG_USB_GADGET=y
 CONFIG_USB_GADGET_DEBUG_FILES=y
 CONFIG_USB_GADGET_DEBUG_FS=y
@@ -307,6 +313,7 @@
 CONFIG_MMC_PARANOID_SD_INIT=y
 CONFIG_MMC_BLOCK_MINORS=32
 CONFIG_MMC_TEST=m
+CONFIG_MMC_BLOCK_TEST=y
 CONFIG_MMC_SDHCI=y
 CONFIG_MMC_SDHCI_PLTFM=y
 CONFIG_MMC_MSM=y
@@ -384,3 +391,4 @@
 CONFIG_CRYPTO_DEV_QCRYPTO=m
 CONFIG_CRYPTO_DEV_QCE=y
 CONFIG_CRYPTO_DEV_QCEDEV=m
+CONFIG_IOSCHED_TEST=y
diff --git a/arch/arm/configs/msm8960-perf_defconfig b/arch/arm/configs/msm8960-perf_defconfig
index 6c18a97..fe62c19 100644
--- a/arch/arm/configs/msm8960-perf_defconfig
+++ b/arch/arm/configs/msm8960-perf_defconfig
@@ -95,6 +95,8 @@
 CONFIG_MSM_L2_ERP_2BIT_PANIC=y
 CONFIG_MSM_DCVS=y
 CONFIG_MSM_HSIC_SYSMON=y
+CONFIG_WALL_CLK=m
+CONFIG_WALL_CLK_SYSFS=m
 CONFIG_STRICT_MEMORY_RWX=y
 CONFIG_PCI=y
 CONFIG_PCI_MSI=y
diff --git a/arch/arm/configs/msm8974-perf_defconfig b/arch/arm/configs/msm8974-perf_defconfig
index 72032dc..b933faa 100644
--- a/arch/arm/configs/msm8974-perf_defconfig
+++ b/arch/arm/configs/msm8974-perf_defconfig
@@ -368,6 +368,7 @@
 CONFIG_SND_USB_AUDIO=y
 CONFIG_SND_SOC=y
 CONFIG_SND_SOC_MSM8974=y
+CONFIG_SND_SOC_APQ8074=y
 CONFIG_UHID=y
 CONFIG_HID_APPLE=y
 CONFIG_HID_MAGICMOUSE=y
diff --git a/arch/arm/configs/msm8974_defconfig b/arch/arm/configs/msm8974_defconfig
index 8036a44..cfdbb29a 100644
--- a/arch/arm/configs/msm8974_defconfig
+++ b/arch/arm/configs/msm8974_defconfig
@@ -37,6 +37,7 @@
 CONFIG_DEFAULT_ROW=y
 CONFIG_ARCH_MSM=y
 CONFIG_ARCH_MSM8974=y
+CONFIG_ARCH_MSMSAMARIUM=y
 CONFIG_MSM_KRAIT_TBB_ABORT_HANDLER=y
 # CONFIG_MSM_STACKED_MEMORY is not set
 CONFIG_CPU_HAS_L2_PMU=y
@@ -373,6 +374,7 @@
 CONFIG_SND_USB_AUDIO=y
 CONFIG_SND_SOC=y
 CONFIG_SND_SOC_MSM8974=y
+CONFIG_SND_SOC_APQ8074=y
 CONFIG_UHID=y
 CONFIG_HID_APPLE=y
 CONFIG_HID_MAGICMOUSE=y
diff --git a/arch/arm/configs/msm9625-perf_defconfig b/arch/arm/configs/msm9625-perf_defconfig
index f434199..c48eb79 100644
--- a/arch/arm/configs/msm9625-perf_defconfig
+++ b/arch/arm/configs/msm9625-perf_defconfig
@@ -161,6 +161,7 @@
 CONFIG_CFG80211=m
 CONFIG_NL80211_TESTMODE=y
 CONFIG_MTD=y
+CONFIG_MTD_CHAR=y
 CONFIG_MTD_CMDLINE_PARTS=y
 CONFIG_MTD_OF_PARTS=y
 CONFIG_MTD_BLOCK=y
diff --git a/arch/arm/configs/msm9625_defconfig b/arch/arm/configs/msm9625_defconfig
index 2a1215d..4f2a637 100644
--- a/arch/arm/configs/msm9625_defconfig
+++ b/arch/arm/configs/msm9625_defconfig
@@ -108,12 +108,15 @@
 CONFIG_NF_CT_NETLINK=y
 CONFIG_NETFILTER_XT_MARK=y
 CONFIG_NETFILTER_XT_CONNMARK=y
+CONFIG_NETFILTER_XT_TARGET_LOG=y
+CONFIG_NETFILTER_XT_TARGET_TRACE=y
 CONFIG_NETFILTER_XT_MATCH_ADDRTYPE=y
 CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y
 CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y
 CONFIG_NETFILTER_XT_MATCH_DSCP=y
 CONFIG_NETFILTER_XT_MATCH_ESP=y
 CONFIG_NETFILTER_XT_MATCH_IPRANGE=y
+CONFIG_NETFILTER_XT_MATCH_LIMIT=y
 CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y
 CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
 CONFIG_IP_SET=y
@@ -160,6 +163,7 @@
 CONFIG_CFG80211=m
 CONFIG_NL80211_TESTMODE=y
 CONFIG_MTD=y
+CONFIG_MTD_CHAR=y
 CONFIG_MTD_CMDLINE_PARTS=y
 CONFIG_MTD_OF_PARTS=y
 CONFIG_MTD_BLOCK=y
diff --git a/arch/arm/include/asm/system_misc.h b/arch/arm/include/asm/system_misc.h
index 5a85f14..71f4827 100644
--- a/arch/arm/include/asm/system_misc.h
+++ b/arch/arm/include/asm/system_misc.h
@@ -23,6 +23,7 @@
 
 extern void disable_hlt(void);
 extern void enable_hlt(void);
+extern int get_hlt(void);
 
 #endif /* !__ASSEMBLY__ */
 
diff --git a/arch/arm/kernel/devtree.c b/arch/arm/kernel/devtree.c
index bee7f9d..24bc80b 100644
--- a/arch/arm/kernel/devtree.c
+++ b/arch/arm/kernel/devtree.c
@@ -26,6 +26,18 @@
 
 void __init early_init_dt_add_memory_arch(u64 base, u64 size)
 {
+#ifndef CONFIG_ARM_LPAE
+	if (base > ((phys_addr_t)~0)) {
+		pr_crit("Ignoring memory at 0x%08llx due to lack of LPAE support\n",
+			base);
+		return;
+	}
+
+	if (size > ((phys_addr_t)~0))
+		size = ((phys_addr_t)~0);
+
+	/* arm_add_memory() already checks for the case of base + size > 4GB */
+#endif
 	arm_add_memory(base, size);
 }
 
diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c
index e7a9237..fe97ff2 100644
--- a/arch/arm/kernel/process.c
+++ b/arch/arm/kernel/process.c
@@ -86,6 +86,12 @@
 
 EXPORT_SYMBOL(enable_hlt);
 
+int get_hlt(void)
+{
+	return hlt_counter;
+}
+EXPORT_SYMBOL(get_hlt);
+
 static int __init nohlt_setup(char *__unused)
 {
 	hlt_counter = 1;
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index be0daf3..22891b8 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -304,6 +304,9 @@
 	select ARM_HAS_SG_CHAIN
 	select ARCH_DMA_ADDR_T_64BIT if ARM_LPAE
 	select ARCH_WANT_KMAP_ATOMIC_FLUSH
+	select MEMORY_HOLE_CARVEOUT
+	select DONT_MAP_HOLE_AFTER_MEMBANK0
+	select QMI_ENCDEC
 
 config ARCH_MPQ8092
 	bool "MPQ8092"
@@ -509,6 +512,26 @@
 	select MSM_RPM_LOG
 	select MSM_RPM_STATS_LOG
 	select ARCH_WANT_KMAP_ATOMIC_FLUSH
+
+config ARCH_MSMSAMARIUM
+	bool "MSMSAMARIUM"
+	select ARCH_MSM_KRAITMP
+	select GPIO_MSM_V3
+	select ARM_GIC
+	select CPU_V7
+	select MSM_SCM
+	select MSM_GPIOMUX
+	select MULTI_IRQ_HANDLER
+	select MSM_SPM_V2
+	select MSM_L2_SPM
+	select MSM_NATIVE_RESTART
+	select MSM_RESTART_V2
+	select MSM_PM8X60 if PM
+	select MAY_HAVE_SPARSE_IRQ
+	select SPARSE_IRQ
+	select ARM_HAS_SG_CHAIN
+	select MSM_RUN_QUEUE_STATS
+	select ARCH_WANT_KMAP_ATOMIC_FLUSH
 endmenu
 
 choice
@@ -1111,6 +1134,7 @@
 	default "0x00000000" if ARCH_MPQ8092
 	default "0x00000000" if ARCH_MSM8226
 	default "0x00000000" if ARCH_MSM8610
+	default "0x00000000" if ARCH_MSMSAMARIUM
 	default "0x10000000" if ARCH_FSM9XXX
 	default "0x00000000" if ARCH_FSM9900
 	default "0x00200000" if ARCH_MSM9625
@@ -1284,6 +1308,14 @@
 		help
 		  Say Y here if you want the debug print routines to direct
 		  their output to the serial port on FSM9900 devices.
+
+	config DEBUG_MSMSAMARIUM_UART
+		bool "Kernel low-level debugging messages via MSM SAMARIUM UART"
+		depends on ARCH_MSMSAMARIUM
+		select MSM_HAS_DEBUG_UART_HS_V14
+		help
+		  Say Y here if you want the debug print routines to direct
+		  their output to the serial port on MSM SAMARIUM devices.
 endchoice
 
 choice
@@ -2690,14 +2722,25 @@
 	  related operations of OCMEM. Both local power management
 	  and RPM assisted power management operations are supported.
 
-config MSM_OCMEM_POWER_DISABLE
-	bool "OCMEM Disable Power Control"
+config MSM_OCMEM_DEBUG_ALWAYS_ON
+	bool "Keep OCMEM always turned ON"
 	depends on MSM_OCMEM_DEBUG
 	help
+	  Always vote for all OCMEM clocks and keep all OCMEM
+	  macros turned ON and never allow them to be turned OFF.
+	  Both local power management and RPM assisted power modes
+	  are supported for individual macro power control operations.
+
+config MSM_OCMEM_POWER_DISABLE
+	bool "OCMEM Disable Power Control"
+	depends on MSM_OCMEM
+	help
 	  Disable all OCMEM power management.
-	  This keeps all OCMEM macros turned ON at all times thus
-	  never allowing them to be turned OFF. Both local power
-	  management and RPM assisted power modes are supported.
+	  Skip all OCMEM power operations that turn ON or
+	  turn OFF the macros. Both local power management and
+	  RPM assisted power management operations are skipped.
+	  Enable this configuration if OCMEM is being exclusively
+	  used as GMEM or OCIMEM.
 
 config SENSORS_ADSP
 	bool "Enable Sensors Driver Support for ADSP"
@@ -2981,4 +3024,21 @@
 	  suggestions in efuse as initial settings. It converts corner vote
 	  to voltage value before writing to a voltage regulator API, such as
 	  that provided by spm-regulator driver.
+
+config WALL_CLK
+	tristate "Wall Clock hardware block simulation"
+	depends on ARCH_APQ8064
+	help
+	 This driver simulates the wall-clock hardware block on fsm8064_ep
+	 femto emulation platform. This block will be used to provide
+	 clock information to the LTE Layer 2 module running on the hexagon
+	 processor.
+
+config WALL_CLK_SYSFS
+	tristate "Wall Clock SysFS Support"
+	depends on SYSFS && WALL_CLK
+	help
+	 Support the wallclk directory in sysfs filesystem to enable the
+	 wall clock simulation and read the current SFN.
+
 endif
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index b8a2b2d..9a34d87 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -111,29 +111,15 @@
 obj-$(CONFIG_MSM_IPC_LOGGING) += ipc_logging_debug.o
 endif
 obj-y += socinfo.o
-ifndef CONFIG_ARCH_MSM8960
-ifndef CONFIG_ARCH_MSM8X60
-ifndef CONFIG_ARCH_APQ8064
-ifndef CONFIG_ARCH_MSM8974
-ifndef CONFIG_ARCH_MSM8226
-ifndef CONFIG_ARCH_MSM9625
-ifndef CONFIG_ARCH_MPQ8092
-ifndef CONFIG_ARCH_MSM8610
-ifndef CONFIG_ARCH_APQ8084
-ifndef CONFIG_ARCH_MSMKRYPTON
-ifndef CONFIG_ARCH_FSM9900
-	obj-y += nand_partitions.o
-endif
-endif
-endif
-endif
-endif
-endif
-endif
-endif
-endif
-endif
-endif
+obj-$(CONFIG_ARCH_MSM7X01A) += nand_partitions.o
+obj-$(CONFIG_ARCH_MSM7X25) += nand_partitions.o
+obj-$(CONFIG_ARCH_MSM7X27) += nand_partitions.o
+obj-$(CONFIG_ARCH_MSM7X30) += nand_partitions.o
+obj-$(CONFIG_ARCH_QSD8X50) += nand_partitions.o
+obj-$(CONFIG_ARCH_FSM9XXX) += nand_partitions.o
+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
@@ -308,14 +294,17 @@
 obj-$(CONFIG_ARCH_MSM9625) += gdsc.o
 obj-$(CONFIG_ARCH_MSM8226) += gdsc.o
 obj-$(CONFIG_ARCH_MSM8610) += gdsc.o
+obj-$(CONFIG_ARCH_MPQ8092) += gdsc.o
 obj-$(CONFIG_ARCH_MSM8974) += krait-regulator.o
 obj-$(CONFIG_ARCH_MSMKRYPTON) += board-krypton.o board-krypton-gpiomux.o
+obj-$(CONFIG_ARCH_MSMSAMARIUM) += board-samarium.o board-samarium-gpiomux.o
 obj-$(CONFIG_ARCH_MSM9625) += board-9625.o board-9625-gpiomux.o
 obj-$(CONFIG_ARCH_MSM9625) += clock-local2.o clock-pll.o clock-9625.o clock-rpm.o clock-voter.o acpuclock-9625.o acpuclock-cortex.o
 obj-$(CONFIG_ARCH_MSM8930) += acpuclock-8930.o acpuclock-8627.o acpuclock-8930aa.o acpuclock-8930ab.o
 obj-$(CONFIG_ARCH_MPQ8092) += board-8092.o board-8092-gpiomux.o
+obj-$(CONFIG_ARCH_MPQ8092) += clock-8092.o
 obj-$(CONFIG_ARCH_MSM8226) += board-8226.o board-8226-gpiomux.o
-obj-$(CONFIG_ARCH_MSM8226) += clock-local2.o clock-pll.o clock-8226.o clock-rpm.o clock-voter.o clock-mdss-8226.o
+obj-$(CONFIG_ARCH_MSM8226) += clock-local2.o clock-pll.o clock-8226.o clock-rpm.o clock-voter.o clock-mdss-8974.o
 obj-$(CONFIG_ARCH_MSM8226) += acpuclock-8226.o acpuclock-cortex.o
 obj-$(CONFIG_ARCH_MSM8610) += board-8610.o board-8610-gpiomux.o
 obj-$(CONFIG_ARCH_MSM8610) += clock-local2.o clock-pll.o clock-8610.o clock-rpm.o clock-voter.o
@@ -376,6 +365,7 @@
 obj-$(CONFIG_ARCH_MSM8974) += gpiomux-v2.o gpiomux.o
 obj-$(CONFIG_ARCH_MSM9625) += gpiomux-v2.o gpiomux.o
 obj-$(CONFIG_ARCH_MSMKRYPTON) += gpiomux-v2.o gpiomux.o
+obj-$(CONFIG_ARCH_MSMSAMARIUM) += gpiomux-v2.o gpiomux.o
 obj-$(CONFIG_ARCH_MPQ8092) += gpiomux-v2.o gpiomux.o
 obj-$(CONFIG_ARCH_MSM8226) += gpiomux-v2.o gpiomux.o
 obj-$(CONFIG_ARCH_MSM8610) += gpiomux-v2.o gpiomux.o
@@ -434,3 +424,6 @@
 obj-$(CONFIG_ARCH_MSM8974) += msm_mpmctr.o
 obj-$(CONFIG_MSM_CPR_REGULATOR) += cpr-regulator.o
 obj-$(CONFIG_CPU_FREQ_MSM) += cpufreq.o
+
+obj-$(CONFIG_WALL_CLK) += wallclk.o
+obj-$(CONFIG_WALL_CLK_SYSFS) += wallclk_sysfs.o
diff --git a/arch/arm/mach-msm/Makefile.boot b/arch/arm/mach-msm/Makefile.boot
index 07969e0..e1fd642 100644
--- a/arch/arm/mach-msm/Makefile.boot
+++ b/arch/arm/mach-msm/Makefile.boot
@@ -87,6 +87,9 @@
         dtb-$(CONFIG_ARCH_MSM8226)	+= msm8226-cdp.dtb
         dtb-$(CONFIG_ARCH_MSM8226)	+= msm8226-mtp.dtb
         dtb-$(CONFIG_ARCH_MSM8226)	+= msm8226-qrd.dtb
+        dtb-$(CONFIG_ARCH_MSM8226)	+= msm8926-cdp.dtb
+        dtb-$(CONFIG_ARCH_MSM8226)	+= msm8926-mtp.dtb
+        dtb-$(CONFIG_ARCH_MSM8226)	+= msm8926-qrd.dtb
 
 # FSM9XXX
    zreladdr-$(CONFIG_ARCH_FSM9XXX)	:= 0x10008000
@@ -105,3 +108,7 @@
    zreladdr-$(CONFIG_ARCH_MSM8610)	:= 0x00008000
         dtb-$(CONFIG_ARCH_MSM8610)	+= msm8610-rumi.dtb
         dtb-$(CONFIG_ARCH_MSM8610)	+= msm8610-sim.dtb
+
+# MSMSAMARIUM
+   zreladdr-$(CONFIG_ARCH_MSMSAMARIUM)	:= 0x00008000
+	dtb-$(CONFIG_ARCH_MSMSAMARIUM)	+= msmsamarium-sim.dtb
diff --git a/arch/arm/mach-msm/acpuclock-8226.c b/arch/arm/mach-msm/acpuclock-8226.c
index 5793326..733c7a8 100644
--- a/arch/arm/mach-msm/acpuclock-8226.c
+++ b/arch/arm/mach-msm/acpuclock-8226.c
@@ -66,7 +66,7 @@
  */
 static struct clkctl_acpu_speed acpu_freq_tbl_8226[] = {
 	{ 1,  300000, PLL0,    4, 2,   CPR_CORNER_SVS,    0, 4 },
-	{ 1,  384000, ACPUPLL, 5, 0,   CPR_CORNER_SVS,    0, 4 },
+	{ 1,  384000, ACPUPLL, 5, 2,   CPR_CORNER_SVS,    0, 4 },
 	{ 1,  600000, PLL0,    4, 0,   CPR_CORNER_NORMAL, 0, 6 },
 	{ 1,  787200, ACPUPLL, 5, 0,   CPR_CORNER_NORMAL, 0, 7 },
 	{ 1,  998400, ACPUPLL, 5, 0,   CPR_CORNER_TURBO,  0, 7 },
@@ -77,7 +77,7 @@
 
 static struct clkctl_acpu_speed acpu_freq_tbl_8610[] = {
 	{ 1,  300000, PLL0,    4, 2,   CPR_CORNER_SVS,    0, 3 },
-	{ 1,  384000, ACPUPLL, 5, 0,   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 },
diff --git a/arch/arm/mach-msm/acpuclock-cortex.c b/arch/arm/mach-msm/acpuclock-cortex.c
index 0c80a56..afa6909 100644
--- a/arch/arm/mach-msm/acpuclock-cortex.c
+++ b/arch/arm/mach-msm/acpuclock-cortex.c
@@ -160,7 +160,8 @@
 static int set_speed(struct clkctl_acpu_speed *tgt_s)
 {
 	int rc = 0;
-	unsigned int tgt_freq_hz = tgt_s->khz * 1000;
+	unsigned int div = tgt_s->src_div ? tgt_s->src_div : 1;
+	unsigned int tgt_freq_hz = tgt_s->khz * 1000 * div;
 	struct clkctl_acpu_speed *strt_s = priv->current_speed;
 	struct clkctl_acpu_speed *cxo_s = &priv->freq_tbl[0];
 	struct clk *strt = priv->src_clocks[strt_s->src].clk;
diff --git a/arch/arm/mach-msm/board-8064-pmic.c b/arch/arm/mach-msm/board-8064-pmic.c
index 5ab4a53..b2dcd7a 100644
--- a/arch/arm/mach-msm/board-8064-pmic.c
+++ b/arch/arm/mach-msm/board-8064-pmic.c
@@ -478,6 +478,10 @@
 	.high_ocv_correction_limit_uv	= 50,
 	.low_ocv_correction_limit_uv	= 100,
 	.hold_soc_est			= 3,
+	.enable_fcc_learning		= 1,
+	.min_fcc_learning_soc		= 20,
+	.min_fcc_ocv_pc			= 30,
+	.max_fcc_learning_samples	= 5,
 };
 
 static struct pm8921_platform_data
diff --git a/arch/arm/mach-msm/board-8064.c b/arch/arm/mach-msm/board-8064.c
index f969e31..f5a9070 100644
--- a/arch/arm/mach-msm/board-8064.c
+++ b/arch/arm/mach-msm/board-8064.c
@@ -85,11 +85,11 @@
 #include "pm.h"
 #include "pm-boot.h"
 #include "devices-msm8x60.h"
-#include "smd_private.h"
 #include "platsmp.h"
 
 #define MHL_GPIO_INT           30
 #define MHL_GPIO_RESET         35
+#include "sysmon.h"
 
 #define MSM_PMEM_ADSP_SIZE         0x7800000
 #define MSM_PMEM_AUDIO_SIZE        0x4CF000
@@ -1902,6 +1902,8 @@
 	.peripheral_platform_device = &apq8064_device_hsic_host,
 	.ramdump_timeout_ms = 120000,
 	.mdm2ap_status_gpio_run_cfg = &mdm2ap_status_gpio_run_cfg,
+	.sysmon_subsys_id_valid = 1,
+	.sysmon_subsys_id = SYSMON_SS_EXT_MODEM,
 };
 
 static struct tsens_platform_data apq_tsens_pdata  = {
diff --git a/arch/arm/mach-msm/board-8084.c b/arch/arm/mach-msm/board-8084.c
index 500c302..67c05ba 100644
--- a/arch/arm/mach-msm/board-8084.c
+++ b/arch/arm/mach-msm/board-8084.c
@@ -31,6 +31,7 @@
 #include "clock.h"
 #include "devices.h"
 #include "platsmp.h"
+#include "modem_notifier.h"
 
 static struct memtype_reserve apq8084_reserve_table[] __initdata = {
 	[MEMTYPE_SMI] = {
@@ -82,6 +83,7 @@
  */
 void __init apq8084_add_drivers(void)
 {
+	msm_init_modem_notifier_list();
 	msm_smd_init();
 	msm_clock_init(&msm8084_clock_init_data);
 }
diff --git a/arch/arm/mach-msm/board-8092.c b/arch/arm/mach-msm/board-8092.c
index cd95bf3..7b81c11 100644
--- a/arch/arm/mach-msm/board-8092.c
+++ b/arch/arm/mach-msm/board-8092.c
@@ -35,21 +35,6 @@
 #include "clock.h"
 #include "platsmp.h"
 
-static struct clk_lookup msm_clocks_dummy[] = {
-	CLK_DUMMY("core_clk",   BLSP1_UART_CLK, "msm_serial_hsl.0", OFF),
-	CLK_DUMMY("iface_clk",  BLSP1_UART_CLK, "msm_serial_hsl.0", 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),
-
-};
-
-struct clock_init_data mpq8092_clock_init_data __initdata = {
-	.table = msm_clocks_dummy,
-	.size = ARRAY_SIZE(msm_clocks_dummy),
-};
-
 static struct memtype_reserve mpq8092_reserve_table[] __initdata = {
 	[MEMTYPE_SMI] = {
 	},
@@ -90,8 +75,6 @@
 static struct of_dev_auxdata mpq8092_auxdata_lookup[] __initdata = {
 	OF_DEV_AUXDATA("qcom,msm-lsuart-v14", 0xF991F000, \
 			"msm_serial_hsl.0", NULL),
-	OF_DEV_AUXDATA("qcom,spmi-pmic-arb", 0xFC4C0000, \
-			"spmi-pmic-arb.0", NULL),
 	OF_DEV_AUXDATA("qcom,msm-sdcc", 0xF9824000, \
 			"msm_sdcc.1", NULL),
 	OF_DEV_AUXDATA("qcom,msm-sdcc", 0xF98A4000, \
diff --git a/arch/arm/mach-msm/board-8226.c b/arch/arm/mach-msm/board-8226.c
index 521898e..0205919 100644
--- a/arch/arm/mach-msm/board-8226.c
+++ b/arch/arm/mach-msm/board-8226.c
@@ -135,6 +135,7 @@
 
 static const char *msm8226_dt_match[] __initconst = {
 	"qcom,msm8226",
+	"qcom,msm8926",
 	NULL
 };
 
diff --git a/arch/arm/mach-msm/board-8930-pmic.c b/arch/arm/mach-msm/board-8930-pmic.c
index ef65613..d7e678e 100644
--- a/arch/arm/mach-msm/board-8930-pmic.c
+++ b/arch/arm/mach-msm/board-8930-pmic.c
@@ -481,6 +481,10 @@
 	.high_ocv_correction_limit_uv	= 50,
 	.low_ocv_correction_limit_uv	= 100,
 	.hold_soc_est			= 3,
+	.enable_fcc_learning		= 1,
+	.min_fcc_learning_soc		= 20,
+	.min_fcc_ocv_pc			= 30,
+	.max_fcc_learning_samples	= 5,
 };
 
 static struct pm8038_platform_data pm8038_platform_data __devinitdata = {
diff --git a/arch/arm/mach-msm/board-8930.c b/arch/arm/mach-msm/board-8930.c
index ccea956..e097faf 100644
--- a/arch/arm/mach-msm/board-8930.c
+++ b/arch/arm/mach-msm/board-8930.c
@@ -96,7 +96,6 @@
 #include "rpm_resources.h"
 #include <mach/mpm.h>
 #include "clock.h"
-#include "smd_private.h"
 #include "pm-boot.h"
 #include "msm_watchdog.h"
 #include "board-8930.h"
diff --git a/arch/arm/mach-msm/board-8960-pmic.c b/arch/arm/mach-msm/board-8960-pmic.c
index c87d966..8e758bf 100644
--- a/arch/arm/mach-msm/board-8960-pmic.c
+++ b/arch/arm/mach-msm/board-8960-pmic.c
@@ -438,6 +438,10 @@
 	.high_ocv_correction_limit_uv	= 50,
 	.low_ocv_correction_limit_uv	= 100,
 	.hold_soc_est			= 3,
+	.enable_fcc_learning		= 1,
+	.min_fcc_learning_soc		= 20,
+	.min_fcc_ocv_pc			= 30,
+	.max_fcc_learning_samples	= 5,
 };
 
 #define	PM8921_LC_LED_MAX_CURRENT	4	/* I = 4mA */
diff --git a/arch/arm/mach-msm/board-8960.c b/arch/arm/mach-msm/board-8960.c
index cb88cdc..b45e690 100644
--- a/arch/arm/mach-msm/board-8960.c
+++ b/arch/arm/mach-msm/board-8960.c
@@ -98,7 +98,6 @@
 #include "rpm_resources.h"
 #include <mach/mpm.h>
 #include "clock.h"
-#include "smd_private.h"
 #include "pm-boot.h"
 #include "msm_watchdog.h"
 #include "platsmp.h"
diff --git a/arch/arm/mach-msm/board-8974-gpiomux.c b/arch/arm/mach-msm/board-8974-gpiomux.c
index 76dbaef..c8a88d7 100644
--- a/arch/arm/mach-msm/board-8974-gpiomux.c
+++ b/arch/arm/mach-msm/board-8974-gpiomux.c
@@ -1001,7 +1001,6 @@
 	},
 };
 
-#ifdef CONFIG_MMC_MSM_SDC3_SUPPORT
 static struct gpiomux_setting sdc3_clk_actv_cfg = {
 	.func = GPIOMUX_FUNC_2,
 	.drv = GPIOMUX_DRV_8MA,
@@ -1082,9 +1081,6 @@
 	msm_gpiomux_install(msm8974_sdc3_configs,
 			    ARRAY_SIZE(msm8974_sdc3_configs));
 }
-#else
-static void msm_gpiomux_sdc3_install(void) {}
-#endif /* CONFIG_MMC_MSM_SDC3_SUPPORT */
 
 #ifdef CONFIG_MMC_MSM_SDC4_SUPPORT
 static struct gpiomux_setting sdc4_clk_actv_cfg = {
@@ -1219,7 +1215,11 @@
 	msm_gpiomux_install(msm_sensor_configs, ARRAY_SIZE(msm_sensor_configs));
 
 	msm_gpiomux_install(&sd_card_det, 1);
-	msm_gpiomux_sdc3_install();
+
+	if (machine_is_apq8074() && (of_board_is_liquid() || \
+	    of_board_is_dragonboard()))
+		msm_gpiomux_sdc3_install();
+
 	msm_gpiomux_sdc4_install();
 
 	msm_gpiomux_install(msm_taiko_config, ARRAY_SIZE(msm_taiko_config));
diff --git a/arch/arm/mach-msm/board-fsm9900.c b/arch/arm/mach-msm/board-fsm9900.c
index 7177355..6e85ece 100644
--- a/arch/arm/mach-msm/board-fsm9900.c
+++ b/arch/arm/mach-msm/board-fsm9900.c
@@ -44,6 +44,22 @@
 	CLK_DUMMY("iface_clk",  BLSP2_UART_CLK, "f9960000.serial", 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",   BLSP2_I2C_CLK,  "f9966000.i2c",    OFF),
+	CLK_DUMMY("iface_clk",  BLSP2_I2C_CLK,  "f9966000.i2c",    OFF),
+	CLK_DUMMY("core_clk",   BLSP1_I2C_CLK,  "f9924000.i2c",    OFF),
+	CLK_DUMMY("iface_clk",  BLSP1_I2C_CLK,  "f9924000.i2c",    OFF),
+	CLK_DUMMY("core_clk",   NULL,           "f9a55000.usb",    OFF),
+	CLK_DUMMY("iface_clk",  NULL,           "f9a55000.usb",    OFF),
+	CLK_DUMMY("phy_clk",    NULL,           "f9a55000.usb",    OFF),
+	CLK_DUMMY("xo",         NULL,           "f9a55000.usb",    OFF),
+	CLK_DUMMY("core_clk",   NULL,           "msm_ehci_host",   OFF),
+	CLK_DUMMY("iface_clk",  NULL,           "msm_ehci_host",   OFF),
+	CLK_DUMMY("sleep_clk",  NULL,           "msm_ehci_host",   OFF),
+	CLK_DUMMY("xo",         NULL,           "msm_ehci_host",   OFF),
+	CLK_DUMMY("core_clk",   NULL,           "f9824900.sdhci_msm", OFF),
+	CLK_DUMMY("iface_clk",  NULL,           "f9824900.sdhci_msm", OFF),
+	CLK_DUMMY("core_clk",   NULL,           "f98a4900.sdhci_msm", OFF),
+	CLK_DUMMY("iface_clk",  NULL,           "f98a4900.sdhci_msm", OFF),
 };
 
 static struct clock_init_data msm_dummy_clock_init_data __initdata = {
diff --git a/arch/arm/mach-msm/board-samarium.c b/arch/arm/mach-msm/board-samarium.c
index 00d63a3..a656cee 100644
--- a/arch/arm/mach-msm/board-samarium.c
+++ b/arch/arm/mach-msm/board-samarium.c
@@ -34,6 +34,10 @@
 static struct clk_lookup msm_clocks_dummy[] = {
 	CLK_DUMMY("core_clk",   BLSP1_UART_CLK, "f991f000.serial", OFF),
 	CLK_DUMMY("iface_clk",  BLSP1_UART_CLK, "f991f000.serial", OFF),
+	CLK_DUMMY("core_clk",	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),
 };
 
 static struct clock_init_data msm_dummy_clock_init_data __initdata = {
@@ -42,6 +46,10 @@
 };
 
 static struct of_dev_auxdata msmsamarium_auxdata_lookup[] __initdata = {
+	OF_DEV_AUXDATA("qcom,msm-sdcc", 0xF9824000, \
+			"msm_sdcc.1", NULL),
+	OF_DEV_AUXDATA("qcom,msm-sdcc", 0xF98A4000, \
+			"msm_sdcc.2", NULL),
 	{},
 };
 
diff --git a/arch/arm/mach-msm/clock-8084.c b/arch/arm/mach-msm/clock-8084.c
index 424b694..b7f9fd7 100644
--- a/arch/arm/mach-msm/clock-8084.c
+++ b/arch/arm/mach-msm/clock-8084.c
@@ -325,7 +325,9 @@
 	CLK_DUMMY("",	mmss_mmssnoc_ahb_clk.c,	"", OFF),
 	CLK_DUMMY("",	mmss_mmssnoc_axi_clk.c,	"", OFF),
 	CLK_DUMMY("",	mmss_s0_axi_clk.c,	"", OFF),
-	CLK_DUMMY("",	ocmemcx_ocmemnoc_clk.c,	"", OFF),
+	CLK_DUMMY("core_clk",  ocmemgx_core_clk.c, "fdd00000.qcom,ocmem", OFF),
+	CLK_DUMMY("iface_clk",	ocmemcx_ocmemnoc_clk.c,
+						"fdd00000.qcom,ocmem", OFF),
 	CLK_DUMMY("",	oxili_ocmemgx_clk.c,	"", OFF),
 	CLK_DUMMY("",	oxili_gfx3d_clk.c,	"", OFF),
 	CLK_DUMMY("",	oxili_rbbmtimer_clk.c,	"", OFF),
diff --git a/arch/arm/mach-msm/clock-8092.c b/arch/arm/mach-msm/clock-8092.c
new file mode 100644
index 0000000..a8520e6
--- /dev/null
+++ b/arch/arm/mach-msm/clock-8092.c
@@ -0,0 +1,323 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/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/socinfo.h>
+#include <mach/rpm-smd.h>
+
+#include "clock-local2.h"
+#include "clock-pll.h"
+#include "clock-rpm.h"
+#include "clock-voter.h"
+#include "clock.h"
+
+/*
+ * Drivers need to fill in the clock names and device names for the clocks
+ * they need to control.
+ */
+static struct clk_lookup msm_clocks_8092[] = {
+	CLK_DUMMY("core_clk",   BLSP1_UART_CLK, "msm_serial_hsl.0", OFF),
+	CLK_DUMMY("iface_clk",  BLSP1_UART_CLK, "msm_serial_hsl.0", 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("",	usb30_master_clk_src.c,	"", OFF),
+	CLK_DUMMY("",	tsif_ref_clk_src.c,	"", OFF),
+	CLK_DUMMY("",	ce1_clk_src.c,	"", OFF),
+	CLK_DUMMY("",	ce2_clk_src.c,	"", OFF),
+	CLK_DUMMY("",	ce3_clk_src.c,	"", OFF),
+	CLK_DUMMY("",	geni_ser_clk_src.c,	"", OFF),
+	CLK_DUMMY("",	gmac_125m_clk_src.c,	"", OFF),
+	CLK_DUMMY("",	gmac_core_clk_src.c,	"", OFF),
+	CLK_DUMMY("",	gmac_sys_25m_clk_src.c,	"", OFF),
+	CLK_DUMMY("",	gp1_clk_src.c,	"", OFF),
+	CLK_DUMMY("",	gp2_clk_src.c,	"", OFF),
+	CLK_DUMMY("",	gp3_clk_src.c,	"", OFF),
+	CLK_DUMMY("",	pcie_aux_clk_src.c,	"", OFF),
+	CLK_DUMMY("",	pcie_pipe_clk_src.c,	"", OFF),
+	CLK_DUMMY("",	pdm2_clk_src.c,	"", OFF),
+	CLK_DUMMY("",	pwm_clk_src.c,	"", OFF),
+	CLK_DUMMY("",	sata_asic0_clk_src.c,	"", OFF),
+	CLK_DUMMY("",	sata_pmalive_clk_src.c,	"", OFF),
+	CLK_DUMMY("",	sata_rx_clk_src.c,	"", OFF),
+	CLK_DUMMY("",	sata_rx_oob_clk_src.c,	"", OFF),
+	CLK_DUMMY("",	sdcc1_apps_clk_src.c,	"", OFF),
+	CLK_DUMMY("",	sdcc2_apps_clk_src.c,	"", OFF),
+	CLK_DUMMY("",	usb30_mock_utmi_clk_src.c,	"", OFF),
+	CLK_DUMMY("",	usb_hs_system_clk_src.c,	"", OFF),
+	CLK_DUMMY("",	usb_hs2_system_clk_src.c,	"", OFF),
+	CLK_DUMMY("",	usb_hsic_clk_src.c,	"", OFF),
+	CLK_DUMMY("",	usb_hsic_io_cal_clk_src.c,	"", OFF),
+	CLK_DUMMY("",	usb_hsic_system_clk_src.c,	"", OFF),
+	CLK_DUMMY("",	gcc_bam_dma_ahb_clk.c,	"", OFF),
+	CLK_DUMMY("",	gcc_bcss_cfg_ahb_clk.c,	"", OFF),
+	CLK_DUMMY("",	gcc_bimc_gfx_clk.c,	"", OFF),
+	CLK_DUMMY("",	gcc_bimc_kpss_axi_mstr_clk.c,	"", OFF),
+	CLK_DUMMY("",	gcc_bimc_sysnoc_axi_mstr_clk.c,	"", OFF),
+	CLK_DUMMY("",	gcc_blsp1_ahb_clk.c,	"", OFF),
+	CLK_DUMMY("",	gcc_blsp1_qup1_i2c_apps_clk.c,	"", OFF),
+	CLK_DUMMY("",	gcc_blsp1_qup1_spi_apps_clk.c,	"", OFF),
+	CLK_DUMMY("",	gcc_blsp1_qup2_i2c_apps_clk.c,	"", OFF),
+	CLK_DUMMY("",	gcc_blsp1_qup2_spi_apps_clk.c,	"", OFF),
+	CLK_DUMMY("",	gcc_blsp1_qup3_i2c_apps_clk.c,	"", OFF),
+	CLK_DUMMY("",	gcc_blsp1_qup3_spi_apps_clk.c,	"", OFF),
+	CLK_DUMMY("",	gcc_blsp1_qup4_i2c_apps_clk.c,	"", OFF),
+	CLK_DUMMY("",	gcc_blsp1_qup4_spi_apps_clk.c,	"", OFF),
+	CLK_DUMMY("",	gcc_blsp1_qup5_i2c_apps_clk.c,	"", OFF),
+	CLK_DUMMY("",	gcc_blsp1_qup5_spi_apps_clk.c,	"", OFF),
+	CLK_DUMMY("",	gcc_blsp1_qup6_i2c_apps_clk.c,	"", OFF),
+	CLK_DUMMY("",	gcc_blsp1_qup6_spi_apps_clk.c,	"", OFF),
+	CLK_DUMMY("",	gcc_blsp1_uart1_apps_clk.c,	"", OFF),
+	CLK_DUMMY("",	gcc_blsp1_uart2_apps_clk.c,	"", OFF),
+	CLK_DUMMY("",	gcc_blsp1_uart3_apps_clk.c,	"", OFF),
+	CLK_DUMMY("",	gcc_blsp1_uart4_apps_clk.c,	"", OFF),
+	CLK_DUMMY("",	gcc_blsp1_uart5_apps_clk.c,	"", OFF),
+	CLK_DUMMY("",	gcc_blsp1_uart6_apps_clk.c,	"", OFF),
+	CLK_DUMMY("",	gcc_blsp2_ahb_clk.c,	"", OFF),
+	CLK_DUMMY("",	gcc_blsp2_qup1_i2c_apps_clk.c,	"", OFF),
+	CLK_DUMMY("",	gcc_blsp2_qup1_spi_apps_clk.c,	"", OFF),
+	CLK_DUMMY("",	gcc_blsp2_qup2_i2c_apps_clk.c,	"", OFF),
+	CLK_DUMMY("",	gcc_blsp2_qup2_spi_apps_clk.c,	"", OFF),
+	CLK_DUMMY("",	gcc_blsp2_qup3_i2c_apps_clk.c,	"", OFF),
+	CLK_DUMMY("",	gcc_blsp2_qup3_spi_apps_clk.c,	"", OFF),
+	CLK_DUMMY("",	gcc_blsp2_qup4_i2c_apps_clk.c,	"", OFF),
+	CLK_DUMMY("",	gcc_blsp2_qup4_spi_apps_clk.c,	"", OFF),
+	CLK_DUMMY("",	gcc_blsp2_qup5_i2c_apps_clk.c,	"", OFF),
+	CLK_DUMMY("",	gcc_blsp2_qup5_spi_apps_clk.c,	"", OFF),
+	CLK_DUMMY("",	gcc_blsp2_qup6_i2c_apps_clk.c,	"", OFF),
+	CLK_DUMMY("",	gcc_blsp2_qup6_spi_apps_clk.c,	"", OFF),
+	CLK_DUMMY("",	gcc_blsp2_uart1_apps_clk.c,	"", OFF),
+	CLK_DUMMY("",	gcc_blsp2_uart2_apps_clk.c,	"", OFF),
+	CLK_DUMMY("",	gcc_blsp2_uart3_apps_clk.c,	"", OFF),
+	CLK_DUMMY("",	gcc_blsp2_uart4_apps_clk.c,	"", OFF),
+	CLK_DUMMY("",	gcc_blsp2_uart5_apps_clk.c,	"", OFF),
+	CLK_DUMMY("",	gcc_blsp2_uart6_apps_clk.c,	"", OFF),
+	CLK_DUMMY("",	gcc_boot_rom_ahb_clk.c,	"", OFF),
+	CLK_DUMMY("",	gcc_ce1_ahb_clk.c,	"", OFF),
+	CLK_DUMMY("",	gcc_ce1_axi_clk.c,	"", OFF),
+	CLK_DUMMY("",	gcc_ce1_clk.c,	"", OFF),
+	CLK_DUMMY("",	gcc_ce2_ahb_clk.c,	"", OFF),
+	CLK_DUMMY("",	gcc_ce2_axi_clk.c,	"", OFF),
+	CLK_DUMMY("",	gcc_ce2_clk.c,	"", OFF),
+	CLK_DUMMY("",	gcc_ce3_ahb_clk.c,	"", OFF),
+	CLK_DUMMY("",	gcc_ce3_axi_clk.c,	"", OFF),
+	CLK_DUMMY("",	gcc_ce3_clk.c,	"", OFF),
+	CLK_DUMMY("",	gcc_xo_clk.c,	"", OFF),
+	CLK_DUMMY("",	gcc_xo_div4_clk.c,	"", OFF),
+	CLK_DUMMY("",	gcc_geni_ahb_clk.c,	"", OFF),
+	CLK_DUMMY("",	gcc_geni_ser_clk.c,	"", OFF),
+	CLK_DUMMY("",	gcc_gmac_125m_clk.c,	"", OFF),
+	CLK_DUMMY("",	gcc_gmac_axi_clk.c,	"", OFF),
+	CLK_DUMMY("",	gcc_gmac_cfg_ahb_clk.c,	"", OFF),
+	CLK_DUMMY("",	gcc_gmac_core_clk.c,	"", OFF),
+	CLK_DUMMY("",	gcc_gmac_rx_clk.c,	"", OFF),
+	CLK_DUMMY("",	gcc_gmac_sys_25m_clk.c,	"", OFF),
+	CLK_DUMMY("",	gcc_gmac_sys_clk.c,	"", OFF),
+	CLK_DUMMY("",	gcc_gp1_clk.c,	"", OFF),
+	CLK_DUMMY("",	gcc_gp2_clk.c,	"", OFF),
+	CLK_DUMMY("",	gcc_gp3_clk.c,	"", OFF),
+	CLK_DUMMY("",	gcc_klm_core_clk.c,	"", OFF),
+	CLK_DUMMY("",	gcc_klm_s_clk.c,	"", OFF),
+	CLK_DUMMY("",	gcc_lpass_q6_axi_clk.c,	"", OFF),
+	CLK_DUMMY("",	gcc_sys_noc_lpass_mport_clk.c,	"", OFF),
+	CLK_DUMMY("",	gcc_sys_noc_lpass_sway_clk.c,	"", OFF),
+	CLK_DUMMY("",	gcc_mmss_a5ss_axi_clk.c,	"", OFF),
+	CLK_DUMMY("",	gcc_mmss_bimc_gfx_clk.c,	"", OFF),
+	CLK_DUMMY("",	gcc_pcie_axi_clk.c,	"", OFF),
+	CLK_DUMMY("",	gcc_pcie_axi_mstr_clk.c,	"", OFF),
+	CLK_DUMMY("",	gcc_pcie_cfg_ahb_clk.c,	"", OFF),
+	CLK_DUMMY("",	gcc_pcie_pipe_clk.c,	"", OFF),
+	CLK_DUMMY("",	gcc_pcie_sleep_clk.c,	"", OFF),
+	CLK_DUMMY("",	gcc_pdm2_clk.c,	"", OFF),
+	CLK_DUMMY("",	gcc_pdm_ahb_clk.c,	"", OFF),
+	CLK_DUMMY("",	gcc_prng_ahb_clk.c,	"", OFF),
+	CLK_DUMMY("",	gcc_pwm_ahb_clk.c,	"", OFF),
+	CLK_DUMMY("",	gcc_pwm_clk.c,	"", OFF),
+	CLK_DUMMY("",	gcc_sata_asic0_clk.c,	"", OFF),
+	CLK_DUMMY("",	gcc_sata_axi_clk.c,	"", OFF),
+	CLK_DUMMY("",	gcc_sata_cfg_ahb_clk.c,	"", OFF),
+	CLK_DUMMY("",	gcc_sata_pmalive_clk.c,	"", OFF),
+	CLK_DUMMY("",	gcc_sata_rx_clk.c,	"", OFF),
+	CLK_DUMMY("",	gcc_sata_rx_oob_clk.c,	"", OFF),
+	CLK_DUMMY("",	gcc_sdcc1_ahb_clk.c,	"", OFF),
+	CLK_DUMMY("",	gcc_sdcc1_apps_clk.c,	"", OFF),
+	CLK_DUMMY("",	gcc_sdcc2_ahb_clk.c,	"", OFF),
+	CLK_DUMMY("",	gcc_sdcc2_apps_clk.c,	"", OFF),
+	CLK_DUMMY("",	gcc_spss_ahb_clk.c,	"", OFF),
+	CLK_DUMMY("",	gcc_sys_noc_usb3_axi_clk.c,	"", OFF),
+	CLK_DUMMY("",	gcc_usb2a_phy_sleep_clk.c,	"", OFF),
+	CLK_DUMMY("",	gcc_usb2b_phy_sleep_clk.c,	"", OFF),
+	CLK_DUMMY("",	gcc_usb2c_phy_sleep_clk.c,	"", OFF),
+	CLK_DUMMY("",	gcc_usb30_master_clk.c,	"", OFF),
+	CLK_DUMMY("",	gcc_usb30_mock_utmi_clk.c,	"", OFF),
+	CLK_DUMMY("",	gcc_usb30_sleep_clk.c,	"", OFF),
+	CLK_DUMMY("",	gcc_usb_hs_ahb_clk.c,	"", OFF),
+	CLK_DUMMY("",	gcc_usb_hs_system_clk.c,	"", OFF),
+	CLK_DUMMY("",	gcc_usb_hs2_ahb_clk.c,	"", OFF),
+	CLK_DUMMY("",	gcc_usb_hs2_system_clk.c,	"", OFF),
+	CLK_DUMMY("",	gcc_usb_hsic_ahb_clk.c,	"", OFF),
+	CLK_DUMMY("",	gcc_usb_hsic_clk.c,	"", OFF),
+	CLK_DUMMY("",	gcc_usb_hsic_io_cal_clk.c,	"", OFF),
+	CLK_DUMMY("",	gcc_usb_hsic_system_clk.c,	"", OFF),
+	/* MMSS Clock Dummy */
+	CLK_DUMMY("",	axi_clk_src.c,	"", OFF),
+	CLK_DUMMY("",	mmpll0_pll_clk_src.c,	"", OFF),
+	CLK_DUMMY("",	mmpll1_pll_clk_src.c,	"", OFF),
+	CLK_DUMMY("",	mmpll2_pll_clk_src.c,	"", OFF),
+	CLK_DUMMY("",	mmpll3_pll_clk_src.c,	"", OFF),
+	CLK_DUMMY("",	mmpll6_pll_clk_src.c,	"", OFF),
+	CLK_DUMMY("",	vcodec0_clk_src.c,	"", OFF),
+	CLK_DUMMY("",	extpclk_clk_src.c,	"", OFF),
+	CLK_DUMMY("",	lvds_clk_src.c,	"", OFF),
+	CLK_DUMMY("",	mdp_clk_src.c,	"", OFF),
+	CLK_DUMMY("",	vbyone_clk_src.c,	"", OFF),
+	CLK_DUMMY("",	gfx3d_clk_src.c,	"", OFF),
+	CLK_DUMMY("",	vp_clk_src.c,	"", OFF),
+	CLK_DUMMY("",	jpeg2_clk_src.c,	"", OFF),
+	CLK_DUMMY("",	hdmi_clk_src.c,	"", OFF),
+	CLK_DUMMY("",	vbyone_symbol_clk_src.c,	"", OFF),
+	CLK_DUMMY("",	mmss_spdm_axi_div_clk.c,	"", OFF),
+	CLK_DUMMY("",	mmss_spdm_gfx3d_div_clk.c,	"", OFF),
+	CLK_DUMMY("",	mmss_spdm_jpeg2_div_clk.c,	"", OFF),
+	CLK_DUMMY("",	mmss_spdm_mdp_div_clk.c,	"", OFF),
+	CLK_DUMMY("",	mmss_spdm_vcodec0_div_clk.c,	"", OFF),
+	CLK_DUMMY("",	afe_pixel_clk_src.c,	"", OFF),
+	CLK_DUMMY("",	cfg_clk_src.c,	"", OFF),
+	CLK_DUMMY("",	hdmi_bus_clk_src.c,	"", OFF),
+	CLK_DUMMY("",	hdmi_rx_clk_src.c,	"", OFF),
+	CLK_DUMMY("",	md_clk_src.c,	"", OFF),
+	CLK_DUMMY("",	ttl_clk_src.c,	"", OFF),
+	CLK_DUMMY("",	vafe_ext_clk_src.c,	"", OFF),
+	CLK_DUMMY("",	vcap_vp_clk_src.c,	"", OFF),
+	CLK_DUMMY("",	gproc_clk_src.c,	"", OFF),
+	CLK_DUMMY("",	hdmc_frcf_clk_src.c,	"", OFF),
+	CLK_DUMMY("",	kproc_clk_src.c,	"", OFF),
+	CLK_DUMMY("",	maple_clk_src.c,	"", OFF),
+	CLK_DUMMY("",	preproc_clk_src.c,	"", OFF),
+	CLK_DUMMY("",	sdmc_frcs_clk_src.c,	"", OFF),
+	CLK_DUMMY("",	sdme_frcf_clk_src.c,	"", OFF),
+	CLK_DUMMY("",	sdme_vproc_clk_src.c,	"", OFF),
+	CLK_DUMMY("",	vdp_clk_src.c,	"", OFF),
+	CLK_DUMMY("",	vpu_bus_clk_src.c,	"", OFF),
+	CLK_DUMMY("",	vpu_frc_xin_clk_src.c,	"", OFF),
+	CLK_DUMMY("",	vpu_vdp_xin_clk_src.c,	"", OFF),
+	CLK_DUMMY("",	avsync_ahb_clk.c,	"", OFF),
+	CLK_DUMMY("",	avsync_extpclk_clk.c,	"", OFF),
+	CLK_DUMMY("",	avsync_lvds_clk.c,	"", OFF),
+	CLK_DUMMY("",	avsync_vbyone_clk.c,	"", OFF),
+	CLK_DUMMY("",	avsync_vp_clk.c,	"", OFF),
+	CLK_DUMMY("",	camss_jpeg_jpeg2_clk.c,	"", OFF),
+	CLK_DUMMY("",	camss_jpeg_jpeg_ahb_clk.c,	"", OFF),
+	CLK_DUMMY("",	camss_jpeg_jpeg_axi_clk.c,	"", OFF),
+	CLK_DUMMY("",	camss_micro_ahb_clk.c,	"", OFF),
+	CLK_DUMMY("",	camss_top_ahb_clk.c,	"", OFF),
+	CLK_DUMMY("",	mdss_ahb_clk.c,	"", OFF),
+	CLK_DUMMY("",	mdss_axi_clk.c,	"", OFF),
+	CLK_DUMMY("",	mdss_extpclk_clk.c,	"", OFF),
+	CLK_DUMMY("",	mdss_hdmi_ahb_clk.c,	"", OFF),
+	CLK_DUMMY("",	mdss_hdmi_clk.c,	"", OFF),
+	CLK_DUMMY("",	mdss_lvds_clk.c,	"", OFF),
+	CLK_DUMMY("",	mdss_mdp_clk.c,	"", OFF),
+	CLK_DUMMY("",	mdss_mdp_lut_clk.c,	"", OFF),
+	CLK_DUMMY("",	mdss_vbyone_clk.c,	"", OFF),
+	CLK_DUMMY("",	mdss_vbyone_symbol_clk.c,	"", OFF),
+	CLK_DUMMY("",	mmss_misc_ahb_clk.c,	"", OFF),
+	CLK_DUMMY("",	mmss_mmssnoc_ahb_clk.c,	"", OFF),
+	CLK_DUMMY("",	mmss_mmssnoc_axi_clk.c,	"", OFF),
+	CLK_DUMMY("",	mmss_s0_axi_clk.c,	"", OFF),
+	CLK_DUMMY("",	ocmemcx_ocmemnoc_clk.c,	"", OFF),
+	CLK_DUMMY("",	oxili_ocmemgx_clk.c,	"", OFF),
+	CLK_DUMMY("",	oxili_gfx3d_clk.c,	"", OFF),
+	CLK_DUMMY("",	oxilicx_ahb_clk.c,	"", OFF),
+	CLK_DUMMY("",	bcss_mmss_ifdemod_clk.c,	"", OFF),
+	CLK_DUMMY("",	vcap_afe_pixel_clk.c,	"", OFF),
+	CLK_DUMMY("",	vcap_ahb_clk.c,	"", OFF),
+	CLK_DUMMY("",	vcap_audio_clk.c,	"", OFF),
+	CLK_DUMMY("",	vcap_axi_clk.c,	"", OFF),
+	CLK_DUMMY("",	vcap_cfg_clk.c,	"", OFF),
+	CLK_DUMMY("",	vcap_hdmi_bus_clk.c,	"", OFF),
+	CLK_DUMMY("",	vcap_hdmi_rx_clk.c,	"", OFF),
+	CLK_DUMMY("",	vcap_md_clk.c,	"", OFF),
+	CLK_DUMMY("",	vcap_ttl_clk.c,	"", OFF),
+	CLK_DUMMY("",	vcap_ttl_debug_clk.c,	"", OFF),
+	CLK_DUMMY("",	vcap_vafe_ext_clk.c,	"", OFF),
+	CLK_DUMMY("",	vcap_vp_clk.c,	"", OFF),
+	CLK_DUMMY("",	venus0_ahb_clk.c,	"", OFF),
+	CLK_DUMMY("",	venus0_axi_clk.c,	"", OFF),
+	CLK_DUMMY("",	venus0_core0_vcodec_clk.c,	"", OFF),
+	CLK_DUMMY("",	venus0_core1_vcodec_clk.c,	"", OFF),
+	CLK_DUMMY("",	venus0_ocmemnoc_clk.c,	"", OFF),
+	CLK_DUMMY("",	venus0_vcodec0_clk.c,	"", OFF),
+	CLK_DUMMY("",	vpu_ahb_clk.c,	"", OFF),
+	CLK_DUMMY("",	vpu_axi_clk.c,	"", OFF),
+	CLK_DUMMY("",	vpu_bus_clk.c,	"", OFF),
+	CLK_DUMMY("",	vpu_cxo_clk.c,	"", OFF),
+	CLK_DUMMY("",	vpu_frc_xin_clk.c,	"", OFF),
+	CLK_DUMMY("",	vpu_gproc_clk.c,	"", OFF),
+	CLK_DUMMY("",	vpu_hdmc_frcf_clk.c,	"", OFF),
+	CLK_DUMMY("",	vpu_kproc_clk.c,	"", OFF),
+	CLK_DUMMY("",	vpu_maple_clk.c,	"", OFF),
+	CLK_DUMMY("",	vpu_preproc_clk.c,	"", OFF),
+	CLK_DUMMY("",	vpu_sdmc_frcs_clk.c,	"", OFF),
+	CLK_DUMMY("",	vpu_sdme_frcf_clk.c,	"", OFF),
+	CLK_DUMMY("",	vpu_sdme_frcs_clk.c,	"", OFF),
+	CLK_DUMMY("",	vpu_sdme_vproc_clk.c,	"", OFF),
+	CLK_DUMMY("",	vpu_sleep_clk.c,	"", OFF),
+	CLK_DUMMY("",	vpu_vdp_clk.c,	"", OFF),
+	CLK_DUMMY("",	vpu_vdp_xin_clk.c,	"", OFF),
+	/* BCSS broadcast */
+	CLK_DUMMY("",	bcc_dem_core_b_clk_src.c,	"", OFF),
+	CLK_DUMMY("",	adc_01_clk_src.c,	"", OFF),
+	CLK_DUMMY("",	bcc_adc_0_in_clk.c,	"", OFF),
+	CLK_DUMMY("",	bcc_dem_ahb_clk.c,	"", OFF),
+	CLK_DUMMY("",	bcc_klm_ahb_clk.c,	"", OFF),
+	CLK_DUMMY("",	bcc_lnb_ahb_clk.c,	"", OFF),
+	CLK_DUMMY("",	bcc_tsc_ahb_clk.c,	"", OFF),
+	CLK_DUMMY("",	bcc_tspp2_ahb_clk.c,	"", OFF),
+	CLK_DUMMY("",	bcc_vbif_ahb_clk.c,	"", OFF),
+	CLK_DUMMY("",	gcc_bcss_ahb_clk.c,	"", OFF),
+	CLK_DUMMY("",	bcc_dem_atv_rxfe_clk.c,	"", OFF),
+	CLK_DUMMY("",	bcc_dem_atv_rxfe_resamp_clk.c,	"", OFF),
+	CLK_DUMMY("",	bcc_dem_core_clk_src.c,	"", OFF),
+	CLK_DUMMY("",	bcc_dem_core_div2_clk_src.c,	"", OFF),
+	CLK_DUMMY("",	bcc_dem_core_x2_b_clk_src.c,	"", OFF),
+	CLK_DUMMY("",	bcc_dem_core_x2_pre_cgf_clk.c,	"", OFF),
+	CLK_DUMMY("",	bcc_tsc_ci_clk.c,	"", OFF),
+	CLK_DUMMY("",	bcc_tsc_cicam_ts_clk_src.c,	"", OFF),
+	CLK_DUMMY("",	bcc_tsc_par_clk.c,	"", OFF),
+	CLK_DUMMY("",	bcc_tsc_ser_clk_src.c,	"", OFF),
+	CLK_DUMMY("",	bcc_tspp2_clk_src.c,	"", OFF),
+	CLK_DUMMY("",	dig_dem_core_b_div2_clk.c,	"", OFF),
+	CLK_DUMMY("",	atv_x5_pre_cgc_clk.c,	"", OFF),
+	CLK_DUMMY("",	bcc_albacore_cvbs_clk.c,	"", OFF),
+	CLK_DUMMY("",	bcc_atv_x1_clk.c,	"", OFF),
+	CLK_DUMMY("",	nidaq_out_clk.c,	"", OFF),
+	CLK_DUMMY("",	gcc_bcss_axi_clk.c,	"", OFF),
+	CLK_DUMMY("",	bcc_lnb_core_clk.c,	"", OFF),
+};
+
+struct clock_init_data mpq8092_clock_init_data __initdata = {
+	.table = msm_clocks_8092,
+	.size = ARRAY_SIZE(msm_clocks_8092),
+};
diff --git a/arch/arm/mach-msm/clock-8226.c b/arch/arm/mach-msm/clock-8226.c
index f3de05a..1477541 100644
--- a/arch/arm/mach-msm/clock-8226.c
+++ b/arch/arm/mach-msm/clock-8226.c
@@ -24,6 +24,7 @@
 #include <mach/rpm-regulator-smd.h>
 #include <mach/socinfo.h>
 #include <mach/rpm-smd.h>
+#include <mach/clock-generic.h>
 
 #include "clock-local2.h"
 #include "clock-pll.h"
@@ -1789,27 +1790,73 @@
 	},
 };
 
-static struct branch_clk mdss_ahb_clk;
-static struct clk dsipll0_byte_clk_src = {
-	.depends = &mdss_ahb_clk.c,
-	.parent = &xo.c,
-	.dbg_name = "dsipll0_byte_clk_src",
-	.ops = &clk_ops_dsi_byte_pll,
-	CLK_INIT(dsipll0_byte_clk_src),
-};
+struct clk_ops clk_ops_pixel_clock;
 
-static struct clk dsipll0_pixel_clk_src = {
-	.depends = &mdss_ahb_clk.c,
-	.parent = &xo.c,
-	.dbg_name = "dsipll0_pixel_clk_src",
-	.ops = &clk_ops_dsi_pixel_pll,
-	CLK_INIT(dsipll0_pixel_clk_src),
-};
+static long round_rate_pixel(struct clk *clk, unsigned long rate)
+{
+	int frac_num[] = {3, 2, 4, 1};
+	int frac_den[] = {8, 9, 9, 1};
+	int delta = 100000;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(frac_num); i++) {
+		unsigned long request = (rate * frac_den[i]) / frac_num[i];
+		unsigned long src_rate;
+
+		src_rate = clk_round_rate(clk->parent, request);
+		if ((src_rate < (request - delta)) ||
+			(src_rate > (request + delta)))
+			continue;
+
+		return (src_rate * frac_num[i]) / frac_den[i];
+	}
+
+	return -EINVAL;
+}
+
+
+static int set_rate_pixel(struct clk *clk, unsigned long rate)
+{
+	struct rcg_clk *rcg = to_rcg_clk(clk);
+	struct clk_freq_tbl *pixel_freq = rcg->current_freq;
+	int frac_num[] = {3, 2, 4, 1};
+	int frac_den[] = {8, 9, 9, 1};
+	int delta = 100000;
+	int i, rc;
+
+	for (i = 0; i < ARRAY_SIZE(frac_num); i++) {
+		unsigned long request = (rate * frac_den[i]) / frac_num[i];
+		unsigned long src_rate;
+
+		src_rate = clk_round_rate(clk->parent, request);
+		if ((src_rate < (request - delta)) ||
+			(src_rate > (request + delta)))
+			continue;
+
+		rc =  clk_set_rate(clk->parent, src_rate);
+		if (rc)
+			return rc;
+
+		pixel_freq->div_src_val &= ~BM(4, 0);
+		if (frac_den[i] == frac_num[i]) {
+			pixel_freq->m_val = 0;
+			pixel_freq->n_val = 0;
+		} else {
+			pixel_freq->m_val = frac_num[i];
+			pixel_freq->n_val = ~(frac_den[i] - frac_num[i]);
+			pixel_freq->d_val = ~frac_den[i];
+		}
+		set_rate_mnd(rcg, pixel_freq);
+		return 0;
+	}
+	return -EINVAL;
+}
 
 static struct clk_freq_tbl pixel_freq_tbl[] = {
 	{
-		.src_clk = &dsipll0_pixel_clk_src,
-		.div_src_val = BVAL(10, 8, dsipll0_pixel_mm_source_val),
+		.src_clk = &pixel_clk_src_8226.c,
+		.div_src_val = BVAL(10, 8, dsipll0_pixel_mm_source_val)
+				| BVAL(4, 0, 0),
 	},
 	F_END
 };
@@ -1819,7 +1866,7 @@
 	.current_freq = pixel_freq_tbl,
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
-		.parent = &dsipll0_pixel_clk_src,
+		.parent = &pixel_clk_src_8226.c,
 		.dbg_name = "pclk0_clk_src",
 		.ops = &clk_ops_pixel,
 		VDD_DIG_FMAX_MAP2(LOW, 83330000, NOMINAL, 166670000),
@@ -2006,7 +2053,7 @@
 
 static struct clk_freq_tbl byte_freq_tbl[] = {
 	{
-		.src_clk = &dsipll0_byte_clk_src,
+		.src_clk = &byte_clk_src_8226.c,
 		.div_src_val = BVAL(10, 8, dsipll0_byte_mm_source_val),
 	},
 	F_END
@@ -2017,7 +2064,7 @@
 	.current_freq = byte_freq_tbl,
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
-		.parent = &dsipll0_byte_clk_src,
+		.parent = &byte_clk_src_8226.c,
 		.dbg_name = "byte0_clk_src",
 		.ops = &clk_ops_byte,
 		VDD_DIG_FMAX_MAP2(LOW, 62500000, NOMINAL, 125000000),
@@ -2764,7 +2811,7 @@
 				vdd_sr2_levels, NULL);
 
 static struct pll_freq_tbl apcs_pll_freq[] = {
-	F_APCS_PLL( 384000000, 20, 0x0, 0x1, 0x0, 0x0, 0x0),
+	F_APCS_PLL( 768000000, 40, 0x0, 0x1, 0x0, 0x0, 0x0),
 	F_APCS_PLL( 787200000, 41, 0x0, 0x1, 0x0, 0x0, 0x0),
 	F_APCS_PLL( 998400000, 52, 0x0, 0x1, 0x0, 0x0, 0x0),
 	F_APCS_PLL(1094400000, 57, 0x0, 0x1, 0x0, 0x0, 0x0),
@@ -3271,7 +3318,8 @@
 	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("pixel_clk", mdss_pclk0_clk.c, "fd922800.qcom,mdss_dsi"),
-	CLK_LOOKUP("iface_clk", mdss_ahb_clk.c, "mdss_dsi_clk_ctrl"),
+	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("core_clk", mdss_mdp_clk.c, "fd900000.qcom,mdss_mdp"),
 	CLK_LOOKUP("lut_clk", mdss_mdp_lut_clk.c, "fd900000.qcom,mdss_mdp"),
@@ -3464,6 +3512,13 @@
 	CLK_LOOKUP("bus_clk",      gcc_ce1_axi_clk.c, "fd404000.qcom,qcrypto"),
 	CLK_LOOKUP("core_clk_src", ce1_clk_src.c,     "fd404000.qcom,qcrypto"),
 
+	/* DSI PLL clocks */
+	CLK_LOOKUP("",		dsi_vco_clk_8226.c,                  ""),
+	CLK_LOOKUP("",		analog_postdiv_clk_8226.c,         ""),
+	CLK_LOOKUP("",		indirect_path_div2_clk_8226.c,     ""),
+	CLK_LOOKUP("",		pixel_clk_src_8226.c,              ""),
+	CLK_LOOKUP("",		byte_mux_8226.c,                   ""),
+	CLK_LOOKUP("",		byte_clk_src_8226.c,               ""),
 };
 
 static struct clk_lookup msm_clocks_8226_rumi[] = {
@@ -3507,6 +3562,9 @@
 	 */
 	clk_prepare_enable(&xo_a_clk.c);
 
+	/* Set an initial rate (fmax at nominal) on the MMSSNOC AXI clock */
+	clk_set_rate(&axi_clk_src.c, 200000000);
+
 	/* Set rates for single-rate clocks. */
 	clk_set_rate(&usb_hs_system_clk_src.c,
 			usb_hs_system_clk_src.freq_tbl[0].freq_hz);
@@ -3586,9 +3644,6 @@
 	 */
 	clk_set_rate(&mmssnoc_ahb_a_clk.c, 40000000);
 
-	/* Set an initial rate (fmax at nominal) on the MMSSNOC AXI clock */
-	clk_set_rate(&axi_clk_src.c, 200000000);
-
 	enable_rpm_scaling();
 
 	reg_init();
@@ -3599,6 +3654,10 @@
 		vfe0_clk_src.c.fmax = camss_vfe_vfe0_fmax_v2;
 	}
 
+	clk_ops_pixel_clock = clk_ops_pixel;
+	clk_ops_pixel_clock.set_rate = set_rate_pixel;
+	clk_ops_pixel_clock.round_rate = round_rate_pixel;
+
 	/*
 	 * MDSS needs the ahb clock and needs to init before we register the
 	 * lookup table.
diff --git a/arch/arm/mach-msm/clock-8610.c b/arch/arm/mach-msm/clock-8610.c
index 340f1ef..7c7d629 100644
--- a/arch/arm/mach-msm/clock-8610.c
+++ b/arch/arm/mach-msm/clock-8610.c
@@ -509,7 +509,6 @@
 
 static DEFINE_CLK_VOTER(pnoc_sps_clk, &pnoc_clk.c, LONG_MAX);
 static DEFINE_CLK_VOTER(pnoc_iommu_clk, &pnoc_clk.c, LONG_MAX);
-static DEFINE_CLK_VOTER(pnoc_qseecom_clk, &pnoc_clk.c, LONG_MAX);
 
 static DEFINE_CLK_MEASURE(apc0_m_clk);
 static DEFINE_CLK_MEASURE(apc1_m_clk);
@@ -544,7 +543,7 @@
 				vdd_sr2_levels, NULL);
 
 static struct pll_freq_tbl apcs_pll_freq[] = {
-	F_APCS_PLL( 384000000, 20, 0x0, 0x1, 0x0, 0x0, 0x0),
+	F_APCS_PLL( 768000000, 40, 0x0, 0x1, 0x0, 0x0, 0x0),
 	F_APCS_PLL( 787200000, 41, 0x0, 0x1, 0x0, 0x0, 0x0),
 	F_APCS_PLL( 998400000, 52, 0x0, 0x1, 0x0, 0x0, 0x0),
 	F_APCS_PLL(1190400000, 62, 0x0, 0x1, 0x0, 0x0, 0x0),
@@ -1546,6 +1545,7 @@
 	F_END,
 };
 
+static struct branch_clk mmss_mmssnoc_axi_clk;
 static struct rcg_clk axi_clk_src = {
 	.cmd_rcgr_reg = AXI_CMD_RCGR,
 	.set_rate = set_rate_hid,
@@ -1557,6 +1557,7 @@
 		.ops = &clk_ops_rcg,
 		VDD_DIG_FMAX_MAP2(LOW, 100000000, NOMINAL, 200000000),
 		CLK_INIT(axi_clk_src.c),
+		.depends = &mmss_mmssnoc_axi_clk.c
 	},
 };
 
@@ -2320,7 +2321,6 @@
 	.has_sibling = 1,
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
-		.parent = &axi_clk_src.c,
 		.dbg_name = "mmss_mmssnoc_axi_clk",
 		.ops = &clk_ops_branch,
 		CLK_INIT(mmss_mmssnoc_axi_clk.c),
@@ -2336,7 +2336,6 @@
 		.dbg_name = "mmss_s0_axi_clk",
 		.ops = &clk_ops_branch,
 		CLK_INIT(mmss_s0_axi_clk.c),
-		.depends = &mmss_mmssnoc_axi_clk.c,
 	},
 };
 
@@ -2764,7 +2763,6 @@
 	CLK_LOOKUP("core_clk",  gcc_blsp1_uart2_apps_clk.c, "f991e000.serial"),
 
 	CLK_LOOKUP("dfab_clk", pnoc_sps_clk.c, "msm_sps"),
-	CLK_LOOKUP("bus_clk",  pnoc_qseecom_clk.c, "qseecom"),
 
 	CLK_LOOKUP("bus_clk", snoc_clk.c, ""),
 	CLK_LOOKUP("bus_clk", pnoc_clk.c, ""),
@@ -3041,6 +3039,18 @@
 	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", ce1_clk_src.c,      "scm"),
+
+	/* 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"),
+	CLK_LOOKUP("bus_clk",      gcc_ce1_axi_clk.c,  "fd400000.qcom,qcedev"),
+	CLK_LOOKUP("core_clk_src", ce1_clk_src.c,      "fd400000.qcom,qcedev"),
+
+	/* Add QCRYPTO clocks */
+	CLK_LOOKUP("core_clk",     gcc_ce1_clk.c,     "fd404000.qcom,qcrypto"),
+	CLK_LOOKUP("iface_clk",    gcc_ce1_ahb_clk.c, "fd404000.qcom,qcrypto"),
+	CLK_LOOKUP("bus_clk",      gcc_ce1_axi_clk.c, "fd404000.qcom,qcrypto"),
+	CLK_LOOKUP("core_clk_src", ce1_clk_src.c,     "fd404000.qcom,qcrypto"),
 };
 
 static struct clk_lookup msm_clocks_8610_rumi[] = {
@@ -3232,10 +3242,6 @@
 	/* Maintain the max nominal frequency on the MMSSNOC AHB bus. */
 	clk_set_rate(&mmssnoc_ahb_a_clk.c,  40000000);
 	clk_prepare_enable(&mmssnoc_ahb_a_clk.c);
-
-	/* TODO: Remove this once the bus driver is in place */
-	clk_set_rate(&axi_clk_src.c, 200000000);
-	clk_prepare_enable(&mmss_s0_axi_clk.c);
 }
 
 struct clock_init_data msm8610_clock_init_data __initdata = {
diff --git a/arch/arm/mach-msm/clock-8960.c b/arch/arm/mach-msm/clock-8960.c
index 9ee4476..9a1611e 100644
--- a/arch/arm/mach-msm/clock-8960.c
+++ b/arch/arm/mach-msm/clock-8960.c
@@ -3526,6 +3526,7 @@
 /*Shared by 8064, and 8930*/
 static struct clk_freq_tbl clk_tbl_gfx3d[] = {
 	F_GFX3D(        0, gnd,   0,  0),
+	F_GFX3D(  1800000, pxo,   1, 15),
 	F_GFX3D( 27000000, pxo,   0,  0),
 	F_GFX3D( 48000000, pll8,  1,  8),
 	F_GFX3D( 54857000, pll8,  1,  7),
diff --git a/arch/arm/mach-msm/clock-8974.c b/arch/arm/mach-msm/clock-8974.c
index 4a16b42..3aef106 100644
--- a/arch/arm/mach-msm/clock-8974.c
+++ b/arch/arm/mach-msm/clock-8974.c
@@ -24,6 +24,7 @@
 #include <mach/rpm-regulator-smd.h>
 #include <mach/socinfo.h>
 #include <mach/rpm-smd.h>
+#include <mach/clock-generic.h>
 
 #include "clock-local2.h"
 #include "clock-pll.h"
@@ -784,6 +785,7 @@
 static DEFINE_CLK_VOTER(snoc_msmbus_clk, &snoc_clk.c, LONG_MAX);
 static DEFINE_CLK_VOTER(cnoc_msmbus_clk, &cnoc_clk.c, LONG_MAX);
 static DEFINE_CLK_VOTER(pnoc_msmbus_a_clk, &pnoc_a_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(pnoc_pm_clk, &pnoc_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);
 
@@ -3011,26 +3013,9 @@
 	},
 };
 
-static struct branch_clk mdss_ahb_clk;
-static struct clk dsipll0_byte_clk_src = {
-	.depends = &mdss_ahb_clk.c,
-	.parent = &cxo_clk_src.c,
-	.dbg_name = "dsipll0_byte_clk_src",
-	.ops = &clk_ops_dsi_byte_pll,
-	CLK_INIT(dsipll0_byte_clk_src),
-};
-
-static struct clk dsipll0_pixel_clk_src = {
-	.depends = &mdss_ahb_clk.c,
-	.parent = &cxo_clk_src.c,
-	.dbg_name = "dsipll0_pixel_clk_src",
-	.ops = &clk_ops_dsi_pixel_pll,
-	CLK_INIT(dsipll0_pixel_clk_src),
-};
-
 static struct clk_freq_tbl byte_freq_tbl[] = {
 	{
-		.src_clk = &dsipll0_byte_clk_src,
+		.src_clk = &byte_clk_src_8974.c,
 		.div_src_val = BVAL(10, 8, dsipll0_byte_mm_source_val),
 	},
 	F_END
@@ -3041,7 +3026,7 @@
 	.current_freq = byte_freq_tbl,
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
-		.parent = &dsipll0_byte_clk_src,
+		.parent = &byte_clk_src_8974.c,
 		.dbg_name = "byte0_clk_src",
 		.ops = &clk_ops_byte,
 		VDD_DIG_FMAX_MAP3(LOW, 93800000, NOMINAL, 187500000,
@@ -3055,7 +3040,7 @@
 	.current_freq = byte_freq_tbl,
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
-		.parent = &dsipll0_byte_clk_src,
+		.parent = &byte_clk_src_8974.c,
 		.dbg_name = "byte1_clk_src",
 		.ops = &clk_ops_byte,
 		VDD_DIG_FMAX_MAP3(LOW, 93800000, NOMINAL, 187500000,
@@ -3235,10 +3220,73 @@
 	},
 };
 
+struct clk_ops clk_ops_pixel_clock;
+
+static long round_rate_pixel(struct clk *clk, unsigned long rate)
+{
+	int frac_num[] = {3, 2, 4, 1};
+	int frac_den[] = {8, 9, 9, 1};
+	int delta = 100000;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(frac_num); i++) {
+		unsigned long request = (rate * frac_den[i]) / frac_num[i];
+		unsigned long src_rate;
+
+		src_rate = clk_round_rate(clk->parent, request);
+		if ((src_rate < (request - delta)) ||
+			(src_rate > (request + delta)))
+			continue;
+
+		return (src_rate * frac_num[i]) / frac_den[i];
+	}
+
+	return -EINVAL;
+}
+
+
+static int set_rate_pixel(struct clk *clk, unsigned long rate)
+{
+	struct rcg_clk *rcg = to_rcg_clk(clk);
+	struct clk_freq_tbl *pixel_freq = rcg->current_freq;
+	int frac_num[] = {3, 2, 4, 1};
+	int frac_den[] = {8, 9, 9, 1};
+	int delta = 100000;
+	int i, rc;
+
+	for (i = 0; i < ARRAY_SIZE(frac_num); i++) {
+		unsigned long request = (rate * frac_den[i]) / frac_num[i];
+		unsigned long src_rate;
+
+		src_rate = clk_round_rate(clk->parent, request);
+		if ((src_rate < (request - delta)) ||
+			(src_rate > (request + delta)))
+			continue;
+
+		rc =  clk_set_rate(clk->parent, src_rate);
+		if (rc)
+			return rc;
+
+		pixel_freq->div_src_val &= ~BM(4, 0);
+		if (frac_den[i] == frac_num[i]) {
+			pixel_freq->m_val = 0;
+			pixel_freq->n_val = 0;
+		} else {
+			pixel_freq->m_val = frac_num[i];
+			pixel_freq->n_val = ~(frac_den[i] - frac_num[i]);
+			pixel_freq->d_val = ~frac_den[i];
+		}
+		set_rate_mnd(rcg, pixel_freq);
+		return 0;
+	}
+	return -EINVAL;
+}
+
 static struct clk_freq_tbl pixel_freq_tbl[] = {
 	{
-		.src_clk = &dsipll0_pixel_clk_src,
-		.div_src_val = BVAL(10, 8, dsipll0_pixel_mm_source_val),
+		.src_clk = &pixel_clk_src_8974.c,
+		.div_src_val = BVAL(10, 8, dsipll0_pixel_mm_source_val)
+				| BVAL(4, 0, 0),
 	},
 	F_END
 };
@@ -3248,9 +3296,9 @@
 	.current_freq = pixel_freq_tbl,
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
-		.parent = &dsipll0_pixel_clk_src,
+		.parent = &pixel_clk_src_8974.c,
 		.dbg_name = "pclk0_clk_src",
-		.ops = &clk_ops_pixel,
+		.ops = &clk_ops_pixel_clock,
 		VDD_DIG_FMAX_MAP2(LOW, 125000000, NOMINAL, 250000000),
 		CLK_INIT(pclk0_clk_src.c),
 	},
@@ -3261,9 +3309,9 @@
 	.current_freq = pixel_freq_tbl,
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
-		.parent = &dsipll0_pixel_clk_src,
+		.parent = &pixel_clk_src_8974.c,
 		.dbg_name = "pclk1_clk_src",
-		.ops = &clk_ops_pixel,
+		.ops = &clk_ops_pixel_clock,
 		VDD_DIG_FMAX_MAP2(LOW, 125000000, NOMINAL, 250000000),
 		CLK_INIT(pclk1_clk_src.c),
 	},
@@ -4212,6 +4260,7 @@
 
 static struct branch_clk venus0_vcodec0_clk = {
 	.cbcr_reg = VENUS0_VCODEC0_CBCR,
+	.bcr_reg = VENUS0_BCR,
 	.has_sibling = 0,
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
@@ -4891,6 +4940,10 @@
 	CLK_LOOKUP("byte_clk", mdss_byte1_clk.c, "fd922e00.qcom,mdss_dsi"),
 	CLK_LOOKUP("core_clk", mdss_esc0_clk.c, "fd922800.qcom,mdss_dsi"),
 	CLK_LOOKUP("core_clk", mdss_esc1_clk.c, "fd922e00.qcom,mdss_dsi"),
+	CLK_LOOKUP("iface_clk", mdss_ahb_clk.c, "fd922800.qcom,mdss_dsi"),
+	CLK_LOOKUP("iface_clk", mdss_ahb_clk.c, "fd922e00.qcom,mdss_dsi"),
+	CLK_LOOKUP("bus_clk", mdss_axi_clk.c, "fd922800.qcom,mdss_dsi"),
+	CLK_LOOKUP("bus_clk", mdss_axi_clk.c, "fd922e00.qcom,mdss_dsi"),
 	CLK_LOOKUP("pixel_clk", mdss_pclk0_clk.c, "fd922800.qcom,mdss_dsi"),
 	CLK_LOOKUP("pixel_clk", mdss_pclk1_clk.c, "fd922e00.qcom,mdss_dsi"),
 	CLK_LOOKUP("iface_clk", mdss_ahb_clk.c, "fd922100.qcom,hdmi_tx"),
@@ -5097,7 +5150,6 @@
 	CLK_LOOKUP("core_clk", camss_vfe_vfe_axi_clk.c, "fda44000.qcom,iommu"),
 	CLK_LOOKUP("alt_core_clk", camss_top_ahb_clk.c, "fda44000.qcom,iommu"),
 	CLK_LOOKUP("iface_clk", mdss_ahb_clk.c, "mdp.0"),
-	CLK_LOOKUP("iface_clk", mdss_ahb_clk.c, "mdss_dsi_clk_ctrl"),
 	CLK_LOOKUP("iface_clk", mdss_ahb_clk.c, "fd923400.qcom,mdss_edp"),
 	CLK_LOOKUP("iface_clk", mdss_ahb_clk.c, "fd928000.qcom,iommu"),
 	CLK_LOOKUP("core_clk", mdss_axi_clk.c, "fd928000.qcom,iommu"),
@@ -5167,6 +5219,7 @@
 	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_clk",   pnoc_pm_clk.c,      "pm_8x60"),
 	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"),
@@ -5248,6 +5301,14 @@
 	CLK_LOOKUP("krait1_m_clk",	krait1_m_clk, ""),
 	CLK_LOOKUP("krait2_m_clk",	krait2_m_clk, ""),
 	CLK_LOOKUP("krait3_m_clk",	krait3_m_clk, ""),
+
+	/* DSI PLL clocks */
+	CLK_LOOKUP("",		dsi_vco_clk_8974.c,                  ""),
+	CLK_LOOKUP("",		analog_postdiv_clk_8974.c,         ""),
+	CLK_LOOKUP("",		indirect_path_div2_clk_8974.c,     ""),
+	CLK_LOOKUP("",		pixel_clk_src_8974.c,              ""),
+	CLK_LOOKUP("",		byte_mux_8974.c,                   ""),
+	CLK_LOOKUP("",		byte_clk_src_8974.c,               ""),
 };
 
 static struct pll_config_regs mmpll0_regs __initdata = {
@@ -5391,12 +5452,6 @@
 		writel_relaxed(regval | BIT(26) | BIT(25),
 				GCC_REG_BASE(APCS_CLOCK_BRANCH_ENA_VOTE));
 	}
-
-	/*
-	 * TODO: Confirm that no clocks need to be voted on in this sleep vote
-	 * register.
-	 */
-	writel_relaxed(0x0, GCC_REG_BASE(APCS_CLOCK_SLEEP_ENA_VOTE));
 }
 
 static void __init msm8974_clock_post_init(void)
@@ -5536,6 +5591,10 @@
 			qup_i2c_clks[i][0]->parent =  qup_i2c_clks[i][1];
 	}
 
+	clk_ops_pixel_clock = clk_ops_pixel;
+	clk_ops_pixel_clock.set_rate = set_rate_pixel;
+	clk_ops_pixel_clock.round_rate = round_rate_pixel;
+
 	/*
 	 * MDSS needs the ahb clock and needs to init before we register the
 	 * lookup table.
diff --git a/arch/arm/mach-msm/clock-local2.c b/arch/arm/mach-msm/clock-local2.c
index e67d973..fd790e2 100644
--- a/arch/arm/mach-msm/clock-local2.c
+++ b/arch/arm/mach-msm/clock-local2.c
@@ -175,39 +175,19 @@
 
 	cf = rcg->current_freq;
 
-	/* Enable source clock dependency for the new freq. */
-	if (c->prepare_count) {
-		rc = clk_prepare(nf->src_clk);
-		if (rc)
-			return rc;
-	}
-
-	spin_lock_irqsave(&c->lock, flags);
-	if (c->count) {
-		rc = clk_enable(nf->src_clk);
-		if (rc) {
-			spin_unlock_irqrestore(&c->lock, flags);
-			clk_unprepare(nf->src_clk);
-			return rc;
-		}
-	}
+	rc = __clk_pre_reparent(c, nf->src_clk, &flags);
+	if (rc)
+		return rc;
 
 	BUG_ON(!rcg->set_rate);
 
 	/* Perform clock-specific frequency switch operations. */
 	rcg->set_rate(rcg, nf);
-
-	/* Release source requirements of the old freq. */
-	if (c->count)
-		clk_disable(cf->src_clk);
-	spin_unlock_irqrestore(&c->lock, flags);
-
-	if (c->prepare_count)
-		clk_unprepare(cf->src_clk);
-
 	rcg->current_freq = nf;
 	c->parent = nf->src_clk;
 
+	__clk_post_reparent(c, cf->src_clk, &flags);
+
 	return 0;
 }
 
@@ -559,11 +539,8 @@
 {
 	struct branch_clk *branch = to_branch_clk(c);
 
-	if (!branch->bcr_reg) {
-		WARN("clk_reset called on an unsupported clock (%s)\n",
-			c->dbg_name);
+	if (!branch->bcr_reg)
 		return -EPERM;
-	}
 	return __branch_clk_reset(BCR_REG(branch), action);
 }
 
@@ -721,7 +698,7 @@
 enum handoff pixel_rcg_handoff(struct clk *clk)
 {
 	struct rcg_clk *rcg = to_rcg_clk(clk);
-	u32 div_val, mval, nval, cfg_regval;
+	u32 div_val = 0, mval = 0, nval = 0, cfg_regval;
 	unsigned long pre_div_rate, parent_rate = clk_get_rate(clk->parent);
 
 	cfg_regval = readl_relaxed(CFG_RCGR_REG(rcg));
@@ -735,6 +712,15 @@
 
 	clk->rate = pre_div_rate;
 
+	/*
+	 * Pixel clocks have one frequency entry in their frequency table.
+	 * Update that entry.
+	 */
+	if (rcg->current_freq) {
+		rcg->current_freq->div_src_val &= ~CFG_RCGR_DIV_MASK;
+		rcg->current_freq->div_src_val |= div_val;
+	}
+
 	/* If MND is used, find the rate after the MND division */
 	if ((cfg_regval & MND_MODE_MASK) == MND_DUAL_EDGE_MODE_BVAL) {
 		mval = readl_relaxed(M_REG(rcg));
@@ -742,6 +728,11 @@
 		if (!nval)
 			return HANDOFF_DISABLED_CLK;
 		nval = (~nval) + mval;
+		if (rcg->current_freq) {
+			rcg->current_freq->n_val = ~(nval - mval);
+			rcg->current_freq->m_val = mval;
+			rcg->current_freq->d_val = ~nval;
+		}
 		clk->rate = (pre_div_rate * mval) / nval;
 	}
 
diff --git a/arch/arm/mach-msm/clock-local2.h b/arch/arm/mach-msm/clock-local2.h
index f307a2f..cee5b8c 100644
--- a/arch/arm/mach-msm/clock-local2.h
+++ b/arch/arm/mach-msm/clock-local2.h
@@ -34,9 +34,9 @@
 struct clk_freq_tbl {
 	unsigned long	freq_hz;
 	struct clk	*src_clk;
-	const u32	m_val;
-	const u32	n_val;
-	const u32	d_val;
+	u32	m_val;
+	u32	n_val;
+	u32	d_val;
 	u32	div_src_val;
 	const unsigned	sys_vdd;
 };
diff --git a/arch/arm/mach-msm/clock-mdss-8226.c b/arch/arm/mach-msm/clock-mdss-8226.c
deleted file mode 100644
index edfaf90..0000000
--- a/arch/arm/mach-msm/clock-mdss-8226.c
+++ /dev/null
@@ -1,454 +0,0 @@
-/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
-
-#include <linux/kernel.h>
-#include <linux/io.h>
-#include <linux/err.h>
-#include <linux/delay.h>
-#include <linux/string.h>
-#include <linux/iopoll.h>
-#include <linux/clk.h>
-
-#include <asm/processor.h>
-#include <mach/msm_iomap.h>
-#include <mach/clk-provider.h>
-
-#include "clock-mdss-8226.h"
-
-#define REG_R(addr)		readl_relaxed(addr)
-#define REG_W(data, addr)	writel_relaxed(data, addr)
-
-#define GDSC_PHYS		0xFD8C2304
-#define GDSC_SIZE		0x4
-
-#define DSI_PHY_PHYS		0xFD922800
-#define DSI_PHY_SIZE		0x00000800
-
-static unsigned char *mdss_dsi_base;
-static unsigned char *gdsc_base;
-static int pll_byte_clk_rate;
-static int pll_pclk_rate;
-static int pll_initialized;
-static struct clk *mdss_dsi_ahb_clk;
-static unsigned long dsi_pll_rate;
-
-void __init mdss_clk_ctrl_pre_init(struct clk *ahb_clk)
-{
-	BUG_ON(ahb_clk == NULL);
-
-	gdsc_base = ioremap(GDSC_PHYS, GDSC_SIZE);
-	if (!gdsc_base)
-		pr_err("%s: unable to remap gdsc base", __func__);
-
-	mdss_dsi_base = ioremap(DSI_PHY_PHYS, DSI_PHY_SIZE);
-	if (!mdss_dsi_base)
-		pr_err("%s: unable to remap dsi base", __func__);
-
-	mdss_dsi_ahb_clk = ahb_clk;
-}
-
-#define PLL_POLL_MAX_READS 10
-#define PLL_POLL_TIMEOUT_US 50
-
-static int mdss_gdsc_enabled(void)
-{
-	if (!gdsc_base)
-		return 0;
-
-	return !!(readl_relaxed(gdsc_base) & BIT(31));
-}
-
-static int mdss_dsi_check_pll_lock(void)
-{
-	u32 status;
-
-	/* poll for PLL ready status */
-	if (readl_poll_timeout_noirq((mdss_dsi_base + 0x02c0),
-				status,
-				((status & BIT(0)) == 1),
-				PLL_POLL_MAX_READS, PLL_POLL_TIMEOUT_US)) {
-		pr_err("%s: DSI PLL status=%x failed to Lock\n",
-				__func__, status);
-		pll_initialized = 0;
-	} else {
-		pll_initialized = 1;
-	}
-
-	return pll_initialized;
-}
-
-static long mdss_dsi_pll_byte_round_rate(struct clk *c, unsigned long rate)
-{
-	if (pll_initialized) {
-		return pll_byte_clk_rate;
-	} else {
-		pr_err("%s: DSI PLL not configured\n", __func__);
-		return -EINVAL;
-	}
-}
-
-static long mdss_dsi_pll_pixel_round_rate(struct clk *c, unsigned long rate)
-{
-	if (pll_initialized) {
-		return pll_pclk_rate;
-	} else {
-		pr_err("%s: Configure Byte clk first\n", __func__);
-		return -EINVAL;
-	}
-}
-
-static int mdss_dsi_pll_pixel_set_rate(struct clk *c, unsigned long rate)
-{
-	if (pll_initialized) {
-		pll_pclk_rate = rate;
-		pr_debug("%s: pll_pclk_rate=%d\n", __func__, pll_pclk_rate);
-		return 0;
-	} else {
-		pr_err("%s: Configure Byte clk first\n", __func__);
-		return -EINVAL;
-	}
-}
-
-static int __mdss_dsi_pll_byte_set_rate(struct clk *c, unsigned long rate)
-{
-	pr_debug("%s: rate=%ld\n", __func__, rate);
-
-	if (pll_initialized)
-		return 0;
-
-	REG_W(0x70, mdss_dsi_base + 0x0230); /* LPFC1 CFG */
-	REG_W(0x08, mdss_dsi_base + 0x022c); /* LPFR CFG */
-	REG_W(0x02, mdss_dsi_base + 0x0210); /* VREG CFG */
-	REG_W(0x00, mdss_dsi_base + 0x0204); /* postDiv1 */
-	REG_W(0x01, mdss_dsi_base + 0x0200); /* REFCLK CFG */
-	REG_W(0x03, mdss_dsi_base + 0x0224); /* postDiv2 */
-	REG_W(0x00, mdss_dsi_base + 0x0238); /* SDM CFG0 */
-	REG_W(0x0b, mdss_dsi_base + 0x023c); /* SDM CFG1 */
-	REG_W(0x00, mdss_dsi_base + 0x0240); /* SDM CFG2 */
-	REG_W(0x6c, mdss_dsi_base + 0x0244); /* SDM CFG3 */
-	REG_W(0x02, mdss_dsi_base + 0x0208); /* ChgPump */
-	REG_W(0x31, mdss_dsi_base + 0x020c); /* VCOLPF CFG */
-	REG_W(0x15, mdss_dsi_base + 0x0234); /* LPFC2 CFG */
-
-	REG_W(0x30, mdss_dsi_base + 0x0284); /* CAL CFG6 */
-	REG_W(0x00, mdss_dsi_base + 0x0288); /* CAL CFG7 */
-	REG_W(0x60, mdss_dsi_base + 0x028c); /* CAL CFG8 */
-	REG_W(0x00, mdss_dsi_base + 0x0290); /* CAL CFG9 */
-	REG_W(0xdd, mdss_dsi_base + 0x0294); /* CAL CFG10 */
-	REG_W(0x01, mdss_dsi_base + 0x0298); /* CAL CFG11 */
-
-	REG_W(0x05, mdss_dsi_base + 0x0228); /* postDiv3 */
-	REG_W(0x2b, mdss_dsi_base + 0x0278); /* Cal CFG3 */
-	REG_W(0x66, mdss_dsi_base + 0x027c); /* Cal CFG4 */
-	REG_W(0x05, mdss_dsi_base + 0x0264); /* LKDET CFG2 */
-	REG_W(0x00, mdss_dsi_base + 0x0248); /* SDM CFG4 */
-	REG_W(0x00, mdss_dsi_base + 0x0214); /* PWRGEN CFG */
-	REG_W(0x0a, mdss_dsi_base + 0x026c); /* CAL CFG0 */
-	REG_W(0x20, mdss_dsi_base + 0x029c); /* EFUSE CFG */
-
-	dsi_pll_rate = rate;
-	pll_byte_clk_rate = rate;
-
-	pr_debug("%s: PLL initialized. bcl=%d\n", __func__, pll_byte_clk_rate);
-	pll_initialized = 1;
-
-	return 0;
-}
-
-static int mdss_dsi_pll_byte_set_rate(struct clk *c, unsigned long rate)
-{
-	int ret;
-
-	clk_prepare_enable(mdss_dsi_ahb_clk);
-	ret = __mdss_dsi_pll_byte_set_rate(c, rate);
-	clk_disable_unprepare(mdss_dsi_ahb_clk);
-
-	return ret;
-}
-
-static void mdss_dsi_uniphy_pll_sw_reset(void)
-{
-	/*
-	 * Add hardware recommended delays after toggling the
-	 * software reset bit off and back on.
-	 */
-	REG_W(0x01, mdss_dsi_base + 0x0268); /* PLL TEST CFG */
-	udelay(300);
-	REG_W(0x00, mdss_dsi_base + 0x0268); /* PLL TEST CFG */
-	udelay(300);
-}
-
-static void mdss_dsi_pll_enable_casem(void)
-{
-	int i;
-
-	/*
-	 * Add hardware recommended delays between register writes for
-	 * the updates to take effect. These delays are necessary for the
-	 * PLL to successfully lock.
-	 */
-	REG_W(0x01, mdss_dsi_base + 0x0220); /* GLB CFG */
-	udelay(200);
-	REG_W(0x05, mdss_dsi_base + 0x0220); /* GLB CFG */
-	udelay(200);
-	REG_W(0x0f, mdss_dsi_base + 0x0220); /* GLB CFG */
-	udelay(1000);
-
-	for (i = 0; (i < 3) && !mdss_dsi_check_pll_lock(); i++) {
-		REG_W(0x07, mdss_dsi_base + 0x0220); /* GLB CFG */
-		udelay(1);
-
-		REG_W(0x0f, mdss_dsi_base + 0x0220); /* GLB CFG */
-		udelay(1000);
-	}
-
-	if (pll_initialized)
-		pr_debug("%s: PLL Locked after %d attempts\n", __func__, i);
-	else
-		pr_debug("%s: PLL failed to lock\n", __func__);
-}
-
-static void mdss_dsi_pll_enable_casef1(void)
-{
-	/*
-	 * Add hardware recommended delays between register writes for
-	 * the updates to take effect. These delays are necessary for the
-	 * PLL to successfully lock.
-	 */
-	REG_W(0x01, mdss_dsi_base + 0x0220); /* GLB CFG */
-	udelay(200);
-	REG_W(0x05, mdss_dsi_base + 0x0220); /* GLB CFG */
-	udelay(200);
-	REG_W(0x0f, mdss_dsi_base + 0x0220); /* GLB CFG */
-	udelay(200);
-	REG_W(0x0d, mdss_dsi_base + 0x0220); /* GLB CFG */
-	udelay(200);
-	REG_W(0x0f, mdss_dsi_base + 0x0220); /* GLB CFG */
-	udelay(1000);
-
-	if (mdss_dsi_check_pll_lock())
-		pr_debug("%s: PLL Locked\n", __func__);
-	else
-		pr_debug("%s: PLL failed to lock\n", __func__);
-}
-
-static void mdss_dsi_pll_enable_cased(void)
-{
-	/*
-	 * Add hardware recommended delays between register writes for
-	 * the updates to take effect. These delays are necessary for the
-	 * PLL to successfully lock.
-	 */
-	REG_W(0x01, mdss_dsi_base + 0x0220); /* GLB CFG */
-	udelay(1);
-	REG_W(0x05, mdss_dsi_base + 0x0220); /* GLB CFG */
-	udelay(1);
-	REG_W(0x07, mdss_dsi_base + 0x0220); /* GLB CFG */
-	udelay(1);
-	REG_W(0x05, mdss_dsi_base + 0x0220); /* GLB CFG */
-	udelay(1);
-	REG_W(0x07, mdss_dsi_base + 0x0220); /* GLB CFG */
-	udelay(1);
-	REG_W(0x0f, mdss_dsi_base + 0x0220); /* GLB CFG */
-	udelay(1);
-
-	if (mdss_dsi_check_pll_lock())
-		pr_debug("%s: PLL Locked\n", __func__);
-	else
-		pr_debug("%s: PLL failed to lock\n", __func__);
-}
-
-static void mdss_dsi_pll_enable_casec(void)
-{
-	/*
-	 * Add hardware recommended delays between register writes for
-	 * the updates to take effect. These delays are necessary for the
-	 * PLL to successfully lock.
-	 */
-	REG_W(0x01, mdss_dsi_base + 0x0220); /* GLB CFG */
-	udelay(200);
-	REG_W(0x05, mdss_dsi_base + 0x0220); /* GLB CFG */
-	udelay(200);
-	REG_W(0x0f, mdss_dsi_base + 0x0220); /* GLB CFG */
-	udelay(1000);
-
-	if (mdss_dsi_check_pll_lock())
-		pr_debug("%s: PLL Locked\n", __func__);
-	else
-		pr_debug("%s: PLL failed to lock\n", __func__);
-}
-
-static void mdss_dsi_pll_enable_casee(void)
-{
-	/*
-	 * Add hardware recommended delays between register writes for
-	 * the updates to take effect. These delays are necessary for the
-	 * PLL to successfully lock.
-	 */
-	REG_W(0x01, mdss_dsi_base + 0x0220); /* GLB CFG */
-	udelay(200);
-	REG_W(0x05, mdss_dsi_base + 0x0220); /* GLB CFG */
-	udelay(200);
-	REG_W(0x0d, mdss_dsi_base + 0x0220); /* GLB CFG */
-	REG_W(0x0f, mdss_dsi_base + 0x0220); /* GLB CFG */
-	udelay(1000);
-
-	if (mdss_dsi_check_pll_lock())
-		pr_debug("%s: PLL Locked\n", __func__);
-	else
-		pr_debug("%s: PLL failed to lock\n", __func__);
-}
-
-static int __mdss_dsi_pll_enable(struct clk *c)
-{
-	if (!pll_initialized) {
-		if (dsi_pll_rate)
-			__mdss_dsi_pll_byte_set_rate(c, dsi_pll_rate);
-		else
-			pr_err("%s: Calling clk_en before set_rate\n",
-				__func__);
-	}
-
-	/*
-	 * Try all PLL power-up sequences one-by-one until
-	 * PLL lock is detected
-	 */
-	mdss_dsi_uniphy_pll_sw_reset();
-	mdss_dsi_pll_enable_casem();
-	if (pll_initialized)
-		goto pll_locked;
-
-	mdss_dsi_uniphy_pll_sw_reset();
-	mdss_dsi_pll_enable_cased();
-	if (pll_initialized)
-		goto pll_locked;
-
-	mdss_dsi_uniphy_pll_sw_reset();
-	mdss_dsi_pll_enable_cased();
-	if (pll_initialized)
-		goto pll_locked;
-
-	mdss_dsi_uniphy_pll_sw_reset();
-	mdss_dsi_pll_enable_casef1();
-	if (pll_initialized)
-		goto pll_locked;
-
-	mdss_dsi_uniphy_pll_sw_reset();
-	mdss_dsi_pll_enable_casec();
-	if (pll_initialized)
-		goto pll_locked;
-
-	mdss_dsi_uniphy_pll_sw_reset();
-	mdss_dsi_pll_enable_casee();
-	if (pll_initialized)
-		goto pll_locked;
-
-	pr_err("%s: DSI PLL failed to Lock\n", __func__);
-	return -EINVAL;
-
-pll_locked:
-	pr_debug("%s: PLL Lock success\n", __func__);
-
-	return 0;
-}
-
-static void __mdss_dsi_pll_disable(void)
-{
-	writel_relaxed(0x00, mdss_dsi_base + 0x0220); /* GLB CFG */
-	pr_debug("%s: PLL disabled\n", __func__);
-	pll_initialized = 0;
-}
-
-static DEFINE_SPINLOCK(dsipll_lock);
-static int dsipll_refcount;
-
-static void mdss_dsi_pll_disable(struct clk *c)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&dsipll_lock, flags);
-	if (WARN(dsipll_refcount == 0, "DSI PLL clock is unbalanced"))
-		goto out;
-	if (dsipll_refcount == 1)
-		__mdss_dsi_pll_disable();
-	dsipll_refcount--;
-out:
-	spin_unlock_irqrestore(&dsipll_lock, flags);
-}
-
-static int mdss_dsi_pll_enable(struct clk *c)
-{
-	unsigned long flags;
-	int ret = 0;
-
-	spin_lock_irqsave(&dsipll_lock, flags);
-	if (dsipll_refcount == 0) {
-		ret = __mdss_dsi_pll_enable(c);
-		if (ret < 0)
-			goto out;
-	}
-	dsipll_refcount++;
-out:
-	spin_unlock_irqrestore(&dsipll_lock, flags);
-	return ret;
-}
-
-/* todo: Adjust these values appropriately */
-static enum handoff mdss_dsi_pll_byte_handoff(struct clk *c)
-{
-	if (mdss_gdsc_enabled()) {
-		clk_prepare_enable(mdss_dsi_ahb_clk);
-		if (mdss_dsi_check_pll_lock()) {
-			c->rate = 59000000;
-			dsi_pll_rate = 59000000;
-			pll_byte_clk_rate = 59000000;
-			pll_pclk_rate = 117000000;
-			dsipll_refcount++;
-			return HANDOFF_ENABLED_CLK;
-		}
-		clk_disable_unprepare(mdss_dsi_ahb_clk);
-	}
-
-	return HANDOFF_DISABLED_CLK;
-}
-
-/* todo: Adjust these values appropriately */
-static enum handoff mdss_dsi_pll_pixel_handoff(struct clk *c)
-{
-	if (mdss_gdsc_enabled()) {
-		clk_prepare_enable(mdss_dsi_ahb_clk);
-		if (mdss_dsi_check_pll_lock()) {
-			c->rate = 117000000;
-			dsipll_refcount++;
-			return HANDOFF_ENABLED_CLK;
-		}
-		clk_disable_unprepare(mdss_dsi_ahb_clk);
-	}
-
-	return HANDOFF_DISABLED_CLK;
-}
-
-struct clk_ops clk_ops_dsi_pixel_pll = {
-	.enable = mdss_dsi_pll_enable,
-	.disable = mdss_dsi_pll_disable,
-	.set_rate = mdss_dsi_pll_pixel_set_rate,
-	.round_rate = mdss_dsi_pll_pixel_round_rate,
-	.handoff = mdss_dsi_pll_pixel_handoff,
-};
-
-struct clk_ops clk_ops_dsi_byte_pll = {
-	.enable = mdss_dsi_pll_enable,
-	.disable = mdss_dsi_pll_disable,
-	.set_rate = mdss_dsi_pll_byte_set_rate,
-	.round_rate = mdss_dsi_pll_byte_round_rate,
-	.handoff = mdss_dsi_pll_byte_handoff,
-};
diff --git a/arch/arm/mach-msm/clock-mdss-8974.c b/arch/arm/mach-msm/clock-mdss-8974.c
index 17a6801..1245287 100644
--- a/arch/arm/mach-msm/clock-mdss-8974.c
+++ b/arch/arm/mach-msm/clock-mdss-8974.c
@@ -21,17 +21,21 @@
 #include <asm/processor.h>
 #include <mach/msm_iomap.h>
 #include <mach/clk-provider.h>
+#include <mach/clk.h>
+#include <mach/clock-generic.h>
 
 #include "clock-mdss-8974.h"
 
-#define REG_R(addr)		readl_relaxed(addr)
-#define REG_W(data, addr)	writel_relaxed(data, addr)
+#define REG_R(addr)			readl_relaxed(addr)
+#define REG_W(data, addr)		writel_relaxed(data, addr)
+#define DSS_REG_W(base, offset, data)	REG_W((data), (base) + (offset))
+#define DSS_REG_R(base, offset)		REG_R((base) + (offset))
 
 #define GDSC_PHYS		0xFD8C2304
 #define GDSC_SIZE		0x4
 
-#define DSI_PHY_PHYS		0xFD922800
-#define DSI_PHY_SIZE		0x00000800
+#define DSI_PHY_PHYS		0xFD922A00
+#define DSI_PHY_SIZE		0x000000D4
 
 #define HDMI_PHY_PHYS		0xFD922500
 #define HDMI_PHY_SIZE		0x0000007C
@@ -100,45 +104,60 @@
 #define HDMI_UNI_PLL_CAL_CFG11          (0x0098)
 #define HDMI_UNI_PLL_STATUS             (0x00C0)
 
-#define VCO_CLK				424000000
+#define DSI_0_PHY_PLL_UNIPHY_PLL_REFCLK_CFG		(0x00000000)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_POSTDIV1_CFG		(0x00000004)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_CHGPUMP_CFG		(0x00000008)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_VCOLPF_CFG		(0x0000000C)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_VREG_CFG		(0x00000010)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_PWRGEN_CFG		(0x00000014)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_DMUX_CFG		(0x00000018)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_AMUX_CFG		(0x0000001C)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG		(0x00000020)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_POSTDIV2_CFG		(0x00000024)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_POSTDIV3_CFG		(0x00000028)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_LPFR_CFG		(0x0000002C)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_LPFC1_CFG		(0x00000030)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_LPFC2_CFG		(0x00000034)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_SDM_CFG0		(0x00000038)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_SDM_CFG1		(0x0000003C)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_SDM_CFG2		(0x00000040)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_SDM_CFG3		(0x00000044)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_SDM_CFG4		(0x00000048)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_SSC_CFG0		(0x0000004C)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_SSC_CFG1		(0x00000050)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_SSC_CFG2		(0x00000054)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_SSC_CFG3		(0x00000058)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_LKDET_CFG0		(0x0000005C)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_LKDET_CFG1		(0x00000060)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_LKDET_CFG2		(0x00000064)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_TEST_CFG		(0x00000068)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_CAL_CFG0		(0x0000006C)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_CAL_CFG1		(0x00000070)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_CAL_CFG2		(0x00000074)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_CAL_CFG3		(0x00000078)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_CAL_CFG4		(0x0000007C)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_CAL_CFG5		(0x00000080)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_CAL_CFG6		(0x00000084)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_CAL_CFG7		(0x00000088)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_CAL_CFG8		(0x0000008C)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_CAL_CFG9		(0x00000090)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_CAL_CFG10		(0x00000094)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_CAL_CFG11		(0x00000098)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_EFUSE_CFG		(0x0000009C)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_STATUS			(0x000000C0)
+
+#define PLL_POLL_MAX_READS	10
+#define PLL_POLL_TIMEOUT_US	50
+
+static long vco_cached_rate;
 static unsigned char *mdss_dsi_base;
 static unsigned char *gdsc_base;
-static int pll_byte_clk_rate;
-static int pll_pclk_rate;
-static int pll_initialized;
-static struct clk *mdss_dsi_ahb_clk;
-static unsigned long dsi_pll_rate;
+static struct clk *mdss_ahb_clk;
 
 static void __iomem *hdmi_phy_base;
 static void __iomem *hdmi_phy_pll_base;
 static unsigned hdmi_pll_on;
 
-void __init mdss_clk_ctrl_pre_init(struct clk *ahb_clk)
-{
-	BUG_ON(ahb_clk == NULL);
-
-	gdsc_base = ioremap(GDSC_PHYS, GDSC_SIZE);
-	if (!gdsc_base)
-		pr_err("%s: unable to remap gdsc base", __func__);
-
-	mdss_dsi_base = ioremap(DSI_PHY_PHYS, DSI_PHY_SIZE);
-	if (!mdss_dsi_base)
-		pr_err("%s: unable to remap dsi base", __func__);
-
-	mdss_dsi_ahb_clk = ahb_clk;
-
-	hdmi_phy_base = ioremap(HDMI_PHY_PHYS, HDMI_PHY_SIZE);
-	if (!hdmi_phy_base)
-		pr_err("%s: unable to ioremap hdmi phy base", __func__);
-
-	hdmi_phy_pll_base = ioremap(HDMI_PHY_PLL_PHYS, HDMI_PHY_PLL_SIZE);
-	if (!hdmi_phy_pll_base)
-		pr_err("%s: unable to ioremap hdmi phy pll base", __func__);
-}
-
-#define PLL_POLL_MAX_READS 10
-#define PLL_POLL_TIMEOUT_US 50
-
 static int mdss_gdsc_enabled(void)
 {
 	if (!gdsc_base)
@@ -147,297 +166,13 @@
 	return !!(readl_relaxed(gdsc_base) & BIT(31));
 }
 
-static int mdss_dsi_check_pll_lock(void)
-{
-	u32 status;
-
-	clk_prepare_enable(mdss_dsi_ahb_clk);
-	/* poll for PLL ready status */
-	if (readl_poll_timeout_noirq((mdss_dsi_base + 0x02c0),
-				status,
-				((status & BIT(0)) == 1),
-				PLL_POLL_MAX_READS, PLL_POLL_TIMEOUT_US)) {
-		pr_err("%s: DSI PLL status=%x failed to Lock\n",
-				__func__, status);
-		pll_initialized = 0;
-	} else {
-		pll_initialized = 1;
-	}
-	clk_disable_unprepare(mdss_dsi_ahb_clk);
-
-	return pll_initialized;
-}
-
-static long mdss_dsi_pll_byte_round_rate(struct clk *c, unsigned long rate)
-{
-	if (pll_initialized)
-		return pll_byte_clk_rate;
-	else {
-		pr_err("%s: DSI PLL not configured\n",
-				__func__);
-		return -EINVAL;
-	}
-}
-
-static long mdss_dsi_pll_pixel_round_rate(struct clk *c, unsigned long rate)
-{
-	if (pll_initialized)
-		return pll_pclk_rate;
-	else {
-		pr_err("%s: Configure Byte clk first\n",
-				__func__);
-		return -EINVAL;
-	}
-}
-
-static int mdss_dsi_pll_pixel_set_rate(struct clk *c, unsigned long rate)
-{
-	if (pll_initialized) {
-		pll_pclk_rate = rate;
-		pr_debug("%s: pll_pclk_rate=%d\n", __func__, pll_pclk_rate);
-		return 0;
-	} else {
-		pr_err("%s: Configure Byte clk first\n", __func__);
-		return -EINVAL;
-	}
-}
-
-static int __mdss_dsi_pll_byte_set_rate(struct clk *c, unsigned long rate)
-{
-	int pll_divcfg1, pll_divcfg2;
-	int half_bitclk_rate;
-
-	pr_debug("%s:\n", __func__);
-	if (pll_initialized)
-		return 0;
-
-	half_bitclk_rate = rate * 4;
-
-	pll_divcfg1 = (VCO_CLK / half_bitclk_rate) - 2;
-
-	/* Configuring the VCO to 424 Mhz */
-	/* Configuring the half rate Bit clk to 212 Mhz */
-
-	pll_divcfg2 = 3; /* ByteClk is 1/4 the half-bitClk rate */
-
-	/* Configure the Loop filter */
-	/* Loop filter resistance value */
-	REG_W(0x08, mdss_dsi_base + 0x022c);
-	/* Loop filter capacitance values : c1 and c2 */
-	REG_W(0x70, mdss_dsi_base + 0x0230);
-	REG_W(0x15, mdss_dsi_base + 0x0234);
-
-	REG_W(0x02, mdss_dsi_base + 0x0208); /* ChgPump */
-	REG_W(pll_divcfg1, mdss_dsi_base + 0x0204); /* postDiv1 */
-	REG_W(pll_divcfg2, mdss_dsi_base + 0x0224); /* postDiv2 */
-	REG_W(0x05, mdss_dsi_base + 0x0228); /* postDiv3 */
-
-	REG_W(0x2b, mdss_dsi_base + 0x0278); /* Cal CFG3 */
-	REG_W(0x66, mdss_dsi_base + 0x027c); /* Cal CFG4 */
-	REG_W(0x05, mdss_dsi_base + 0x0264); /* LKDET CFG2 */
-
-	REG_W(0x0a, mdss_dsi_base + 0x023c); /* SDM CFG1 */
-	REG_W(0xab, mdss_dsi_base + 0x0240); /* SDM CFG2 */
-	REG_W(0x0a, mdss_dsi_base + 0x0244); /* SDM CFG3 */
-	REG_W(0x00, mdss_dsi_base + 0x0248); /* SDM CFG4 */
-
-	REG_W(0x01, mdss_dsi_base + 0x0200); /* REFCLK CFG */
-	REG_W(0x00, mdss_dsi_base + 0x0214); /* PWRGEN CFG */
-	REG_W(0x71, mdss_dsi_base + 0x020c); /* VCOLPF CFG */
-	REG_W(0x02, mdss_dsi_base + 0x0210); /* VREG CFG */
-	REG_W(0x00, mdss_dsi_base + 0x0238); /* SDM CFG0 */
-
-	REG_W(0x5f, mdss_dsi_base + 0x028c); /* CAL CFG8 */
-	REG_W(0xa8, mdss_dsi_base + 0x0294); /* CAL CFG10 */
-	REG_W(0x01, mdss_dsi_base + 0x0298); /* CAL CFG11 */
-	REG_W(0x0a, mdss_dsi_base + 0x026c); /* CAL CFG0 */
-	REG_W(0x30, mdss_dsi_base + 0x0284); /* CAL CFG6 */
-	REG_W(0x00, mdss_dsi_base + 0x0288); /* CAL CFG7 */
-	REG_W(0x00, mdss_dsi_base + 0x0290); /* CAL CFG9 */
-	REG_W(0x20, mdss_dsi_base + 0x029c); /* EFUSE CFG */
-
-	dsi_pll_rate = rate;
-	pll_byte_clk_rate = rate;
-
-	pr_debug("%s: PLL initialized. bcl=%d\n", __func__, pll_byte_clk_rate);
-	pll_initialized = 1;
-
-	return 0;
-}
-
-static int mdss_dsi_pll_byte_set_rate(struct clk *c, unsigned long rate)
-{
-	int ret;
-
-	clk_prepare_enable(mdss_dsi_ahb_clk);
-	ret = __mdss_dsi_pll_byte_set_rate(c, rate);
-	clk_disable_unprepare(mdss_dsi_ahb_clk);
-
-	return ret;
-}
-
-static void mdss_dsi_uniphy_pll_lock_detect_setting(void)
-{
-	REG_W(0x04, mdss_dsi_base + 0x0264); /* LKDetect CFG2 */
-	udelay(100);
-	REG_W(0x05, mdss_dsi_base + 0x0264); /* LKDetect CFG2 */
-	udelay(500);
-}
-
-static void mdss_dsi_uniphy_pll_sw_reset(void)
-{
-	REG_W(0x01, mdss_dsi_base + 0x0268); /* PLL TEST CFG */
-	udelay(1);
-	REG_W(0x00, mdss_dsi_base + 0x0268); /* PLL TEST CFG */
-	udelay(1);
-}
-
-static int __mdss_dsi_pll_enable(struct clk *c)
-{
-	u32 status;
-	u32 max_reads, timeout_us;
-	int i;
-
-	if (!pll_initialized) {
-		if (dsi_pll_rate)
-			__mdss_dsi_pll_byte_set_rate(c, dsi_pll_rate);
-		else
-			pr_err("%s: Calling clk_en before set_rate\n",
-						__func__);
-	}
-
-	mdss_dsi_uniphy_pll_sw_reset();
-	/* PLL power up */
-	/* Add HW recommended delay between
-	   register writes for the update to propagate */
-	REG_W(0x01, mdss_dsi_base + 0x0220); /* GLB CFG */
-	udelay(1000);
-	REG_W(0x05, mdss_dsi_base + 0x0220); /* GLB CFG */
-	udelay(1000);
-	REG_W(0x07, mdss_dsi_base + 0x0220); /* GLB CFG */
-	udelay(1000);
-	REG_W(0x0f, mdss_dsi_base + 0x0220); /* GLB CFG */
-	udelay(1000);
-
-	for (i = 0; i < 3; i++) {
-		mdss_dsi_uniphy_pll_lock_detect_setting();
-		/* poll for PLL ready status */
-		max_reads = 5;
-		timeout_us = 100;
-		if (readl_poll_timeout_noirq((mdss_dsi_base + 0x02c0),
-				   status,
-				   ((status & 0x01) == 1),
-					     max_reads, timeout_us)) {
-			pr_debug("%s: DSI PLL status=%x failed to Lock\n",
-			       __func__, status);
-			pr_debug("%s:Trying to power UP PLL again\n",
-			       __func__);
-		} else
-			break;
-
-		mdss_dsi_uniphy_pll_sw_reset();
-		udelay(1000);
-		/* Add HW recommended delay between
-		   register writes for the update to propagate */
-		REG_W(0x01, mdss_dsi_base + 0x0220); /* GLB CFG */
-		udelay(1000);
-		REG_W(0x05, mdss_dsi_base + 0x0220); /* GLB CFG */
-		udelay(1000);
-		REG_W(0x07, mdss_dsi_base + 0x0220); /* GLB CFG */
-		udelay(1000);
-		REG_W(0x05, mdss_dsi_base + 0x0220); /* GLB CFG */
-		udelay(1000);
-		REG_W(0x07, mdss_dsi_base + 0x0220); /* GLB CFG */
-		udelay(1000);
-		REG_W(0x0f, mdss_dsi_base + 0x0220); /* GLB CFG */
-		udelay(2000);
-
-	}
-
-	if ((status & 0x01) != 1) {
-		pr_err("%s: DSI PLL status=%x failed to Lock\n",
-		       __func__, status);
-		return -EINVAL;
-	}
-
-	pr_debug("%s: **** PLL Lock success\n", __func__);
-
-	return 0;
-}
-
-static void __mdss_dsi_pll_disable(void)
-{
-	writel_relaxed(0x00, mdss_dsi_base + 0x0220); /* GLB CFG */
-	pr_debug("%s: **** disable pll Initialize\n", __func__);
-	pll_initialized = 0;
-}
-
-static DEFINE_SPINLOCK(dsipll_lock);
-static int dsipll_refcount;
-
-static void mdss_dsi_pll_disable(struct clk *c)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&dsipll_lock, flags);
-	if (WARN(dsipll_refcount == 0, "DSI PLL clock is unbalanced"))
-		goto out;
-	if (dsipll_refcount == 1)
-		__mdss_dsi_pll_disable();
-	dsipll_refcount--;
-out:
-	spin_unlock_irqrestore(&dsipll_lock, flags);
-}
-
-static int mdss_dsi_pll_enable(struct clk *c)
-{
-	unsigned long flags;
-	int ret = 0;
-
-	spin_lock_irqsave(&dsipll_lock, flags);
-	if (dsipll_refcount == 0) {
-		ret = __mdss_dsi_pll_enable(c);
-		if (ret < 0)
-			goto out;
-	}
-	dsipll_refcount++;
-out:
-	spin_unlock_irqrestore(&dsipll_lock, flags);
-	return ret;
-}
-
-static enum handoff mdss_dsi_pll_byte_handoff(struct clk *c)
-{
-	if (mdss_gdsc_enabled() && mdss_dsi_check_pll_lock()) {
-		c->rate = 52954560;
-		dsi_pll_rate = 52954560;
-		pll_byte_clk_rate = 52954560;
-		pll_pclk_rate = 105000000;
-		dsipll_refcount++;
-		return HANDOFF_ENABLED_CLK;
-	}
-
-	return HANDOFF_DISABLED_CLK;
-}
-
-static enum handoff mdss_dsi_pll_pixel_handoff(struct clk *c)
-{
-	if (mdss_gdsc_enabled() && mdss_dsi_check_pll_lock()) {
-		c->rate = 105000000;
-		dsipll_refcount++;
-		return HANDOFF_ENABLED_CLK;
-	}
-
-	return HANDOFF_DISABLED_CLK;
-}
-
 void hdmi_pll_disable(void)
 {
-	clk_enable(mdss_dsi_ahb_clk);
+	clk_enable(mdss_ahb_clk);
 	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_dsi_ahb_clk);
+	clk_disable(mdss_ahb_clk);
 
 	hdmi_pll_on = 0;
 } /* hdmi_pll_disable */
@@ -447,7 +182,7 @@
 	u32 status;
 	u32 max_reads, timeout_us;
 
-	clk_enable(mdss_dsi_ahb_clk);
+	clk_enable(mdss_ahb_clk);
 	/* Global Enable */
 	REG_W(0x81, hdmi_phy_base + HDMI_PHY_GLB_CFG);
 	/* Power up power gen */
@@ -473,7 +208,7 @@
 		pr_err("%s: hdmi phy pll status=%x failed to Lock\n",
 		       __func__, status);
 		hdmi_pll_disable();
-		clk_disable(mdss_dsi_ahb_clk);
+		clk_disable(mdss_ahb_clk);
 		return -EINVAL;
 	}
 	pr_debug("%s: hdmi phy pll is locked\n", __func__);
@@ -487,11 +222,11 @@
 		pr_err("%s: hdmi phy status=%x failed to Lock\n",
 		       __func__, status);
 		hdmi_pll_disable();
-		clk_disable(mdss_dsi_ahb_clk);
+		clk_disable(mdss_ahb_clk);
 		return -EINVAL;
 	}
 	pr_debug("%s: hdmi phy is locked\n", __func__);
-	clk_disable(mdss_dsi_ahb_clk);
+	clk_disable(mdss_ahb_clk);
 
 	hdmi_pll_on = 1;
 
@@ -507,7 +242,7 @@
 		set_power_dwn = 1;
 	}
 
-	clk_enable(mdss_dsi_ahb_clk);
+	clk_enable(mdss_ahb_clk);
 	pr_debug("%s: rate=%ld\n", __func__, rate);
 	switch (rate) {
 	case 0:
@@ -922,7 +657,7 @@
 	/* Make sure writes complete before disabling iface clock */
 	mb();
 
-	clk_disable(mdss_dsi_ahb_clk);
+	clk_disable(mdss_ahb_clk);
 
 	if (set_power_dwn)
 		hdmi_pll_enable();
@@ -930,18 +665,977 @@
 	return 0;
 } /* hdmi_pll_set_rate */
 
-struct clk_ops clk_ops_dsi_pixel_pll = {
-	.enable = mdss_dsi_pll_enable,
-	.disable = mdss_dsi_pll_disable,
-	.set_rate = mdss_dsi_pll_pixel_set_rate,
-	.round_rate = mdss_dsi_pll_pixel_round_rate,
-	.handoff = mdss_dsi_pll_pixel_handoff,
+/* 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__,
+		sel ? "indirect" : "direct");
+	DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_VREG_CFG,
+			(sel << 1));
+	return 0;
+}
+
+int get_byte_mux_sel(struct mux_clk *clk)
+{
+	int mux_mode;
+
+	if (mdss_ahb_clk_enable(1)) {
+		pr_debug("%s: Failed to enable mdss ahb clock\n", __func__);
+		return 0;
+	}
+
+	mux_mode = DSS_REG_R(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_VREG_CFG)
+				& BIT(1);
+	pr_debug("%s: byte mux mode = %s", __func__,
+		mux_mode ? "indirect" : "direct");
+
+	mdss_ahb_clk_enable(0);
+	return !!mux_mode;
+}
+
+static inline struct dsi_pll_vco_clk *to_vco_clk(struct clk *clk)
+{
+	return container_of(clk, struct dsi_pll_vco_clk, c);
+}
+
+/*
+ * When the display is turned off, the display registers are wiped out.
+ * Temporarily use the prepare ops to restore the register values.
+ *
+*/
+int div_prepare(struct clk *c)
+{
+	struct div_clk *div = to_div_clk(c);
+	/* Restore the divider's value */
+	return div->ops->set_div(div, div->div);
+}
+
+int mux_prepare(struct clk *c)
+{
+	struct mux_clk *mux = to_mux_clk(c);
+	int i, rc, sel = 0;
+
+	rc = mdss_ahb_clk_enable(1);
+	if (rc) {
+		pr_err("%s: failed to enable mdss ahb clock. rc=%d\n",
+			__func__, rc);
+		return rc;
+	}
+
+	for (i = 0; i < mux->num_parents; i++)
+		if (mux->parents[i].src == c->parent) {
+			sel = mux->parents[i].sel;
+			break;
+		}
+
+	if (i == mux->num_parents) {
+		rc = -EINVAL;
+		goto error;
+	}
+
+	/* Restore the mux source select value */
+	rc = mux->ops->set_mux_sel(mux, sel);
+
+error:
+	mdss_ahb_clk_enable(0);
+	return rc;
+}
+
+static int fixed_4div_set_div(struct div_clk *clk, int div)
+{
+	int rc = 0;
+
+	rc = mdss_ahb_clk_enable(1);
+	if (rc) {
+		pr_err("%s: failed to enable mdss ahb clock. rc=%d\n",
+			__func__, rc);
+		return rc;
+	}
+
+	DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_POSTDIV2_CFG,
+			(div - 1));
+
+	mdss_ahb_clk_enable(0);
+	return 0;
+}
+
+static int fixed_4div_get_div(struct div_clk *clk)
+{
+	int div = 0;
+
+	if (mdss_ahb_clk_enable(1)) {
+		pr_debug("%s: Failed to enable mdss ahb clock\n", __func__);
+		return 1;
+	}
+	div = DSS_REG_R(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_POSTDIV2_CFG);
+	mdss_ahb_clk_enable(0);
+	return div + 1;
+}
+
+static int digital_set_div(struct div_clk *clk, int div)
+{
+	int rc = 0;
+
+	rc = mdss_ahb_clk_enable(1);
+	if (rc) {
+		pr_err("%s: failed to enable mdss ahb clock. rc=%d\n",
+			__func__, rc);
+		return rc;
+	}
+
+	DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_POSTDIV3_CFG,
+			(div - 1));
+
+	mdss_ahb_clk_enable(0);
+	return 0;
+}
+
+static int digital_get_div(struct div_clk *clk)
+{
+	int div = 0;
+
+	if (mdss_ahb_clk_enable(1)) {
+		pr_debug("%s: Failed to enable mdss ahb clock\n", __func__);
+		return 1;
+	}
+	div = DSS_REG_R(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_POSTDIV3_CFG);
+	mdss_ahb_clk_enable(0);
+	return div + 1;
+}
+
+static int analog_set_div(struct div_clk *clk, int div)
+{
+	int rc = 0;
+
+	rc = mdss_ahb_clk_enable(1);
+	if (rc) {
+		pr_err("%s: failed to enable mdss ahb clock. rc=%d\n",
+			__func__, rc);
+		return rc;
+	}
+
+	DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_POSTDIV1_CFG,
+			div - 1);
+
+	mdss_ahb_clk_enable(0);
+	return 0;
+}
+
+static int analog_get_div(struct div_clk *clk)
+{
+	int div = 0;
+
+	if (mdss_ahb_clk_enable(1)) {
+		pr_debug("%s: Failed to enable mdss ahb clock\n", __func__);
+		return 1;
+	}
+	div = DSS_REG_R(mdss_dsi_base,
+		DSI_0_PHY_PLL_UNIPHY_PLL_POSTDIV1_CFG) + 1;
+	mdss_ahb_clk_enable(0);
+	return div;
+}
+
+static int dsi_pll_lock_status(void)
+{
+	u32 status;
+	int pll_locked = 0;
+
+	/* poll for PLL ready status */
+	if (readl_poll_timeout_noirq((mdss_dsi_base +
+			DSI_0_PHY_PLL_UNIPHY_PLL_STATUS),
+			status,
+			((status & BIT(0)) == 1),
+			PLL_POLL_MAX_READS, PLL_POLL_TIMEOUT_US)) {
+		pr_debug("%s: DSI PLL status=%x failed to Lock\n",
+				__func__, status);
+		pll_locked = 0;
+	} else {
+		pll_locked = 1;
+	}
+
+	return pll_locked;
+}
+
+static void dsi_pll_software_reset(void)
+{
+	/*
+	 * Add HW recommended delays after toggling the software
+	 * reset bit off and back on.
+	 */
+	DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_TEST_CFG, 0x01);
+	udelay(1000);
+	DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_TEST_CFG, 0x00);
+	udelay(1000);
+}
+
+static int dsi_pll_enable_seq_m(void)
+{
+	int i = 0;
+	int pll_locked = 0;
+
+	dsi_pll_software_reset();
+
+	/*
+	 * Add hardware recommended delays between register writes for
+	 * 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_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);
+
+	do {
+		pll_locked = dsi_pll_lock_status();
+		if (!pll_locked) {
+			DSS_REG_W(mdss_dsi_base,
+				DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x07);
+			udelay(1);
+			DSS_REG_W(mdss_dsi_base,
+				DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x0f);
+			udelay(1000);
+			i++;
+		}
+	} while ((i < 3) && !pll_locked);
+
+	if (pll_locked)
+		pr_debug("%s: PLL Locked at attempt #%d\n", __func__, i);
+	else
+		pr_debug("%s: PLL failed to lock after %d attempt(s)\n",
+			__func__, i);
+
+	return pll_locked ? 0 : -EINVAL;
+}
+
+static int dsi_pll_enable_seq_d(void)
+{
+	int pll_locked = 0;
+
+	dsi_pll_software_reset();
+
+	/*
+	 * Add hardware recommended delays between register writes for
+	 * 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_GLB_CFG, 0x01);
+	udelay(1);
+	DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x05);
+	udelay(1);
+	DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x07);
+	udelay(1);
+	DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x05);
+	udelay(1);
+	DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x07);
+	udelay(1);
+	DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x0f);
+	udelay(1);
+
+	pll_locked = dsi_pll_lock_status();
+	pr_debug("%s: PLL status = %s\n", __func__,
+		pll_locked ? "Locked" : "Unlocked");
+
+	return pll_locked ? 0 : -EINVAL;
+}
+
+static int dsi_pll_enable_seq_f1(void)
+{
+	int pll_locked = 0;
+
+	dsi_pll_software_reset();
+
+	/*
+	 * Add hardware recommended delays between register writes for
+	 * 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_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(200);
+	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);
+
+	pll_locked = dsi_pll_lock_status();
+	pr_debug("%s: PLL status = %s\n", __func__,
+		pll_locked ? "Locked" : "Unlocked");
+
+	return pll_locked ? 0 : -EINVAL;
+}
+
+static int dsi_pll_enable_seq_c(void)
+{
+	int pll_locked = 0;
+
+	dsi_pll_software_reset();
+
+	/*
+	 * Add hardware recommended delays between register writes for
+	 * 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_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);
+
+	pll_locked = dsi_pll_lock_status();
+	pr_debug("%s: PLL status = %s\n", __func__,
+		pll_locked ? "Locked" : "Unlocked");
+
+	return pll_locked ? 0 : -EINVAL;
+}
+
+static int dsi_pll_enable_seq_e(void)
+{
+	int pll_locked = 0;
+
+	dsi_pll_software_reset();
+
+	/*
+	 * Add hardware recommended delays between register writes for
+	 * 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_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, 0x0d);
+	DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x0f);
+	udelay(1000);
+
+	pll_locked = dsi_pll_lock_status();
+	pr_debug("%s: PLL status = %s\n", __func__,
+		pll_locked ? "Locked" : "Unlocked");
+
+	return pll_locked ? 0 : -EINVAL;
+}
+
+static int dsi_pll_enable_seq_8974(void)
+{
+	int i, rc = 0;
+	u32 status, max_reads, timeout_us;
+
+	dsi_pll_software_reset();
+
+	/*
+	 * PLL power up sequence.
+	 * Add necessary delays recommeded by hardware.
+	 */
+	DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x01);
+	udelay(1000);
+	DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x05);
+	udelay(1000);
+	DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x07);
+	udelay(1000);
+	DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x0f);
+	udelay(1000);
+
+	for (i = 0; i < 3; i++) {
+		/* DSI Uniphy lock detect setting */
+		DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_LKDET_CFG2,
+			0x04);
+		udelay(100);
+		DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_LKDET_CFG2,
+			0x05);
+		udelay(500);
+		/* poll for PLL ready status */
+		max_reads = 5;
+		timeout_us = 100;
+		if (readl_poll_timeout_noirq((mdss_dsi_base +
+				DSI_0_PHY_PLL_UNIPHY_PLL_STATUS),
+				status,
+				((status & 0x01) == 1),
+				max_reads, timeout_us)) {
+			pr_debug("%s: DSI PLL status=%x failed to Lock\n",
+			       __func__, status);
+			pr_debug("%s:Trying to power UP PLL again\n",
+			       __func__);
+		} else {
+			break;
+		}
+
+		dsi_pll_software_reset();
+		/*
+		 * PLL power up sequence.
+		 * Add necessary delays recommeded by hardware.
+		 */
+		DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x1);
+		udelay(1000);
+		DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x5);
+		udelay(1000);
+		DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x7);
+		udelay(1000);
+		DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x5);
+		udelay(1000);
+		DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x7);
+		udelay(1000);
+		DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0xf);
+		udelay(2000);
+
+	}
+
+	if ((status & 0x01) != 1) {
+		pr_debug("%s: DSI PLL status=%x failed to Lock\n",
+		       __func__, status);
+		rc = -EINVAL;
+		goto error;
+	}
+
+	pr_debug("%s: DSI PLL Lock success\n", __func__);
+
+error:
+	return rc;
+}
+
+static int vco_enable(struct clk *c)
+{
+	int i, rc = 0;
+	struct dsi_pll_vco_clk *vco = to_vco_clk(c);
+
+	rc = clk_enable(mdss_ahb_clk);
+	if (rc) {
+		pr_err("%s: failed to enable mdss ahb clock. rc=%d\n",
+			__func__, rc);
+		return rc;
+	}
+
+	/* Try all enable sequences until one succeeds */
+	for (i = 0; i < vco->pll_en_seq_cnt; i++) {
+		rc = vco->pll_enable_seqs[i]();
+		pr_debug("%s: DSI PLL %s after sequence #%d\n", __func__,
+			rc ? "unlocked" : "locked", i + 1);
+		if (!rc)
+			break;
+	}
+	clk_disable(mdss_ahb_clk);
+
+	if (rc)
+		pr_err("%s: DSI PLL failed to lock\n", __func__);
+
+	return rc;
+}
+
+static void vco_disable(struct clk *c)
+{
+	int rc = 0;
+
+	rc = clk_enable(mdss_ahb_clk);
+	if (rc) {
+		pr_err("%s: failed to enable mdss ahb clock. rc=%d\n",
+			__func__, rc);
+		return;
+	}
+
+	DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x00);
+
+	clk_disable(mdss_ahb_clk);
+	pr_debug("%s: DSI PLL Disabled\n", __func__);
+	return;
+}
+
+static int vco_set_rate(struct clk *c, unsigned long rate)
+{
+	s64 vco_clk_rate = rate;
+	s32 rem;
+	s64 refclk_cfg, frac_n_mode, ref_doubler_en_b;
+	s64 ref_clk_to_pll, div_fbx1000, frac_n_value;
+	s64 sdm_cfg0, sdm_cfg1, sdm_cfg2, sdm_cfg3;
+	s64 gen_vco_clk, cal_cfg10, cal_cfg11;
+	u32 res;
+	int i, rc = 0;
+	struct dsi_pll_vco_clk *vco = to_vco_clk(c);
+
+	rc = mdss_ahb_clk_enable(1);
+	if (rc) {
+		pr_err("%s: failed to enable mdss ahb clock. rc=%d\n",
+			__func__, rc);
+		return rc;
+	}
+
+	/* Configure the Loop filter resistance */
+	for (i = 0; i < vco->lpfr_lut_size; i++)
+		if (vco_clk_rate <= vco->lpfr_lut[i].vco_rate)
+			break;
+	if (i == vco->lpfr_lut_size) {
+		pr_err("%s: unable to get loop filter resistance. vco=%ld\n",
+			__func__, rate);
+		rc = -EINVAL;
+		goto error;
+	}
+	res = vco->lpfr_lut[i].r;
+	DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_LPFR_CFG, res);
+
+	/* Loop filter capacitance values : c1 and c2 */
+	DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_LPFC1_CFG, 0x70);
+	DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_LPFC2_CFG, 0x15);
+
+	div_s64_rem(vco_clk_rate, vco->ref_clk_rate, &rem);
+	if (rem) {
+		refclk_cfg = 0x1;
+		frac_n_mode = 1;
+		ref_doubler_en_b = 0;
+	} else {
+		refclk_cfg = 0x0;
+		frac_n_mode = 0;
+		ref_doubler_en_b = 1;
+	}
+
+	pr_debug("%s:refclk_cfg = %lld\n", __func__, refclk_cfg);
+
+	ref_clk_to_pll = ((vco->ref_clk_rate * 2 * (refclk_cfg))
+			  + (ref_doubler_en_b * vco->ref_clk_rate));
+	div_fbx1000 = div_s64((vco_clk_rate * 1000), ref_clk_to_pll);
+
+	div_s64_rem(div_fbx1000, 1000, &rem);
+	frac_n_value = div_s64((rem * (1 << 16)), 1000);
+	gen_vco_clk = div_s64(div_fbx1000 * ref_clk_to_pll, 1000);
+
+	pr_debug("%s:ref_clk_to_pll = %lld\n", __func__, ref_clk_to_pll);
+	pr_debug("%s:div_fb = %lld\n", __func__, div_fbx1000);
+	pr_debug("%s:frac_n_value = %lld\n", __func__, frac_n_value);
+
+	pr_debug("%s:Generated VCO Clock: %lld\n", __func__, gen_vco_clk);
+	rem = 0;
+	if (frac_n_mode) {
+		sdm_cfg0 = (0x0 << 5);
+		sdm_cfg0 |= (0x0 & 0x3f);
+		sdm_cfg1 = (div_s64(div_fbx1000, 1000) & 0x3f) - 1;
+		sdm_cfg3 = div_s64_rem(frac_n_value, 256, &rem);
+		sdm_cfg2 = rem;
+	} else {
+		sdm_cfg0 = (0x1 << 5);
+		sdm_cfg0 |= (div_s64(div_fbx1000, 1000) & 0x3f) - 1;
+		sdm_cfg1 = (0x0 & 0x3f);
+		sdm_cfg2 = 0;
+		sdm_cfg3 = 0;
+	}
+
+	pr_debug("%s: sdm_cfg0=%lld\n", __func__, sdm_cfg0);
+	pr_debug("%s: sdm_cfg1=%lld\n", __func__, sdm_cfg1);
+	pr_debug("%s: sdm_cfg2=%lld\n", __func__, sdm_cfg2);
+	pr_debug("%s: sdm_cfg3=%lld\n", __func__, sdm_cfg3);
+
+	cal_cfg11 = div_s64_rem(gen_vco_clk, 256 * 1000000, &rem);
+	cal_cfg10 = rem / 1000000;
+	pr_debug("%s: cal_cfg10=%lld, cal_cfg11=%lld\n", __func__,
+		cal_cfg10, cal_cfg11);
+
+	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_SDM_CFG1,
+		(u32)(sdm_cfg1 & 0xff));
+	DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_SDM_CFG2,
+		(u32)(sdm_cfg2 & 0xff));
+	DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_SDM_CFG3,
+		(u32)(sdm_cfg3 & 0xff));
+	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);
+
+	DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_REFCLK_CFG,
+		(u32)refclk_cfg);
+	DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_PWRGEN_CFG, 0x00);
+	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_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);
+	DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_CAL_CFG9, 0x00);
+	DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_CAL_CFG10,
+		(u32)(cal_cfg10 & 0xff));
+	DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_CAL_CFG11,
+		(u32)(cal_cfg11 & 0xff));
+	DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_EFUSE_CFG, 0x20);
+
+error:
+	mdss_ahb_clk_enable(0);
+	return rc;
+}
+
+/* rate is the bit clk rate */
+static long vco_round_rate(struct clk *c, unsigned long rate)
+{
+	unsigned long rrate = rate;
+	struct dsi_pll_vco_clk *vco = to_vco_clk(c);
+
+	if (rate < vco->min_rate)
+		rrate = vco->min_rate;
+	if (rate > vco->max_rate)
+		rrate = vco->max_rate;
+
+	return rrate;
+}
+
+static unsigned long vco_get_rate(struct clk *c)
+{
+	u32 sdm0, doubler, sdm_byp_div;
+	u64 vco_rate;
+	u32 sdm_dc_off, sdm_freq_seed, sdm2, sdm3;
+	struct dsi_pll_vco_clk *vco = to_vco_clk(c);
+	u64 ref_clk = vco->ref_clk_rate;
+
+	/* Check to see if the ref clk doubler is enabled */
+	doubler = DSS_REG_R(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_REFCLK_CFG)
+		& BIT(0);
+	ref_clk += (doubler * vco->ref_clk_rate);
+
+	/* see if it is integer mode or sdm mode */
+	sdm0 = DSS_REG_R(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_SDM_CFG0);
+	if (sdm0 & BIT(6)) {
+		/* integer mode */
+		sdm_byp_div = (DSS_REG_R(mdss_dsi_base,
+			DSI_0_PHY_PLL_UNIPHY_PLL_SDM_CFG0) & 0x3f) + 1;
+		vco_rate = ref_clk * sdm_byp_div;
+	} else {
+		/* sdm mode */
+		sdm_dc_off = DSS_REG_R(mdss_dsi_base,
+			DSI_0_PHY_PLL_UNIPHY_PLL_SDM_CFG1) & 0xFF;
+		pr_debug("%s: sdm_dc_off = %d\n", __func__, sdm_dc_off);
+		sdm2 = DSS_REG_R(mdss_dsi_base,
+			DSI_0_PHY_PLL_UNIPHY_PLL_SDM_CFG2) & 0xFF;
+		sdm3 = DSS_REG_R(mdss_dsi_base,
+			DSI_0_PHY_PLL_UNIPHY_PLL_SDM_CFG3) & 0xFF;
+		sdm_freq_seed = (sdm3 << 8) | sdm2;
+		pr_debug("%s: sdm_freq_seed = %d\n", __func__, sdm_freq_seed);
+
+		vco_rate = (ref_clk * (sdm_dc_off + 1)) +
+			mult_frac(ref_clk, sdm_freq_seed, BIT(16));
+		pr_debug("%s: vco rate = %lld", __func__, vco_rate);
+	}
+
+	pr_debug("%s: returning vco rate = %lu\n", __func__,
+		(unsigned long)vco_rate);
+	return (unsigned long)vco_rate;
+}
+
+static enum handoff vco_handoff(struct clk *c)
+{
+	int rc = 0;
+	enum handoff ret = HANDOFF_DISABLED_CLK;
+
+	rc = mdss_ahb_clk_enable(1);
+	if (rc) {
+		pr_err("%s: failed to enable mdss ahb clock. rc=%d\n",
+			__func__, rc);
+		return ret;
+	}
+	if (dsi_pll_lock_status()) {
+		c->rate = vco_get_rate(c);
+		ret = HANDOFF_ENABLED_CLK;
+	}
+
+	mdss_ahb_clk_enable(0);
+	return ret;
+}
+
+static int vco_prepare(struct clk *c)
+{
+	return vco_set_rate(c, vco_cached_rate);
+}
+
+static void vco_unprepare(struct clk *c)
+{
+	vco_cached_rate = c->rate;
+}
+
+/* Op structures */
+
+static struct clk_ops clk_ops_dsi_vco = {
+	.enable = vco_enable,
+	.disable = vco_disable,
+	.set_rate = vco_set_rate,
+	.round_rate = vco_round_rate,
+	.handoff = vco_handoff,
+	.prepare = vco_prepare,
+	.unprepare = vco_unprepare,
 };
 
-struct clk_ops clk_ops_dsi_byte_pll = {
-	.enable = mdss_dsi_pll_enable,
-	.disable = mdss_dsi_pll_disable,
-	.set_rate = mdss_dsi_pll_byte_set_rate,
-	.round_rate = mdss_dsi_pll_byte_round_rate,
-	.handoff = mdss_dsi_pll_byte_handoff,
+static struct clk_div_ops fixed_2div_ops;
+
+static struct clk_div_ops fixed_4div_ops = {
+	.set_div = fixed_4div_set_div,
+	.get_div = fixed_4div_get_div,
 };
+
+static struct clk_div_ops analog_postdiv_ops = {
+	.set_div = analog_set_div,
+	.get_div = analog_get_div,
+};
+
+static struct clk_div_ops digital_postdiv_ops = {
+	.set_div = digital_set_div,
+	.get_div = digital_get_div,
+};
+
+struct clk_mux_ops byte_mux_ops = {
+	.set_mux_sel = set_byte_mux_sel,
+	.get_mux_sel = get_byte_mux_sel,
+};
+
+struct clk_ops byte_mux_clk_ops;
+
+static struct clk_ops pixel_clk_src_ops;
+static struct clk_ops byte_clk_src_ops;
+static struct clk_ops analog_potsdiv_clk_ops;
+
+/* Display clocks */
+
+struct dsi_pll_vco_clk dsi_vco_clk_8226 = {
+	.ref_clk_rate = 19200000,
+	.min_rate = 350000000,
+	.max_rate = 750000000,
+	.pll_en_seq_cnt = 6,
+	.pll_enable_seqs[0] = dsi_pll_enable_seq_m,
+	.pll_enable_seqs[1] = dsi_pll_enable_seq_d,
+	.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,
+	.lpfr_lut_size = 10,
+	.lpfr_lut = (struct lpfr_cfg[]){
+		{479500000, 8},
+		{480000000, 11},
+		{575500000, 8},
+		{576000000, 12},
+		{610500000, 8},
+		{659500000, 9},
+		{671500000, 10},
+		{672000000, 14},
+		{708500000, 10},
+		{750000000, 11},
+	},
+	.c = {
+		.dbg_name = "dsi_vco_clk",
+		.ops = &clk_ops_dsi_vco,
+		CLK_INIT(dsi_vco_clk_8226.c),
+	},
+};
+
+struct div_clk analog_postdiv_clk_8226 = {
+	.max_div = 255,
+	.min_div = 1,
+	.ops = &analog_postdiv_ops,
+	.c = {
+		.parent = &dsi_vco_clk_8226.c,
+		.dbg_name = "analog_postdiv_clk",
+		.ops = &analog_potsdiv_clk_ops,
+		.flags = CLKFLAG_NO_RATE_CACHE,
+		CLK_INIT(analog_postdiv_clk_8226.c),
+	},
+};
+
+struct div_clk indirect_path_div2_clk_8226 = {
+	.ops = &fixed_2div_ops,
+	.div = 2,
+	.c = {
+		.parent = &analog_postdiv_clk_8226.c,
+		.dbg_name = "indirect_path_div2_clk",
+		.ops = &clk_ops_div,
+		.flags = CLKFLAG_NO_RATE_CACHE,
+		CLK_INIT(indirect_path_div2_clk_8226.c),
+	},
+};
+
+struct div_clk pixel_clk_src_8226 = {
+	.max_div = 255,
+	.min_div = 1,
+	.ops = &digital_postdiv_ops,
+	.c = {
+		.parent = &dsi_vco_clk_8226.c,
+		.dbg_name = "pixel_clk_src",
+		.ops = &pixel_clk_src_ops,
+		.flags = CLKFLAG_NO_RATE_CACHE,
+		CLK_INIT(pixel_clk_src_8226.c),
+	},
+};
+
+struct mux_clk byte_mux_8226 = {
+	.num_parents = 2,
+	.parents = (struct clk_src[]){
+		{&dsi_vco_clk_8226.c, 0},
+		{&indirect_path_div2_clk_8226.c, 1},
+	},
+	.ops = &byte_mux_ops,
+	.c = {
+		.parent = &dsi_vco_clk_8226.c,
+		.dbg_name = "byte_mux",
+		.ops = &byte_mux_clk_ops,
+		CLK_INIT(byte_mux_8226.c),
+	},
+};
+
+struct div_clk byte_clk_src_8226 = {
+	.ops = &fixed_4div_ops,
+	.min_div = 4,
+	.max_div = 4,
+	.c = {
+		.parent = &byte_mux_8226.c,
+		.dbg_name = "byte_clk_src",
+		.ops = &byte_clk_src_ops,
+		CLK_INIT(byte_clk_src_8226.c),
+	},
+};
+
+struct dsi_pll_vco_clk dsi_vco_clk_8974 = {
+	.ref_clk_rate = 19200000,
+	.min_rate = 350000000,
+	.max_rate = 750000000,
+	.pll_en_seq_cnt = 3,
+	.pll_enable_seqs[0] = dsi_pll_enable_seq_8974,
+	.pll_enable_seqs[1] = dsi_pll_enable_seq_8974,
+	.pll_enable_seqs[2] = dsi_pll_enable_seq_8974,
+	.lpfr_lut_size = 10,
+	.lpfr_lut = (struct lpfr_cfg[]){
+		{479500000, 8},
+		{480000000, 11},
+		{575500000, 8},
+		{576000000, 12},
+		{610500000, 8},
+		{659500000, 9},
+		{671500000, 10},
+		{672000000, 14},
+		{708500000, 10},
+		{750000000, 11},
+	},
+	.c = {
+		.dbg_name = "dsi_vco_clk",
+		.ops = &clk_ops_dsi_vco,
+		CLK_INIT(dsi_vco_clk_8974.c),
+	},
+};
+
+struct div_clk analog_postdiv_clk_8974 = {
+	.max_div = 255,
+	.min_div = 1,
+	.ops = &analog_postdiv_ops,
+	.c = {
+		.parent = &dsi_vco_clk_8974.c,
+		.dbg_name = "analog_postdiv_clk",
+		.ops = &analog_potsdiv_clk_ops,
+		.flags = CLKFLAG_NO_RATE_CACHE,
+		CLK_INIT(analog_postdiv_clk_8974.c),
+	},
+};
+
+struct div_clk indirect_path_div2_clk_8974 = {
+	.ops = &fixed_2div_ops,
+	.div = 2,
+	.c = {
+		.parent = &analog_postdiv_clk_8974.c,
+		.dbg_name = "indirect_path_div2_clk",
+		.ops = &clk_ops_div,
+		.flags = CLKFLAG_NO_RATE_CACHE,
+		CLK_INIT(indirect_path_div2_clk_8974.c),
+	},
+};
+
+struct div_clk pixel_clk_src_8974 = {
+	.max_div = 255,
+	.min_div = 1,
+	.ops = &digital_postdiv_ops,
+	.c = {
+		.parent = &dsi_vco_clk_8974.c,
+		.dbg_name = "pixel_clk_src",
+		.ops = &pixel_clk_src_ops,
+		.flags = CLKFLAG_NO_RATE_CACHE,
+		CLK_INIT(pixel_clk_src_8974.c),
+	},
+};
+
+struct mux_clk byte_mux_8974 = {
+	.num_parents = 2,
+	.parents = (struct clk_src[]){
+		{&dsi_vco_clk_8974.c, 0},
+		{&indirect_path_div2_clk_8974.c, 1},
+	},
+	.ops = &byte_mux_ops,
+	.c = {
+		.parent = &dsi_vco_clk_8974.c,
+		.dbg_name = "byte_mux",
+		.ops = &byte_mux_clk_ops,
+		CLK_INIT(byte_mux_8974.c),
+	},
+};
+
+struct div_clk byte_clk_src_8974 = {
+	.ops = &fixed_4div_ops,
+	.min_div = 4,
+	.max_div = 4,
+	.c = {
+		.parent = &byte_mux_8974.c,
+		.dbg_name = "byte_clk_src",
+		.ops = &byte_clk_src_ops,
+		CLK_INIT(byte_clk_src_8974.c),
+	},
+};
+
+void __init mdss_clk_ctrl_pre_init(struct clk *ahb_clk)
+{
+	BUG_ON(ahb_clk == NULL);
+
+	gdsc_base = ioremap(GDSC_PHYS, GDSC_SIZE);
+	if (!gdsc_base)
+		pr_err("%s: unable to remap gdsc base", __func__);
+
+	mdss_dsi_base = ioremap(DSI_PHY_PHYS, DSI_PHY_SIZE);
+	if (!mdss_dsi_base)
+		pr_err("%s: unable to remap dsi base", __func__);
+
+	mdss_ahb_clk = ahb_clk;
+
+	hdmi_phy_base = ioremap(HDMI_PHY_PHYS, HDMI_PHY_SIZE);
+	if (!hdmi_phy_base)
+		pr_err("%s: unable to ioremap hdmi phy base", __func__);
+
+	hdmi_phy_pll_base = ioremap(HDMI_PHY_PLL_PHYS, HDMI_PHY_PLL_SIZE);
+	if (!hdmi_phy_pll_base)
+		pr_err("%s: unable to ioremap hdmi phy pll base", __func__);
+
+	pixel_clk_src_ops = clk_ops_slave_div;
+	pixel_clk_src_ops.prepare = div_prepare;
+
+	byte_clk_src_ops = clk_ops_div;
+	byte_clk_src_ops.prepare = div_prepare;
+
+	analog_potsdiv_clk_ops = clk_ops_div;
+	analog_potsdiv_clk_ops.prepare = div_prepare;
+
+	byte_mux_clk_ops = clk_ops_gen_mux;
+	byte_mux_clk_ops.prepare = mux_prepare;
+}
+
diff --git a/arch/arm/mach-msm/clock-mdss-8974.h b/arch/arm/mach-msm/clock-mdss-8974.h
index e242669..9fd3026 100644
--- a/arch/arm/mach-msm/clock-mdss-8974.h
+++ b/arch/arm/mach-msm/clock-mdss-8974.h
@@ -13,6 +13,10 @@
 #ifndef __ARCH_ARM_MACH_MSM_CLOCK_MDSS_8974
 #define __ARCH_ARM_MACH_MSM_CLOCK_MDSS_8974
 
+#include <linux/clk.h>
+
+#define MAX_DSI_PLL_EN_SEQS	10
+
 extern struct clk_ops clk_ops_dsi_byte_pll;
 extern struct clk_ops clk_ops_dsi_pixel_pll;
 
@@ -22,4 +26,35 @@
 void hdmi_pll_disable(void);
 int hdmi_pll_set_rate(unsigned long rate);
 
+struct lpfr_cfg {
+	unsigned long vco_rate;
+	u32 r;
+};
+
+struct dsi_pll_vco_clk {
+	unsigned long ref_clk_rate;
+	unsigned long min_rate;
+	unsigned long max_rate;
+	int (*pll_enable_seqs[MAX_DSI_PLL_EN_SEQS])(void);
+	u32 pll_en_seq_cnt;
+	struct lpfr_cfg *lpfr_lut;
+	u32 lpfr_lut_size;
+
+	struct clk c;
+};
+
+extern struct dsi_pll_vco_clk dsi_vco_clk_8974;
+extern struct div_clk analog_postdiv_clk_8974;
+extern struct div_clk indirect_path_div2_clk_8974;
+extern struct div_clk pixel_clk_src_8974;
+extern struct mux_clk byte_mux_8974;
+extern struct div_clk byte_clk_src_8974;
+
+extern struct dsi_pll_vco_clk dsi_vco_clk_8226;
+extern struct div_clk analog_postdiv_clk_8226;
+extern struct div_clk indirect_path_div2_clk_8226;
+extern struct div_clk pixel_clk_src_8226;
+extern struct mux_clk byte_mux_8226;
+extern struct div_clk byte_clk_src_8226;
+
 #endif
diff --git a/arch/arm/mach-msm/clock-pll.c b/arch/arm/mach-msm/clock-pll.c
index 8d99ad1..fcdcb29 100644
--- a/arch/arm/mach-msm/clock-pll.c
+++ b/arch/arm/mach-msm/clock-pll.c
@@ -15,6 +15,7 @@
 #include <linux/kernel.h>
 #include <linux/delay.h>
 #include <linux/err.h>
+#include <linux/clk.h>
 #include <linux/remote_spinlock.h>
 
 #include <mach/scm-io.h>
@@ -262,11 +263,31 @@
 	struct pll_clk *pll = to_pll_clk(c);
 	u32 mode = readl_relaxed(PLL_MODE_REG(pll));
 	u32 mask = PLL_BYPASSNL | PLL_RESET_N | PLL_OUTCTRL;
+	unsigned long parent_rate;
+	u32 lval, mval, nval, userval;
 
-	if ((mode & mask) == mask)
+	if ((mode & mask) != mask)
+		return HANDOFF_DISABLED_CLK;
+
+	/* Assume bootloaders configure PLL to c->rate */
+	if (c->rate)
 		return HANDOFF_ENABLED_CLK;
 
-	return HANDOFF_DISABLED_CLK;
+	parent_rate = clk_get_rate(c->parent);
+	lval = readl_relaxed(PLL_L_REG(pll));
+	mval = readl_relaxed(PLL_M_REG(pll));
+	nval = readl_relaxed(PLL_N_REG(pll));
+	userval = readl_relaxed(PLL_CONFIG_REG(pll));
+
+	c->rate = parent_rate * lval;
+
+	if (pll->masks.mn_en_mask && userval) {
+		if (!nval)
+			nval = 1;
+		c->rate += (parent_rate * mval) / nval;
+	}
+
+	return HANDOFF_ENABLED_CLK;
 }
 
 static int local_pll_clk_set_rate(struct clk *c, unsigned long rate)
diff --git a/arch/arm/mach-msm/clock.c b/arch/arm/mach-msm/clock.c
index 608018c..582bccf 100644
--- a/arch/arm/mach-msm/clock.c
+++ b/arch/arm/mach-msm/clock.c
@@ -475,7 +475,7 @@
 	mutex_lock(&clk->prepare_lock);
 
 	/* Return early if the rate isn't going to change */
-	if (clk->rate == rate)
+	if (clk->rate == rate && !(clk->flags & CLKFLAG_NO_RATE_CACHE))
 		goto out;
 
 	trace_clock_set_rate(name, rate, raw_smp_processor_id());
diff --git a/arch/arm/mach-msm/clock.h b/arch/arm/mach-msm/clock.h
index 674ef77..2a65d2f 100644
--- a/arch/arm/mach-msm/clock.h
+++ b/arch/arm/mach-msm/clock.h
@@ -54,6 +54,7 @@
 extern struct clock_init_data msm8226_clock_init_data;
 extern struct clock_init_data msm8226_rumi_clock_init_data;
 extern struct clock_init_data msm8084_clock_init_data;
+extern struct clock_init_data mpq8092_clock_init_data;
 
 int msm_clock_init(struct clock_init_data *data);
 int find_vdd_level(struct clk *clk, unsigned long rate);
diff --git a/arch/arm/mach-msm/cpr-regulator.c b/arch/arm/mach-msm/cpr-regulator.c
index e51a1f5..e647d1d 100644
--- a/arch/arm/mach-msm/cpr-regulator.c
+++ b/arch/arm/mach-msm/cpr-regulator.c
@@ -114,6 +114,11 @@
 #define CPR_NUM_RING_OSC	8
 #define CPR_NUM_SAVE_REGS	10
 
+/* RBCPR Clock Control Register */
+#define RBCPR_CLK_SEL_MASK	BIT(0)
+#define RBCPR_CLK_SEL_19P2_MHZ	0
+#define RBCPR_CLK_SEL_AHB_CLK	BIT(0)
+
 /* CPR eFuse parameters */
 #define CPR_FUSE_TARGET_QUOT_BITS	12
 #define CPR_FUSE_TARGET_QUOT_BITS_MASK	((1<<CPR_FUSE_TARGET_QUOT_BITS)-1)
@@ -180,6 +185,7 @@
 
 	unsigned int	cpr_irq;
 	void __iomem	*rbcpr_base;
+	phys_addr_t	rbcpr_clk_addr;
 	struct mutex	cpr_mutex;
 
 	int		ceiling_volt[CPR_CORNER_MAX];
@@ -815,10 +821,23 @@
 #define cpr_regulator_resume NULL
 #endif
 
-static void cpr_config(struct cpr_regulator *cpr_vreg)
+static int cpr_config(struct cpr_regulator *cpr_vreg)
 {
 	int i;
-	u32 val, gcnt;
+	u32 val, gcnt, reg;
+	void __iomem *rbcpr_clk;
+
+	/* Use 19.2 MHz clock for CPR. */
+	rbcpr_clk = ioremap(cpr_vreg->rbcpr_clk_addr, 4);
+	if (!rbcpr_clk) {
+		pr_err("Unable to map rbcpr_clk\n");
+		return -EINVAL;
+	}
+	reg = readl_relaxed(rbcpr_clk);
+	reg &= ~RBCPR_CLK_SEL_MASK;
+	reg |= RBCPR_CLK_SEL_19P2_MHZ & RBCPR_CLK_SEL_MASK;
+	writel_relaxed(reg, rbcpr_clk);
+	iounmap(rbcpr_clk);
 
 	/* Disable interrupt and CPR */
 	cpr_write(cpr_vreg, REG_RBIF_IRQ_EN(cpr_vreg->irq_line), 0);
@@ -888,6 +907,8 @@
 	cpr_corner_save(cpr_vreg, CPR_CORNER_SVS);
 	cpr_corner_save(cpr_vreg, CPR_CORNER_NORMAL);
 	cpr_corner_save(cpr_vreg, CPR_CORNER_TURBO);
+
+	return 0;
 }
 
 static int __init cpr_pvs_init(struct cpr_regulator *cpr_vreg)
@@ -1199,6 +1220,13 @@
 	}
 	cpr_vreg->cpr_fuse_addr = res->start;
 
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "rbcpr_clk");
+	if (!res || !res->start) {
+		pr_err("missing rbcpr_clk address: res=%p\n", res);
+		return -EINVAL;
+	}
+	cpr_vreg->rbcpr_clk_addr = res->start;
+
 	rc = cpr_init_cpr_efuse(cpr_vreg);
 	if (rc)
 		return rc;
@@ -1227,7 +1255,9 @@
 	}
 
 	/* Configure CPR HW but keep it disabled */
-	cpr_config(cpr_vreg);
+	rc = cpr_config(cpr_vreg);
+	if (rc)
+		return rc;
 
 	rc = request_threaded_irq(cpr_vreg->cpr_irq, NULL, cpr_irq_handler,
 				  IRQF_TRIGGER_RISING, "cpr", cpr_vreg);
diff --git a/arch/arm/mach-msm/devices-9615.c b/arch/arm/mach-msm/devices-9615.c
index bf89321..483d8b3 100644
--- a/arch/arm/mach-msm/devices-9615.c
+++ b/arch/arm/mach-msm/devices-9615.c
@@ -1270,6 +1270,7 @@
 	LPASS_SCSS_GP_HIGH_IRQ,
 	SPS_MTI_31,
 	A2_BAM_IRQ,
+	USB1_HS_BAM_IRQ,
 };
 
 struct msm_mpm_device_data msm9615_mpm_dev_data __initdata = {
diff --git a/arch/arm/mach-msm/footswitch-8x60.c b/arch/arm/mach-msm/footswitch-8x60.c
index 76ad9b8..581c563 100644
--- a/arch/arm/mach-msm/footswitch-8x60.c
+++ b/arch/arm/mach-msm/footswitch-8x60.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -52,7 +52,7 @@
 
 #define GFS_DELAY_CNT		31
 
-#define RESET_DELAY_US		1
+#define DEFAULT_RESET_DELAY_US	1
 /* Clock rate to use if one has not previously been set. */
 #define DEFAULT_RATE		27000000
 #define MAX_CLKS		10
@@ -72,6 +72,7 @@
 	bool			is_claimed;
 	struct fs_clk_data	*clk_data;
 	struct clk		*core_clk;
+	unsigned long		reset_delay_us;
 };
 
 static int setup_clocks(struct footswitch *fs)
@@ -181,7 +182,7 @@
 	for (clock--; clock >= fs->clk_data; clock--)
 		clk_reset(clock->clk, CLK_RESET_ASSERT);
 	/* Wait for synchronous resets to propagate. */
-	udelay(RESET_DELAY_US);
+	udelay(fs->reset_delay_us);
 
 	/* Enable the power rail at the footswitch. */
 	regval |= ENABLE_BIT;
@@ -200,9 +201,9 @@
 	/* Toggle core reset again after first power-on (required for GFX3D). */
 	if (fs->desc.id == FS_GFX3D) {
 		clk_reset(fs->core_clk, CLK_RESET_ASSERT);
-		udelay(RESET_DELAY_US);
+		udelay(fs->reset_delay_us);
 		clk_reset(fs->core_clk, CLK_RESET_DEASSERT);
-		udelay(RESET_DELAY_US);
+		udelay(fs->reset_delay_us);
 	}
 
 	/* Prevent core memory from collapsing when its clock is gated. */
@@ -265,7 +266,7 @@
 	for (clock--; clock >= fs->clk_data; clock--)
 		clk_reset(clock->clk, CLK_RESET_ASSERT);
 	/* Wait for synchronous resets to propagate. */
-	udelay(RESET_DELAY_US);
+	udelay(fs->reset_delay_us);
 
 	/*
 	 * Return clocks to their state before this function. For robustness
@@ -339,7 +340,7 @@
 	for (clock--; clock >= fs->clk_data; clock--)
 		clk_reset(clock->clk, CLK_RESET_ASSERT);
 	/* Wait for synchronous resets to propagate. */
-	udelay(RESET_DELAY_US);
+	udelay(fs->reset_delay_us);
 
 	/* Enable the power rail at the footswitch. */
 	regval |= ENABLE_BIT;
@@ -354,7 +355,7 @@
 	/* Deassert resets for all clocks in the power domain. */
 	for (clock = fs->clk_data; clock->clk; clock++)
 		clk_reset(clock->clk, CLK_RESET_DEASSERT);
-	udelay(RESET_DELAY_US);
+	udelay(fs->reset_delay_us);
 
 	/* Re-enable core clock. */
 	clk_prepare_enable(fs->core_clk);
@@ -497,6 +498,8 @@
 	fs->clk_data = driver_data->clks;
 	fs->bus_port0 = driver_data->bus_port0;
 	fs->bus_port1 = driver_data->bus_port1;
+	fs->reset_delay_us =
+		driver_data->reset_delay_us ? : DEFAULT_RESET_DELAY_US;
 
 	for (clock = fs->clk_data; clock->name; clock++) {
 		clock->clk = clk_get(&pdev->dev, clock->name);
diff --git a/arch/arm/mach-msm/footswitch.h b/arch/arm/mach-msm/footswitch.h
index 2a49426..57e8eba 100644
--- a/arch/arm/mach-msm/footswitch.h
+++ b/arch/arm/mach-msm/footswitch.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2012 The Linux Foundation. All rights reserved.
+/* Copyright (c) 2010-2013 The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -41,6 +41,7 @@
 struct fs_driver_data {
 	int bus_port0, bus_port1;
 	struct fs_clk_data *clks;
+	unsigned long reset_delay_us;
 };
 
 #define FS_GENERIC(_drv_name, _id, _name, _dev_id, _data) \
diff --git a/arch/arm/mach-msm/gdsc.c b/arch/arm/mach-msm/gdsc.c
index 30a034e..0963e27 100644
--- a/arch/arm/mach-msm/gdsc.c
+++ b/arch/arm/mach-msm/gdsc.c
@@ -48,12 +48,17 @@
 	struct clk		**clocks;
 	int			clock_count;
 	bool			toggle_mems;
+	bool			toggle_logic;
+	bool			resets_asserted;
 };
 
 static int gdsc_is_enabled(struct regulator_dev *rdev)
 {
 	struct gdsc *sc = rdev_get_drvdata(rdev);
 
+	if (!sc->toggle_logic)
+		return !sc->resets_asserted;
+
 	return !!(readl_relaxed(sc->gdscr) & PWR_ON_MASK);
 }
 
@@ -63,15 +68,22 @@
 	uint32_t regval;
 	int i, ret;
 
-	regval = readl_relaxed(sc->gdscr);
-	regval &= ~SW_COLLAPSE_MASK;
-	writel_relaxed(regval, sc->gdscr);
+	if (sc->toggle_logic) {
+		regval = readl_relaxed(sc->gdscr);
+		regval &= ~SW_COLLAPSE_MASK;
+		writel_relaxed(regval, sc->gdscr);
 
-	ret = readl_tight_poll_timeout(sc->gdscr, regval, regval & PWR_ON_MASK,
-				       TIMEOUT_US);
-	if (ret) {
-		dev_err(&rdev->dev, "%s enable timed out\n", sc->rdesc.name);
-		return ret;
+		ret = readl_tight_poll_timeout(sc->gdscr, regval,
+					regval & PWR_ON_MASK, TIMEOUT_US);
+		if (ret) {
+			dev_err(&rdev->dev, "%s enable timed out\n",
+				sc->rdesc.name);
+			return ret;
+		}
+	} else {
+		for (i = 0; i < sc->clock_count; i++)
+			clk_reset(sc->clocks[i], CLK_RESET_DEASSERT);
+		sc->resets_asserted = false;
 	}
 
 	if (sc->toggle_mems) {
@@ -96,16 +108,24 @@
 {
 	struct gdsc *sc = rdev_get_drvdata(rdev);
 	uint32_t regval;
-	int i, ret;
+	int i, ret = 0;
 
-	regval = readl_relaxed(sc->gdscr);
-	regval |= SW_COLLAPSE_MASK;
-	writel_relaxed(regval, sc->gdscr);
+	if (sc->toggle_logic) {
+		regval = readl_relaxed(sc->gdscr);
+		regval |= SW_COLLAPSE_MASK;
+		writel_relaxed(regval, sc->gdscr);
 
-	ret = readl_tight_poll_timeout(sc->gdscr, regval,
-				       !(regval & PWR_ON_MASK), TIMEOUT_US);
-	if (ret)
-		dev_err(&rdev->dev, "%s disable timed out\n", sc->rdesc.name);
+		ret = readl_tight_poll_timeout(sc->gdscr, regval,
+					       !(regval & PWR_ON_MASK),
+						TIMEOUT_US);
+		if (ret)
+			dev_err(&rdev->dev, "%s disable timed out\n",
+				sc->rdesc.name);
+	} else {
+		for (i = 0; i < sc->clock_count; i++)
+			clk_reset(sc->clocks[i], CLK_RESET_ASSERT);
+		sc->resets_asserted = true;
+	}
 
 	if (sc->toggle_mems) {
 		for (i = 0; i < sc->clock_count; i++) {
@@ -214,6 +234,20 @@
 		}
 	}
 	sc->toggle_mems = !retain_mems;
+	sc->toggle_logic = !of_property_read_bool(pdev->dev.of_node,
+						"qcom,skip-logic-collapse");
+	if (!sc->toggle_logic) {
+		regval &= ~SW_COLLAPSE_MASK;
+		writel_relaxed(regval, sc->gdscr);
+
+		ret = readl_tight_poll_timeout(sc->gdscr, regval,
+					regval & PWR_ON_MASK, TIMEOUT_US);
+		if (ret) {
+			dev_err(&pdev->dev, "%s enable timed out\n",
+				sc->rdesc.name);
+			return ret;
+		}
+	}
 
 	sc->rdev = regulator_register(&sc->rdesc, &pdev->dev, init_data, sc,
 				      pdev->dev.of_node);
diff --git a/arch/arm/mach-msm/hotplug.c b/arch/arm/mach-msm/hotplug.c
index 0e97c27..e9a4af0 100644
--- a/arch/arm/mach-msm/hotplug.c
+++ b/arch/arm/mach-msm/hotplug.c
@@ -1,7 +1,7 @@
 /*
  *  Copyright (C) 2002 ARM Ltd.
  *  All Rights Reserved
- *  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 as
@@ -29,6 +29,9 @@
 	unsigned int warm_boot;
 };
 
+
+static cpumask_t cpu_dying_mask;
+
 static DEFINE_PER_CPU_SHARED_ALIGNED(struct msm_hotplug_device,
 			msm_hotplug_devices);
 
@@ -70,12 +73,12 @@
 
 int platform_cpu_kill(unsigned int cpu)
 {
-	int ret;
+	int ret = 0;
 
-	ret = msm_pm_wait_cpu_shutdown(cpu);
-	if (ret)
-		return 0;
-	return 1;
+	if (cpumask_test_and_clear_cpu(cpu, &cpu_dying_mask))
+		ret = msm_pm_wait_cpu_shutdown(cpu);
+
+	return ret ? 0 : 1;
 }
 
 /*
@@ -142,6 +145,7 @@
 		uncached_logk(LOGK_HOTPLUG, (void *)(cpudata | this_cpumask));
 		break;
 	case CPU_DYING:
+		cpumask_set_cpu((unsigned long)hcpu, &cpu_dying_mask);
 		uncached_logk(LOGK_HOTPLUG, (void *)(cpudata & ~this_cpumask));
 		break;
 	default:
diff --git a/arch/arm/mach-msm/include/mach/board.h b/arch/arm/mach-msm/include/mach/board.h
index d3ef0be..7b26bd6 100644
--- a/arch/arm/mach-msm/include/mach/board.h
+++ b/arch/arm/mach-msm/include/mach/board.h
@@ -510,6 +510,15 @@
 	bool mhl_enabled;
 };
 
+/**
+ * msm_i2c_platform_data: i2c-qup driver configuration data
+ *
+ * @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).
+ * @master_id master id number of the i2c core or its wrapper (BLSP/GSBI).
+ *       When zero, clock path voting is disabled.
+ */
 struct msm_i2c_platform_data {
 	int clk_freq;
 	uint32_t rmutex;
@@ -523,6 +532,8 @@
 	int use_gsbi_shared_mode;
 	int keep_ahb_clk_on;
 	void (*msm_i2c_config_gpio)(int iface, int config_type);
+	bool active_only;
+	uint32_t master_id;
 };
 
 struct msm_i2c_ssbi_platform_data {
diff --git a/arch/arm/mach-msm/include/mach/camera2.h b/arch/arm/mach-msm/include/mach/camera2.h
index 248c9b0..3e7e5fd 100644
--- a/arch/arm/mach-msm/include/mach/camera2.h
+++ b/arch/arm/mach-msm/include/mach/camera2.h
@@ -79,6 +79,7 @@
 	struct msm_camera_i2c_conf *i2c_conf;
 	struct msm_sensor_info_t *sensor_info;
 	struct msm_sensor_init_params *sensor_init_params;
+	const char *misc_regulator;
 };
 
 enum msm_camera_i2c_cmd_type {
diff --git a/arch/arm/mach-msm/include/mach/clk.h b/arch/arm/mach-msm/include/mach/clk.h
index 1809456..fae0777 100644
--- a/arch/arm/mach-msm/include/mach/clk.h
+++ b/arch/arm/mach-msm/include/mach/clk.h
@@ -25,6 +25,7 @@
 #define CLKFLAG_MAX			0x00000800
 #define CLKFLAG_INIT_DONE		0x00001000
 #define CLKFLAG_INIT_ERR		0x00002000
+#define CLKFLAG_NO_RATE_CACHE		0x00004000
 
 struct clk_lookup;
 struct clk;
diff --git a/arch/arm/mach-msm/include/mach/iommu.h b/arch/arm/mach-msm/include/mach/iommu.h
index 23d204a..70c696c 100644
--- a/arch/arm/mach-msm/include/mach/iommu.h
+++ b/arch/arm/mach-msm/include/mach/iommu.h
@@ -98,6 +98,7 @@
  * @halt_enabled: Set to 1 if IOMMU halt is supported in the IOMMU, 0 otherwise.
  * @asid:         List of ASID and their usage count (index is ASID value).
  * @ctx_attach_count: Count of how many context are attached.
+ * @bus_client  : Bus client needed to vote for bus bandwidth.
  *
  * A msm_iommu_drvdata holds the global driver data about a single piece
  * of an IOMMU hardware instance.
@@ -121,12 +122,14 @@
 	int halt_enabled;
 	int *asid;
 	unsigned int ctx_attach_count;
+	unsigned int bus_client;
 };
 
 /**
  * struct iommu_access_ops - Callbacks for accessing IOMMU
  * @iommu_power_on:     Turn on power to unit
  * @iommu_power_off:    Turn off power to unit
+ * @iommu_bus_vote:     Vote for bus bandwidth
  * @iommu_clk_on:       Turn on clks to unit
  * @iommu_clk_off:      Turn off clks to unit
  * @iommu_lock_initialize: Initialize the remote lock
@@ -136,6 +139,8 @@
 struct iommu_access_ops {
 	int (*iommu_power_on)(struct msm_iommu_drvdata *);
 	void (*iommu_power_off)(struct msm_iommu_drvdata *);
+	int (*iommu_bus_vote)(struct msm_iommu_drvdata *drvdata,
+			      unsigned int vote);
 	int (*iommu_clk_on)(struct msm_iommu_drvdata *);
 	void (*iommu_clk_off)(struct msm_iommu_drvdata *);
 	void * (*iommu_lock_initialize)(void);
@@ -181,6 +186,22 @@
 	int attach_count;
 };
 
+struct msm_iommu_context_regs {
+	uint32_t far;
+	uint32_t par;
+	uint32_t fsr;
+	uint32_t fsynr0;
+	uint32_t fsynr1;
+	uint32_t ttbr0;
+	uint32_t ttbr1;
+	uint32_t sctlr;
+	uint32_t actlr;
+	uint32_t prrr;
+	uint32_t nmrr;
+};
+
+void print_ctx_regs(struct msm_iommu_context_regs *regs);
+
 /*
  * Interrupt handler for the IOMMU context fault interrupt. Hooking the
  * interrupt is not supported in the API yet, but this will print an error
@@ -188,6 +209,7 @@
  */
 irqreturn_t msm_iommu_fault_handler(int irq, void *dev_id);
 irqreturn_t msm_iommu_fault_handler_v2(int irq, void *dev_id);
+irqreturn_t msm_iommu_secure_fault_handler_v2(int irq, void *dev_id);
 
 enum {
 	PROC_APPS,
diff --git a/arch/arm/mach-msm/include/mach/ipa.h b/arch/arm/mach-msm/include/mach/ipa.h
index db5e126..697de5e 100644
--- a/arch/arm/mach-msm/include/mach/ipa.h
+++ b/arch/arm/mach-msm/include/mach/ipa.h
@@ -186,6 +186,16 @@
 };
 
 /**
+ * struct ipa_ep_cfg_holb - head of line blocking configuration in IPA end-point
+ * @en: enable(1 => ok to drop pkt)/disable(0 => never drop pkt)
+ * @tmr_val: duration in units of 128 IPA clk clock cyles [0,511], 1 clk=1.28us
+ */
+struct ipa_ep_cfg_holb {
+	u16 en;
+	u16 tmr_val;
+};
+
+/**
  * struct ipa_ep_cfg - configuration of IPA end-point
  * @nat:	NAT parmeters
  * @hdr:	Header parameters
@@ -485,6 +495,11 @@
 
 int ipa_cfg_ep_route(u32 clnt_hdl, const struct ipa_ep_cfg_route *ipa_ep_cfg);
 
+int ipa_cfg_ep_holb(u32 clnt_hdl, const struct ipa_ep_cfg_holb *ipa_ep_cfg);
+
+int ipa_cfg_ep_holb_by_client(enum ipa_client_type client,
+				const struct ipa_ep_cfg_holb *ipa_ep_cfg);
+
 /*
  * Header removal / addition
  */
@@ -754,6 +769,12 @@
 	return -EPERM;
 }
 
+static inline int ipa_cfg_ep_holb(u32 clnt_hdl,
+		const struct ipa_ep_cfg_holb *ipa_ep_cfg)
+{
+	return -EPERM;
+}
+
 /*
  * Header removal / addition
  */
diff --git a/arch/arm/mach-msm/include/mach/kgsl.h b/arch/arm/mach-msm/include/mach/kgsl.h
index 349dbe7..2216183 100644
--- a/arch/arm/mach-msm/include/mach/kgsl.h
+++ b/arch/arm/mach-msm/include/mach/kgsl.h
@@ -89,6 +89,8 @@
 	struct kgsl_device_iommu_data *iommu_data;
 	int iommu_count;
 	struct msm_dcvs_core_info *core_info;
+	struct coresight_device *csdev;
+	struct coresight_platform_data *coresight_pdata;
 	unsigned int chipid;
 };
 
diff --git a/arch/arm/mach-msm/include/mach/mdm2.h b/arch/arm/mach-msm/include/mach/mdm2.h
index 46069d2..c6c03e4 100644
--- a/arch/arm/mach-msm/include/mach/mdm2.h
+++ b/arch/arm/mach-msm/include/mach/mdm2.h
@@ -12,6 +12,7 @@
 
 #ifndef _ARCH_ARM_MACH_MSM_MDM2_H
 #define _ARCH_ARM_MACH_MSM_MDM2_H
+#include "sysmon.h"
 
 struct mdm_vddmin_resource {
 	int rpm_id;
@@ -35,6 +36,9 @@
 	int image_upgrade_supported;
 	struct gpiomux_setting *mdm2ap_status_gpio_run_cfg;
 	int send_shdn;
+	int cascading_ssr;
+	int sysmon_subsys_id_valid;
+	enum subsys_id sysmon_subsys_id;
 };
 
 #endif
diff --git a/arch/arm/mach-msm/include/mach/msm_iomap.h b/arch/arm/mach-msm/include/mach/msm_iomap.h
index 676df66..7b73333 100644
--- a/arch/arm/mach-msm/include/mach/msm_iomap.h
+++ b/arch/arm/mach-msm/include/mach/msm_iomap.h
@@ -81,16 +81,6 @@
 #define MSM_LPASS_CLK_CTL_BASE	IOMEM(0xFA015000)	/*  4K	*/
 #define MSM_HFPLL_BASE		IOMEM(0xFA016000)	/*  4K	*/
 #define MSM_TLMM_BASE		IOMEM(0xFA017000)	/* 16K	*/
-#define MSM_SHARED_RAM_BASE	IOMEM(0xFA400000)	/*  2M  */
-#define MSM_SIC_NON_SECURE_BASE	IOMEM(0xFA600000)	/* 64K	*/
-#define MSM_HDMI_BASE		IOMEM(0xFA800000)	/*  4K  */
-#define MSM_RPM_BASE		IOMEM(0xFA801000)	/*  4K	*/
-#define MSM_RPM_MPM_BASE	IOMEM(0xFA802000)	/*  4K	*/
-#define MSM_QFPROM_BASE		IOMEM(0xFA700000)	/*  4K  */
-#define MSM_L2CC_BASE		IOMEM(0xFA701000)	/*  4K  */
-#define MSM_APCS_GLB_BASE	IOMEM(0xFA702000)	/*  4K  */
-#define MSM_SAW2_BASE		IOMEM(0xFA703000)	/*  4k  */
-#define MSM_SAW3_BASE		IOMEM(0xFA704000)	/*  4k  */
 #define MSM_VIC_BASE		IOMEM(0xFA100000)	/*  4K */
 #define MSM_CSR_BASE		IOMEM(0xFA101000)	/*  4K */
 #define MSM_GPIO1_BASE		IOMEM(0xFA102000)	/*  4K */
@@ -99,7 +89,16 @@
 #define MSM_CFG_CTL_BASE	IOMEM(0xFA105000)	/*  4K */
 #define MSM_CLK_CTL_SH2_BASE	IOMEM(0xFA106000)	/*  4K */
 #define MSM_MPM2_PSHOLD_BASE	IOMEM(0xFA107000)	/*  4k */
-#define MSM_MDC_BASE		IOMEM(0xFA400000)	/*  1M */
+#define MSM_SHARED_RAM_BASE	IOMEM(0xFA400000)	/*  2M  */
+#define MSM_SIC_NON_SECURE_BASE	IOMEM(0xFA600000)	/* 64K	*/
+#define MSM_QFPROM_BASE		IOMEM(0xFA700000)	/*  4K  */
+#define MSM_L2CC_BASE		IOMEM(0xFA701000)	/*  4K  */
+#define MSM_APCS_GLB_BASE	IOMEM(0xFA702000)	/*  4K  */
+#define MSM_SAW2_BASE		IOMEM(0xFA703000)	/*  4k  */
+#define MSM_SAW3_BASE		IOMEM(0xFA704000)	/*  4k  */
+#define MSM_HDMI_BASE		IOMEM(0xFA800000)	/*  4K  */
+#define MSM_RPM_BASE		IOMEM(0xFA801000)	/*  4K	*/
+#define MSM_RPM_MPM_BASE	IOMEM(0xFA802000)	/*  4K	*/
 #define MSM_AD5_BASE		IOMEM(0xFA900000)	/*  13M (D00000)
 							  0xFB600000 */
 /* MSM9625 has unaligned imem so we need to map excess 2K virtually
diff --git a/arch/arm/mach-msm/include/mach/msm_ipc_router.h b/arch/arm/mach-msm/include/mach/msm_ipc_router.h
index 894379e..a87380c 100644
--- a/arch/arm/mach-msm/include/mach/msm_ipc_router.h
+++ b/arch/arm/mach-msm/include/mach/msm_ipc_router.h
@@ -46,11 +46,8 @@
 	spinlock_t port_lock;
 	struct comm_mode_info mode_info;
 
-	struct list_head incomplete;
-	struct mutex incomplete_lock;
-
 	struct list_head port_rx_q;
-	struct mutex port_rx_q_lock;
+	struct mutex port_rx_q_lock_lhb3;
 	char rx_wakelock_name[MAX_WAKELOCK_NAME_SZ];
 	struct wake_lock port_rx_wake_lock;
 	wait_queue_head_t port_rx_wait_q;
diff --git a/arch/arm/mach-msm/include/mach/msm_memtypes.h b/arch/arm/mach-msm/include/mach/msm_memtypes.h
index 3bf05e6..5c8f525 100644
--- a/arch/arm/mach-msm/include/mach/msm_memtypes.h
+++ b/arch/arm/mach-msm/include/mach/msm_memtypes.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2011, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2010-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
@@ -39,6 +39,15 @@
 	MEMTYPE_MAX,
 };
 
+enum {
+	SYS_MEMORY = 1,        /* system memory*/
+	BOOT_REGION_MEMORY1,   /* boot loader memory 1*/
+	BOOT_REGION_MEMORY2,   /* boot loader memory 2,reserved*/
+	APPSBL_MEMORY,         /* apps boot loader memory*/
+	APPS_MEMORY,           /* apps  usage memory*/
+};
+
+
 void msm_reserve(void);
 
 #define MEMTYPE_FLAGS_FIXED	0x1
diff --git a/arch/arm/mach-msm/include/mach/msm_smsm.h b/arch/arm/mach-msm/include/mach/msm_smsm.h
index 733f5a9..f97d5e4 100644
--- a/arch/arm/mach-msm/include/mach/msm_smsm.h
+++ b/arch/arm/mach-msm/include/mach/msm_smsm.h
@@ -39,12 +39,16 @@
 };
 #endif
 
+/*
+ * Ordered by when processors adopted the SMSM protocol.  May not be 1-to-1
+ * with SMEM PIDs, despite initial expectations.
+ */
 enum {
 	SMSM_APPS = SMEM_APPS,
 	SMSM_MODEM = SMEM_MODEM,
 	SMSM_Q6 = SMEM_Q6,
-	SMSM_DSPS = SMEM_DSPS,
-	SMSM_WCNSS = SMEM_WCNSS,
+	SMSM_WCNSS,
+	SMSM_DSPS,
 };
 extern uint32_t SMSM_NUM_HOSTS;
 
diff --git a/arch/arm/mach-msm/include/mach/ocmem_priv.h b/arch/arm/mach-msm/include/mach/ocmem_priv.h
index 8539dcc..6f83c53 100644
--- a/arch/arm/mach-msm/include/mach/ocmem_priv.h
+++ b/arch/arm/mach-msm/include/mach/ocmem_priv.h
@@ -42,7 +42,7 @@
 struct ocmem_zone;
 
 struct ocmem_zone_ops {
-	unsigned long (*allocate) (struct ocmem_zone *, unsigned long);
+	int (*allocate) (struct ocmem_zone *, unsigned long, unsigned long *);
 	int (*free) (struct ocmem_zone *, unsigned long, unsigned long);
 };
 
@@ -197,9 +197,9 @@
 int zone_active(int);
 unsigned long offset_to_phys(unsigned long);
 unsigned long phys_to_offset(unsigned long);
-unsigned long allocate_head(struct ocmem_zone *, unsigned long);
+int allocate_head(struct ocmem_zone *, unsigned long, unsigned long *);
 int free_head(struct ocmem_zone *, unsigned long, unsigned long);
-unsigned long allocate_tail(struct ocmem_zone *, unsigned long);
+int allocate_tail(struct ocmem_zone *, unsigned long, unsigned long *);
 int free_tail(struct ocmem_zone *, unsigned long, unsigned long);
 
 int ocmem_notifier_init(void);
diff --git a/arch/arm/mach-msm/include/mach/socinfo.h b/arch/arm/mach-msm/include/mach/socinfo.h
index 99bff66..5aaab18 100644
--- a/arch/arm/mach-msm/include/mach/socinfo.h
+++ b/arch/arm/mach-msm/include/mach/socinfo.h
@@ -38,6 +38,9 @@
 #define of_board_is_liquid()	of_machine_is_compatible("qcom,liquid")
 #define of_board_is_dragonboard()	\
 	of_machine_is_compatible("qcom,dragonboard")
+#define of_board_is_cdp()	of_machine_is_compatible("qcom,cdp")
+#define of_board_is_mtp()	of_machine_is_compatible("qcom,mtp")
+#define of_board_is_qrd()	of_machine_is_compatible("qcom,qrd")
 
 #define machine_is_msm8974()	of_machine_is_compatible("qcom,msm8974")
 #define machine_is_msm9625()	of_machine_is_compatible("qcom,msm9625")
@@ -63,6 +66,9 @@
 #define of_board_is_fluid()		0
 #define of_board_is_liquid()		0
 #define of_board_is_dragonboard()	0
+#define of_board_is_cdp()		0
+#define of_board_is_mtp()		0
+#define of_board_is_qrd()		0
 
 #define machine_is_msm8974()		0
 #define machine_is_msm9625()		0
diff --git a/arch/arm/mach-msm/include/mach/sps.h b/arch/arm/mach-msm/include/mach/sps.h
index c5ad35d..3332701 100644
--- a/arch/arm/mach-msm/include/mach/sps.h
+++ b/arch/arm/mach-msm/include/mach/sps.h
@@ -1271,6 +1271,15 @@
 int sps_get_bam_debug_info(u32 dev, u32 option, u32 para,
 		u32 tb_sel, u32 desc_sel);
 
+/**
+ * Vote for or relinquish BAM DMA clock
+ *
+ * @clk_on - to turn on or turn off the clock
+ *
+ * @return 0 on success, negative value on error
+ *
+ */
+int sps_ctrl_bam_dma_clk(bool clk_on);
 #else
 static inline int sps_register_bam_device(const struct sps_bam_props
 			*bam_props, u32 *dev_handle)
@@ -1433,6 +1442,11 @@
 {
 	return -EPERM;
 }
+
+static inline int sps_ctrl_bam_dma_clk(bool clk_on)
+{
+	return -EPERM;
+}
 #endif
 
 #endif /* _SPS_H_ */
diff --git a/arch/arm/mach-msm/trace_msm_low_power.h b/arch/arm/mach-msm/include/mach/trace_msm_low_power.h
similarity index 98%
rename from arch/arm/mach-msm/trace_msm_low_power.h
rename to arch/arm/mach-msm/include/mach/trace_msm_low_power.h
index 4e9da85..faa4209 100644
--- a/arch/arm/mach-msm/trace_msm_low_power.h
+++ b/arch/arm/mach-msm/include/mach/trace_msm_low_power.h
@@ -149,6 +149,6 @@
 );
 #endif
 #undef TRACE_INCLUDE_PATH
-#define TRACE_INCLUDE_PATH .
+#define TRACE_INCLUDE_PATH mach
 #define TRACE_INCLUDE_FILE trace_msm_low_power
 #include <trace/define_trace.h>
diff --git a/arch/arm/mach-msm/trace_rpm_smd.h b/arch/arm/mach-msm/include/mach/trace_rpm_smd.h
similarity index 98%
rename from arch/arm/mach-msm/trace_rpm_smd.h
rename to arch/arm/mach-msm/include/mach/trace_rpm_smd.h
index eff4860..1b019d8 100644
--- a/arch/arm/mach-msm/trace_rpm_smd.h
+++ b/arch/arm/mach-msm/include/mach/trace_rpm_smd.h
@@ -74,6 +74,6 @@
 );
 #endif
 #undef TRACE_INCLUDE_PATH
-#define TRACE_INCLUDE_PATH .
+#define TRACE_INCLUDE_PATH mach
 #define TRACE_INCLUDE_FILE trace_rpm_smd
 #include <trace/define_trace.h>
diff --git a/arch/arm/mach-msm/include/mach/usb_bam.h b/arch/arm/mach-msm/include/mach/usb_bam.h
index 5ecc63b..bc76f56 100644
--- a/arch/arm/mach-msm/include/mach/usb_bam.h
+++ b/arch/arm/mach-msm/include/mach/usb_bam.h
@@ -126,6 +126,7 @@
 	struct sps_mem_buffer desc_mem_buf;
 	struct usb_bam_event_info event;
 	bool enabled;
+	bool suspended;
 	int ipa_clnt_hdl;
 	void *priv;
 	int (*activity_notify)(void *priv);
diff --git a/arch/arm/mach-msm/io.c b/arch/arm/mach-msm/io.c
index 73e960f..f736b30 100644
--- a/arch/arm/mach-msm/io.c
+++ b/arch/arm/mach-msm/io.c
@@ -69,7 +69,6 @@
 	MSM_CHIP_DEVICE(GPIO2, MSM7XXX),
 	MSM_CHIP_DEVICE(CLK_CTL, MSM7XXX),
 	MSM_CHIP_DEVICE(AD5, MSM7XXX),
-	MSM_CHIP_DEVICE(MDC, MSM7XXX),
 #if defined(CONFIG_DEBUG_MSM_UART1) || defined(CONFIG_DEBUG_MSM_UART2) || \
 	defined(CONFIG_DEBUG_MSM_UART3)
 	MSM_DEVICE(DEBUG_UART),
@@ -117,7 +116,6 @@
 	MSM_DEVICE(SIRC),
 	MSM_DEVICE(SCPLL),
 	MSM_DEVICE(AD5),
-	MSM_DEVICE(MDC),
 	MSM_DEVICE(TCSR),
 #if defined(CONFIG_DEBUG_MSM_UART1) || defined(CONFIG_DEBUG_MSM_UART2) || \
 	defined(CONFIG_DEBUG_MSM_UART3)
@@ -353,7 +351,6 @@
 	MSM_CHIP_DEVICE(CLK_CTL, MSM7X30),
 	MSM_CHIP_DEVICE(CLK_CTL_SH2, MSM7X30),
 	MSM_CHIP_DEVICE(AD5, MSM7X30),
-	MSM_CHIP_DEVICE(MDC, MSM7X30),
 	MSM_CHIP_DEVICE(ACC0, MSM7X30),
 	MSM_CHIP_DEVICE(SAW0, MSM7X30),
 	MSM_CHIP_DEVICE(APCS_GCC, MSM7X30),
@@ -476,7 +473,6 @@
 	MSM_CHIP_DEVICE(SAW2, MSM8625),
 	MSM_CHIP_DEVICE(SAW3, MSM8625),
 	MSM_CHIP_DEVICE(AD5, MSM7XXX),
-	MSM_CHIP_DEVICE(MDC, MSM7XXX),
 #if defined(CONFIG_DEBUG_MSM_UART1) || defined(CONFIG_DEBUG_MSM_UART2) || \
 	defined(CONFIG_DEBUG_MSM_UART3)
 	MSM_DEVICE(DEBUG_UART),
@@ -566,6 +562,7 @@
 {
 	msm_shared_ram_phys = MPQ8092_MSM_SHARED_RAM_PHYS;
 	msm_map_io(mpq8092_io_desc, ARRAY_SIZE(mpq8092_io_desc));
+	of_scan_flat_dt(msm_scan_dt_map_imem, NULL);
 }
 #endif /* CONFIG_ARCH_MPQ8092 */
 
diff --git a/arch/arm/mach-msm/iommu_domains.c b/arch/arm/mach-msm/iommu_domains.c
index f4ac37e..12f5a8e 100644
--- a/arch/arm/mach-msm/iommu_domains.c
+++ b/arch/arm/mach-msm/iommu_domains.c
@@ -570,12 +570,14 @@
 			goto out;
 		}
 		ctx = msm_iommu_get_ctx(name);
-		if (!ctx) {
-			pr_err("Unable to find context %s\n", name);
-			ret_val = -EINVAL;
+		if (IS_ERR(ctx)) {
+			ret_val = PTR_ERR(ctx);
 			goto out;
 		}
-		iommu_group_add_device(group, ctx);
+
+		ret_val = iommu_group_add_device(group, ctx);
+		if (ret_val)
+			goto out;
 	}
 out:
 	return ret_val;
@@ -590,7 +592,7 @@
 	struct msm_iova_layout l;
 	struct msm_iova_partition *part = 0;
 	struct iommu_domain *domain = 0;
-	unsigned int *addr_array;
+	unsigned int *addr_array = 0;
 	unsigned int array_size;
 	int domain_no;
 	int secure_domain;
@@ -661,11 +663,46 @@
 	iommu_group_set_iommudata(group, domain, NULL);
 
 free_mem:
+	kfree(addr_array);
 	kfree(part);
 out:
 	return ret_val;
 }
 
+static int __msm_group_get_domain(struct device *dev, void *data)
+{
+	struct msm_iommu_data_entry *list_entry;
+	struct list_head *dev_list = data;
+	int ret_val = 0;
+
+	list_entry = kmalloc(sizeof(*list_entry), GFP_KERNEL);
+	if (list_entry) {
+		list_entry->data = dev;
+		list_add(&list_entry->list, dev_list);
+	} else {
+		ret_val = -ENOMEM;
+	}
+
+	return ret_val;
+}
+
+static void __msm_iommu_group_remove_device(struct iommu_group *grp)
+{
+	struct msm_iommu_data_entry *tmp;
+	struct msm_iommu_data_entry *list_entry;
+	struct list_head dev_list;
+
+	INIT_LIST_HEAD(&dev_list);
+	iommu_group_for_each_dev(grp, &dev_list, __msm_group_get_domain);
+
+	list_for_each_entry_safe(list_entry, tmp, &dev_list, list) {
+		iommu_group_remove_device(list_entry->data);
+		list_del(&list_entry->list);
+		kfree(list_entry);
+	}
+}
+
+
 static int iommu_domain_parse_dt(const struct device_node *dt_node)
 {
 	struct device_node *node;
@@ -674,13 +711,30 @@
 	int ret_val = 0;
 	struct iommu_group *group = 0;
 	const char *name;
+	struct msm_iommu_data_entry *grp_list_entry;
+	struct msm_iommu_data_entry *tmp;
+	struct list_head iommu_group_list;
+	INIT_LIST_HEAD(&iommu_group_list);
 
 	for_each_child_of_node(dt_node, node) {
 		group = iommu_group_alloc();
 		if (IS_ERR(group)) {
 			ret_val = PTR_ERR(group);
-			goto out;
+			group = 0;
+			goto free_group;
 		}
+
+		/* This is only needed to clean up memory if something fails */
+		grp_list_entry = kmalloc(sizeof(*grp_list_entry),
+					   GFP_KERNEL);
+		if (grp_list_entry) {
+			grp_list_entry->data = group;
+			list_add(&grp_list_entry->list, &iommu_group_list);
+		} else {
+			ret_val = -ENOMEM;
+			goto free_group;
+		}
+
 		if (of_property_read_string(node, "label", &name)) {
 			ret_val = -EINVAL;
 			goto free_group;
@@ -696,7 +750,6 @@
 
 		ret_val = find_and_add_contexts(group, node, num_contexts);
 		if (ret_val) {
-			ret_val = -EINVAL;
 			goto free_group;
 		}
 		ret_val = create_and_add_domain(group, node, name);
@@ -704,9 +757,33 @@
 			ret_val = -EINVAL;
 			goto free_group;
 		}
+
+		/* Remove reference to the group that is taken when the group
+		 * is allocated. This will ensure that when all the devices in
+		 * the group are removed the group will be released.
+		 */
+		iommu_group_put(group);
 	}
+
+	list_for_each_entry_safe(grp_list_entry, tmp, &iommu_group_list, list) {
+		list_del(&grp_list_entry->list);
+		kfree(grp_list_entry);
+	}
+	goto out;
+
 free_group:
-	/* No iommu_group_free() function */
+	list_for_each_entry_safe(grp_list_entry, tmp, &iommu_group_list, list) {
+		struct iommu_domain *d;
+
+		d = iommu_group_get_iommudata(grp_list_entry->data);
+		if (d)
+			msm_unregister_domain(d);
+
+		__msm_iommu_group_remove_device(grp_list_entry->data);
+		list_del(&grp_list_entry->list);
+		kfree(grp_list_entry);
+	}
+	iommu_group_put(group);
 out:
 	return ret_val;
 }
diff --git a/arch/arm/mach-msm/ipc_logging.c b/arch/arm/mach-msm/ipc_logging.c
index 1260a1a..280f237 100644
--- a/arch/arm/mach-msm/ipc_logging.c
+++ b/arch/arm/mach-msm/ipc_logging.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
@@ -32,7 +32,7 @@
 #include "ipc_logging.h"
 
 static LIST_HEAD(ipc_log_context_list);
-DEFINE_SPINLOCK(ipc_log_context_list_lock);
+DEFINE_RWLOCK(ipc_log_context_list_lock);
 static atomic_t next_log_id = ATOMIC_INIT(0);
 
 static struct ipc_log_page *get_first_page(struct ipc_log_context *ilctxt)
@@ -140,7 +140,7 @@
 		return;
 	}
 
-	spin_lock_irqsave(&ipc_log_context_list_lock, flags);
+	read_lock_irqsave(&ipc_log_context_list_lock, flags);
 	spin_lock(&ilctxt->ipc_log_context_lock);
 	while (ilctxt->write_avail < ectxt->offset)
 		msg_read(ilctxt, NULL);
@@ -165,7 +165,7 @@
 	ilctxt->write_avail -= ectxt->offset;
 	complete(&ilctxt->read_avail);
 	spin_unlock(&ilctxt->ipc_log_context_lock);
-	spin_unlock_irqrestore(&ipc_log_context_list_lock, flags);
+	read_unlock_irqrestore(&ipc_log_context_list_lock, flags);
 }
 EXPORT_SYMBOL(ipc_log_write);
 
@@ -471,13 +471,13 @@
 	if (!df_info)
 		return -ENOSPC;
 
-	spin_lock_irqsave(&ipc_log_context_list_lock, flags);
+	read_lock_irqsave(&ipc_log_context_list_lock, flags);
 	spin_lock(&ilctxt->ipc_log_context_lock);
 	df_info->type = type;
 	df_info->dfunc = dfunc;
 	list_add_tail(&df_info->list, &ilctxt->dfunc_info_list);
 	spin_unlock(&ilctxt->ipc_log_context_lock);
-	spin_unlock_irqrestore(&ipc_log_context_list_lock, flags);
+	read_unlock_irqrestore(&ipc_log_context_list_lock, flags);
 	return 0;
 }
 EXPORT_SYMBOL(add_deserialization_func);
@@ -528,9 +528,9 @@
 
 	create_ctx_debugfs(ctxt, mod_name);
 
-	spin_lock_irqsave(&ipc_log_context_list_lock, flags);
+	write_lock_irqsave(&ipc_log_context_list_lock, flags);
 	list_add_tail(&ctxt->list, &ipc_log_context_list);
-	spin_unlock_irqrestore(&ipc_log_context_list_lock, flags);
+	write_unlock_irqrestore(&ipc_log_context_list_lock, flags);
 	return (void *)ctxt;
 
 release_ipc_log_context:
diff --git a/arch/arm/mach-msm/ipc_logging.h b/arch/arm/mach-msm/ipc_logging.h
index 0eb82a5..36b4171 100644
--- a/arch/arm/mach-msm/ipc_logging.h
+++ b/arch/arm/mach-msm/ipc_logging.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
@@ -65,7 +65,7 @@
 #define IS_MSG_TYPE(x) (((x) > TSV_TYPE_MSG_START) && \
 			((x) < TSV_TYPE_MSG_END))
 
-extern spinlock_t ipc_log_context_list_lock;
+extern rwlock_t ipc_log_context_list_lock;
 
 extern int msg_read(struct ipc_log_context *ilctxt,
 		    struct encode_context *ectxt);
diff --git a/arch/arm/mach-msm/ipc_logging_debug.c b/arch/arm/mach-msm/ipc_logging_debug.c
index ff947ef..246fb99 100644
--- a/arch/arm/mach-msm/ipc_logging_debug.c
+++ b/arch/arm/mach-msm/ipc_logging_debug.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
@@ -62,7 +62,7 @@
 	dctxt.output_format = OUTPUT_DEBUGFS;
 	dctxt.buff = buff;
 	dctxt.size = size;
-	spin_lock_irqsave(&ipc_log_context_list_lock, flags);
+	read_lock_irqsave(&ipc_log_context_list_lock, flags);
 	spin_lock(&ilctxt->ipc_log_context_lock);
 	while (dctxt.size >= MAX_MSG_DECODED_SIZE &&
 	       !is_ilctxt_empty(ilctxt)) {
@@ -70,19 +70,19 @@
 		deserialize_func = get_deserialization_func(ilctxt,
 							ectxt.hdr.type);
 		spin_unlock(&ilctxt->ipc_log_context_lock);
-		spin_unlock_irqrestore(&ipc_log_context_list_lock, flags);
+		read_unlock_irqrestore(&ipc_log_context_list_lock, flags);
 		if (deserialize_func)
 			deserialize_func(&ectxt, &dctxt);
 		else
 			pr_err("%s: unknown message 0x%x\n",
 				__func__, ectxt.hdr.type);
-		spin_lock_irqsave(&ipc_log_context_list_lock, flags);
+		read_lock_irqsave(&ipc_log_context_list_lock, flags);
 		spin_lock(&ilctxt->ipc_log_context_lock);
 	}
 	if ((size - dctxt.size) == 0)
 		init_completion(&ilctxt->read_avail);
 	spin_unlock(&ilctxt->ipc_log_context_lock);
-	spin_unlock_irqrestore(&ipc_log_context_list_lock, flags);
+	read_unlock_irqrestore(&ipc_log_context_list_lock, flags);
 	return size - dctxt.size;
 }
 
diff --git a/arch/arm/mach-msm/ipc_router.c b/arch/arm/mach-msm/ipc_router.c
index c620419..41fd485 100644
--- a/arch/arm/mach-msm/ipc_router.c
+++ b/arch/arm/mach-msm/ipc_router.c
@@ -27,6 +27,7 @@
 #include <linux/platform_device.h>
 #include <linux/uaccess.h>
 #include <linux/debugfs.h>
+#include <linux/rwsem.h>
 
 #include <asm/uaccess.h>
 #include <asm/byteorder.h>
@@ -99,11 +100,11 @@
 #define IPC_ROUTER_LOG_EVENT_RX         0x12
 
 static LIST_HEAD(control_ports);
-static DEFINE_MUTEX(control_ports_lock);
+static DECLARE_RWSEM(control_ports_lock_lha5);
 
 #define LP_HASH_SIZE 32
 static struct list_head local_ports[LP_HASH_SIZE];
-static DEFINE_MUTEX(local_ports_lock);
+static DECLARE_RWSEM(local_ports_lock_lha2);
 
 /*
  * Server info is organized as a hash table. The server's service ID is
@@ -114,8 +115,7 @@
  */
 #define SRV_HASH_SIZE 32
 static struct list_head server_list[SRV_HASH_SIZE];
-static DEFINE_MUTEX(server_list_lock);
-static wait_queue_head_t newserver_wait;
+static DECLARE_RWSEM(server_list_lock_lha2);
 
 struct msm_ipc_server {
 	struct list_head list;
@@ -144,11 +144,11 @@
 	struct list_head list;
 	uint32_t node_id;
 	uint32_t port_id;
-	uint32_t restart_state;
 	uint32_t tx_quota_cnt;
-	struct mutex quota_lock;
+	struct mutex quota_lock_lhb2;
 	struct list_head resume_tx_port_list;
 	void *sec_rule;
+	struct msm_ipc_server *server;
 };
 
 struct msm_ipc_router_xprt_info {
@@ -158,8 +158,8 @@
 	uint32_t initialized;
 	struct list_head pkt_list;
 	struct wake_lock wakelock;
-	struct mutex rx_lock;
-	struct mutex tx_lock;
+	struct mutex rx_lock_lhb2;
+	struct mutex tx_lock_lhb2;
 	uint32_t need_len;
 	uint32_t abort_data_read;
 	struct work_struct read_data;
@@ -173,39 +173,25 @@
 	uint32_t neighbor_node_id;
 	struct list_head remote_port_list[RP_HASH_SIZE];
 	struct msm_ipc_router_xprt_info *xprt_info;
-	struct mutex lock;
+	struct rw_semaphore lock_lha4;
 	unsigned long num_tx_bytes;
 	unsigned long num_rx_bytes;
 };
 
 static struct list_head routing_table[RT_HASH_SIZE];
-static DEFINE_MUTEX(routing_table_lock);
+static DECLARE_RWSEM(routing_table_lock_lha3);
 static int routing_table_inited;
 
-static LIST_HEAD(msm_ipc_board_dev_list);
-static DEFINE_MUTEX(msm_ipc_board_dev_list_lock);
-
 static void do_read_data(struct work_struct *work);
 
-#define RR_STATE_IDLE    0
-#define RR_STATE_HEADER  1
-#define RR_STATE_BODY    2
-#define RR_STATE_ERROR   3
-
-#define RESTART_NORMAL 0
-#define RESTART_PEND 1
-
-/* State for remote ep following restart */
-#define RESTART_QUOTA_ABORT  1
-
 static LIST_HEAD(xprt_info_list);
-static DEFINE_MUTEX(xprt_info_list_lock);
+static DECLARE_RWSEM(xprt_info_list_lock_lha5);
 
 static DECLARE_COMPLETION(msm_ipc_local_router_up);
 #define IPC_ROUTER_INIT_TIMEOUT (10 * HZ)
 
 static uint32_t next_port_id;
-static DEFINE_MUTEX(next_port_id_lock);
+static DEFINE_MUTEX(next_port_id_lock_lha1);
 static atomic_t pending_close_count = ATOMIC_INIT(0);
 static wait_queue_head_t subsystem_restart_wait;
 static struct workqueue_struct *msm_ipc_router_workqueue;
@@ -239,13 +225,13 @@
 	for (i = 0; i < RP_HASH_SIZE; i++)
 		INIT_LIST_HEAD(&rt_entry->remote_port_list[i]);
 
-	mutex_init(&rt_entry->lock);
+	init_rwsem(&rt_entry->lock_lha4);
 	rt_entry->node_id = node_id;
 	rt_entry->xprt_info = NULL;
 	return rt_entry;
 }
 
-/*Please take routing_table_lock before calling this function*/
+/* Must be called with routing_table_lock_lha3 locked. */
 static int add_routing_table_entry(
 	struct msm_ipc_routing_table_entry *rt_entry)
 {
@@ -259,7 +245,7 @@
 	return 0;
 }
 
-/*Please take routing_table_lock before calling this function*/
+/* Must be called with routing_table_lock_lha3 locked. */
 static struct msm_ipc_routing_table_entry *lookup_routing_table(
 	uint32_t node_id)
 {
@@ -280,16 +266,16 @@
 	if (!xprt_info)
 		return NULL;
 
-	mutex_lock(&xprt_info->rx_lock);
+	mutex_lock(&xprt_info->rx_lock_lhb2);
 	if (xprt_info->abort_data_read) {
-		mutex_unlock(&xprt_info->rx_lock);
+		mutex_unlock(&xprt_info->rx_lock_lhb2);
 		pr_err("%s detected SSR & exiting now\n",
 			xprt_info->xprt->name);
 		return NULL;
 	}
 
 	if (list_empty(&xprt_info->pkt_list)) {
-		mutex_unlock(&xprt_info->rx_lock);
+		mutex_unlock(&xprt_info->rx_lock_lhb2);
 		return NULL;
 	}
 
@@ -298,7 +284,7 @@
 	list_del(&temp_pkt->list);
 	if (list_empty(&xprt_info->pkt_list))
 		wake_unlock(&xprt_info->wakelock);
-	mutex_unlock(&xprt_info->rx_lock);
+	mutex_unlock(&xprt_info->rx_lock_lhb2);
 	return temp_pkt;
 }
 
@@ -476,24 +462,45 @@
 	kfree(skb_head);
 }
 
+static int post_pkt_to_port(struct msm_ipc_port *port_ptr,
+			    struct rr_packet *pkt, int clone)
+{
+	struct rr_packet *temp_pkt = pkt;
+
+	if (unlikely(!port_ptr || !pkt))
+		return -EINVAL;
+
+	if (clone) {
+		temp_pkt = clone_pkt(pkt);
+		if (!temp_pkt) {
+			pr_err("%s: Error cloning packet for port %08x:%08x\n",
+				__func__, port_ptr->this_port.node_id,
+				port_ptr->this_port.port_id);
+			return -ENOMEM;
+		}
+	}
+
+	mutex_lock(&port_ptr->port_rx_q_lock_lhb3);
+	wake_lock(&port_ptr->port_rx_wake_lock);
+	list_add_tail(&temp_pkt->list, &port_ptr->port_rx_q);
+	wake_up(&port_ptr->port_rx_wait_q);
+	if (port_ptr->notify)
+		port_ptr->notify(MSM_IPC_ROUTER_READ_CB, port_ptr->priv);
+	mutex_unlock(&port_ptr->port_rx_q_lock_lhb3);
+	return 0;
+}
+
 static int post_control_ports(struct rr_packet *pkt)
 {
 	struct msm_ipc_port *port_ptr;
-	struct rr_packet *cloned_pkt;
 
 	if (!pkt)
 		return -EINVAL;
 
-	mutex_lock(&control_ports_lock);
-	list_for_each_entry(port_ptr, &control_ports, list) {
-		mutex_lock(&port_ptr->port_rx_q_lock);
-		cloned_pkt = clone_pkt(pkt);
-		wake_lock(&port_ptr->port_rx_wake_lock);
-		list_add_tail(&cloned_pkt->list, &port_ptr->port_rx_q);
-		wake_up(&port_ptr->port_rx_wait_q);
-		mutex_unlock(&port_ptr->port_rx_q_lock);
-	}
-	mutex_unlock(&control_ports_lock);
+	down_read(&control_ports_lock_lha5);
+	list_for_each_entry(port_ptr, &control_ports, list)
+		post_pkt_to_port(port_ptr, pkt, 1);
+	up_read(&control_ports_lock_lha5);
 	return 0;
 }
 
@@ -502,9 +509,9 @@
 	uint32_t port_id = 0, prev_port_id, key;
 	struct msm_ipc_port *port_ptr;
 
-	mutex_lock(&next_port_id_lock);
+	mutex_lock(&next_port_id_lock_lha1);
 	prev_port_id = next_port_id;
-	mutex_lock(&local_ports_lock);
+	down_read(&local_ports_lock_lha2);
 	do {
 		next_port_id++;
 		if ((next_port_id & 0xFFFFFFFE) == 0xFFFFFFFE)
@@ -527,8 +534,8 @@
 		}
 		port_id = 0;
 	} while (next_port_id != prev_port_id);
-	mutex_unlock(&local_ports_lock);
-	mutex_unlock(&next_port_id_lock);
+	up_read(&local_ports_lock_lha2);
+	mutex_unlock(&next_port_id_lock_lha1);
 
 	return port_id;
 }
@@ -541,9 +548,9 @@
 		return;
 
 	key = (port_ptr->this_port.port_id & (LP_HASH_SIZE - 1));
-	mutex_lock(&local_ports_lock);
+	down_write(&local_ports_lock_lha2);
 	list_add_tail(&port_ptr->list, &local_ports[key]);
-	mutex_unlock(&local_ports_lock);
+	up_write(&local_ports_lock_lha2);
 }
 
 struct msm_ipc_port *msm_ipc_router_create_raw_port(void *endpoint,
@@ -565,10 +572,8 @@
 	}
 
 	spin_lock_init(&port_ptr->port_lock);
-	INIT_LIST_HEAD(&port_ptr->incomplete);
-	mutex_init(&port_ptr->incomplete_lock);
 	INIT_LIST_HEAD(&port_ptr->port_rx_q);
-	mutex_init(&port_ptr->port_rx_q_lock);
+	mutex_init(&port_ptr->port_rx_q_lock_lhb3);
 	init_waitqueue_head(&port_ptr->port_rx_wait_q);
 	snprintf(port_ptr->rx_wakelock_name, MAX_WAKELOCK_NAME_SZ,
 		 "ipc%08x_%s",
@@ -585,9 +590,7 @@
 	return port_ptr;
 }
 
-/*
- * Should be called with local_ports_lock locked
- */
+/* Must be called with local_ports_lock_lha2 locked. */
 static struct msm_ipc_port *msm_ipc_router_lookup_local_port(uint32_t port_id)
 {
 	int key = (port_id & (LP_HASH_SIZE - 1));
@@ -601,6 +604,7 @@
 	return NULL;
 }
 
+/* Must be called with routing_table_lock_lha3 locked. */
 static struct msm_ipc_router_remote_port *msm_ipc_router_lookup_remote_port(
 						uint32_t node_id,
 						uint32_t port_id)
@@ -609,30 +613,25 @@
 	struct msm_ipc_routing_table_entry *rt_entry;
 	int key = (port_id & (RP_HASH_SIZE - 1));
 
-	mutex_lock(&routing_table_lock);
 	rt_entry = lookup_routing_table(node_id);
 	if (!rt_entry) {
-		mutex_unlock(&routing_table_lock);
 		pr_err("%s: Node is not up\n", __func__);
 		return NULL;
 	}
 
-	mutex_lock(&rt_entry->lock);
+	down_read(&rt_entry->lock_lha4);
 	list_for_each_entry(rport_ptr,
 			    &rt_entry->remote_port_list[key], list) {
 		if (rport_ptr->port_id == port_id) {
-			if (rport_ptr->restart_state != RESTART_NORMAL)
-				rport_ptr = NULL;
-			mutex_unlock(&rt_entry->lock);
-			mutex_unlock(&routing_table_lock);
+			up_read(&rt_entry->lock_lha4);
 			return rport_ptr;
 		}
 	}
-	mutex_unlock(&rt_entry->lock);
-	mutex_unlock(&routing_table_lock);
+	up_read(&rt_entry->lock_lha4);
 	return NULL;
 }
 
+/* Must be called with routing_table_lock_lha3 locked. */
 static struct msm_ipc_router_remote_port *msm_ipc_router_create_remote_port(
 						uint32_t node_id,
 						uint32_t port_id)
@@ -641,34 +640,29 @@
 	struct msm_ipc_routing_table_entry *rt_entry;
 	int key = (port_id & (RP_HASH_SIZE - 1));
 
-	mutex_lock(&routing_table_lock);
 	rt_entry = lookup_routing_table(node_id);
 	if (!rt_entry) {
-		mutex_unlock(&routing_table_lock);
 		pr_err("%s: Node is not up\n", __func__);
 		return NULL;
 	}
 
-	mutex_lock(&rt_entry->lock);
 	rport_ptr = kmalloc(sizeof(struct msm_ipc_router_remote_port),
 			    GFP_KERNEL);
 	if (!rport_ptr) {
-		mutex_unlock(&rt_entry->lock);
-		mutex_unlock(&routing_table_lock);
 		pr_err("%s: Remote port alloc failed\n", __func__);
 		return NULL;
 	}
 	rport_ptr->port_id = port_id;
 	rport_ptr->node_id = node_id;
-	rport_ptr->restart_state = RESTART_NORMAL;
 	rport_ptr->sec_rule = NULL;
+	rport_ptr->server = NULL;
 	rport_ptr->tx_quota_cnt = 0;
-	mutex_init(&rport_ptr->quota_lock);
+	mutex_init(&rport_ptr->quota_lock_lhb2);
 	INIT_LIST_HEAD(&rport_ptr->resume_tx_port_list);
+	down_write(&rt_entry->lock_lha4);
 	list_add_tail(&rport_ptr->list,
 		      &rt_entry->remote_port_list[key]);
-	mutex_unlock(&rt_entry->lock);
-	mutex_unlock(&routing_table_lock);
+	up_write(&rt_entry->lock_lha4);
 	return rport_ptr;
 }
 
@@ -679,7 +673,7 @@
  * This function deletes all the resume_tx ports associated with a remote port
  * and frees the memory allocated to each resume_tx port.
  *
- * Must be called with rport_ptr->quota_lock locked.
+ * Must be called with rport_ptr->quota_lock_lhb2 locked.
  */
 static void msm_ipc_router_free_resume_tx_port(
 	struct msm_ipc_router_remote_port *rport_ptr)
@@ -704,7 +698,7 @@
  * remote port's resume_tx list. This function is used to ensure that
  * the same port is not added to the remote_port's resume_tx list repeatedly.
  *
- * Must be called with rport_ptr->quota_lock locked.
+ * Must be called with rport_ptr->quota_lock_lhb2 locked.
  */
 static int msm_ipc_router_lookup_resume_tx_port(
 	struct msm_ipc_router_remote_port *rport_ptr, uint32_t port_id)
@@ -729,40 +723,26 @@
  * function sequentially deletes each entry in the resume_tx_port_list of the
  * remote port.
  *
- * Must be called with rport_ptr->quota_lock locked.
+ * Must be called with rport_ptr->quota_lock_lhb2 locked.
  */
 static void post_resume_tx(struct msm_ipc_router_remote_port *rport_ptr,
 						   struct rr_packet *pkt)
 {
 	struct msm_ipc_resume_tx_port *rtx_port, *tmp_rtx_port;
 	struct msm_ipc_port *local_port;
-	struct rr_packet *cloned_pkt;
 
 	list_for_each_entry_safe(rtx_port, tmp_rtx_port,
 				&rport_ptr->resume_tx_port_list, list) {
-		mutex_lock(&local_ports_lock);
 		local_port =
 			msm_ipc_router_lookup_local_port(rtx_port->port_id);
-		if (local_port) {
-			cloned_pkt = clone_pkt(pkt);
-			if (cloned_pkt) {
-				mutex_lock(&local_port->port_rx_q_lock);
-				list_add_tail(&cloned_pkt->list,
-						&local_port->port_rx_q);
-				wake_up(&local_port->port_rx_wait_q);
-				mutex_unlock(&local_port->port_rx_q_lock);
-			} else {
-				pr_err("%s: Clone_pkt failed for %08x:%08x\n",
-					__func__, local_port->this_port.node_id,
-					local_port->this_port.port_id);
-			}
-		}
-		mutex_unlock(&local_ports_lock);
+		if (local_port)
+			post_pkt_to_port(local_port, pkt, 1);
 		list_del(&rtx_port->list);
 		kfree(rtx_port);
 	}
 }
 
+/* Must be called with routing_table_lock_lha3 locked. */
 static void msm_ipc_router_destroy_remote_port(
 	struct msm_ipc_router_remote_port *rport_ptr)
 {
@@ -773,21 +753,18 @@
 		return;
 
 	node_id = rport_ptr->node_id;
-	mutex_lock(&routing_table_lock);
 	rt_entry = lookup_routing_table(node_id);
 	if (!rt_entry) {
-		mutex_unlock(&routing_table_lock);
 		pr_err("%s: Node %d is not up\n", __func__, node_id);
 		return;
 	}
-	mutex_lock(&rport_ptr->quota_lock);
-	msm_ipc_router_free_resume_tx_port(rport_ptr);
-	mutex_unlock(&rport_ptr->quota_lock);
-	mutex_lock(&rt_entry->lock);
+	down_write(&rt_entry->lock_lha4);
 	list_del(&rport_ptr->list);
+	up_write(&rt_entry->lock_lha4);
+	mutex_lock(&rport_ptr->quota_lock_lhb2);
+	msm_ipc_router_free_resume_tx_port(rport_ptr);
+	mutex_unlock(&rport_ptr->quota_lock_lhb2);
 	kfree(rport_ptr);
-	mutex_unlock(&rt_entry->lock);
-	mutex_unlock(&routing_table_lock);
 	return;
 }
 
@@ -800,7 +777,7 @@
  *
  * @return: If found Pointer to server structure, else NULL.
  *
- * Note1: Lock the server_list_lock before accessing this function.
+ * Note1: Lock the server_list_lock_lha2 before accessing this function.
  * Note2: If the <node_id:port_id> are <0:0>, then the lookup is restricted
  *        to <service:instance>. Used only when a client wants to send a
  *        message to any QMI server.
@@ -848,7 +825,7 @@
  * This function adds the server info to the hash table. If the same
  * server(i.e. <service_id:instance_id>) is hosted in different nodes,
  * they are maintained as list of "server_port" under "server" structure.
- * Note: Lock the server_list_lock before accessing this function.
+ * Note: Lock the server_list_lock_lha2 before accessing this function.
  */
 static struct msm_ipc_server *msm_ipc_router_create_server(
 					uint32_t service,
@@ -914,7 +891,7 @@
  * from the server structure. If the server_port list under server structure
  * is empty after removal, then remove the server structure from the server
  * hash table.
- * Note: Lock the server_list_lock before accessing this function.
+ * Note: Lock the server_list_lock_lha2 before accessing this function.
  */
 static void msm_ipc_router_destroy_server(struct msm_ipc_server *server,
 					  uint32_t node_id, uint32_t port_id)
@@ -1009,9 +986,9 @@
 	pkt->pkt_fragment_q = pkt_fragment_q;
 	pkt->length = pkt_size;
 
-	mutex_lock(&xprt_info->tx_lock);
+	mutex_lock(&xprt_info->tx_lock_lhb2);
 	ret = xprt_info->xprt->write(pkt, pkt_size, xprt_info->xprt);
-	mutex_unlock(&xprt_info->tx_lock);
+	mutex_unlock(&xprt_info->tx_lock_lhb2);
 
 	release_pkt(pkt);
 	return ret;
@@ -1146,11 +1123,11 @@
 {
 	struct msm_ipc_router_xprt_info *xprt_info;
 
-	mutex_lock(&xprt_info_list_lock);
+	down_read(&xprt_info_list_lock_lha5);
 	list_for_each_entry(xprt_info, &xprt_info_list, list) {
 		msm_ipc_router_send_control_msg(xprt_info, ctl);
 	}
-	mutex_unlock(&xprt_info_list_lock);
+	up_read(&xprt_info_list_lock_lha5);
 
 	return 0;
 }
@@ -1163,12 +1140,12 @@
 	if (!xprt_info || !ctl)
 		return -EINVAL;
 
-	mutex_lock(&xprt_info_list_lock);
+	down_read(&xprt_info_list_lock_lha5);
 	list_for_each_entry(fwd_xprt_info, &xprt_info_list, list) {
 		if (xprt_info->xprt->link_id != fwd_xprt_info->xprt->link_id)
 			msm_ipc_router_send_control_msg(fwd_xprt_info, ctl);
 	}
-	mutex_unlock(&xprt_info_list_lock);
+	up_read(&xprt_info_list_lock_lha5);
 
 	return 0;
 }
@@ -1181,15 +1158,15 @@
 	if (!xprt_info || !pkt)
 		return -EINVAL;
 
-	mutex_lock(&xprt_info_list_lock);
+	down_read(&xprt_info_list_lock_lha5);
 	list_for_each_entry(fwd_xprt_info, &xprt_info_list, list) {
-		mutex_lock(&fwd_xprt_info->tx_lock);
+		mutex_lock(&fwd_xprt_info->tx_lock_lhb2);
 		if (xprt_info->xprt->link_id != fwd_xprt_info->xprt->link_id)
 			fwd_xprt_info->xprt->write(pkt, pkt->length,
 						   fwd_xprt_info->xprt);
-		mutex_unlock(&fwd_xprt_info->tx_lock);
+		mutex_unlock(&fwd_xprt_info->tx_lock_lhb2);
 	}
-	mutex_unlock(&xprt_info_list_lock);
+	up_read(&xprt_info_list_lock_lha5);
 	return 0;
 }
 
@@ -1201,6 +1178,7 @@
 	struct rr_header *hdr;
 	struct msm_ipc_router_xprt_info *fwd_xprt_info;
 	struct msm_ipc_routing_table_entry *rt_entry;
+	int ret = 0;
 
 	if (!xprt_info || !pkt)
 		return -EINVAL;
@@ -1211,38 +1189,34 @@
 
 	hdr = (struct rr_header *)head_pkt->data;
 	dst_node_id = hdr->dst_node_id;
-	mutex_lock(&routing_table_lock);
+	down_read(&routing_table_lock_lha3);
 	rt_entry = lookup_routing_table(dst_node_id);
 	if (!(rt_entry) || !(rt_entry->xprt_info)) {
-		mutex_unlock(&routing_table_lock);
+		up_read(&routing_table_lock_lha3);
 		pr_err("%s: Routing table not initialized\n", __func__);
 		return -ENODEV;
 	}
 
-	mutex_lock(&rt_entry->lock);
+	down_read(&rt_entry->lock_lha4);
 	fwd_xprt_info = rt_entry->xprt_info;
-	mutex_lock(&fwd_xprt_info->tx_lock);
 	if (xprt_info->remote_node_id == fwd_xprt_info->remote_node_id) {
-		mutex_unlock(&fwd_xprt_info->tx_lock);
-		mutex_unlock(&rt_entry->lock);
-		mutex_unlock(&routing_table_lock);
 		pr_err("%s: Discarding Command to route back\n", __func__);
-		return -EINVAL;
+		ret = -EINVAL;
+		goto fwd_msg_out;
 	}
 
 	if (xprt_info->xprt->link_id == fwd_xprt_info->xprt->link_id) {
-		mutex_unlock(&fwd_xprt_info->tx_lock);
-		mutex_unlock(&rt_entry->lock);
-		mutex_unlock(&routing_table_lock);
 		pr_err("%s: DST in the same cluster\n", __func__);
-		return 0;
+		goto fwd_msg_out;
 	}
+	mutex_lock(&fwd_xprt_info->tx_lock_lhb2);
 	fwd_xprt_info->xprt->write(pkt, pkt->length, fwd_xprt_info->xprt);
-	mutex_unlock(&fwd_xprt_info->tx_lock);
-	mutex_unlock(&rt_entry->lock);
-	mutex_unlock(&routing_table_lock);
+	mutex_unlock(&fwd_xprt_info->tx_lock_lhb2);
+fwd_msg_out:
+	up_read(&rt_entry->lock_lha4);
+	up_read(&routing_table_lock_lha3);
 
-	return 0;
+	return ret;
 }
 
 static int msm_ipc_router_send_remove_client(struct comm_mode_info *mode_info,
@@ -1266,14 +1240,14 @@
 	msg.cli.port_id = port_id;
 
 	if ((mode == SINGLE_LINK_MODE) && xprt_info) {
-		mutex_lock(&xprt_info_list_lock);
+		down_read(&xprt_info_list_lock_lha5);
 		list_for_each_entry(tmp_xprt_info, &xprt_info_list, list) {
 			if (tmp_xprt_info != xprt_info)
 				continue;
 			msm_ipc_router_send_control_msg(tmp_xprt_info, &msg);
 			break;
 		}
-		mutex_unlock(&xprt_info_list_lock);
+		up_read(&xprt_info_list_lock_lha5);
 	} else if ((mode == SINGLE_LINK_MODE) && !xprt_info) {
 		broadcast_ctl_msg_locally(&msg);
 	} else if (mode == MULTI_LINK_MODE) {
@@ -1306,141 +1280,52 @@
 	return;
 }
 
-static void reset_remote_port_info(uint32_t node_id, uint32_t port_id)
+static void cleanup_rmt_server(struct msm_ipc_router_xprt_info *xprt_info,
+			       struct msm_ipc_router_remote_port *rport_ptr)
 {
-	struct msm_ipc_router_remote_port *rport_ptr;
-
-	rport_ptr = msm_ipc_router_lookup_remote_port(node_id, port_id);
-	if (!rport_ptr) {
-		pr_err("%s: No such remote port %08x:%08x\n",
-			__func__, node_id, port_id);
-		return;
-	}
-	mutex_lock(&rport_ptr->quota_lock);
-	rport_ptr->restart_state = RESTART_PEND;
-	msm_ipc_router_free_resume_tx_port(rport_ptr);
-	mutex_unlock(&rport_ptr->quota_lock);
-	return;
-}
-
-static void msm_ipc_cleanup_remote_server_info(
-		struct msm_ipc_router_xprt_info *xprt_info)
-{
-	struct msm_ipc_server *svr, *tmp_svr;
-	struct msm_ipc_server_port *svr_port, *tmp_svr_port;
-	int i;
 	union rr_control_msg ctl;
+	struct msm_ipc_server *server = rport_ptr->server;
 
-	if (!xprt_info) {
-		pr_err("%s: Invalid xprt_info\n", __func__);
-		return;
-	}
-
+	D("Remove server %08x:%08x - %08x:%08x",
+	   server->name.service, server->name.instance,
+	   rport_ptr->node_id, rport_ptr->port_id);
 	ctl.cmd = IPC_ROUTER_CTRL_CMD_REMOVE_SERVER;
-	mutex_lock(&server_list_lock);
-	for (i = 0; i < SRV_HASH_SIZE; i++) {
-		list_for_each_entry_safe(svr, tmp_svr, &server_list[i], list) {
-			ctl.srv.service = svr->name.service;
-			ctl.srv.instance = svr->name.instance;
-			list_for_each_entry_safe(svr_port, tmp_svr_port,
-					 &svr->server_port_list, list) {
-				if (svr_port->xprt_info != xprt_info)
-					continue;
-				D("Remove server %08x:%08x - %08x:%08x",
-				   ctl.srv.service, ctl.srv.instance,
-				   svr_port->server_addr.node_id,
-				   svr_port->server_addr.port_id);
-				reset_remote_port_info(
-					svr_port->server_addr.node_id,
-					svr_port->server_addr.port_id);
-				ctl.srv.node_id = svr_port->server_addr.node_id;
-				ctl.srv.port_id = svr_port->server_addr.port_id;
-				relay_ctl_msg(xprt_info, &ctl);
-				broadcast_ctl_msg_locally(&ctl);
-				platform_device_unregister(&svr_port->pdev);
-				list_del(&svr_port->list);
-				kfree(svr_port);
-			}
-			if (list_empty(&svr->server_port_list)) {
-				list_del(&svr->list);
-				kfree(svr);
-			}
-		}
-	}
-	mutex_unlock(&server_list_lock);
+	ctl.srv.service = server->name.service;
+	ctl.srv.instance = server->name.instance;
+	ctl.srv.node_id = rport_ptr->node_id;
+	ctl.srv.port_id = rport_ptr->port_id;
+	relay_ctl_msg(xprt_info, &ctl);
+	broadcast_ctl_msg_locally(&ctl);
+	msm_ipc_router_destroy_server(server,
+			rport_ptr->node_id, rport_ptr->port_id);
 }
 
-static void msm_ipc_cleanup_remote_client_info(
-		struct msm_ipc_router_xprt_info *xprt_info)
+static void cleanup_rmt_ports(struct msm_ipc_router_xprt_info *xprt_info,
+			      struct msm_ipc_routing_table_entry *rt_entry)
 {
-	struct msm_ipc_routing_table_entry *rt_entry;
-	struct msm_ipc_router_remote_port *rport_ptr;
-	int i, j;
-	union rr_control_msg ctl;
-
-	if (!xprt_info) {
-		pr_err("%s: Invalid xprt_info\n", __func__);
-		return;
-	}
-
-	ctl.cmd = IPC_ROUTER_CTRL_CMD_REMOVE_CLIENT;
-	mutex_lock(&routing_table_lock);
-	for (i = 0; i < RT_HASH_SIZE; i++) {
-		list_for_each_entry(rt_entry, &routing_table[i], list) {
-			mutex_lock(&rt_entry->lock);
-			if (rt_entry->xprt_info != xprt_info) {
-				mutex_unlock(&rt_entry->lock);
-				continue;
-			}
-			for (j = 0; j < RP_HASH_SIZE; j++) {
-				list_for_each_entry(rport_ptr,
-					&rt_entry->remote_port_list[j], list) {
-					if (rport_ptr->restart_state ==
-						RESTART_PEND)
-						continue;
-					mutex_lock(&rport_ptr->quota_lock);
-					rport_ptr->restart_state = RESTART_PEND;
-					msm_ipc_router_free_resume_tx_port(
-								rport_ptr);
-					mutex_unlock(&rport_ptr->quota_lock);
-					ctl.cli.node_id = rport_ptr->node_id;
-					ctl.cli.port_id = rport_ptr->port_id;
-					broadcast_ctl_msg_locally(&ctl);
-				}
-			}
-			mutex_unlock(&rt_entry->lock);
-		}
-	}
-	mutex_unlock(&routing_table_lock);
-}
-
-static void msm_ipc_cleanup_remote_port_info(uint32_t node_id)
-{
-	struct msm_ipc_routing_table_entry *rt_entry, *tmp_rt_entry;
 	struct msm_ipc_router_remote_port *rport_ptr, *tmp_rport_ptr;
-	int i, j;
+	union rr_control_msg ctl;
+	int j;
 
-	mutex_lock(&routing_table_lock);
-	for (i = 0; i < RT_HASH_SIZE; i++) {
-		list_for_each_entry_safe(rt_entry, tmp_rt_entry,
-					 &routing_table[i], list) {
-			mutex_lock(&rt_entry->lock);
-			if (rt_entry->neighbor_node_id != node_id) {
-				mutex_unlock(&rt_entry->lock);
-				continue;
-			}
-			for (j = 0; j < RP_HASH_SIZE; j++) {
-				list_for_each_entry_safe(rport_ptr,
-					tmp_rport_ptr,
-					&rt_entry->remote_port_list[j], list) {
-					list_del(&rport_ptr->list);
-					kfree(rport_ptr);
-				}
-			}
-			mutex_unlock(&rt_entry->lock);
+	for (j = 0; j < RP_HASH_SIZE; j++) {
+		list_for_each_entry_safe(rport_ptr, tmp_rport_ptr,
+				&rt_entry->remote_port_list[j], list) {
+			list_del(&rport_ptr->list);
+			mutex_lock(&rport_ptr->quota_lock_lhb2);
+			msm_ipc_router_free_resume_tx_port(rport_ptr);
+			mutex_unlock(&rport_ptr->quota_lock_lhb2);
+
+			if (rport_ptr->server)
+				cleanup_rmt_server(xprt_info, rport_ptr);
+
+			ctl.cmd = IPC_ROUTER_CTRL_CMD_REMOVE_CLIENT;
+			ctl.cli.node_id = rport_ptr->node_id;
+			ctl.cli.port_id = rport_ptr->port_id;
+			relay_ctl_msg(xprt_info, &ctl);
+			broadcast_ctl_msg_locally(&ctl);
+			kfree(rport_ptr);
 		}
 	}
-	mutex_unlock(&routing_table_lock);
 }
 
 static void msm_ipc_cleanup_routing_table(
@@ -1454,29 +1339,22 @@
 		return;
 	}
 
-	mutex_lock(&routing_table_lock);
+	down_write(&server_list_lock_lha2);
+	down_write(&routing_table_lock_lha3);
 	for (i = 0; i < RT_HASH_SIZE; i++) {
 		list_for_each_entry(rt_entry, &routing_table[i], list) {
-			mutex_lock(&rt_entry->lock);
-			if (rt_entry->xprt_info == xprt_info)
-				rt_entry->xprt_info = NULL;
-			mutex_unlock(&rt_entry->lock);
+			down_write(&rt_entry->lock_lha4);
+			if (rt_entry->xprt_info != xprt_info) {
+				up_write(&rt_entry->lock_lha4);
+				continue;
+			}
+			cleanup_rmt_ports(xprt_info, rt_entry);
+			rt_entry->xprt_info = NULL;
+			up_write(&rt_entry->lock_lha4);
 		}
 	}
-	mutex_unlock(&routing_table_lock);
-}
-
-static void modem_reset_cleanup(struct msm_ipc_router_xprt_info *xprt_info)
-{
-
-	if (!xprt_info) {
-		pr_err("%s: Invalid xprt_info\n", __func__);
-		return;
-	}
-
-	msm_ipc_cleanup_remote_server_info(xprt_info);
-	msm_ipc_cleanup_remote_client_info(xprt_info);
-	msm_ipc_cleanup_routing_table(xprt_info);
+	up_write(&routing_table_lock_lha3);
+	up_write(&server_list_lock_lha2);
 }
 
 /**
@@ -1492,6 +1370,7 @@
 	struct msm_ipc_server_port *server_port;
 	struct msm_ipc_router_remote_port *rport_ptr = NULL;
 
+	down_read(&routing_table_lock_lha3);
 	list_for_each_entry(server_port, &server->server_port_list, list) {
 		rport_ptr = msm_ipc_router_lookup_remote_port(
 				server_port->server_addr.node_id,
@@ -1500,6 +1379,7 @@
 			continue;
 		rport_ptr->sec_rule = rule;
 	}
+	up_read(&routing_table_lock_lha3);
 	server->synced_sec_rule = 1;
 }
 
@@ -1519,7 +1399,7 @@
 	int key = (service & (SRV_HASH_SIZE - 1));
 	struct msm_ipc_server *server;
 
-	mutex_lock(&server_list_lock);
+	down_write(&server_list_lock_lha2);
 	list_for_each_entry(server, &server_list[key], list) {
 		if (server->name.service != service)
 			continue;
@@ -1538,7 +1418,7 @@
 
 		sync_sec_rule(server, rule);
 	}
-	mutex_unlock(&server_list_lock);
+	up_write(&server_list_lock_lha2);
 }
 
 /**
@@ -1556,7 +1436,7 @@
 	int key;
 	struct msm_ipc_server *server;
 
-	mutex_lock(&server_list_lock);
+	down_write(&server_list_lock_lha2);
 	for (key = 0; key < SRV_HASH_SIZE; key++) {
 		list_for_each_entry(server, &server_list[key], list) {
 			if (server->synced_sec_rule)
@@ -1565,7 +1445,7 @@
 			sync_sec_rule(server, rule);
 		}
 	}
-	mutex_unlock(&server_list_lock);
+	up_write(&server_list_lock_lha2);
 }
 
 static int process_hello_msg(struct msm_ipc_router_xprt_info *xprt_info,
@@ -1588,25 +1468,22 @@
 	 * an entry. Update the entry with the Node ID that it corresponds
 	 * to and the XPRT through which it can be reached.
 	 */
-	mutex_lock(&routing_table_lock);
+	down_write(&routing_table_lock_lha3);
 	rt_entry = lookup_routing_table(hdr->src_node_id);
 	if (!rt_entry) {
 		rt_entry = alloc_routing_table_entry(hdr->src_node_id);
 		if (!rt_entry) {
-			mutex_unlock(&routing_table_lock);
+			up_write(&routing_table_lock_lha3);
 			pr_err("%s: rt_entry allocation failed\n", __func__);
 			return -ENOMEM;
 		}
 		add_routing_table_entry(rt_entry);
 	}
-	mutex_lock(&rt_entry->lock);
+	down_write(&rt_entry->lock_lha4);
 	rt_entry->neighbor_node_id = xprt_info->remote_node_id;
 	rt_entry->xprt_info = xprt_info;
-	mutex_unlock(&rt_entry->lock);
-	mutex_unlock(&routing_table_lock);
-
-	/* Cleanup any remote ports, if the node is coming out of reset */
-	msm_ipc_cleanup_remote_port_info(xprt_info->remote_node_id);
+	up_write(&rt_entry->lock_lha4);
+	up_write(&routing_table_lock_lha3);
 
 	/* Send a reply HELLO message */
 	memset(&ctl, 0, sizeof(ctl));
@@ -1622,8 +1499,8 @@
 	 * Send list of servers from the local node and from nodes
 	 * outside the mesh network in which this XPRT is part of.
 	 */
-	mutex_lock(&server_list_lock);
-	mutex_lock(&routing_table_lock);
+	down_read(&server_list_lock_lha2);
+	down_read(&routing_table_lock_lha3);
 	for (i = 0; i < RT_HASH_SIZE; i++) {
 		list_for_each_entry(rt_entry, &routing_table[i], list) {
 			if ((rt_entry->node_id != IPC_ROUTER_NID_LOCAL) &&
@@ -1634,28 +1511,182 @@
 			rc = msm_ipc_router_send_server_list(rt_entry->node_id,
 							     xprt_info);
 			if (rc < 0) {
-				mutex_unlock(&routing_table_lock);
-				mutex_unlock(&server_list_lock);
+				up_read(&routing_table_lock_lha3);
+				up_read(&server_list_lock_lha2);
 				return rc;
 			}
 		}
 	}
-	mutex_unlock(&routing_table_lock);
-	mutex_unlock(&server_list_lock);
+	up_read(&routing_table_lock_lha3);
+	up_read(&server_list_lock_lha2);
 	RR("HELLO message processed\n");
 	return rc;
 }
 
+static int process_resume_tx_msg(union rr_control_msg *msg,
+				 struct rr_packet *pkt)
+{
+	struct msm_ipc_router_remote_port *rport_ptr;
+	int ret = 0;
+
+	RR("o RESUME_TX id=%d:%08x\n", msg->cli.node_id, msg->cli.port_id);
+
+	down_read(&local_ports_lock_lha2);
+	down_read(&routing_table_lock_lha3);
+	rport_ptr = msm_ipc_router_lookup_remote_port(msg->cli.node_id,
+						      msg->cli.port_id);
+	if (!rport_ptr) {
+		pr_err("%s: Unable to resume client\n", __func__);
+		ret = -ENODEV;
+		goto prtm_out;
+	}
+	mutex_lock(&rport_ptr->quota_lock_lhb2);
+	rport_ptr->tx_quota_cnt = 0;
+	post_resume_tx(rport_ptr, pkt);
+	mutex_unlock(&rport_ptr->quota_lock_lhb2);
+prtm_out:
+	up_read(&routing_table_lock_lha3);
+	up_read(&local_ports_lock_lha2);
+	return 0;
+}
+
+static int process_new_server_msg(struct msm_ipc_router_xprt_info *xprt_info,
+			union rr_control_msg *msg, struct rr_packet *pkt)
+{
+	struct msm_ipc_routing_table_entry *rt_entry;
+	struct msm_ipc_server *server;
+	struct msm_ipc_router_remote_port *rport_ptr;
+
+	if (msg->srv.instance == 0) {
+		pr_err("%s: Server %08x create rejected, version = 0\n",
+			__func__, msg->srv.service);
+		return -EINVAL;
+	}
+
+	RR("o NEW_SERVER id=%d:%08x service=%08x:%08x\n", msg->srv.node_id,
+	    msg->srv.port_id, msg->srv.service, msg->srv.instance);
+	/*
+	 * Find the entry from Routing Table corresponding to Node ID.
+	 * Under SSR, an entry will be found. When the subsystem hosting
+	 * service is not adjacent, an entry will not be found and hence
+	 * allocate an entry. Update the entry with the Node ID that it
+	 * corresponds to and the XPRT through which it can be reached.
+	 */
+	down_write(&routing_table_lock_lha3);
+	rt_entry = lookup_routing_table(msg->srv.node_id);
+	if (!rt_entry) {
+		rt_entry = alloc_routing_table_entry(msg->srv.node_id);
+		if (!rt_entry) {
+			up_write(&routing_table_lock_lha3);
+			pr_err("%s: rt_entry allocation failed\n", __func__);
+			return -ENOMEM;
+		}
+		down_write(&rt_entry->lock_lha4);
+		rt_entry->neighbor_node_id = xprt_info->remote_node_id;
+		rt_entry->xprt_info = xprt_info;
+		up_write(&rt_entry->lock_lha4);
+		add_routing_table_entry(rt_entry);
+	}
+	up_write(&routing_table_lock_lha3);
+
+	/*
+	 * If the service does not exist already in the database, create and
+	 * store the service info. Create a remote port structure in which
+	 * the service is hosted and cache the security rule for the service
+	 * in that remote port structure.
+	 */
+	down_write(&server_list_lock_lha2);
+	server = msm_ipc_router_lookup_server(msg->srv.service,
+			msg->srv.instance, msg->srv.node_id, msg->srv.port_id);
+	if (!server) {
+		server = msm_ipc_router_create_server(
+				msg->srv.service, msg->srv.instance,
+				msg->srv.node_id, msg->srv.port_id, xprt_info);
+		if (!server) {
+			up_write(&server_list_lock_lha2);
+			pr_err("%s: Server Create failed\n", __func__);
+			return -ENOMEM;
+		}
+
+		down_read(&routing_table_lock_lha3);
+		if (!msm_ipc_router_lookup_remote_port(
+				msg->srv.node_id, msg->srv.port_id)) {
+			rport_ptr = msm_ipc_router_create_remote_port(
+					msg->srv.node_id, msg->srv.port_id);
+			if (!rport_ptr) {
+				up_read(&routing_table_lock_lha3);
+				up_write(&server_list_lock_lha2);
+				return -ENOMEM;
+			}
+			rport_ptr->server = server;
+			rport_ptr->sec_rule = msm_ipc_get_security_rule(
+						msg->srv.service,
+						msg->srv.instance);
+		}
+		up_read(&routing_table_lock_lha3);
+	}
+	up_write(&server_list_lock_lha2);
+
+	/*
+	 * Relay the new server message to other subsystems that do not belong
+	 * to the cluster from which this message is received. Notify the
+	 * local clients waiting for this service.
+	 */
+	relay_msg(xprt_info, pkt);
+	post_control_ports(pkt);
+	return 0;
+}
+
+static int process_rmv_server_msg(struct msm_ipc_router_xprt_info *xprt_info,
+			union rr_control_msg *msg, struct rr_packet *pkt)
+{
+	struct msm_ipc_server *server;
+
+	RR("o REMOVE_SERVER service=%08x:%d\n",
+	    msg->srv.service, msg->srv.instance);
+	down_write(&server_list_lock_lha2);
+	server = msm_ipc_router_lookup_server(msg->srv.service,
+			msg->srv.instance, msg->srv.node_id, msg->srv.port_id);
+	if (server) {
+		msm_ipc_router_destroy_server(server, msg->srv.node_id,
+					      msg->srv.port_id);
+		/*
+		 * Relay the new server message to other subsystems that do not
+		 * belong to the cluster from which this message is received.
+		 * Notify the local clients communicating with the service.
+		 */
+		relay_msg(xprt_info, pkt);
+		post_control_ports(pkt);
+	}
+	up_write(&server_list_lock_lha2);
+	return 0;
+}
+
+static int process_rmv_client_msg(struct msm_ipc_router_xprt_info *xprt_info,
+			union rr_control_msg *msg, struct rr_packet *pkt)
+{
+	struct msm_ipc_router_remote_port *rport_ptr;
+
+	RR("o REMOVE_CLIENT id=%d:%08x\n", msg->cli.node_id, msg->cli.port_id);
+	down_write(&routing_table_lock_lha3);
+	rport_ptr = msm_ipc_router_lookup_remote_port(msg->cli.node_id,
+						      msg->cli.port_id);
+	if (rport_ptr)
+		msm_ipc_router_destroy_remote_port(rport_ptr);
+	up_write(&routing_table_lock_lha3);
+
+	relay_msg(xprt_info, pkt);
+	post_control_ports(pkt);
+	return 0;
+}
+
 static int process_control_msg(struct msm_ipc_router_xprt_info *xprt_info,
 			       struct rr_packet *pkt)
 {
 	union rr_control_msg *msg;
-	struct msm_ipc_router_remote_port *rport_ptr;
 	int rc = 0;
 	struct sk_buff *temp_ptr;
 	struct rr_header *hdr;
-	struct msm_ipc_server *server;
-	struct msm_ipc_routing_table_entry *rt_entry;
 
 	if (pkt->length != (IPC_ROUTER_HDR_SIZE + sizeof(*msg))) {
 		pr_err("%s: r2r msg size %d != %d\n", __func__, pkt->length,
@@ -1679,115 +1710,17 @@
 	case IPC_ROUTER_CTRL_CMD_HELLO:
 		rc = process_hello_msg(xprt_info, hdr);
 		break;
-
 	case IPC_ROUTER_CTRL_CMD_RESUME_TX:
-		RR("o RESUME_TX id=%d:%08x\n",
-		   msg->cli.node_id, msg->cli.port_id);
-
-		rport_ptr = msm_ipc_router_lookup_remote_port(msg->cli.node_id,
-							msg->cli.port_id);
-		if (!rport_ptr) {
-			pr_err("%s: Unable to resume client\n", __func__);
-			break;
-		}
-		mutex_lock(&rport_ptr->quota_lock);
-		rport_ptr->tx_quota_cnt = 0;
-		post_resume_tx(rport_ptr, pkt);
-		mutex_unlock(&rport_ptr->quota_lock);
+		rc = process_resume_tx_msg(msg, pkt);
 		break;
-
 	case IPC_ROUTER_CTRL_CMD_NEW_SERVER:
-		if (msg->srv.instance == 0) {
-			pr_err(
-			"rpcrouter: Server create rejected, version = 0, "
-			"service = %08x\n", msg->srv.service);
-			break;
-		}
-
-		RR("o NEW_SERVER id=%d:%08x service=%08x:%08x\n",
-		   msg->srv.node_id, msg->srv.port_id,
-		   msg->srv.service, msg->srv.instance);
-
-		mutex_lock(&routing_table_lock);
-		rt_entry = lookup_routing_table(msg->srv.node_id);
-		if (!rt_entry) {
-			rt_entry = alloc_routing_table_entry(msg->srv.node_id);
-			if (!rt_entry) {
-				mutex_unlock(&routing_table_lock);
-				pr_err("%s: rt_entry allocation failed\n",
-					__func__);
-				return -ENOMEM;
-			}
-			mutex_lock(&rt_entry->lock);
-			rt_entry->neighbor_node_id = xprt_info->remote_node_id;
-			rt_entry->xprt_info = xprt_info;
-			mutex_unlock(&rt_entry->lock);
-			add_routing_table_entry(rt_entry);
-		}
-		mutex_unlock(&routing_table_lock);
-
-		mutex_lock(&server_list_lock);
-		server = msm_ipc_router_lookup_server(msg->srv.service,
-						      msg->srv.instance,
-						      msg->srv.node_id,
-						      msg->srv.port_id);
-		if (!server) {
-			server = msm_ipc_router_create_server(
-				msg->srv.service, msg->srv.instance,
-				msg->srv.node_id, msg->srv.port_id, xprt_info);
-			if (!server) {
-				mutex_unlock(&server_list_lock);
-				pr_err("%s: Server Create failed\n", __func__);
-				return -ENOMEM;
-			}
-
-			if (!msm_ipc_router_lookup_remote_port(
-					msg->srv.node_id, msg->srv.port_id)) {
-				rport_ptr = msm_ipc_router_create_remote_port(
-					msg->srv.node_id, msg->srv.port_id);
-				if (!rport_ptr)
-					pr_err("%s: Remote port create "
-					       "failed\n", __func__);
-				else
-					rport_ptr->sec_rule =
-						msm_ipc_get_security_rule(
-						msg->srv.service,
-						msg->srv.instance);
-			}
-			wake_up(&newserver_wait);
-		}
-		mutex_unlock(&server_list_lock);
-
-		relay_msg(xprt_info, pkt);
-		post_control_ports(pkt);
+		rc = process_new_server_msg(xprt_info, msg, pkt);
 		break;
 	case IPC_ROUTER_CTRL_CMD_REMOVE_SERVER:
-		RR("o REMOVE_SERVER service=%08x:%d\n",
-		   msg->srv.service, msg->srv.instance);
-		mutex_lock(&server_list_lock);
-		server = msm_ipc_router_lookup_server(msg->srv.service,
-						      msg->srv.instance,
-						      msg->srv.node_id,
-						      msg->srv.port_id);
-		if (server) {
-			msm_ipc_router_destroy_server(server,
-						      msg->srv.node_id,
-						      msg->srv.port_id);
-			relay_msg(xprt_info, pkt);
-			post_control_ports(pkt);
-		}
-		mutex_unlock(&server_list_lock);
+		rc = process_rmv_server_msg(xprt_info, msg, pkt);
 		break;
 	case IPC_ROUTER_CTRL_CMD_REMOVE_CLIENT:
-		RR("o REMOVE_CLIENT id=%d:%08x\n",
-		    msg->cli.node_id, msg->cli.port_id);
-		rport_ptr = msm_ipc_router_lookup_remote_port(msg->cli.node_id,
-							msg->cli.port_id);
-		if (rport_ptr)
-			msm_ipc_router_destroy_remote_port(rport_ptr);
-
-		relay_msg(xprt_info, pkt);
-		post_control_ports(pkt);
+		rc = process_rmv_client_msg(xprt_info, msg, pkt);
 		break;
 	case IPC_ROUTER_CTRL_CMD_PING:
 		/* No action needed for ping messages received */
@@ -1875,19 +1808,19 @@
 		resume_tx_node_id = hdr->dst_node_id;
 		resume_tx_port_id = hdr->dst_port_id;
 
-		rport_ptr = msm_ipc_router_lookup_remote_port(hdr->src_node_id,
-						      hdr->src_port_id);
-
-		mutex_lock(&local_ports_lock);
+		down_read(&local_ports_lock_lha2);
 		port_ptr = msm_ipc_router_lookup_local_port(hdr->dst_port_id);
 		if (!port_ptr) {
 			pr_err("%s: No local port id %08x\n", __func__,
 				hdr->dst_port_id);
-			mutex_unlock(&local_ports_lock);
+			up_read(&local_ports_lock_lha2);
 			release_pkt(pkt);
 			goto process_done;
 		}
 
+		down_read(&routing_table_lock_lha3);
+		rport_ptr = msm_ipc_router_lookup_remote_port(hdr->src_node_id,
+							hdr->src_port_id);
 		if (!rport_ptr) {
 			rport_ptr = msm_ipc_router_create_remote_port(
 							hdr->src_node_id,
@@ -1896,20 +1829,14 @@
 				pr_err("%s: Rmt Prt %08x:%08x create failed\n",
 					__func__, hdr->src_node_id,
 					hdr->src_port_id);
-				mutex_unlock(&local_ports_lock);
+				up_read(&routing_table_lock_lha3);
+				up_read(&local_ports_lock_lha2);
 				goto process_done;
 			}
 		}
-
-		mutex_lock(&port_ptr->port_rx_q_lock);
-		wake_lock(&port_ptr->port_rx_wake_lock);
-		list_add_tail(&pkt->list, &port_ptr->port_rx_q);
-		wake_up(&port_ptr->port_rx_wait_q);
-		if (port_ptr->notify)
-			port_ptr->notify(MSM_IPC_ROUTER_READ_CB,
-					 port_ptr->priv);
-		mutex_unlock(&port_ptr->port_rx_q_lock);
-		mutex_unlock(&local_ports_lock);
+		up_read(&routing_table_lock_lha3);
+		post_pkt_to_port(port_ptr, pkt, 0);
+		up_read(&local_ports_lock_lha2);
 
 process_done:
 		if (resume_tx) {
@@ -1945,13 +1872,13 @@
 	if (name->addrtype != MSM_IPC_ADDR_NAME)
 		return -EINVAL;
 
-	mutex_lock(&server_list_lock);
+	down_write(&server_list_lock_lha2);
 	server = msm_ipc_router_lookup_server(name->addr.port_name.service,
 					      name->addr.port_name.instance,
 					      IPC_ROUTER_NID_LOCAL,
 					      port_ptr->this_port.port_id);
 	if (server) {
-		mutex_unlock(&server_list_lock);
+		up_write(&server_list_lock_lha2);
 		pr_err("%s: Server already present\n", __func__);
 		return -EINVAL;
 	}
@@ -1962,7 +1889,7 @@
 					      port_ptr->this_port.port_id,
 					      NULL);
 	if (!server) {
-		mutex_unlock(&server_list_lock);
+		up_write(&server_list_lock_lha2);
 		pr_err("%s: Server Creation failed\n", __func__);
 		return -EINVAL;
 	}
@@ -1972,7 +1899,7 @@
 	ctl.srv.instance = server->name.instance;
 	ctl.srv.node_id = IPC_ROUTER_NID_LOCAL;
 	ctl.srv.port_id = port_ptr->this_port.port_id;
-	mutex_unlock(&server_list_lock);
+	up_write(&server_list_lock_lha2);
 	broadcast_ctl_msg(&ctl);
 	spin_lock_irqsave(&port_ptr->port_lock, flags);
 	port_ptr->type = SERVER_PORT;
@@ -2004,13 +1931,13 @@
 		return -EINVAL;
 	}
 
-	mutex_lock(&server_list_lock);
+	down_write(&server_list_lock_lha2);
 	server = msm_ipc_router_lookup_server(port_ptr->port_name.service,
 					      port_ptr->port_name.instance,
 					      port_ptr->this_port.node_id,
 					      port_ptr->this_port.port_id);
 	if (!server) {
-		mutex_unlock(&server_list_lock);
+		up_write(&server_list_lock_lha2);
 		pr_err("%s: Server lookup failed\n", __func__);
 		return -ENODEV;
 	}
@@ -2022,7 +1949,7 @@
 	ctl.srv.port_id = port_ptr->this_port.port_id;
 	msm_ipc_router_destroy_server(server, port_ptr->this_port.node_id,
 				      port_ptr->this_port.port_id);
-	mutex_unlock(&server_list_lock);
+	up_write(&server_list_lock_lha2);
 	broadcast_ctl_msg(&ctl);
 	spin_lock_irqsave(&port_ptr->port_lock, flags);
 	port_ptr->type = CLIENT_PORT;
@@ -2073,23 +2000,19 @@
 	hdr->dst_port_id = port_id;
 	pkt->length += IPC_ROUTER_HDR_SIZE;
 
-	mutex_lock(&local_ports_lock);
+	down_read(&local_ports_lock_lha2);
 	port_ptr = msm_ipc_router_lookup_local_port(port_id);
 	if (!port_ptr) {
 		pr_err("%s: Local port %d not present\n", __func__, port_id);
-		mutex_unlock(&local_ports_lock);
+		up_read(&local_ports_lock_lha2);
 		release_pkt(pkt);
 		return -ENODEV;
 	}
 
-	mutex_lock(&port_ptr->port_rx_q_lock);
-	wake_lock(&port_ptr->port_rx_wake_lock);
-	list_add_tail(&pkt->list, &port_ptr->port_rx_q);
 	ret_len = pkt->length;
-	wake_up(&port_ptr->port_rx_wait_q);
-	mutex_unlock(&port_ptr->port_rx_q_lock);
+	post_pkt_to_port(port_ptr, pkt, 0);
 	update_comm_mode_info(&src->mode_info, NULL);
-	mutex_unlock(&local_ports_lock);
+	up_read(&local_ports_lock_lha2);
 
 	return ret_len;
 }
@@ -2128,15 +2051,11 @@
 	hdr->dst_port_id = rport_ptr->port_id;
 	pkt->length += IPC_ROUTER_HDR_SIZE;
 
-	mutex_lock(&rport_ptr->quota_lock);
-	if (rport_ptr->restart_state != RESTART_NORMAL) {
-		mutex_unlock(&rport_ptr->quota_lock);
-		return -ENETRESET;
-	}
+	mutex_lock(&rport_ptr->quota_lock_lhb2);
 	if (rport_ptr->tx_quota_cnt == IPC_ROUTER_DEFAULT_RX_QUOTA) {
 		if (msm_ipc_router_lookup_resume_tx_port(
 			rport_ptr, src->this_port.port_id)) {
-			mutex_unlock(&rport_ptr->quota_lock);
+			mutex_unlock(&rport_ptr->quota_lock_lhb2);
 			return -EAGAIN;
 		}
 		resume_tx_port =
@@ -2145,7 +2064,7 @@
 		if (!resume_tx_port) {
 			pr_err("%s: Resume_Tx port allocation failed\n",
 								__func__);
-			mutex_unlock(&rport_ptr->quota_lock);
+			mutex_unlock(&rport_ptr->quota_lock_lhb2);
 			return -ENOMEM;
 		}
 		INIT_LIST_HEAD(&resume_tx_port->list);
@@ -2153,29 +2072,26 @@
 		resume_tx_port->node_id = src->this_port.node_id;
 		list_add_tail(&resume_tx_port->list,
 				&rport_ptr->resume_tx_port_list);
-		mutex_unlock(&rport_ptr->quota_lock);
+		mutex_unlock(&rport_ptr->quota_lock_lhb2);
 		return -EAGAIN;
 	}
 	rport_ptr->tx_quota_cnt++;
 	if (rport_ptr->tx_quota_cnt == IPC_ROUTER_DEFAULT_RX_QUOTA)
 		hdr->confirm_rx = 1;
-	mutex_unlock(&rport_ptr->quota_lock);
+	mutex_unlock(&rport_ptr->quota_lock_lhb2);
 
-	mutex_lock(&routing_table_lock);
 	rt_entry = lookup_routing_table(hdr->dst_node_id);
 	if (!rt_entry || !rt_entry->xprt_info) {
-		mutex_unlock(&routing_table_lock);
 		pr_err("%s: Remote node %d not up\n",
 			__func__, hdr->dst_node_id);
 		return -ENODEV;
 	}
-	mutex_lock(&rt_entry->lock);
+	down_read(&rt_entry->lock_lha4);
 	xprt_info = rt_entry->xprt_info;
-	mutex_lock(&xprt_info->tx_lock);
+	mutex_lock(&xprt_info->tx_lock_lhb2);
 	ret = xprt_info->xprt->write(pkt, pkt->length, xprt_info->xprt);
-	mutex_unlock(&xprt_info->tx_lock);
-	mutex_unlock(&rt_entry->lock);
-	mutex_unlock(&routing_table_lock);
+	mutex_unlock(&xprt_info->tx_lock_lhb2);
+	up_read(&rt_entry->lock_lha4);
 
 	if (ret < 0) {
 		pr_err("%s: Write on XPRT failed\n", __func__);
@@ -2231,13 +2147,13 @@
 		dst_node_id = dest->addr.port_addr.node_id;
 		dst_port_id = dest->addr.port_addr.port_id;
 	} else if (dest->addrtype == MSM_IPC_ADDR_NAME) {
-		mutex_lock(&server_list_lock);
+		down_read(&server_list_lock_lha2);
 		server = msm_ipc_router_lookup_server(
 					dest->addr.port_name.service,
 					dest->addr.port_name.instance,
 					0, 0);
 		if (!server) {
-			mutex_unlock(&server_list_lock);
+			up_read(&server_list_lock_lha2);
 			pr_err("%s: Destination not reachable\n", __func__);
 			return -ENODEV;
 		}
@@ -2246,16 +2162,18 @@
 					       list);
 		dst_node_id = server_port->server_addr.node_id;
 		dst_port_id = server_port->server_addr.port_id;
-		mutex_unlock(&server_list_lock);
+		up_read(&server_list_lock_lha2);
 	}
 	if (dst_node_id == IPC_ROUTER_NID_LOCAL) {
 		ret = loopback_data(src, dst_port_id, data);
 		return ret;
 	}
 
+	down_read(&routing_table_lock_lha3);
 	rport_ptr = msm_ipc_router_lookup_remote_port(dst_node_id,
 						      dst_port_id);
 	if (!rport_ptr) {
+		up_read(&routing_table_lock_lha3);
 		pr_err("%s: Remote port not found\n", __func__);
 		return -ENODEV;
 	}
@@ -2263,6 +2181,7 @@
 	if (src->check_send_permissions) {
 		ret = src->check_send_permissions(rport_ptr->sec_rule);
 		if (ret <= 0) {
+			up_read(&routing_table_lock_lha3);
 			pr_err("%s: permission failure for %s\n",
 				__func__, current->comm);
 			return -EPERM;
@@ -2271,11 +2190,13 @@
 
 	pkt = create_pkt(data);
 	if (!pkt) {
+		up_read(&routing_table_lock_lha3);
 		pr_err("%s: Pkt creation failed\n", __func__);
 		return -ENOMEM;
 	}
 
 	ret = msm_ipc_router_write_pkt(src, rport_ptr, pkt);
+	up_read(&routing_table_lock_lha3);
 	release_pkt(pkt);
 
 	return ret;
@@ -2313,15 +2234,15 @@
 	if (!port_ptr || !data)
 		return -EINVAL;
 
-	mutex_lock(&port_ptr->port_rx_q_lock);
+	mutex_lock(&port_ptr->port_rx_q_lock_lhb3);
 	if (list_empty(&port_ptr->port_rx_q)) {
-		mutex_unlock(&port_ptr->port_rx_q_lock);
+		mutex_unlock(&port_ptr->port_rx_q_lock_lhb3);
 		return -EAGAIN;
 	}
 
 	pkt = list_first_entry(&port_ptr->port_rx_q, struct rr_packet, list);
 	if ((buf_len) && ((pkt->length - IPC_ROUTER_HDR_SIZE) > buf_len)) {
-		mutex_unlock(&port_ptr->port_rx_q_lock);
+		mutex_unlock(&port_ptr->port_rx_q_lock_lhb3);
 		return -ETOOSMALL;
 	}
 	list_del(&pkt->list);
@@ -2330,7 +2251,7 @@
 	*data = pkt->pkt_fragment_q;
 	ret = pkt->length;
 	kfree(pkt);
-	mutex_unlock(&port_ptr->port_rx_q_lock);
+	mutex_unlock(&port_ptr->port_rx_q_lock_lhb3);
 
 	return ret;
 }
@@ -2350,9 +2271,9 @@
 	}
 
 	*data = NULL;
-	mutex_lock(&port_ptr->port_rx_q_lock);
+	mutex_lock(&port_ptr->port_rx_q_lock_lhb3);
 	while (list_empty(&port_ptr->port_rx_q)) {
-		mutex_unlock(&port_ptr->port_rx_q_lock);
+		mutex_unlock(&port_ptr->port_rx_q_lock_lhb3);
 		if (timeout < 0) {
 			ret = wait_event_interruptible(
 					port_ptr->port_rx_wait_q,
@@ -2369,9 +2290,9 @@
 		}
 		if (timeout == 0)
 			return -ETIMEDOUT;
-		mutex_lock(&port_ptr->port_rx_q_lock);
+		mutex_lock(&port_ptr->port_rx_q_lock_lhb3);
 	}
-	mutex_unlock(&port_ptr->port_rx_q_lock);
+	mutex_unlock(&port_ptr->port_rx_q_lock_lhb3);
 
 	ret = msm_ipc_router_read(port_ptr, data, 0);
 	if (ret <= 0 || !(*data))
@@ -2449,9 +2370,9 @@
 		return -EINVAL;
 
 	if (port_ptr->type == SERVER_PORT || port_ptr->type == CLIENT_PORT) {
-		mutex_lock(&local_ports_lock);
+		down_write(&local_ports_lock_lha2);
 		list_del(&port_ptr->list);
-		mutex_unlock(&local_ports_lock);
+		up_write(&local_ports_lock_lha2);
 
 		if (port_ptr->type == SERVER_PORT) {
 			msg.cmd = IPC_ROUTER_CTRL_CMD_REMOVE_SERVER;
@@ -2476,25 +2397,25 @@
 			port_ptr->this_port.node_id,
 			port_ptr->this_port.port_id);
 	} else if (port_ptr->type == CONTROL_PORT) {
-		mutex_lock(&control_ports_lock);
+		down_write(&control_ports_lock_lha5);
 		list_del(&port_ptr->list);
-		mutex_unlock(&control_ports_lock);
+		up_write(&control_ports_lock_lha5);
 	} else if (port_ptr->type == IRSC_PORT) {
-		mutex_lock(&local_ports_lock);
+		down_write(&local_ports_lock_lha2);
 		list_del(&port_ptr->list);
-		mutex_unlock(&local_ports_lock);
+		up_write(&local_ports_lock_lha2);
 		signal_irsc_completion();
 	}
 
-	mutex_lock(&port_ptr->port_rx_q_lock);
+	mutex_lock(&port_ptr->port_rx_q_lock_lhb3);
 	list_for_each_entry_safe(pkt, temp_pkt, &port_ptr->port_rx_q, list) {
 		list_del(&pkt->list);
 		release_pkt(pkt);
 	}
-	mutex_unlock(&port_ptr->port_rx_q_lock);
+	mutex_unlock(&port_ptr->port_rx_q_lock_lhb3);
 
 	if (port_ptr->type == SERVER_PORT) {
-		mutex_lock(&server_list_lock);
+		down_write(&server_list_lock_lha2);
 		server = msm_ipc_router_lookup_server(
 				port_ptr->port_name.service,
 				port_ptr->port_name.instance,
@@ -2504,7 +2425,7 @@
 			msm_ipc_router_destroy_server(server,
 				port_ptr->this_port.node_id,
 				port_ptr->this_port.port_id);
-		mutex_unlock(&server_list_lock);
+		up_write(&server_list_lock_lha2);
 	}
 
 	wake_lock_destroy(&port_ptr->port_rx_wake_lock);
@@ -2520,13 +2441,13 @@
 	if (!port_ptr)
 		return -EINVAL;
 
-	mutex_lock(&port_ptr->port_rx_q_lock);
+	mutex_lock(&port_ptr->port_rx_q_lock_lhb3);
 	if (!list_empty(&port_ptr->port_rx_q)) {
 		pkt = list_first_entry(&port_ptr->port_rx_q,
 					struct rr_packet, list);
 		rc = pkt->length;
 	}
-	mutex_unlock(&port_ptr->port_rx_q_lock);
+	mutex_unlock(&port_ptr->port_rx_q_lock_lhb3);
 
 	return rc;
 }
@@ -2536,13 +2457,13 @@
 	if (!port_ptr)
 		return -EINVAL;
 
-	mutex_lock(&local_ports_lock);
+	down_write(&local_ports_lock_lha2);
 	list_del(&port_ptr->list);
-	mutex_unlock(&local_ports_lock);
+	up_write(&local_ports_lock_lha2);
 	port_ptr->type = CONTROL_PORT;
-	mutex_lock(&control_ports_lock);
+	down_write(&control_ports_lock_lha5);
 	list_add_tail(&port_ptr->list, &control_ports);
-	mutex_unlock(&control_ports_lock);
+	up_write(&control_ports_lock_lha5);
 
 	return 0;
 }
@@ -2566,7 +2487,7 @@
 		return -EINVAL;
 	}
 
-	mutex_lock(&server_list_lock);
+	down_read(&server_list_lock_lha2);
 	if (!lookup_mask)
 		lookup_mask = 0xFFFFFFFF;
 	key = (srv_name->service & (SRV_HASH_SIZE - 1));
@@ -2589,7 +2510,7 @@
 			i++;
 		}
 	}
-	mutex_unlock(&server_list_lock);
+	up_read(&server_list_lock_lha2);
 
 	return i;
 }
@@ -2598,14 +2519,14 @@
 {
 	struct msm_ipc_router_xprt_info *xprt_info, *tmp_xprt_info;
 
-	mutex_lock(&xprt_info_list_lock);
+	down_write(&xprt_info_list_lock_lha5);
 	list_for_each_entry_safe(xprt_info, tmp_xprt_info,
 				 &xprt_info_list, list) {
 		xprt_info->xprt->close(xprt_info->xprt);
 		list_del(&xprt_info->list);
 		kfree(xprt_info);
 	}
-	mutex_unlock(&xprt_info_list_lock);
+	up_write(&xprt_info_list_lock_lha5);
 	return 0;
 }
 
@@ -2616,9 +2537,9 @@
 	struct msm_ipc_routing_table_entry *rt_entry;
 
 	for (j = 0; j < RT_HASH_SIZE; j++) {
-		mutex_lock(&routing_table_lock);
+		down_read(&routing_table_lock_lha3);
 		list_for_each_entry(rt_entry, &routing_table[j], list) {
-			mutex_lock(&rt_entry->lock);
+			down_read(&rt_entry->lock_lha4);
 			i += scnprintf(buf + i, max - i,
 				       "Node Id: 0x%08x\n", rt_entry->node_id);
 			if (rt_entry->node_id == IPC_ROUTER_NID_LOCAL) {
@@ -2635,9 +2556,9 @@
 					rt_entry->xprt_info->remote_node_id);
 			}
 			i += scnprintf(buf + i, max - i, "\n");
-			mutex_unlock(&rt_entry->lock);
+			up_read(&rt_entry->lock_lha4);
 		}
-		mutex_unlock(&routing_table_lock);
+		up_read(&routing_table_lock_lha3);
 	}
 
 	return i;
@@ -2648,7 +2569,7 @@
 	int i = 0;
 	struct msm_ipc_router_xprt_info *xprt_info;
 
-	mutex_lock(&xprt_info_list_lock);
+	down_read(&xprt_info_list_lock_lha5);
 	list_for_each_entry(xprt_info, &xprt_info_list, list) {
 		i += scnprintf(buf + i, max - i, "XPRT Name: %s\n",
 			       xprt_info->xprt->name);
@@ -2660,7 +2581,7 @@
 			       xprt_info->remote_node_id);
 		i += scnprintf(buf + i, max - i, "\n");
 	}
-	mutex_unlock(&xprt_info_list_lock);
+	up_read(&xprt_info_list_lock_lha5);
 
 	return i;
 }
@@ -2671,7 +2592,7 @@
 	struct msm_ipc_server *server;
 	struct msm_ipc_server_port *server_port;
 
-	mutex_lock(&server_list_lock);
+	down_read(&server_list_lock_lha2);
 	for (j = 0; j < SRV_HASH_SIZE; j++) {
 		list_for_each_entry(server, &server_list[j], list) {
 			list_for_each_entry(server_port,
@@ -2691,7 +2612,7 @@
 			}
 		}
 	}
-	mutex_unlock(&server_list_lock);
+	up_read(&server_list_lock_lha2);
 
 	return i;
 }
@@ -2703,9 +2624,9 @@
 	struct msm_ipc_routing_table_entry *rt_entry;
 
 	for (j = 0; j < RT_HASH_SIZE; j++) {
-		mutex_lock(&routing_table_lock);
+		down_read(&routing_table_lock_lha3);
 		list_for_each_entry(rt_entry, &routing_table[j], list) {
-			mutex_lock(&rt_entry->lock);
+			down_read(&rt_entry->lock_lha4);
 			for (k = 0; k < RP_HASH_SIZE; k++) {
 				list_for_each_entry(rport_ptr,
 					&rt_entry->remote_port_list[k],
@@ -2722,9 +2643,9 @@
 				i += scnprintf(buf + i, max - i, "\n");
 				}
 			}
-			mutex_unlock(&rt_entry->lock);
+			up_read(&rt_entry->lock_lha4);
 		}
-		mutex_unlock(&routing_table_lock);
+		up_read(&routing_table_lock_lha3);
 	}
 
 	return i;
@@ -2735,7 +2656,7 @@
 	int i = 0;
 	struct msm_ipc_port *port_ptr;
 
-	mutex_lock(&control_ports_lock);
+	down_read(&control_ports_lock_lha5);
 	list_for_each_entry(port_ptr, &control_ports, list) {
 		i += scnprintf(buf + i, max - i, "Node_id: 0x%08x\n",
 			       port_ptr->this_port.node_id);
@@ -2743,7 +2664,7 @@
 			       port_ptr->this_port.port_id);
 		i += scnprintf(buf + i, max - i, "\n");
 	}
-	mutex_unlock(&control_ports_lock);
+	up_read(&control_ports_lock_lha5);
 
 	return i;
 }
@@ -2754,7 +2675,7 @@
 	unsigned long flags;
 	struct msm_ipc_port *port_ptr;
 
-	mutex_lock(&local_ports_lock);
+	down_read(&local_ports_lock_lha2);
 	for (j = 0; j < LP_HASH_SIZE; j++) {
 		list_for_each_entry(port_ptr, &local_ports[j], list) {
 			spin_lock_irqsave(&port_ptr->port_lock, flags);
@@ -2774,7 +2695,7 @@
 			i += scnprintf(buf + i, max - i, "\n");
 		}
 	}
-	mutex_unlock(&local_ports_lock);
+	up_read(&local_ports_lock_lha2);
 
 	return i;
 }
@@ -2848,8 +2769,8 @@
 	xprt_info->initialized = 0;
 	xprt_info->remote_node_id = -1;
 	INIT_LIST_HEAD(&xprt_info->pkt_list);
-	mutex_init(&xprt_info->rx_lock);
-	mutex_init(&xprt_info->tx_lock);
+	mutex_init(&xprt_info->rx_lock_lhb2);
+	mutex_init(&xprt_info->tx_lock_lhb2);
 	wake_lock_init(&xprt_info->wakelock,
 			WAKE_LOCK_SUSPEND, xprt->name);
 	xprt_info->need_len = 0;
@@ -2868,18 +2789,18 @@
 		xprt_info->initialized = 1;
 	}
 
-	mutex_lock(&xprt_info_list_lock);
+	down_write(&xprt_info_list_lock_lha5);
 	list_add_tail(&xprt_info->list, &xprt_info_list);
-	mutex_unlock(&xprt_info_list_lock);
+	up_write(&xprt_info_list_lock_lha5);
 
-	mutex_lock(&routing_table_lock);
+	down_write(&routing_table_lock_lha3);
 	if (!routing_table_inited) {
 		init_routing_table();
 		rt_entry = alloc_routing_table_entry(IPC_ROUTER_NID_LOCAL);
 		add_routing_table_entry(rt_entry);
 		routing_table_inited = 1;
 	}
-	mutex_unlock(&routing_table_lock);
+	up_write(&routing_table_lock_lha3);
 
 	xprt->priv = xprt_info;
 
@@ -2893,13 +2814,13 @@
 	if (xprt && xprt->priv) {
 		xprt_info = xprt->priv;
 
-		mutex_lock(&xprt_info->rx_lock);
+		mutex_lock(&xprt_info->rx_lock_lhb2);
 		xprt_info->abort_data_read = 1;
-		mutex_unlock(&xprt_info->rx_lock);
+		mutex_unlock(&xprt_info->rx_lock_lhb2);
 
-		mutex_lock(&xprt_info_list_lock);
+		down_write(&xprt_info_list_lock_lha5);
 		list_del(&xprt_info->list);
-		mutex_unlock(&xprt_info_list_lock);
+		up_write(&xprt_info_list_lock_lha5);
 
 		flush_workqueue(xprt_info->workqueue);
 		destroy_workqueue(xprt_info->workqueue);
@@ -2930,7 +2851,7 @@
 	struct msm_ipc_router_xprt_work *xprt_work =
 		container_of(work, struct msm_ipc_router_xprt_work, work);
 
-	modem_reset_cleanup(xprt_work->xprt->priv);
+	msm_ipc_cleanup_routing_table(xprt_work->xprt->priv);
 	msm_ipc_router_remove_xprt(xprt_work->xprt);
 
 	if (atomic_dec_return(&pending_close_count) == 0)
@@ -3000,10 +2921,10 @@
 	if (!pkt)
 		return;
 
-	mutex_lock(&xprt_info->rx_lock);
+	mutex_lock(&xprt_info->rx_lock_lhb2);
 	list_add_tail(&pkt->list, &xprt_info->pkt_list);
 	wake_lock(&xprt_info->wakelock);
-	mutex_unlock(&xprt_info->rx_lock);
+	mutex_unlock(&xprt_info->rx_lock_lhb2);
 	queue_work(xprt_info->workqueue, &xprt_info->read_data);
 }
 
@@ -3071,16 +2992,15 @@
 	for (i = 0; i < LP_HASH_SIZE; i++)
 		INIT_LIST_HEAD(&local_ports[i]);
 
-	mutex_lock(&routing_table_lock);
+	down_write(&routing_table_lock_lha3);
 	if (!routing_table_inited) {
 		init_routing_table();
 		rt_entry = alloc_routing_table_entry(IPC_ROUTER_NID_LOCAL);
 		add_routing_table_entry(rt_entry);
 		routing_table_inited = 1;
 	}
-	mutex_unlock(&routing_table_lock);
+	up_write(&routing_table_lock_lha3);
 
-	init_waitqueue_head(&newserver_wait);
 	init_waitqueue_head(&subsystem_restart_wait);
 	ret = msm_ipc_router_init_sockets();
 	if (ret < 0)
diff --git a/arch/arm/mach-msm/ipc_socket.c b/arch/arm/mach-msm/ipc_socket.c
index 64d8fed..042b9f1 100644
--- a/arch/arm/mach-msm/ipc_socket.c
+++ b/arch/arm/mach-msm/ipc_socket.c
@@ -407,9 +407,9 @@
 
 	lock_sock(sk);
 	timeout = sk->sk_rcvtimeo;
-	mutex_lock(&port_ptr->port_rx_q_lock);
+	mutex_lock(&port_ptr->port_rx_q_lock_lhb3);
 	while (list_empty(&port_ptr->port_rx_q)) {
-		mutex_unlock(&port_ptr->port_rx_q_lock);
+		mutex_unlock(&port_ptr->port_rx_q_lock_lhb3);
 		release_sock(sk);
 		if (timeout < 0) {
 			ret = wait_event_interruptible(
@@ -431,9 +431,9 @@
 			return 0;
 		}
 		lock_sock(sk);
-		mutex_lock(&port_ptr->port_rx_q_lock);
+		mutex_lock(&port_ptr->port_rx_q_lock_lhb3);
 	}
-	mutex_unlock(&port_ptr->port_rx_q_lock);
+	mutex_unlock(&port_ptr->port_rx_q_lock_lhb3);
 
 	ret = msm_ipc_router_read(port_ptr, &msg, buf_len);
 	if (ret <= 0 || !msg) {
diff --git a/arch/arm/mach-msm/lpm_resources.c b/arch/arm/mach-msm/lpm_resources.c
index 624a27c..1d9c539 100644
--- a/arch/arm/mach-msm/lpm_resources.c
+++ b/arch/arm/mach-msm/lpm_resources.c
@@ -23,11 +23,12 @@
 #include <linux/tick.h>
 #include <mach/mpm.h>
 #include <mach/rpm-smd.h>
+#include <mach/trace_msm_low_power.h>
 #include "spm.h"
 #include "lpm_resources.h"
 #include "rpm-notifier.h"
 #include "idle.h"
-#include "trace_msm_low_power.h"
+
 
 /*Debug Definitions*/
 enum {
diff --git a/arch/arm/mach-msm/mdm2.c b/arch/arm/mach-msm/mdm2.c
index c8d6d5a..e43a0e27 100644
--- a/arch/arm/mach-msm/mdm2.c
+++ b/arch/arm/mach-msm/mdm2.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
@@ -28,6 +28,7 @@
 #include <linux/debugfs.h>
 #include <linux/completion.h>
 #include <linux/workqueue.h>
+#include <linux/clk.h>
 #include <linux/mfd/pmic8058.h>
 #include <asm/mach-types.h>
 #include <asm/uaccess.h>
@@ -38,26 +39,24 @@
 #include <linux/msm_charm.h>
 #include "msm_watchdog.h"
 #include "devices.h"
+#include "clock.h"
 #include "mdm_private.h"
 #define MDM_PBLRDY_CNT		20
 
 static int mdm_debug_mask;
-static int power_on_count;
-static int hsic_peripheral_status;
-static DEFINE_MUTEX(hsic_status_lock);
 
 static void mdm_peripheral_connect(struct mdm_modem_drv *mdm_drv)
 {
 	if (!mdm_drv->pdata->peripheral_platform_device)
 		return;
 
-	mutex_lock(&hsic_status_lock);
-	if (hsic_peripheral_status)
+	mutex_lock(&mdm_drv->peripheral_status_lock);
+	if (mdm_drv->peripheral_status)
 		goto out;
 	platform_device_add(mdm_drv->pdata->peripheral_platform_device);
-	hsic_peripheral_status = 1;
+	mdm_drv->peripheral_status = 1;
 out:
-	mutex_unlock(&hsic_status_lock);
+	mutex_unlock(&mdm_drv->peripheral_status_lock);
 }
 
 static void mdm_peripheral_disconnect(struct mdm_modem_drv *mdm_drv)
@@ -65,13 +64,13 @@
 	if (!mdm_drv->pdata->peripheral_platform_device)
 		return;
 
-	mutex_lock(&hsic_status_lock);
-	if (!hsic_peripheral_status)
+	mutex_lock(&mdm_drv->peripheral_status_lock);
+	if (!mdm_drv->peripheral_status)
 		goto out;
 	platform_device_del(mdm_drv->pdata->peripheral_platform_device);
-	hsic_peripheral_status = 0;
+	mdm_drv->peripheral_status = 0;
 out:
-	mutex_unlock(&hsic_status_lock);
+	mutex_unlock(&mdm_drv->peripheral_status_lock);
 }
 
 /* This function can be called from atomic context. */
@@ -112,8 +111,8 @@
 	for (i = 20; i > 0; i--) {
 		if (gpio_get_value(mdm_drv->mdm2ap_status_gpio) == 0) {
 			if (mdm_debug_mask & MDM_DEBUG_MASK_SHDN_LOG)
-				pr_info("%s: mdm2ap_status went low, i = %d\n",
-					__func__, i);
+				pr_debug("%s:id %d: mdm2ap_statuswent low, i=%d\n",
+					__func__, mdm_drv->device_id, i);
 			break;
 		}
 		msleep(100);
@@ -123,8 +122,10 @@
 	gpio_direction_output(mdm_drv->ap2mdm_soft_reset_gpio,
 					soft_reset_direction);
 	if (i == 0) {
-		pr_err("%s: MDM2AP_STATUS never went low. Doing a hard reset\n",
-			   __func__);
+		pr_debug("%s:id %d: MDM2AP_STATUS never went low. Doing a hard reset\n",
+			   __func__, mdm_drv->device_id);
+		gpio_direction_output(mdm_drv->ap2mdm_soft_reset_gpio,
+					soft_reset_direction);
 		/*
 		* Currently, there is a debounce timer on the charm PMIC. It is
 		* necessary to hold the PMIC RESET low for ~3.5 seconds
@@ -139,13 +140,14 @@
 {
 	int i;
 	int pblrdy;
-	if (power_on_count != 1) {
-		pr_err("%s: Calling fn when power_on_count != 1\n",
-			   __func__);
+	if (mdm_drv->power_on_count != 1) {
+		pr_debug("%s:id %d: Calling fn when power_on_count != 1\n",
+			   __func__, mdm_drv->device_id);
 		return;
 	}
 
-	pr_err("%s: Powering on modem for the first time\n", __func__);
+	pr_debug("%s:id %d: Powering on modem for the first time\n",
+		   __func__, mdm_drv->device_id);
 	mdm_peripheral_disconnect(mdm_drv);
 
 	/* If this is the first power-up after a panic, the modem may still
@@ -159,13 +161,15 @@
 		/* Pull AP2MDM_KPDPWR gpio high and wait for PS_HOLD to settle,
 		 * then	pull it back low.
 		 */
-		pr_debug("%s: Pulling AP2MDM_KPDPWR gpio high\n", __func__);
+		pr_debug("%s:id %d: Pulling AP2MDM_KPDPWR gpio high\n",
+				 __func__, mdm_drv->device_id);
 		gpio_direction_output(mdm_drv->ap2mdm_kpdpwr_n_gpio, 1);
 		gpio_direction_output(mdm_drv->ap2mdm_status_gpio, 1);
 		msleep(1000);
 		gpio_direction_output(mdm_drv->ap2mdm_kpdpwr_n_gpio, 0);
-	} else
+	} else {
 		gpio_direction_output(mdm_drv->ap2mdm_status_gpio, 1);
+	}
 
 	if (!GPIO_IS_VALID(mdm_drv->mdm2ap_pblrdy))
 		goto start_mdm_peripheral;
@@ -176,7 +180,8 @@
 			break;
 		usleep_range(5000, 5000);
 	}
-	pr_debug("%s: i:%d\n", __func__, i);
+	pr_debug("%s: id %d: pblrdy i:%d\n", __func__,
+			 mdm_drv->device_id, i);
 
 start_mdm_peripheral:
 	mdm_peripheral_connect(mdm_drv);
@@ -188,7 +193,8 @@
 	int i;
 	int pblrdy;
 
-	pr_err("%s: soft resetting mdm modem\n", __func__);
+	pr_debug("%s: id %d:  soft resetting mdm modem\n",
+		   __func__, mdm_drv->device_id);
 	mdm_peripheral_disconnect(mdm_drv);
 	mdm_toggle_soft_reset(mdm_drv);
 
@@ -202,7 +208,8 @@
 		usleep_range(5000, 5000);
 	}
 
-	pr_debug("%s: i:%d\n", __func__, i);
+	pr_debug("%s: id %d: pblrdy i:%d\n", __func__,
+			 mdm_drv->device_id, i);
 
 start_mdm_peripheral:
 	mdm_peripheral_connect(mdm_drv);
@@ -211,7 +218,7 @@
 
 static void mdm_power_on_common(struct mdm_modem_drv *mdm_drv)
 {
-	power_on_count++;
+	mdm_drv->power_on_count++;
 
 	/* this gpio will be used to indicate apq readiness,
 	 * de-assert it now so that it can be asserted later.
@@ -226,10 +233,10 @@
 	 * user space but we're already powered on. Ignore it.
 	 */
 	if (mdm_drv->pdata->early_power_on &&
-			(power_on_count == 2))
+			(mdm_drv->power_on_count == 2))
 		return;
 
-	if (power_on_count == 1)
+	if (mdm_drv->power_on_count == 1)
 		mdm_do_first_power_on(mdm_drv);
 	else
 		mdm_do_soft_power_on(mdm_drv);
@@ -242,7 +249,8 @@
 
 static void mdm_status_changed(struct mdm_modem_drv *mdm_drv, int value)
 {
-	pr_debug("%s: value:%d\n", __func__, value);
+	pr_debug("%s: id %d: value:%d\n", __func__,
+			 value, mdm_drv->device_id);
 
 	if (value) {
 		mdm_peripheral_disconnect(mdm_drv);
@@ -256,13 +264,15 @@
 {
 	switch (type) {
 	case APQ_CONTROLLED_UPGRADE:
-		pr_debug("%s APQ controlled modem image upgrade\n", __func__);
-		mdm_drv->mdm_ready = 0;
+		pr_debug("%s: id %d: APQ controlled modem image upgrade\n",
+				 __func__, mdm_drv->device_id);
+		atomic_set(&mdm_drv->mdm_ready, 0);
 		mdm_toggle_soft_reset(mdm_drv);
 		break;
 	case MDM_CONTROLLED_UPGRADE:
-		pr_debug("%s MDM controlled modem image upgrade\n", __func__);
-		mdm_drv->mdm_ready = 0;
+		pr_debug("%s: id %d: MDM controlled modem image upgrade\n",
+				 __func__, mdm_drv->device_id);
+		atomic_set(&mdm_drv->mdm_ready, 0);
 		/*
 		 * If we have no image currently present on the modem, then we
 		 * would be in PBL, in which case the status gpio would not go
@@ -270,15 +280,19 @@
 		 */
 		mdm_drv->disable_status_check = 1;
 		if (GPIO_IS_VALID(mdm_drv->usb_switch_gpio)) {
-			pr_info("%s Switching usb control to MDM\n", __func__);
+			pr_debug("%s: id %d: Switching usb control to MDM\n",
+					__func__, mdm_drv->device_id);
 			gpio_direction_output(mdm_drv->usb_switch_gpio, 1);
 		} else
-			pr_err("%s usb switch gpio unavailable\n", __func__);
+			pr_err("%s: id %d: usb switch gpio unavailable\n",
+				   __func__, mdm_drv->device_id);
 		break;
 	default:
-		pr_err("%s invalid upgrade type\n", __func__);
+		pr_err("%s: id %d: invalid upgrade type\n",
+			   __func__, mdm_drv->device_id);
 	}
 }
+
 static struct mdm_ops mdm_cb = {
 	.power_on_mdm_cb = mdm_power_on_common,
 	.reset_mdm_cb = mdm_power_on_common,
@@ -289,44 +303,10 @@
 	.image_upgrade_cb = mdm_image_upgrade,
 };
 
-static int __init mdm_modem_probe(struct platform_device *pdev)
+int mdm_get_ops(struct mdm_ops **mdm_ops)
 {
-	return mdm_common_create(pdev, &mdm_cb);
+	*mdm_ops = &mdm_cb;
+	return 0;
 }
 
-static int __devexit mdm_modem_remove(struct platform_device *pdev)
-{
-	return mdm_common_modem_remove(pdev);
-}
 
-static void mdm_modem_shutdown(struct platform_device *pdev)
-{
-	mdm_common_modem_shutdown(pdev);
-}
-
-static struct platform_driver mdm_modem_driver = {
-	.remove         = mdm_modem_remove,
-	.shutdown	= mdm_modem_shutdown,
-	.driver         = {
-		.name = "mdm2_modem",
-		.owner = THIS_MODULE
-	},
-};
-
-static int __init mdm_modem_init(void)
-{
-	return platform_driver_probe(&mdm_modem_driver, mdm_modem_probe);
-}
-
-static void __exit mdm_modem_exit(void)
-{
-	platform_driver_unregister(&mdm_modem_driver);
-}
-
-module_init(mdm_modem_init);
-module_exit(mdm_modem_exit);
-
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("mdm modem driver");
-MODULE_VERSION("2.0");
-MODULE_ALIAS("mdm_modem");
diff --git a/arch/arm/mach-msm/mdm_common.c b/arch/arm/mach-msm/mdm_common.c
index de46be8..bdb5455 100644
--- a/arch/arm/mach-msm/mdm_common.c
+++ b/arch/arm/mach-msm/mdm_common.c
@@ -49,22 +49,15 @@
 #define MDM_RDUMP_TIMEOUT	120000L
 #define MDM2AP_STATUS_TIMEOUT_MS 60000L
 
-static unsigned int mdm_debug_mask;
-static struct workqueue_struct *mdm_queue;
-static struct workqueue_struct *mdm_sfr_queue;
-static unsigned int dump_timeout_ms;
-static int vddmin_gpios_sent;
-
+/* Allow a maximum device id of this many digits */
+#define MAX_DEVICE_DIGITS  10
 #define EXTERNAL_MODEM "external_modem"
+#define SUBSYS_NAME_LENGTH \
+	(sizeof(EXTERNAL_MODEM) + MAX_DEVICE_DIGITS)
 
-static struct mdm_modem_drv *mdm_drv;
-static struct subsys_device *mdm_subsys_dev;
-
-DECLARE_COMPLETION(mdm_needs_reload);
-DECLARE_COMPLETION(mdm_boot);
-DECLARE_COMPLETION(mdm_ram_dumps);
-
-static int first_boot = 1;
+#define DEVICE_BASE_NAME "mdm"
+#define DEVICE_NAME_LENGTH \
+	(sizeof(DEVICE_BASE_NAME) + MAX_DEVICE_DIGITS)
 
 #define RD_BUF_SIZE			100
 #define SFR_MAX_RETRIES		10
@@ -74,58 +67,246 @@
 	GPIO_UPDATE_BOOTING_CONFIG = 1,
 	GPIO_UPDATE_RUNNING_CONFIG,
 };
-static int mdm2ap_status_valid_old_config;
-static struct gpiomux_setting mdm2ap_status_old_config;
+
+struct mdm_device {
+	struct list_head		link;
+	struct mdm_modem_drv	mdm_data;
+
+	int mdm2ap_status_valid_old_config;
+	struct gpiomux_setting mdm2ap_status_old_config;
+	int first_boot;
+	struct workqueue_struct *mdm_queue;
+	struct workqueue_struct *mdm_sfr_queue;
+	unsigned int dump_timeout_ms;
+
+	char subsys_name[SUBSYS_NAME_LENGTH];
+	struct subsys_desc mdm_subsys;
+	struct subsys_device *mdm_subsys_dev;
+
+	char device_name[DEVICE_NAME_LENGTH];
+	struct miscdevice misc_device;
+
+	struct completion mdm_needs_reload;
+	struct completion mdm_boot;
+	struct completion mdm_ram_dumps;
+	int mdm_errfatal_irq;
+	int mdm_status_irq;
+	int mdm_pblrdy_irq;
+
+	struct delayed_work mdm2ap_status_check_work;
+	struct work_struct mdm_status_work;
+	struct work_struct sfr_reason_work;
+
+	struct notifier_block mdm_panic_blk;
+
+	int ssr_started_internally;
+};
+
+static struct list_head	mdm_devices;
+static DEFINE_SPINLOCK(mdm_devices_lock);
+
+static int ssr_count;
+static DEFINE_SPINLOCK(ssr_lock);
+
+static unsigned int mdm_debug_mask;
+int vddmin_gpios_sent;
+static struct mdm_ops *mdm_ops;
+
+static void mdm_device_list_add(struct mdm_device *mdev)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&mdm_devices_lock, flags);
+	list_add_tail(&mdev->link, &mdm_devices);
+	spin_unlock_irqrestore(&mdm_devices_lock, flags);
+}
+
+static void mdm_device_list_remove(struct mdm_device *mdev)
+{
+	unsigned long flags;
+	struct mdm_device *lmdev, *tmp;
+
+	spin_lock_irqsave(&mdm_devices_lock, flags);
+	list_for_each_entry_safe(lmdev, tmp, &mdm_devices, link) {
+		if (mdev && mdev == lmdev) {
+			pr_debug("%s: removing device id %d\n",
+			  __func__, mdev->mdm_data.device_id);
+			list_del(&mdev->link);
+			break;
+		}
+	}
+	spin_unlock_irqrestore(&mdm_devices_lock, flags);
+}
+
+struct mdm_device *mdm_get_device_by_device_id(int device_id)
+{
+	unsigned long flags;
+	struct mdm_device *mdev = NULL;
+
+	spin_lock_irqsave(&mdm_devices_lock, flags);
+	list_for_each_entry(mdev, &mdm_devices, link) {
+		if (mdev && mdev->mdm_data.device_id == device_id) {
+			spin_unlock_irqrestore(&mdm_devices_lock, flags);
+			return mdev;
+		}
+	}
+	spin_unlock_irqrestore(&mdm_devices_lock, flags);
+	return NULL;
+}
+
+struct mdm_device *mdm_get_device_by_name(const char *name)
+{
+	unsigned long flags;
+	struct mdm_device *mdev;
+
+	if (!name)
+		return NULL;
+	spin_lock_irqsave(&mdm_devices_lock, flags);
+	list_for_each_entry(mdev, &mdm_devices, link) {
+		if (mdev && !strncmp(mdev->device_name, name,
+				sizeof(mdev->device_name))) {
+			spin_unlock_irqrestore(&mdm_devices_lock, flags);
+			return mdev;
+		}
+	}
+	spin_unlock_irqrestore(&mdm_devices_lock, flags);
+	return NULL;
+}
+
+/* If the platform's cascading_ssr flag is set, the subsystem
+ * restart module will restart the other modems so stop
+ * monitoring them as well.
+ * This function can be called from interrupt context.
+ */
+static void mdm_start_ssr(struct mdm_device *mdev)
+{
+	unsigned long flags;
+	int start_ssr = 1;
+
+	spin_lock_irqsave(&ssr_lock, flags);
+	if (mdev->mdm_data.pdata->cascading_ssr &&
+			ssr_count > 0) {
+		start_ssr = 0;
+	} else {
+		ssr_count++;
+		mdev->ssr_started_internally = 1;
+	}
+	spin_unlock_irqrestore(&ssr_lock, flags);
+
+	if (start_ssr) {
+		atomic_set(&mdev->mdm_data.mdm_ready, 0);
+		pr_debug("%s: Resetting mdm id %d due to mdm error\n",
+				__func__, mdev->mdm_data.device_id);
+		subsystem_restart_dev(mdev->mdm_subsys_dev);
+	} else {
+		pr_debug("%s: Another modem is already in SSR\n",
+				__func__);
+	}
+}
+
+/* Increment the reference count to handle the case where
+ * subsystem restart is initiated by the SSR service.
+ */
+static void mdm_ssr_started(struct mdm_device *mdev)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&ssr_lock, flags);
+	ssr_count++;
+	atomic_set(&mdev->mdm_data.mdm_ready, 0);
+	spin_unlock_irqrestore(&ssr_lock, flags);
+}
+
+/* mdm_ssr_completed assumes that mdm_ssr_started has previously
+ * been called.
+ */
+static void mdm_ssr_completed(struct mdm_device *mdev)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&ssr_lock, flags);
+	ssr_count--;
+	if (mdev->ssr_started_internally) {
+		mdev->ssr_started_internally = 0;
+		ssr_count--;
+	}
+
+	if (ssr_count < 0) {
+		pr_err("%s: ssr_count = %d\n",
+			    __func__, ssr_count);
+		panic("%s: ssr_count = %d < 0\n",
+			  __func__, ssr_count);
+	}
+	spin_unlock_irqrestore(&ssr_lock, flags);
+}
 
 static irqreturn_t mdm_vddmin_change(int irq, void *dev_id)
 {
-	int value = gpio_get_value(
-		mdm_drv->pdata->vddmin_resource->mdm2ap_vddmin_gpio);
+	struct mdm_device *mdev = (struct mdm_device *)dev_id;
+	struct mdm_vddmin_resource *vddmin_res;
+	int value;
 
+	if (!mdev)
+		goto handled;
+
+	vddmin_res = mdev->mdm_data.pdata->vddmin_resource;
+	if (!vddmin_res)
+		goto handled;
+
+	value = gpio_get_value(
+	   vddmin_res->mdm2ap_vddmin_gpio);
 	if (value == 0)
-		pr_info("External Modem entered Vddmin\n");
+		pr_debug("External Modem id %d entered Vddmin\n",
+				mdev->mdm_data.device_id);
 	else
-		pr_info("External Modem exited Vddmin\n");
-
+		pr_debug("External Modem id %d exited Vddmin\n",
+				mdev->mdm_data.device_id);
+handled:
 	return IRQ_HANDLED;
 }
 
+/* The vddmin_res resource may not be supported by some platforms. */
 static void mdm_setup_vddmin_gpios(void)
 {
+	unsigned long flags;
 	struct msm_rpm_iv_pair req;
+	struct mdm_device *mdev;
 	struct mdm_vddmin_resource *vddmin_res;
 	int irq, ret;
 
-	/* This resource may not be supported by some platforms. */
-	vddmin_res = mdm_drv->pdata->vddmin_resource;
-	if (!vddmin_res)
-		return;
+	spin_lock_irqsave(&mdm_devices_lock, flags);
+	list_for_each_entry(mdev, &mdm_devices, link) {
+		vddmin_res = mdev->mdm_data.pdata->vddmin_resource;
+		if (!vddmin_res)
+			continue;
 
-	pr_info("Enabling vddmin logging\n");
-	req.id = vddmin_res->rpm_id;
-	req.value = ((uint32_t)vddmin_res->ap2mdm_vddmin_gpio & 0x0000FFFF)
-							<< 16;
-	req.value |= ((uint32_t)vddmin_res->modes & 0x000000FF) << 8;
-	req.value |= (uint32_t)vddmin_res->drive_strength & 0x000000FF;
+		pr_debug("Enabling vddmin logging on modem id %d\n",
+				mdev->mdm_data.device_id);
+		req.id = vddmin_res->rpm_id;
+		req.value =
+			((uint32_t)vddmin_res->ap2mdm_vddmin_gpio & 0x0000FFFF)
+						<< 16;
+		req.value |= ((uint32_t)vddmin_res->modes & 0x000000FF) << 8;
+		req.value |= (uint32_t)vddmin_res->drive_strength & 0x000000FF;
 
-	msm_rpm_set(MSM_RPM_CTX_SET_0, &req, 1);
+		msm_rpm_set(MSM_RPM_CTX_SET_0, &req, 1);
 
-	/* Start monitoring low power gpio from mdm */
-	irq = MSM_GPIO_TO_INT(vddmin_res->mdm2ap_vddmin_gpio);
-	if (irq < 0) {
-		pr_err("%s: could not get LPM POWER IRQ resource.\n",
-			__func__);
-		goto error_end;
+		/* Start monitoring low power gpio from mdm */
+		irq = gpio_to_irq(vddmin_res->mdm2ap_vddmin_gpio);
+		if (irq < 0)
+			pr_err("%s: could not get LPM POWER IRQ resource mdm id %d.\n",
+				   __func__, mdev->mdm_data.device_id);
+		else {
+			ret = request_threaded_irq(irq, NULL, mdm_vddmin_change,
+				IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+				"mdm lpm", mdev);
+
+			if (ret < 0)
+				pr_err("%s: MDM LPM IRQ#%d request failed with error=%d",
+					   __func__, irq, ret);
+		}
 	}
-
-	ret = request_threaded_irq(irq, NULL, mdm_vddmin_change,
-		IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
-		"mdm lpm", NULL);
-
-	if (ret < 0)
-		pr_err("%s: MDM LPM IRQ#%d request failed with error=%d",
-			__func__, irq, ret);
-error_end:
+	spin_unlock_irqrestore(&mdm_devices_lock, flags);
 	return;
 }
 
@@ -133,48 +314,53 @@
 {
 	int ret, ntries = 0;
 	char sfr_buf[RD_BUF_SIZE];
+	struct mdm_platform_data *pdata;
+	struct mdm_device *mdev = container_of(work,
+			struct mdm_device, sfr_reason_work);
 
-	do {
-		msleep(SFR_RETRY_INTERVAL);
-		ret = sysmon_get_reason(SYSMON_SS_EXT_MODEM,
+	pdata = mdev->mdm_data.pdata;
+	if (pdata->sysmon_subsys_id_valid) {
+		do {
+			ret = sysmon_get_reason(pdata->sysmon_subsys_id,
 					sfr_buf, sizeof(sfr_buf));
-		if (ret) {
-			/*
-			 * The sysmon device may not have been probed as yet
-			 * after the restart.
+			if (!ret) {
+				pr_err("mdm restart reason: %s\n", sfr_buf);
+				return;
+			}
+			/* Wait for the modem to be fully booted after a
+			 * subsystem restart. This may take several seconds.
 			 */
-			pr_err("%s: Error retrieving mdm restart reason, ret = %d, "
-					"%d/%d tries\n", __func__, ret,
-					ntries + 1,	SFR_MAX_RETRIES);
-		} else {
-			pr_err("mdm restart reason: %s\n", sfr_buf);
-			break;
-		}
-	} while (++ntries < SFR_MAX_RETRIES);
+			msleep(SFR_RETRY_INTERVAL);
+		} while (++ntries < SFR_MAX_RETRIES);
+		pr_debug("%s: Error retrieving restart reason: %d\n",
+				__func__, ret);
+	}
 }
 
-static DECLARE_WORK(sfr_reason_work, mdm_restart_reason_fn);
-
 static void mdm2ap_status_check(struct work_struct *work)
 {
+	struct mdm_device *mdev =
+		container_of(work, struct mdm_device,
+					 mdm2ap_status_check_work.work);
+	struct mdm_modem_drv *mdm_drv = &mdev->mdm_data;
 	/*
 	 * If the mdm modem did not pull the MDM2AP_STATUS gpio
 	 * high then call subsystem_restart.
 	 */
 	if (!mdm_drv->disable_status_check) {
 		if (gpio_get_value(mdm_drv->mdm2ap_status_gpio) == 0) {
-			pr_err("%s: MDM2AP_STATUS gpio did not go high\n",
-					__func__);
-			mdm_drv->mdm_ready = 0;
-			subsystem_restart_dev(mdm_subsys_dev);
+			pr_debug("%s: MDM2AP_STATUS did not go high on mdm id %d\n",
+				   __func__, mdev->mdm_data.device_id);
+			mdm_start_ssr(mdev);
 		}
 	}
 }
 
-static DECLARE_DELAYED_WORK(mdm2ap_status_check_work, mdm2ap_status_check);
-
-static void mdm_update_gpio_configs(enum gpio_update_config gpio_config)
+static void mdm_update_gpio_configs(struct mdm_device *mdev,
+				enum gpio_update_config gpio_config)
 {
+	struct mdm_modem_drv *mdm_drv = &mdev->mdm_data;
+
 	/* Some gpio configuration may need updating after modem bootup.*/
 	switch (gpio_config) {
 	case GPIO_UPDATE_RUNNING_CONFIG:
@@ -182,20 +368,20 @@
 			if (msm_gpiomux_write(mdm_drv->mdm2ap_status_gpio,
 				GPIOMUX_ACTIVE,
 				mdm_drv->pdata->mdm2ap_status_gpio_run_cfg,
-				&mdm2ap_status_old_config))
-				pr_err("%s: failed updating running gpio config\n",
-					   __func__);
+				&mdev->mdm2ap_status_old_config))
+				pr_err("%s: failed updating running gpio config mdm id %d\n",
+					   __func__, mdev->mdm_data.device_id);
 			else
-				mdm2ap_status_valid_old_config = 1;
+				mdev->mdm2ap_status_valid_old_config = 1;
 		}
 		break;
 	case GPIO_UPDATE_BOOTING_CONFIG:
-		if (mdm2ap_status_valid_old_config) {
+		if (mdev->mdm2ap_status_valid_old_config) {
 			msm_gpiomux_write(mdm_drv->mdm2ap_status_gpio,
 					GPIOMUX_ACTIVE,
-					&mdm2ap_status_old_config,
+					&mdev->mdm2ap_status_old_config,
 					NULL);
-			mdm2ap_status_valid_old_config = 0;
+			mdev->mdm2ap_status_valid_old_config = 0;
 		}
 		break;
 	default:
@@ -208,17 +394,29 @@
 				unsigned long arg)
 {
 	int status, ret = 0;
+	struct mdm_device *mdev;
+	struct mdm_modem_drv *mdm_drv;
+
+	mdev = mdm_get_device_by_name(filp->f_path.dentry->d_iname);
+	if (!mdev) {
+		pr_err("%s: mdm_device not found\n", __func__);
+		return -ENODEV;
+	}
 
 	if (_IOC_TYPE(cmd) != CHARM_CODE) {
-		pr_err("%s: invalid ioctl code\n", __func__);
+		pr_err("%s: invalid ioctl code to mdm id %d\n",
+			   __func__, mdev->mdm_data.device_id);
 		return -EINVAL;
 	}
 
-	pr_debug("%s: Entering ioctl cmd = %d\n", __func__, _IOC_NR(cmd));
+	mdm_drv = &mdev->mdm_data;
+	pr_debug("%s: Entering ioctl cmd = %d, mdm id = %d\n",
+			 __func__, _IOC_NR(cmd), mdev->mdm_data.device_id);
 	switch (cmd) {
 	case WAKE_CHARM:
-		pr_info("%s: Powering on mdm\n", __func__);
-		mdm_drv->ops->power_on_mdm_cb(mdm_drv);
+		pr_debug("%s: Powering on mdm id %d\n",
+				__func__, mdev->mdm_data.device_id);
+		mdm_ops->power_on_mdm_cb(mdm_drv);
 		break;
 	case CHECK_FOR_BOOT:
 		if (gpio_get_value(mdm_drv->mdm2ap_status_gpio) == 0)
@@ -227,30 +425,33 @@
 			put_user(0, (unsigned long __user *) arg);
 		break;
 	case NORMAL_BOOT_DONE:
-		pr_debug("%s: check if mdm is booted up\n", __func__);
+		pr_debug("%s: check if mdm id %d is booted up\n",
+				 __func__, mdev->mdm_data.device_id);
 		get_user(status, (unsigned long __user *) arg);
 		if (status) {
-			pr_debug("%s: normal boot failed\n", __func__);
+			pr_debug("%s: normal boot of mdm id %d failed\n",
+					 __func__, mdev->mdm_data.device_id);
 			mdm_drv->mdm_boot_status = -EIO;
 		} else {
-			pr_info("%s: normal boot done\n", __func__);
+			pr_debug("%s: normal boot of mdm id %d done\n",
+					__func__, mdev->mdm_data.device_id);
 			mdm_drv->mdm_boot_status = 0;
 		}
-		mdm_drv->mdm_ready = 1;
+		atomic_set(&mdm_drv->mdm_ready, 1);
 
-		if (mdm_drv->ops->normal_boot_done_cb != NULL)
-			mdm_drv->ops->normal_boot_done_cb(mdm_drv);
+		if (mdm_ops->normal_boot_done_cb != NULL)
+			mdm_ops->normal_boot_done_cb(mdm_drv);
 
-		if (!first_boot)
-			complete(&mdm_boot);
+		if (!mdev->first_boot)
+			complete(&mdev->mdm_boot);
 		else
-			first_boot = 0;
+			mdev->first_boot = 0;
 
 		/* If successful, start a timer to check that the mdm2ap_status
 		 * gpio goes high.
 		 */
 		if (!status && gpio_get_value(mdm_drv->mdm2ap_status_gpio) == 0)
-			schedule_delayed_work(&mdm2ap_status_check_work,
+			schedule_delayed_work(&mdev->mdm2ap_status_check_work,
 				msecs_to_jiffies(MDM2AP_STATUS_TIMEOUT_MS));
 		break;
 	case RAM_DUMP_DONE:
@@ -259,24 +460,26 @@
 		if (status)
 			mdm_drv->mdm_ram_dump_status = -EIO;
 		else {
-			pr_info("%s: ramdump collection completed\n", __func__);
+			pr_debug("%s: ramdump collection completed\n",
+					 __func__);
 			mdm_drv->mdm_ram_dump_status = 0;
 		}
-		complete(&mdm_ram_dumps);
+		complete(&mdev->mdm_ram_dumps);
 		break;
 	case WAIT_FOR_RESTART:
 		pr_debug("%s: wait for mdm to need images reloaded\n",
 				__func__);
-		ret = wait_for_completion_interruptible(&mdm_needs_reload);
+		ret = wait_for_completion_interruptible(
+				&mdev->mdm_needs_reload);
 		if (!ret)
 			put_user(mdm_drv->boot_type,
 					 (unsigned long __user *) arg);
-		INIT_COMPLETION(mdm_needs_reload);
+		init_completion(&mdev->mdm_needs_reload);
 		break;
 	case GET_DLOAD_STATUS:
 		pr_debug("getting status of mdm2ap_errfatal_gpio\n");
 		if (gpio_get_value(mdm_drv->mdm2ap_errfatal_gpio) == 1 &&
-			!mdm_drv->mdm_ready)
+			!atomic_read(&mdm_drv->mdm_ready))
 			put_user(1, (unsigned long __user *) arg);
 		else
 			put_user(0, (unsigned long __user *) arg);
@@ -284,18 +487,18 @@
 	case IMAGE_UPGRADE:
 		pr_debug("%s Image upgrade ioctl recieved\n", __func__);
 		if (mdm_drv->pdata->image_upgrade_supported &&
-				mdm_drv->ops->image_upgrade_cb) {
+				mdm_ops->image_upgrade_cb) {
 			get_user(status, (unsigned long __user *) arg);
-			mdm_drv->ops->image_upgrade_cb(mdm_drv, status);
+			mdm_ops->image_upgrade_cb(mdm_drv, status);
 		} else
 			pr_debug("%s Image upgrade not supported\n", __func__);
 		break;
 	case SHUTDOWN_CHARM:
 		if (!mdm_drv->pdata->send_shdn)
 			break;
-		mdm_drv->mdm_ready = 0;
+		atomic_set(&mdm_drv->mdm_ready, 0);
 		if (mdm_debug_mask & MDM_DEBUG_MASK_SHDN_LOG)
-			pr_info("Sending shutdown request to mdm\n");
+			pr_debug("Sending shutdown request to mdm\n");
 		ret = sysmon_send_shutdown(SYSMON_SS_EXT_MODEM);
 		if (ret)
 			pr_err("%s: Graceful shutdown of the external modem failed, ret = %d\n",
@@ -307,68 +510,71 @@
 		ret = -EINVAL;
 		break;
 	}
-
 	return ret;
 }
 
 static void mdm_status_fn(struct work_struct *work)
 {
+	struct mdm_device *mdev =
+		container_of(work, struct mdm_device, mdm_status_work);
+	struct mdm_modem_drv *mdm_drv = &mdev->mdm_data;
 	int value = gpio_get_value(mdm_drv->mdm2ap_status_gpio);
 
 	pr_debug("%s: status:%d\n", __func__, value);
-	if (mdm_drv->mdm_ready && mdm_drv->ops->status_cb)
-		mdm_drv->ops->status_cb(mdm_drv, value);
+	if (atomic_read(&mdm_drv->mdm_ready) && mdm_ops->status_cb)
+		mdm_ops->status_cb(mdm_drv, value);
 
 	/* Update gpio configuration to "running" config. */
-	mdm_update_gpio_configs(GPIO_UPDATE_RUNNING_CONFIG);
+	mdm_update_gpio_configs(mdev, GPIO_UPDATE_RUNNING_CONFIG);
 }
 
-static DECLARE_WORK(mdm_status_work, mdm_status_fn);
-
-static void mdm_disable_irqs(void)
+static void mdm_disable_irqs(struct mdm_device *mdev)
 {
-	disable_irq_nosync(mdm_drv->mdm_errfatal_irq);
-	disable_irq_nosync(mdm_drv->mdm_status_irq);
+	if (!mdev)
+		return;
+	disable_irq_nosync(mdev->mdm_errfatal_irq);
+	disable_irq_nosync(mdev->mdm_status_irq);
+	disable_irq_nosync(mdev->mdm_pblrdy_irq);
 }
 
 static irqreturn_t mdm_errfatal(int irq, void *dev_id)
 {
-	pr_debug("%s: mdm got errfatal interrupt\n", __func__);
-	if (mdm_drv->mdm_ready &&
+	struct mdm_modem_drv *mdm_drv;
+	struct mdm_device *mdev = (struct mdm_device *)dev_id;
+	if (!mdev)
+		return IRQ_HANDLED;
+
+	pr_debug("%s: mdm id %d sent errfatal interrupt\n",
+			 __func__, mdev->mdm_data.device_id);
+	mdm_drv = &mdev->mdm_data;
+	if (atomic_read(&mdm_drv->mdm_ready) &&
 		(gpio_get_value(mdm_drv->mdm2ap_status_gpio) == 1)) {
-		pr_info("%s: Reseting the mdm due to an errfatal\n", __func__);
-		mdm_drv->mdm_ready = 0;
-		subsystem_restart_dev(mdm_subsys_dev);
+		pr_debug("%s: Received err fatal from mdm id %d\n",
+				__func__, mdev->mdm_data.device_id);
+		mdm_start_ssr(mdev);
 	}
 	return IRQ_HANDLED;
 }
 
+/* set the mdm_device as the file's private data */
 static int mdm_modem_open(struct inode *inode, struct file *file)
 {
 	return 0;
 }
 
-static const struct file_operations mdm_modem_fops = {
-	.owner		= THIS_MODULE,
-	.open		= mdm_modem_open,
-	.unlocked_ioctl	= mdm_modem_ioctl,
-};
-
-
-static struct miscdevice mdm_modem_misc = {
-	.minor	= MISC_DYNAMIC_MINOR,
-	.name	= "mdm",
-	.fops	= &mdm_modem_fops
-};
-
 static int mdm_panic_prep(struct notifier_block *this,
 				unsigned long event, void *ptr)
 {
 	int i;
+	struct mdm_modem_drv *mdm_drv;
+	struct mdm_device *mdev =
+		container_of(this, struct mdm_device, mdm_panic_blk);
+
+	mdm_drv = &mdev->mdm_data;
 
 	pr_debug("%s: setting AP2MDM_ERRFATAL high for a non graceful reset\n",
 			 __func__);
-	mdm_disable_irqs();
+	mdm_disable_irqs(mdev);
 	gpio_set_value(mdm_drv->ap2mdm_errfatal_gpio, 1);
 
 	for (i = MDM_MODEM_TIMEOUT; i > 0; i -= MDM_MODEM_DELTA) {
@@ -380,49 +586,67 @@
 	if (i <= 0) {
 		pr_err("%s: MDM2AP_STATUS never went low\n", __func__);
 		/* Reset the modem so that it will go into download mode. */
-		if (mdm_drv && mdm_drv->ops->atomic_reset_mdm_cb)
-			mdm_drv->ops->atomic_reset_mdm_cb(mdm_drv);
+		if (mdm_drv && mdm_ops->atomic_reset_mdm_cb)
+			mdm_ops->atomic_reset_mdm_cb(mdm_drv);
 	}
 	return NOTIFY_DONE;
 }
 
-static struct notifier_block mdm_panic_blk = {
-	.notifier_call  = mdm_panic_prep,
-};
-
 static irqreturn_t mdm_status_change(int irq, void *dev_id)
 {
-	int value = gpio_get_value(mdm_drv->mdm2ap_status_gpio);
+	struct mdm_modem_drv *mdm_drv;
+	struct mdm_device *mdev = (struct mdm_device *)dev_id;
+	int value;
+	if (!mdev)
+		return IRQ_HANDLED;
+
+	mdm_drv = &mdev->mdm_data;
+	value = gpio_get_value(mdm_drv->mdm2ap_status_gpio);
 
 	if ((mdm_debug_mask & MDM_DEBUG_MASK_SHDN_LOG) && (value == 0))
-		pr_info("%s: mdm2ap_status went low\n", __func__);
+		pr_debug("%s: mdm2ap_status went low\n", __func__);
 
-	pr_debug("%s: mdm sent status change interrupt\n", __func__);
-	if (value == 0 && mdm_drv->mdm_ready == 1) {
-		pr_info("%s: unexpected reset external modem\n", __func__);
+	pr_debug("%s: mdm id %d sent status change interrupt\n",
+			 __func__, mdev->mdm_data.device_id);
+	if (value == 0 && atomic_read(&mdm_drv->mdm_ready)) {
+		pr_debug("%s: unexpected reset external modem id %d\n",
+				__func__, mdev->mdm_data.device_id);
 		mdm_drv->mdm_unexpected_reset_occurred = 1;
-		mdm_drv->mdm_ready = 0;
-		subsystem_restart_dev(mdm_subsys_dev);
+		mdm_start_ssr(mdev);
 	} else if (value == 1) {
-		cancel_delayed_work(&mdm2ap_status_check_work);
-		pr_info("%s: status = 1: mdm is now ready\n", __func__);
-		queue_work(mdm_queue, &mdm_status_work);
+		cancel_delayed_work(&mdev->mdm2ap_status_check_work);
+		pr_debug("%s: status = 1: mdm id %d is now ready\n",
+				__func__, mdev->mdm_data.device_id);
+		queue_work(mdev->mdm_queue, &mdev->mdm_status_work);
 	}
 	return IRQ_HANDLED;
 }
 
 static irqreturn_t mdm_pblrdy_change(int irq, void *dev_id)
 {
-	pr_info("%s: pbl ready:%d\n", __func__,
-			gpio_get_value(mdm_drv->mdm2ap_pblrdy));
+	struct mdm_modem_drv *mdm_drv;
+	struct mdm_device *mdev = (struct mdm_device *)dev_id;
+	if (!mdev)
+		return IRQ_HANDLED;
 
+	mdm_drv = &mdev->mdm_data;
+	pr_debug("%s: mdm id %d: pbl ready:%d\n",
+			__func__, mdev->mdm_data.device_id,
+			gpio_get_value(mdm_drv->mdm2ap_pblrdy));
 	return IRQ_HANDLED;
 }
 
 static int mdm_subsys_shutdown(const struct subsys_desc *crashed_subsys)
 {
-	mdm_drv->mdm_ready = 0;
-	cancel_delayed_work(&mdm2ap_status_check_work);
+	struct mdm_device *mdev =
+	 container_of(crashed_subsys, struct mdm_device, mdm_subsys);
+	struct mdm_modem_drv *mdm_drv = &mdev->mdm_data;
+
+	pr_debug("%s: ssr on modem id %d\n", __func__,
+			 mdev->mdm_data.device_id);
+
+	mdm_ssr_started(mdev);
+	cancel_delayed_work(&mdev->mdm2ap_status_check_work);
 	gpio_direction_output(mdm_drv->ap2mdm_errfatal_gpio, 1);
 	if (mdm_drv->pdata->ramdump_delay_ms > 0) {
 		/* Wait for the external modem to complete
@@ -431,9 +655,9 @@
 		msleep(mdm_drv->pdata->ramdump_delay_ms);
 	}
 	if (!mdm_drv->mdm_unexpected_reset_occurred) {
-		mdm_drv->ops->reset_mdm_cb(mdm_drv);
+		mdm_ops->reset_mdm_cb(mdm_drv);
 		/* Update gpio configuration to "booting" config. */
-		mdm_update_gpio_configs(GPIO_UPDATE_BOOTING_CONFIG);
+		mdm_update_gpio_configs(mdev, GPIO_UPDATE_BOOTING_CONFIG);
 	} else {
 		mdm_drv->mdm_unexpected_reset_occurred = 0;
 	}
@@ -442,63 +666,76 @@
 
 static int mdm_subsys_powerup(const struct subsys_desc *crashed_subsys)
 {
+	struct mdm_device *mdev =
+		container_of(crashed_subsys, struct mdm_device,
+					 mdm_subsys);
+	struct mdm_modem_drv *mdm_drv = &mdev->mdm_data;
+
+	pr_debug("%s: ssr on modem id %d\n",
+			 __func__, mdev->mdm_data.device_id);
+
 	gpio_direction_output(mdm_drv->ap2mdm_errfatal_gpio, 0);
 	gpio_direction_output(mdm_drv->ap2mdm_status_gpio, 1);
 
 	if (mdm_drv->pdata->ps_hold_delay_ms > 0)
 		msleep(mdm_drv->pdata->ps_hold_delay_ms);
 
-	mdm_drv->ops->power_on_mdm_cb(mdm_drv);
+	mdm_ops->power_on_mdm_cb(mdm_drv);
 	mdm_drv->boot_type = CHARM_NORMAL_BOOT;
-	complete(&mdm_needs_reload);
-	if (!wait_for_completion_timeout(&mdm_boot,
+	mdm_ssr_completed(mdev);
+	complete(&mdev->mdm_needs_reload);
+	if (!wait_for_completion_timeout(&mdev->mdm_boot,
 			msecs_to_jiffies(MDM_BOOT_TIMEOUT))) {
 		mdm_drv->mdm_boot_status = -ETIMEDOUT;
-		pr_info("%s: mdm modem restart timed out.\n", __func__);
+		pr_debug("%s: mdm modem restart timed out.\n", __func__);
 	} else {
-		pr_info("%s: mdm modem has been restarted\n", __func__);
+		pr_debug("%s: id %d: mdm modem has been restarted\n",
+				__func__, mdm_drv->device_id);
 
 		/* Log the reason for the restart */
 		if (mdm_drv->pdata->sfr_query)
-			queue_work(mdm_sfr_queue, &sfr_reason_work);
+			queue_work(mdev->mdm_sfr_queue, &mdev->sfr_reason_work);
 	}
-	INIT_COMPLETION(mdm_boot);
+	init_completion(&mdev->mdm_boot);
 	return mdm_drv->mdm_boot_status;
 }
 
 static int mdm_subsys_ramdumps(int want_dumps,
 				const struct subsys_desc *crashed_subsys)
 {
+	struct mdm_device *mdev =
+		container_of(crashed_subsys, struct mdm_device,
+					 mdm_subsys);
+	struct mdm_modem_drv *mdm_drv = &mdev->mdm_data;
+
+	pr_debug("%s: ssr on modem id %d\n", __func__,
+			 mdev->mdm_data.device_id);
+
 	mdm_drv->mdm_ram_dump_status = 0;
-	cancel_delayed_work(&mdm2ap_status_check_work);
+	cancel_delayed_work(&mdev->mdm2ap_status_check_work);
 	if (want_dumps) {
 		mdm_drv->boot_type = CHARM_RAM_DUMPS;
-		complete(&mdm_needs_reload);
-		if (!wait_for_completion_timeout(&mdm_ram_dumps,
-				msecs_to_jiffies(dump_timeout_ms))) {
+		complete(&mdev->mdm_needs_reload);
+		if (!wait_for_completion_timeout(&mdev->mdm_ram_dumps,
+				msecs_to_jiffies(mdev->dump_timeout_ms))) {
 			mdm_drv->mdm_ram_dump_status = -ETIMEDOUT;
-			pr_info("%s: mdm modem ramdumps timed out.\n",
+			mdm_ssr_completed(mdev);
+			pr_err("%s: mdm modem ramdumps timed out.\n",
 					__func__);
 		} else
-			pr_info("%s: mdm modem ramdumps completed.\n",
+			pr_debug("%s: mdm modem ramdumps completed.\n",
 					__func__);
-		INIT_COMPLETION(mdm_ram_dumps);
+		init_completion(&mdev->mdm_ram_dumps);
 		if (!mdm_drv->pdata->no_powerdown_after_ramdumps) {
-			mdm_drv->ops->power_down_mdm_cb(mdm_drv);
+			mdm_ops->power_down_mdm_cb(mdm_drv);
 			/* Update gpio configuration to "booting" config. */
-			mdm_update_gpio_configs(GPIO_UPDATE_BOOTING_CONFIG);
+			mdm_update_gpio_configs(mdev,
+						GPIO_UPDATE_BOOTING_CONFIG);
 		}
 	}
 	return mdm_drv->mdm_ram_dump_status;
 }
 
-static struct subsys_desc mdm_subsystem = {
-	.shutdown = mdm_subsys_shutdown,
-	.ramdump = mdm_subsys_ramdumps,
-	.powerup = mdm_subsys_powerup,
-	.name = EXTERNAL_MODEM,
-};
-
 /* Once the gpios are sent to RPM and debugging
  * starts, there is no way to stop it without
  * rebooting the device.
@@ -512,8 +749,8 @@
 	}
 
 	mdm_debug_mask = val;
-	if (mdm_drv->ops->debug_state_changed_cb)
-		mdm_drv->ops->debug_state_changed_cb(mdm_debug_mask);
+	if (mdm_ops->debug_state_changed_cb)
+		mdm_ops->debug_state_changed_cb(mdm_debug_mask);
 	return 0;
 }
 
@@ -540,11 +777,55 @@
 	return 0;
 }
 
-static void mdm_modem_initialize_data(struct platform_device  *pdev,
-				struct mdm_ops *mdm_ops)
+static const struct file_operations mdm_modem_fops = {
+	.owner		= THIS_MODULE,
+	.open		= mdm_modem_open,
+	.unlocked_ioctl	= mdm_modem_ioctl,
+};
+
+static void mdm_modem_initialize_data(struct platform_device *pdev,
+						struct mdm_device *mdev)
 {
+	struct mdm_modem_drv *mdm_drv = &mdev->mdm_data;
 	struct resource *pres;
 
+	mdm_drv->pdata    = pdev->dev.platform_data;
+	if (pdev->id < 0)
+		mdm_drv->device_id   = 0;
+	else
+		mdm_drv->device_id   = pdev->id;
+
+	memset((void *)&mdev->mdm_subsys, 0,
+		   sizeof(struct subsys_desc));
+	if (mdev->mdm_data.device_id <= 0)
+		snprintf(mdev->subsys_name, sizeof(mdev->subsys_name),
+			 "%s",  EXTERNAL_MODEM);
+	else
+		snprintf(mdev->subsys_name, sizeof(mdev->subsys_name),
+			 "%s.%d",  EXTERNAL_MODEM, mdev->mdm_data.device_id);
+	mdev->mdm_subsys.shutdown = mdm_subsys_shutdown;
+	mdev->mdm_subsys.ramdump = mdm_subsys_ramdumps;
+	mdev->mdm_subsys.powerup = mdm_subsys_powerup;
+	mdev->mdm_subsys.name = mdev->subsys_name;
+
+	memset((void *)&mdev->misc_device, 0,
+		   sizeof(struct miscdevice));
+	if (mdev->mdm_data.device_id <= 0)
+		snprintf(mdev->device_name, sizeof(mdev->device_name),
+			 "%s",  DEVICE_BASE_NAME);
+	else
+		snprintf(mdev->device_name, sizeof(mdev->device_name),
+			 "%s%d",  DEVICE_BASE_NAME, mdev->mdm_data.device_id);
+	mdev->misc_device.minor	= MISC_DYNAMIC_MINOR;
+	mdev->misc_device.name	= mdev->device_name;
+	mdev->misc_device.fops	= &mdm_modem_fops;
+
+	memset((void *)&mdev->mdm_panic_blk, 0,
+		   sizeof(struct notifier_block));
+	mdev->mdm_panic_blk.notifier_call  = mdm_panic_prep;
+	atomic_notifier_chain_register(&panic_notifier_list,
+				   &mdev->mdm_panic_blk);
+
 	/* MDM2AP_ERRFATAL */
 	pres = platform_get_resource_byname(pdev, IORESOURCE_IO,
 							"MDM2AP_ERRFATAL");
@@ -602,26 +883,49 @@
 
 	mdm_drv->boot_type                  = CHARM_NORMAL_BOOT;
 
-	mdm_drv->ops      = mdm_ops;
-	mdm_drv->pdata    = pdev->dev.platform_data;
-	dump_timeout_ms = mdm_drv->pdata->ramdump_timeout_ms > 0 ?
+	mdm_drv->dump_timeout_ms = mdm_drv->pdata->ramdump_timeout_ms > 0 ?
 		mdm_drv->pdata->ramdump_timeout_ms : MDM_RDUMP_TIMEOUT;
+
+	init_completion(&mdev->mdm_needs_reload);
+	init_completion(&mdev->mdm_boot);
+	init_completion(&mdev->mdm_ram_dumps);
+
+	mdev->first_boot = 1;
+	mutex_init(&mdm_drv->peripheral_status_lock);
 }
 
-int mdm_common_create(struct platform_device  *pdev,
-					  struct mdm_ops *p_mdm_cb)
+static void mdm_deconfigure_ipc(struct mdm_device *mdev)
 {
-	int ret = -1, irq;
+	struct mdm_modem_drv *mdm_drv = &mdev->mdm_data;
 
-	mdm_drv = kzalloc(sizeof(struct mdm_modem_drv), GFP_KERNEL);
-	if (mdm_drv == NULL) {
-		pr_err("%s: kzalloc fail.\n", __func__);
-		goto alloc_err;
+	gpio_free(mdm_drv->ap2mdm_status_gpio);
+	gpio_free(mdm_drv->ap2mdm_errfatal_gpio);
+	if (GPIO_IS_VALID(mdm_drv->ap2mdm_kpdpwr_n_gpio))
+		gpio_free(mdm_drv->ap2mdm_kpdpwr_n_gpio);
+	if (GPIO_IS_VALID(mdm_drv->ap2mdm_pmic_pwr_en_gpio))
+		gpio_free(mdm_drv->ap2mdm_pmic_pwr_en_gpio);
+	gpio_free(mdm_drv->mdm2ap_status_gpio);
+	gpio_free(mdm_drv->mdm2ap_errfatal_gpio);
+	if (GPIO_IS_VALID(mdm_drv->ap2mdm_soft_reset_gpio))
+		gpio_free(mdm_drv->ap2mdm_soft_reset_gpio);
+
+	if (GPIO_IS_VALID(mdm_drv->ap2mdm_wakeup_gpio))
+		gpio_free(mdm_drv->ap2mdm_wakeup_gpio);
+
+	if (mdev->mdm_queue) {
+		destroy_workqueue(mdev->mdm_queue);
+		mdev->mdm_queue = NULL;
 	}
+	if (mdev->mdm_sfr_queue) {
+		destroy_workqueue(mdev->mdm_sfr_queue);
+		mdev->mdm_sfr_queue = NULL;
+	}
+}
 
-	mdm_modem_initialize_data(pdev, p_mdm_cb);
-	if (mdm_drv->ops->debug_state_changed_cb)
-		mdm_drv->ops->debug_state_changed_cb(mdm_debug_mask);
+static int mdm_configure_ipc(struct mdm_device *mdev)
+{
+	struct mdm_modem_drv *mdm_drv = &mdev->mdm_data;
+	int ret = -1, irq;
 
 	gpio_request(mdm_drv->ap2mdm_status_gpio, "AP2MDM_STATUS");
 	gpio_request(mdm_drv->ap2mdm_errfatal_gpio, "AP2MDM_ERRFATAL");
@@ -648,7 +952,6 @@
 			mdm_drv->usb_switch_gpio = -1;
 		}
 	}
-
 	gpio_direction_output(mdm_drv->ap2mdm_status_gpio, 0);
 	gpio_direction_output(mdm_drv->ap2mdm_errfatal_gpio, 0);
 
@@ -658,97 +961,88 @@
 	gpio_direction_input(mdm_drv->mdm2ap_status_gpio);
 	gpio_direction_input(mdm_drv->mdm2ap_errfatal_gpio);
 
-	mdm_queue = create_singlethread_workqueue("mdm_queue");
-	if (!mdm_queue) {
-		pr_err("%s: could not create workqueue. All mdm "
-				"functionality will be disabled\n",
-			__func__);
+	mdev->mdm_queue = alloc_workqueue("mdm_queue", 0, 0);
+	if (!mdev->mdm_queue) {
+		pr_err("%s: could not create mdm_queue for mdm id %d\n",
+			   __func__, mdev->mdm_data.device_id);
 		ret = -ENOMEM;
 		goto fatal_err;
 	}
 
-	mdm_sfr_queue = alloc_workqueue("mdm_sfr_queue", 0, 0);
-	if (!mdm_sfr_queue) {
-		pr_err("%s: could not create workqueue mdm_sfr_queue."
-			" All mdm functionality will be disabled\n",
-			__func__);
+	mdev->mdm_sfr_queue = alloc_workqueue("mdm_sfr_queue", 0, 0);
+	if (!mdev->mdm_sfr_queue) {
+		pr_err("%s: could not create mdm_sfr_queue for mdm id %d\n",
+			   __func__, mdev->mdm_data.device_id);
 		ret = -ENOMEM;
-		destroy_workqueue(mdm_queue);
 		goto fatal_err;
 	}
 
-	atomic_notifier_chain_register(&panic_notifier_list, &mdm_panic_blk);
-	mdm_debugfs_init();
-
 	/* Register subsystem handlers */
-	mdm_subsys_dev = subsys_register(&mdm_subsystem);
-	if (IS_ERR(mdm_subsys_dev)) {
-		ret = PTR_ERR(mdm_subsys_dev);
+	mdev->mdm_subsys_dev = subsys_register(&mdev->mdm_subsys);
+	if (IS_ERR(mdev->mdm_subsys_dev)) {
+		ret = PTR_ERR(mdev->mdm_subsys_dev);
 		goto fatal_err;
 	}
-	subsys_default_online(mdm_subsys_dev);
+	subsys_default_online(mdev->mdm_subsys_dev);
 
 	/* ERR_FATAL irq. */
-	irq = MSM_GPIO_TO_INT(mdm_drv->mdm2ap_errfatal_gpio);
+	irq = gpio_to_irq(mdm_drv->mdm2ap_errfatal_gpio);
 	if (irq < 0) {
-		pr_err("%s: could not get MDM2AP_ERRFATAL IRQ resource. "
-			"error=%d No IRQ will be generated on errfatal.",
-			__func__, irq);
+		pr_err("%s: bad MDM2AP_ERRFATAL IRQ resource, err = %d\n",
+			   __func__, irq);
 		goto errfatal_err;
 	}
 	ret = request_irq(irq, mdm_errfatal,
-		IRQF_TRIGGER_RISING , "mdm errfatal", NULL);
+			IRQF_TRIGGER_RISING , "mdm errfatal", mdev);
 
 	if (ret < 0) {
-		pr_err("%s: MDM2AP_ERRFATAL IRQ#%d request failed with error=%d"
-			". No IRQ will be generated on errfatal.",
-			__func__, irq, ret);
+		pr_err("%s: MDM2AP_ERRFATAL IRQ#%d request failed, err=%d\n",
+					__func__, irq, ret);
 		goto errfatal_err;
 	}
-	mdm_drv->mdm_errfatal_irq = irq;
+	mdev->mdm_errfatal_irq = irq;
 
 errfatal_err:
 
-	/* status irq */
-	irq = MSM_GPIO_TO_INT(mdm_drv->mdm2ap_status_gpio);
+	 /* status irq */
+	irq = gpio_to_irq(mdm_drv->mdm2ap_status_gpio);
 	if (irq < 0) {
-		pr_err("%s: could not get MDM2AP_STATUS IRQ resource. "
-			"error=%d No IRQ will be generated on status change.",
-			__func__, irq);
+		pr_err("%s: bad MDM2AP_STATUS IRQ resource, err = %d\n",
+				__func__, irq);
 		goto status_err;
 	}
 
 	ret = request_threaded_irq(irq, NULL, mdm_status_change,
 		IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_SHARED,
-		"mdm status", mdm_drv);
+		"mdm status", mdev);
 
 	if (ret < 0) {
-		pr_err("%s: MDM2AP_STATUS IRQ#%d request failed with error=%d"
-			". No IRQ will be generated on status change.",
-			__func__, irq, ret);
+		pr_err("%s: MDM2AP_STATUS IRQ#%d request failed, err=%d",
+			 __func__, irq, ret);
 		goto status_err;
 	}
-	mdm_drv->mdm_status_irq = irq;
+	mdev->mdm_status_irq = irq;
 
 status_err:
 	if (GPIO_IS_VALID(mdm_drv->mdm2ap_pblrdy)) {
-		irq = MSM_GPIO_TO_INT(mdm_drv->mdm2ap_pblrdy);
+		irq = gpio_to_irq(mdm_drv->mdm2ap_pblrdy);
 		if (irq < 0) {
-			pr_err("%s: could not get MDM2AP_PBLRDY IRQ resource",
-				__func__);
+			pr_err("%s: could not get MDM2AP_PBLRDY IRQ resource\n",
+				 __func__);
 			goto pblrdy_err;
 		}
 
 		ret = request_threaded_irq(irq, NULL, mdm_pblrdy_change,
-			IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING |
-			IRQF_SHARED,
-			"mdm pbl ready", mdm_drv);
+				IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING |
+				IRQF_SHARED,
+				"mdm pbl ready", mdev);
 
 		if (ret < 0) {
-			pr_err("%s: MDM2AP_PBL IRQ#%d request failed error=%d",
+			pr_err("%s: MDM2AP_PBL IRQ#%d request failed error=%d\n",
 				__func__, irq, ret);
 			goto pblrdy_err;
 		}
+		mdev->mdm_pblrdy_irq = irq;
 	}
 
 pblrdy_err:
@@ -759,67 +1053,140 @@
 	if (GPIO_IS_VALID(mdm_drv->ap2mdm_pmic_pwr_en_gpio))
 		gpio_direction_output(mdm_drv->ap2mdm_pmic_pwr_en_gpio, 1);
 
-	/* Perform early powerup of the external modem in order to
-	 * allow tabla devices to be found.
-	 */
-	if (mdm_drv->pdata->early_power_on)
-		mdm_drv->ops->power_on_mdm_cb(mdm_drv);
-
-	pr_info("%s: Registering mdm modem\n", __func__);
-	return misc_register(&mdm_modem_misc);
+	return 0;
 
 fatal_err:
-	gpio_free(mdm_drv->ap2mdm_status_gpio);
-	gpio_free(mdm_drv->ap2mdm_errfatal_gpio);
-	if (GPIO_IS_VALID(mdm_drv->ap2mdm_kpdpwr_n_gpio))
-		gpio_free(mdm_drv->ap2mdm_kpdpwr_n_gpio);
-	if (GPIO_IS_VALID(mdm_drv->ap2mdm_pmic_pwr_en_gpio))
-		gpio_free(mdm_drv->ap2mdm_pmic_pwr_en_gpio);
-	gpio_free(mdm_drv->mdm2ap_status_gpio);
-	gpio_free(mdm_drv->mdm2ap_errfatal_gpio);
-	if (GPIO_IS_VALID(mdm_drv->ap2mdm_soft_reset_gpio))
-		gpio_free(mdm_drv->ap2mdm_soft_reset_gpio);
-
-	if (GPIO_IS_VALID(mdm_drv->ap2mdm_wakeup_gpio))
-		gpio_free(mdm_drv->ap2mdm_wakeup_gpio);
-
-	kfree(mdm_drv);
-	ret = -ENODEV;
-
-alloc_err:
+	mdm_deconfigure_ipc(mdev);
 	return ret;
 }
 
-int mdm_common_modem_remove(struct platform_device *pdev)
+static int __devinit mdm_modem_probe(struct platform_device *pdev)
+{
+	struct mdm_device *mdev = NULL;
+	int ret = -1;
+
+	mdev = kzalloc(sizeof(struct mdm_device), GFP_KERNEL);
+	if (!mdev) {
+		pr_err("%s: kzalloc fail.\n", __func__);
+		ret = -ENOMEM;
+		goto init_err;
+	}
+
+	mdm_modem_initialize_data(pdev, mdev);
+
+	if (mdm_ops->debug_state_changed_cb)
+		mdm_ops->debug_state_changed_cb(mdm_debug_mask);
+
+	if (mdm_configure_ipc(mdev)) {
+		pr_err("%s: mdm_configure_ipc failed, id = %d\n",
+			   __func__, mdev->mdm_data.device_id);
+		goto init_err;
+	}
+
+	pr_debug("%s: Registering mdm id %d\n", __func__,
+			mdev->mdm_data.device_id);
+	ret = misc_register(&mdev->misc_device);
+	if (ret) {
+		pr_err("%s: failed registering mdm id %d, ret = %d\n",
+			   __func__, mdev->mdm_data.device_id, ret);
+		mdm_deconfigure_ipc(mdev);
+		goto init_err;
+	} else {
+		pr_err("%s: registered mdm id %d\n",
+			   __func__, mdev->mdm_data.device_id);
+
+		mdm_device_list_add(mdev);
+		INIT_DELAYED_WORK(&mdev->mdm2ap_status_check_work,
+					mdm2ap_status_check);
+		INIT_WORK(&mdev->mdm_status_work, mdm_status_fn);
+		INIT_WORK(&mdev->sfr_reason_work, mdm_restart_reason_fn);
+
+		/* Perform early powerup of the external modem in order to
+		 * allow tabla devices to be found.
+		 */
+		if (mdev->mdm_data.pdata->early_power_on)
+			mdm_ops->power_on_mdm_cb(&mdev->mdm_data);
+	}
+
+	return ret;
+
+init_err:
+	kfree(mdev);
+	return ret;
+}
+
+static int __devexit mdm_modem_remove(struct platform_device *pdev)
 {
 	int ret;
+	struct mdm_device *mdev = mdm_get_device_by_device_id(pdev->id);
 
-	gpio_free(mdm_drv->ap2mdm_status_gpio);
-	gpio_free(mdm_drv->ap2mdm_errfatal_gpio);
-	if (GPIO_IS_VALID(mdm_drv->ap2mdm_kpdpwr_n_gpio))
-		gpio_free(mdm_drv->ap2mdm_kpdpwr_n_gpio);
-	if (GPIO_IS_VALID(mdm_drv->ap2mdm_pmic_pwr_en_gpio))
-		gpio_free(mdm_drv->ap2mdm_pmic_pwr_en_gpio);
-	gpio_free(mdm_drv->mdm2ap_status_gpio);
-	gpio_free(mdm_drv->mdm2ap_errfatal_gpio);
-	if (GPIO_IS_VALID(mdm_drv->ap2mdm_soft_reset_gpio))
-		gpio_free(mdm_drv->ap2mdm_soft_reset_gpio);
+	if (!mdev)
+		return -ENODEV;
 
-	if (GPIO_IS_VALID(mdm_drv->ap2mdm_wakeup_gpio))
-		gpio_free(mdm_drv->ap2mdm_wakeup_gpio);
-
-	kfree(mdm_drv);
-
-	ret = misc_deregister(&mdm_modem_misc);
+	pr_debug("%s: removing device id %d\n",
+			__func__, mdev->mdm_data.device_id);
+	mdm_deconfigure_ipc(mdev);
+	ret = misc_deregister(&mdev->misc_device);
+	mdm_device_list_remove(mdev);
+	kfree(mdev);
 	return ret;
 }
 
-void mdm_common_modem_shutdown(struct platform_device *pdev)
+static void mdm_modem_shutdown(struct platform_device *pdev)
 {
-	mdm_disable_irqs();
+	struct mdm_modem_drv *mdm_drv;
+	struct mdm_device *mdev = mdm_get_device_by_device_id(pdev->id);
+	if (!mdev)
+		return;
 
-	mdm_drv->ops->power_down_mdm_cb(mdm_drv);
+	pr_debug("%s: shutting down device id %d\n",
+		 __func__, mdev->mdm_data.device_id);
+
+	mdm_disable_irqs(mdev);
+	mdm_drv = &mdev->mdm_data;
+	mdm_ops->power_down_mdm_cb(mdm_drv);
 	if (GPIO_IS_VALID(mdm_drv->ap2mdm_pmic_pwr_en_gpio))
 		gpio_direction_output(mdm_drv->ap2mdm_pmic_pwr_en_gpio, 0);
 }
 
+static struct of_device_id mdm_match_table[] = {
+	{.compatible = "qcom,mdm2_modem,mdm2_modem.1"},
+	{},
+};
+
+static struct platform_driver mdm_modem_driver = {
+	.probe    = mdm_modem_probe,
+	.remove   = __devexit_p(mdm_modem_remove),
+	.shutdown = mdm_modem_shutdown,
+	.driver         = {
+		.name = "mdm2_modem",
+		.owner = THIS_MODULE,
+		.of_match_table = mdm_match_table,
+	},
+};
+
+static int __init mdm_modem_init(void)
+{
+	int ret;
+
+	ret = mdm_get_ops(&mdm_ops);
+	if (ret)
+		return ret;
+
+	INIT_LIST_HEAD(&mdm_devices);
+	mdm_debugfs_init();
+	return platform_driver_register(&mdm_modem_driver);
+}
+
+static void __exit mdm_modem_exit(void)
+{
+	platform_driver_unregister(&mdm_modem_driver);
+}
+
+module_init(mdm_modem_init);
+module_exit(mdm_modem_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("mdm modem driver");
+MODULE_VERSION("2.0");
+MODULE_ALIAS("mdm_modem");
diff --git a/arch/arm/mach-msm/mdm_private.h b/arch/arm/mach-msm/mdm_private.h
index 92fb141..5a91cf9 100644
--- a/arch/arm/mach-msm/mdm_private.h
+++ b/arch/arm/mach-msm/mdm_private.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -44,25 +44,22 @@
 	unsigned mdm2ap_pblrdy;
 	unsigned usb_switch_gpio;
 
-	int mdm_errfatal_irq;
-	int mdm_status_irq;
-	int mdm_ready;
+	atomic_t mdm_ready;
 	int mdm_boot_status;
 	int mdm_ram_dump_status;
 	enum charm_boot_type boot_type;
 	int mdm_debug_on;
 	int mdm_unexpected_reset_occurred;
 	int disable_status_check;
+	unsigned int dump_timeout_ms;
+	int power_on_count;
+	int peripheral_status;
+	struct mutex peripheral_status_lock;
+	int device_id;
 
-	struct mdm_ops *ops;
 	struct mdm_platform_data *pdata;
 };
-
-int mdm_common_create(struct platform_device  *pdev,
-					  struct mdm_ops *mdm_cb);
-int mdm_common_modem_remove(struct platform_device *pdev);
-void mdm_common_modem_shutdown(struct platform_device *pdev);
-void mdm_common_set_debug_state(int value);
+int mdm_get_ops(struct mdm_ops **mdm_ops);
 
 #endif
 
diff --git a/arch/arm/mach-msm/memory.c b/arch/arm/mach-msm/memory.c
index 1680993..7a7fb99 100644
--- a/arch/arm/mach-msm/memory.c
+++ b/arch/arm/mach-msm/memory.c
@@ -315,6 +315,8 @@
 	unsigned long memory_remove_prop_length;
 	unsigned long memory_size_prop_length;
 	unsigned int *memory_size_prop;
+	unsigned int *memory_reserve_prop;
+	unsigned long memory_reserve_prop_length;
 	unsigned int memory_size;
 	unsigned int memory_start;
 	int ret;
@@ -326,7 +328,11 @@
 						"qcom,memblock-remove",
 						&memory_remove_prop_length);
 
-	if (memory_name_prop || memory_remove_prop) {
+	memory_reserve_prop = of_get_flat_dt_prop(node,
+						"qcom,memblock-reserve",
+						&memory_reserve_prop_length);
+
+	if (memory_name_prop || memory_remove_prop || memory_reserve_prop) {
 		if (!check_for_compat(node))
 			goto out;
 	} else {
@@ -365,7 +371,7 @@
 	if (memory_remove_prop) {
 		if (memory_remove_prop_length != (2*sizeof(unsigned int))) {
 			WARN(1, "Memory remove malformed\n");
-			goto out;
+			goto mem_reserve;
 		}
 
 		memory_start = be32_to_cpu(memory_remove_prop[0]);
@@ -380,11 +386,52 @@
 				memory_start, memory_start+memory_size);
 	}
 
+mem_reserve:
+
+	if (memory_reserve_prop) {
+		if (memory_reserve_prop_length != (2*sizeof(unsigned int))) {
+			WARN(1, "Memory reserve malformed\n");
+			goto out;
+		}
+
+		memory_start = be32_to_cpu(memory_reserve_prop[0]);
+		memory_size = be32_to_cpu(memory_reserve_prop[1]);
+
+		ret = memblock_reserve(memory_start, memory_size);
+		if (ret)
+			WARN(1, "Failed to reserve memory %x-%x\n",
+				memory_start, memory_start+memory_size);
+		else
+			pr_info("Node %s memblock_reserve memory %x-%x\n",
+				uname, memory_start, memory_start+memory_size);
+	}
+
 out:
 	return 0;
 }
 
-/* This function scans the device tree to populate the memory hole table */
+/* Function to remove any meminfo blocks which are of size zero */
+static void merge_meminfo(void)
+{
+	int i = 0;
+
+	while (i < meminfo.nr_banks) {
+		struct membank *bank = &meminfo.bank[i];
+
+		if (bank->size == 0) {
+			memmove(bank, bank + 1,
+			(meminfo.nr_banks - i) * sizeof(*bank));
+			meminfo.nr_banks--;
+			continue;
+		}
+		i++;
+	}
+}
+
+/*
+ * Function to scan the device tree and adjust the meminfo table to
+ * reflect the memory holes.
+ */
 int __init dt_scan_for_memory_hole(unsigned long node, const char *uname,
 		int depth, void *data)
 {
@@ -413,16 +460,6 @@
 		hole_start = be32_to_cpu(memory_remove_prop[0]);
 		hole_size = be32_to_cpu(memory_remove_prop[1]);
 
-		if (hole_start + hole_size <= MAX_HOLE_ADDRESS) {
-			if (memory_hole_start == 0 && memory_hole_end == 0) {
-				memory_hole_start = hole_start;
-				memory_hole_end = hole_start + hole_size;
-			} else if ((memory_hole_end - memory_hole_start)
-							<= hole_size) {
-				memory_hole_start = hole_start;
-				memory_hole_end = hole_start + hole_size;
-			}
-		}
 		adjust_meminfo(hole_start, hole_size);
 	}
 
@@ -452,6 +489,7 @@
 			bank[1].start = (start + size);
 			bank[1].size -= (bank->size + size);
 			bank[1].highmem = 0;
+			merge_meminfo();
 		}
 	}
 }
diff --git a/arch/arm/mach-msm/memory_topology.c b/arch/arm/mach-msm/memory_topology.c
index 97195e3..de90427 100644
--- a/arch/arm/mach-msm/memory_topology.c
+++ b/arch/arm/mach-msm/memory_topology.c
@@ -20,12 +20,44 @@
 #include <mach/msm_memtypes.h>
 #include <mach/socinfo.h>
 #include <mach/msm_smem.h>
-#include "smd_private.h"
 
 #if defined(CONFIG_ARCH_MSM8960)
 #include "rpm_resources.h"
 #endif
 
+struct smem_ram_ptn {
+	char name[16];
+	unsigned start;
+	unsigned size;
+
+	/* RAM Partition attribute: READ_ONLY, READWRITE etc.  */
+	unsigned attr;
+
+	/* RAM Partition category: EBI0, EBI1, IRAM, IMEM */
+	unsigned category;
+
+	/* RAM Partition domain: APPS, MODEM, APPS & MODEM (SHARED) etc. */
+	unsigned domain;
+
+	/* RAM Partition type: system, bootloader, appsboot, apps etc. */
+	unsigned type;
+
+	/* reserved for future expansion without changing version number */
+	unsigned reserved2, reserved3, reserved4, reserved5;
+} __attribute__ ((__packed__));
+
+
+struct smem_ram_ptable {
+	#define _SMEM_RAM_PTABLE_MAGIC_1 0x9DA5E0A8
+	#define _SMEM_RAM_PTABLE_MAGIC_2 0xAF9EC4E2
+	unsigned magic[2];
+	unsigned version;
+	unsigned reserved1;
+	unsigned len;
+	struct smem_ram_ptn parts[32];
+	unsigned buf;
+} __attribute__ ((__packed__));
+
 static struct mem_region_t {
 	u64 start;
 	u64 size;
diff --git a/arch/arm/mach-msm/msm_ipc_router_security.c b/arch/arm/mach-msm/msm_ipc_router_security.c
index 69efd13..63c8cd7 100644
--- a/arch/arm/mach-msm/msm_ipc_router_security.c
+++ b/arch/arm/mach-msm/msm_ipc_router_security.c
@@ -22,6 +22,7 @@
 #include <linux/uaccess.h>
 #include <linux/kernel.h>
 #include <linux/msm_ipc.h>
+#include <linux/rwsem.h>
 
 #include <asm/uaccess.h>
 
@@ -40,7 +41,7 @@
 	gid_t *group_id;
 };
 
-static DEFINE_MUTEX(security_rules_lock);
+static DECLARE_RWSEM(security_rules_lock_lha4);
 static struct list_head security_rules[SEC_RULES_HASH_SZ];
 static DECLARE_COMPLETION(irsc_completion);
 
@@ -146,7 +147,7 @@
 	}
 
 	key = rule->service_id & (SEC_RULES_HASH_SZ - 1);
-	mutex_lock(&security_rules_lock);
+	down_write(&security_rules_lock_lha4);
 	if (rule->service_id == ALL_SERVICE) {
 		temp_rule = list_first_entry(&security_rules[key],
 					     struct security_rule, list);
@@ -155,7 +156,7 @@
 		kfree(temp_rule);
 	}
 	list_add_tail(&rule->list, &security_rules[key]);
-	mutex_unlock(&security_rules_lock);
+	up_write(&security_rules_lock_lha4);
 
 	if (rule->service_id == ALL_SERVICE)
 		msm_ipc_sync_default_sec_rule((void *)rule);
@@ -198,10 +199,10 @@
 	rule->instance_id = ALL_INSTANCE;
 	rule->num_group_info = 1;
 	*(rule->group_id) = AID_NET_RAW;
-	mutex_lock(&security_rules_lock);
+	down_write(&security_rules_lock_lha4);
 	key = (ALL_SERVICE & (SEC_RULES_HASH_SZ - 1));
 	list_add_tail(&rule->list, &security_rules[key]);
-	mutex_unlock(&security_rules_lock);
+	up_write(&security_rules_lock_lha4);
 	return 0;
 }
 
@@ -222,12 +223,12 @@
 	struct security_rule *rule;
 
 	key = (service_id & (SEC_RULES_HASH_SZ - 1));
-	mutex_lock(&security_rules_lock);
+	down_read(&security_rules_lock_lha4);
 	/* Return the rule for a specific <service:instance>, if found. */
 	list_for_each_entry(rule, &security_rules[key], list) {
 		if ((rule->service_id == service_id) &&
 		    (rule->instance_id == instance_id)) {
-			mutex_unlock(&security_rules_lock);
+			up_read(&security_rules_lock_lha4);
 			return (void *)rule;
 		}
 	}
@@ -236,7 +237,7 @@
 	list_for_each_entry(rule, &security_rules[key], list) {
 		if ((rule->service_id == service_id) &&
 		    (rule->instance_id == ALL_INSTANCE)) {
-			mutex_unlock(&security_rules_lock);
+			up_read(&security_rules_lock_lha4);
 			return (void *)rule;
 		}
 	}
@@ -246,10 +247,11 @@
 	list_for_each_entry(rule, &security_rules[key], list) {
 		if ((rule->service_id == ALL_SERVICE) &&
 		    (rule->instance_id == ALL_INSTANCE)) {
-			mutex_unlock(&security_rules_lock);
+			up_read(&security_rules_lock_lha4);
 			return (void *)rule;
 		}
 	}
+	up_read(&security_rules_lock_lha4);
 	return NULL;
 }
 EXPORT_SYMBOL(msm_ipc_get_security_rule);
diff --git a/arch/arm/mach-msm/nohlt.c b/arch/arm/mach-msm/nohlt.c
index e598ed0..94cbc4b 100644
--- a/arch/arm/mach-msm/nohlt.c
+++ b/arch/arm/mach-msm/nohlt.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2009, 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
@@ -28,11 +28,18 @@
 	return 0;
 }
 
-DEFINE_SIMPLE_ATTRIBUTE(nohalt_ops, NULL, set_nohalt, "%llu\n");
+static int get_nohalt(void *data, u64 *val)
+{
+	*val = (unsigned int)get_hlt();
+
+	return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(nohalt_ops, get_nohalt, set_nohalt, "%llu\n");
 
 static int __init init_hlt_debug(void)
 {
-	debugfs_create_file("nohlt", 0200, NULL, NULL, &nohalt_ops);
+	debugfs_create_file("nohlt", 0600, NULL, NULL, &nohalt_ops);
 
 	return 0;
 }
diff --git a/arch/arm/mach-msm/ocmem_allocator.c b/arch/arm/mach-msm/ocmem_allocator.c
index 203bb60..a0ff9f9 100644
--- a/arch/arm/mach-msm/ocmem_allocator.c
+++ b/arch/arm/mach-msm/ocmem_allocator.c
@@ -36,24 +36,22 @@
 	reserve:    Enable libgenpool to simulate tail allocations
 */
 
-unsigned long allocate_head(struct ocmem_zone *z, unsigned long size)
+int allocate_head(struct ocmem_zone *z, unsigned long size,
+							unsigned long *offset)
 {
+	*offset  = gen_pool_alloc(z->z_pool, size);
 
-	unsigned long offset;
-
-	offset  = gen_pool_alloc(z->z_pool, size);
-
-	if (!offset)
+	if (!(*offset))
 		return -ENOMEM;
 
 	z->z_head += size;
 	z->z_free -= size;
-	return offset;
+	return 0;
 }
 
-unsigned long allocate_tail(struct ocmem_zone *z, unsigned long size)
+int allocate_tail(struct ocmem_zone *z, unsigned long size,
+							unsigned long *offset)
 {
-	unsigned long offset;
 	unsigned long reserve;
 	unsigned long head;
 
@@ -63,17 +61,17 @@
 	reserve = z->z_tail - z->z_head - size;
 	if (reserve) {
 		head = gen_pool_alloc(z->z_pool, reserve);
-		offset = gen_pool_alloc(z->z_pool, size);
+		*offset = gen_pool_alloc(z->z_pool, size);
 		gen_pool_free(z->z_pool, head, reserve);
 	} else
-		offset = gen_pool_alloc(z->z_pool, size);
+		*offset = gen_pool_alloc(z->z_pool, size);
 
-	if (!offset)
+	if (!(*offset))
 		return -ENOMEM;
 
 	z->z_tail -= size;
 	z->z_free -= size;
-	return offset;
+	return 0;
 }
 
 int free_head(struct ocmem_zone *z, unsigned long offset,
diff --git a/arch/arm/mach-msm/ocmem_core.c b/arch/arm/mach-msm/ocmem_core.c
index 9b18c59..153864d 100644
--- a/arch/arm/mach-msm/ocmem_core.c
+++ b/arch/arm/mach-msm/ocmem_core.c
@@ -759,7 +759,7 @@
 	return -EINVAL;
 }
 
-#if defined(CONFIG_MSM_OCMEM_POWER_DISABLE)
+#if defined(CONFIG_MSM_OCMEM_DEBUG_ALWAYS_ON)
 static int ocmem_core_set_default_state(void)
 {
 	int rc = 0;
@@ -775,7 +775,14 @@
 
 	return 0;
 }
+#else
+static int ocmem_core_set_default_state(void)
+{
+	return 0;
+}
+#endif
 
+#if defined(CONFIG_MSM_OCMEM_POWER_DISABLE)
 /* Initializes a region to be turned ON in wide mode */
 static int ocmem_region_set_default_state(unsigned int r_num)
 {
@@ -800,15 +807,9 @@
 {
 	return 0;
 }
-
-static int ocmem_core_set_default_state(void)
-{
-	return 0;
-}
 #endif
 
 #if defined(CONFIG_MSM_OCMEM_POWER_DEBUG)
-
 static int read_hw_region_state(unsigned region_num)
 {
 	int state;
diff --git a/arch/arm/mach-msm/ocmem_sched.c b/arch/arm/mach-msm/ocmem_sched.c
index a14b960..a3fd6b2 100644
--- a/arch/arm/mach-msm/ocmem_sched.c
+++ b/arch/arm/mach-msm/ocmem_sched.c
@@ -724,6 +724,7 @@
 	bool retry;
 	struct ocmem_region *spanned_r = NULL;
 	struct ocmem_region *overlap_r = NULL;
+	int rc = 0;
 
 	struct ocmem_req *matched_req = NULL;
 	struct ocmem_region *matched_region = NULL;
@@ -767,9 +768,10 @@
 	if (overlap_r == NULL) {
 		/* no conflicting regions, schedule this region */
 		zone->z_ops->free(zone, curr_start, curr_sz);
-		alloc_addr = zone->z_ops->allocate(zone, curr_sz + growth_sz);
+		rc = zone->z_ops->allocate(zone, curr_sz + growth_sz,
+								&alloc_addr);
 
-		if (alloc_addr < 0) {
+		if (rc) {
 			pr_err("ocmem: zone allocation operation failed\n");
 			goto internal_error;
 		}
@@ -933,6 +935,7 @@
 	struct ocmem_region *matched_region = NULL;
 	struct ocmem_region *region = NULL;
 	unsigned long alloc_addr = 0x0;
+	int rc =  0;
 
 	struct ocmem_zone *zone = get_zone(owner);
 
@@ -957,9 +960,9 @@
 		goto internal_error;
 	}
 
-	alloc_addr = zone->z_ops->allocate(zone, new_sz);
+	rc = zone->z_ops->allocate(zone, new_sz, &alloc_addr);
 
-	if (alloc_addr < 0) {
+	if (rc) {
 		pr_err("Zone Allocation operation failed\n");
 		goto internal_error;
 	}
@@ -1032,6 +1035,7 @@
 	enum client_prio prio = req->prio;
 	unsigned long alloc_addr = 0x0;
 	bool retry;
+	int rc = 0;
 
 	struct ocmem_region *spanned_r = NULL;
 	struct ocmem_region *overlap_r = NULL;
@@ -1056,13 +1060,6 @@
 			goto invalid_op_error;
 	}
 
-	region = create_region();
-
-	if (!region) {
-		pr_err("ocmem: Unable to create region\n");
-		goto invalid_op_error;
-	}
-
 	retry = false;
 
 	pr_debug("ocmem: do_allocate: %s request %p size %lx\n",
@@ -1077,10 +1074,18 @@
 	overlap_r = find_region_intersection(zone->z_head, zone->z_head + sz);
 
 	if (overlap_r == NULL) {
-		/* no conflicting regions, schedule this region */
-		alloc_addr = zone->z_ops->allocate(zone, sz);
 
-		if (alloc_addr < 0) {
+		region = create_region();
+
+		if (!region) {
+			pr_err("ocmem: Unable to create region\n");
+			goto invalid_op_error;
+		}
+
+		/* no conflicting regions, schedule this region */
+		rc = zone->z_ops->allocate(zone, sz, &alloc_addr);
+
+		if (rc) {
 			pr_err("Zone Allocation operation failed\n");
 			goto internal_error;
 		}
@@ -1172,7 +1177,6 @@
 
 trigger_eviction:
 	pr_debug("Trigger eviction of region %p\n", overlap_r);
-	destroy_region(region);
 	return OP_EVICT;
 
 err_not_supported:
diff --git a/arch/arm/mach-msm/pil-q6v5-lpass.c b/arch/arm/mach-msm/pil-q6v5-lpass.c
index 19b5671..6cd6ffe 100644
--- a/arch/arm/mach-msm/pil-q6v5-lpass.c
+++ b/arch/arm/mach-msm/pil-q6v5-lpass.c
@@ -176,12 +176,25 @@
 
 static int pil_lpass_reset_trusted(struct pil_desc *pil)
 {
+	struct q6v5_data *drv = container_of(pil, struct q6v5_data, desc);
+	int ret;
+
+	ret = clk_prepare_enable(drv->axi_clk);
+	if (ret)
+		return ret;
 	return pas_auth_and_reset(PAS_Q6);
 }
 
 static int pil_lpass_shutdown_trusted(struct pil_desc *pil)
 {
-	return pas_shutdown(PAS_Q6);
+	struct q6v5_data *drv = container_of(pil, struct q6v5_data, desc);
+	int ret;
+
+	ret = pas_shutdown(PAS_Q6);
+	if (ret)
+		return ret;
+	clk_disable_unprepare(drv->axi_clk);
+	return 0;
 }
 
 static struct pil_reset_ops pil_lpass_ops_trusted = {
diff --git a/arch/arm/mach-msm/pm-8x60.c b/arch/arm/mach-msm/pm-8x60.c
index 5c1b5bf..7792276 100644
--- a/arch/arm/mach-msm/pm-8x60.c
+++ b/arch/arm/mach-msm/pm-8x60.c
@@ -30,11 +30,14 @@
 #include <linux/of_platform.h>
 #include <linux/regulator/krait-regulator.h>
 #include <linux/cpu.h>
+#include <linux/clk.h>
 #include <mach/msm_iomap.h>
 #include <mach/socinfo.h>
 #include <mach/system.h>
 #include <mach/scm.h>
 #include <mach/socinfo.h>
+#define CREATE_TRACE_POINTS
+#include <mach/trace_msm_low_power.h>
 #include <mach/msm-krait-l2-accessors.h>
 #include <mach/msm_bus.h>
 #include <asm/cacheflush.h>
@@ -56,8 +59,7 @@
 #include "timer.h"
 #include "pm-boot.h"
 #include <mach/event_timer.h>
-#define CREATE_TRACE_POINTS
-#include "trace_msm_low_power.h"
+
 #define SCM_L2_RETENTION	(0x2)
 #define SCM_CMD_TERMINATE_PC	(0x2)
 
@@ -130,6 +132,7 @@
 static bool msm_no_ramp_down_pc;
 static struct msm_pm_sleep_status_data *msm_pm_slp_sts;
 static bool msm_pm_pc_reset_timer;
+static struct clk *pnoc_clk;
 
 static int msm_pm_get_pc_mode(struct device_node *node,
 		const char *key, uint32_t *pc_mode_val)
@@ -855,8 +858,10 @@
 	time = ktime_to_ns(ktime_get());
 
 	if (sleep_mode == MSM_PM_SLEEP_MODE_POWER_COLLAPSE) {
+		int64_t ns = msm_pm_timer_enter_idle();
 		notify_rpm = true;
-		sleep_delay = (uint32_t)msm_pm_timer_enter_idle();
+		do_div(ns, NSEC_PER_SEC / SCLK_HZ);
+		sleep_delay = (uint32_t)ns;
 
 		if (sleep_delay == 0) /* 0 would mean infinite time */
 			sleep_delay = 1;
@@ -881,7 +886,11 @@
 
 	case MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE:
 		collapsed = msm_pm_power_collapse_standalone(true);
-		exit_stat = MSM_PM_STAT_IDLE_STANDALONE_POWER_COLLAPSE;
+		if (collapsed)
+			exit_stat = MSM_PM_STAT_IDLE_STANDALONE_POWER_COLLAPSE;
+		else
+			exit_stat
+			    = MSM_PM_STAT_IDLE_FAILED_STANDALONE_POWER_COLLAPSE;
 		break;
 
 	case MSM_PM_SLEEP_MODE_POWER_COLLAPSE:
@@ -891,7 +900,11 @@
 		collapsed = msm_pm_power_collapse(true);
 		timer_halted = true;
 
-		exit_stat = MSM_PM_STAT_IDLE_POWER_COLLAPSE;
+		if (collapsed)
+			exit_stat = MSM_PM_STAT_IDLE_POWER_COLLAPSE;
+		else
+			exit_stat = MSM_PM_STAT_IDLE_FAILED_POWER_COLLAPSE;
+
 		msm_pm_timer_exit_idle(timer_halted);
 		break;
 
@@ -927,13 +940,13 @@
 
 int msm_pm_wait_cpu_shutdown(unsigned int cpu)
 {
-	int timeout = 10;
+	int timeout = 0;
 
 	if (!msm_pm_slp_sts)
 		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
@@ -944,10 +957,10 @@
 		if (acc_sts & msm_pm_slp_sts[cpu].mask)
 			return 0;
 		udelay(100);
+		WARN(++timeout == 10, "CPU%u didn't collape within 1ms\n",
+					cpu);
 	}
 
-	pr_info("%s(): Timed out waiting for CPU %u SPM to enter sleep state",
-		__func__, cpu);
 	return -EBUSY;
 }
 
@@ -1045,6 +1058,7 @@
 		int ret = -ENODEV;
 		uint32_t power;
 		uint32_t msm_pm_max_sleep_time = 0;
+		int collapsed = 0;
 
 		if (MSM_PM_DEBUG_SUSPEND & msm_pm_debug_mask)
 			pr_info("%s: power collapse\n", __func__);
@@ -1068,7 +1082,7 @@
 						msm_pm_max_sleep_time,
 						rs_limits, false, true);
 			if (!ret) {
-				int collapsed = msm_pm_power_collapse(false);
+				collapsed = msm_pm_power_collapse(false);
 				if (pm_sleep_ops.exit_sleep) {
 					pm_sleep_ops.exit_sleep(rs_limits,
 						false, true, collapsed);
@@ -1079,7 +1093,10 @@
 				__func__);
 		}
 		time = msm_pm_timer_exit_suspend(time, period);
-		msm_pm_add_stat(MSM_PM_STAT_SUSPEND, time);
+		if (collapsed)
+			msm_pm_add_stat(MSM_PM_STAT_SUSPEND, time);
+		else
+			msm_pm_add_stat(MSM_PM_STAT_FAILED_SUSPEND, time);
 	} else if (allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE]) {
 		if (MSM_PM_DEBUG_SUSPEND & msm_pm_debug_mask)
 			pr_info("%s: standalone power collapse\n", __func__);
@@ -1107,9 +1124,24 @@
 		pm_sleep_ops = *ops;
 }
 
+int msm_suspend_prepare(void)
+{
+	if (pnoc_clk != NULL)
+		clk_disable_unprepare(pnoc_clk);
+	return 0;
+}
+
+void msm_suspend_wake(void)
+{
+	if (pnoc_clk != NULL)
+		clk_prepare_enable(pnoc_clk);
+}
+
 static const struct platform_suspend_ops msm_pm_ops = {
 	.enter = msm_pm_enter,
 	.valid = suspend_valid_only_mem,
+	.prepare_late = msm_suspend_prepare,
+	.wake = msm_suspend_wake,
 };
 
 static int __devinit msm_pm_snoc_client_probe(struct platform_device *pdev)
@@ -1592,6 +1624,18 @@
 		return rc;
 	}
 
+	pnoc_clk = clk_get_sys("pm_8x60", "bus_clk");
+
+	if (IS_ERR(pnoc_clk))
+		pnoc_clk = NULL;
+	else {
+		clk_set_rate(pnoc_clk, 19200000);
+		rc = clk_prepare_enable(pnoc_clk);
+
+		if (rc)
+			pr_err("%s: PNOC clock enable failed\n", __func__);
+	}
+
 	return platform_driver_register(&msm_pm_8x60_driver);
 }
 device_initcall(msm_pm_8x60_init);
diff --git a/arch/arm/mach-msm/rpm-smd.c b/arch/arm/mach-msm/rpm-smd.c
index 1eb66f4..38ed867 100644
--- a/arch/arm/mach-msm/rpm-smd.c
+++ b/arch/arm/mach-msm/rpm-smd.c
@@ -36,9 +36,9 @@
 #include <mach/socinfo.h>
 #include <mach/msm_smd.h>
 #include <mach/rpm-smd.h>
-#include "rpm-notifier.h"
 #define CREATE_TRACE_POINTS
-#include "trace_rpm_smd.h"
+#include <mach/trace_rpm_smd.h>
+#include "rpm-notifier.h"
 /* Debug Definitions */
 
 enum {
diff --git a/arch/arm/mach-msm/sdio_al_dloader.c b/arch/arm/mach-msm/sdio_al_dloader.c
index b0cb88f..f3effa8 100644
--- a/arch/arm/mach-msm/sdio_al_dloader.c
+++ b/arch/arm/mach-msm/sdio_al_dloader.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
@@ -228,6 +228,7 @@
 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 -
@@ -2388,6 +2389,14 @@
 	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__);
@@ -2478,6 +2487,7 @@
 		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);
 	}
@@ -2518,6 +2528,7 @@
 		goto exit_err;
 	}
 
+	atomic_set(&sdio_dld_setup_done, 1);
 	return 0;
 
 exit_err:
@@ -2526,7 +2537,9 @@
 	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;
 }
 
@@ -2534,22 +2547,24 @@
 {
 	int status = 0;
 
-	del_timer_sync(&sdio_dld->timer);
-	del_timer_sync(&sdio_dld->push_timer);
-
-	sdio_dld_dealloc_local_buffers();
+	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");
diff --git a/arch/arm/mach-msm/smd.c b/arch/arm/mach-msm/smd.c
index a177593..4649390 100644
--- a/arch/arm/mach-msm/smd.c
+++ b/arch/arm/mach-msm/smd.c
@@ -73,7 +73,6 @@
 #endif
 
 #define MODULE_NAME "msm_smd"
-#define SMEM_VERSION 0x000B
 #define SMD_VERSION 0x00020000
 #define SMSM_SNAPSHOT_CNT 64
 #define SMSM_SNAPSHOT_SIZE ((SMSM_NUM_ENTRIES + 1) * 4)
@@ -3802,6 +3801,9 @@
 {
 	int ret;
 
+	if (!smem_initialized_check())
+		return -ENODEV;
+
 	SMD_INFO("smd probe\n");
 	INIT_WORK(&probe_work, smd_channel_probe_worker);
 
diff --git a/arch/arm/mach-msm/smd_private.h b/arch/arm/mach-msm/smd_private.h
index 4fe9592..2096063 100644
--- a/arch/arm/mach-msm/smd_private.h
+++ b/arch/arm/mach-msm/smd_private.h
@@ -155,27 +155,6 @@
 
 struct smd_half_channel_access *get_half_ch_funcs(unsigned ch_type);
 
-struct smem_ram_ptn {
-	char name[16];
-	unsigned start;
-	unsigned size;
-
-	/* RAM Partition attribute: READ_ONLY, READWRITE etc.  */
-	unsigned attr;
-
-	/* RAM Partition category: EBI0, EBI1, IRAM, IMEM */
-	unsigned category;
-
-	/* RAM Partition domain: APPS, MODEM, APPS & MODEM (SHARED) etc. */
-	unsigned domain;
-
-	/* RAM Partition type: system, bootloader, appsboot, apps etc. */
-	unsigned type;
-
-	/* reserved for future expansion without changing version number */
-	unsigned reserved2, reserved3, reserved4, reserved5;
-} __attribute__ ((__packed__));
-
 struct smd_channel {
 	volatile void __iomem *send; /* some variant of smd_half_channel */
 	volatile void __iomem *recv; /* some variant of smd_half_channel */
@@ -217,54 +196,6 @@
 	struct smd_half_channel_access *half_ch;
 };
 
-struct smem_ram_ptable {
-	#define _SMEM_RAM_PTABLE_MAGIC_1 0x9DA5E0A8
-	#define _SMEM_RAM_PTABLE_MAGIC_2 0xAF9EC4E2
-	unsigned magic[2];
-	unsigned version;
-	unsigned reserved1;
-	unsigned len;
-	struct smem_ram_ptn parts[32];
-	unsigned buf;
-} __attribute__ ((__packed__));
-
-/* SMEM RAM Partition */
-enum {
-	DEFAULT_ATTRB = ~0x0,
-	READ_ONLY = 0x0,
-	READWRITE,
-};
-
-enum {
-	DEFAULT_CATEGORY = ~0x0,
-	SMI = 0x0,
-	EBI1,
-	EBI2,
-	QDSP6,
-	IRAM,
-	IMEM,
-	EBI0_CS0,
-	EBI0_CS1,
-	EBI1_CS0,
-	EBI1_CS1,
-	SDRAM = 0xE,
-};
-
-enum {
-	DEFAULT_DOMAIN = 0x0,
-	APPS_DOMAIN,
-	MODEM_DOMAIN,
-	SHARED_DOMAIN,
-};
-
-enum {
-	SYS_MEMORY = 1,        /* system memory*/
-	BOOT_REGION_MEMORY1,   /* boot loader memory 1*/
-	BOOT_REGION_MEMORY2,   /* boot loader memory 2,reserved*/
-	APPSBL_MEMORY,         /* apps boot loader memory*/
-	APPS_MEMORY,           /* apps  usage memory*/
-};
-
 extern spinlock_t smem_lock;
 
 
diff --git a/arch/arm/mach-msm/smem.c b/arch/arm/mach-msm/smem.c
index 2204609..bbb6ce0 100644
--- a/arch/arm/mach-msm/smem.c
+++ b/arch/arm/mach-msm/smem.c
@@ -35,6 +35,10 @@
 #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
+
 enum {
 	MSM_SMEM_DEBUG = 1U << 0,
 	MSM_SMEM_INFO = 1U << 1,
@@ -57,6 +61,7 @@
 
 static void *smem_ramdump_dev;
 static DEFINE_MUTEX(spinlock_init_lock);
+static DEFINE_SPINLOCK(smem_init_check_lock);
 
 struct restart_notifier_block {
 	unsigned processor;
@@ -187,12 +192,48 @@
 }
 EXPORT_SYMBOL(smem_alloc);
 
-void *smem_find(unsigned id, unsigned size_in)
+static void *__smem_get_entry(unsigned id, unsigned *size, bool skip_init_check)
+{
+	struct smem_shared *shared = (void *) MSM_SHARED_RAM_BASE;
+	struct smem_heap_entry *toc = shared->heap_toc;
+	int use_spinlocks = spinlocks_initialized;
+	void *ret = 0;
+	unsigned long flags = 0;
+
+	if (!skip_init_check && !smem_initialized_check())
+		return ret;
+
+	if (id >= SMEM_NUM_ITEMS)
+		return ret;
+
+	if (use_spinlocks)
+		remote_spin_lock_irqsave(&remote_spinlock, flags);
+	/* toc is in device memory and cannot be speculatively accessed */
+	if (toc[id].allocated) {
+		phys_addr_t phys_base;
+
+		*size = toc[id].size;
+		barrier();
+
+		phys_base = toc[id].reserved & BASE_ADDR_MASK;
+		if (!phys_base)
+			phys_base = (phys_addr_t)msm_shared_ram_phys;
+		ret = smem_phys_to_virt(phys_base, toc[id].offset);
+	} else {
+		*size = 0;
+	}
+	if (use_spinlocks)
+		remote_spin_unlock_irqrestore(&remote_spinlock, flags);
+
+	return ret;
+}
+
+static void *__smem_find(unsigned id, unsigned size_in, bool skip_init_check)
 {
 	unsigned size;
 	void *ptr;
 
-	ptr = smem_get_entry(id, &size);
+	ptr = __smem_get_entry(id, &size, skip_init_check);
 	if (!ptr)
 		return 0;
 
@@ -205,6 +246,11 @@
 
 	return ptr;
 }
+
+void *smem_find(unsigned id, unsigned size_in)
+{
+	return __smem_find(id, size_in, false);
+}
 EXPORT_SYMBOL(smem_find);
 
 /* smem_alloc2 returns the pointer to smem item.  If it is not allocated,
@@ -218,10 +264,8 @@
 	void *ret = NULL;
 	int rc;
 
-	if (!shared->heap_info.initialized) {
-		pr_err("%s: smem heap info not initialized\n", __func__);
+	if (!smem_initialized_check())
 		return NULL;
-	}
 
 	if (id >= SMEM_NUM_ITEMS)
 		return NULL;
@@ -268,35 +312,7 @@
 
 void *smem_get_entry(unsigned id, unsigned *size)
 {
-	struct smem_shared *shared = (void *) MSM_SHARED_RAM_BASE;
-	struct smem_heap_entry *toc = shared->heap_toc;
-	int use_spinlocks = spinlocks_initialized;
-	void *ret = 0;
-	unsigned long flags = 0;
-
-	if (id >= SMEM_NUM_ITEMS)
-		return ret;
-
-	if (use_spinlocks)
-		remote_spin_lock_irqsave(&remote_spinlock, flags);
-	/* toc is in device memory and cannot be speculatively accessed */
-	if (toc[id].allocated) {
-		phys_addr_t phys_base;
-
-		*size = toc[id].size;
-		barrier();
-
-		phys_base = toc[id].reserved & BASE_ADDR_MASK;
-		if (!phys_base)
-			phys_base = (phys_addr_t)msm_shared_ram_phys;
-		ret = smem_phys_to_virt(phys_base, toc[id].offset);
-	} else {
-		*size = 0;
-	}
-	if (use_spinlocks)
-		remote_spin_unlock_irqrestore(&remote_spinlock, flags);
-
-	return ret;
+	return __smem_get_entry(id, size, false);
 }
 EXPORT_SYMBOL(smem_get_entry);
 
@@ -341,6 +357,62 @@
 	return rc;
 }
 
+/**
+ * smem_initialized_check - Reentrant check that smem has been initialized
+ *
+ * @returns: true if initialized, false if not.
+ */
+bool smem_initialized_check(void)
+{
+	static int checked;
+	static int is_inited;
+	unsigned long flags;
+	struct smem_shared *smem;
+	int *version_array;
+
+	if (likely(checked)) {
+		if (unlikely(!is_inited))
+			pr_err("%s: smem not initialized\n", __func__);
+		return is_inited;
+	}
+
+	spin_lock_irqsave(&smem_init_check_lock, flags);
+	if (checked) {
+		spin_unlock_irqrestore(&smem_init_check_lock, flags);
+		if (unlikely(!is_inited))
+			pr_err("%s: smem not initialized\n", __func__);
+		return is_inited;
+	}
+
+	smem = (void *)MSM_SHARED_RAM_BASE;
+
+	if (smem->heap_info.initialized != 1)
+		goto failed;
+	if (smem->heap_info.reserved != 0)
+		goto failed;
+
+	version_array = __smem_find(SMEM_VERSION_INFO, SMEM_VERSION_INFO_SIZE,
+									true);
+	if (version_array == NULL)
+		goto failed;
+	if (version_array[MODEM_SBL_VERSION_INDEX] != SMEM_VERSION << 16)
+		goto failed;
+
+	is_inited = 1;
+	checked = 1;
+	spin_unlock_irqrestore(&smem_init_check_lock, flags);
+	return is_inited;
+
+failed:
+	is_inited = 0;
+	checked = 1;
+	spin_unlock_irqrestore(&smem_init_check_lock, flags);
+	pr_err("%s: bootloader failure detected, shared memory not inited\n",
+								__func__);
+	return is_inited;
+}
+EXPORT_SYMBOL(smem_initialized_check);
+
 static int restart_notifier_cb(struct notifier_block *this,
 				unsigned long code,
 				void *data)
diff --git a/arch/arm/mach-msm/smem_private.h b/arch/arm/mach-msm/smem_private.h
index b631e7c..c4f9a77 100644
--- a/arch/arm/mach-msm/smem_private.h
+++ b/arch/arm/mach-msm/smem_private.h
@@ -71,4 +71,6 @@
  * spinlock init code appears non-reentrant
  */
 int init_smem_remote_spinlock(void);
+
+bool smem_initialized_check(void);
 #endif /* _ARCH_ARM_MACH_MSM_SMEM_PRIVATE_H_ */
diff --git a/arch/arm/mach-msm/socinfo.c b/arch/arm/mach-msm/socinfo.c
index 928f5cb..575cb49 100644
--- a/arch/arm/mach-msm/socinfo.c
+++ b/arch/arm/mach-msm/socinfo.c
@@ -327,6 +327,9 @@
 	[158] = MSM_CPU_8226,
 	[159] = MSM_CPU_8226,
 	[198] = MSM_CPU_8226,
+	[199] = MSM_CPU_8226,
+	[200] = MSM_CPU_8226,
+	[205] = MSM_CPU_8226,
 
 	/* 8092 IDs */
 	[146] = MSM_CPU_8092,
diff --git a/arch/arm/mach-msm/spm-regulator.c b/arch/arm/mach-msm/spm-regulator.c
index 00817c0..244a779 100644
--- a/arch/arm/mach-msm/spm-regulator.c
+++ b/arch/arm/mach-msm/spm-regulator.c
@@ -42,17 +42,40 @@
 static const struct voltage_range fts2_range0 = {0, 350000, 1275000,  5000};
 static const struct voltage_range fts2_range1 = {0, 700000, 2040000, 10000};
 
-/* Specifies the PMIC internal slew rate in uV/us. */
-#define QPNP_FTS2_SLEW_RATE		6000
-
 #define QPNP_FTS2_REG_TYPE		0x04
 #define QPNP_FTS2_REG_SUBTYPE		0x05
 #define QPNP_FTS2_REG_VOLTAGE_RANGE	0x40
 #define QPNP_FTS2_REG_VOLTAGE_SETPOINT	0x41
+#define QPNP_FTS2_REG_MODE		0x45
+#define QPNP_FTS2_REG_STEP_CTRL		0x61
 
 #define QPNP_FTS2_TYPE			0x1C
 #define QPNP_FTS2_SUBTYPE		0x08
 
+#define QPNP_FTS2_MODE_PWM		0x80
+#define QPNP_FTS2_MODE_AUTO		0x40
+
+#define QPNP_FTS2_STEP_CTRL_STEP_MASK	0x18
+#define QPNP_FTS2_STEP_CTRL_STEP_SHIFT	3
+#define QPNP_FTS2_STEP_CTRL_DELAY_MASK	0x07
+#define QPNP_FTS2_STEP_CTRL_DELAY_SHIFT	0
+
+/* Clock rate in kHz of the FTS2 regulator reference clock. */
+#define QPNP_FTS2_CLOCK_RATE		19200
+
+/* Time to delay in us to ensure that a mode change has completed. */
+#define QPNP_FTS2_MODE_CHANGE_DELAY	50
+
+/* Minimum time in us that it takes to complete a single SPMI write. */
+#define QPNP_SPMI_WRITE_MIN_DELAY	8
+
+/*
+ * The ratio QPNP_FTS2_STEP_MARGIN_NUM/QPNP_FTS2_STEP_MARGIN_DEN is use to
+ * adjust the step rate in order to account for oscillator variance.
+ */
+#define QPNP_FTS2_STEP_MARGIN_NUM	4
+#define QPNP_FTS2_STEP_MARGIN_DEN	5
+
 struct spm_vreg {
 	struct regulator_desc		rdesc;
 	struct regulator_dev		*rdev;
@@ -64,8 +87,23 @@
 	unsigned			last_set_vlevel;
 	bool				online;
 	u16				spmi_base_addr;
+	u8				init_mode;
+	int				step_rate;
 };
 
+static int qpnp_fts2_set_mode(struct spm_vreg *vreg, u8 mode)
+{
+	int rc;
+
+	rc = spmi_ext_register_writel(vreg->spmi_dev->ctrl, vreg->spmi_dev->sid,
+		vreg->spmi_base_addr + QPNP_FTS2_REG_MODE, &mode, 1);
+	if (rc)
+		dev_err(&vreg->spmi_dev->dev, "%s: could not write to mode register, rc=%d\n",
+			__func__, rc);
+
+	return rc;
+}
+
 static int _spm_regulator_set_voltage(struct regulator_dev *rdev)
 {
 	struct spm_vreg *vreg = rdev_get_drvdata(rdev);
@@ -74,6 +112,14 @@
 	if (vreg->vlevel == vreg->last_set_vlevel)
 		return 0;
 
+	if (!(vreg->init_mode & QPNP_FTS2_MODE_PWM)
+	    && vreg->uV > vreg->last_set_uV) {
+		/* Switch to PWM mode so that voltage ramping is fast. */
+		rc = qpnp_fts2_set_mode(vreg, QPNP_FTS2_MODE_PWM);
+		if (rc)
+			return rc;
+	}
+
 	rc = msm_spm_apcs_set_vdd(vreg->vlevel);
 	if (rc) {
 		pr_err("%s: msm_spm_set_vdd failed %d\n", vreg->rdesc.name, rc);
@@ -81,10 +127,21 @@
 	}
 
 	if (vreg->uV > vreg->last_set_uV) {
-		/* Wait for voltage to stabalize. */
+		/* Wait for voltage stepping to complete. */
 		udelay(DIV_ROUND_UP(vreg->uV - vreg->last_set_uV,
-					QPNP_FTS2_SLEW_RATE));
+					vreg->step_rate));
 	}
+
+	if (!(vreg->init_mode & QPNP_FTS2_MODE_PWM)
+	    && vreg->uV > vreg->last_set_uV) {
+		/* Wait for mode transition to complete. */
+		udelay(QPNP_FTS2_MODE_CHANGE_DELAY - QPNP_SPMI_WRITE_MIN_DELAY);
+		/* Switch to AUTO mode so that power consumption is lowered. */
+		rc = qpnp_fts2_set_mode(vreg, QPNP_FTS2_MODE_AUTO);
+		if (rc)
+			return rc;
+	}
+
 	vreg->last_set_uV = vreg->uV;
 	vreg->last_set_vlevel = vreg->vlevel;
 
@@ -254,6 +311,51 @@
 	return rc;
 }
 
+static int qpnp_fts2_init_mode(struct spm_vreg *vreg)
+{
+	int rc;
+
+	rc = spmi_ext_register_readl(vreg->spmi_dev->ctrl, vreg->spmi_dev->sid,
+		vreg->spmi_base_addr + QPNP_FTS2_REG_MODE, &vreg->init_mode, 1);
+	if (rc)
+		dev_err(&vreg->spmi_dev->dev, "%s: could not read mode register, rc=%d\n",
+			__func__, rc);
+
+	return rc;
+}
+
+static int qpnp_fts2_init_step_rate(struct spm_vreg *vreg)
+{
+	int rc;
+	u8 reg = 0;
+	int step, delay;
+
+	rc = spmi_ext_register_readl(vreg->spmi_dev->ctrl, vreg->spmi_dev->sid,
+		vreg->spmi_base_addr + QPNP_FTS2_REG_STEP_CTRL, &reg, 1);
+	if (rc) {
+		dev_err(&vreg->spmi_dev->dev, "%s: could not read stepping control register, rc=%d\n",
+			__func__, rc);
+		return rc;
+	}
+
+	step = (reg & QPNP_FTS2_STEP_CTRL_STEP_MASK)
+		>> QPNP_FTS2_STEP_CTRL_STEP_SHIFT;
+	delay = (reg & QPNP_FTS2_STEP_CTRL_DELAY_MASK)
+		>> QPNP_FTS2_STEP_CTRL_DELAY_SHIFT;
+
+	/* step_rate has units of uV/us. */
+	vreg->step_rate = QPNP_FTS2_CLOCK_RATE * vreg->range->step_uV
+				* (1 << step);
+	vreg->step_rate /= 1000 * (8 << delay);
+	vreg->step_rate = vreg->step_rate * QPNP_FTS2_STEP_MARGIN_NUM
+				/ QPNP_FTS2_STEP_MARGIN_DEN;
+
+	/* Ensure that the stepping rate is greater than 0. */
+	vreg->step_rate = max(vreg->step_rate, 1);
+
+	return rc;
+}
+
 static int __devinit spm_regulator_probe(struct spmi_device *spmi)
 {
 	struct device_node *node = spmi->dev.of_node;
@@ -299,6 +401,14 @@
 	if (rc)
 		return rc;
 
+	rc = qpnp_fts2_init_mode(vreg);
+	if (rc)
+		return rc;
+
+	rc = qpnp_fts2_init_step_rate(vreg);
+	if (rc)
+		return rc;
+
 	init_data = of_get_regulator_init_data(&spmi->dev, node);
 	if (!init_data) {
 		dev_err(&spmi->dev, "%s: unable to allocate memory\n",
@@ -334,8 +444,12 @@
 
 	dev_set_drvdata(&spmi->dev, vreg);
 
-	pr_info("name=%s, range=%d\n", vreg->rdesc.name,
-		(vreg->range == &fts2_range0) ? 0 : 1);
+	pr_info("name=%s, range=%s, voltage=%d uV, mode=%s, step rate=%d uV/us\n",
+		vreg->rdesc.name, vreg->range == &fts2_range0 ? "LV" : "MV",
+		vreg->uV,
+		vreg->init_mode & QPNP_FTS2_MODE_PWM ? "PWM" :
+		    (vreg->init_mode & QPNP_FTS2_MODE_AUTO ? "AUTO" : "PFM"),
+		vreg->step_rate);
 
 	return rc;
 }
diff --git a/arch/arm/mach-msm/subsystem_restart.c b/arch/arm/mach-msm/subsystem_restart.c
index b956649..8e507ff 100644
--- a/arch/arm/mach-msm/subsystem_restart.c
+++ b/arch/arm/mach-msm/subsystem_restart.c
@@ -427,8 +427,10 @@
 
 	ret = wait_for_completion_timeout(&subsys->err_ready,
 					  msecs_to_jiffies(10000));
-	if (!ret)
+	if (!ret) {
+		pr_err("[%s]: Error ready timed out\n", subsys->desc->name);
 		return -ETIMEDOUT;
+	}
 
 	return 0;
 }
diff --git a/arch/arm/mach-msm/wallclk.c b/arch/arm/mach-msm/wallclk.c
new file mode 100644
index 0000000..9624795
--- /dev/null
+++ b/arch/arm/mach-msm/wallclk.c
@@ -0,0 +1,475 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/spinlock.h>
+#include <linux/semaphore.h>
+#include <linux/kthread.h>
+#include <linux/sched.h>
+#include <linux/hrtimer.h>
+#include <linux/timer.h>
+#include <linux/io.h>
+#include <linux/ctype.h>
+#include <linux/uaccess.h>
+#include <linux/errno.h>
+
+#include <mach/msm_iomap.h>
+
+#include "wallclk.h"
+
+#define WALLCLK_MODULE_NAME	"wallclk"
+#define WALLCLK_MODULE_NAME_LEN	10
+
+#define FLAG_WALLCLK_INITED		0x1
+#define FLAG_WALLCLK_SFN_REF_SET	0x2
+#define FLAG_WALLCLK_ENABLED		0x4
+
+#define WALLCLK_TIMER_INTERVAL_NS	100000
+
+#define WALLCLK_SHARED_MEM_SIZE		1024
+#define ALIGN_64(addr)			(((addr) + 7) & ~0x7)
+
+#define GPS_EPOCH_DIFF			315964800
+
+struct wallclk_cnt {
+	u32	pulse;
+	u32	clk;
+};
+
+struct wallclk_reg {
+	u32	ctrl;
+	u32	pulse_cnt;
+	u32	snapshot_clock_cnt;
+	u32	clock_cnt;
+	u32	__unused__[5];
+	u32	base_time0;
+	u32	base_time1;
+};
+
+struct wallclk_sm {
+	struct wallclk_reg	reg;
+	u32			sfn_ref;
+};
+
+struct wallclk_cfg {
+	u32	ppns;
+	u32	clk_rate;
+	u32	clk_rate_v;	/* clk_rate = clk_rate_v x clk_rate_p */
+	u32	clk_rate_p;	/* power of 10 */
+	u32	ns_per_clk_rate_v;
+};
+
+struct wallclk {
+	struct wallclk_sm	*shm;
+
+	struct wallclk_cfg	cfg;
+
+	struct timespec		tv;
+
+	struct hrtimer		timer;
+	ktime_t			interval;
+
+	spinlock_t		lock;
+	u32			flags;
+
+	char			name[WALLCLK_MODULE_NAME_LEN];
+};
+
+static struct wallclk wall_clk;
+
+static inline int is_valid_register(u32 offset)
+{
+	int rc = 0;
+
+	switch (offset) {
+	case CTRL_REG_OFFSET:
+	case PULSE_CNT_REG_OFFSET:
+	case CLK_CNT_SNAPSHOT_REG_OFFSET:
+	case CLK_CNT_REG_OFFSET:
+	case CLK_BASE_TIME0_OFFSET:
+	case CLK_BASE_TIME1_OFFSET:
+		rc = 1;
+		break;
+	default:
+		break;
+	}
+	return rc;
+}
+
+static inline void wallclk_ctrl_reg_set(struct wallclk *wclk, u32 v)
+{
+	struct wallclk_reg *reg = &wclk->shm->reg;
+
+	if (v & CTRL_ENABLE_MASK) {
+		if (!(wclk->flags & FLAG_WALLCLK_ENABLED)) {
+			getnstimeofday(&wclk->tv);
+			__raw_writel(0, &reg->snapshot_clock_cnt);
+			__raw_writel(0, &reg->clock_cnt);
+			__raw_writel(0, &reg->pulse_cnt);
+			hrtimer_start(&wclk->timer,
+				      wclk->interval,
+				      HRTIMER_MODE_REL);
+			wclk->flags |= FLAG_WALLCLK_ENABLED;
+		}
+	} else {
+		if (wclk->flags & FLAG_WALLCLK_ENABLED) {
+			hrtimer_cancel(&wclk->timer);
+			wclk->flags &= ~FLAG_WALLCLK_ENABLED;
+		}
+	}
+
+	__raw_writel(v, &reg->ctrl);
+}
+
+static inline void wallclk_cfg_init(struct wallclk_cfg *cfg,
+				    u32 ppns,
+				    u32 clk_rate)
+{
+	cfg->ppns = ppns;
+	cfg->clk_rate = clk_rate;
+	cfg->clk_rate_v = clk_rate;
+	cfg->clk_rate_p = 1;
+	cfg->ns_per_clk_rate_v = 1000000000;
+
+	while (!(cfg->clk_rate_v % 10)) {
+		cfg->clk_rate_v /= 10;
+		cfg->clk_rate_p *= 10;
+		cfg->ns_per_clk_rate_v /= 10;
+	}
+}
+
+static inline struct timespec timestamp_convert(const struct timespec *tv)
+{
+	struct timespec rc;
+
+	rc.tv_sec = tv->tv_sec - GPS_EPOCH_DIFF;
+	rc.tv_nsec = tv->tv_nsec;
+
+	return rc;
+}
+
+static inline void timespec_delta_to_wclk_cnt(const struct timespec *tv,
+					      const struct wallclk_cfg *cfg,
+					      struct wallclk_cnt *wclk_cnt)
+{
+	long ns;
+
+	wclk_cnt->pulse = tv->tv_sec / cfg->ppns;
+	wclk_cnt->clk = (tv->tv_sec % cfg->ppns) * cfg->clk_rate;
+
+	ns = tv->tv_nsec;
+	while (ns >= cfg->ns_per_clk_rate_v) {
+		ns -= cfg->ns_per_clk_rate_v;
+		wclk_cnt->clk += cfg->clk_rate_v;
+	}
+
+	wclk_cnt->clk += (ns * cfg->clk_rate_v)/cfg->ns_per_clk_rate_v;
+}
+
+static inline u32 wallclk_cnt_to_sfn(const struct wallclk_cnt *cnt,
+				     const struct wallclk_cfg *cfg)
+{
+	u32 sfn;
+	u32 delta, p;
+
+	sfn = SFN_PER_SECOND * cnt->pulse * cfg->ppns;
+	if (cfg->clk_rate_p > 100) {
+		p = cfg->clk_rate_p/100;
+		delta = cnt->clk/(cfg->clk_rate_v * p);
+	} else {
+		p = 100/cfg->clk_rate_p;
+		delta = (cnt->clk * p)/cfg->clk_rate_v;
+	}
+	sfn += delta;
+
+	return sfn;
+}
+
+static void update_wallclk(struct wallclk *wclk)
+{
+	struct timespec tv;
+	struct timespec delta_tv;
+	struct wallclk_cnt cnt;
+	struct wallclk_reg *reg = &wclk->shm->reg;
+
+	spin_lock(&wclk->lock);
+	getnstimeofday(&tv);
+	delta_tv = timespec_sub(tv, wclk->tv);
+	timespec_delta_to_wclk_cnt(&delta_tv, &wclk->cfg, &cnt);
+	__raw_writel(cnt.pulse, &reg->pulse_cnt);
+	__raw_writel(cnt.clk, &reg->clock_cnt);
+	__raw_writel(cnt.clk, &reg->snapshot_clock_cnt);
+
+	spin_unlock(&wclk->lock);
+}
+
+static int set_sfn(struct wallclk *wclk, u16 sfn)
+{
+	int rc = 0;
+	struct wallclk_reg *reg = &wclk->shm->reg;
+	u32 v;
+	struct timespec ts;
+
+	if (sfn > MAX_SFN) {
+		rc = -EINVAL;
+		goto out;
+	}
+
+	if (!(wclk->flags & FLAG_WALLCLK_INITED)) {
+		rc = -EIO;
+		goto out;
+	}
+
+	spin_lock_bh(&wclk->lock);
+
+	v = __raw_readl(&reg->ctrl);
+	wallclk_ctrl_reg_set(wclk, v & ~CTRL_ENABLE_MASK);
+
+	getnstimeofday(&wclk->tv);
+	ts = timestamp_convert(&wclk->tv);
+	__raw_writel(ts.tv_sec, &reg->base_time0);
+	__raw_writel(ts.tv_nsec, &reg->base_time1);
+
+	wclk->shm->sfn_ref = sfn;
+	wclk->flags |= FLAG_WALLCLK_SFN_REF_SET;
+
+	__raw_writel(0, &reg->pulse_cnt);
+	__raw_writel(0, &reg->clock_cnt);
+	__raw_writel(0, &reg->snapshot_clock_cnt);
+	hrtimer_start(&wclk->timer, wclk->interval, HRTIMER_MODE_REL);
+	wclk->flags |= FLAG_WALLCLK_ENABLED;
+	__raw_writel(v | CTRL_ENABLE_MASK, &reg->ctrl);
+
+	spin_unlock_bh(&wclk->lock);
+
+out:
+	return rc;
+}
+
+static int get_sfn(struct wallclk *wclk)
+{
+	struct wallclk_cnt cnt;
+	int rc = 0;
+	u32 sfn;
+
+	if (!(wclk->flags & FLAG_WALLCLK_INITED)) {
+		rc = -EIO;
+		goto out;
+	}
+
+	spin_lock_bh(&wclk->lock);
+
+	if (!(wclk->flags & FLAG_WALLCLK_ENABLED) ||
+	    !(wclk->flags & FLAG_WALLCLK_SFN_REF_SET)) {
+		rc = -EIO;
+		goto unlock;
+	}
+
+	cnt.pulse = __raw_readl(&(wclk->shm->reg.pulse_cnt));
+	cnt.clk = __raw_readl(&(wclk->shm->reg.clock_cnt));
+	sfn = wallclk_cnt_to_sfn(&cnt, &wclk->cfg);
+
+	sfn += wclk->shm->sfn_ref;
+	rc = sfn & MAX_SFN;
+
+unlock:
+	spin_unlock_bh(&wclk->lock);
+out:
+	return rc;
+}
+
+enum hrtimer_restart wallclk_timer_cb(struct hrtimer *timer)
+{
+	update_wallclk(&wall_clk);
+	hrtimer_forward_now(timer, wall_clk.interval);
+	return HRTIMER_RESTART;
+}
+
+int wallclk_set_sfn(u16 sfn)
+{
+	return set_sfn(&wall_clk, sfn);
+}
+EXPORT_SYMBOL_GPL(wallclk_set_sfn);
+
+int wallclk_get_sfn(void)
+{
+	return get_sfn(&wall_clk);
+}
+EXPORT_SYMBOL_GPL(wallclk_get_sfn);
+
+int wallclk_set_sfn_ref(u16 sfn)
+{
+	int rc = 0;
+
+	if (sfn > MAX_SFN) {
+		rc = -EINVAL;
+		goto out;
+	}
+
+	if (!(wall_clk.flags & FLAG_WALLCLK_INITED)) {
+		rc = -EIO;
+		goto out;
+	}
+
+	spin_lock_bh(&wall_clk.lock);
+
+	wall_clk.shm->sfn_ref = sfn;
+	wall_clk.flags |= FLAG_WALLCLK_SFN_REF_SET;
+
+	spin_unlock_bh(&wall_clk.lock);
+
+out:
+	return rc;
+}
+EXPORT_SYMBOL_GPL(wallclk_set_sfn_ref);
+
+int wallclk_get_sfn_ref(void)
+{
+	int rc = 0;
+
+	if (!(wall_clk.flags & FLAG_WALLCLK_INITED)) {
+		rc = -EIO;
+		goto out;
+	}
+
+	spin_lock_bh(&wall_clk.lock);
+
+	if (!(wall_clk.flags & FLAG_WALLCLK_SFN_REF_SET)) {
+		rc = -EAGAIN;
+		goto unlock;
+	}
+	rc = wall_clk.shm->sfn_ref;
+
+unlock:
+	spin_unlock_bh(&wall_clk.lock);
+out:
+	return rc;
+}
+EXPORT_SYMBOL_GPL(wallclk_get_sfn_ref);
+
+int wallclk_reg_read(u32 offset, u32 *p)
+{
+	int rc = 0;
+
+	if (!(wall_clk.flags & FLAG_WALLCLK_INITED)) {
+		rc = -EIO;
+		goto out;
+	}
+
+	if (!is_valid_register(offset)) {
+		rc = -EINVAL;
+		goto out;
+	}
+
+	spin_lock_bh(&wall_clk.lock);
+	*p = __raw_readl((char *)&wall_clk.shm->reg + offset);
+	spin_unlock_bh(&wall_clk.lock);
+out:
+	return rc;
+}
+EXPORT_SYMBOL_GPL(wallclk_reg_read);
+
+int wallclk_reg_write(u32 offset, u32 val)
+{
+	int rc = 0;
+	char *p;
+
+	if (!(wall_clk.flags & FLAG_WALLCLK_INITED)) {
+		rc = -EIO;
+		goto out;
+	}
+
+	p = (char *)&wall_clk.shm->reg;
+
+	spin_lock_bh(&wall_clk.lock);
+	switch (offset) {
+	case CTRL_REG_OFFSET:
+		wallclk_ctrl_reg_set(&wall_clk, val);
+		break;
+	case PULSE_CNT_REG_OFFSET:
+	case CLK_BASE_TIME0_OFFSET:
+	case CLK_BASE_TIME1_OFFSET:
+		__raw_writel(val, p + offset);
+		break;
+	case CLK_CNT_REG_OFFSET:
+		__raw_writel(val, p + CLK_CNT_REG_OFFSET);
+		__raw_writel(val, p + CLK_CNT_SNAPSHOT_REG_OFFSET);
+		break;
+	case CLK_CNT_SNAPSHOT_REG_OFFSET:
+		rc = -EIO;
+		break;
+	default:
+		rc = -EINVAL;
+		break;
+	}
+
+	spin_unlock_bh(&wall_clk.lock);
+out:
+	return rc;
+}
+EXPORT_SYMBOL_GPL(wallclk_reg_write);
+
+static int __init wallclk_init(void)
+{
+	int rc = 0;
+	u32 addr;
+
+	memset(&wall_clk, 0, sizeof(wall_clk));
+
+	addr = (u32)MSM_SHARED_RAM_BASE + MSM_SHARED_RAM_SIZE -
+		WALLCLK_SHARED_MEM_SIZE;
+	wall_clk.shm = (struct wallclk_sm *)ALIGN_64(addr);
+
+	__raw_writel(0, &(wall_clk.shm->reg.ctrl));
+	__raw_writel(0, &(wall_clk.shm->reg.pulse_cnt));
+	__raw_writel(0, &(wall_clk.shm->reg.snapshot_clock_cnt));
+	__raw_writel(0, &(wall_clk.shm->reg.clock_cnt));
+	__raw_writel(0, &(wall_clk.shm->reg.clock_cnt));
+	__raw_writel(0, &(wall_clk.shm->reg.base_time0));
+	__raw_writel(0, &(wall_clk.shm->reg.base_time1));
+
+	wall_clk.shm->sfn_ref = 0;
+
+	wallclk_cfg_init(&wall_clk.cfg, PPNS_PULSE, CLK_RATE);
+
+	strlcpy(wall_clk.name, WALLCLK_MODULE_NAME, WALLCLK_MODULE_NAME_LEN);
+
+	hrtimer_init(&wall_clk.timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+	wall_clk.timer.function = wallclk_timer_cb;
+	wall_clk.interval = ns_to_ktime(WALLCLK_TIMER_INTERVAL_NS);
+	spin_lock_init(&wall_clk.lock);
+
+	wall_clk.flags |= FLAG_WALLCLK_INITED;
+
+	printk(KERN_INFO "%s: clk_rate=%u ppns=%u clk_reg_addr=0x%x\n",
+	       wall_clk.name, wall_clk.cfg.clk_rate, wall_clk.cfg.ppns,
+	       (int)(&wall_clk.shm->reg));
+	return rc;
+}
+
+static void __exit wallclk_exit(void)
+{
+	if (wall_clk.flags & FLAG_WALLCLK_INITED) {
+		spin_lock_bh(&wall_clk.lock);
+		wallclk_ctrl_reg_set(&wall_clk, 0);
+		wall_clk.flags = 0;
+		spin_unlock_bh(&wall_clk.lock);
+	}
+}
+
+module_init(wallclk_init);
+module_exit(wallclk_exit);
+
+MODULE_DESCRIPTION("Wall clock");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/wallclk.h b/arch/arm/mach-msm/wallclk.h
new file mode 100644
index 0000000..1794395
--- /dev/null
+++ b/arch/arm/mach-msm/wallclk.h
@@ -0,0 +1,46 @@
+/* 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 _WALLCLK_H
+#define _WALLCLK_H
+
+/* wallclock register offset */
+#define CTRL_REG_OFFSET			0x0
+#define PULSE_CNT_REG_OFFSET		0x4
+#define CLK_CNT_SNAPSHOT_REG_OFFSET	0x8
+#define CLK_CNT_REG_OFFSET		0xC
+#define CLK_BASE_TIME0_OFFSET		0x24
+#define CLK_BASE_TIME1_OFFSET		0x28
+
+/* ctrl register bitmap */
+#define CTRL_TIME_SRC_POS	0
+#define CTRL_TIME_SRC_MASK	0x0000000F
+#define CTRL_SW_BITS_POS	4
+#define CTRL_SW_BITS_MASK	0x7FFFFFF0
+#define CTRL_ENA_DIS_POS	31
+#define CTRL_ENABLE_MASK	0x80000000
+
+/* clock rate from time source */
+#define CLK_RATE		122880000	/* 122.88 Mhz */
+#define PPNS_PULSE		2		/* PP2S */
+
+#define MAX_SFN			1023
+#define SFN_PER_SECOND		100
+
+extern int wallclk_set_sfn(u16 sfn);
+extern int wallclk_get_sfn(void);
+extern int wallclk_set_sfn_ref(u16 sfn);
+extern int wallclk_get_sfn_ref(void);
+extern int wallclk_reg_read(u32 offset, u32 *p);
+extern int wallclk_reg_write(u32 offset, u32 value);
+
+#endif /* _WALLCLK_H */
diff --git a/arch/arm/mach-msm/wallclk_sysfs.c b/arch/arm/mach-msm/wallclk_sysfs.c
new file mode 100644
index 0000000..9274137
--- /dev/null
+++ b/arch/arm/mach-msm/wallclk_sysfs.c
@@ -0,0 +1,308 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/spinlock.h>
+#include <linux/semaphore.h>
+#include <linux/kthread.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/ctype.h>
+#include <linux/uaccess.h>
+#include <linux/errno.h>
+
+#include "wallclk.h"
+
+#define WALLCLK_SYSFS_MODULE_NAME	"wallclk_sysfs"
+
+static struct kobject *wallclk_kobj;
+
+static ssize_t sfn_show(struct kobject *kobj,
+			struct kobj_attribute *attr,
+			char *buf)
+{
+	int rc;
+
+	rc = wallclk_get_sfn();
+	if (rc < 0)
+		return rc;
+	return snprintf(buf, 10, "%d\n", rc);
+}
+
+static ssize_t sfn_store(struct kobject *kobj,
+			 struct kobj_attribute *attr,
+			 const char *buf,
+			 size_t count)
+{
+	u16 sfn;
+	int rc;
+
+	if (kstrtou16(buf, 0, &sfn)) {
+		printk(KERN_ERR "%s: sfn input is not a valid u16 value\n",
+		       WALLCLK_SYSFS_MODULE_NAME);
+		rc = -EINVAL;
+		goto out;
+	}
+
+	rc = wallclk_set_sfn(sfn);
+
+	if (rc) {
+		printk(KERN_ERR "%s: fail to set sfn\n",
+		       WALLCLK_SYSFS_MODULE_NAME);
+		goto out;
+	}
+	rc = count;
+
+out:
+	return rc;
+}
+
+static struct kobj_attribute sfn_attribute =
+	__ATTR(sfn, 0666, sfn_show, sfn_store);
+
+static ssize_t sfn_ref_show(struct kobject *kobj,
+			    struct kobj_attribute *attr,
+			    char *buf)
+{
+	int rc;
+
+	rc = wallclk_get_sfn_ref();
+	if (rc < 0)
+		return rc;
+	return snprintf(buf, 10, "%d\n", rc);
+}
+
+static ssize_t sfn_ref_store(struct kobject *kobj,
+			     struct kobj_attribute *attr,
+			     const char *buf,
+			     size_t count)
+{
+	u16 sfn_ref;
+	int rc;
+
+	if (kstrtou16(buf, 0, &sfn_ref)) {
+		printk(KERN_ERR "%s: sfn_ref input is not a valid u16 value\n",
+		       WALLCLK_SYSFS_MODULE_NAME);
+		rc = -EINVAL;
+		goto out;
+	}
+
+	rc = wallclk_set_sfn_ref(sfn_ref);
+
+	if (rc) {
+		printk(KERN_ERR "%s: fail to set sfn_ref\n",
+		       WALLCLK_SYSFS_MODULE_NAME);
+		goto out;
+	}
+	rc = count;
+
+out:
+	return rc;
+}
+
+static struct kobj_attribute sfn_ref_attribute =
+	__ATTR(sfn_ref, 0666, sfn_ref_show, sfn_ref_store);
+
+static ssize_t reg_show(struct kobject *kobj,
+			struct kobj_attribute *attr,
+			char *buf,
+			u32 offset)
+{
+	int rc;
+	u32 val;
+
+	rc = wallclk_reg_read(offset, &val);
+	if (rc)
+		return rc;
+
+	return snprintf(buf, 20, "%08x\n", val);
+}
+
+static ssize_t reg_store(struct kobject *kobj,
+			 struct kobj_attribute *attr,
+			 const char *buf,
+			 const size_t count,
+			 u32 offset)
+{
+	u32 v;
+	int rc;
+
+	if (kstrtou32(buf, 0, &v)) {
+		printk(KERN_ERR "%s: input is not a valid u32 value\n",
+		       WALLCLK_SYSFS_MODULE_NAME);
+		rc = -EINVAL;
+		goto out;
+	}
+
+	rc = wallclk_reg_write(offset, v);
+
+	if (rc) {
+		printk(KERN_ERR "%s: fail to set register(offset=0x%x)\n",
+		       WALLCLK_SYSFS_MODULE_NAME, offset);
+		goto out;
+	}
+	rc = count;
+
+out:
+	return rc;
+}
+
+static ssize_t ctrl_reg_show(struct kobject *kobj,
+			     struct kobj_attribute *attr,
+			     char *buf)
+{
+	return reg_show(kobj, attr, buf, CTRL_REG_OFFSET);
+}
+
+static ssize_t ctrl_reg_store(struct kobject *kobj,
+			      struct kobj_attribute *attr,
+			      const char *buf,
+			      const size_t count)
+{
+	return reg_store(kobj, attr, buf, count, CTRL_REG_OFFSET);
+}
+
+static struct kobj_attribute ctrl_reg_attribute =
+	__ATTR(ctrl_reg, 0666, ctrl_reg_show, ctrl_reg_store);
+
+static ssize_t basetime0_reg_show(struct kobject *kobj,
+				  struct kobj_attribute *attr,
+				  char *buf)
+{
+	return reg_show(kobj, attr, buf, CLK_BASE_TIME0_OFFSET);
+}
+
+static ssize_t basetime0_reg_store(struct kobject *kobj,
+				   struct kobj_attribute *attr,
+				   const char *buf,
+				   size_t count)
+{
+	return reg_store(kobj, attr, buf, count, CLK_BASE_TIME0_OFFSET);
+}
+
+static struct kobj_attribute basetime0_reg_attribute =
+	__ATTR(base_time0_reg, 0666, basetime0_reg_show, basetime0_reg_store);
+
+static ssize_t basetime1_reg_show(struct kobject *kobj,
+				  struct kobj_attribute *attr,
+				  char *buf)
+{
+	return reg_show(kobj, attr, buf, CLK_BASE_TIME1_OFFSET);
+}
+
+static ssize_t basetime1_reg_store(struct kobject *kobj,
+				   struct kobj_attribute *attr,
+				   const char *buf,
+				   size_t count)
+{
+	return reg_store(kobj, attr, buf, count, CLK_BASE_TIME1_OFFSET);
+}
+
+static struct kobj_attribute basetime1_reg_attribute =
+	__ATTR(base_time1_reg, 0666, basetime1_reg_show, basetime1_reg_store);
+
+static ssize_t pulse_cnt_reg_show(struct kobject *kobj,
+				  struct kobj_attribute *attr,
+				  char *buf)
+{
+	return reg_show(kobj, attr, buf, PULSE_CNT_REG_OFFSET);
+}
+
+static ssize_t pulse_cnt_reg_store(struct kobject *kobj,
+				   struct kobj_attribute *attr,
+				   const char *buf,
+				   size_t count)
+{
+	return reg_store(kobj, attr, buf, count, PULSE_CNT_REG_OFFSET);
+}
+
+static struct kobj_attribute pulse_cnt_reg_attribute =
+	__ATTR(pulse_cnt_reg, 0666, pulse_cnt_reg_show, pulse_cnt_reg_store);
+
+static ssize_t clk_cnt_reg_show(struct kobject *kobj,
+				struct kobj_attribute *attr,
+				char *buf)
+{
+	return reg_show(kobj, attr, buf, CLK_CNT_REG_OFFSET);
+}
+
+static ssize_t clk_cnt_reg_store(struct kobject *kobj,
+				 struct kobj_attribute *attr,
+				 const char *buf,
+				 size_t count)
+{
+	return reg_store(kobj, attr, buf, count, CLK_CNT_REG_OFFSET);
+}
+
+static struct kobj_attribute clk_cnt_reg_attribute =
+	__ATTR(clock_cnt_reg, 0666, clk_cnt_reg_show, clk_cnt_reg_store);
+
+static ssize_t clk_cnt_snapshot_reg_show(struct kobject *kobj,
+					 struct kobj_attribute *attr,
+					 char *buf)
+{
+	return reg_show(kobj, attr, buf, CLK_CNT_SNAPSHOT_REG_OFFSET);
+}
+
+static struct kobj_attribute clk_cnt_snapshot_reg_attribute =
+	__ATTR(clock_cnt_snapshot_reg, 0444, clk_cnt_snapshot_reg_show, NULL);
+
+static struct attribute *wallclk_attrs[] = {
+	&sfn_attribute.attr,
+	&sfn_ref_attribute.attr,
+	&ctrl_reg_attribute.attr,
+	&pulse_cnt_reg_attribute.attr,
+	&clk_cnt_snapshot_reg_attribute.attr,
+	&clk_cnt_reg_attribute.attr,
+	&basetime0_reg_attribute.attr,
+	&basetime1_reg_attribute.attr,
+	NULL
+};
+
+static struct attribute_group wallclk_attr_group = {
+	.attrs = wallclk_attrs,
+};
+
+static int __init wallclk_sysfs_init(void)
+{
+	int rc;
+
+	wallclk_kobj = kobject_create_and_add("wallclk", kernel_kobj);
+	if (!wallclk_kobj) {
+		printk(KERN_ERR "%s: failed to create kobject\n",
+		       WALLCLK_SYSFS_MODULE_NAME);
+		rc = -ENOMEM;
+		goto out;
+	}
+
+	rc = sysfs_create_group(wallclk_kobj, &wallclk_attr_group);
+	if (rc) {
+		kobject_put(wallclk_kobj);
+		printk(KERN_ERR "%s: failed to create sysfs group\n",
+		       WALLCLK_SYSFS_MODULE_NAME);
+	}
+
+out:
+	return rc;
+}
+
+static void __exit wallclk_sysfs_exit(void)
+{
+	kobject_put(wallclk_kobj);
+}
+
+module_init(wallclk_sysfs_init);
+module_exit(wallclk_sysfs_exit);
+
+MODULE_DESCRIPTION("Wall clock SysFS");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c
index 26b92d4..34cb153 100644
--- a/arch/arm/mm/init.c
+++ b/arch/arm/mm/init.c
@@ -395,32 +395,29 @@
 	unsigned long hole_end_virt;
 
 	/*
-	 * Find the start and end of the hole, using meminfo
-	 * if it hasnt been found already.
+	 * Find the start and end of the hole, using meminfo.
 	 */
-	if (memory_hole_start == 0 && memory_hole_end == 0) {
-		for (i = 0; i < (meminfo.nr_banks - 1); i++) {
-			if ((meminfo.bank[i].start + meminfo.bank[i].size) !=
+	for (i = 0; i < (meminfo.nr_banks - 1); i++) {
+		if ((meminfo.bank[i].start + meminfo.bank[i].size) !=
 						meminfo.bank[i+1].start) {
-				if (meminfo.bank[i].start + meminfo.bank[i].size
+			if (meminfo.bank[i].start + meminfo.bank[i].size
 							<= MAX_HOLE_ADDRESS) {
 
-					hole_start = meminfo.bank[i].start +
+				hole_start = meminfo.bank[i].start +
 							meminfo.bank[i].size;
-					hole_size = meminfo.bank[i+1].start -
+				hole_size = meminfo.bank[i+1].start -
 								hole_start;
 
-					if (memory_hole_start == 0 &&
+				if (memory_hole_start == 0 &&
 							memory_hole_end == 0) {
-						memory_hole_start = hole_start;
-						memory_hole_end = hole_start +
+					memory_hole_start = hole_start;
+					memory_hole_end = hole_start +
 								hole_size;
-					} else if ((memory_hole_end -
+				} else if ((memory_hole_end -
 					memory_hole_start) <= hole_size) {
-						memory_hole_start = hole_start;
-						memory_hole_end = hole_start +
+					memory_hole_start = hole_start;
+					memory_hole_end = hole_start +
 								hole_size;
-					}
 				}
 			}
 		}
diff --git a/block/blk-core.c b/block/blk-core.c
index 2b6595c..153240e 100644
--- a/block/blk-core.c
+++ b/block/blk-core.c
@@ -1086,7 +1086,7 @@
 		 * urgent requests. We want to be able to track this
 		 * down.
 		 */
-		pr_err("%s(): requeueing an URGENT request", __func__);
+		pr_debug("%s(): requeueing an URGENT request", __func__);
 		WARN_ON(!q->dispatched_urgent);
 		q->dispatched_urgent = false;
 	}
@@ -1123,7 +1123,7 @@
 		 * urgent requests. We want to be able to track this
 		 * down.
 		 */
-		pr_err("%s(): reinserting an URGENT request", __func__);
+		pr_debug("%s(): reinserting an URGENT request", __func__);
 		WARN_ON(!q->dispatched_urgent);
 		q->dispatched_urgent = false;
 	}
diff --git a/drivers/char/diag/diag_dci.c b/drivers/char/diag/diag_dci.c
index 682d876..9b404c6 100644
--- a/drivers/char/diag/diag_dci.c
+++ b/drivers/char/diag/diag_dci.c
@@ -58,14 +58,14 @@
 		pr_debug("diag: bytes read = %d, single dci pkt len = %d\n",
 			read_bytes, dci_pkt_len);
 		/* print_hex_dump(KERN_DEBUG, "Single DCI packet :",
-		 DUMP_PREFIX_ADDRESS, 16, 1, buf, 5 + dci_pkt_len, 1);*/
+		 DUMP_PREFIX_ADDRESS, 16, 1, buf, 5 + dci_pkt_len, 1); */
 		recv_pkt_cmd_code = *(uint8_t *)(buf+4);
 		if (recv_pkt_cmd_code == LOG_CMD_CODE)
 			extract_dci_log(buf+4);
 		else if (recv_pkt_cmd_code == EVENT_CMD_CODE)
 			extract_dci_events(buf+4);
 		else
-			extract_dci_pkt_rsp(buf); /* pkt response */
+			extract_dci_pkt_rsp(smd_info, buf); /* pkt response */
 		read_bytes += 5 + dci_pkt_len;
 		buf += 5 + dci_pkt_len; /* advance to next DCI pkt */
 	}
@@ -83,7 +83,7 @@
 	return 0;
 }
 
-void extract_dci_pkt_rsp(unsigned char *buf)
+void extract_dci_pkt_rsp(struct diag_smd_info *smd_info, unsigned char *buf)
 {
 	int i = 0, index = -1, cmd_code_len = 1;
 	int curr_client_pid = 0, write_len;
@@ -95,6 +95,7 @@
 	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;
+
 	pr_debug("diag: len = %d\n", write_len);
 	/* look up DCI client with tag */
 	for (i = 0; i < dci_max_reg; i++) {
@@ -139,8 +140,7 @@
 			buf+4+cmd_code_len, write_len);
 		entry->data_len += write_len;
 		/* delete immediate response entry */
-		if (driver->smd_dci[MODEM_DATA].
-			buf_in_1[8+cmd_code_len] != 0x80)
+		if (smd_info->buf_in_1[8+cmd_code_len] != 0x80)
 			driver->req_tracking_tbl[index].pid = 0;
 	}
 }
@@ -372,26 +372,6 @@
 	} /* end of loop for all DCI clients */
 }
 
-static int diag_dci_probe(struct platform_device *pdev)
-{
-	int err = 0;
-	int index;
-
-	if (pdev->id == SMD_APPS_MODEM) {
-		index = MODEM_DATA;
-		err = smd_open("DIAG_2", &driver->smd_dci[index].ch,
-					&driver->smd_dci[index],
-					diag_smd_notify);
-		driver->smd_dci[index].ch_save =
-					driver->smd_dci[index].ch;
-		if (err)
-			pr_err("diag: In %s, cannot open DCI port, Id = %d, err: %d\n",
-				__func__, pdev->id, err);
-	}
-
-	return err;
-}
-
 int diag_send_dci_pkt(struct diag_master_table entry, unsigned char *buf,
 					 int len, int index)
 {
@@ -418,9 +398,12 @@
 	driver->apps_dci_buf[9+len] = CONTROL_CHAR; /* end */
 
 	for (i = 0; i < NUM_SMD_DCI_CHANNELS; i++) {
-		if (entry.client_id == driver->smd_dci[i].peripheral) {
-			if (driver->smd_dci[i].ch) {
-				smd_write(driver->smd_dci[i].ch,
+		struct diag_smd_info *smd_info = driver->separate_cmdrsp[i] ?
+					&driver->smd_dci_cmd[i] :
+					&driver->smd_dci[i];
+		if (entry.client_id == smd_info->peripheral) {
+			if (smd_info->ch) {
+				smd_write(smd_info->ch,
 					driver->apps_dci_buf, len + 10);
 				status = DIAG_DCI_NO_ERROR;
 			}
@@ -1000,6 +983,49 @@
 	memset(tbl_buf, 0, 512);
 }
 
+static int diag_dci_probe(struct platform_device *pdev)
+{
+	int err = 0;
+	int index;
+
+	if (pdev->id == SMD_APPS_MODEM) {
+		index = MODEM_DATA;
+		err = smd_open("DIAG_2",
+			&driver->smd_dci[index].ch,
+			&driver->smd_dci[index],
+			diag_smd_notify);
+		driver->smd_dci[index].ch_save =
+			driver->smd_dci[index].ch;
+		if (err)
+			pr_err("diag: In %s, cannot open DCI port, Id = %d, err: %d\n",
+				__func__, pdev->id, err);
+	}
+
+	return err;
+}
+
+static int diag_dci_cmd_probe(struct platform_device *pdev)
+{
+	int err = 0;
+	int index;
+
+	if (pdev->id == SMD_APPS_MODEM) {
+		index = MODEM_DATA;
+		err = smd_named_open_on_edge("DIAG_2_CMD",
+			pdev->id,
+			&driver->smd_dci_cmd[index].ch,
+			&driver->smd_dci_cmd[index],
+			diag_smd_notify);
+		driver->smd_dci_cmd[index].ch_save =
+			driver->smd_dci_cmd[index].ch;
+		if (err)
+			pr_err("diag: In %s, cannot open DCI port, Id = %d, err: %d\n",
+				__func__, pdev->id, err);
+	}
+
+	return err;
+}
+
 static int diag_dci_runtime_suspend(struct device *dev)
 {
 	dev_dbg(dev, "pm_runtime: suspending...\n");
@@ -1020,9 +1046,18 @@
 struct platform_driver msm_diag_dci_driver = {
 	.probe = diag_dci_probe,
 	.driver = {
-			.name = "DIAG_2",
-			.owner = THIS_MODULE,
-			.pm   = &diag_dci_dev_pm_ops,
+		.name = "DIAG_2",
+		.owner = THIS_MODULE,
+		.pm   = &diag_dci_dev_pm_ops,
+	},
+};
+
+struct platform_driver msm_diag_dci_cmd_driver = {
+	.probe = diag_dci_cmd_probe,
+	.driver = {
+		.name = "DIAG_2_CMD",
+		.owner = THIS_MODULE,
+		.pm   = &diag_dci_dev_pm_ops,
 	},
 };
 
@@ -1040,12 +1075,21 @@
 	mutex_init(&dci_health_mutex);
 
 	for (i = 0; i < NUM_SMD_DCI_CHANNELS; i++) {
-		success = diag_smd_constructor(&driver->smd_dci[i],
-					i, SMD_DCI_TYPE);
+		success = diag_smd_constructor(&driver->smd_dci[i], i,
+							SMD_DCI_TYPE);
 		if (!success)
 			goto err;
 	}
 
+	if (driver->supports_separate_cmdrsp) {
+		for (i = 0; i < NUM_SMD_DCI_CMD_CHANNELS; i++) {
+			success = diag_smd_constructor(&driver->smd_dci_cmd[i],
+							i, SMD_DCI_CMD_TYPE);
+			if (!success)
+				goto err;
+		}
+	}
+
 	if (driver->req_tracking_tbl == NULL) {
 		driver->req_tracking_tbl = kzalloc(dci_max_reg *
 			sizeof(struct dci_pkt_req_tracking_tbl), GFP_KERNEL);
@@ -1069,6 +1113,13 @@
 		pr_err("diag: Could not register DCI driver\n");
 		goto err;
 	}
+	if (driver->supports_separate_cmdrsp) {
+		success = platform_driver_register(&msm_diag_dci_cmd_driver);
+		if (success) {
+			pr_err("diag: Could not register DCI cmd driver\n");
+			goto err;
+		}
+	}
 	return DIAG_DCI_NO_ERROR;
 err:
 	pr_err("diag: Could not initialize diag DCI buffers");
@@ -1077,6 +1128,11 @@
 	kfree(driver->apps_dci_buf);
 	for (i = 0; i < NUM_SMD_DCI_CHANNELS; i++)
 		diag_smd_destructor(&driver->smd_dci[i]);
+
+	if (driver->supports_separate_cmdrsp)
+		for (i = 0; i < NUM_SMD_DCI_CMD_CHANNELS; i++)
+			diag_smd_destructor(&driver->smd_dci_cmd[i]);
+
 	if (driver->diag_dci_wq)
 		destroy_workqueue(driver->diag_dci_wq);
 	return DIAG_DCI_NO_REG;
@@ -1096,6 +1152,12 @@
 			kfree(driver->dci_client_tbl[i].dci_data);
 	}
 
+	if (driver->supports_separate_cmdrsp) {
+		for (i = 0; i < NUM_SMD_DCI_CMD_CHANNELS; i++)
+			diag_smd_destructor(&driver->smd_dci_cmd[i]);
+
+		platform_driver_unregister(&msm_diag_dci_cmd_driver);
+	}
 	kfree(driver->req_tracking_tbl);
 	kfree(driver->dci_client_tbl);
 	kfree(driver->apps_dci_buf);
diff --git a/drivers/char/diag/diag_dci.h b/drivers/char/diag/diag_dci.h
index 260cdf3..4dc1bfc 100644
--- a/drivers/char/diag/diag_dci.h
+++ b/drivers/char/diag/diag_dci.h
@@ -95,7 +95,7 @@
 int diag_process_dci_transaction(unsigned char *buf, int len);
 int diag_send_dci_pkt(struct diag_master_table entry, unsigned char *buf,
 							 int len, int index);
-void extract_dci_pkt_rsp(unsigned char *buf);
+void extract_dci_pkt_rsp(struct diag_smd_info *smd_info, unsigned char *buf);
 int diag_dci_find_client_index(int client_id);
 /* DCI Log streaming functions */
 void create_dci_log_mask_tbl(unsigned char *tbl_buf);
diff --git a/drivers/char/diag/diag_debugfs.c b/drivers/char/diag/diag_debugfs.c
index 76490c8..6e948b7 100644
--- a/drivers/char/diag/diag_debugfs.c
+++ b/drivers/char/diag/diag_debugfs.c
@@ -44,12 +44,18 @@
 		"modem cntl_ch: 0x%x\n"
 		"lpass cntl_ch: 0x%x\n"
 		"riva cntl_ch: 0x%x\n"
+		"modem cmd ch: 0x%x\n"
+		"dci cmd ch: 0x%x\n"
 		"CPU Tools id: %d\n"
 		"Apps only: %d\n"
 		"Apps master: %d\n"
 		"Check Polling Response: %d\n"
 		"polling_reg_flag: %d\n"
 		"uses device tree: %d\n"
+		"supports separate cmdrsp: %d\n"
+		"Modem separate cmdrsp: %d\n"
+		"LPASS separate cmdrsp: %d\n"
+		"RIVA separate cmdrsp: %d\n"
 		"Modem in_busy_1: %d\n"
 		"Modem in_busy_2: %d\n"
 		"LPASS in_busy_1: %d\n"
@@ -57,6 +63,9 @@
 		"RIVA in_busy_1: %d\n"
 		"RIVA in_busy_2: %d\n"
 		"DCI Modem in_busy_1: %d\n"
+		"Modem CMD in_busy_1: %d\n"
+		"Modem CMD in_busy_2: %d\n"
+		"DCI CMD Modem in_busy_1: %d\n"
 		"logging_mode: %d\n",
 		(unsigned int)driver->smd_data[MODEM_DATA].ch,
 		(unsigned int)driver->smd_data[LPASS_DATA].ch,
@@ -65,12 +74,18 @@
 		(unsigned int)driver->smd_cntl[MODEM_DATA].ch,
 		(unsigned int)driver->smd_cntl[LPASS_DATA].ch,
 		(unsigned int)driver->smd_cntl[WCNSS_DATA].ch,
+		(unsigned int)driver->smd_cmd[MODEM_DATA].ch,
+		(unsigned int)driver->smd_dci_cmd[MODEM_DATA].ch,
 		chk_config_get_id(),
 		chk_apps_only(),
 		chk_apps_master(),
 		chk_polling_response(),
 		driver->polling_reg_flag,
 		driver->use_device_tree,
+		driver->supports_separate_cmdrsp,
+		driver->separate_cmdrsp[MODEM_DATA],
+		driver->separate_cmdrsp[LPASS_DATA],
+		driver->separate_cmdrsp[WCNSS_DATA],
 		driver->smd_data[MODEM_DATA].in_busy_1,
 		driver->smd_data[MODEM_DATA].in_busy_2,
 		driver->smd_data[LPASS_DATA].in_busy_1,
@@ -78,6 +93,9 @@
 		driver->smd_data[WCNSS_DATA].in_busy_1,
 		driver->smd_data[WCNSS_DATA].in_busy_2,
 		driver->smd_dci[MODEM_DATA].in_busy_1,
+		driver->smd_cmd[MODEM_DATA].in_busy_1,
+		driver->smd_cmd[MODEM_DATA].in_busy_2,
+		driver->smd_dci_cmd[MODEM_DATA].in_busy_1,
 		driver->logging_mode);
 
 #ifdef CONFIG_DIAG_OVER_USB
diff --git a/drivers/char/diag/diag_masks.c b/drivers/char/diag/diag_masks.c
index 04c3300..5aed793 100644
--- a/drivers/char/diag/diag_masks.c
+++ b/drivers/char/diag/diag_masks.c
@@ -27,7 +27,6 @@
 #define MAX_SSID_PER_RANGE	100
 
 #define FEATURE_MASK_LEN_BYTES		1
-#define APPS_RESPOND_LOG_ON_DEMAND	0x04
 
 struct mask_info {
 	int equip_id;
@@ -48,13 +47,6 @@
 	msg_mask_tbl_ptr += MAX_SSID_PER_RANGE * sizeof(int);		\
 } while (0)
 
-#define WAIT_FOR_SMD(num_delays, delay_time)		\
-do {							\
-	int count;					\
-	for (count = 0; count < (num_delays); count++)	\
-		udelay((delay_time));			\
-} while (0)
-
 static void diag_print_mask_table(void)
 {
 /* Enable this to print mask table when updated */
@@ -312,7 +304,7 @@
 						smd_info->peripheral);
 	diag_send_log_mask_update(smd_info->ch, ALL_EQUIP_ID);
 	diag_send_event_mask_update(smd_info->ch, diag_event_num_bytes);
-	diag_send_feature_mask_update(smd_info->ch, smd_info->peripheral);
+	diag_send_feature_mask_update(smd_info);
 
 	if (smd_info->notify_context == SMD_EVENT_OPEN)
 		diag_send_diag_mode_update_by_smd(smd_info, MODE_REALTIME);
@@ -352,7 +344,7 @@
 							 header_size + size);
 					if (wr_size == -ENOMEM) {
 						retry_count++;
-						WAIT_FOR_SMD(5, 2000);
+						usleep_range(10000, 10100);
 					} else
 						break;
 				}
@@ -397,7 +389,7 @@
 			wr_size = smd_write(ch, buf, header_size + num_bytes);
 			if (wr_size == -ENOMEM) {
 				retry_count++;
-				WAIT_FOR_SMD(5, 2000);
+				usleep_range(10000, 10100);
 			} else
 				break;
 		}
@@ -447,7 +439,7 @@
 					 4*(driver->msg_mask->msg_mask_size));
 					if (size == -ENOMEM) {
 						retry_count++;
-						WAIT_FOR_SMD(5, 2000);
+						usleep_range(10000, 10100);
 					} else
 						break;
 				}
@@ -468,12 +460,25 @@
 	mutex_unlock(&driver->diag_cntl_mutex);
 }
 
-void diag_send_feature_mask_update(smd_channel_t *ch, int proc)
+void diag_send_feature_mask_update(struct diag_smd_info *smd_info)
 {
 	void *buf = driver->buf_feature_mask_update;
 	int header_size = sizeof(struct diag_ctrl_feature_mask);
-	int wr_size = -ENOMEM, retry_count = 0, timer;
+	int wr_size = -ENOMEM, retry_count = 0;
 	uint8_t feature_byte = 0;
+	int total_len = 0;
+
+	if (!smd_info) {
+		pr_err("diag: In %s, null smd info pointer\n",
+			__func__);
+		return;
+	}
+
+	if (!smd_info->ch) {
+		pr_err("diag: In %s, smd channel not open for peripheral: %d, type: %d\n",
+				__func__, smd_info->peripheral, smd_info->type);
+		return;
+	}
 
 	mutex_lock(&driver->diag_cntl_mutex);
 	/* send feature mask update */
@@ -482,27 +487,32 @@
 	driver->feature_mask->feature_mask_len = FEATURE_MASK_LEN_BYTES;
 	memcpy(buf, driver->feature_mask, header_size);
 	feature_byte |= F_DIAG_INT_FEATURE_MASK;
-	feature_byte |= APPS_RESPOND_LOG_ON_DEMAND;
+	feature_byte |= F_DIAG_LOG_ON_DEMAND_RSP_ON_MASTER;
+	feature_byte |= driver->supports_separate_cmdrsp ?
+				F_DIAG_REQ_RSP_CHANNEL : 0;
 	memcpy(buf+header_size, &feature_byte, FEATURE_MASK_LEN_BYTES);
+	total_len = header_size + FEATURE_MASK_LEN_BYTES;
 
-	if (ch) {
-		while (retry_count < 3) {
-			wr_size = smd_write(ch, buf, header_size +
-						FEATURE_MASK_LEN_BYTES);
-			if (wr_size == -ENOMEM) {
-				retry_count++;
-				for (timer = 0; timer < 5; timer++)
-					udelay(2000);
-			} else
-				break;
-		}
-		if (wr_size != header_size + FEATURE_MASK_LEN_BYTES)
-			pr_err("diag: proc %d fail feature update %d, tried %d",
-			   proc, wr_size, header_size + FEATURE_MASK_LEN_BYTES);
-	} else
-		pr_err("diag: ch invalid, feature update on proc %d\n", proc);
+	while (retry_count < 3) {
+		wr_size = smd_write(smd_info->ch, buf, total_len);
+		if (wr_size == -ENOMEM) {
+			retry_count++;
+			/*
+			 * The smd channel is full. Delay while
+			 * smd processes existing data and smd
+			 * has memory become available. The delay
+			 * of 10000 was determined empirically as
+			 * best value to use.
+			 */
+			usleep_range(10000, 10100);
+		} else
+			break;
+	}
+	if (wr_size != total_len)
+		pr_err("diag: In %s, peripheral %d fail feature update, size: %d, tried: %d",
+			__func__, smd_info->peripheral, wr_size, total_len);
+
 	mutex_unlock(&driver->diag_cntl_mutex);
-
 }
 
 int diag_process_apps_masks(unsigned char *buf, int len)
diff --git a/drivers/char/diag/diag_masks.h b/drivers/char/diag/diag_masks.h
index 53f72e8..c66a4b6 100644
--- a/drivers/char/diag/diag_masks.h
+++ b/drivers/char/diag/diag_masks.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -21,7 +21,7 @@
 					 int ssid_last, int proc);
 void diag_send_log_mask_update(smd_channel_t *, int);
 void diag_mask_update_fn(struct work_struct *work);
-void diag_send_feature_mask_update(smd_channel_t *ch, int proc);
+void diag_send_feature_mask_update(struct diag_smd_info *smd_info);
 int diag_process_apps_masks(unsigned char *buf, int len);
 void diag_masks_init(void);
 void diag_masks_exit(void);
diff --git a/drivers/char/diag/diagchar.h b/drivers/char/diag/diagchar.h
index 292a0be..b05bcef 100644
--- a/drivers/char/diag/diagchar.h
+++ b/drivers/char/diag/diagchar.h
@@ -82,12 +82,16 @@
 #define MODE_NONREALTIME 0
 
 #define NUM_SMD_DATA_CHANNELS 3
-#define NUM_SMD_CONTROL_CHANNELS 3
+#define NUM_SMD_CONTROL_CHANNELS NUM_SMD_DATA_CHANNELS
 #define NUM_SMD_DCI_CHANNELS 1
+#define NUM_SMD_CMD_CHANNELS 1
+#define NUM_SMD_DCI_CMD_CHANNELS 1
 
 #define SMD_DATA_TYPE 0
 #define SMD_CNTL_TYPE 1
 #define SMD_DCI_TYPE 2
+#define SMD_CMD_TYPE 3
+#define SMD_DCI_CMD_TYPE 4
 
 /* Maximum number of pkt reg supported at initialization*/
 extern int diag_max_reg;
@@ -221,6 +225,7 @@
 	struct diag_write_device *buf_tbl;
 	unsigned int buf_tbl_size;
 	int use_device_tree;
+	int supports_separate_cmdrsp;
 	/* DCI related variables */
 	struct dci_pkt_req_tracking_tbl *req_tracking_tbl;
 	struct diag_dci_client_tbl *dci_client_tbl;
@@ -263,6 +268,9 @@
 	struct diag_smd_info smd_data[NUM_SMD_DATA_CHANNELS];
 	struct diag_smd_info smd_cntl[NUM_SMD_CONTROL_CHANNELS];
 	struct diag_smd_info smd_dci[NUM_SMD_DCI_CHANNELS];
+	struct diag_smd_info smd_cmd[NUM_SMD_CMD_CHANNELS];
+	struct diag_smd_info smd_dci_cmd[NUM_SMD_DCI_CMD_CHANNELS];
+	int separate_cmdrsp[NUM_SMD_CONTROL_CHANNELS];
 	unsigned char *usb_buf_out;
 	unsigned char *apps_rsp_buf;
 	/* buffer for updating mask to peripherals */
diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c
index 96e8b11..66e1abc 100644
--- a/drivers/char/diag/diagchar_core.c
+++ b/drivers/char/diag/diagchar_core.c
@@ -782,7 +782,7 @@
 
 int diag_switch_logging(unsigned long ioarg)
 {
-	int i, temp, success = -EINVAL, status;
+	int temp = 0, success = -EINVAL, status = 0;
 	int temp_realtime_mode = driver->real_time_mode;
 	int requested_mode = (int)ioarg;
 
@@ -857,24 +857,13 @@
 
 	if (temp == MEMORY_DEVICE_MODE && driver->logging_mode
 						== NO_LOGGING_MODE) {
-		for (i = 0; i < NUM_SMD_DATA_CHANNELS; i++) {
-			driver->smd_data[i].in_busy_1 = 0;
-			driver->smd_data[i].in_busy_2 = 0;
-		}
+		diag_reset_smd_data(RESET_AND_NO_QUEUE);
 		diag_cmp_logging_modes_sdio_pipe(temp, driver->logging_mode);
 		diag_cmp_logging_modes_diagfwd_bridge(temp,
 							driver->logging_mode);
 	} else if (temp == NO_LOGGING_MODE && driver->logging_mode
 						== MEMORY_DEVICE_MODE) {
-		for (i = 0; i < NUM_SMD_DATA_CHANNELS; i++) {
-			driver->smd_data[i].in_busy_1 = 0;
-			driver->smd_data[i].in_busy_2 = 0;
-			/* Poll SMD channels to check for data*/
-			if (driver->smd_data[i].ch)
-				queue_work(driver->diag_wq,
-					&(driver->smd_data[i].
-						diag_read_smd_work));
-		}
+		diag_reset_smd_data(RESET_AND_QUEUE);
 		diag_cmp_logging_modes_sdio_pipe(temp,
 						driver->logging_mode);
 		diag_cmp_logging_modes_diagfwd_bridge(temp,
@@ -892,15 +881,7 @@
 	} else if (temp == USB_MODE && driver->logging_mode
 						== MEMORY_DEVICE_MODE) {
 		diagfwd_disconnect();
-		for (i = 0; i < NUM_SMD_DATA_CHANNELS; i++) {
-			driver->smd_data[i].in_busy_1 = 0;
-			driver->smd_data[i].in_busy_2 = 0;
-			/* Poll SMD channels to check for data*/
-			if (driver->smd_data[i].ch)
-				queue_work(driver->diag_wq,
-					&(driver->smd_data[i].
-						diag_read_smd_work));
-		}
+		diag_reset_smd_data(RESET_AND_QUEUE);
 		diag_cmp_logging_modes_sdio_pipe(temp, driver->logging_mode);
 		diag_cmp_logging_modes_diagfwd_bridge(temp,
 						driver->logging_mode);
@@ -964,9 +945,13 @@
 			return -EFAULT;
 		}
 		mutex_lock(&driver->dci_mutex);
-		if (!(driver->num_dci_client))
+		if (!(driver->num_dci_client)) {
 			for (i = 0; i < NUM_SMD_DCI_CHANNELS; i++)
 				driver->smd_dci[i].in_busy_1 = 0;
+			if (driver->supports_separate_cmdrsp)
+				for (i = 0; i < NUM_SMD_DCI_CMD_CHANNELS; i++)
+					driver->smd_dci_cmd[i].in_busy_1 = 0;
+		}
 		driver->num_dci_client++;
 		pr_debug("diag: In %s, id = %d\n",
 				__func__, driver->dci_client_id);
@@ -1206,7 +1191,7 @@
 			}
 		}
 
-		/* copy modem data */
+		/* Copy peripheral data */
 		for (i = 0; i < NUM_SMD_DATA_CHANNELS; i++) {
 			struct diag_smd_info *data = &driver->smd_data[i];
 			if (data->in_busy_1 == 1) {
@@ -1240,6 +1225,37 @@
 				data->in_busy_2 = 0;
 			}
 		}
+		if (driver->supports_separate_cmdrsp) {
+			for (i = 0; i < NUM_SMD_CMD_CHANNELS; i++) {
+				struct diag_smd_info *data =
+						&driver->smd_cmd[i];
+				if (!driver->separate_cmdrsp[i])
+					continue;
+
+				if (data->in_busy_1 == 1) {
+					num_data++;
+					/*Copy the length of data being passed*/
+					COPY_USER_SPACE_OR_EXIT(buf+ret,
+						(data->write_ptr_1->length), 4);
+					/*Copy the actual data being passed*/
+					COPY_USER_SPACE_OR_EXIT(buf+ret,
+						*(data->buf_in_1),
+						data->write_ptr_1->length);
+					data->in_busy_1 = 0;
+				}
+				if (data->in_busy_2 == 1) {
+					num_data++;
+					/*Copy the length of data being passed*/
+					COPY_USER_SPACE_OR_EXIT(buf+ret,
+						(data->write_ptr_2->length), 4);
+					/*Copy the actual data being passed*/
+					COPY_USER_SPACE_OR_EXIT(buf+ret,
+						*(data->buf_in_2),
+						data->write_ptr_2->length);
+					data->in_busy_2 = 0;
+				}
+			}
+		}
 #ifdef CONFIG_DIAG_SDIO_PIPE
 		/* copy 9K data over SDIO */
 		if (driver->in_busy_sdio == 1) {
@@ -1360,6 +1376,17 @@
 				queue_work(driver->diag_dci_wq,
 				&(driver->smd_dci[i].diag_read_smd_work));
 		}
+		if (driver->supports_separate_cmdrsp) {
+			for (i = 0; i < NUM_SMD_DCI_CMD_CHANNELS; i++) {
+				if (!driver->separate_cmdrsp[i])
+					continue;
+				driver->smd_dci_cmd[i].in_busy_1 = 0;
+				if (driver->smd_dci_cmd[i].ch)
+					queue_work(driver->diag_dci_wq,
+						&(driver->smd_dci_cmd[i].
+							diag_read_smd_work));
+			}
+		}
 		goto exit;
 	}
 exit:
diff --git a/drivers/char/diag/diagfwd.c b/drivers/char/diag/diagfwd.c
index f76d41a..6851fd8 100644
--- a/drivers/char/diag/diagfwd.c
+++ b/drivers/char/diag/diagfwd.c
@@ -321,6 +321,19 @@
 {
 	struct diag_request *write_ptr_modem = NULL;
 	int *in_busy_ptr = 0;
+	int err = 0;
+
+	/*
+	 * Do not process data on command channel if the
+	 * channel is not designated to do so
+	 */
+	if ((smd_info->type == SMD_CMD_TYPE) &&
+		!driver->separate_cmdrsp[smd_info->peripheral]) {
+		/* This print is for debugging */
+		pr_err("diag, In %s, received data on non-designated command channel: %d\n",
+			__func__, smd_info->peripheral);
+		return 0;
+	}
 
 	if (smd_info->buf_in_1 == buf) {
 		write_ptr_modem = smd_info->write_ptr_1;
@@ -335,7 +348,14 @@
 	if (write_ptr_modem) {
 		write_ptr_modem->length = total_recd;
 		*in_busy_ptr = 1;
-		diag_device_write(buf, smd_info->peripheral, write_ptr_modem);
+		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);
+		}
 	}
 
 	return 0;
@@ -356,7 +376,8 @@
 
 	if (!smd_info->in_busy_1)
 		buf = smd_info->buf_in_1;
-	else if ((smd_info->type == SMD_DATA_TYPE) && !smd_info->in_busy_2)
+	else if (!smd_info->in_busy_2 &&
+			(smd_info->type == SMD_DATA_TYPE))
 		buf = smd_info->buf_in_2;
 
 	if (smd_info->ch && buf) {
@@ -526,12 +547,20 @@
 		} else
 			return -EINVAL;
 	} else if (driver->logging_mode == NO_LOGGING_MODE) {
-		if ((data_type >= 0) && (data_type < NUM_SMD_DATA_CHANNELS)) {
+		if ((data_type >= MODEM_DATA) && (data_type <= WCNSS_DATA)) {
 			driver->smd_data[data_type].in_busy_1 = 0;
 			driver->smd_data[data_type].in_busy_2 = 0;
 			queue_work(driver->diag_wq,
 				&(driver->smd_data[data_type].
 							diag_read_smd_work));
+			if (data_type == MODEM_DATA &&
+				driver->separate_cmdrsp[data_type]) {
+				driver->smd_cmd[data_type].in_busy_1 = 0;
+				driver->smd_cmd[data_type].in_busy_2 = 0;
+				queue_work(driver->diag_wq,
+					&(driver->smd_cmd[data_type].
+							diag_read_smd_work));
+			}
 		}
 #ifdef CONFIG_DIAG_SDIO_PIPE
 		else if (data_type == SDIO_DATA) {
@@ -564,8 +593,8 @@
 						driver->write_ptr_svc);
 			} else
 				err = -1;
-		} else if ((data_type >= 0) &&
-				(data_type < NUM_SMD_DATA_CHANNELS)) {
+		} else if ((data_type >= MODEM_DATA) &&
+				(data_type <= WCNSS_DATA)) {
 			write_ptr->buf = buf;
 #ifdef DIAG_DEBUG
 			printk(KERN_INFO "writing data to USB,"
@@ -689,27 +718,42 @@
 					 int len, int type)
 {
 	driver->pkt_length = len;
-	if (entry.process_id != NON_APPS_PROC && type != MODEM_DATA) {
-		diag_update_pkt_buffer(buf);
-		diag_update_sleeping_process(entry.process_id, PKT_TYPE);
+
+	/* If the process_id corresponds to an apps process */
+	if (entry.process_id != NON_APPS_PROC) {
+		/* If the message is to be sent to the apps process */
+		if (type != MODEM_DATA) {
+			diag_update_pkt_buffer(buf);
+			diag_update_sleeping_process(entry.process_id,
+							PKT_TYPE);
+		}
 	} else {
 		if (len > 0) {
 			if (entry.client_id < NUM_SMD_DATA_CHANNELS) {
+				struct diag_smd_info *smd_info;
 				int index = entry.client_id;
-				if (driver->smd_data[index].ch) {
-					if ((index == MODEM_DATA) &&
-						diag_check_mode_reset(buf)) {
-						return;
-					}
-					mutex_lock(&driver->smd_data[index].
-								smd_ch_mutex);
-					smd_write(driver->smd_data[index].ch,
-							buf, len);
-					mutex_unlock(&driver->smd_data[index].
-								smd_ch_mutex);
+				/*
+				 * Mode reset should work even if
+				 * modem is down
+				 */
+				if ((index == MODEM_DATA) &&
+					diag_check_mode_reset(buf)) {
+					return;
+				}
+				smd_info = (driver->separate_cmdrsp[index] &&
+						index < NUM_SMD_CMD_CHANNELS) ?
+						&driver->smd_cmd[index] :
+						&driver->smd_data[index];
+
+				if (smd_info->ch) {
+					mutex_lock(&smd_info->smd_ch_mutex);
+					smd_write(smd_info->ch, buf, len);
+					mutex_unlock(&smd_info->smd_ch_mutex);
 				} else {
-					pr_err("diag: In %s, smd channel %d not open\n",
-						__func__, index);
+					pr_err("diag: In %s, smd channel %d not open, peripheral: %d, type: %d\n",
+						__func__, index,
+						smd_info->peripheral,
+						smd_info->type);
 				}
 			} else {
 				pr_alert("diag: In %s, incorrect channel: %d",
@@ -1278,9 +1322,37 @@
 	mutex_unlock(&driver->diag_hdlc_mutex);
 }
 
+void diag_reset_smd_data(int queue)
+{
+	int i;
+
+	for (i = 0; i < NUM_SMD_DATA_CHANNELS; i++) {
+		driver->smd_data[i].in_busy_1 = 0;
+		driver->smd_data[i].in_busy_2 = 0;
+		if (queue)
+			/* Poll SMD data channels to check for data */
+			queue_work(driver->diag_wq,
+				&(driver->smd_data[i].diag_read_smd_work));
+	}
+
+	if (driver->supports_separate_cmdrsp) {
+		for (i = 0; i < NUM_SMD_CMD_CHANNELS; i++) {
+			driver->smd_cmd[i].in_busy_1 = 0;
+			driver->smd_cmd[i].in_busy_2 = 0;
+			if (queue)
+				/* Poll SMD data channels to check for data */
+				queue_work(driver->diag_wq,
+					&(driver->smd_cmd[i].
+						diag_read_smd_work));
+		}
+	}
+}
+
 #ifdef CONFIG_DIAG_OVER_USB
 /* 2+1 for modem ; 2 for LPASS ; 1 for WCNSS */
 #define N_LEGACY_WRITE	(driver->poolsize + 6)
+/* Additionally support number of command data and dci channels */
+#define N_LEGACY_WRITE_CMD ((N_LEGACY_WRITE) + 4)
 #define N_LEGACY_READ	1
 
 static void diag_usb_connect_work_fn(struct work_struct *w)
@@ -1299,18 +1371,16 @@
 	int i;
 
 	printk(KERN_DEBUG "diag: USB connected\n");
-	err = usb_diag_alloc_req(driver->legacy_ch, N_LEGACY_WRITE,
+	err = usb_diag_alloc_req(driver->legacy_ch,
+			(driver->supports_separate_cmdrsp ?
+			N_LEGACY_WRITE_CMD : N_LEGACY_WRITE),
 			N_LEGACY_READ);
 	if (err)
 		printk(KERN_ERR "diag: unable to alloc USB req on legacy ch");
 
 	driver->usb_connected = 1;
+	diag_reset_smd_data(RESET_AND_QUEUE);
 	for (i = 0; i < NUM_SMD_DATA_CHANNELS; i++) {
-		driver->smd_data[i].in_busy_1 = 0;
-		driver->smd_data[i].in_busy_2 = 0;
-		/* Poll SMD data channels to check for data */
-		queue_work(driver->diag_wq,
-			&(driver->smd_data[i].diag_read_smd_work));
 		/* Poll SMD CNTL channels to check for data */
 		diag_smd_notify(&(driver->smd_cntl[i]), SMD_EVENT_DATA);
 	}
@@ -1341,6 +1411,13 @@
 			driver->smd_data[i].in_busy_1 = 1;
 			driver->smd_data[i].in_busy_2 = 1;
 		}
+
+		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;
+			}
+		}
 	}
 #ifdef CONFIG_DIAG_SDIO_PIPE
 	if (machine_is_msm8x60_fusion() || machine_is_msm8x60_fusn_ffa())
@@ -1351,30 +1428,44 @@
 	return 0;
 }
 
-int diagfwd_write_complete(struct diag_request *diag_write_ptr)
+static int diagfwd_check_buf_match(int num_channels,
+			struct diag_smd_info *data, unsigned char *buf)
 {
-	unsigned char *buf = diag_write_ptr->buf;
-	int found_it = 0;
 	int i;
+	int found_it = 0;
 
-	/* Determine if the write complete is for data from modem/apps/q6 */
-	/* Need a context variable here instead */
-	for (i = 0; i < NUM_SMD_DATA_CHANNELS; i++) {
-		struct diag_smd_info *data = &(driver->smd_data[i]);
-		if (buf == (void *)data->buf_in_1) {
-			data->in_busy_1 = 0;
+	for (i = 0; i < num_channels; i++) {
+		if (buf == (void *)data[i].buf_in_1) {
+			data[i].in_busy_1 = 0;
 			queue_work(driver->diag_wq,
-				&(data->diag_read_smd_work));
+				&(data[i].diag_read_smd_work));
 			found_it = 1;
 			break;
-		} else if (buf == (void *)data->buf_in_2) {
-			data->in_busy_2 = 0;
+		} else if (buf == (void *)data[i].buf_in_2) {
+			data[i].in_busy_2 = 0;
 			queue_work(driver->diag_wq,
-				&(data->diag_read_smd_work));
+				&(data[i].diag_read_smd_work));
 			found_it = 1;
 			break;
 		}
 	}
+
+	return found_it;
+}
+
+int diagfwd_write_complete(struct diag_request *diag_write_ptr)
+{
+	unsigned char *buf = diag_write_ptr->buf;
+	int found_it = 0;
+
+	/* Determine if the write complete is for data from modem/apps/q6 */
+	found_it = diagfwd_check_buf_match(NUM_SMD_DATA_CHANNELS,
+						driver->smd_data, buf);
+
+	if (!found_it && driver->supports_separate_cmdrsp)
+		found_it = diagfwd_check_buf_match(NUM_SMD_CMD_CHANNELS,
+						driver->smd_cmd, buf);
+
 #ifdef CONFIG_DIAG_SDIO_PIPE
 	if (!found_it) {
 		if (buf == (void *)driver->buf_in_sdio) {
@@ -1522,7 +1613,8 @@
 
 	wake_up(&driver->smd_wait_q);
 
-	if (smd_info->type == SMD_DCI_TYPE)
+	if (smd_info->type == SMD_DCI_TYPE ||
+		smd_info->type == SMD_DCI_CMD_TYPE)
 		queue_work(driver->diag_dci_wq,
 				&(smd_info->diag_read_smd_work));
 	else
@@ -1533,40 +1625,66 @@
 {
 	int r = 0;
 	int index = -1;
+	const char *channel_name = NULL;
 
 	if (pdev->id == SMD_APPS_MODEM) {
 		index = MODEM_DATA;
-		r = smd_open("DIAG", &driver->smd_data[index].ch,
-					&driver->smd_data[index],
-					diag_smd_notify);
-		driver->smd_data[index].ch_save =
-					driver->smd_data[index].ch;
+		channel_name = "DIAG";
 	}
 #if defined(CONFIG_MSM_N_WAY_SMD)
-	if (pdev->id == SMD_APPS_QDSP) {
+	else if (pdev->id == SMD_APPS_QDSP) {
 		index = LPASS_DATA;
-		r = smd_named_open_on_edge("DIAG", SMD_APPS_QDSP,
-					&driver->smd_data[index].ch,
-					&driver->smd_data[index],
-					diag_smd_notify);
-		driver->smd_data[index].ch_save =
-					driver->smd_data[index].ch;
+		channel_name = "DIAG";
 	}
 #endif
-	if (pdev->id == SMD_APPS_WCNSS) {
+	else if (pdev->id == SMD_APPS_WCNSS) {
 		index = WCNSS_DATA;
-		r = smd_named_open_on_edge("APPS_RIVA_DATA",
-					SMD_APPS_WCNSS,
+		channel_name = "APPS_RIVA_DATA";
+	}
+
+	if (index != -1) {
+		r = smd_named_open_on_edge(channel_name,
+					pdev->id,
 					&driver->smd_data[index].ch,
 					&driver->smd_data[index],
 					diag_smd_notify);
-		driver->smd_data[index].ch_save =
-					driver->smd_data[index].ch;
+		driver->smd_data[index].ch_save = driver->smd_data[index].ch;
 	}
 
 	pm_runtime_set_active(&pdev->dev);
 	pm_runtime_enable(&pdev->dev);
-	pr_debug("diag: open SMD port, Id = %d, r = %d\n", pdev->id, r);
+	pr_debug("diag: In %s, open SMD port, Id = %d, r = %d\n",
+		__func__, pdev->id, r);
+
+	return 0;
+}
+
+static int diag_smd_cmd_probe(struct platform_device *pdev)
+{
+	int r = 0;
+	int index = -1;
+	const char *channel_name = NULL;
+
+	if (!driver->supports_separate_cmdrsp)
+		return 0;
+
+	if (pdev->id == SMD_APPS_MODEM) {
+		index = MODEM_DATA;
+		channel_name = "DIAG_CMD";
+	}
+
+	if (index != -1) {
+		r = smd_named_open_on_edge(channel_name,
+			pdev->id,
+			&driver->smd_cmd[index].ch,
+			&driver->smd_cmd[index],
+			diag_smd_notify);
+		driver->smd_cmd[index].ch_save =
+			driver->smd_cmd[index].ch;
+	}
+
+	pr_debug("diag: In %s, open SMD CMD port, Id = %d, r = %d\n",
+		__func__, pdev->id, r);
 
 	return 0;
 }
@@ -1608,6 +1726,24 @@
 	},
 };
 
+static struct platform_driver
+		smd_lite_data_cmd_drivers[NUM_SMD_CMD_CHANNELS] = {
+	{
+		/* Modem data */
+		.probe = diag_smd_cmd_probe,
+		.driver = {
+			.name = "DIAG_CMD",
+			.owner = THIS_MODULE,
+			.pm   = &diag_smd_dev_pm_ops,
+		},
+	}
+};
+
+int device_supports_separate_cmdrsp(void)
+{
+	return driver->use_device_tree;
+}
+
 void diag_smd_destructor(struct diag_smd_info *smd_info)
 {
 	if (smd_info->type == SMD_DATA_TYPE)
@@ -1693,16 +1829,22 @@
 	 * information to the update function.
 	 */
 	smd_info->notify_context = 0;
-	if (type == SMD_DATA_TYPE)
+	switch (type) {
+	case SMD_DATA_TYPE:
+	case SMD_CMD_TYPE:
 		INIT_WORK(&(smd_info->diag_notify_update_smd_work),
-							diag_clean_reg_fn);
-	else if (type == SMD_CNTL_TYPE)
+						diag_clean_reg_fn);
+		break;
+	case SMD_CNTL_TYPE:
 		INIT_WORK(&(smd_info->diag_notify_update_smd_work),
-							diag_mask_update_fn);
-	else if (type == SMD_DCI_TYPE)
+						diag_mask_update_fn);
+		break;
+	case SMD_DCI_TYPE:
+	case SMD_DCI_CMD_TYPE:
 		INIT_WORK(&(smd_info->diag_notify_update_smd_work),
-						diag_update_smd_dci_work_fn);
-	else {
+					diag_update_smd_dci_work_fn);
+		break;
+	default:
 		pr_err("diag: In %s, unknown type, type: %d\n", __func__, type);
 		goto err;
 	}
@@ -1711,15 +1853,21 @@
 	 * Set function ptr for function to call to process the data that
 	 * was just read from the smd channel
 	 */
-	if (type == SMD_DATA_TYPE)
+	switch (type) {
+	case SMD_DATA_TYPE:
+	case SMD_CMD_TYPE:
 		smd_info->process_smd_read_data = diag_process_smd_read_data;
-	else if (type == SMD_CNTL_TYPE)
+		break;
+	case SMD_CNTL_TYPE:
 		smd_info->process_smd_read_data =
 						diag_process_smd_cntl_read_data;
-	else if (type == SMD_DCI_TYPE)
+		break;
+	case SMD_DCI_TYPE:
+	case SMD_DCI_CMD_TYPE:
 		smd_info->process_smd_read_data =
 						diag_process_smd_dci_read_data;
-	else {
+		break;
+	default:
 		pr_err("diag: In %s, unknown type, type: %d\n", __func__, type);
 		goto err;
 	}
@@ -1775,23 +1923,28 @@
 	 */
 	driver->buf_tbl_size = (buf_tbl_size < driver->poolsize_hdlc) ?
 				driver->poolsize_hdlc : buf_tbl_size;
+	driver->supports_separate_cmdrsp = device_supports_separate_cmdrsp();
 	mutex_init(&driver->diag_hdlc_mutex);
 	mutex_init(&driver->diag_cntl_mutex);
 
-	success = diag_smd_constructor(&driver->smd_data[MODEM_DATA],
-					MODEM_DATA, SMD_DATA_TYPE);
-	if (!success)
-		goto err;
+	for (i = 0; i < NUM_SMD_CONTROL_CHANNELS; i++)
+		driver->separate_cmdrsp[i] = 0;
 
-	success = diag_smd_constructor(&driver->smd_data[LPASS_DATA],
-					LPASS_DATA, SMD_DATA_TYPE);
-	if (!success)
-		goto err;
+	for (i = 0; i < NUM_SMD_DATA_CHANNELS; i++) {
+		success = diag_smd_constructor(&driver->smd_data[i], i,
+							SMD_DATA_TYPE);
+		if (!success)
+			goto err;
+	}
 
-	success = diag_smd_constructor(&driver->smd_data[WCNSS_DATA],
-					WCNSS_DATA, SMD_DATA_TYPE);
-	if (!success)
-		goto err;
+	if (driver->supports_separate_cmdrsp) {
+		for (i = 0; i < NUM_SMD_CMD_CHANNELS; i++) {
+			success = diag_smd_constructor(&driver->smd_cmd[i], i,
+								SMD_CMD_TYPE);
+			if (!success)
+				goto err;
+		}
+	}
 
 	if (driver->usb_buf_out  == NULL &&
 	     (driver->usb_buf_out = kzalloc(USB_MAX_OUT_BUF,
@@ -1861,6 +2014,12 @@
 #endif
 	platform_driver_register(&msm_smd_ch1_driver);
 	platform_driver_register(&diag_smd_lite_driver);
+
+	if (driver->supports_separate_cmdrsp) {
+		for (i = 0; i < NUM_SMD_CMD_CHANNELS; i++)
+			platform_driver_register(&smd_lite_data_cmd_drivers[i]);
+	}
+
 	return;
 err:
 	pr_err("diag: Could not initialize diag buffers");
@@ -1868,6 +2027,9 @@
 	for (i = 0; i < NUM_SMD_DATA_CHANNELS; i++)
 		diag_smd_destructor(&driver->smd_data[i]);
 
+	for (i = 0; i < NUM_SMD_CMD_CHANNELS; i++)
+		diag_smd_destructor(&driver->smd_cmd[i]);
+
 	kfree(driver->buf_msg_mask_update);
 	kfree(driver->buf_log_mask_update);
 	kfree(driver->buf_event_mask_update);
@@ -1897,9 +2059,16 @@
 	usb_diag_close(driver->legacy_ch);
 #endif
 	platform_driver_unregister(&msm_smd_ch1_driver);
-	platform_driver_unregister(&msm_diag_dci_driver);
 	platform_driver_unregister(&diag_smd_lite_driver);
 
+	if (driver->supports_separate_cmdrsp) {
+		for (i = 0; i < NUM_SMD_CMD_CHANNELS; i++) {
+			diag_smd_destructor(&driver->smd_cmd[i]);
+			platform_driver_unregister(
+				&smd_lite_data_cmd_drivers[i]);
+		}
+	}
+
 	kfree(driver->buf_msg_mask_update);
 	kfree(driver->buf_log_mask_update);
 	kfree(driver->buf_event_mask_update);
diff --git a/drivers/char/diag/diagfwd.h b/drivers/char/diag/diagfwd.h
index 09f2f5e..c6e1273 100644
--- a/drivers/char/diag/diagfwd.h
+++ b/drivers/char/diag/diagfwd.h
@@ -16,6 +16,9 @@
 #define NO_PROCESS	0
 #define NON_APPS_PROC	-1
 
+#define RESET_AND_NO_QUEUE 0
+#define RESET_AND_QUEUE 1
+
 #define CHK_OVERFLOW(bufStart, start, end, length) \
 	((((bufStart) <= (start)) && ((end) - (start) >= (length))) ? 1 : 0)
 
@@ -49,6 +52,7 @@
 void diag_cmp_logging_modes_sdio_pipe(int old_mode, int new_mode);
 void diag_cmp_logging_modes_diagfwd_bridge(int old_mode, int new_mode);
 int diag_process_apps_pkt(unsigned char *buf, int len);
+void diag_reset_smd_data(int queue);
 /* State for diag forwarding */
 #ifdef CONFIG_DIAG_OVER_USB
 int diagfwd_connect(void);
diff --git a/drivers/char/diag/diagfwd_cntl.c b/drivers/char/diag/diagfwd_cntl.c
index 2776c58..960fdb9 100644
--- a/drivers/char/diag/diagfwd_cntl.c
+++ b/drivers/char/diag/diagfwd_cntl.c
@@ -45,7 +45,6 @@
 								int total_recd)
 {
 	int data_len = 0, type = -1, count_bytes = 0, j, flag = 0;
-	int feature_mask_len;
 	struct bindpkt_params_per_process *pkt_params =
 		kzalloc(sizeof(struct bindpkt_params_per_process), GFP_KERNEL);
 	struct diag_ctrl_msg *msg;
@@ -116,11 +115,32 @@
 				pr_err("diag: drop reg proc %d\n",
 						smd_info->peripheral);
 			kfree(pkt_params->params);
-		} else if ((type == DIAG_CTRL_MSG_FEATURE) &&
-				(smd_info->peripheral == MODEM_DATA)) {
-			feature_mask_len = *(int *)(buf + 8);
-			driver->log_on_demand_support = (*(uint8_t *)
-							 (buf + 12)) & 0x04;
+		} else if (type == DIAG_CTRL_MSG_FEATURE &&
+				total_recd >= count_bytes) {
+			uint8_t feature_mask = 0;
+			int feature_mask_len = *(int *)(buf+8);
+			if (feature_mask_len > 0) {
+				feature_mask = *(uint8_t *)(buf+12);
+				if (smd_info->peripheral == MODEM_DATA)
+					driver->log_on_demand_support =
+						feature_mask &
+					F_DIAG_LOG_ON_DEMAND_RSP_ON_MASTER;
+				/*
+				 * If apps supports separate cmd/rsp channels
+				 * and the peripheral supports separate cmd/rsp
+				 * channels
+				 */
+				if (driver->supports_separate_cmdrsp &&
+					(feature_mask & F_DIAG_REQ_RSP_CHANNEL))
+					driver->separate_cmdrsp
+						[smd_info->peripheral] =
+							ENABLE_SEPARATE_CMDRSP;
+				else
+					driver->separate_cmdrsp
+						[smd_info->peripheral] =
+							DISABLE_SEPARATE_CMDRSP;
+			}
+			flag = 1;
 		} else if (type != DIAG_CTRL_MSG_REG) {
 			flag = 1;
 		}
@@ -212,39 +232,38 @@
 {
 	int r = 0;
 	int index = -1;
+	const char *channel_name = NULL;
 
 	/* open control ports only on 8960 & newer targets */
 	if (chk_apps_only()) {
 		if (pdev->id == SMD_APPS_MODEM) {
 			index = MODEM_DATA;
-			r = smd_open("DIAG_CNTL",
-					&driver->smd_cntl[index].ch,
-					&driver->smd_cntl[index],
-					diag_smd_notify);
-			driver->smd_cntl[index].ch_save =
-					driver->smd_cntl[index].ch;
-		} else if (pdev->id == SMD_APPS_QDSP) {
+			channel_name = "DIAG_CNTL";
+		}
+#if defined(CONFIG_MSM_N_WAY_SMD)
+		else if (pdev->id == SMD_APPS_QDSP) {
 			index = LPASS_DATA;
-			r = smd_named_open_on_edge("DIAG_CNTL",
-					SMD_APPS_QDSP,
-					&driver->smd_cntl[index].ch,
-					&driver->smd_cntl[index],
-					diag_smd_notify);
-			driver->smd_cntl[index].ch_save =
-					driver->smd_cntl[index].ch;
-		} else if (pdev->id == SMD_APPS_WCNSS) {
+			channel_name = "DIAG_CNTL";
+		}
+#endif
+		else if (pdev->id == SMD_APPS_WCNSS) {
 			index = WCNSS_DATA;
-			r = smd_named_open_on_edge("APPS_RIVA_CTRL",
-					SMD_APPS_WCNSS,
-					&driver->smd_cntl[index].ch,
-					&driver->smd_cntl[index],
-					diag_smd_notify);
-			driver->smd_cntl[index].ch_save =
-					driver->smd_cntl[index].ch;
+			channel_name = "APPS_RIVA_CTRL";
 		}
 
-		pr_debug("diag: open CNTL port, ID = %d,r = %d\n", pdev->id, r);
+		if (index != -1) {
+			r = smd_named_open_on_edge(channel_name,
+				pdev->id,
+				&driver->smd_cntl[index].ch,
+				&driver->smd_cntl[index],
+				diag_smd_notify);
+			driver->smd_cntl[index].ch_save =
+				driver->smd_cntl[index].ch;
+		}
+		pr_debug("diag: In %s, open SMD CNTL port, Id = %d, r = %d\n",
+			__func__, pdev->id, r);
 	}
+
 	return 0;
 }
 
@@ -269,20 +288,20 @@
 
 	.probe = diag_smd_cntl_probe,
 	.driver = {
-			.name = "DIAG_CNTL",
-			.owner = THIS_MODULE,
-			.pm   = &diagfwd_cntl_dev_pm_ops,
-		   },
+		.name = "DIAG_CNTL",
+		.owner = THIS_MODULE,
+		.pm   = &diagfwd_cntl_dev_pm_ops,
+	},
 };
 
 static struct platform_driver diag_smd_lite_cntl_driver = {
 
 	.probe = diag_smd_cntl_probe,
 	.driver = {
-			.name = "APPS_RIVA_CTRL",
-			.owner = THIS_MODULE,
-			.pm   = &diagfwd_cntl_dev_pm_ops,
-		   },
+		.name = "APPS_RIVA_CTRL",
+		.owner = THIS_MODULE,
+		.pm   = &diagfwd_cntl_dev_pm_ops,
+	},
 };
 
 void diagfwd_cntl_init(void)
@@ -295,20 +314,12 @@
 	driver->log_on_demand_support = 1;
 	driver->diag_cntl_wq = create_singlethread_workqueue("diag_cntl_wq");
 
-	success = diag_smd_constructor(&driver->smd_cntl[MODEM_DATA],
-					MODEM_DATA, SMD_CNTL_TYPE);
-	if (!success)
-		goto err;
-
-	success = diag_smd_constructor(&driver->smd_cntl[LPASS_DATA],
-					LPASS_DATA, SMD_CNTL_TYPE);
-	if (!success)
-		goto err;
-
-	success = diag_smd_constructor(&driver->smd_cntl[WCNSS_DATA],
-					WCNSS_DATA, SMD_CNTL_TYPE);
-	if (!success)
-		goto err;
+	for (i = 0; i < NUM_SMD_CONTROL_CHANNELS; i++) {
+		success = diag_smd_constructor(&driver->smd_cntl[i], i,
+							SMD_CNTL_TYPE);
+		if (!success)
+			goto err;
+	}
 
 	platform_driver_register(&msm_smd_ch1_cntl_driver);
 	platform_driver_register(&diag_smd_lite_cntl_driver);
diff --git a/drivers/char/diag/diagfwd_cntl.h b/drivers/char/diag/diagfwd_cntl.h
index f58ab24..02b9757 100644
--- a/drivers/char/diag/diagfwd_cntl.h
+++ b/drivers/char/diag/diagfwd_cntl.h
@@ -37,7 +37,17 @@
 #define DIAG_CTRL_MSG_LAST DIAG_CTRL_MSG_F3_MASK_WITH_PRESET_ID
 
 /* Denotes that we support sending/receiving the feature mask */
-#define F_DIAG_INT_FEATURE_MASK	0x01
+#define F_DIAG_INT_FEATURE_MASK		0x01
+/* Denotes that we support responding to "Log on Demand" */
+#define F_DIAG_LOG_ON_DEMAND_RSP_ON_MASTER	0x04
+/*
+ * Supports dedicated main request/response on
+ * new Data Rx and DCI Rx channels
+ */
+#define F_DIAG_REQ_RSP_CHANNEL		0x10
+
+#define ENABLE_SEPARATE_CMDRSP	1
+#define DISABLE_SEPARATE_CMDRSP	0
 
 struct cmd_code_range {
 	uint16_t cmd_code_lo;
@@ -110,6 +120,7 @@
 void diagfwd_cntl_init(void);
 void diagfwd_cntl_exit(void);
 void diag_read_smd_cntl_work_fn(struct work_struct *);
+void diag_notify_ctrl_update_fn(struct work_struct *work);
 void diag_clean_reg_fn(struct work_struct *work);
 int diag_process_smd_cntl_read_data(struct diag_smd_info *smd_info, void *buf,
 								int total_recd);
diff --git a/drivers/char/msm_rotator.c b/drivers/char/msm_rotator.c
index 9a43ea4..156a2a5 100644
--- a/drivers/char/msm_rotator.c
+++ b/drivers/char/msm_rotator.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2009-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
@@ -351,6 +351,7 @@
 	case MDP_RGBA_8888:
 	case MDP_BGRA_8888:
 	case MDP_RGBX_8888:
+	case MDP_BGRX_8888:
 		return 4;
 
 	case MDP_Y_CBCR_H2V2:
@@ -407,6 +408,7 @@
 	case MDP_RGBA_8888:
 	case MDP_BGRA_8888:
 	case MDP_RGBX_8888:
+	case MDP_BGRX_8888:
 	case MDP_RGB_888:
 	case MDP_RGB_565:
 	case MDP_BGR_565:
@@ -811,6 +813,7 @@
 			break;
 
 		case MDP_BGRA_8888:
+		case MDP_BGRX_8888:
 			iowrite32(GET_PACK_PATTERN(CLR_ALPHA, CLR_B, CLR_G,
 						   CLR_R, 8),
 				  MSM_ROTATOR_SRC_UNPACK_PATTERN1);
@@ -1118,6 +1121,7 @@
 	case MDP_XRGB_8888:
 	case MDP_BGRA_8888:
 	case MDP_RGBX_8888:
+	case MDP_BGRX_8888:
 	case MDP_YCBCR_H1V1:
 	case MDP_YCRCB_H1V1:
 		rc = msm_rotator_rgb_types(msm_rotator_dev->img_info[s],
@@ -1275,6 +1279,7 @@
 	case MDP_XRGB_8888:
 	case MDP_RGBX_8888:
 	case MDP_BGRA_8888:
+	case MDP_BGRX_8888:
 		is_rgb = 1;
 		info.dst.format = info.src.format;
 		break;
diff --git a/drivers/cpufreq/cpufreq_conservative.c b/drivers/cpufreq/cpufreq_conservative.c
index 235a340..85c28d4 100644
--- a/drivers/cpufreq/cpufreq_conservative.c
+++ b/drivers/cpufreq/cpufreq_conservative.c
@@ -80,6 +80,8 @@
  */
 static DEFINE_MUTEX(dbs_mutex);
 
+static struct workqueue_struct *dbs_wq;
+
 static struct dbs_tuners {
 	unsigned int sampling_rate;
 	unsigned int sampling_down_factor;
@@ -455,7 +457,7 @@
 
 	dbs_check_cpu(dbs_info);
 
-	schedule_delayed_work_on(cpu, &dbs_info->work, delay);
+	queue_delayed_work_on(cpu, dbs_wq, &dbs_info->work, delay);
 	mutex_unlock(&dbs_info->timer_mutex);
 }
 
@@ -467,7 +469,7 @@
 
 	dbs_info->enable = 1;
 	INIT_DELAYED_WORK_DEFERRABLE(&dbs_info->work, do_dbs_timer);
-	schedule_delayed_work_on(dbs_info->cpu, &dbs_info->work, delay);
+	queue_delayed_work_on(dbs_info->cpu, dbs_wq, &dbs_info->work, delay);
 }
 
 static inline void dbs_timer_exit(struct cpu_dbs_info_s *dbs_info)
@@ -602,12 +604,19 @@
 
 static int __init cpufreq_gov_dbs_init(void)
 {
+	dbs_wq = alloc_workqueue("conservative_dbs_wq", WQ_HIGHPRI, 0);
+	if (!dbs_wq) {
+		printk(KERN_ERR "Failed to create conservative_dbs_wq workqueue\n");
+		return -EFAULT;
+	}
+
 	return cpufreq_register_governor(&cpufreq_gov_conservative);
 }
 
 static void __exit cpufreq_gov_dbs_exit(void)
 {
 	cpufreq_unregister_governor(&cpufreq_gov_conservative);
+	destroy_workqueue(dbs_wq);
 }
 
 
diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c
index a506aa8..79f7174 100644
--- a/drivers/cpufreq/cpufreq_ondemand.c
+++ b/drivers/cpufreq/cpufreq_ondemand.c
@@ -4,6 +4,7 @@
  *  Copyright (C)  2001 Russell King
  *            (C)  2003 Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>.
  *                      Jun Nakajima <jun.nakajima@intel.com>
+ *            (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 as
@@ -115,7 +116,7 @@
  */
 static DEFINE_MUTEX(dbs_mutex);
 
-static struct workqueue_struct *input_wq;
+static struct workqueue_struct *dbs_wq;
 
 struct dbs_work_struct {
 	struct work_struct work;
@@ -124,6 +125,14 @@
 
 static DEFINE_PER_CPU(struct dbs_work_struct, dbs_refresh_work);
 
+struct dbs_sync_work_struct {
+	struct work_struct work;
+	unsigned int src_cpu;
+	unsigned int targ_cpu;
+};
+
+static DEFINE_PER_CPU(struct dbs_sync_work_struct, dbs_sync_work);
+
 static struct dbs_tuners {
 	unsigned int sampling_rate;
 	unsigned int up_threshold;
@@ -367,8 +376,8 @@
 			cancel_delayed_work_sync(&dbs_info->work);
 			mutex_lock(&dbs_info->timer_mutex);
 
-			schedule_delayed_work_on(dbs_info->cpu, &dbs_info->work,
-						 usecs_to_jiffies(new_rate));
+			queue_delayed_work_on(dbs_info->cpu, dbs_wq,
+				&dbs_info->work, usecs_to_jiffies(new_rate));
 
 		}
 		mutex_unlock(&dbs_info->timer_mutex);
@@ -932,7 +941,7 @@
 			dbs_info->freq_lo, CPUFREQ_RELATION_H);
 		delay = dbs_info->freq_lo_jiffies;
 	}
-	schedule_delayed_work_on(cpu, &dbs_info->work, delay);
+	queue_delayed_work_on(cpu, dbs_wq, &dbs_info->work, delay);
 	mutex_unlock(&dbs_info->timer_mutex);
 }
 
@@ -946,7 +955,7 @@
 
 	dbs_info->sample_type = DBS_NORMAL_SAMPLE;
 	INIT_DELAYED_WORK_DEFERRABLE(&dbs_info->work, do_dbs_timer);
-	schedule_delayed_work_on(dbs_info->cpu, &dbs_info->work, delay);
+	queue_delayed_work_on(dbs_info->cpu, dbs_wq, &dbs_info->work, delay);
 }
 
 static inline void dbs_timer_exit(struct cpu_dbs_info_s *dbs_info)
@@ -1020,6 +1029,92 @@
 	return;
 }
 
+static int dbs_migration_notify(struct notifier_block *nb,
+				unsigned long target_cpu, void *arg)
+{
+	struct dbs_sync_work_struct *sync_work =
+		&per_cpu(dbs_sync_work, target_cpu);
+	sync_work->src_cpu = (unsigned int)arg;
+
+	queue_work_on(target_cpu, dbs_wq,
+		&per_cpu(dbs_sync_work, target_cpu).work);
+
+	return NOTIFY_OK;
+}
+
+static struct notifier_block dbs_migration_nb = {
+	.notifier_call = dbs_migration_notify,
+};
+
+void dbs_synchronize(struct work_struct *work)
+{
+	struct cpufreq_policy *policy;
+	struct cpu_dbs_info_s *this_dbs_info, *src_dbs_info;
+	struct dbs_sync_work_struct *dbs_work;
+	unsigned int cpu, src_cpu;
+	unsigned int src_freq, src_max_load;
+	int delay;
+
+	dbs_work = container_of(work, struct dbs_sync_work_struct, work);
+	cpu = dbs_work->targ_cpu;
+	src_cpu = dbs_work->src_cpu;
+
+	get_online_cpus();
+
+	/* Getting source cpu info  */
+	src_dbs_info = &per_cpu(od_cpu_dbs_info, src_cpu);
+	if (src_dbs_info != NULL && src_dbs_info->cur_policy != NULL) {
+		src_freq = src_dbs_info->cur_policy->cur;
+		src_max_load = src_dbs_info->max_load;
+	} else {
+		src_freq = dbs_tuners_ins.sync_freq;
+		src_max_load = 0;
+	}
+
+	if (lock_policy_rwsem_write(cpu) < 0)
+		goto bail_acq_sema_failed;
+
+	this_dbs_info = &per_cpu(od_cpu_dbs_info, cpu);
+	policy = this_dbs_info->cur_policy;
+	if (!policy) {
+		/* CPU not using ondemand governor */
+		goto bail_incorrect_governor;
+	}
+
+	delay = usecs_to_jiffies(dbs_tuners_ins.sampling_rate);
+
+	if (policy->cur < src_freq) {
+
+		/* Cancelling the next ondemand sample */
+		cancel_delayed_work_sync(&this_dbs_info->work);
+
+		/*
+		 * Arch specific cpufreq driver may fail.
+		 * Don't update governor frequency upon failure.
+		 */
+		if (__cpufreq_driver_target(policy, src_freq,
+					CPUFREQ_RELATION_L) >= 0) {
+			policy->cur = src_freq;
+			if (src_max_load > this_dbs_info->max_load) {
+				this_dbs_info->max_load = src_max_load;
+				this_dbs_info->prev_load = src_max_load;
+			}
+		}
+
+		/* Rescheduling the next ondemand sample */
+		mutex_lock(&this_dbs_info->timer_mutex);
+		schedule_delayed_work_on(cpu, &this_dbs_info->work,
+					delay);
+		mutex_unlock(&this_dbs_info->timer_mutex);
+	}
+bail_incorrect_governor:
+	unlock_policy_rwsem_write(cpu);
+
+bail_acq_sema_failed:
+	put_online_cpus();
+	return;
+}
+
 static void dbs_input_event(struct input_handle *handle, unsigned int type,
 		unsigned int code, int value)
 {
@@ -1032,7 +1127,7 @@
 	}
 
 	for_each_online_cpu(i)
-		queue_work_on(i, input_wq, &per_cpu(dbs_refresh_work, i).work);
+		queue_work_on(i, dbs_wq, &per_cpu(dbs_refresh_work, i).work);
 }
 
 static int dbs_input_connect(struct input_handler *handler,
@@ -1148,6 +1243,9 @@
 
 			if (dbs_tuners_ins.sync_freq == 0)
 				dbs_tuners_ins.sync_freq = policy->min;
+
+			atomic_notifier_chain_register(&migration_notifier_head,
+					&dbs_migration_nb);
 		}
 		if (!cpu)
 			rc = input_register_handler(&dbs_input_handler);
@@ -1171,9 +1269,14 @@
 		this_dbs_info->cur_policy = NULL;
 		if (!cpu)
 			input_unregister_handler(&dbs_input_handler);
-		if (!dbs_enable)
+		if (!dbs_enable) {
 			sysfs_remove_group(cpufreq_global_kobject,
 					   &dbs_attr_group);
+			atomic_notifier_chain_unregister(
+				&migration_notifier_head,
+				&dbs_migration_nb);
+		}
+
 		mutex_unlock(&dbs_mutex);
 
 		break;
@@ -1222,9 +1325,9 @@
 			MIN_SAMPLING_RATE_RATIO * jiffies_to_usecs(10);
 	}
 
-	input_wq = create_workqueue("iewq");
-	if (!input_wq) {
-		printk(KERN_ERR "Failed to create iewq workqueue\n");
+	dbs_wq = alloc_workqueue("ondemand_dbs_wq", WQ_HIGHPRI, 0);
+	if (!dbs_wq) {
+		printk(KERN_ERR "Failed to create ondemand_dbs_wq workqueue\n");
 		return -EFAULT;
 	}
 	for_each_possible_cpu(i) {
@@ -1232,10 +1335,17 @@
 			&per_cpu(od_cpu_dbs_info, i);
 		struct dbs_work_struct *dbs_work =
 			&per_cpu(dbs_refresh_work, i);
+		struct dbs_sync_work_struct *dbs_sync =
+			&per_cpu(dbs_sync_work, i);
 
 		mutex_init(&this_dbs_info->timer_mutex);
 		INIT_WORK(&dbs_work->work, dbs_refresh_callback);
 		dbs_work->cpu = i;
+
+		INIT_WORK(&dbs_sync->work, dbs_synchronize);
+		dbs_sync->src_cpu = 0;
+		dbs_sync->targ_cpu = i;
+
 	}
 
 	return cpufreq_register_governor(&cpufreq_gov_ondemand);
@@ -1251,7 +1361,7 @@
 			&per_cpu(od_cpu_dbs_info, i);
 		mutex_destroy(&this_dbs_info->timer_mutex);
 	}
-	destroy_workqueue(input_wq);
+	destroy_workqueue(dbs_wq);
 }
 
 
diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig
index 99ace44..3422f05 100644
--- a/drivers/crypto/Kconfig
+++ b/drivers/crypto/Kconfig
@@ -306,7 +306,7 @@
 config CRYPTO_DEV_QCE
 	tristate "Qualcomm Crypto Engine (QCE) module"
 	select  CRYPTO_DEV_QCE40 if ARCH_MSM8960 || ARCH_MSM9615
-	select  CRYPTO_DEV_QCE50 if ARCH_MSM8974 || ARCH_MSM9625 || ARCH_MSM8226
+	select  CRYPTO_DEV_QCE50 if ARCH_MSM8974 || ARCH_MSM9625 || ARCH_MSM8226 || ARCH_MSM8610
 	default n
 	help
           This driver supports Qualcomm Crypto Engine in MSM7x30, MSM8660
diff --git a/drivers/crypto/msm/ota_crypto.c b/drivers/crypto/msm/ota_crypto.c
index af53543..5051a3a 100644
--- a/drivers/crypto/msm/ota_crypto.c
+++ b/drivers/crypto/msm/ota_crypto.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2011, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -42,7 +42,7 @@
 struct ota_dev_control;
 
 struct ota_async_req {
-	struct list_head list;
+	struct list_head rlist;
 	struct completion complete;
 	int err;
 	enum qce_ota_oper_enum op;
@@ -52,7 +52,7 @@
 		struct qce_f8_multi_pkt_req f8_mp_req;
 	} req;
 
-	struct ota_dev_control  *podev;
+	struct ota_qce_dev  *pqce;
 };
 
 /*
@@ -68,19 +68,29 @@
 
 	/* misc device */
 	struct miscdevice miscdevice;
+	struct list_head ready_commands;
+	unsigned magic;
+	struct list_head qce_dev;
+	spinlock_t lock;
+	struct mutex register_lock;
+	bool registered;
+	uint32_t total_units;
+};
 
+struct ota_qce_dev {
+	struct list_head qlist;
 	/* qce handle */
 	void *qce;
 
 	/* platform device */
 	struct platform_device *pdev;
 
-	unsigned magic;
-
-	struct list_head ready_commands;
 	struct ota_async_req *active_command;
-	spinlock_t lock;
 	struct tasklet_struct done_tasklet;
+	struct ota_dev_control *podev;
+	uint32_t unit;
+	u32 totalReq;
+	u32 errReq;
 };
 
 #define OTA_MAGIC 0x4f544143
@@ -89,7 +99,7 @@
 			  unsigned cmd, unsigned long arg);
 static int qcota_open(struct inode *inode, struct file *file);
 static int qcota_release(struct inode *inode, struct file *file);
-static int start_req(struct ota_dev_control *podev);
+static int start_req(struct ota_qce_dev *pqce, struct ota_async_req *areq);
 
 static const struct file_operations qcota_fops = {
 	.owner = THIS_MODULE,
@@ -98,35 +108,15 @@
 	.release = qcota_release,
 };
 
-static struct ota_dev_control qcota_dev[] = {
-	{
-		.miscdevice = {
+static struct ota_dev_control qcota_dev = {
+	.miscdevice = {
 			.minor = MISC_DYNAMIC_MINOR,
 			.name = "qcota0",
 			.fops = &qcota_fops,
-		},
-		.magic = OTA_MAGIC,
 	},
-	{
-		.miscdevice = {
-			.minor = MISC_DYNAMIC_MINOR,
-			.name = "qcota1",
-			.fops = &qcota_fops,
-		},
-		.magic = OTA_MAGIC,
-	},
-	{
-		.miscdevice = {
-			.minor = MISC_DYNAMIC_MINOR,
-			.name = "qcota2",
-			.fops = &qcota_fops,
-		},
-		.magic = OTA_MAGIC,
-	}
+	.magic = OTA_MAGIC,
 };
 
-#define MAX_OTA_DEVICE ARRAY_SIZE(qcota_dev)
-
 #define DEBUG_MAX_FNAME  16
 #define DEBUG_MAX_RW_BUF 1024
 
@@ -141,27 +131,22 @@
 	u32 f9_op_success;
 	u32 f9_op_fail;
 };
-static struct qcota_stat _qcota_stat[MAX_OTA_DEVICE];
+static struct qcota_stat _qcota_stat;
 static struct dentry *_debug_dent;
 static char _debug_read_buf[DEBUG_MAX_RW_BUF];
-static int _debug_qcota[MAX_OTA_DEVICE];
+static int _debug_qcota;
 
-static struct ota_dev_control *qcota_minor_to_control(unsigned n)
+static struct ota_dev_control *qcota_control(void)
 {
-	int i;
 
-	for (i = 0; i < MAX_OTA_DEVICE; i++) {
-		if (qcota_dev[i].miscdevice.minor == n)
-			return &qcota_dev[i];
-	}
-	return NULL;
+	return &qcota_dev;
 }
 
 static int qcota_open(struct inode *inode, struct file *file)
 {
 	struct ota_dev_control *podev;
 
-	podev = qcota_minor_to_control(MINOR(inode->i_rdev));
+	podev = qcota_control();
 	if (podev == NULL) {
 		pr_err("%s: no such device %d\n", __func__,
 				MINOR(inode->i_rdev));
@@ -191,38 +176,52 @@
 
 static void req_done(unsigned long data)
 {
-	struct ota_dev_control *podev = (struct ota_dev_control *)data;
+	struct ota_qce_dev *pqce = (struct ota_qce_dev *)data;
+	struct ota_dev_control *podev = pqce->podev;
 	struct ota_async_req *areq;
 	unsigned long flags;
 	struct ota_async_req *new_req = NULL;
 	int ret = 0;
 
+
 	spin_lock_irqsave(&podev->lock, flags);
-	areq = podev->active_command;
-	podev->active_command = NULL;
+
+	areq = pqce->active_command;
+	if (unlikely(areq == NULL))
+		pr_err("ota_crypto: req_done, no active request\n");
+	pqce->active_command = NULL;
 
 again:
 	if (!list_empty(&podev->ready_commands)) {
 		new_req = container_of(podev->ready_commands.next,
-						struct ota_async_req, list);
-		list_del(&new_req->list);
-		podev->active_command = new_req;
+						struct ota_async_req, rlist);
+		list_del(&new_req->rlist);
+		pqce->active_command = new_req;
+		spin_unlock_irqrestore(&podev->lock, flags);
+
 		new_req->err = 0;
-		ret = start_req(podev);
-	}
+		ret = start_req(pqce, new_req); /* start a new request */
 
-	spin_unlock_irqrestore(&podev->lock, flags);
+	} else {
+		spin_unlock_irqrestore(&podev->lock, flags);
+	};
 
-	if (areq)
+	if (areq) {
 		complete(&areq->complete);
-
-	if (new_req && ret) {
-		complete(&new_req->complete);
-		spin_lock_irqsave(&podev->lock, flags);
-		podev->active_command = NULL;
 		areq = NULL;
+	};
+
+	/* if error from issuing request  */
+	if (unlikely(new_req && ret)) {
+		new_req->err = ret;
+		complete(&new_req->complete);
 		ret = 0;
 		new_req = NULL;
+
+		spin_lock_irqsave(&podev->lock, flags);
+		pqce->active_command = NULL;
+
+		/* try to get next new request */
 		goto again;
 	}
 
@@ -233,64 +232,61 @@
 	int ret)
 {
 	struct ota_async_req *areq = (struct ota_async_req *) cookie;
-	struct ota_dev_control *podev;
-	struct qcota_stat *pstat;
+	struct ota_qce_dev *pqce;
 
-	podev = areq->podev;
-	pstat = &_qcota_stat[podev->pdev->id];
+	pqce = areq->pqce;
 	areq->req.f9_req.mac_i  = (uint32_t) icv;
 
-	if (ret)
+	if (ret) {
+		pqce->errReq++;
 		areq->err = -ENXIO;
-	else
+	} else
 		areq->err = 0;
 
-	tasklet_schedule(&podev->done_tasklet);
-};
+	tasklet_schedule(&pqce->done_tasklet);
+}
 
 static void f8_cb(void *cookie, unsigned char *icv, unsigned char *iv,
 	int ret)
 {
 	struct ota_async_req *areq = (struct ota_async_req *) cookie;
-	struct ota_dev_control *podev;
-	struct qcota_stat *pstat;
+	struct ota_qce_dev *pqce;
 
-	podev = areq->podev;
-	pstat = &_qcota_stat[podev->pdev->id];
+	pqce = areq->pqce;
 
-	if (ret)
+	if (ret) {
+		pqce->errReq++;
 		areq->err = -ENXIO;
-	else
+	} else {
 		areq->err = 0;
+	}
 
-	tasklet_schedule(&podev->done_tasklet);
-};
+	tasklet_schedule(&pqce->done_tasklet);
+}
 
-static int start_req(struct ota_dev_control *podev)
+static int start_req(struct ota_qce_dev *pqce, struct ota_async_req *areq)
 {
-	struct ota_async_req *areq;
 	struct qce_f9_req *pf9;
 	struct qce_f8_multi_pkt_req *p_mp_f8;
 	struct qce_f8_req *pf8;
 	int ret = 0;
 
-	/* start the command on the podev->active_command */
-	areq = podev->active_command;
-	areq->podev = podev;
+	/* command should be on the podev->active_command */
+	areq->pqce = pqce;
 
 	switch (areq->op) {
 	case QCE_OTA_F8_OPER:
 		pf8 = &areq->req.f8_req;
-		ret = qce_f8_req(podev->qce, pf8, areq, f8_cb);
+		ret = qce_f8_req(pqce->qce, pf8, areq, f8_cb);
 		break;
 	case QCE_OTA_MPKT_F8_OPER:
 		p_mp_f8 = &areq->req.f8_mp_req;
-		ret = qce_f8_multi_pkt_req(podev->qce, p_mp_f8, areq, f8_cb);
+		ret = qce_f8_multi_pkt_req(pqce->qce, p_mp_f8, areq, f8_cb);
 		break;
 
 	case QCE_OTA_F9_OPER:
 		pf9 = &areq->req.f9_req;
-		ret =  qce_f9_req(podev->qce, pf9, areq, f9_cb);
+		ret =  qce_f9_req(pqce->qce, pf9, areq, f9_cb);
 		break;
 
 	default:
@@ -298,32 +294,60 @@
 		break;
 	};
 	areq->err = ret;
+	pqce->totalReq++;
+	if (ret)
+		pqce->errReq++;
 	return ret;
-};
+}
+
+static struct ota_qce_dev *schedule_qce(struct ota_dev_control *podev)
+{
+	/* do this function with spinlock set */
+	struct ota_qce_dev *p;
+
+	if (unlikely(list_empty(&podev->qce_dev))) {
+		pr_err("%s: no valid qce to schedule\n", __func__);
+		return NULL;
+	}
+
+	list_for_each_entry(p, &podev->qce_dev, qlist) {
+		if (p->active_command == NULL)
+			return p;
+	}
+	return NULL;
+}
 
 static int submit_req(struct ota_async_req *areq, struct ota_dev_control *podev)
 {
 	unsigned long flags;
 	int ret = 0;
 	struct qcota_stat *pstat;
+	struct ota_qce_dev *pqce;
 
 	areq->err = 0;
-	spin_lock_irqsave(&podev->lock, flags);
-	if (podev->active_command == NULL) {
-		podev->active_command = areq;
-		ret = start_req(podev);
-	} else {
-		list_add_tail(&areq->list, &podev->ready_commands);
-	}
 
-	if (ret != 0)
-		podev->active_command = NULL;
-	spin_unlock_irqrestore(&podev->lock, flags);
+	spin_lock_irqsave(&podev->lock, flags);
+	pqce = schedule_qce(podev);
+	if (pqce) {
+		pqce->active_command = areq;
+		spin_unlock_irqrestore(&podev->lock, flags);
+
+		ret = start_req(pqce, areq);
+		if (ret != 0) {
+			spin_lock_irqsave(&podev->lock, flags);
+			pqce->active_command = NULL;
+			spin_unlock_irqrestore(&podev->lock, flags);
+		}
+
+	} else {
+		list_add_tail(&areq->rlist, &podev->ready_commands);
+		spin_unlock_irqrestore(&podev->lock, flags);
+	}
 
 	if (ret == 0)
 		wait_for_completion(&areq->complete);
 
-	pstat = &_qcota_stat[podev->pdev->id];
+	pstat = &_qcota_stat;
 	switch (areq->op) {
 	case QCE_OTA_F8_OPER:
 		if (areq->err)
@@ -350,7 +374,7 @@
 	};
 
 	return areq->err;
-};
+}
 
 static long qcota_ioctl(struct file *file,
 			  unsigned cmd, unsigned long arg)
@@ -377,7 +401,7 @@
 
 	init_completion(&areq.complete);
 
-	pstat = &_qcota_stat[podev->pdev->id];
+	pstat = &_qcota_stat;
 
 	switch (cmd) {
 	case QCOTA_F9_REQ:
@@ -523,67 +547,112 @@
 	int rc = 0;
 	struct ota_dev_control *podev;
 	struct ce_hw_support ce_support;
+	struct ota_qce_dev *pqce;
+	unsigned long flags;
 
-	if (pdev->id >= MAX_OTA_DEVICE) {
-		pr_err("%s: device id %d  exceeds allowed %d\n",
-			__func__, pdev->id, MAX_OTA_DEVICE);
-		return -ENOENT;
+	podev = &qcota_dev;
+	pqce = kzalloc(sizeof(*pqce), GFP_KERNEL);
+	if (!pqce) {
+		pr_err("qcota_probe: Memory allocation FAIL\n");
+		return -ENOMEM;
 	}
 
-	podev = &qcota_dev[pdev->id];
-
-	INIT_LIST_HEAD(&podev->ready_commands);
-	podev->active_command = NULL;
-	spin_lock_init(&podev->lock);
-	tasklet_init(&podev->done_tasklet, req_done, (unsigned long)podev);
+	pqce->podev = podev;
+	pqce->active_command = NULL;
+	tasklet_init(&pqce->done_tasklet, req_done, (unsigned long)pqce);
 
 	/* open qce */
 	handle = qce_open(pdev, &rc);
 	if (handle == NULL) {
-		pr_err("%s: device id %d, can not open qce\n",
-			__func__, pdev->id);
-		platform_set_drvdata(pdev, NULL);
-		return rc;
+		pr_err("%s: device %s, can not open qce\n",
+			__func__, pdev->name);
+		goto err;
 	}
 	if (qce_hw_support(handle, &ce_support) < 0 ||
 					ce_support.ota == false) {
-		pr_err("%s: device id %d, qce does not support ota capability\n",
-			__func__, pdev->id);
+		pr_err("%s: device %s, qce does not support ota capability\n",
+			__func__, pdev->name);
 		rc = -ENODEV;
 		goto err;
 	}
-	podev->qce = handle;
-	podev->pdev = pdev;
-	platform_set_drvdata(pdev, podev);
+	pqce->qce = handle;
+	pqce->pdev = pdev;
+	pqce->totalReq = 0;
+	pqce->errReq = 0;
+	platform_set_drvdata(pdev, pqce);
 
-	rc = misc_register(&podev->miscdevice);
-	if (rc < 0)
+	mutex_lock(&podev->register_lock);
+	rc = 0;
+	if (podev->registered == false) {
+		rc = misc_register(&podev->miscdevice);
+		if (rc == 0) {
+			pqce->unit = podev->total_units;
+			podev->total_units++;
+			podev->registered = true;
+		};
+	} else {
+		pqce->unit = podev->total_units;
+		podev->total_units++;
+	}
+	mutex_unlock(&podev->register_lock);
+	if (rc) {
+		pr_err("ion: failed to register misc device.\n");
 		goto err;
+	}
+
+	spin_lock_irqsave(&podev->lock, flags);
+	list_add_tail(&pqce->qlist, &podev->qce_dev);
+	spin_unlock_irqrestore(&podev->lock, flags);
 
 	return 0;
 err:
 	if (handle)
 		qce_close(handle);
+
 	platform_set_drvdata(pdev, NULL);
-	podev->qce = NULL;
-	podev->pdev = NULL;
+	tasklet_kill(&pqce->done_tasklet);
+	kfree(pqce);
 	return rc;
-};
+}
 
 static int qcota_remove(struct platform_device *pdev)
 {
 	struct ota_dev_control *podev;
+	struct ota_qce_dev *pqce;
+	unsigned long flags;
 
-	podev = platform_get_drvdata(pdev);
-	if (!podev)
+	pqce = platform_get_drvdata(pdev);
+	if (!pqce)
 		return 0;
-	if (podev->qce)
-		qce_close(podev->qce);
+	if (pqce->qce)
+		qce_close(pqce->qce);
 
-	if (podev->miscdevice.minor != MISC_DYNAMIC_MINOR)
-		misc_deregister(&podev->miscdevice);
-	tasklet_kill(&podev->done_tasklet);
+	podev = pqce->podev;
+	if (!podev)
+		goto ret;
+
+	spin_lock_irqsave(&podev->lock, flags);
+	list_del(&pqce->qlist);
+	spin_unlock_irqrestore(&podev->lock, flags);
+
+	mutex_lock(&podev->register_lock);
+	if (--podev->total_units == 0) {
+		if (podev->miscdevice.minor != MISC_DYNAMIC_MINOR)
+			misc_deregister(&podev->miscdevice);
+		podev->registered = false;
+	}
+	mutex_unlock(&podev->register_lock);
+ret:
+
+	tasklet_kill(&pqce->done_tasklet);
+	kfree(pqce);
 	return 0;
+}
+
+static struct of_device_id qcota_match[] = {
+	{	.compatible = "qcom,qcota",
+	},
+	{}
 };
 
 static struct platform_driver qcota_plat_driver = {
@@ -592,18 +661,21 @@
 	.driver = {
 		.name = "qcota",
 		.owner = THIS_MODULE,
+		.of_match_table = qcota_match,
 	},
 };
 
-static int _disp_stats(int id)
+static int _disp_stats(void)
 {
 	struct qcota_stat *pstat;
 	int len = 0;
+	struct ota_dev_control *podev = &qcota_dev;
+	unsigned long flags;
+	struct ota_qce_dev *p;
 
-	pstat = &_qcota_stat[id];
+	pstat = &_qcota_stat;
 	len = snprintf(_debug_read_buf, DEBUG_MAX_RW_BUF - 1,
-			"\nQualcomm OTA crypto accelerator %d Statistics:\n",
-				id + 1);
+			"\nQualcomm OTA crypto accelerator Statistics:\n");
 
 	len += snprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
 			"   F8 request             : %d\n",
@@ -635,6 +707,27 @@
 			"   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(
+			_debug_read_buf + len,
+			DEBUG_MAX_RW_BUF - len - 1,
+			"   Engine %d Req          : %d\n",
+			p->unit,
+			p->totalReq
+		);
+		len += snprintf(
+			_debug_read_buf + len,
+			DEBUG_MAX_RW_BUF - len - 1,
+			"   Engine %d Req Error    : %d\n",
+			p->unit,
+			p->errReq
+		);
+	}
+
+	spin_unlock_irqrestore(&podev->lock, flags);
+
 	return len;
 }
 
@@ -648,10 +741,9 @@
 			size_t count, loff_t *ppos)
 {
 	int rc = -EINVAL;
-	int qcota = *((int *) file->private_data);
 	int len;
 
-	len = _disp_stats(qcota);
+	len = _disp_stats();
 
 	rc = simple_read_from_buffer((void __user *) buf, len,
 			ppos, (void *) _debug_read_buf, len);
@@ -662,12 +754,23 @@
 static ssize_t _debug_stats_write(struct file *file, const char __user *buf,
 			size_t count, loff_t *ppos)
 {
+	struct ota_dev_control *podev = &qcota_dev;
+	unsigned long flags;
+	struct ota_qce_dev *p;
 
-	int qcota = *((int *) file->private_data);
+	memset((char *)&_qcota_stat, 0, sizeof(struct qcota_stat));
 
-	memset((char *)&_qcota_stat[qcota], 0, sizeof(struct qcota_stat));
+	spin_lock_irqsave(&podev->lock, flags);
+
+	list_for_each_entry(p, &podev->qce_dev, qlist) {
+		p->totalReq = 0;
+		p->errReq = 0;
+	}
+
+	spin_unlock_irqrestore(&podev->lock, flags);
+
 	return count;
-};
+}
 
 static const struct file_operations _debug_stats_ops = {
 	.open =         _debug_stats_open,
@@ -679,7 +782,6 @@
 {
 	int rc;
 	char name[DEBUG_MAX_FNAME];
-	int i;
 	struct dentry *dent;
 
 	_debug_dent = debugfs_create_dir("qcota", NULL);
@@ -689,17 +791,15 @@
 		return PTR_ERR(_debug_dent);
 	}
 
-	for (i = 0; i < MAX_OTA_DEVICE; i++) {
-		snprintf(name, DEBUG_MAX_FNAME-1, "stats-%d", i+1);
-		_debug_qcota[i] = i;
-		dent = debugfs_create_file(name, 0644, _debug_dent,
-				&_debug_qcota[i], &_debug_stats_ops);
-		if (dent == NULL) {
-			pr_err("qcota debugfs_create_file fail, error %ld\n",
+	snprintf(name, DEBUG_MAX_FNAME-1, "stats-0");
+	_debug_qcota = 0;
+	dent = debugfs_create_file(name, 0644, _debug_dent,
+				&_debug_qcota, &_debug_stats_ops);
+	if (dent == NULL) {
+		pr_err("qcota debugfs_create_file fail, error %ld\n",
 					PTR_ERR(dent));
-			rc = PTR_ERR(dent);
-			goto err;
-		}
+		rc = PTR_ERR(dent);
+		goto err;
 	}
 	return 0;
 err:
@@ -710,10 +810,20 @@
 static int __init qcota_init(void)
 {
 	int rc;
+	struct ota_dev_control *podev;
 
 	rc = _qcota_debug_init();
 	if (rc)
 		return rc;
+
+	podev = &qcota_dev;
+	INIT_LIST_HEAD(&podev->ready_commands);
+	INIT_LIST_HEAD(&podev->qce_dev);
+	spin_lock_init(&podev->lock);
+	mutex_init(&podev->register_lock);
+	podev->registered = false;
+	podev->total_units = 0;
+
 	return platform_driver_register(&qcota_plat_driver);
 }
 static void __exit qcota_exit(void)
@@ -725,7 +835,7 @@
 MODULE_LICENSE("GPL v2");
 MODULE_AUTHOR("Rohit Vaswani <rvaswani@codeaurora.org>");
 MODULE_DESCRIPTION("Qualcomm Ota Crypto driver");
-MODULE_VERSION("1.01");
+MODULE_VERSION("1.02");
 
 module_init(qcota_init);
 module_exit(qcota_exit);
diff --git a/drivers/crypto/msm/qce.h b/drivers/crypto/msm/qce.h
index 51a74b6..b9b7a4e 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-2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -32,6 +32,8 @@
 #define SHA256_DIGESTSIZE		32
 #define SHA1_DIGESTSIZE			20
 
+#define AES_CE_BLOCK_SIZE		16
+
 /* key size in bytes */
 #define HMAC_KEY_SIZE			(SHA1_DIGESTSIZE)    /* hmac-sha1 */
 #define SHA_HMAC_KEY_SIZE		64
@@ -114,6 +116,7 @@
 	bool aligned_only;
 	bool bam;
 	bool is_shared;
+	bool hw_key;
 };
 
 /* Sha operation parameters */
diff --git a/drivers/crypto/msm/qce50.c b/drivers/crypto/msm/qce50.c
index 2b70d3f..6d85767 100644
--- a/drivers/crypto/msm/qce50.c
+++ b/drivers/crypto/msm/qce50.c
@@ -63,6 +63,7 @@
 	int memsize;				/* Memory allocated */
 	int is_shared;				/* CE HW is shared */
 	bool support_cmd_dscr;
+	bool support_hw_key;
 
 	void __iomem *iobase;	    /* Virtual io base of CE HW  */
 	unsigned int phy_iobase;    /* Physical io base of CE HW    */
@@ -1504,6 +1505,45 @@
 }
 #endif
 
+
+static void _qce_dump_descr_fifos_fail(struct qce_device *pce_dev)
+{
+	int i, j, ents;
+	struct sps_iovec *iovec = pce_dev->ce_sps.in_transfer.iovec;
+	uint32_t cmd_flags = SPS_IOVEC_FLAG_CMD;
+
+	printk(KERN_INFO "==============================================\n");
+	printk(KERN_INFO "CONSUMER (TX/IN/DEST) PIPE DESCRIPTOR\n");
+	printk(KERN_INFO "==============================================\n");
+	for (i = 0; i <  pce_dev->ce_sps.in_transfer.iovec_count; i++) {
+		printk(KERN_INFO " [%d] addr=0x%x  size=0x%x  flags=0x%x\n", i,
+					iovec->addr, iovec->size, iovec->flags);
+		if (iovec->flags & cmd_flags) {
+			struct sps_command_element *pced;
+
+			pced = (struct sps_command_element *)
+					(GET_VIRT_ADDR(iovec->addr));
+			ents = iovec->size/(sizeof(struct sps_command_element));
+			for (j = 0; j < ents; j++) {
+				printk(KERN_INFO "      [%d] [0x%x] 0x%x\n", j,
+					pced->addr, pced->data);
+				pced++;
+			}
+		}
+		iovec++;
+	}
+
+	printk(KERN_INFO "==============================================\n");
+	printk(KERN_INFO "PRODUCER (RX/OUT/SRC) PIPE DESCRIPTOR\n");
+	printk(KERN_INFO "==============================================\n");
+	iovec = pce_dev->ce_sps.out_transfer.iovec;
+	for (i = 0; i <  pce_dev->ce_sps.out_transfer.iovec_count; i++) {
+		printk(KERN_INFO " [%d] addr=0x%x  size=0x%x  flags=0x%x\n", i,
+				iovec->addr, iovec->size, iovec->flags);
+		iovec++;
+	}
+}
+
 static void _qce_sps_iovec_count_init(struct qce_device *pce_dev)
 {
 	pce_dev->ce_sps.in_transfer.iovec_count = 0;
@@ -1602,6 +1642,7 @@
 	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;
 	}
 	rc = sps_transfer(pce_dev->ce_sps.producer.pipe,
@@ -3271,6 +3312,8 @@
 
 	pce_dev->is_shared = of_property_read_bool((&pdev->dev)->of_node,
 				"qcom,ce-hw-shared");
+	pce_dev->support_hw_key = of_property_read_bool((&pdev->dev)->of_node,
+				"qcom,ce-hw-key");
 	if (of_property_read_u32((&pdev->dev)->of_node,
 				"qcom,bam-pipe-pair",
 				&pce_dev->ce_sps.pipe_pair_index)) {
@@ -3599,6 +3642,7 @@
 	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;
 	if (pce_dev->ce_sps.minor_version)
 		ce_support->aligned_only = false;
diff --git a/drivers/crypto/msm/qcedev.c b/drivers/crypto/msm/qcedev.c
index a09bb42..d069f2e 100644
--- a/drivers/crypto/msm/qcedev.c
+++ b/drivers/crypto/msm/qcedev.c
@@ -1650,6 +1650,10 @@
 								 __func__);
 			goto error;
 		}
+		if (req->byteoffset >= AES_CE_BLOCK_SIZE) {
+			pr_err("%s: Invalid byte offset\n", __func__);
+			goto error;
+		}
 	}
 	/* Ensure zer ivlen for ECB  mode  */
 	if (req->ivlen > 0) {
@@ -1933,19 +1937,18 @@
 	rc = misc_register(&podev->miscdevice);
 	qce_hw_support(podev->qce, &podev->ce_support);
 	if (podev->ce_support.bam) {
-		podev->platform_support.ce_shared = 0;
+		podev->platform_support.ce_shared = podev->ce_support.is_shared;
 		podev->platform_support.shared_ce_resource = 0;
-		podev->platform_support.hw_key_support = 0;
+		podev->platform_support.hw_key_support =
+						podev->ce_support.hw_key;
 		podev->platform_support.bus_scale_table = NULL;
 		podev->platform_support.sha_hmac = 1;
 
-		if (podev->ce_support.is_shared == false) {
-			podev->platform_support.bus_scale_table =
-				(struct msm_bus_scale_pdata *)
-						msm_bus_cl_get_pdata(pdev);
-			if (!podev->platform_support.bus_scale_table)
-				pr_err("bus_scale_table is NULL\n");
-		}
+		podev->platform_support.bus_scale_table =
+			(struct msm_bus_scale_pdata *)
+					msm_bus_cl_get_pdata(pdev);
+		if (!podev->platform_support.bus_scale_table)
+			pr_err("bus_scale_table is NULL\n");
 	} else {
 		platform_support =
 			(struct msm_ce_hw_support *)pdev->dev.platform_data;
diff --git a/drivers/crypto/msm/qcrypto.c b/drivers/crypto/msm/qcrypto.c
index a4bb2f1..d2f511d 100644
--- a/drivers/crypto/msm/qcrypto.c
+++ b/drivers/crypto/msm/qcrypto.c
@@ -3387,19 +3387,17 @@
 	cp->pdev = pdev;
 	qce_hw_support(cp->qce, &cp->ce_support);
 	if (cp->ce_support.bam)	 {
-		cp->platform_support.ce_shared = 0;
+		cp->platform_support.ce_shared = cp->ce_support.is_shared;
 		cp->platform_support.shared_ce_resource = 0;
-		cp->platform_support.hw_key_support = 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;
 
-		if (cp->ce_support.is_shared == false) {
-			cp->platform_support.bus_scale_table =
-				(struct msm_bus_scale_pdata *)
-						msm_bus_cl_get_pdata(pdev);
-			if (!cp->platform_support.bus_scale_table)
-				pr_warn("bus_scale_table is NULL\n");
-		}
+		cp->platform_support.bus_scale_table =
+			(struct msm_bus_scale_pdata *)
+					msm_bus_cl_get_pdata(pdev);
+		if (!cp->platform_support.bus_scale_table)
+			pr_warn("bus_scale_table is NULL\n");
 	} else {
 		platform_support =
 			(struct msm_ce_hw_support *)pdev->dev.platform_data;
diff --git a/drivers/gpu/ion/ion_cma_heap.c b/drivers/gpu/ion/ion_cma_heap.c
index 193f4d4..e7f7836 100644
--- a/drivers/gpu/ion/ion_cma_heap.c
+++ b/drivers/gpu/ion/ion_cma_heap.c
@@ -115,6 +115,7 @@
 	dev_dbg(dev, "Release buffer %p\n", buffer);
 	/* release memory */
 	dma_free_coherent(dev, buffer->size, info->cpu_addr, info->handle);
+	sg_free_table(info->table);
 	/* release sg table */
 	kfree(info->table);
 	kfree(info);
diff --git a/drivers/gpu/ion/ion_cma_secure_heap.c b/drivers/gpu/ion/ion_cma_secure_heap.c
index e1b3eea..b3960b2 100644
--- a/drivers/gpu/ion/ion_cma_secure_heap.c
+++ b/drivers/gpu/ion/ion_cma_secure_heap.c
@@ -154,6 +154,7 @@
 	dev_dbg(dev, "Release buffer %p\n", buffer);
 	/* release memory */
 	dma_free_coherent(dev, buffer->size, info->cpu_addr, info->handle);
+	sg_free_table(info->table);
 	/* release sg table */
 	kfree(info->table);
 	kfree(info);
diff --git a/drivers/gpu/ion/ion_iommu_heap.c b/drivers/gpu/ion/ion_iommu_heap.c
index bc9bddd..b1c1c5d 100644
--- a/drivers/gpu/ion/ion_iommu_heap.c
+++ b/drivers/gpu/ion/ion_iommu_heap.c
@@ -42,6 +42,7 @@
  */
 struct ion_iommu_priv_data {
 	struct page **pages;
+	unsigned int pages_uses_vmalloc;
 	int nrpages;
 	unsigned long size;
 };
@@ -118,6 +119,7 @@
 		unsigned int npages_to_vmap, total_pages, num_large_pages = 0;
 		unsigned long size_remaining = PAGE_ALIGN(size);
 		unsigned int max_order = ION_IS_CACHED(flags) ? 0 : orders[0];
+		unsigned int page_tbl_size;
 
 		data = kmalloc(sizeof(*data), GFP_KERNEL);
 		if (!data)
@@ -139,8 +141,24 @@
 
 		data->size = PFN_ALIGN(size);
 		data->nrpages = data->size >> PAGE_SHIFT;
-		data->pages = kzalloc(sizeof(struct page *)*data->nrpages,
-				GFP_KERNEL);
+		data->pages_uses_vmalloc = 0;
+		page_tbl_size = sizeof(struct page *) * data->nrpages;
+
+		if (page_tbl_size > SZ_8K) {
+			/*
+			 * Do fallback to ensure we have a balance between
+			 * performance and availability.
+			 */
+			data->pages = kmalloc(page_tbl_size,
+					      __GFP_COMP | __GFP_NORETRY |
+					      __GFP_NO_KSWAPD | __GFP_NOWARN);
+			if (!data->pages) {
+				data->pages = vmalloc(page_tbl_size);
+				data->pages_uses_vmalloc = 1;
+			}
+		} else {
+			data->pages = kmalloc(page_tbl_size, GFP_KERNEL);
+		}
 		if (!data->pages) {
 			ret = -ENOMEM;
 			goto err_free_data;
@@ -222,7 +240,10 @@
 	kfree(buffer->sg_table);
 	buffer->sg_table = 0;
 err1:
-	kfree(data->pages);
+	if (data->pages_uses_vmalloc)
+		vfree(data->pages);
+	else
+		kfree(data->pages);
 err_free_data:
 	kfree(data);
 
@@ -253,7 +274,10 @@
 	sg_free_table(table);
 	kfree(table);
 	table = 0;
-	kfree(data->pages);
+	if (data->pages_uses_vmalloc)
+		vfree(data->pages);
+	else
+		kfree(data->pages);
 	kfree(data);
 }
 
diff --git a/drivers/gpu/msm/Makefile b/drivers/gpu/msm/Makefile
index 3441afa..fc66328 100644
--- a/drivers/gpu/msm/Makefile
+++ b/drivers/gpu/msm/Makefile
@@ -25,6 +25,7 @@
 	adreno_drawctxt.o \
 	adreno_postmortem.o \
 	adreno_snapshot.o \
+	adreno_coresight.o \
 	adreno_a2xx.o \
 	adreno_a2xx_trace.o \
 	adreno_a2xx_snapshot.o \
diff --git a/drivers/gpu/msm/a3xx_reg.h b/drivers/gpu/msm/a3xx_reg.h
index 5f435f3..0c398c4 100644
--- a/drivers/gpu/msm/a3xx_reg.h
+++ b/drivers/gpu/msm/a3xx_reg.h
@@ -165,8 +165,16 @@
 #define A3XX_RBBM_PERFCTR_PWR_0_HI 0x0EB
 #define A3XX_RBBM_PERFCTR_PWR_1_LO 0x0EC
 #define A3XX_RBBM_PERFCTR_PWR_1_HI 0x0ED
-#define A3XX_RBBM_DEBUG_BUS_CTL             0x111
-#define A3XX_RBBM_DEBUG_BUS_DATA_STATUS     0x112
+#define A3XX_RBBM_DEBUG_BUS_CTL 0x111
+#define A3XX_RBBM_DEBUG_BUS_DATA_STATUS 0x112
+#define A3XX_RBBM_DEBUG_BUS_STB_CTL0 0x11B
+#define A3XX_RBBM_DEBUG_BUS_STB_CTL1 0x11C
+#define A3XX_RBBM_INT_TRACE_BUS_CTL 0x11D
+#define A3XX_RBBM_EXT_TRACE_BUS_CTL 0x11E
+#define A3XX_RBBM_EXT_TRACE_STOP_CNT 0x11F
+#define A3XX_RBBM_EXT_TRACE_START_CNT 0x120
+#define A3XX_RBBM_EXT_TRACE_PERIOD_CNT 0x121
+#define A3XX_RBBM_EXT_TRACE_CMD 0x122
 
 /* Following two are same as on A2XX, just in a different place */
 #define A3XX_CP_PFP_UCODE_ADDR 0x1C9
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index a4f60f9..d0e3e34 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -18,6 +18,7 @@
 #include <linux/of.h>
 #include <linux/of_device.h>
 #include <linux/delay.h>
+#include <linux/of_coresight.h>
 
 #include <mach/socinfo.h>
 #include <mach/msm_bus_board.h>
@@ -1522,6 +1523,9 @@
 	if (ret)
 		goto err;
 
+	pdata->coresight_pdata = of_get_coresight_platform_data(&pdev->dev,
+			pdev->dev.of_node);
+
 	pdev->dev.platform_data = pdata;
 	return 0;
 
@@ -1595,6 +1599,7 @@
 adreno_probe(struct platform_device *pdev)
 {
 	struct kgsl_device *device;
+	struct kgsl_device_platform_data *pdata = NULL;
 	struct adreno_device *adreno_dev;
 	int status = -EINVAL;
 	bool is_dt;
@@ -1625,6 +1630,10 @@
 	kgsl_pwrscale_attach_policy(device, ADRENO_DEFAULT_PWRSCALE_POLICY);
 
 	device->flags &= ~KGSL_FLAGS_SOFT_RESET;
+	pdata = kgsl_device_get_drvdata(device);
+
+	adreno_coresight_init(pdev);
+
 	return 0;
 
 error_close_rb:
@@ -1643,6 +1652,8 @@
 	device = (struct kgsl_device *)pdev->id_entry->driver_data;
 	adreno_dev = ADRENO_DEVICE(device);
 
+	adreno_coresight_remove(pdev);
+
 	kgsl_pwrscale_detach_policy(device);
 	kgsl_pwrscale_close(device);
 
@@ -2570,6 +2581,7 @@
 		INIT_COMPLETION(device->ft_gate);
 		/* Detected a hang */
 
+		kgsl_cffdump_hang(device->id);
 		/* Run fault tolerance at max power level */
 		curr_pwrlevel = pwr->active_pwrlevel;
 		kgsl_pwrctrl_pwrlevel_change(device, pwr->max_pwrlevel);
diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h
index fa892b9..77b654b 100644
--- a/drivers/gpu/msm/adreno.h
+++ b/drivers/gpu/msm/adreno.h
@@ -80,6 +80,15 @@
 	ADRENO_REV_A305B = 335,
 };
 
+enum coresight_debug_reg {
+	DEBUG_BUS_CTL,
+	TRACE_STOP_CNT,
+	TRACE_START_CNT,
+	TRACE_PERIOD_CNT,
+	TRACE_CMD,
+	TRACE_BUS_CTL,
+};
+
 struct adreno_gpudev;
 
 struct adreno_device {
@@ -187,6 +196,10 @@
 	uint64_t (*perfcounter_read)(struct adreno_device *adreno_dev,
 		unsigned int group, unsigned int counter,
 		unsigned int offset);
+	int (*coresight_enable) (struct kgsl_device *device);
+	void (*coresight_disable) (struct kgsl_device *device);
+	void (*coresight_config_debug_reg) (struct kgsl_device *device,
+			int debug_reg, unsigned int val);
 };
 
 /*
@@ -269,6 +282,10 @@
 extern unsigned int ft_detect_regs[];
 extern const unsigned int ft_detect_regs_count;
 
+int adreno_coresight_enable(struct coresight_device *csdev);
+void adreno_coresight_disable(struct coresight_device *csdev);
+void adreno_coresight_remove(struct platform_device *pdev);
+int adreno_coresight_init(struct platform_device *pdev);
 
 int adreno_idle(struct kgsl_device *device);
 void adreno_regread(struct kgsl_device *device, unsigned int offsetwords,
diff --git a/drivers/gpu/msm/adreno_a3xx.c b/drivers/gpu/msm/adreno_a3xx.c
index a4b3121..1cdc87a 100644
--- a/drivers/gpu/msm/adreno_a3xx.c
+++ b/drivers/gpu/msm/adreno_a3xx.c
@@ -3235,6 +3235,108 @@
 	adreno_dev->gpu_cycles = 0;
 }
 
+/**
+ * a3xx_coresight_enable() - Enables debugging through coresight
+ * debug bus for adreno a3xx devices.
+ * @device: Pointer to GPU device structure
+ */
+int a3xx_coresight_enable(struct kgsl_device *device)
+{
+	mutex_lock(&device->mutex);
+	if (!kgsl_active_count_get(device)) {
+		adreno_regwrite(device, A3XX_RBBM_DEBUG_BUS_CTL, 0x0001093F);
+		adreno_regwrite(device, A3XX_RBBM_DEBUG_BUS_STB_CTL0,
+				0x00000000);
+		adreno_regwrite(device, A3XX_RBBM_DEBUG_BUS_STB_CTL1,
+				0xFFFFFFFE);
+		adreno_regwrite(device, A3XX_RBBM_INT_TRACE_BUS_CTL,
+				0x00201111);
+		adreno_regwrite(device, A3XX_RBBM_EXT_TRACE_BUS_CTL,
+				0x89100010);
+		adreno_regwrite(device, A3XX_RBBM_EXT_TRACE_STOP_CNT,
+				0x00017fff);
+		adreno_regwrite(device, A3XX_RBBM_EXT_TRACE_START_CNT,
+				0x0001000f);
+		adreno_regwrite(device, A3XX_RBBM_EXT_TRACE_PERIOD_CNT ,
+				0x0001ffff);
+		adreno_regwrite(device, A3XX_RBBM_EXT_TRACE_CMD,
+				0x00000001);
+		kgsl_active_count_put(device);
+	}
+	mutex_unlock(&device->mutex);
+	return 0;
+}
+
+/**
+ * a3xx_coresight_disable() - Disables debugging through coresight
+ * debug bus for adreno a3xx devices.
+ * @device: Pointer to GPU device structure
+ */
+void a3xx_coresight_disable(struct kgsl_device *device)
+{
+	mutex_lock(&device->mutex);
+	if (!kgsl_active_count_get(device)) {
+		adreno_regwrite(device, A3XX_RBBM_DEBUG_BUS_CTL, 0x0);
+		adreno_regwrite(device, A3XX_RBBM_DEBUG_BUS_STB_CTL0, 0x0);
+		adreno_regwrite(device, A3XX_RBBM_DEBUG_BUS_STB_CTL1, 0x0);
+		adreno_regwrite(device, A3XX_RBBM_INT_TRACE_BUS_CTL, 0x0);
+		adreno_regwrite(device, A3XX_RBBM_EXT_TRACE_BUS_CTL, 0x0);
+		adreno_regwrite(device, A3XX_RBBM_EXT_TRACE_STOP_CNT, 0x0);
+		adreno_regwrite(device, A3XX_RBBM_EXT_TRACE_START_CNT, 0x0);
+		adreno_regwrite(device, A3XX_RBBM_EXT_TRACE_PERIOD_CNT , 0x0);
+		adreno_regwrite(device, A3XX_RBBM_EXT_TRACE_CMD, 0x0);
+		kgsl_active_count_put(device);
+	}
+	mutex_unlock(&device->mutex);
+}
+
+static void a3xx_coresight_write_reg(struct kgsl_device *device,
+		unsigned int wordoffset, unsigned int val)
+{
+	mutex_lock(&device->mutex);
+	if (!kgsl_active_count_get(device)) {
+		adreno_regwrite(device, wordoffset, val);
+		kgsl_active_count_put(device);
+	}
+	mutex_unlock(&device->mutex);
+}
+
+void a3xx_coresight_config_debug_reg(struct kgsl_device *device,
+		int debug_reg, unsigned int val)
+{
+	switch (debug_reg) {
+
+	case DEBUG_BUS_CTL:
+		a3xx_coresight_write_reg(device, A3XX_RBBM_DEBUG_BUS_CTL, val);
+		break;
+
+	case TRACE_STOP_CNT:
+		a3xx_coresight_write_reg(device, A3XX_RBBM_EXT_TRACE_STOP_CNT,
+				val);
+		break;
+
+	case TRACE_START_CNT:
+		a3xx_coresight_write_reg(device, A3XX_RBBM_EXT_TRACE_START_CNT,
+				val);
+		break;
+
+	case TRACE_PERIOD_CNT:
+		a3xx_coresight_write_reg(device, A3XX_RBBM_EXT_TRACE_PERIOD_CNT,
+				val);
+		break;
+
+	case TRACE_CMD:
+		a3xx_coresight_write_reg(device, A3XX_RBBM_EXT_TRACE_CMD, val);
+		break;
+
+	case TRACE_BUS_CTL:
+		a3xx_coresight_write_reg(device, A3XX_RBBM_EXT_TRACE_BUS_CTL,
+				val);
+		break;
+	}
+
+}
+
 /*
  * Define the available perfcounter groups - these get used by
  * adreno_perfcounter_get and adreno_perfcounter_put
@@ -3381,4 +3483,7 @@
 	.snapshot = a3xx_snapshot,
 	.perfcounter_enable = a3xx_perfcounter_enable,
 	.perfcounter_read = a3xx_perfcounter_read,
+	.coresight_enable = a3xx_coresight_enable,
+	.coresight_disable = a3xx_coresight_disable,
+	.coresight_config_debug_reg = a3xx_coresight_config_debug_reg,
 };
diff --git a/drivers/gpu/msm/adreno_coresight.c b/drivers/gpu/msm/adreno_coresight.c
new file mode 100644
index 0000000..e18568d
--- /dev/null
+++ b/drivers/gpu/msm/adreno_coresight.c
@@ -0,0 +1,219 @@
+/* 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/clk.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/uaccess.h>
+#include <linux/miscdevice.h>
+#include <linux/of_coresight.h>
+#include <linux/coresight.h>
+#include <linux/memory_alloc.h>
+#include <linux/io.h>
+#include <linux/of.h>
+
+#include "kgsl.h"
+#include "kgsl_device.h"
+#include "adreno.h"
+
+struct coresight_attr {
+	struct device_attribute attr;
+	int regname;
+};
+
+#define CORESIGHT_CREATE_REG_ATTR(_attrname, _regname) \
+	struct coresight_attr coresight_attr_##_attrname = \
+	{ __ATTR(_attrname, S_IRUGO | S_IWUSR, gfx_show_reg, gfx_store_reg),\
+		_regname}
+
+/**
+ * adreno_coresight_enable() - Generic function to enable coresight debugging
+ * @csdev: Pointer to coresight's device struct
+ *
+ * This is a generic function to enable coresight debug bus on adreno
+ * devices. This should be used in all cases of enabling
+ * coresight debug bus for adreno devices. This function in turn calls
+ * the adreno device specific function through gpudev hook.
+ * This function is registered as the coresight enable function
+ * with coresight driver. It should only be called through coresight driver
+ * as that would ensure that the necessary setup required to be done
+ * on coresight driver's part is also done.
+ */
+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);
+
+	/* Check if coresight compatible device, return error otherwise */
+	if (adreno_dev->gpudev->coresight_enable)
+		return adreno_dev->gpudev->coresight_enable(device);
+	else
+		return -ENODEV;
+}
+
+/**
+ * adreno_coresight_disable() - Generic function to disable coresight debugging
+ * @csdev: Pointer to coresight's device struct
+ *
+ * This is a generic function to disable coresight debug bus on adreno
+ * devices. This should be used in all cases of disabling
+ * coresight debug bus for adreno devices. This function in turn calls
+ * the adreno device specific function through the gpudev hook.
+ * This function is registered as the coresight disable function
+ * with coresight driver. It should only be called through coresight driver
+ * as that would ensure that the necessary setup required to be done on
+ * coresight driver's part is also done.
+ */
+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);
+
+	/* Check if coresight compatible device, bail otherwise */
+	if (adreno_dev->gpudev->coresight_disable)
+		return adreno_dev->gpudev->coresight_disable(device);
+}
+
+static const struct coresight_ops_source adreno_coresight_ops_source = {
+	.enable = adreno_coresight_enable,
+	.disable = adreno_coresight_disable,
+};
+
+static const struct coresight_ops adreno_coresight_cs_ops = {
+	.source_ops = &adreno_coresight_ops_source,
+};
+
+void adreno_coresight_remove(struct platform_device *pdev)
+{
+	struct kgsl_device_platform_data *pdata = pdev->dev.platform_data;
+	coresight_unregister(pdata->csdev);
+}
+
+static ssize_t coresight_read_reg(struct kgsl_device *device,
+		unsigned int offset, char *buf)
+{
+	unsigned int regval = 0;
+
+	mutex_lock(&device->mutex);
+	if (!kgsl_active_count_get(device)) {
+		adreno_regread(device, offset, &regval);
+		kgsl_active_count_put(device);
+	}
+	mutex_unlock(&device->mutex);
+	return snprintf(buf, PAGE_SIZE, "0x%X", regval);
+}
+
+static inline unsigned int coresight_convert_reg(const char *buf)
+{
+	long regval = 0;
+	int rv = 0;
+
+	rv = kstrtoul(buf, 16, &regval);
+	if (!rv)
+		return (unsigned int)regval;
+	else
+		return rv;
+}
+
+static ssize_t gfx_show_reg(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct kgsl_device *device = dev_get_drvdata(dev->parent);
+	struct coresight_attr *csight_attr = container_of(attr,
+			struct coresight_attr, attr);
+	return coresight_read_reg(device, csight_attr->regname, buf);
+}
+
+static ssize_t gfx_store_reg(struct device *dev,
+		struct device_attribute *attr,
+		const char *buf, size_t size)
+{
+	struct kgsl_device *device = dev_get_drvdata(dev->parent);
+	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+	struct coresight_attr *csight_attr = container_of(attr,
+			struct coresight_attr, attr);
+	unsigned int regval = 0;
+
+	regval = coresight_convert_reg(buf);
+
+	if (adreno_dev->gpudev->coresight_config_debug_reg)
+		adreno_dev->gpudev->coresight_config_debug_reg(device,
+				csight_attr->regname, regval);
+	return size;
+}
+
+CORESIGHT_CREATE_REG_ATTR(config_debug_bus, DEBUG_BUS_CTL);
+CORESIGHT_CREATE_REG_ATTR(config_trace_stop_cnt, TRACE_STOP_CNT);
+CORESIGHT_CREATE_REG_ATTR(config_trace_start_cnt, TRACE_START_CNT);
+CORESIGHT_CREATE_REG_ATTR(config_trace_period_cnt, TRACE_PERIOD_CNT);
+CORESIGHT_CREATE_REG_ATTR(config_trace_cmd, TRACE_CMD);
+CORESIGHT_CREATE_REG_ATTR(config_trace_bus_ctl, TRACE_BUS_CTL);
+
+static struct attribute *gfx_attrs[] = {
+	&coresight_attr_config_debug_bus.attr.attr,
+	&coresight_attr_config_trace_start_cnt.attr.attr,
+	&coresight_attr_config_trace_stop_cnt.attr.attr,
+	&coresight_attr_config_trace_period_cnt.attr.attr,
+	&coresight_attr_config_trace_cmd.attr.attr,
+	&coresight_attr_config_trace_bus_ctl.attr.attr,
+	NULL,
+};
+
+static struct attribute_group gfx_attr_grp = {
+	.attrs = gfx_attrs,
+};
+
+static const struct attribute_group *gfx_attr_grps[] = {
+	&gfx_attr_grp,
+	NULL,
+};
+
+int adreno_coresight_init(struct platform_device *pdev)
+{
+	int ret = 0;
+	struct kgsl_device_platform_data *pdata = pdev->dev.platform_data;
+	struct device *dev = &pdev->dev;
+	struct coresight_desc *desc;
+
+	if (IS_ERR_OR_NULL(pdata->coresight_pdata))
+		return -ENODATA;
+
+
+	desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL);
+	if (!desc)
+		return -ENOMEM;
+
+
+	desc->type = CORESIGHT_DEV_TYPE_SOURCE;
+	desc->subtype.source_subtype = CORESIGHT_DEV_SUBTYPE_SOURCE_BUS;
+	desc->ops = &adreno_coresight_cs_ops;
+	desc->pdata = pdata->coresight_pdata;
+	desc->dev = &pdev->dev;
+	desc->owner = THIS_MODULE;
+	desc->groups = gfx_attr_grps;
+	pdata->csdev = coresight_register(desc);
+	if (IS_ERR(pdata->csdev)) {
+		ret = PTR_ERR(pdata->csdev);
+		goto err;
+	}
+
+	return 0;
+
+err:
+	devm_kfree(dev, desc);
+	return ret;
+}
+
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index 992f88d..9b67c61 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -18,17 +18,18 @@
 #include <linux/uaccess.h>
 #include <linux/interrupt.h>
 #include <linux/workqueue.h>
-
+#include <linux/dma-buf.h>
 #include <linux/vmalloc.h>
 #include <linux/pm_runtime.h>
 #include <linux/genlock.h>
 #include <linux/rbtree.h>
 #include <linux/ashmem.h>
 #include <linux/major.h>
-#include <linux/msm_ion.h>
 #include <linux/io.h>
 #include <mach/socinfo.h>
 #include <linux/mman.h>
+#include <linux/sort.h>
+#include <asm/cacheflush.h>
 
 #include "kgsl.h"
 #include "kgsl_debugfs.h"
@@ -51,7 +52,11 @@
 MODULE_PARM_DESC(ksgl_mmu_type,
 "Type of MMU to be used for graphics. Valid values are 'iommu' or 'gpummu' or 'nommu'");
 
-static struct ion_client *kgsl_ion_client;
+struct kgsl_dma_buf_meta {
+	struct dma_buf_attachment *attach;
+	struct dma_buf *dmabuf;
+	struct sg_table *table;
+};
 
 /**
  * kgsl_trace_issueibcmds() - Call trace_issueibcmds by proxy
@@ -186,6 +191,14 @@
 	return entry;
 }
 
+static void kgsl_destroy_ion(struct kgsl_dma_buf_meta *meta)
+{
+	dma_buf_unmap_attachment(meta->attach, meta->table, DMA_FROM_DEVICE);
+	dma_buf_detach(meta->dmabuf, meta->attach);
+	dma_buf_put(meta->dmabuf);
+	kfree(meta);
+}
+
 void
 kgsl_mem_entry_destroy(struct kref *kref)
 {
@@ -215,7 +228,7 @@
 			fput(entry->priv_data);
 		break;
 	case KGSL_MEM_ENTRY_ION:
-		ion_free(kgsl_ion_client, entry->priv_data);
+		kgsl_destroy_ion(entry->priv_data);
 		break;
 	}
 
@@ -674,7 +687,7 @@
 	list_del(&private->list);
 	mutex_unlock(&kgsl_driver.process_mutex);
 
-	if (private->kobj.parent)
+	if (private->kobj.ktype)
 		kgsl_process_uninit_sysfs(private);
 	if (private->debug_root)
 		debugfs_remove_recursive(private->debug_root);
@@ -791,7 +804,7 @@
 		}
 	}
 
-	if (!private->kobj.parent)
+	if (!private->kobj.ktype)
 		kgsl_process_init_sysfs(private);
 	if (!private->debug_root)
 		kgsl_process_init_debugfs(private);
@@ -1842,38 +1855,55 @@
 #endif
 
 static int kgsl_setup_ion(struct kgsl_mem_entry *entry,
-		struct kgsl_pagetable *pagetable, void *data)
+		struct kgsl_pagetable *pagetable, void *data,
+		struct kgsl_device *device)
 {
-	struct ion_handle *handle;
 	struct scatterlist *s;
 	struct sg_table *sg_table;
 	struct kgsl_map_user_mem *param = data;
 	int fd = param->fd;
+	struct dma_buf *dmabuf;
+	struct dma_buf_attachment *attach;
+	struct kgsl_dma_buf_meta *meta;
+	int ret;
 
 	if (!param->len)
 		return -EINVAL;
 
-	if (IS_ERR_OR_NULL(kgsl_ion_client))
-		return -ENODEV;
+	meta = kzalloc(sizeof(*meta), GFP_KERNEL);
+	if (!meta)
+		return -ENOMEM;
 
-	handle = ion_import_dma_buf(kgsl_ion_client, fd);
-	if (IS_ERR(handle))
-		return PTR_ERR(handle);
-	else if (!handle)
-		return -EINVAL;
+	dmabuf = dma_buf_get(fd);
+	if (IS_ERR_OR_NULL(dmabuf)) {
+		ret = PTR_ERR(dmabuf);
+		goto err1;
+	}
+
+	attach = dma_buf_attach(dmabuf, device->dev);
+	if (IS_ERR_OR_NULL(attach)) {
+		ret = PTR_ERR(attach);
+		goto err2;
+	}
+
+	meta->dmabuf = dmabuf;
+	meta->attach = attach;
 
 	entry->memtype = KGSL_MEM_ENTRY_ION;
-	entry->priv_data = handle;
+	entry->priv_data = meta;
 	entry->memdesc.pagetable = pagetable;
 	entry->memdesc.size = 0;
 	/* USE_CPU_MAP is not impemented for ION. */
 	entry->memdesc.flags &= ~KGSL_MEMFLAGS_USE_CPU_MAP;
 
-	sg_table = ion_sg_table(kgsl_ion_client, handle);
+	sg_table = dma_buf_map_attachment(attach, DMA_TO_DEVICE);
 
-	if (IS_ERR_OR_NULL(sg_table))
-		goto err;
+	if (IS_ERR_OR_NULL(sg_table)) {
+		ret = PTR_ERR(sg_table);
+		goto err3;
+	}
 
+	meta->table = sg_table;
 	entry->memdesc.sg = sg_table->sgl;
 
 	/* Calculate the size of the memdesc from the sglist */
@@ -1888,9 +1918,13 @@
 	entry->memdesc.size = PAGE_ALIGN(entry->memdesc.size);
 
 	return 0;
-err:
-	ion_free(kgsl_ion_client, handle);
-	return -ENOMEM;
+err3:
+	dma_buf_detach(dmabuf, attach);
+err2:
+	dma_buf_put(dmabuf);
+err1:
+	kfree(meta);
+	return ret;
 }
 
 static long kgsl_ioctl_map_user_mem(struct kgsl_device_private *dev_priv,
@@ -1978,7 +2012,8 @@
 		entry->memtype = KGSL_MEM_ENTRY_ASHMEM;
 		break;
 	case KGSL_USER_MEM_TYPE_ION:
-		result = kgsl_setup_ion(entry, private->pagetable, data);
+		result = kgsl_setup_ion(entry, private->pagetable, data,
+					dev_priv->device);
 		break;
 	default:
 		KGSL_CORE_ERR("Invalid memory type: %x\n", memtype);
@@ -2025,7 +2060,7 @@
 			fput(entry->priv_data);
 		break;
 	case KGSL_MEM_ENTRY_ION:
-		ion_free(kgsl_ion_client, entry->priv_data);
+		kgsl_destroy_ion(entry->priv_data);
 		break;
 	default:
 		break;
@@ -2104,6 +2139,97 @@
 	return ret;
 }
 
+static int mem_id_cmp(const void *_a, const void *_b)
+{
+	const unsigned int *a = _a, *b = _b;
+	int cmp = a - b;
+	return (cmp < 0) ? -1 : (cmp > 0);
+}
+
+static long
+kgsl_ioctl_gpumem_sync_cache_bulk(struct kgsl_device_private *dev_priv,
+	unsigned int cmd, void *data)
+{
+	int i;
+	struct kgsl_gpumem_sync_cache_bulk *param = data;
+	struct kgsl_process_private *private = dev_priv->process_priv;
+	unsigned int id, last_id = 0, *id_list = NULL, actual_count = 0;
+	struct kgsl_mem_entry **entries = NULL;
+	long ret = 0;
+	size_t op_size = 0;
+	bool full_flush = false;
+
+	if (param->id_list == NULL || param->count == 0
+			|| param->count > (UINT_MAX/sizeof(unsigned int)))
+		return -EINVAL;
+
+	id_list = kzalloc(param->count * sizeof(unsigned int), GFP_KERNEL);
+	if (id_list == NULL)
+		return -ENOMEM;
+
+	entries = kzalloc(param->count * sizeof(*entries), GFP_KERNEL);
+	if (entries == NULL) {
+		ret = -ENOMEM;
+		goto end;
+	}
+
+	if (copy_from_user(id_list, param->id_list,
+				param->count * sizeof(unsigned int))) {
+		ret = -EFAULT;
+		goto end;
+	}
+	/* sort the ids so we can weed out duplicates */
+	sort(id_list, param->count, sizeof(int), mem_id_cmp, NULL);
+
+	for (i = 0; i < param->count; i++) {
+		unsigned int cachemode;
+		struct kgsl_mem_entry *entry = NULL;
+
+		id = id_list[i];
+		/* skip 0 ids or duplicates */
+		if (id == last_id)
+			continue;
+
+		entry = kgsl_sharedmem_find_id(private, id);
+		if (entry == NULL)
+			continue;
+
+		/* skip uncached memory */
+		cachemode = kgsl_memdesc_get_cachemode(&entry->memdesc);
+		if (cachemode != KGSL_CACHEMODE_WRITETHROUGH &&
+		    cachemode != KGSL_CACHEMODE_WRITEBACK) {
+			kgsl_mem_entry_put(entry);
+			continue;
+		}
+
+		op_size += entry->memdesc.size;
+		entries[actual_count++] = entry;
+
+		/* If we exceed the breakeven point, flush the entire cache */
+		if (op_size >= kgsl_driver.full_cache_threshold &&
+		    param->op == KGSL_GPUMEM_CACHE_FLUSH) {
+			full_flush = true;
+			break;
+		}
+		last_id = id;
+	}
+	if (full_flush) {
+		trace_kgsl_mem_sync_full_cache(actual_count, op_size,
+					       param->op);
+		__cpuc_flush_kern_all();
+	}
+
+	for (i = 0; i < actual_count; i++) {
+		if (!full_flush)
+			_kgsl_gpumem_sync_cache(entries[i], param->op);
+		kgsl_mem_entry_put(entries[i]);
+	}
+end:
+	kfree(entries);
+	kfree(id_list);
+	return ret;
+}
+
 /* Legacy cache function, does a flush (clean  + invalidate) */
 
 static long
@@ -2510,6 +2636,8 @@
 			kgsl_ioctl_gpumem_get_info, 0),
 	KGSL_IOCTL_FUNC(IOCTL_KGSL_GPUMEM_SYNC_CACHE,
 			kgsl_ioctl_gpumem_sync_cache, 0),
+	KGSL_IOCTL_FUNC(IOCTL_KGSL_GPUMEM_SYNC_CACHE_BULK,
+			kgsl_ioctl_gpumem_sync_cache_bulk, 0),
 };
 
 static long kgsl_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
@@ -2809,16 +2937,17 @@
 			ret = ALIGN(ret, (1 << align));
 
 		/*make sure there isn't a GPU only mapping at this address */
-		if (kgsl_sharedmem_region_empty(private, ret, len))
+		if (kgsl_sharedmem_region_empty(private, ret, orig_len))
 			break;
 
-		trace_kgsl_mem_unmapped_area_collision(entry, addr, len, ret);
+		trace_kgsl_mem_unmapped_area_collision(entry, addr, orig_len,
+							ret);
 
 		/*
 		 * If we collided, bump the hint address so that
 		 * get_umapped_area knows to look somewhere else.
 		 */
-		addr = (addr == 0) ? ret + len : addr + len;
+		addr = (addr == 0) ? ret + orig_len : addr + orig_len;
 
 		/*
 		 * The addr hint can be set by userspace to be near
@@ -2952,6 +3081,11 @@
 	.devlock = __MUTEX_INITIALIZER(kgsl_driver.devlock),
 	.memfree_hist_mutex =
 		__MUTEX_INITIALIZER(kgsl_driver.memfree_hist_mutex),
+	/*
+	 * Full cache flushes are faster than line by line on at least
+	 * 8064 and 8974 once the region to be flushed is > 16mb.
+	 */
+	.full_cache_threshold = SZ_16M,
 };
 EXPORT_SYMBOL(kgsl_driver);
 
@@ -3032,8 +3166,6 @@
 	if (status)
 		goto error;
 
-	kgsl_ion_client = msm_ion_client_create(UINT_MAX, KGSL_NAME);
-
 	/* Get starting physical address of device registers */
 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
 					   device->iomemname);
diff --git a/drivers/gpu/msm/kgsl.h b/drivers/gpu/msm/kgsl.h
index c7cbaf8..de3f619 100644
--- a/drivers/gpu/msm/kgsl.h
+++ b/drivers/gpu/msm/kgsl.h
@@ -134,6 +134,7 @@
 		unsigned int mapped_max;
 		unsigned int histogram[16];
 	} stats;
+	unsigned int full_cache_threshold;
 };
 
 extern struct kgsl_driver kgsl_driver;
diff --git a/drivers/gpu/msm/kgsl_iommu.c b/drivers/gpu/msm/kgsl_iommu.c
index 513fb90..4fb2f87 100644
--- a/drivers/gpu/msm/kgsl_iommu.c
+++ b/drivers/gpu/msm/kgsl_iommu.c
@@ -242,7 +242,7 @@
 
 	list_for_each_entry(private, &kgsl_driver.process_list, list) {
 
-		if (private->pagetable->name != id)
+		if (private->pagetable && (private->pagetable->name != id))
 			continue;
 
 		spin_lock(&private->mem_lock);
@@ -920,15 +920,15 @@
 
 	iommu_access_ops = get_iommu_access_ops_v0();
 
-	if (iommu_access_ops && iommu_access_ops->iommu_lock_initialize)
-		lock_phy_addr = (iommu_access_ops->iommu_lock_initialize()
-			- MSM_SHARED_RAM_BASE + msm_shared_ram_phys);
-
-	if (!lock_phy_addr) {
-		iommu_access_ops = NULL;
-		KGSL_DRV_ERR(mmu->device,
-				"GPU CPU sync lock is not supported by kernel\n");
-		return -ENXIO;
+	if (iommu_access_ops && iommu_access_ops->iommu_lock_initialize) {
+		lock_phy_addr = (uint32_t)
+				iommu_access_ops->iommu_lock_initialize();
+		if (!lock_phy_addr) {
+			iommu_access_ops = NULL;
+			return status;
+		}
+		lock_phy_addr = lock_phy_addr - (uint32_t)MSM_SHARED_RAM_BASE +
+				(uint32_t)msm_shared_ram_phys;
 	}
 
 	/* Align the physical address to PAGE boundary and store the offset */
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c
index 52340cc..5b386b3 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.c
+++ b/drivers/gpu/msm/kgsl_pwrctrl.c
@@ -76,6 +76,10 @@
 	},
 };
 
+static void kgsl_pwrctrl_clk(struct kgsl_device *device, int state,
+					  int requested_state);
+static void kgsl_pwrctrl_axi(struct kgsl_device *device, int state);
+
 /* Update the elapsed time at a particular clock level
  * if the device is active(on_time = true).Otherwise
  * store it as sleep time.
@@ -671,6 +675,87 @@
 	return snprintf(buf, PAGE_SIZE, "%d\n", device->reset_counter);
 }
 
+static void __force_on(struct kgsl_device *device, int flag, int on)
+{
+	if (on) {
+		switch (flag) {
+		case KGSL_PWRFLAGS_CLK_ON:
+			kgsl_pwrctrl_clk(device, KGSL_PWRFLAGS_ON,
+				KGSL_STATE_ACTIVE);
+			break;
+		case KGSL_PWRFLAGS_AXI_ON:
+			kgsl_pwrctrl_axi(device, KGSL_PWRFLAGS_ON);
+			break;
+		}
+		set_bit(flag, &device->pwrctrl.ctrl_flags);
+	} else {
+		clear_bit(flag, &device->pwrctrl.ctrl_flags);
+	}
+}
+
+static int __force_on_show(struct device *dev,
+					struct device_attribute *attr,
+					char *buf, int flag)
+{
+	struct kgsl_device *device = kgsl_device_from_dev(dev);
+	int i = test_bit(flag, &device->pwrctrl.ctrl_flags);
+	return snprintf(buf, PAGE_SIZE, "%d\n", i);
+}
+
+static int __force_on_store(struct device *dev,
+					struct device_attribute *attr,
+					const char *buf, size_t count,
+					int flag)
+{
+	char temp[20];
+	unsigned long val;
+	struct kgsl_device *device = kgsl_device_from_dev(dev);
+	int rc;
+
+	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;
+
+	mutex_lock(&device->mutex);
+	__force_on(device, flag, val);
+	mutex_unlock(&device->mutex);
+
+	return count;
+}
+
+static int kgsl_pwrctrl_force_clk_on_show(struct device *dev,
+					struct device_attribute *attr,
+					char *buf)
+{
+	return __force_on_show(dev, attr, buf, KGSL_PWRFLAGS_CLK_ON);
+}
+
+static int kgsl_pwrctrl_force_clk_on_store(struct device *dev,
+					struct device_attribute *attr,
+					const char *buf, size_t count)
+{
+	return __force_on_store(dev, attr, buf, count, KGSL_PWRFLAGS_CLK_ON);
+}
+
+static int kgsl_pwrctrl_force_bus_on_show(struct device *dev,
+					struct device_attribute *attr,
+					char *buf)
+{
+	return __force_on_show(dev, attr, buf, KGSL_PWRFLAGS_AXI_ON);
+}
+
+static int kgsl_pwrctrl_force_bus_on_store(struct device *dev,
+					struct device_attribute *attr,
+					const char *buf, size_t count)
+{
+	return __force_on_store(dev, attr, buf, count, KGSL_PWRFLAGS_AXI_ON);
+}
+
 DEVICE_ATTR(gpuclk, 0644, kgsl_pwrctrl_gpuclk_show, kgsl_pwrctrl_gpuclk_store);
 DEVICE_ATTR(max_gpuclk, 0644, kgsl_pwrctrl_max_gpuclk_show,
 	kgsl_pwrctrl_max_gpuclk_store);
@@ -702,6 +787,12 @@
 DEVICE_ATTR(reset_count, 0444,
 	kgsl_pwrctrl_reset_count_show,
 	NULL);
+DEVICE_ATTR(force_clk_on, 0644,
+	kgsl_pwrctrl_force_clk_on_show,
+	kgsl_pwrctrl_force_clk_on_store);
+DEVICE_ATTR(force_bus_on, 0644,
+	kgsl_pwrctrl_force_bus_on_show,
+	kgsl_pwrctrl_force_bus_on_store);
 
 static const struct device_attribute *pwrctrl_attr_list[] = {
 	&dev_attr_gpuclk,
@@ -717,6 +808,8 @@
 	&dev_attr_num_pwrlevels,
 	&dev_attr_pmqos_latency,
 	&dev_attr_reset_count,
+	&dev_attr_force_clk_on,
+	&dev_attr_force_bus_on,
 	NULL
 };
 
@@ -766,11 +859,15 @@
 	}
 }
 
-void kgsl_pwrctrl_clk(struct kgsl_device *device, int state,
+static void kgsl_pwrctrl_clk(struct kgsl_device *device, int state,
 					  int requested_state)
 {
 	struct kgsl_pwrctrl *pwr = &device->pwrctrl;
 	int i = 0;
+
+	if (test_bit(KGSL_PWRFLAGS_CLK_ON, &pwr->ctrl_flags))
+		return;
+
 	if (state == KGSL_PWRFLAGS_OFF) {
 		if (test_and_clear_bit(KGSL_PWRFLAGS_CLK_ON,
 			&pwr->power_flags)) {
@@ -824,10 +921,13 @@
 	}
 }
 
-void kgsl_pwrctrl_axi(struct kgsl_device *device, int state)
+static void kgsl_pwrctrl_axi(struct kgsl_device *device, int state)
 {
 	struct kgsl_pwrctrl *pwr = &device->pwrctrl;
 
+	if (test_bit(KGSL_PWRFLAGS_AXI_ON, &pwr->ctrl_flags))
+		return;
+
 	if (state == KGSL_PWRFLAGS_OFF) {
 		if (test_and_clear_bit(KGSL_PWRFLAGS_AXI_ON,
 			&pwr->power_flags)) {
@@ -858,7 +958,7 @@
 	}
 }
 
-void kgsl_pwrctrl_pwrrail(struct kgsl_device *device, int state)
+static void kgsl_pwrctrl_pwrrail(struct kgsl_device *device, int state)
 {
 	struct kgsl_pwrctrl *pwr = &device->pwrctrl;
 
@@ -961,6 +1061,7 @@
 
 	pwr->active_pwrlevel = pdata->init_level;
 	pwr->default_pwrlevel = pdata->init_level;
+	pwr->init_pwrlevel = pdata->init_level;
 	for (i = 0; i < pdata->num_levels; i++) {
 		pwr->pwrlevels[i].gpu_freq =
 		(pdata->pwrlevel[i].gpu_freq > 0) ?
@@ -1366,8 +1467,10 @@
 
 void kgsl_pwrctrl_enable(struct kgsl_device *device)
 {
+	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->default_pwrlevel);
 	kgsl_pwrctrl_clk(device, KGSL_PWRFLAGS_ON, KGSL_STATE_ACTIVE);
 	kgsl_pwrctrl_axi(device, KGSL_PWRFLAGS_ON);
 }
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.h b/drivers/gpu/msm/kgsl_pwrctrl.h
index 2b986c8..5cadaa7 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.h
+++ b/drivers/gpu/msm/kgsl_pwrctrl.h
@@ -47,6 +47,8 @@
  * @pwrlevels - List of supported power levels
  * @active_pwrlevel - The currently active power level
  * @thermal_pwrlevel - maximum powerlevel constraint from thermal
+ * @default_pwrlevel - device wake up power level
+ * @init_pwrlevel - device inital power level
  * @max_pwrlevel - maximum allowable powerlevel per the user
  * @min_pwrlevel - minimum allowable powerlevel per the user
  * @num_pwrlevels - number of available power levels
@@ -69,10 +71,12 @@
 	struct clk *ebi1_clk;
 	struct clk *grp_clks[KGSL_MAX_CLKS];
 	unsigned long power_flags;
+	unsigned long ctrl_flags;
 	struct kgsl_pwrlevel pwrlevels[KGSL_MAX_PWRLEVELS];
 	unsigned int active_pwrlevel;
 	int thermal_pwrlevel;
 	unsigned int default_pwrlevel;
+	unsigned int init_pwrlevel;
 	unsigned int max_pwrlevel;
 	unsigned int min_pwrlevel;
 	unsigned int num_pwrlevels;
diff --git a/drivers/gpu/msm/kgsl_pwrscale.c b/drivers/gpu/msm/kgsl_pwrscale.c
index afef62e..e5e23f0 100644
--- a/drivers/gpu/msm/kgsl_pwrscale.c
+++ b/drivers/gpu/msm/kgsl_pwrscale.c
@@ -306,6 +306,8 @@
 
 		kgsl_pwrctrl_pwrlevel_change(device,
 				device->pwrctrl.max_pwrlevel);
+		device->pwrctrl.default_pwrlevel =
+				device->pwrctrl.max_pwrlevel;
 	}
 	device->pwrscale.policy = NULL;
 }
@@ -338,6 +340,8 @@
 
 	device->pwrscale.policy = policy;
 
+	device->pwrctrl.default_pwrlevel =
+			device->pwrctrl.init_pwrlevel;
 	/* Pwrscale is enabled by default at attach time */
 	kgsl_pwrscale_enable(device);
 
diff --git a/drivers/gpu/msm/kgsl_pwrscale_trustzone.c b/drivers/gpu/msm/kgsl_pwrscale_trustzone.c
index 5d5d5b1..cfc409c 100644
--- a/drivers/gpu/msm/kgsl_pwrscale_trustzone.c
+++ b/drivers/gpu/msm/kgsl_pwrscale_trustzone.c
@@ -110,8 +110,12 @@
 	else if (!strncmp(str, "performance", 11))
 		priv->governor = TZ_GOVERNOR_PERFORMANCE;
 
-	if (priv->governor == TZ_GOVERNOR_PERFORMANCE)
+	if (priv->governor == TZ_GOVERNOR_PERFORMANCE) {
 		kgsl_pwrctrl_pwrlevel_change(device, pwr->max_pwrlevel);
+		pwr->default_pwrlevel = pwr->max_pwrlevel;
+	} else {
+		pwr->default_pwrlevel = pwr->init_pwrlevel;
+	}
 
 	mutex_unlock(&device->mutex);
 	return count;
diff --git a/drivers/gpu/msm/kgsl_sharedmem.c b/drivers/gpu/msm/kgsl_sharedmem.c
index b9bc432..1691762 100644
--- a/drivers/gpu/msm/kgsl_sharedmem.c
+++ b/drivers/gpu/msm/kgsl_sharedmem.c
@@ -234,6 +234,29 @@
 	return len;
 }
 
+static int kgsl_drv_full_cache_threshold_store(struct device *dev,
+					 struct device_attribute *attr,
+					 const char *buf, size_t count)
+{
+	int ret;
+	unsigned int thresh;
+	ret = sscanf(buf, "%d", &thresh);
+	if (ret != 1)
+		return count;
+
+	kgsl_driver.full_cache_threshold = thresh;
+
+	return count;
+}
+
+static int kgsl_drv_full_cache_threshold_show(struct device *dev,
+					struct device_attribute *attr,
+					char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "%d\n",
+			kgsl_driver.full_cache_threshold);
+}
+
 DEVICE_ATTR(vmalloc, 0444, kgsl_drv_memstat_show, NULL);
 DEVICE_ATTR(vmalloc_max, 0444, kgsl_drv_memstat_show, NULL);
 DEVICE_ATTR(page_alloc, 0444, kgsl_drv_memstat_show, NULL);
@@ -243,6 +266,9 @@
 DEVICE_ATTR(mapped, 0444, kgsl_drv_memstat_show, NULL);
 DEVICE_ATTR(mapped_max, 0444, kgsl_drv_memstat_show, NULL);
 DEVICE_ATTR(histogram, 0444, kgsl_drv_histogram_show, NULL);
+DEVICE_ATTR(full_cache_threshold, 0644,
+		kgsl_drv_full_cache_threshold_show,
+		kgsl_drv_full_cache_threshold_store);
 
 static const struct device_attribute *drv_attr_list[] = {
 	&dev_attr_vmalloc,
@@ -254,6 +280,7 @@
 	&dev_attr_mapped,
 	&dev_attr_mapped_max,
 	&dev_attr_histogram,
+	&dev_attr_full_cache_threshold,
 	NULL
 };
 
@@ -598,7 +625,7 @@
 			gfp_mask |= __GFP_COMP | __GFP_NORETRY |
 				__GFP_NO_KSWAPD | __GFP_NOWARN;
 		else
-			gfp_mask |= GFP_KERNEL | __GFP_NORETRY;
+			gfp_mask |= GFP_KERNEL;
 
 		page = alloc_pages(gfp_mask, get_order(page_size));
 
diff --git a/drivers/gpu/msm/kgsl_trace.h b/drivers/gpu/msm/kgsl_trace.h
index 08677ef..6917883 100644
--- a/drivers/gpu/msm/kgsl_trace.h
+++ b/drivers/gpu/msm/kgsl_trace.h
@@ -539,6 +539,33 @@
 	)
 );
 
+TRACE_EVENT(kgsl_mem_sync_full_cache,
+
+	TP_PROTO(unsigned int num_bufs, unsigned int bulk_size,
+		unsigned int op),
+
+	TP_ARGS(num_bufs, bulk_size, op),
+
+	TP_STRUCT__entry(
+		__field(unsigned int, num_bufs)
+		__field(unsigned int, bulk_size)
+		__field(unsigned int, op)
+	),
+
+	TP_fast_assign(
+		__entry->num_bufs = num_bufs;
+		__entry->bulk_size = bulk_size;
+		__entry->op = op;
+	),
+
+	TP_printk(
+		"num_bufs=%d bulk_size=%d op=%c%c",
+		__entry->num_bufs, __entry->bulk_size,
+		(__entry->op & KGSL_GPUMEM_CACHE_CLEAN) ? 'c' : '.',
+		(__entry->op & KGSL_GPUMEM_CACHE_INV) ? 'i' : '.'
+	)
+);
+
 DECLARE_EVENT_CLASS(kgsl_mem_timestamp_template,
 
 	TP_PROTO(struct kgsl_device *device, struct kgsl_mem_entry *mem_entry,
diff --git a/drivers/hwmon/qpnp-adc-current.c b/drivers/hwmon/qpnp-adc-current.c
index f6ab3c2..de7b0e9 100644
--- a/drivers/hwmon/qpnp-adc-current.c
+++ b/drivers/hwmon/qpnp-adc-current.c
@@ -646,13 +646,15 @@
 {
 	struct qpnp_iadc_drv *iadc = qpnp_iadc;
 	uint8_t	rslt_rsense;
-	int32_t	rc, sign_bit = 0;
+	int32_t	rc = 0, sign_bit = 0;
 
 	if (!iadc || !iadc->iadc_initialized)
 		return -EPROBE_DEFER;
 
-	if (iadc->external_rsense)
+	if (iadc->external_rsense) {
 		*rsense = iadc->rsense;
+		return rc;
+	}
 
 	rc = qpnp_iadc_read_reg(QPNP_IADC_NOMINAL_RSENSE, &rslt_rsense);
 	if (rc < 0) {
diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c
index a77dacb..b96349e 100644
--- a/drivers/i2c/busses/i2c-qup.c
+++ b/drivers/i2c/busses/i2c-qup.c
@@ -37,6 +37,7 @@
 #include <linux/of_gpio.h>
 #include <mach/board.h>
 #include <mach/gpiomux.h>
+#include <mach/msm_bus_board.h>
 
 MODULE_LICENSE("GPL v2");
 MODULE_VERSION("0.2");
@@ -142,6 +143,22 @@
 	.pull = GPIOMUX_PULL_NONE,
 };
 
+/**
+ * qup_i2c_clk_path_vote: data to use bus scaling driver for clock path vote
+ *
+ * @client_hdl when zero, client is not registered with the bus scaling driver,
+ *      and bus scaling functionality should not be used. When non zero, it
+ *      is a bus scaling client id and may be used to vote for clock path.
+ * @reg_err when true, registration error was detected and an error message was
+ *      logged. i2c will attempt to re-register but will log error only once.
+ *      once registration succeed, the flag is set to false.
+ */
+struct qup_i2c_clk_path_vote {
+	u32                         client_hdl;
+	struct msm_bus_scale_pdata *pdata;
+	bool                        reg_err;
+};
+
 struct qup_i2c_dev {
 	struct device                *dev;
 	void __iomem                 *base;		/* virtual */
@@ -172,6 +189,7 @@
 	struct mutex                 mlock;
 	void                         *complete;
 	int                          i2c_gpios[ARRAY_SIZE(i2c_rsrcs)];
+	struct qup_i2c_clk_path_vote clk_path_vote;
 };
 
 #ifdef DEBUG
@@ -333,11 +351,160 @@
 	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)
+
+static int i2c_qup_clk_path_init(struct platform_device *pdev,
+							struct qup_i2c_dev *dev)
+{
+	struct msm_bus_vectors *paths    = NULL;
+	struct msm_bus_paths   *usecases = NULL;
+
+	if (!dev->pdata->master_id)
+		return 0;
+
+	dev_dbg(&pdev->dev, "initialises bus-scaling clock voting");
+
+	paths = devm_kzalloc(&pdev->dev, sizeof(*paths) * 2, GFP_KERNEL);
+	if (!paths) {
+		dev_err(&pdev->dev,
+		"msm_bus_paths.paths memory allocation failed");
+		return -ENOMEM;
+	}
+
+	usecases = devm_kzalloc(&pdev->dev, sizeof(*usecases) * 2, GFP_KERNEL);
+	if (!usecases) {
+		dev_err(&pdev->dev,
+		"msm_bus_scale_pdata.usecases memory allocation failed");
+		goto path_init_err;
+	}
+
+	dev->clk_path_vote.pdata = devm_kzalloc(&pdev->dev,
+					    sizeof(*dev->clk_path_vote.pdata),
+					    GFP_KERNEL);
+	if (!dev->clk_path_vote.pdata) {
+		dev_err(&pdev->dev,
+		"msm_bus_scale_pdata memory allocation failed");
+		goto path_init_err;
+	}
+
+	paths[MSM_I2C_CLK_PATH_SUSPEND] = (struct msm_bus_vectors) {
+		dev->pdata->master_id, MSM_BUS_SLAVE_EBI_CH0, 0, 0
+	};
+
+	paths[MSM_I2C_CLK_PATH_RESUME]  = (struct msm_bus_vectors) {
+		dev->pdata->master_id, MSM_BUS_SLAVE_EBI_CH0, 0,
+						MSM_I2C_CLK_PATH_MAX_BW(dev)
+	};
+
+	usecases[MSM_I2C_CLK_PATH_SUSPEND] = (struct msm_bus_paths) {
+		.num_paths = 1,
+		.vectors   = &paths[MSM_I2C_CLK_PATH_SUSPEND],
+	};
+
+	usecases[MSM_I2C_CLK_PATH_RESUME] = (struct msm_bus_paths) {
+		.num_paths = 1,
+		.vectors   = &paths[MSM_I2C_CLK_PATH_RESUME],
+	};
+
+	*dev->clk_path_vote.pdata = (struct msm_bus_scale_pdata) {
+		.active_only  = dev->pdata->active_only,
+		.name         = pdev->name,
+		.num_usecases = 2,
+		.usecase      = usecases,
+	};
+
+	return 0;
+
+path_init_err:
+	devm_kfree(&pdev->dev, paths);
+	devm_kfree(&pdev->dev, usecases);
+	devm_kfree(&pdev->dev, dev->clk_path_vote.pdata);
+	dev->clk_path_vote.pdata = NULL;
+	return -ENOMEM;
+}
+
+static void i2c_qup_clk_path_teardown(struct qup_i2c_dev *dev)
+{
+	if (dev->clk_path_vote.client_hdl) {
+		msm_bus_scale_unregister_client(dev->clk_path_vote.client_hdl);
+		dev->clk_path_vote.client_hdl = 0;
+	}
+}
+
+static void i2c_qup_clk_path_vote(struct qup_i2c_dev *dev)
+{
+	if (dev->clk_path_vote.client_hdl)
+		msm_bus_scale_client_update_request(
+						dev->clk_path_vote.client_hdl,
+						MSM_I2C_CLK_PATH_RESUME);
+}
+
+static void i2c_qup_clk_path_unvote(struct qup_i2c_dev *dev)
+{
+	if (dev->clk_path_vote.client_hdl)
+		msm_bus_scale_client_update_request(
+						dev->clk_path_vote.client_hdl,
+						MSM_I2C_CLK_PATH_SUSPEND);
+}
+
+/**
+ * i2c_qup_clk_path_postponed_register: reg with bus-scaling after it is probed
+ *
+ * Workaround: i2c driver may be probed before the bus scaling driver. Thus,
+ * this function should be called not from probe but from a later context.
+ * This function may be called more then once before register succeed. At
+ * this case only one error message will be logged. At boot time all clocks
+ * are on, so earlier i2c transactions should succeed.
+ */
+static void i2c_qup_clk_path_postponed_register(struct qup_i2c_dev *dev)
+{
+	/*
+	 * bail out if path voting is diabled (master_id == 0) or if it is
+	 * already registered (client_hdl != 0)
+	 */
+	if (!dev->pdata->master_id || dev->clk_path_vote.client_hdl)
+		return;
+
+	dev->clk_path_vote.client_hdl = msm_bus_scale_register_client(
+						dev->clk_path_vote.pdata);
+
+	if (dev->clk_path_vote.client_hdl) {
+		if (dev->clk_path_vote.reg_err) {
+			/* log a success message if an error msg was logged */
+			dev->clk_path_vote.reg_err = false;
+			dev_info(dev->dev,
+				"msm_bus_scale_register_client(mstr-id:%d "
+				"actv-only:%d):0x%x",
+				dev->pdata->master_id, dev->pdata->active_only,
+				dev->clk_path_vote.client_hdl);
+		}
+
+		if (dev->pdata->active_only)
+			i2c_qup_clk_path_vote(dev);
+	} else {
+		/* guard to log only one error on multiple failure */
+		if (!dev->clk_path_vote.reg_err) {
+			dev->clk_path_vote.reg_err = true;
+
+			dev_info(dev->dev,
+				"msm_bus_scale_register_client(mstr-id:%d "
+				"actv-only:%d):0",
+				dev->pdata->master_id, dev->pdata->active_only);
+		}
+	}
+}
+
 static void
 qup_i2c_pwr_mgmt(struct qup_i2c_dev *dev, unsigned int state)
 {
 	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);
+
 		clk_prepare_enable(dev->clk);
 		if (!dev->pdata->keep_ahb_clk_on)
 			clk_prepare_enable(dev->pclk);
@@ -347,6 +514,8 @@
 		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);
 	}
 }
 
@@ -1099,11 +1268,12 @@
 enum msm_i2c_dt_entry_type {
 	DT_U32,
 	DT_GPIO,
+	DT_BOOL,
 };
 
 struct msm_i2c_dt_to_pdata_map {
 	const char                  *dt_name;
-	int                         *ptr_data;
+	void                        *ptr_data;
 	enum msm_i2c_dt_entry_status status;
 	enum msm_i2c_dt_entry_type   type;
 	int                          default_val;
@@ -1119,28 +1289,42 @@
 	{"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},
 	};
 
 	for (itr = map; itr->dt_name ; ++itr) {
-		if (itr->type == DT_GPIO) {
+		switch (itr->type) {
+		case DT_GPIO:
 			ret = of_get_named_gpio(node, itr->dt_name, 0);
 			if (ret >= 0) {
-				*itr->ptr_data = ret;
+				*((int *) itr->ptr_data) = ret;
 				ret = 0;
 			}
-		} else {
+			break;
+		case DT_U32:
 			ret = of_property_read_u32(node, itr->dt_name,
-								itr->ptr_data);
+							 (u32 *) itr->ptr_data);
+			break;
+		case DT_BOOL:
+			*((bool *) itr->ptr_data) =
+				of_property_read_bool(node, itr->dt_name);
+			ret = 0;
+			break;
+		default:
+			dev_err(&pdev->dev, "%d is an unknown DT entry type\n",
+								itr->type);
+			ret = -EBADE;
 		}
 
 		dev_dbg(&pdev->dev, "DT entry ret:%d name:%s val:%d\n",
-					ret, itr->dt_name, *itr->ptr_data);
+				ret, itr->dt_name, *((int *)itr->ptr_data));
 
 		if (ret) {
-			*itr->ptr_data = itr->default_val;
+			*((int *)itr->ptr_data) = itr->default_val;
 
 			if (itr->status < DT_OPTIONAL) {
 				dev_err(&pdev->dev, "Missing '%s' DT entry\n",
@@ -1326,6 +1510,14 @@
 	dev->clk_ctl = 0;
 	dev->pos = 0;
 
+	ret = i2c_qup_clk_path_init(pdev, dev);
+	if (ret) {
+		dev_err(&pdev->dev,
+		"Failed to init clock path-voting data structs. err:%d", ret);
+		/* disable i2c_qup_clk_path_xxx() functionality */
+		dev->pdata->master_id = 0;
+	}
+
 	if (dev->pdata->src_clk_rate <= 0) {
 		dev_info(&pdev->dev,
 			"No src_clk_rate specified in platfrom data\n");
@@ -1443,6 +1635,7 @@
 err_reset_failed:
 	clk_disable_unprepare(dev->clk);
 	clk_disable_unprepare(dev->pclk);
+	i2c_qup_clk_path_teardown(dev);
 err_gsbi_failed:
 	iounmap(dev->base);
 err_ioremap_failed:
@@ -1488,6 +1681,11 @@
 		clk_put(dev->pclk);
 	}
 	clk_put(dev->clk);
+
+	if (dev->pdata->active_only)
+		i2c_qup_clk_path_unvote(dev);
+	i2c_qup_clk_path_teardown(dev);
+
 	if (dev->gsbi)
 		iounmap(dev->gsbi);
 	iounmap(dev->base);
diff --git a/drivers/iommu/msm_iommu-v0.c b/drivers/iommu/msm_iommu-v0.c
index 06f4a0f..eadbd64 100644
--- a/drivers/iommu/msm_iommu-v0.c
+++ b/drivers/iommu/msm_iommu-v0.c
@@ -32,6 +32,7 @@
 #include <mach/msm_iommu_priv.h>
 #include <mach/iommu.h>
 #include <mach/msm_smem.h>
+#include <mach/msm_bus.h>
 
 #define MRC(reg, processor, op1, crn, crm, op2)				\
 __asm__ __volatile__ (							\
@@ -135,6 +136,20 @@
 	return msm_iommu_remote_lock.lock;
 }
 
+static int apply_bus_vote(struct msm_iommu_drvdata *drvdata, unsigned int vote)
+{
+	int ret = 0;
+
+	if (drvdata->bus_client) {
+		ret = msm_bus_scale_client_update_request(drvdata->bus_client,
+							  vote);
+		if (ret)
+			pr_err("%s: Failed to vote for bus: %d\n", __func__,
+				vote);
+	}
+	return ret;
+}
+
 static int __enable_clocks(struct msm_iommu_drvdata *drvdata)
 {
 	int ret;
@@ -202,6 +217,7 @@
 struct iommu_access_ops iommu_access_ops_v0 = {
 	.iommu_power_on = __enable_regulators,
 	.iommu_power_off = __disable_regulators,
+	.iommu_bus_vote = apply_bus_vote,
 	.iommu_clk_on = __enable_clocks,
 	.iommu_clk_off = __disable_clocks,
 	.iommu_lock_initialize = _iommu_lock_initialize,
@@ -506,6 +522,11 @@
 			goto unlock;
 		}
 
+	ret = apply_bus_vote(iommu_drvdata, 1);
+
+	if (ret)
+		goto unlock;
+
 	ret = __enable_clocks(iommu_drvdata);
 	if (ret)
 		goto unlock;
@@ -572,6 +593,9 @@
 	msm_iommu_remote_spin_unlock();
 
 	__disable_clocks(iommu_drvdata);
+
+	apply_bus_vote(iommu_drvdata, 0);
+
 	list_del_init(&ctx_drvdata->attached_elm);
 	ctx_drvdata->attached_domain = NULL;
 unlock:
@@ -1257,7 +1281,7 @@
 	return 0;
 }
 
-static void print_ctx_regs(void __iomem *base, int ctx)
+static void __print_ctx_regs(void __iomem *base, int ctx)
 {
 	unsigned int fsr = GET_FSR(base, ctx);
 	pr_err("FAR    = %08x    PAR    = %08x\n",
@@ -1323,7 +1347,7 @@
 			pr_err("name    = %s\n", drvdata->name);
 			pr_err("context = %s (%d)\n", ctx_drvdata->name, num);
 			pr_err("Interesting registers:\n");
-			print_ctx_regs(base, num);
+			__print_ctx_regs(base, num);
 		}
 
 		SET_FSR(base, num, fsr);
diff --git a/drivers/iommu/msm_iommu-v1.c b/drivers/iommu/msm_iommu-v1.c
index 8e68beb..5ee8794 100644
--- a/drivers/iommu/msm_iommu-v1.c
+++ b/drivers/iommu/msm_iommu-v1.c
@@ -32,6 +32,7 @@
 #include <mach/iommu.h>
 #include <mach/msm_iommu_priv.h>
 #include <mach/iommu_perfmon.h>
+#include <mach/msm_bus.h>
 #include "msm_iommu_pagetable.h"
 
 /* bitmap of the page sizes currently supported */
@@ -62,6 +63,20 @@
 	regulator_disable(drvdata->gdsc);
 }
 
+static int apply_bus_vote(struct msm_iommu_drvdata *drvdata, unsigned int vote)
+{
+	int ret = 0;
+
+	if (drvdata->bus_client) {
+		ret = msm_bus_scale_client_update_request(drvdata->bus_client,
+							  vote);
+		if (ret)
+			pr_err("%s: Failed to vote for bus: %d\n", __func__,
+				vote);
+	}
+	return ret;
+}
+
 static int __enable_clocks(struct msm_iommu_drvdata *drvdata)
 {
 	int ret;
@@ -116,6 +131,7 @@
 struct iommu_access_ops iommu_access_ops_v1 = {
 	.iommu_power_on = __enable_regulators,
 	.iommu_power_off = __disable_regulators,
+	.iommu_bus_vote = apply_bus_vote,
 	.iommu_clk_on = __enable_clocks,
 	.iommu_clk_off = __disable_clocks,
 	.iommu_lock_acquire = _iommu_lock_acquire,
@@ -513,6 +529,10 @@
 	if (ret)
 		goto fail;
 
+	ret = apply_bus_vote(iommu_drvdata, 1);
+	if (ret)
+		goto fail;
+
 	ret = __enable_clocks(iommu_drvdata);
 	if (ret) {
 		__disable_regulators(iommu_drvdata);
@@ -602,6 +622,8 @@
 
 	__disable_clocks(iommu_drvdata);
 
+	apply_bus_vote(iommu_drvdata, 0);
+
 	__disable_regulators(iommu_drvdata);
 
 	list_del_init(&ctx_drvdata->attached_elm);
@@ -761,10 +783,12 @@
 	return 0;
 }
 
-static void print_ctx_regs(void __iomem *base, int ctx, unsigned int fsr)
+void print_ctx_regs(struct msm_iommu_context_regs *regs)
 {
+	uint32_t fsr = regs->fsr;
+
 	pr_err("FAR    = %08x    PAR    = %08x\n",
-		 GET_FAR(base, ctx), GET_PAR(base, ctx));
+		 regs->far, regs->par);
 	pr_err("FSR    = %08x [%s%s%s%s%s%s%s%s%s]\n", fsr,
 			(fsr & 0x02) ? "TF " : "",
 			(fsr & 0x04) ? "AFF " : "",
@@ -777,13 +801,31 @@
 			(fsr & 0x80000000) ? "MULTI " : "");
 
 	pr_err("FSYNR0 = %08x    FSYNR1 = %08x\n",
-		 GET_FSYNR0(base, ctx), GET_FSYNR1(base, ctx));
+		 regs->fsynr0, regs->fsynr1);
 	pr_err("TTBR0  = %08x    TTBR1  = %08x\n",
-		 GET_TTBR0(base, ctx), GET_TTBR1(base, ctx));
+		 regs->ttbr0, regs->ttbr1);
 	pr_err("SCTLR  = %08x    ACTLR  = %08x\n",
-		 GET_SCTLR(base, ctx), GET_ACTLR(base, ctx));
+		 regs->sctlr, regs->actlr);
 	pr_err("PRRR   = %08x    NMRR   = %08x\n",
-		 GET_PRRR(base, ctx), GET_NMRR(base, ctx));
+		 regs->prrr, regs->nmrr);
+}
+
+static void __print_ctx_regs(void __iomem *base, int ctx, unsigned int fsr)
+{
+	struct msm_iommu_context_regs regs = {
+		.far = GET_FAR(base, ctx),
+		.par = GET_PAR(base, ctx),
+		.fsr = fsr,
+		.fsynr0 = GET_FSYNR0(base, ctx),
+		.fsynr1 = GET_FSYNR1(base, ctx),
+		.ttbr0 = GET_TTBR0(base, ctx),
+		.ttbr1 = GET_TTBR1(base, ctx),
+		.sctlr = GET_SCTLR(base, ctx),
+		.actlr = GET_ACTLR(base, ctx),
+		.prrr = GET_PRRR(base, ctx),
+		.nmrr = GET_NMRR(base, ctx),
+	};
+	print_ctx_regs(&regs);
 }
 
 irqreturn_t msm_iommu_fault_handler_v2(int irq, void *dev_id)
@@ -839,7 +881,7 @@
 			pr_err("context = %s (%d)\n", ctx_drvdata->name,
 							ctx_drvdata->num);
 			pr_err("Interesting registers:\n");
-			print_ctx_regs(drvdata->base, ctx_drvdata->num, fsr);
+			__print_ctx_regs(drvdata->base, ctx_drvdata->num, fsr);
 		}
 
 		SET_FSR(drvdata->base, ctx_drvdata->num, fsr);
diff --git a/drivers/iommu/msm_iommu_dev-v0.c b/drivers/iommu/msm_iommu_dev-v0.c
index 059216e..4ee65d8 100644
--- a/drivers/iommu/msm_iommu_dev-v0.c
+++ b/drivers/iommu/msm_iommu_dev-v0.c
@@ -30,10 +30,13 @@
 #include <mach/iommu_perfmon.h>
 #include <mach/iommu_hw-v0.h>
 #include <mach/iommu.h>
+#include <mach/msm_bus.h>
 
 static DEFINE_MUTEX(iommu_list_lock);
 static LIST_HEAD(iommu_list);
 
+static struct of_device_id msm_iommu_v0_ctx_match_table[];
+
 void msm_iommu_add_drv(struct msm_iommu_drvdata *drv)
 {
 	mutex_lock(&iommu_list_lock);
@@ -77,10 +80,13 @@
 	}
 	mutex_unlock(&iommu_list_lock);
 
-	if (!dev || !dev_get_drvdata(dev))
-		pr_err("Could not find context <%s>\n", ctx_name);
 	put_device(dev);
 
+	if (!dev || !dev_get_drvdata(dev)) {
+		pr_debug("Could not find context <%s>\n", ctx_name);
+		dev = ERR_PTR(-EPROBE_DEFER);
+	}
+
 	return dev;
 }
 EXPORT_SYMBOL(msm_iommu_get_ctx);
@@ -128,74 +134,24 @@
 	mb();
 }
 
-static int msm_iommu_parse_dt(struct platform_device *pdev,
-				struct msm_iommu_drvdata *drvdata,
-				int *needs_alt_core_clk)
-{
-#ifdef CONFIG_OF_DEVICE
-	struct device_node *child;
-	struct resource *r;
-	u32 glb_offset = 0;
-	int ret;
-
-	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!r) {
-		pr_err("%s: Missing property reg\n", __func__);
-		return -EINVAL;
-	}
-	drvdata->base = devm_ioremap(&pdev->dev, r->start, resource_size(r));
-	if (!drvdata->base) {
-		pr_err("%s: Unable to ioremap %pr\n", __func__, r);
-		return -ENOMEM;
-	}
-	drvdata->glb_base = drvdata->base;
-
-	if (!of_property_read_u32(pdev->dev.of_node, "qcom,glb-offset",
-			&glb_offset)) {
-		drvdata->glb_base += glb_offset;
-	} else {
-		pr_err("%s: Missing property qcom,glb-offset\n", __func__);
-		return -EINVAL;
-	}
-
-	for_each_child_of_node(pdev->dev.of_node, child) {
-		drvdata->ncb++;
-		if (!of_platform_device_create(child, NULL, &pdev->dev))
-			pr_err("Failed to create %s device\n", child->name);
-	}
-
-	ret = of_property_read_string(pdev->dev.of_node, "label",
-			&drvdata->name);
-	if (ret) {
-		pr_err("%s: Missing property label\n", __func__);
-		return -EINVAL;
-	}
-
-	*needs_alt_core_clk = of_property_read_bool(pdev->dev.of_node,
-						   "qcom,needs-alt-core-clk");
-
-	drvdata->sec_id = -1;
-	drvdata->ttbr_split = 0;
-#endif
-	return 0;
-}
-
 static int __get_clocks(struct platform_device *pdev,
 			struct msm_iommu_drvdata *drvdata,
 			int needs_alt_core_clk)
 {
 	int ret = 0;
 
-	drvdata->pclk = clk_get(&pdev->dev, "iface_clk");
+	drvdata->pclk = devm_clk_get(&pdev->dev, "iface_clk");
 	if (IS_ERR(drvdata->pclk)) {
 		ret = PTR_ERR(drvdata->pclk);
 		drvdata->pclk = NULL;
-		pr_err("Unable to get %s clock for %s IOMMU device\n",
-			dev_name(&pdev->dev), drvdata->name);
+		if (ret != -EPROBE_DEFER) {
+			pr_err("Unable to get %s clock for %s IOMMU device\n",
+				dev_name(&pdev->dev), drvdata->name);
+		}
 		goto fail;
 	}
 
-	drvdata->clk = clk_get(&pdev->dev, "core_clk");
+	drvdata->clk = devm_clk_get(&pdev->dev, "core_clk");
 
 	if (!IS_ERR(drvdata->clk)) {
 		if (clk_get_rate(drvdata->clk) == 0) {
@@ -208,8 +164,10 @@
 
 	if (needs_alt_core_clk) {
 		drvdata->aclk = devm_clk_get(&pdev->dev, "alt_core_clk");
-		if (IS_ERR(drvdata->aclk))
-			return PTR_ERR(drvdata->aclk);
+		if (IS_ERR(drvdata->aclk)) {
+			ret = PTR_ERR(drvdata->aclk);
+			goto fail;
+		}
 	}
 
 	if (drvdata->aclk && clk_get_rate(drvdata->aclk) == 0) {
@@ -222,15 +180,127 @@
 	return ret;
 }
 
-static void __put_clocks(struct msm_iommu_drvdata *drvdata)
+#ifdef CONFIG_OF_DEVICE
+
+static int __get_bus_vote_client(struct platform_device *pdev,
+				  struct msm_iommu_drvdata *drvdata)
 {
-	if (drvdata->aclk)
-		clk_put(drvdata->aclk);
-	if (drvdata->clk)
-		clk_put(drvdata->clk);
-	clk_put(drvdata->pclk);
+	int ret = 0;
+	struct msm_bus_scale_pdata *bs_table;
+	const char *dummy;
+
+	/* Check whether bus scaling has been specified for this node */
+	ret = of_property_read_string(pdev->dev.of_node, "qcom,msm-bus,name",
+				      &dummy);
+	if (ret)
+		return 0;
+
+	bs_table = msm_bus_cl_get_pdata(pdev);
+
+	if (bs_table) {
+		drvdata->bus_client = msm_bus_scale_register_client(bs_table);
+		if (IS_ERR(&drvdata->bus_client)) {
+			pr_err("%s(): Bus client register failed.\n", __func__);
+			ret = -EINVAL;
+		}
+	}
+	return ret;
 }
 
+static void __put_bus_vote_client(struct msm_iommu_drvdata *drvdata)
+{
+	msm_bus_scale_unregister_client(drvdata->bus_client);
+	drvdata->bus_client = 0;
+}
+
+static int msm_iommu_parse_dt(struct platform_device *pdev,
+				struct msm_iommu_drvdata *drvdata)
+{
+	struct device_node *child;
+	struct resource *r;
+	u32 glb_offset = 0;
+	int ret = 0;
+	int needs_alt_core_clk;
+
+	ret = __get_bus_vote_client(pdev, drvdata);
+
+	if (ret)
+		goto fail;
+
+	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!r) {
+		pr_err("%s: Missing property reg\n", __func__);
+		ret = -EINVAL;
+		goto fail;
+	}
+	drvdata->base = devm_ioremap(&pdev->dev, r->start, resource_size(r));
+	if (!drvdata->base) {
+		pr_err("%s: Unable to ioremap %pr\n", __func__, r);
+		ret = -ENOMEM;
+		goto fail;
+	}
+	drvdata->glb_base = drvdata->base;
+
+	if (!of_property_read_u32(pdev->dev.of_node, "qcom,glb-offset",
+			&glb_offset)) {
+		drvdata->glb_base += glb_offset;
+	} else {
+		pr_err("%s: Missing property qcom,glb-offset\n", __func__);
+		ret = -EINVAL;
+		goto fail;
+	}
+
+	for_each_child_of_node(pdev->dev.of_node, child)
+		drvdata->ncb++;
+
+	ret = of_property_read_string(pdev->dev.of_node, "label",
+			&drvdata->name);
+	if (ret) {
+		pr_err("%s: Missing property label\n", __func__);
+		ret = -EINVAL;
+		goto fail;
+	}
+
+	needs_alt_core_clk = of_property_read_bool(pdev->dev.of_node,
+						   "qcom,needs-alt-core-clk");
+
+	ret = __get_clocks(pdev, drvdata, needs_alt_core_clk);
+
+	if (ret)
+		goto fail;
+
+	drvdata->sec_id = -1;
+	drvdata->ttbr_split = 0;
+
+	ret = of_platform_populate(pdev->dev.of_node,
+				   msm_iommu_v0_ctx_match_table,
+				   NULL, &pdev->dev);
+	if (ret) {
+		pr_err("Failed to create iommu context device\n");
+		goto fail;
+	}
+
+	return ret;
+
+fail:
+	__put_bus_vote_client(drvdata);
+	return ret;
+}
+
+#else
+static int msm_iommu_parse_dt(struct platform_device *pdev,
+				struct msm_iommu_drvdata *drvdata)
+{
+	return 0;
+}
+
+static void __put_bus_vote_client(struct msm_iommu_drvdata *drvdata)
+{
+
+}
+
+#endif
+
 /*
  * Do a basic check of the IOMMU by performing an ATS operation
  * on context bank 0.
@@ -322,23 +392,27 @@
 	struct msm_iommu_drvdata *drvdata;
 	struct msm_iommu_dev *iommu_dev = pdev->dev.platform_data;
 	int ret;
-	int needs_alt_core_clk = 0;
 
 	drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL);
 
 	if (!drvdata) {
 		ret = -ENOMEM;
-		goto fail;
+		goto fail_mem;
 	}
 
 	if (pdev->dev.of_node) {
-		ret = msm_iommu_parse_dt(pdev, drvdata, &needs_alt_core_clk);
+		ret = msm_iommu_parse_dt(pdev, drvdata);
 		if (ret)
 			goto fail;
 	} else if (pdev->dev.platform_data) {
 		struct resource *r, *r2;
 		resource_size_t	len;
 
+		ret = __get_clocks(pdev, drvdata, 0);
+
+		if (ret)
+			goto fail;
+
 		r = platform_get_resource_byname(pdev, IORESOURCE_MEM,
 						"physbase");
 
@@ -349,7 +423,8 @@
 
 		len = resource_size(r);
 
-		r2 = request_mem_region(r->start, len, r->name);
+		r2 = devm_request_mem_region(&pdev->dev, r->start,
+					     len, r->name);
 		if (!r2) {
 			pr_err("Could not request memory region: %pr\n", r);
 			ret = -EBUSY;
@@ -379,11 +454,6 @@
 
 	drvdata->dev = &pdev->dev;
 
-	ret = __get_clocks(pdev, drvdata, needs_alt_core_clk);
-
-	if (ret)
-		goto fail;
-
 	iommu_access_ops_v0.iommu_clk_on(drvdata);
 
 	msm_iommu_reset(drvdata->base, drvdata->glb_base, drvdata->ncb);
@@ -392,14 +462,14 @@
 	if (ret)
 		goto fail_clk;
 
+	iommu_access_ops_v0.iommu_clk_off(drvdata);
+
 	pr_info("device %s mapped at %p, with %d ctx banks\n",
 		drvdata->name, drvdata->base, drvdata->ncb);
 
 	msm_iommu_add_drv(drvdata);
 	platform_set_drvdata(pdev, drvdata);
 
-	iommu_access_ops_v0.iommu_clk_off(drvdata);
-
 	pmon_info = msm_iommu_pm_alloc(&pdev->dev);
 	if (pmon_info != NULL) {
 		ret = msm_iommu_pmon_parse_dt(pdev, pmon_info);
@@ -428,8 +498,9 @@
 
 fail_clk:
 	iommu_access_ops_v0.iommu_clk_off(drvdata);
-	__put_clocks(drvdata);
 fail:
+	__put_bus_vote_client(drvdata);
+fail_mem:
 	return ret;
 }
 
@@ -437,12 +508,13 @@
 {
 	struct msm_iommu_drvdata *drv = NULL;
 
+	msm_iommu_pm_iommu_unregister(&pdev->dev);
+	msm_iommu_pm_free(&pdev->dev);
+
 	drv = platform_get_drvdata(pdev);
 	if (drv) {
+		__put_bus_vote_client(drv);
 		msm_iommu_remove_drv(drv);
-		if (drv->clk)
-			clk_put(drv->clk);
-		clk_put(drv->pclk);
 		platform_set_drvdata(pdev, NULL);
 	}
 	return 0;
@@ -458,26 +530,28 @@
 
 	irq = platform_get_irq(pdev, 0);
 	if (irq > 0) {
-		ret = request_threaded_irq(irq, NULL,
+		ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
 				msm_iommu_fault_handler,
 				IRQF_ONESHOT | IRQF_SHARED,
 				"msm_iommu_nonsecure_irq", ctx_drvdata);
 		if (ret) {
 			pr_err("Request IRQ %d failed with ret=%d\n", irq, ret);
-			return ret;
+			goto out;
 		}
 	}
 
 	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	if (!r) {
 		pr_err("Could not find reg property for context bank\n");
-		return -EINVAL;
+		ret = -EINVAL;
+		goto out;
 	}
 
 	ret = of_address_to_resource(pdev->dev.parent->of_node, 0, &rp);
 	if (ret) {
 		pr_err("of_address_to_resource failed\n");
-		return -EINVAL;
+		ret = -EINVAL;
+		goto out;
 	}
 
 	/* Calculate the context bank number using the base addresses. CB0
@@ -488,29 +562,34 @@
 	if (of_property_read_string(pdev->dev.of_node, "label",
 					&ctx_drvdata->name)) {
 		pr_err("Could not find label property\n");
-		return -EINVAL;
+		ret = -EINVAL;
+		goto out;
 	}
 
 	if (!of_get_property(pdev->dev.of_node, "qcom,iommu-ctx-mids",
 			     &nmid_array_size)) {
 		pr_err("Could not find iommu-ctx-mids property\n");
-		return -EINVAL;
+		ret = -EINVAL;
+		goto out;
 	}
 	if (nmid_array_size >= sizeof(ctx_drvdata->sids)) {
 		pr_err("Too many mids defined - array size: %u, mids size: %u\n",
 			nmid_array_size, sizeof(ctx_drvdata->sids));
-		return -EINVAL;
+		ret = -EINVAL;
+		goto out;
 	}
 	nmid = nmid_array_size / sizeof(*ctx_drvdata->sids);
 
 	if (of_property_read_u32_array(pdev->dev.of_node, "qcom,iommu-ctx-mids",
 				       ctx_drvdata->sids, nmid)) {
 		pr_err("Could not find iommu-ctx-mids property\n");
-		return -EINVAL;
+		ret = -EINVAL;
+		goto out;
 	}
 	ctx_drvdata->nsid = nmid;
 
-	return 0;
+out:
+	return ret;
 }
 
 static void __program_m2v_tables(struct msm_iommu_drvdata *drvdata,
@@ -560,7 +639,7 @@
 	drvdata = dev_get_drvdata(pdev->dev.parent);
 
 	if (!drvdata) {
-		ret = -ENODEV;
+		ret = -EPROBE_DEFER;
 		goto fail;
 	}
 
@@ -578,8 +657,10 @@
 
 	if (pdev->dev.of_node) {
 		ret = msm_iommu_ctx_parse_dt(pdev, ctx_drvdata);
-		if (ret)
+		if (ret) {
+			platform_set_drvdata(pdev, NULL);
 			goto fail;
+		}
 	} else if (pdev->dev.platform_data) {
 		struct msm_iommu_ctx_dev *c = pdev->dev.platform_data;
 
@@ -601,7 +682,8 @@
 			goto fail;
 		}
 
-		ret = request_threaded_irq(irq, NULL, msm_iommu_fault_handler,
+		ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
+					msm_iommu_fault_handler,
 					IRQF_ONESHOT | IRQF_SHARED,
 					"msm_iommu_nonsecure_irq", ctx_drvdata);
 
@@ -647,15 +729,15 @@
 	.remove		= __devexit_p(msm_iommu_remove),
 };
 
-static struct of_device_id msm_iommu_ctx_match_table[] = {
-	{ .name = "qcom,iommu-ctx", },
+static struct of_device_id msm_iommu_v0_ctx_match_table[] = {
+	{ .compatible = "qcom,msm-smmu-v0-ctx", },
 	{}
 };
 
 static struct platform_driver msm_iommu_ctx_driver = {
 	.driver = {
 		.name	= "msm_iommu_ctx",
-		.of_match_table = msm_iommu_ctx_match_table,
+		.of_match_table = msm_iommu_v0_ctx_match_table,
 	},
 	.probe		= msm_iommu_ctx_probe,
 	.remove		= __devexit_p(msm_iommu_ctx_remove),
diff --git a/drivers/iommu/msm_iommu_dev-v1.c b/drivers/iommu/msm_iommu_dev-v1.c
index 418a086..958b7b1 100644
--- a/drivers/iommu/msm_iommu_dev-v1.c
+++ b/drivers/iommu/msm_iommu_dev-v1.c
@@ -28,6 +28,9 @@
 #include <mach/iommu_hw-v1.h>
 #include <mach/iommu.h>
 #include <mach/iommu_perfmon.h>
+#include <mach/msm_bus.h>
+
+static struct of_device_id msm_iommu_v1_ctx_match_table[];
 
 static int msm_iommu_parse_bfb_settings(struct platform_device *pdev,
 				    struct msm_iommu_drvdata *drvdata)
@@ -84,6 +87,36 @@
 	return 0;
 }
 
+static int __get_bus_vote_client(struct platform_device *pdev,
+				  struct msm_iommu_drvdata *drvdata)
+{
+	int ret = 0;
+	struct msm_bus_scale_pdata *bs_table;
+	const char *dummy;
+
+	/* Check whether bus scaling has been specified for this node */
+	ret = of_property_read_string(pdev->dev.of_node, "qcom,msm-bus,name",
+				      &dummy);
+	if (ret)
+		return 0;
+
+	bs_table = msm_bus_cl_get_pdata(pdev);
+
+	if (bs_table) {
+		drvdata->bus_client = msm_bus_scale_register_client(bs_table);
+		if (IS_ERR(&drvdata->bus_client)) {
+			pr_err("%s(): Bus client register failed.\n", __func__);
+			ret = -EINVAL;
+		}
+	}
+	return ret;
+}
+
+static void __put_bus_vote_client(struct msm_iommu_drvdata *drvdata)
+{
+	msm_bus_scale_unregister_client(drvdata->bus_client);
+}
+
 static int msm_iommu_parse_dt(struct platform_device *pdev,
 				struct msm_iommu_drvdata *drvdata)
 {
@@ -92,17 +125,18 @@
 	struct resource *r;
 
 	drvdata->dev = &pdev->dev;
-	msm_iommu_add_drv(drvdata);
+
+	ret = __get_bus_vote_client(pdev, drvdata);
+
+	if (ret)
+		goto fail;
 
 	ret = msm_iommu_parse_bfb_settings(pdev, drvdata);
 	if (ret)
 		goto fail;
 
-	for_each_child_of_node(pdev->dev.of_node, child) {
+	for_each_child_of_node(pdev->dev.of_node, child)
 		drvdata->ncb++;
-		if (!of_platform_device_create(child, NULL, &pdev->dev))
-			pr_err("Failed to create %s device\n", child->name);
-	}
 
 	drvdata->asid = devm_kzalloc(&pdev->dev, drvdata->ncb * sizeof(int),
 				     GFP_KERNEL);
@@ -137,8 +171,15 @@
 	drvdata->halt_enabled = of_property_read_bool(pdev->dev.of_node,
 						      "qcom,iommu-enable-halt");
 
-	return 0;
+	ret = of_platform_populate(pdev->dev.of_node,
+				   msm_iommu_v1_ctx_match_table,
+				   NULL, &pdev->dev);
+	if (ret)
+		pr_err("Failed to create iommu context device\n");
+
+	msm_iommu_add_drv(drvdata);
 fail:
+	__put_bus_vote_client(drvdata);
 	return ret;
 }
 
@@ -224,7 +265,7 @@
 
 	drvdata->gdsc = devm_regulator_get(&pdev->dev, "vdd");
 	if (IS_ERR(drvdata->gdsc))
-		return -EINVAL;
+		return PTR_ERR(drvdata->gdsc);
 
 	drvdata->alt_gdsc = devm_regulator_get(&pdev->dev, "qcom,alt-vdd");
 	if (IS_ERR(drvdata->alt_gdsc))
@@ -301,10 +342,8 @@
 
 	drv = platform_get_drvdata(pdev);
 	if (drv) {
+		__put_bus_vote_client(drv);
 		msm_iommu_remove_drv(drv);
-		if (drv->clk)
-			clk_put(drv->clk);
-		clk_put(drv->pclk);
 		platform_set_drvdata(pdev, NULL);
 	}
 	return 0;
@@ -314,34 +353,49 @@
 				struct msm_iommu_ctx_drvdata *ctx_drvdata)
 {
 	struct resource *r, rp;
-	int irq, ret;
+	int irq = 0, ret = 0;
 	u32 nsid;
 
 	ctx_drvdata->secure_context = of_property_read_bool(pdev->dev.of_node,
 							"qcom,secure-context");
 
-	if (!ctx_drvdata->secure_context) {
-		irq = platform_get_irq(pdev, 0);
+	if (ctx_drvdata->secure_context) {
+		irq = platform_get_irq(pdev, 1);
 		if (irq > 0) {
-			ret = request_threaded_irq(irq, NULL,
-					msm_iommu_fault_handler_v2,
+			ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
+					msm_iommu_secure_fault_handler_v2,
 					IRQF_ONESHOT | IRQF_SHARED,
-					"msm_iommu_nonsecure_irq", pdev);
+					"msm_iommu_secure_irq", pdev);
 			if (ret) {
 				pr_err("Request IRQ %d failed with ret=%d\n",
 					irq, ret);
 				return ret;
 			}
 		}
+	} else {
+		irq = platform_get_irq(pdev, 0);
+		if (irq > 0) {
+			ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
+					msm_iommu_fault_handler_v2,
+					IRQF_ONESHOT | IRQF_SHARED,
+					"msm_iommu_nonsecure_irq", pdev);
+			if (ret) {
+				pr_err("Request IRQ %d failed with ret=%d\n",
+					irq, ret);
+				goto out;
+			}
+		}
 	}
 
 	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!r)
-		return -EINVAL;
+	if (!r) {
+		ret = -EINVAL;
+		goto out;
+	}
 
 	ret = of_address_to_resource(pdev->dev.parent->of_node, 0, &rp);
 	if (ret)
-		return -EINVAL;
+		goto out;
 
 	/* Calculate the context bank number using the base addresses. The
 	 * first 8 pages belong to the global address space which is followed
@@ -354,21 +408,26 @@
 					&ctx_drvdata->name))
 		ctx_drvdata->name = dev_name(&pdev->dev);
 
-	if (!of_get_property(pdev->dev.of_node, "qcom,iommu-ctx-sids", &nsid))
-		return -EINVAL;
-
-	if (nsid >= sizeof(ctx_drvdata->sids))
-		return -EINVAL;
+	if (!of_get_property(pdev->dev.of_node, "qcom,iommu-ctx-sids", &nsid)) {
+		ret = -EINVAL;
+		goto out;
+	}
+	if (nsid >= sizeof(ctx_drvdata->sids)) {
+		ret = -EINVAL;
+		goto out;
+	}
 
 	if (of_property_read_u32_array(pdev->dev.of_node, "qcom,iommu-ctx-sids",
 				       ctx_drvdata->sids,
 				       nsid / sizeof(*ctx_drvdata->sids))) {
-		return -EINVAL;
+		ret = -EINVAL;
+		goto out;
 	}
 	ctx_drvdata->nsid = nsid;
 
 	ctx_drvdata->asid = -1;
-	return 0;
+out:
+	return ret;
 }
 
 static int __devinit msm_iommu_ctx_probe(struct platform_device *pdev)
@@ -386,12 +445,14 @@
 
 	ctx_drvdata->pdev = pdev;
 	INIT_LIST_HEAD(&ctx_drvdata->attached_elm);
-	platform_set_drvdata(pdev, ctx_drvdata);
 
 	ret = msm_iommu_ctx_parse_dt(pdev, ctx_drvdata);
-	if (!ret)
+	if (!ret) {
+		platform_set_drvdata(pdev, ctx_drvdata);
+
 		dev_info(&pdev->dev, "context %s using bank %d\n",
 			 ctx_drvdata->name, ctx_drvdata->num);
+	}
 
 	return ret;
 }
@@ -416,15 +477,15 @@
 	.remove		= __devexit_p(msm_iommu_remove),
 };
 
-static struct of_device_id msm_iommu_ctx_match_table[] = {
-	{ .name = "qcom,iommu-ctx", },
+static struct of_device_id msm_iommu_v1_ctx_match_table[] = {
+	{ .compatible = "qcom,msm-smmu-v1-ctx", },
 	{}
 };
 
 static struct platform_driver msm_iommu_ctx_driver = {
 	.driver = {
 		.name	= "msm_iommu_ctx_v1",
-		.of_match_table = msm_iommu_ctx_match_table,
+		.of_match_table = msm_iommu_v1_ctx_match_table,
 	},
 	.probe		= msm_iommu_ctx_probe,
 	.remove		= __devexit_p(msm_iommu_ctx_remove),
diff --git a/drivers/iommu/msm_iommu_perfmon.c b/drivers/iommu/msm_iommu_perfmon.c
index a11d794..958c6ca 100644
--- a/drivers/iommu/msm_iommu_perfmon.c
+++ b/drivers/iommu/msm_iommu_perfmon.c
@@ -257,6 +257,7 @@
 					dev_get_drvdata(iommu->iommu_dev);
 
 	iommu->ops->iommu_power_on(iommu_drvdata);
+	iommu->ops->iommu_bus_vote(iommu_drvdata, 1);
 	iommu->ops->iommu_clk_on(iommu_drvdata);
 
 	/* Reset counters in HW */
@@ -311,6 +312,7 @@
 
 	iommu->ops->iommu_lock_release();
 	iommu->ops->iommu_clk_off(iommu_drvdata);
+	iommu->ops->iommu_bus_vote(iommu_drvdata, 0);
 	iommu->ops->iommu_power_off(iommu_drvdata);
 
 	pr_info("%s: TLB performance monitoring turned OFF\n",
diff --git a/drivers/iommu/msm_iommu_sec.c b/drivers/iommu/msm_iommu_sec.c
index 74d8b48..a17a4e8 100644
--- a/drivers/iommu/msm_iommu_sec.c
+++ b/drivers/iommu/msm_iommu_sec.c
@@ -38,6 +38,7 @@
 /* bitmap of the page sizes currently supported */
 #define MSM_IOMMU_PGSIZES	(SZ_4K | SZ_64K | SZ_1M | SZ_16M)
 
+/* commands for SCM_SVC_MP */
 #define IOMMU_SECURE_CFG	2
 #define IOMMU_SECURE_PTBL_SIZE  3
 #define IOMMU_SECURE_PTBL_INIT  4
@@ -47,6 +48,9 @@
 #define IOMMU_SECURE_UNMAP2 0x0C
 #define IOMMU_TLBINVAL_FLAG 0x00000001
 
+/* commands for SCM_SVC_UTIL */
+#define IOMMU_DUMP_SMMU_FAULT_REGS 0X0C
+
 static struct iommu_access_ops *iommu_access_ops;
 
 struct msm_scm_paddr_list {
@@ -73,11 +77,154 @@
 	unsigned int flags;
 };
 
+struct msm_scm_fault_regs_dump {
+	uint32_t dump_size;
+	uint32_t fsr_addr;
+	uint32_t fsr;
+	uint32_t far0_addr;
+	uint32_t far0;
+	uint32_t far1_addr;
+	uint32_t far1;
+	uint32_t par0_addr;
+	uint32_t par0;
+	uint32_t par1_addr;
+	uint32_t par1;
+	uint32_t fsyn0_addr;
+	uint32_t fsyn0;
+	uint32_t fsyn1_addr;
+	uint32_t fsyn1;
+	uint32_t ttbr0_addr;
+	uint32_t ttbr0;
+	uint32_t ttbr1_addr;
+	uint32_t ttbr1;
+	uint32_t ttbcr_addr;
+	uint32_t ttbcr;
+	uint32_t sctlr_addr;
+	uint32_t sctlr;
+	uint32_t actlr_addr;
+	uint32_t actlr;
+	uint32_t prrr_addr;
+	uint32_t prrr;
+	uint32_t nmrr_addr;
+	uint32_t nmrr;
+};
+
 void msm_iommu_sec_set_access_ops(struct iommu_access_ops *access_ops)
 {
 	iommu_access_ops = access_ops;
 }
 
+static int msm_iommu_dump_fault_regs(int smmu_id, int cb_num,
+				struct msm_scm_fault_regs_dump *regs)
+{
+	int ret;
+
+	struct msm_scm_fault_regs_dump_req {
+		uint32_t id;
+		uint32_t cb_num;
+		phys_addr_t buff;
+		uint32_t len;
+	} req_info;
+	int resp;
+
+	req_info.id = smmu_id;
+	req_info.cb_num = cb_num;
+	req_info.buff = virt_to_phys(regs);
+	req_info.len = sizeof(*regs);
+
+	ret = scm_call(SCM_SVC_UTIL, IOMMU_DUMP_SMMU_FAULT_REGS,
+		&req_info, sizeof(req_info), &resp, 1);
+
+	return ret;
+}
+
+irqreturn_t msm_iommu_secure_fault_handler_v2(int irq, void *dev_id)
+{
+	struct platform_device *pdev = dev_id;
+	struct msm_iommu_drvdata *drvdata;
+	struct msm_iommu_ctx_drvdata *ctx_drvdata;
+	struct msm_scm_fault_regs_dump *regs;
+	int tmp, ret = IRQ_HANDLED;
+
+	iommu_access_ops->iommu_lock_acquire();
+
+	BUG_ON(!pdev);
+
+	drvdata = dev_get_drvdata(pdev->dev.parent);
+	BUG_ON(!drvdata);
+
+	ctx_drvdata = dev_get_drvdata(&pdev->dev);
+	BUG_ON(!ctx_drvdata);
+
+	regs = kmalloc(sizeof(*regs), GFP_KERNEL);
+	if (!regs) {
+		pr_err("%s: Couldn't allocate memory\n", __func__);
+		goto lock_release;
+	}
+
+	if (!drvdata->ctx_attach_count) {
+		pr_err("Unexpected IOMMU page fault from secure context bank!\n");
+		pr_err("name = %s\n", drvdata->name);
+		pr_err("Power is OFF. Unable to read page fault information\n");
+		/*
+		 * We cannot determine which context bank caused the issue so
+		 * we just return handled here to ensure IRQ handler code is
+		 * happy
+		 */
+		goto free_regs;
+	}
+
+	iommu_access_ops->iommu_clk_on(drvdata);
+	tmp = msm_iommu_dump_fault_regs(drvdata->sec_id,
+					ctx_drvdata->num, regs);
+	iommu_access_ops->iommu_clk_off(drvdata);
+
+	if (tmp) {
+		pr_err("%s: Couldn't dump fault registers!\n", __func__);
+		goto free_regs;
+	} else if (regs->fsr) {
+		struct msm_iommu_context_regs ctx_regs = {
+			.far = regs->far0,
+			.par = regs->par0,
+			.fsr = regs->fsr,
+			.fsynr0 = regs->fsyn0,
+			.fsynr1 = regs->fsyn1,
+			.ttbr0 = regs->ttbr0,
+			.ttbr1 = regs->ttbr1,
+			.sctlr = regs->sctlr,
+			.actlr = regs->actlr,
+			.prrr = regs->prrr,
+			.nmrr = regs->nmrr,
+		};
+
+		if (!ctx_drvdata->attached_domain) {
+			pr_err("Bad domain in interrupt handler\n");
+			tmp = -ENOSYS;
+		} else {
+			tmp = report_iommu_fault(ctx_drvdata->attached_domain,
+				&ctx_drvdata->pdev->dev,
+				regs->far0, 0);
+		}
+
+		/* if the fault wasn't handled by someone else: */
+		if (tmp == -ENOSYS) {
+			pr_err("Unexpected IOMMU page fault from secure context bank!\n");
+			pr_err("name = %s\n", drvdata->name);
+			pr_err("context = %s (%d)\n", ctx_drvdata->name,
+				ctx_drvdata->num);
+			pr_err("Interesting registers:\n");
+			print_ctx_regs(&ctx_regs);
+		}
+	} else {
+		ret = IRQ_NONE;
+	}
+free_regs:
+	kfree(regs);
+lock_release:
+	iommu_access_ops->iommu_lock_release();
+	return ret;
+}
+
 static int msm_iommu_sec_ptbl_init(void)
 {
 	struct device_node *np;
diff --git a/drivers/leds/leds-qpnp.c b/drivers/leds/leds-qpnp.c
index 0233e18..9101a3d 100644
--- a/drivers/leds/leds-qpnp.c
+++ b/drivers/leds/leds-qpnp.c
@@ -166,7 +166,8 @@
 #define LED_MPP_EN_CTRL(base)		(base + 0x46)
 #define LED_MPP_SINK_CTRL(base)		(base + 0x4C)
 
-#define LED_MPP_CURRENT_DEFAULT		10
+#define LED_MPP_CURRENT_DEFAULT		5
+#define LED_MPP_CURRENT_PER_SETTING	5
 #define LED_MPP_SOURCE_SEL_DEFAULT	LED_MPP_MODE_ENABLE
 
 #define LED_MPP_SINK_MASK		0x07
@@ -258,6 +259,7 @@
 enum led_mode {
 	PWM_MODE = 0,
 	LPG_MODE,
+	MANUAL_MODE,
 };
 
 static u8 wled_debug_regs[] = {
@@ -290,6 +292,24 @@
 };
 
 /**
+ *  pwm_config_data - pwm configuration data
+ *  @lut_params - lut parameters to be used by pwm driver
+ *  @pwm_device - pwm device
+ *  @pwm_channel - pwm channel to be configured for led
+ *  @pwm_period_us - period for pwm, in us
+ *  @mode - mode the led operates in
+ */
+struct pwm_config_data {
+	struct lut_params	lut_params;
+	struct pwm_device	*pwm_dev;
+	int			pwm_channel;
+	u32			pwm_period_us;
+	struct pwm_duty_cycles	*duty_cycles;
+	u8	mode;
+	u8	enable;
+};
+
+/**
  *  wled_config_data - wled configuration data
  *  @num_strings - number of wled strings supported
  *  @ovp_val - over voltage protection threshold
@@ -314,12 +334,18 @@
 
 /**
  *  mpp_config_data - mpp configuration data
+ *  @pwm_cfg - device pwm configuration
  *  @current_setting - current setting, 5ma-40ma in 5ma increments
+ *  @source_sel - source selection
+ *  @mode_ctrl - mode control
+ *  @pwm_mode - pwm mode in use
  */
 struct mpp_config_data {
+	struct pwm_config_data	*pwm_cfg;
 	u8	current_setting;
 	u8	source_sel;
 	u8	mode_ctrl;
+	u8 pwm_mode;
 };
 
 /**
@@ -354,38 +380,25 @@
 
 /**
  *  kpdbl_config_data - kpdbl configuration data
- *  @pwm_device - pwm device
- *  @pwm_channel - pwm channel to be configured for led
- *  @pwm_period_us - period for pwm, in us
+ *  @pwm_cfg - device pwm configuration
  *  @row_src_sel_val - select source, 0 for vph_pwr and 1 for vbst
  *  @row_scan_en - enable row scan
  *  @row_scan_val - map to enable needed rows
  */
 struct kpdbl_config_data {
-	struct pwm_device	*pwm_dev;
-	int	pwm_channel;
-	u32	pwm_period_us;
+	struct pwm_config_data	*pwm_cfg;
 	u32	row_src_sel_val;
 	u32	row_scan_en;
 	u32	row_scan_val;
-	u8	mode;
 };
 
 /**
  *  rgb_config_data - rgb configuration data
- *  @lut_params - lut parameters to be used by pwm driver
- *  @pwm_device - pwm device
- *  @pwm_channel - pwm channel to be configured for led
- *  @pwm_period_us - period for pwm, in us
- *  @mode - mode the led operates in
+ *  @pwm_cfg - device pwm configuration
+ *  @enable - bits to enable led
  */
 struct rgb_config_data {
-	struct lut_params	lut_params;
-	struct pwm_device	*pwm_dev;
-	int			pwm_channel;
-	u32			pwm_period_us;
-	struct pwm_duty_cycles	*duty_cycles;
-	u8	mode;
+	struct pwm_config_data	*pwm_cfg;
 	u8	enable;
 };
 
@@ -542,24 +555,33 @@
 static int qpnp_mpp_set(struct qpnp_led_data *led)
 {
 	int rc, val;
+	int duty_us;
 
 	if (led->cdev.brightness) {
-		val = (led->cdev.brightness * LED_MPP_SINK_MASK) / LED_FULL;
-		rc = qpnp_led_masked_write(led,
-				LED_MPP_SINK_CTRL(led->base),
-				LED_MPP_SINK_MASK, val);
-		if (rc) {
-			dev_err(&led->spmi_dev->dev,
-				"Failed to write led enable reg\n");
-			return rc;
+		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(led->mpp_cfg->pwm_cfg->pwm_dev,
+					duty_us,
+					led->mpp_cfg->pwm_cfg->pwm_period_us);
+			if (rc < 0) {
+				dev_err(&led->spmi_dev->dev, "Failed to " \
+					"configure pwm for new values\n");
+				return rc;
+			}
 		}
 
+		if (led->mpp_cfg->pwm_mode != MANUAL_MODE)
+			pwm_enable(led->mpp_cfg->pwm_cfg->pwm_dev);
+
 		val = (led->mpp_cfg->source_sel & LED_MPP_SRC_MASK) |
 			(led->mpp_cfg->mode_ctrl & LED_MPP_MODE_CTRL_MASK);
 
 		rc = qpnp_led_masked_write(led,
-		LED_MPP_MODE_CTRL(led->base), LED_MPP_MODE_MASK,
-		val);
+			LED_MPP_MODE_CTRL(led->base), LED_MPP_MODE_MASK,
+			val);
 		if (rc) {
 			dev_err(&led->spmi_dev->dev,
 					"Failed to write led mode reg\n");
@@ -569,13 +591,15 @@
 		rc = qpnp_led_masked_write(led,
 				LED_MPP_EN_CTRL(led->base), LED_MPP_EN_MASK,
 				LED_MPP_EN_ENABLE);
-			if (rc) {
-				dev_err(&led->spmi_dev->dev,
-						"Failed to write led enable " \
-						"reg\n");
-				return rc;
-			}
+		if (rc) {
+			dev_err(&led->spmi_dev->dev,
+					"Failed to write led enable " \
+					"reg\n");
+			return rc;
+		}
 	} else {
+		if (led->mpp_cfg->pwm_mode != MANUAL_MODE)
+			pwm_disable(led->mpp_cfg->pwm_cfg->pwm_dev);
 		rc = qpnp_led_masked_write(led,
 					LED_MPP_MODE_CTRL(led->base),
 					LED_MPP_MODE_MASK,
@@ -831,21 +855,21 @@
 	if (led->cdev.brightness) {
 		rc = qpnp_led_masked_write(led, KPDBL_ENABLE(led->base),
 				KPDBL_MODULE_EN_MASK, KPDBL_MODULE_EN);
-		duty_us = (led->kpdbl_cfg->pwm_period_us *
+		duty_us = (led->kpdbl_cfg->pwm_cfg->pwm_period_us *
 			led->cdev.brightness) / KPDBL_MAX_LEVEL;
-		rc = pwm_config(led->kpdbl_cfg->pwm_dev, duty_us,
-				led->kpdbl_cfg->pwm_period_us);
+		rc = pwm_config(led->kpdbl_cfg->pwm_cfg->pwm_dev, duty_us,
+				led->kpdbl_cfg->pwm_cfg->pwm_period_us);
 		if (rc < 0) {
 			dev_err(&led->spmi_dev->dev, "pwm config failed\n");
 			return rc;
 		}
-		rc = pwm_enable(led->kpdbl_cfg->pwm_dev);
+		rc = pwm_enable(led->kpdbl_cfg->pwm_cfg->pwm_dev);
 		if (rc < 0) {
 			dev_err(&led->spmi_dev->dev, "pwm enable failed\n");
 			return rc;
 		}
 	} else {
-		pwm_disable(led->kpdbl_cfg->pwm_dev);
+		pwm_disable(led->kpdbl_cfg->pwm_cfg->pwm_dev);
 		rc = qpnp_led_masked_write(led, KPDBL_ENABLE(led->base),
 				KPDBL_MODULE_EN_MASK, KPDBL_MODULE_DIS);
 		if (rc) {
@@ -866,11 +890,11 @@
 	int rc;
 
 	if (led->cdev.brightness) {
-		if (led->rgb_cfg->mode == PWM_MODE) {
-			duty_us = (led->rgb_cfg->pwm_period_us *
+		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(led->rgb_cfg->pwm_dev, duty_us,
-					led->rgb_cfg->pwm_period_us);
+			rc = pwm_config(led->rgb_cfg->pwm_cfg->pwm_dev, duty_us,
+					led->rgb_cfg->pwm_cfg->pwm_period_us);
 			if (rc < 0) {
 				dev_err(&led->spmi_dev->dev,
 					"pwm config failed\n");
@@ -885,13 +909,14 @@
 				"Failed to write led enable reg\n");
 			return rc;
 		}
-		rc = pwm_enable(led->rgb_cfg->pwm_dev);
+
+		rc = pwm_enable(led->rgb_cfg->pwm_cfg->pwm_dev);
 		if (rc < 0) {
 			dev_err(&led->spmi_dev->dev, "pwm enable failed\n");
 			return rc;
 		}
 	} else {
-		pwm_disable(led->rgb_cfg->pwm_dev);
+		pwm_disable(led->rgb_cfg->pwm_cfg->pwm_dev);
 		rc = qpnp_led_masked_write(led,
 			RGB_LED_EN_CTL(led->base),
 			led->rgb_cfg->enable, RGB_LED_DISABLE);
@@ -1299,6 +1324,63 @@
 	return 0;
 }
 
+static int __devinit qpnp_pwm_init(struct pwm_config_data *pwm_cfg,
+					struct spmi_device *spmi_dev,
+					const char *name)
+{
+	int rc, start_idx, idx_len;
+
+	if (pwm_cfg->pwm_channel != -1) {
+		pwm_cfg->pwm_dev =
+			pwm_request(pwm_cfg->pwm_channel, name);
+
+		if (IS_ERR_OR_NULL(pwm_cfg->pwm_dev)) {
+			dev_err(&spmi_dev->dev,
+				"could not acquire PWM Channel %d, " \
+				"error %ld\n",
+				pwm_cfg->pwm_channel,
+				PTR_ERR(pwm_cfg->pwm_dev));
+			pwm_cfg->pwm_dev = NULL;
+			return -ENODEV;
+		}
+
+		if (pwm_cfg->mode == LPG_MODE) {
+			start_idx =
+			pwm_cfg->duty_cycles->start_idx;
+			idx_len =
+			pwm_cfg->duty_cycles->num_duty_pcts;
+
+			if (idx_len >= PWM_LUT_MAX_SIZE &&
+					start_idx) {
+				dev_err(&spmi_dev->dev,
+					"Wrong LUT size or index\n");
+				return -EINVAL;
+			}
+			if ((start_idx + idx_len) >
+					PWM_LUT_MAX_SIZE) {
+				dev_err(&spmi_dev->dev,
+					"Exceed LUT limit\n");
+				return -EINVAL;
+			}
+			rc = pwm_lut_config(pwm_cfg->pwm_dev,
+				PM_PWM_PERIOD_MIN, /* ignored by hardware */
+				pwm_cfg->duty_cycles->duty_pcts,
+				pwm_cfg->lut_params);
+			if (rc < 0) {
+				dev_err(&spmi_dev->dev, "Failed to " \
+					"configure pwm LUT\n");
+				return rc;
+			}
+		}
+	} else {
+		dev_err(&spmi_dev->dev,
+			"Invalid PWM channel\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
 static int __devinit qpnp_kpdbl_init(struct qpnp_led_data *led)
 {
 	int rc;
@@ -1348,24 +1430,12 @@
 		return rc;
 	}
 
-	if (led->kpdbl_cfg->pwm_channel != -1) {
-		led->kpdbl_cfg->pwm_dev =
-			pwm_request(led->kpdbl_cfg->pwm_channel,
-						led->cdev.name);
-
-		if (IS_ERR_OR_NULL(led->kpdbl_cfg->pwm_dev)) {
-			dev_err(&led->spmi_dev->dev,
-				"could not acquire PWM Channel %d, " \
-				"error %ld\n",
-				led->kpdbl_cfg->pwm_channel,
-				PTR_ERR(led->kpdbl_cfg->pwm_dev));
-			led->kpdbl_cfg->pwm_dev = NULL;
-			return -ENODEV;
-		}
-	} else {
+	rc = qpnp_pwm_init(led->kpdbl_cfg->pwm_cfg, led->spmi_dev,
+				led->cdev.name);
+	if (rc) {
 		dev_err(&led->spmi_dev->dev,
-			"Invalid PWM channel\n");
-		return -EINVAL;
+			"Failed to initialize pwm\n");
+		return rc;
 	}
 
 	/* dump kpdbl registers */
@@ -1376,7 +1446,7 @@
 
 static int __devinit qpnp_rgb_init(struct qpnp_led_data *led)
 {
-	int rc, start_idx, idx_len;
+	int rc;
 
 	rc = qpnp_led_masked_write(led, RGB_LED_SRC_SEL(led->base),
 		RGB_LED_SRC_MASK, RGB_LED_SOURCE_VPH_PWR);
@@ -1386,55 +1456,13 @@
 		return rc;
 	}
 
-	if (led->rgb_cfg->pwm_channel != -1) {
-		led->rgb_cfg->pwm_dev =
-			pwm_request(led->rgb_cfg->pwm_channel,
-						led->cdev.name);
-
-		if (IS_ERR_OR_NULL(led->rgb_cfg->pwm_dev)) {
-			dev_err(&led->spmi_dev->dev,
-				"could not acquire PWM Channel %d, " \
-				"error %ld\n",
-				led->rgb_cfg->pwm_channel,
-				PTR_ERR(led->rgb_cfg->pwm_dev));
-			led->rgb_cfg->pwm_dev = NULL;
-			return -ENODEV;
-		}
-
-		if (led->rgb_cfg->mode == LPG_MODE) {
-			start_idx =
-			led->rgb_cfg->duty_cycles->start_idx;
-			idx_len =
-			led->rgb_cfg->duty_cycles->num_duty_pcts;
-
-			if (idx_len >= PWM_LUT_MAX_SIZE &&
-					start_idx) {
-				dev_err(&led->spmi_dev->dev,
-					"Wrong LUT size or index\n");
-				return -EINVAL;
-			}
-			if ((start_idx + idx_len) >
-					PWM_LUT_MAX_SIZE) {
-				dev_err(&led->spmi_dev->dev,
-					"Exceed LUT limit\n");
-				return -EINVAL;
-			}
-			rc = pwm_lut_config(led->rgb_cfg->pwm_dev,
-				PM_PWM_PERIOD_MIN, /* ignored by hardware */
-				led->rgb_cfg->duty_cycles->duty_pcts,
-				led->rgb_cfg->lut_params);
-			if (rc < 0) {
-				dev_err(&led->spmi_dev->dev, "Failed to " \
-					"configure pwm LUT\n");
-				return rc;
-			}
-		}
-	} else {
+	rc = qpnp_pwm_init(led->rgb_cfg->pwm_cfg, led->spmi_dev,
+				led->cdev.name);
+	if (rc) {
 		dev_err(&led->spmi_dev->dev,
-			"Invalid PWM channel\n");
-		return -EINVAL;
+			"Failed to initialize pwm\n");
+		return rc;
 	}
-
 	/* Initialize led for use in auto trickle charging mode */
 	rc = qpnp_led_masked_write(led, RGB_LED_ATC_CTL(led->base),
 		led->rgb_cfg->enable, led->rgb_cfg->enable);
@@ -1442,6 +1470,36 @@
 	return 0;
 }
 
+static int __devinit qpnp_mpp_init(struct qpnp_led_data *led)
+{
+	int rc, val;
+
+	val = (led->mpp_cfg->current_setting / LED_MPP_CURRENT_PER_SETTING) - 1;
+
+	if (val < 0)
+		val = 0;
+
+	rc = qpnp_led_masked_write(led, LED_MPP_SINK_CTRL(led->base),
+		LED_MPP_SINK_MASK, val);
+	if (rc) {
+		dev_err(&led->spmi_dev->dev,
+			"Failed to write led enable reg\n");
+		return rc;
+	}
+
+	if (led->mpp_cfg->pwm_mode != MANUAL_MODE) {
+		rc = qpnp_pwm_init(led->mpp_cfg->pwm_cfg, led->spmi_dev,
+					led->cdev.name);
+		if (rc) {
+			dev_err(&led->spmi_dev->dev,
+				"Failed to initialize pwm\n");
+			return rc;
+		}
+	}
+
+	return 0;
+}
+
 static int __devinit qpnp_led_initialize(struct qpnp_led_data *led)
 {
 	int rc = 0;
@@ -1469,6 +1527,10 @@
 				"RGB initialize failed(%d)\n", rc);
 		break;
 	case QPNP_ID_LED_MPP:
+		rc = qpnp_mpp_init(led);
+		if (rc)
+			dev_err(&led->spmi_dev->dev,
+				"MPP initialize failed(%d)\n", rc);
 		break;
 	case QPNP_ID_KPDBL:
 		rc = qpnp_kpdbl_init(led);
@@ -1631,7 +1693,7 @@
 	if (!rc)
 		led->flash_cfg->headroom = (u8) val;
 	else if (rc == -EINVAL)
-		led->flash_cfg->headroom = HEADROOM_300mV;
+		led->flash_cfg->headroom = HEADROOM_500mV;
 	else
 		return rc;
 
@@ -1656,7 +1718,7 @@
 	if (!rc)
 		led->flash_cfg->startup_dly = (u8) val;
 	else if (rc == -EINVAL)
-		led->flash_cfg->startup_dly = DELAY_32us;
+		led->flash_cfg->startup_dly = DELAY_128us;
 	else
 		return rc;
 
@@ -1669,11 +1731,138 @@
 	return 0;
 }
 
+static int __devinit qpnp_get_config_pwm(struct pwm_config_data *pwm_cfg,
+				struct spmi_device *spmi_dev,
+				struct device_node *node)
+{
+	struct property *prop;
+	int rc, i;
+	u32 val;
+	u8 *temp_cfg;
+
+	rc = of_property_read_u32(node, "qcom,pwm-channel", &val);
+	if (!rc)
+		pwm_cfg->pwm_channel = val;
+	else
+		return rc;
+
+	if (pwm_cfg->mode == PWM_MODE) {
+		rc = of_property_read_u32(node, "qcom,pwm-us", &val);
+		if (!rc)
+			pwm_cfg->pwm_period_us = val;
+		else
+			return rc;
+	}
+
+	if (pwm_cfg->mode == LPG_MODE) {
+		pwm_cfg->duty_cycles =
+			devm_kzalloc(&spmi_dev->dev,
+			sizeof(struct pwm_duty_cycles), GFP_KERNEL);
+		if (!pwm_cfg->duty_cycles) {
+			dev_err(&spmi_dev->dev,
+				"Unable to allocate memory\n");
+			return -ENOMEM;
+		}
+
+		prop = of_find_property(node, "qcom,duty-pcts",
+			&pwm_cfg->duty_cycles->num_duty_pcts);
+		if (!prop) {
+			dev_err(&spmi_dev->dev, "Looking up property " \
+				"node qcom,duty-pcts failed\n");
+			return -ENODEV;
+		} else if (!pwm_cfg->duty_cycles->num_duty_pcts) {
+			dev_err(&spmi_dev->dev, "Invalid length of " \
+				"duty pcts\n");
+			return -EINVAL;
+		}
+
+		pwm_cfg->duty_cycles->duty_pcts =
+			devm_kzalloc(&spmi_dev->dev,
+			sizeof(int) * pwm_cfg->duty_cycles->num_duty_pcts,
+			GFP_KERNEL);
+		if (!pwm_cfg->duty_cycles->duty_pcts) {
+			dev_err(&spmi_dev->dev,
+				"Unable to allocate memory\n");
+			return -ENOMEM;
+		}
+
+		temp_cfg = devm_kzalloc(&spmi_dev->dev,
+				pwm_cfg->duty_cycles->num_duty_pcts *
+				sizeof(u8), GFP_KERNEL);
+		if (!temp_cfg) {
+			dev_err(&spmi_dev->dev, "Failed to allocate " \
+				"memory for duty pcts\n");
+			return -ENOMEM;
+		}
+
+		memcpy(temp_cfg, prop->value,
+			pwm_cfg->duty_cycles->num_duty_pcts);
+
+		for (i = 0; i < pwm_cfg->duty_cycles->num_duty_pcts; i++)
+			pwm_cfg->duty_cycles->duty_pcts[i] =
+				(int) temp_cfg[i];
+
+		rc = of_property_read_u32(node, "qcom,start-idx", &val);
+		if (!rc) {
+			pwm_cfg->lut_params.start_idx = val;
+			pwm_cfg->duty_cycles->start_idx = val;
+		} else
+			return rc;
+
+		pwm_cfg->lut_params.lut_pause_hi = 0;
+		rc = of_property_read_u32(node, "qcom,pause-hi", &val);
+		if (!rc)
+			pwm_cfg->lut_params.lut_pause_hi = val;
+		else if (rc != -EINVAL)
+			return rc;
+
+		pwm_cfg->lut_params.lut_pause_lo = 0;
+		rc = of_property_read_u32(node, "qcom,pause-lo", &val);
+		if (!rc)
+			pwm_cfg->lut_params.lut_pause_lo = val;
+		else if (rc != -EINVAL)
+			return rc;
+
+		pwm_cfg->lut_params.ramp_step_ms =
+				QPNP_LUT_RAMP_STEP_DEFAULT;
+		rc = of_property_read_u32(node, "qcom,ramp-step-ms", &val);
+		if (!rc)
+			pwm_cfg->lut_params.ramp_step_ms = val;
+		else if (rc != -EINVAL)
+			return rc;
+
+		pwm_cfg->lut_params.flags = QPNP_LED_PWM_FLAGS;
+		rc = of_property_read_u32(node, "qcom,lut-flags", &val);
+		if (!rc)
+			pwm_cfg->lut_params.flags = (u8) val;
+		else if (rc != -EINVAL)
+			return rc;
+
+		pwm_cfg->lut_params.idx_len =
+			pwm_cfg->duty_cycles->num_duty_pcts;
+	}
+	return 0;
+};
+
+static int qpnp_led_get_mode(const char *mode)
+{
+	if (strncmp(mode, "manual", strlen(mode)) == 0)
+		return MANUAL_MODE;
+	else if (strncmp(mode, "pwm", strlen(mode)) == 0)
+		return PWM_MODE;
+	else if (strncmp(mode, "lpg", strlen(mode)) == 0)
+		return LPG_MODE;
+	else
+		return -EINVAL;
+};
+
 static int __devinit qpnp_get_config_kpdbl(struct qpnp_led_data *led,
 				struct device_node *node)
 {
 	int rc;
 	u32 val;
+	u8 led_mode;
+	const char *mode;
 
 	led->kpdbl_cfg = devm_kzalloc(&led->spmi_dev->dev,
 				sizeof(struct kpdbl_config_data), GFP_KERNEL);
@@ -1681,28 +1870,28 @@
 		dev_err(&led->spmi_dev->dev, "Unable to allocate memory\n");
 		return -ENOMEM;
 	}
-
-	rc = of_property_read_u32(node, "qcom,mode", &val);
-	if (!rc)
-		led->kpdbl_cfg->mode = (u8) val;
-	else
+	rc = of_property_read_string(node, "qcom,mode", &mode);
+	if (!rc) {
+		led_mode = qpnp_led_get_mode(mode);
+		if ((led_mode == MANUAL_MODE) || (led_mode == -EINVAL)) {
+			dev_err(&led->spmi_dev->dev, "Selected mode not " \
+				"supported for kpdbl.\n");
+			return -EINVAL;
+		}
+		led->kpdbl_cfg->pwm_cfg = devm_kzalloc(&led->spmi_dev->dev,
+					sizeof(struct pwm_config_data),
+					GFP_KERNEL);
+		if (!led->kpdbl_cfg->pwm_cfg) {
+			dev_err(&led->spmi_dev->dev,
+				"Unable to allocate memory\n");
+			return -ENOMEM;
+		}
+		led->kpdbl_cfg->pwm_cfg->mode = led_mode;
+	} else
 		return rc;
 
-	if (led->kpdbl_cfg->mode == LPG_MODE) {
-		dev_err(&led->spmi_dev->dev, "LPG mode not supported\n");
-		return -EINVAL;
-	}
-
-	rc = of_property_read_u32(node, "qcom,pwm-channel", &val);
-	if (!rc)
-		led->kpdbl_cfg->pwm_channel = (u8) val;
-	else
-		return rc;
-
-	rc = of_property_read_u32(node, "qcom,pwm-us", &val);
-	if (!rc)
-		led->kpdbl_cfg->pwm_period_us = val;
-	else
+	rc = qpnp_get_config_pwm(led->kpdbl_cfg->pwm_cfg, led->spmi_dev,  node);
+	if (rc < 0)
 		return rc;
 
 	rc = of_property_read_u32(node, "qcom,row-src-sel-val", &val);
@@ -1729,10 +1918,9 @@
 static int __devinit qpnp_get_config_rgb(struct qpnp_led_data *led,
 				struct device_node *node)
 {
-	struct property *prop;
-	int rc, i;
-	u32 val;
-	u8 *temp_cfg;
+	int rc;
+	u8 led_mode;
+	const char *mode;
 
 	led->rgb_cfg = devm_kzalloc(&led->spmi_dev->dev,
 				sizeof(struct rgb_config_data), GFP_KERNEL);
@@ -1750,113 +1938,29 @@
 	else
 		return -EINVAL;
 
-	rc = of_property_read_u32(node, "qcom,mode", &val);
-	if (!rc)
-		led->rgb_cfg->mode = (u8) val;
-	else
-		return rc;
-
-	rc = of_property_read_u32(node, "qcom,pwm-channel", &val);
-	if (!rc)
-		led->rgb_cfg->pwm_channel = val;
-	else
-		return rc;
-
-	if (led->rgb_cfg->mode == PWM_MODE) {
-		rc = of_property_read_u32(node, "qcom,pwm-us", &val);
-		if (!rc)
-			led->rgb_cfg->pwm_period_us = val;
-		else
-			return rc;
-	}
-
-	if (led->rgb_cfg->mode == LPG_MODE) {
-		led->rgb_cfg->duty_cycles =
-			devm_kzalloc(&led->spmi_dev->dev,
-			sizeof(struct pwm_duty_cycles), GFP_KERNEL);
-		if (!led->rgb_cfg->duty_cycles) {
-			dev_err(&led->spmi_dev->dev,
-				"Unable to allocate memory\n");
-			return -ENOMEM;
-		}
-
-		prop = of_find_property(node, "qcom,duty-pcts",
-			&led->rgb_cfg->duty_cycles->num_duty_pcts);
-		if (!prop) {
-			dev_err(&led->spmi_dev->dev, "Looking up property " \
-				"node qcom,duty-pcts failed\n");
-			return -ENODEV;
-		} else if (!led->rgb_cfg->duty_cycles->num_duty_pcts) {
-			dev_err(&led->spmi_dev->dev, "Invalid length of " \
-				"duty pcts\n");
+	rc = of_property_read_string(node, "qcom,mode", &mode);
+	if (!rc) {
+		led_mode = qpnp_led_get_mode(mode);
+		if ((led_mode == MANUAL_MODE) || (led_mode == -EINVAL)) {
+			dev_err(&led->spmi_dev->dev, "Selected mode not " \
+				"supported for rgb.\n");
 			return -EINVAL;
 		}
-
-		led->rgb_cfg->duty_cycles->duty_pcts =
-			devm_kzalloc(&led->spmi_dev->dev,
-			sizeof(int) * led->rgb_cfg->duty_cycles->num_duty_pcts,
-			GFP_KERNEL);
-		if (!led->rgb_cfg->duty_cycles->duty_pcts) {
+		led->rgb_cfg->pwm_cfg = devm_kzalloc(&led->spmi_dev->dev,
+					sizeof(struct pwm_config_data),
+					GFP_KERNEL);
+		if (!led->rgb_cfg->pwm_cfg) {
 			dev_err(&led->spmi_dev->dev,
 				"Unable to allocate memory\n");
 			return -ENOMEM;
 		}
+		led->rgb_cfg->pwm_cfg->mode = led_mode;
+	} else
+		return rc;
 
-		temp_cfg = devm_kzalloc(&led->spmi_dev->dev,
-				led->rgb_cfg->duty_cycles->num_duty_pcts *
-				sizeof(u8), GFP_KERNEL);
-		if (!temp_cfg) {
-			dev_err(&led->spmi_dev->dev, "Failed to allocate " \
-				"memory for duty pcts\n");
-			return -ENOMEM;
-		}
-
-		memcpy(temp_cfg, prop->value,
-			led->rgb_cfg->duty_cycles->num_duty_pcts);
-
-		for (i = 0; i < led->rgb_cfg->duty_cycles->num_duty_pcts; i++)
-			led->rgb_cfg->duty_cycles->duty_pcts[i] =
-				(int) temp_cfg[i];
-
-		rc = of_property_read_u32(node, "qcom,start-idx", &val);
-		if (!rc) {
-			led->rgb_cfg->lut_params.start_idx = val;
-			led->rgb_cfg->duty_cycles->start_idx = val;
-		} else
-			return rc;
-
-		led->rgb_cfg->lut_params.lut_pause_hi = 0;
-		rc = of_property_read_u32(node, "qcom,pause-hi", &val);
-		if (!rc)
-			led->rgb_cfg->lut_params.lut_pause_hi = val;
-		else if (rc != -EINVAL)
-			return rc;
-
-		led->rgb_cfg->lut_params.lut_pause_lo = 0;
-		rc = of_property_read_u32(node, "qcom,pause-lo", &val);
-		if (!rc)
-			led->rgb_cfg->lut_params.lut_pause_lo = val;
-		else if (rc != -EINVAL)
-			return rc;
-
-		led->rgb_cfg->lut_params.ramp_step_ms =
-				QPNP_LUT_RAMP_STEP_DEFAULT;
-		rc = of_property_read_u32(node, "qcom,ramp-step-ms", &val);
-		if (!rc)
-			led->rgb_cfg->lut_params.ramp_step_ms = val;
-		else if (rc != -EINVAL)
-			return rc;
-
-		led->rgb_cfg->lut_params.flags = QPNP_LED_PWM_FLAGS;
-		rc = of_property_read_u32(node, "qcom,lut-flags", &val);
-		if (!rc)
-			led->rgb_cfg->lut_params.flags = val;
-		else if (rc != -EINVAL)
-			return rc;
-
-		led->rgb_cfg->lut_params.idx_len =
-			led->rgb_cfg->duty_cycles->num_duty_pcts;
-	}
+	rc = qpnp_get_config_pwm(led->rgb_cfg->pwm_cfg, led->spmi_dev, node);
+	if (rc < 0)
+		return rc;
 
 	return 0;
 }
@@ -1866,6 +1970,8 @@
 {
 	int rc;
 	u32 val;
+	u8 led_mode;
+	const char *mode;
 
 	led->mpp_cfg = devm_kzalloc(&led->spmi_dev->dev,
 			sizeof(struct mpp_config_data), GFP_KERNEL);
@@ -1895,6 +2001,33 @@
 	else if (rc != -EINVAL)
 		return rc;
 
+	rc = of_property_read_string(node, "qcom,mode", &mode);
+	if (!rc) {
+		led_mode = qpnp_led_get_mode(mode);
+		led->mpp_cfg->pwm_mode = led_mode;
+		if (led_mode == MANUAL_MODE)
+			return MANUAL_MODE;
+		else if (led_mode == -EINVAL) {
+			dev_err(&led->spmi_dev->dev, "Selected mode not " \
+				"supported for mpp.\n");
+			return -EINVAL;
+		}
+		led->mpp_cfg->pwm_cfg = devm_kzalloc(&led->spmi_dev->dev,
+					sizeof(struct pwm_config_data),
+					GFP_KERNEL);
+		if (!led->mpp_cfg->pwm_cfg) {
+			dev_err(&led->spmi_dev->dev,
+				"Unable to allocate memory\n");
+			return -ENOMEM;
+		}
+		led->mpp_cfg->pwm_cfg->mode = led_mode;
+	} else
+		return rc;
+
+	rc = qpnp_get_config_pwm(led->mpp_cfg->pwm_cfg, led->spmi_dev, node);
+	if (rc < 0)
+		return rc;
+
 	return 0;
 }
 
@@ -2005,6 +2138,7 @@
 			if (rc < 0) {
 				dev_err(&led->spmi_dev->dev,
 						"Unable to read mpp config data\n");
+				goto fail_id_check;
 			}
 		} else if (strncmp(led_label, "kpdbl", sizeof("kpdbl")) == 0) {
 			rc = qpnp_get_config_kpdbl(led, temp);
diff --git a/drivers/media/dvb/dvb-core/dvb_demux.c b/drivers/media/dvb/dvb-core/dvb_demux.c
index 8caa9dd..b8c3c44 100644
--- a/drivers/media/dvb/dvb-core/dvb_demux.c
+++ b/drivers/media/dvb/dvb-core/dvb_demux.c
@@ -1577,9 +1577,11 @@
 
 		if (pktsize == 192) {
 			if (leadingbytes)
-				memcpy(timestamp, &buf[p], TIMESTAMP_LEN);
+				memcpy(timestamp, &demux->tsbuf[p],
+					TIMESTAMP_LEN);
 			else
-				memcpy(timestamp, &buf[188], TIMESTAMP_LEN);
+				memcpy(timestamp, &demux->tsbuf[188],
+					TIMESTAMP_LEN);
 		} else {
 			memset(timestamp, 0, TIMESTAMP_LEN);
 		}
diff --git a/drivers/media/platform/msm/camera_v2/Kconfig b/drivers/media/platform/msm/camera_v2/Kconfig
index 52864ae..525a545 100644
--- a/drivers/media/platform/msm/camera_v2/Kconfig
+++ b/drivers/media/platform/msm/camera_v2/Kconfig
@@ -36,6 +36,16 @@
           This config macro is required targets based on 8960,
           8930 and 8064 platforms.
 
+config MSM_CSI22_HEADER
+        bool "Qualcomm MSM CSI 2.2 Header"
+        depends on MSMB_CAMERA
+        ---help---
+          Enable support for CSI drivers to include 2.2
+          header. This header has register macros and its
+          values and bit mask for register configuration bits
+          This config macro is required targets based on 8610
+          platform.
+
 config MSM_CSI30_HEADER
         bool "Qualcomm MSM CSI 3.0 Header"
         depends on MSMB_CAMERA
@@ -82,6 +92,15 @@
           of any CID of CSID can be routed to of of pixel or raw
           data interface in VFE.
 
+config MSM_ISPIF_V1
+        bool "Qualcomm MSM Image Signal Processing interface support"
+        depends on MSMB_CAMERA
+        ---help---
+          Enable support for Image Signal Processing interface module.
+          This module acts as a crossbar between CSID and VFE. Output
+          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
diff --git a/drivers/media/platform/msm/camera_v2/camera/camera.c b/drivers/media/platform/msm/camera_v2/camera/camera.c
index 4579cee..08fa7dd 100644
--- a/drivers/media/platform/msm/camera_v2/camera/camera.c
+++ b/drivers/media/platform/msm/camera_v2/camera/camera.c
@@ -539,7 +539,6 @@
 		rc = msm_create_session(pvdev->vdev->num, pvdev->vdev);
 		if (rc < 0)
 			goto session_fail;
-
 		rc = msm_create_command_ack_q(pvdev->vdev->num, 0);
 		if (rc < 0)
 			goto command_ack_q_fail;
@@ -611,6 +610,7 @@
 
 		/* Donot wait, imaging server may have crashed */
 		msm_post_event(&event, -1);
+		msm_delete_command_ack_q(pvdev->vdev->num, 0);
 
 		/* This should take care of both normal close
 		 * and application crashes */
@@ -622,7 +622,6 @@
 
 		/* Donot wait, imaging server may have crashed */
 		msm_post_event(&event, MSM_POST_EVT_TIMEOUT);
-
 		msm_delete_command_ack_q(pvdev->vdev->num,
 			sp->stream_id);
 
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 b31b3f1..ff9c9b8 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp.c
@@ -121,6 +121,7 @@
 	vfe_dev->subdev.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV;
 	vfe_dev->subdev.sd.entity.group_id = MSM_CAMERA_SUBDEV_VFE;
 	vfe_dev->subdev.sd.entity.name = pdev->name;
+	vfe_dev->subdev.close_seq = MSM_SD_CLOSE_1ST_CATEGORY | 0x2;
 	rc = msm_sd_register(&vfe_dev->subdev);
 	if (rc != 0) {
 		pr_err("%s: msm_sd_register error = %d\n", __func__, rc);
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 c4a1b63..7bf8511 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
@@ -29,8 +29,9 @@
 #define CDBG(fmt, args...) do { } while (0)
 #endif
 
-#define VFE40_V1_VERSION 0x10000018
-#define VFE40_V2_VERSION 0x1001001A
+#define VFE40_8974V1_VERSION 0x10000018
+#define VFE40_8974V2_VERSION 0x1001001A
+#define VFE40_8x26_VERSION 0x20000013
 
 #define VFE40_BURST_LEN 3
 #define VFE40_STATS_BURST_LEN 2
@@ -90,7 +91,8 @@
 static void msm_vfe40_init_qos_parms(struct vfe_device *vfe_dev)
 {
 	void __iomem *vfebase = vfe_dev->vfe_base;
-	if (vfe_dev->vfe_hw_version == VFE40_V1_VERSION) {
+	if (vfe_dev->vfe_hw_version == VFE40_8974V1_VERSION ||
+		vfe_dev->vfe_hw_version == VFE40_8x26_VERSION) {
 		msm_camera_io_w(0xAAAAAAAA, vfebase + VFE40_BUS_BDG_QOS_CFG_0);
 		msm_camera_io_w(0xAAAAAAAA, vfebase + VFE40_BUS_BDG_QOS_CFG_1);
 		msm_camera_io_w(0xAAAAAAAA, vfebase + VFE40_BUS_BDG_QOS_CFG_2);
@@ -99,7 +101,7 @@
 		msm_camera_io_w(0xAAAAAAAA, vfebase + VFE40_BUS_BDG_QOS_CFG_5);
 		msm_camera_io_w(0xAAAAAAAA, vfebase + VFE40_BUS_BDG_QOS_CFG_6);
 		msm_camera_io_w(0x0002AAAA, vfebase + VFE40_BUS_BDG_QOS_CFG_7);
-	} else if (vfe_dev->vfe_hw_version == VFE40_V2_VERSION) {
+	} else if (vfe_dev->vfe_hw_version == VFE40_8974V2_VERSION) {
 		msm_camera_io_w(0xAAA9AAA9, vfebase + VFE40_BUS_BDG_QOS_CFG_0);
 		msm_camera_io_w(0xAAA9AAA9, vfebase + VFE40_BUS_BDG_QOS_CFG_1);
 		msm_camera_io_w(0xAAA9AAA9, vfebase + VFE40_BUS_BDG_QOS_CFG_2);
@@ -108,81 +110,138 @@
 		msm_camera_io_w(0xAAA9AAA9, vfebase + VFE40_BUS_BDG_QOS_CFG_5);
 		msm_camera_io_w(0xAAA9AAA9, vfebase + VFE40_BUS_BDG_QOS_CFG_6);
 		msm_camera_io_w(0x0001AAA9, vfebase + VFE40_BUS_BDG_QOS_CFG_7);
+	} else {
+		BUG();
+		pr_err("%s: QOS is NOT configured for HW Version %x\n",
+			__func__, vfe_dev->vfe_hw_version);
 	}
 }
 
+static void msm_vfe40_init_vbif_parms_8974_v1(struct vfe_device *vfe_dev)
+{
+	void __iomem *vfe_vbif_base = vfe_dev->vfe_vbif_base;
+	msm_camera_io_w(0x1,
+		vfe_vbif_base + VFE40_VBIF_CLKON);
+	msm_camera_io_w(0x01010101,
+		vfe_vbif_base + VFE40_VBIF_IN_RD_LIM_CONF0);
+	msm_camera_io_w(0x01010101,
+		vfe_vbif_base + VFE40_VBIF_IN_RD_LIM_CONF1);
+	msm_camera_io_w(0x10010110,
+		vfe_vbif_base + VFE40_VBIF_IN_RD_LIM_CONF2);
+	msm_camera_io_w(0x10101010,
+		vfe_vbif_base + VFE40_VBIF_IN_WR_LIM_CONF0);
+	msm_camera_io_w(0x10101010,
+		vfe_vbif_base + VFE40_VBIF_IN_WR_LIM_CONF1);
+	msm_camera_io_w(0x10101010,
+		vfe_vbif_base + VFE40_VBIF_IN_WR_LIM_CONF2);
+	msm_camera_io_w(0x00001010,
+		vfe_vbif_base + VFE40_VBIF_OUT_RD_LIM_CONF0);
+	msm_camera_io_w(0x00001010,
+		vfe_vbif_base + VFE40_VBIF_OUT_WR_LIM_CONF0);
+	msm_camera_io_w(0x00000707,
+		vfe_vbif_base + VFE40_VBIF_DDR_OUT_MAX_BURST);
+	msm_camera_io_w(0x00000707,
+		vfe_vbif_base + VFE40_VBIF_OCMEM_OUT_MAX_BURST);
+	msm_camera_io_w(0x00000030,
+		vfe_vbif_base + VFE40_VBIF_ARB_CTL);
+	msm_camera_io_w(0x00000FFF,
+		vfe_vbif_base + VFE40_VBIF_OUT_AXI_AOOO_EN);
+	msm_camera_io_w(0x0FFF0FFF,
+		vfe_vbif_base + VFE40_VBIF_OUT_AXI_AOOO);
+	msm_camera_io_w(0x00000001,
+		vfe_vbif_base + VFE40_VBIF_ROUND_ROBIN_QOS_ARB);
+	msm_camera_io_w(0x22222222,
+		vfe_vbif_base + VFE40_VBIF_OUT_AXI_AMEMTYPE_CONF0);
+	msm_camera_io_w(0x00002222,
+		vfe_vbif_base + VFE40_VBIF_OUT_AXI_AMEMTYPE_CONF1);
+	return;
+}
+
+static void msm_vfe40_init_vbif_parms_8974_v2(struct vfe_device *vfe_dev)
+{
+	void __iomem *vfe_vbif_base = vfe_dev->vfe_vbif_base;
+	msm_camera_io_w(0x1,
+		vfe_vbif_base + VFE40_VBIF_CLKON);
+	msm_camera_io_w(0x10101010,
+		vfe_vbif_base + VFE40_VBIF_IN_RD_LIM_CONF0);
+	msm_camera_io_w(0x10101010,
+		vfe_vbif_base + VFE40_VBIF_IN_RD_LIM_CONF1);
+	msm_camera_io_w(0x10101010,
+		vfe_vbif_base + VFE40_VBIF_IN_RD_LIM_CONF2);
+	msm_camera_io_w(0x10101010,
+		vfe_vbif_base + VFE40_VBIF_IN_WR_LIM_CONF0);
+	msm_camera_io_w(0x10101010,
+		vfe_vbif_base + VFE40_VBIF_IN_WR_LIM_CONF1);
+	msm_camera_io_w(0x10101010,
+		vfe_vbif_base + VFE40_VBIF_IN_WR_LIM_CONF2);
+	msm_camera_io_w(0x00000010,
+		vfe_vbif_base + VFE40_VBIF_OUT_RD_LIM_CONF0);
+	msm_camera_io_w(0x00000010,
+		vfe_vbif_base + VFE40_VBIF_OUT_WR_LIM_CONF0);
+	msm_camera_io_w(0x00000707,
+		vfe_vbif_base + VFE40_VBIF_DDR_OUT_MAX_BURST);
+	msm_camera_io_w(0x00000010,
+		vfe_vbif_base + VFE40_VBIF_ARB_CTL);
+	msm_camera_io_w(0x00000FFF,
+		vfe_vbif_base + VFE40_VBIF_OUT_AXI_AOOO_EN);
+	msm_camera_io_w(0x0FFF0FFF,
+		vfe_vbif_base + VFE40_VBIF_OUT_AXI_AOOO);
+	msm_camera_io_w(0x00000003,
+		vfe_vbif_base + VFE40_VBIF_ROUND_ROBIN_QOS_ARB);
+	msm_camera_io_w(0x22222222,
+		vfe_vbif_base + VFE40_VBIF_OUT_AXI_AMEMTYPE_CONF0);
+	msm_camera_io_w(0x00002222,
+		vfe_vbif_base + VFE40_VBIF_OUT_AXI_AMEMTYPE_CONF1);
+	return;
+}
+
+static void msm_vfe40_init_vbif_parms_8x26(struct vfe_device *vfe_dev)
+{
+	void __iomem *vfe_vbif_base = vfe_dev->vfe_vbif_base;
+	msm_camera_io_w(0x10101010,
+		vfe_vbif_base + VFE40_VBIF_IN_RD_LIM_CONF0);
+	msm_camera_io_w(0x10101010,
+		vfe_vbif_base + VFE40_VBIF_IN_RD_LIM_CONF1);
+	msm_camera_io_w(0x10101010,
+		vfe_vbif_base + VFE40_VBIF_IN_WR_LIM_CONF0);
+	msm_camera_io_w(0x10101010,
+		vfe_vbif_base + VFE40_VBIF_IN_WR_LIM_CONF1);
+	msm_camera_io_w(0x00000010,
+		vfe_vbif_base + VFE40_VBIF_OUT_RD_LIM_CONF0);
+	msm_camera_io_w(0x00000010,
+		vfe_vbif_base + VFE40_VBIF_OUT_WR_LIM_CONF0);
+	msm_camera_io_w(0x00000707,
+		vfe_vbif_base + VFE40_VBIF_DDR_OUT_MAX_BURST);
+	msm_camera_io_w(0x000000FF,
+		vfe_vbif_base + VFE40_VBIF_OUT_AXI_AOOO_EN);
+	msm_camera_io_w(0x00FF00FF,
+		vfe_vbif_base + VFE40_VBIF_OUT_AXI_AOOO);
+	msm_camera_io_w(0x00000003,
+		vfe_vbif_base + VFE40_VBIF_ROUND_ROBIN_QOS_ARB);
+	msm_camera_io_w(0x22222222,
+		vfe_vbif_base + VFE40_VBIF_OUT_AXI_AMEMTYPE_CONF0);
+	return;
+}
+
 static void msm_vfe40_init_vbif_parms(struct vfe_device *vfe_dev)
 {
-	void __iomem *vfe_vbif_base = vfe_dev->vfe_vbif_base;
-	if (vfe_dev->vfe_hw_version == VFE40_V1_VERSION) {
-		msm_camera_io_w(0x1,
-			vfe_vbif_base + VFE40_VBIF_CLKON);
-		msm_camera_io_w(0x01010101,
-			vfe_vbif_base + VFE40_VBIF_IN_RD_LIM_CONF0);
-		msm_camera_io_w(0x01010101,
-			vfe_vbif_base + VFE40_VBIF_IN_RD_LIM_CONF1);
-		msm_camera_io_w(0x10010110,
-			vfe_vbif_base + VFE40_VBIF_IN_RD_LIM_CONF2);
-		msm_camera_io_w(0x10101010,
-			vfe_vbif_base + VFE40_VBIF_IN_WR_LIM_CONF0);
-		msm_camera_io_w(0x10101010,
-			vfe_vbif_base + VFE40_VBIF_IN_WR_LIM_CONF1);
-		msm_camera_io_w(0x10101010,
-			vfe_vbif_base + VFE40_VBIF_IN_WR_LIM_CONF2);
-		msm_camera_io_w(0x00001010,
-			vfe_vbif_base + VFE40_VBIF_OUT_RD_LIM_CONF0);
-		msm_camera_io_w(0x00001010,
-			vfe_vbif_base + VFE40_VBIF_OUT_WR_LIM_CONF0);
-		msm_camera_io_w(0x00000707,
-			vfe_vbif_base + VFE40_VBIF_DDR_OUT_MAX_BURST);
-		msm_camera_io_w(0x00000707,
-			vfe_vbif_base + VFE40_VBIF_OCMEM_OUT_MAX_BURST);
-		msm_camera_io_w(0x00000030,
-			vfe_vbif_base + VFE40_VBIF_ARB_CTL);
-		msm_camera_io_w(0x00000FFF,
-			vfe_vbif_base + VFE40_VBIF_OUT_AXI_AOOO_EN);
-		msm_camera_io_w(0x0FFF0FFF,
-			vfe_vbif_base + VFE40_VBIF_OUT_AXI_AOOO);
-		msm_camera_io_w(0x00000001,
-			vfe_vbif_base + VFE40_VBIF_ROUND_ROBIN_QOS_ARB);
-		msm_camera_io_w(0x22222222,
-			vfe_vbif_base + VFE40_VBIF_OUT_AXI_AMEMTYPE_CONF0);
-		msm_camera_io_w(0x00002222,
-			vfe_vbif_base + VFE40_VBIF_OUT_AXI_AMEMTYPE_CONF1);
-	} else if (vfe_dev->vfe_hw_version == VFE40_V2_VERSION) {
-		msm_camera_io_w(0x1,
-			vfe_vbif_base + VFE40_VBIF_CLKON);
-		msm_camera_io_w(0x10101010,
-			vfe_vbif_base + VFE40_VBIF_IN_RD_LIM_CONF0);
-		msm_camera_io_w(0x10101010,
-			vfe_vbif_base + VFE40_VBIF_IN_RD_LIM_CONF1);
-		msm_camera_io_w(0x10101010,
-			vfe_vbif_base + VFE40_VBIF_IN_RD_LIM_CONF2);
-		msm_camera_io_w(0x10101010,
-			vfe_vbif_base + VFE40_VBIF_IN_WR_LIM_CONF0);
-		msm_camera_io_w(0x10101010,
-			vfe_vbif_base + VFE40_VBIF_IN_WR_LIM_CONF1);
-		msm_camera_io_w(0x10101010,
-			vfe_vbif_base + VFE40_VBIF_IN_WR_LIM_CONF2);
-		msm_camera_io_w(0x00000010,
-			vfe_vbif_base + VFE40_VBIF_OUT_RD_LIM_CONF0);
-		msm_camera_io_w(0x00000010,
-			vfe_vbif_base + VFE40_VBIF_OUT_WR_LIM_CONF0);
-		msm_camera_io_w(0x00000707,
-			vfe_vbif_base + VFE40_VBIF_DDR_OUT_MAX_BURST);
-		msm_camera_io_w(0x00000010,
-			vfe_vbif_base + VFE40_VBIF_ARB_CTL);
-		msm_camera_io_w(0x00000FFF,
-			vfe_vbif_base + VFE40_VBIF_OUT_AXI_AOOO_EN);
-		msm_camera_io_w(0x0FFF0FFF,
-			vfe_vbif_base + VFE40_VBIF_OUT_AXI_AOOO);
-		msm_camera_io_w(0x00000003,
-			vfe_vbif_base + VFE40_VBIF_ROUND_ROBIN_QOS_ARB);
-		msm_camera_io_w(0x22222222,
-			vfe_vbif_base + VFE40_VBIF_OUT_AXI_AMEMTYPE_CONF0);
-		msm_camera_io_w(0x00002222,
-			vfe_vbif_base + VFE40_VBIF_OUT_AXI_AMEMTYPE_CONF1);
+	switch (vfe_dev->vfe_hw_version) {
+	case VFE40_8974V1_VERSION:
+		msm_vfe40_init_vbif_parms_8974_v1(vfe_dev);
+		break;
+	case VFE40_8974V2_VERSION:
+		msm_vfe40_init_vbif_parms_8974_v2(vfe_dev);
+		break;
+	case VFE40_8x26_VERSION:
+		msm_vfe40_init_vbif_parms_8x26(vfe_dev);
+		break;
+	default:
+		BUG();
+		pr_err("%s: VBIF is NOT configured for HW Version %x\n",
+			__func__, vfe_dev->vfe_hw_version);
+		break;
 	}
+
 }
 
 static int msm_vfe40_init_hardware(struct vfe_device *vfe_dev)
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 dd8db03..ee205c0 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
@@ -389,6 +389,11 @@
 		rc = msm_isp_update_axi_stream(vfe_dev, arg);
 		mutex_unlock(&vfe_dev->core_mutex);
 		break;
+	case MSM_SD_SHUTDOWN:
+		while (vfe_dev->vfe_open_cnt != 0)
+			msm_isp_close_node(sd, NULL);
+		break;
+
 	default:
 		pr_err("%s: Invalid ISP command\n", __func__);
 		rc = -EINVAL;
@@ -912,11 +917,10 @@
 
 	rc = vfe_dev->hw_info->vfe_ops.axi_ops.halt(vfe_dev);
 	if (rc <= 0)
-		pr_err("%s: halt timeout\n", __func__);
+		pr_err("%s: halt timeout rc=%ld\n", __func__, rc);
 
 	vfe_dev->buf_mgr->ops->buf_mgr_deinit(vfe_dev->buf_mgr);
 	vfe_dev->hw_info->vfe_ops.core_ops.release_hw(vfe_dev);
-
 	vfe_dev->vfe_open_cnt--;
 	mutex_unlock(&vfe_dev->core_mutex);
 	mutex_unlock(&vfe_dev->realtime_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 a95eda7..dc1bcc3 100644
--- a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c
+++ b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c
@@ -91,7 +91,6 @@
 	BUG_ON(!ispif);
 
 	memset(ispif->sof_count, 0, sizeof(ispif->sof_count));
-
 	for (i = 0; i < ispif->vfe_info.num_vfe; i++) {
 
 		msm_camera_io_w(1 << PIX0_LINE_BUF_EN_BIT,
@@ -105,9 +104,13 @@
 			ISPIF_VFE_m_IRQ_CLEAR_1(i));
 		msm_camera_io_w(0xFFFFFFFF, ispif->base +
 			ISPIF_VFE_m_IRQ_CLEAR_2(i));
+
 		msm_camera_io_w(0, ispif->base + ISPIF_VFE_m_INPUT_SEL(i));
-		msm_camera_io_w(0, ispif->base + ISPIF_VFE_m_INTF_CMD_0(i));
-		msm_camera_io_w(0, ispif->base + ISPIF_VFE_m_INTF_CMD_1(i));
+
+		msm_camera_io_w(ISPIF_STOP_INTF_IMMEDIATELY,
+			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));
 
 		msm_camera_io_w(0, ispif->base +
 			ISPIF_VFE_m_PIX_INTF_n_CID_MASK(i, 0));
@@ -905,6 +908,12 @@
 	switch (cmd) {
 	case VIDIOC_MSM_ISPIF_CFG:
 		return msm_ispif_cmd(sd, arg);
+	case MSM_SD_SHUTDOWN: {
+		struct ispif_device *ispif =
+			(struct ispif_device *)v4l2_get_subdevdata(sd);
+		msm_ispif_release(ispif);
+		return 0;
+	}
 	default:
 		pr_err("%s: invalid cmd 0x%x received\n", __func__, cmd);
 		return -ENOIOCTLCMD;
@@ -986,6 +995,7 @@
 	ispif->msm_sd.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV;
 	ispif->msm_sd.sd.entity.group_id = MSM_CAMERA_SUBDEV_ISPIF;
 	ispif->msm_sd.sd.entity.name = pdev->name;
+	ispif->msm_sd.close_seq = MSM_SD_CLOSE_1ST_CATEGORY | 0x1;
 	rc = msm_sd_register(&ispif->msm_sd);
 	if (rc) {
 		pr_err("%s: msm_sd_register error = %d\n", __func__, rc);
diff --git a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif_hwreg_v2.h b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif_hwreg_v2.h
index c805c3d..3cc21a7 100644
--- a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif_hwreg_v2.h
+++ b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif_hwreg_v2.h
@@ -91,4 +91,6 @@
 
 #define ISPIF_IRQ_GLOBAL_CLEAR_CMD               0x1
 
+#define ISPIF_STOP_INTF_IMMEDIATELY              0xAAAAAAAA
+
 #endif /* __MSM_ISPIF_HWREG_V2_H__ */
diff --git a/drivers/media/platform/msm/camera_v2/msm.c b/drivers/media/platform/msm/camera_v2/msm.c
index be9f613..5581723 100644
--- a/drivers/media/platform/msm/camera_v2/msm.c
+++ b/drivers/media/platform/msm/camera_v2/msm.c
@@ -31,6 +31,7 @@
 #include "msm_sd.h"
 
 static struct v4l2_device *msm_v4l2_dev;
+static struct list_head    ordered_sd_list;
 
 static struct msm_queue_head *msm_session_q;
 
@@ -301,6 +302,20 @@
 	return rc;
 }
 
+static void msm_add_sd_in_position(struct msm_sd_subdev *msm_subdev,
+	struct list_head *sd_list)
+{
+	struct msm_sd_subdev *temp_sd;
+
+	list_for_each_entry(temp_sd, sd_list, list) {
+		if (msm_subdev->close_seq < temp_sd->close_seq) {
+			list_add_tail(&msm_subdev->list, &temp_sd->list);
+			return;
+		}
+	}
+	list_add_tail(&msm_subdev->list, sd_list);
+}
+
 int msm_sd_register(struct msm_sd_subdev *msm_subdev)
 {
 	if (WARN_ON(!msm_subdev))
@@ -309,6 +324,7 @@
 	if (WARN_ON(!msm_v4l2_dev) || WARN_ON(!msm_v4l2_dev->dev))
 		return -EIO;
 
+	msm_add_sd_in_position(msm_subdev, &ordered_sd_list);
 	return __msm_sd_register_subdev(&msm_subdev->sd);
 }
 
@@ -397,66 +413,40 @@
 
 	spin_lock_irqsave(&(session->command_ack_q.lock), flags);
 	list_del_init(&cmd_ack->list);
+	kzfree(cmd_ack);
 	session->command_ack_q.len--;
 	spin_unlock_irqrestore(&(session->command_ack_q.lock), flags);
 }
 
-static inline int __msm_v4l2_subdev_shutdown(struct v4l2_subdev *sd)
-{
-	return 0;
-}
-
-static void msm_sd_try_shutdown(void)
-{
-	unsigned long flags;
-	struct v4l2_subdev *sd;
-
-	/* release all subdev's resource */
-	spin_lock_irqsave(&msm_v4l2_dev->lock, flags);
-	if (!list_empty(&msm_v4l2_dev->subdevs)) {
-		list_for_each_entry(sd, &msm_v4l2_dev->subdevs, list)
-			__msm_v4l2_subdev_shutdown(sd);
-	}
-	spin_unlock_irqrestore(&msm_v4l2_dev->lock, flags);
-}
-
-static inline int __msm_sd_close_session_streams(struct v4l2_subdev *sd,
+static inline int __msm_sd_close_subdevs(struct msm_sd_subdev *msm_sd,
 	struct msm_sd_close_ioctl *sd_close)
 {
+	struct v4l2_subdev *sd;
+	sd = &msm_sd->sd;
+	pr_debug("%s: Shutting down subdev %s", __func__, sd->name);
+
+	v4l2_subdev_call(sd, core, ioctl, MSM_SD_SHUTDOWN, sd_close);
+	v4l2_subdev_call(sd, core, s_power, 0);
+
 	return 0;
 }
 
 static inline int __msm_destroy_session_streams(void *d1, void *d2)
 {
 	struct msm_stream *stream = d1;
-	struct msm_sd_close_ioctl *sd_close = d2;
-	struct v4l2_subdev *sd;
-	unsigned long flags;
 
-	sd_close->stream = stream->stream_id;
-
-	spin_lock_irqsave(&msm_v4l2_dev->lock, flags);
-	if (!list_empty(&msm_v4l2_dev->subdevs))
-		list_for_each_entry(sd, &msm_v4l2_dev->subdevs, list)
-			__msm_sd_close_session_streams(sd, sd_close);
-	spin_unlock_irqrestore(&msm_v4l2_dev->lock, flags);
 	INIT_LIST_HEAD(&stream->queued_list);
 	return 0;
 }
 
 static void msm_destroy_session_streams(struct msm_session *session)
 {
-	struct msm_sd_close_ioctl sd_close;
 
-	/* to ensure error handling purpose, it needs to detach all subdevs
-	 * which are being connected to streams */
 	if (!session)
 		return;
 
-	sd_close.session = session->session_id;
-
 	msm_queue_traverse_action(&session->stream_q, struct msm_stream, list,
-		__msm_destroy_session_streams, &sd_close);
+		__msm_destroy_session_streams, NULL);
 
 	msm_queue_drain(&session->stream_q, struct msm_stream, list);
 }
@@ -694,16 +684,13 @@
 	struct msm_v4l2_event_data *event_data =
 		(struct msm_v4l2_event_data *)&event.u.data[0];
 	struct msm_session *session = d1;
-	mutex_lock(&session->lock);
+
 	event.type = MSM_CAMERA_V4L2_EVENT_TYPE;
 	event.id   = MSM_CAMERA_MSM_NOTIFY;
 	event_data->command = MSM_CAMERA_PRIV_SHUTDOWN;
 
 	v4l2_event_queue(session->event_q.vdev, &event);
 
-	msm_destroy_session_streams(session);
-	msm_remove_session_cmd_ack_q(session);
-	mutex_unlock(&session->lock);
 	return 0;
 }
 
@@ -712,22 +699,23 @@
 	int rc = 0;
 	unsigned long flags;
 	struct msm_video_device *pvdev = video_drvdata(filep);
+	struct msm_sd_close_ioctl sd_close;
+	struct msm_sd_subdev *msm_sd;
 
-	/* 1st thing 1st, send v4l2_event to HAL immediately,
-	 * to ensure error handling purpose, it needs to detach all subdevs
-	 * which are being connected to streams */
+	/*stop all hardware blocks immediately*/
+	if (!list_empty(&msm_v4l2_dev->subdevs))
+		list_for_each_entry(msm_sd, &ordered_sd_list, list)
+			__msm_sd_close_subdevs(msm_sd, &sd_close);
+
+	/* send v4l2_event to HAL next*/
 	msm_queue_traverse_action(msm_session_q, struct msm_session, list,
 		__msm_close_destry_session_notify_apps, NULL);
 
-	msm_queue_drain(msm_session_q, struct msm_session, list);
-
 	spin_lock_irqsave(&msm_eventq_lock, flags);
 	msm_eventq = NULL;
 	spin_unlock_irqrestore(&msm_eventq_lock, flags);
 	v4l2_fh_release(filep);
 
-	msm_sd_try_shutdown();
-
 	spin_lock_irqsave(&msm_pid_lock, flags);
 	put_pid(msm_pid);
 	msm_pid = NULL;
@@ -754,7 +742,6 @@
 	int rc;
 	unsigned long flags;
 	struct msm_video_device *pvdev = video_drvdata(filep);
-
 	BUG_ON(!pvdev);
 
 	/* !!! only ONE open is allowed !!! */
@@ -990,7 +977,7 @@
 	msm_init_queue(msm_session_q);
 	spin_lock_init(&msm_eventq_lock);
 	spin_lock_init(&msm_pid_lock);
-
+	INIT_LIST_HEAD(&ordered_sd_list);
 	goto probe_end;
 
 v4l2_fail:
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 b0ff832..895f452 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
@@ -161,6 +161,7 @@
 	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.close_seq = MSM_SD_CLOSE_4TH_CATEGORY;
 	rc = msm_sd_register(&msm_buf_mngr_dev->subdev);
 	if (rc != 0) {
 		pr_err("%s: msm_sd_register error = %d\n", __func__, rc);
diff --git a/drivers/media/platform/msm/camera_v2/msm_sd.h b/drivers/media/platform/msm/camera_v2/msm_sd.h
index 958e030..7c1519d 100644
--- a/drivers/media/platform/msm/camera_v2/msm_sd.h
+++ b/drivers/media/platform/msm/camera_v2/msm_sd.h
@@ -50,10 +50,12 @@
 #define MSM_SD_CLOSE_1ST_CATEGORY  0x00010000
 #define MSM_SD_CLOSE_2ND_CATEGORY  0x00020000
 #define MSM_SD_CLOSE_3RD_CATEGORY  0x00030000
+#define MSM_SD_CLOSE_4TH_CATEGORY  0x00040000
 
 struct msm_sd_subdev {
 	struct v4l2_subdev sd;
 	int close_seq;
+	struct list_head list;
 };
 
 struct msm_sd_req_sd {
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 5a174f5..4dd3f3d 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
@@ -43,6 +43,9 @@
 
 #define CONFIG_MSM_CPP_DBG 0
 
+/* dump the frame command before writing to the hardware */
+#define  MSM_CPP_DUMP_FRM_CMD 0
+
 #if CONFIG_MSM_CPP_DBG
 #define CPP_DBG(fmt, args...) pr_err(fmt, ##args)
 #else
@@ -208,7 +211,6 @@
 		pr_err("ION import failed\n");
 		goto QUEUE_BUFF_ERROR1;
 	}
-
 	rc = ion_map_iommu(cpp_dev->client, buff->map_info.ion_handle,
 		cpp_dev->domain_num, 0, SZ_4K, 0,
 		(unsigned long *)&buff->map_info.phy_addr,
@@ -237,6 +239,7 @@
 static void msm_cpp_dequeue_buffer_info(struct cpp_device *cpp_dev,
 	struct msm_cpp_buffer_map_list_t *buff)
 {
+
 	ion_unmap_iommu(cpp_dev->client, buff->map_info.ion_handle,
 		cpp_dev->domain_num, 0);
 	ion_free(cpp_dev->client, buff->map_info.ion_handle);
@@ -390,6 +393,8 @@
 			pr_err("Queue not free sessionid: %d, streamid: %d\n",
 				cpp_dev->buff_queue[i].session_id,
 				cpp_dev->buff_queue[i].stream_id);
+			msm_cpp_dequeue_buff_info_list
+				(cpp_dev, &cpp_dev->buff_queue[i]);
 			msm_cpp_free_buff_queue_entry(cpp_dev,
 				cpp_dev->buff_queue[i].session_id,
 				cpp_dev->buff_queue[i].stream_id);
@@ -821,9 +826,16 @@
 {
 	uint32_t i;
 	struct cpp_device *cpp_dev = v4l2_get_subdevdata(sd);
+
 	mutex_lock(&cpp_dev->mutex);
+
+	if (cpp_dev->cpp_open_cnt == 0) {
+		mutex_unlock(&cpp_dev->mutex);
+		return 0;
+	}
+
 	for (i = 0; i < MAX_ACTIVE_CPP_INSTANCE; i++) {
-		if (cpp_dev->cpp_subscribe_list[i].vfh == &fh->vfh) {
+		if (cpp_dev->cpp_subscribe_list[i].active == 1) {
 			cpp_dev->cpp_subscribe_list[i].active = 0;
 			cpp_dev->cpp_subscribe_list[i].vfh = NULL;
 			break;
@@ -835,7 +847,6 @@
 		return -ENODEV;
 	}
 
-	CPP_DBG("close %d %p\n", i, &fh->vfh);
 	cpp_dev->cpp_open_cnt--;
 	if (cpp_dev->cpp_open_cnt == 0) {
 		msm_camera_io_w(0x0, cpp_dev->base + MSM_CPP_MICRO_CLKEN_CTL);
@@ -843,6 +854,7 @@
 		cpp_release_hardware(cpp_dev);
 		cpp_dev->state = CPP_STATE_OFF;
 	}
+
 	mutex_unlock(&cpp_dev->mutex);
 	return 0;
 }
@@ -888,8 +900,7 @@
 		event_qcmd->command = processed_frame;
 		CPP_DBG("fid %d\n", processed_frame->frame_id);
 		msm_enqueue(&cpp_dev->eventData_q, &event_qcmd->list_eventdata);
-
-		if (!processed_frame->output_buffer_info.processed_divert) {
+		if (!processed_frame->output_buffer_info[0].processed_divert) {
 			memset(&buff_mgr_info, 0 ,
 				sizeof(struct msm_buf_mngr_info));
 			buff_mgr_info.session_id =
@@ -899,7 +910,7 @@
 			buff_mgr_info.frame_id = processed_frame->frame_id;
 			buff_mgr_info.timestamp = processed_frame->timestamp;
 			buff_mgr_info.index =
-				processed_frame->output_buffer_info.index;
+				processed_frame->output_buffer_info[0].index;
 			rc = msm_cpp_buffer_ops(cpp_dev,
 				VIDIOC_MSM_BUF_MNGR_BUF_DONE,
 				&buff_mgr_info);
@@ -908,6 +919,28 @@
 				rc = -EINVAL;
 			}
 		}
+
+		if (processed_frame->duplicate_output  &&
+			!processed_frame->
+				output_buffer_info[1].processed_divert) {
+			memset(&buff_mgr_info, 0 ,
+				sizeof(struct msm_buf_mngr_info));
+			buff_mgr_info.session_id =
+			((processed_frame->duplicate_identity >> 16) & 0xFFFF);
+			buff_mgr_info.stream_id =
+				(processed_frame->duplicate_identity & 0xFFFF);
+			buff_mgr_info.frame_id = processed_frame->frame_id;
+			buff_mgr_info.timestamp = processed_frame->timestamp;
+			buff_mgr_info.index =
+				processed_frame->output_buffer_info[1].index;
+			rc = msm_cpp_buffer_ops(cpp_dev,
+				VIDIOC_MSM_BUF_MNGR_BUF_DONE,
+					&buff_mgr_info);
+			if (rc < 0) {
+				pr_err("error putting buffer\n");
+				rc = -EINVAL;
+			}
+		}
 		v4l2_evt.id = processed_frame->inst_id;
 		v4l2_evt.type = V4L2_EVENT_CPP_FRAME_DONE;
 		v4l2_event_queue(cpp_dev->msm_sd.sd.devnode, &v4l2_evt);
@@ -915,6 +948,23 @@
 	return rc;
 }
 
+#if MSM_CPP_DUMP_FRM_CMD
+static int msm_cpp_dump_frame_cmd(uint32_t *cmd, int32_t len)
+{
+	int i;
+	pr_err("%s: -------- cpp frame cmd msg start --------", __func__);
+	for (i = 0; i < len; i++)
+		pr_err("%s: msg[%03d] = 0x%08x", __func__, i, cmd[i]);
+	pr_err("%s: --------- cpp frame cmd msg end ---------", __func__);
+	return 0;
+}
+#else
+static int msm_cpp_dump_frame_cmd(uint32_t *cmd, int32_t len)
+{
+	return 0;
+}
+#endif
+
 static int msm_cpp_send_frame_to_hardware(struct cpp_device *cpp_dev,
 	struct msm_queue_cmd *frame_qcmd)
 {
@@ -927,6 +977,8 @@
 		msm_enqueue(&cpp_dev->processing_q,
 					&frame_qcmd->list_frame);
 		msm_cpp_write(0x6, cpp_dev->base);
+		msm_cpp_dump_frame_cmd(process_frame->cpp_cmd_msg,
+				process_frame->msg_len);
 		for (i = 0; i < process_frame->msg_len; i++)
 			msm_cpp_write(process_frame->cpp_cmd_msg[i],
 				cpp_dev->base);
@@ -951,7 +1003,7 @@
 	struct msm_cpp_frame_info_t *new_frame =
 		kzalloc(sizeof(struct msm_cpp_frame_info_t), GFP_KERNEL);
 	uint32_t *cpp_frame_msg;
-	unsigned long in_phyaddr, out_phyaddr;
+	unsigned long in_phyaddr, out_phyaddr0, out_phyaddr1;
 	uint16_t num_stripes = 0;
 	struct msm_buf_mngr_info buff_mgr_info;
 	struct msm_cpp_frame_info_t *u_frame_info =
@@ -1001,7 +1053,7 @@
 		goto ERROR2;
 	}
 
-	memset(&new_frame->output_buffer_info, 0,
+	memset(&new_frame->output_buffer_info[0], 0,
 		sizeof(struct msm_cpp_buffer_info_t));
 	memset(&buff_mgr_info, 0, sizeof(struct msm_buf_mngr_info));
 	buff_mgr_info.session_id = ((new_frame->identity >> 16) & 0xFFFF);
@@ -1013,17 +1065,49 @@
 		pr_debug("error getting buffer rc:%d\n", rc);
 		goto ERROR2;
 	}
-
-	new_frame->output_buffer_info.index = buff_mgr_info.index;
-	out_phyaddr = msm_cpp_fetch_buffer_info(cpp_dev,
-		&new_frame->output_buffer_info,
+	new_frame->output_buffer_info[0].index = buff_mgr_info.index;
+	out_phyaddr0 = msm_cpp_fetch_buffer_info(cpp_dev,
+		&new_frame->output_buffer_info[0],
 		((new_frame->identity >> 16) & 0xFFFF),
 		(new_frame->identity & 0xFFFF));
-	if (!out_phyaddr) {
+	if (!out_phyaddr0) {
 		pr_err("error gettting output physical address\n");
 		rc = -EINVAL;
 		goto ERROR3;
 	}
+	out_phyaddr1 = out_phyaddr0;
+
+	/* get buffer for duplicate output */
+	if (new_frame->duplicate_output) {
+		CPP_DBG("duplication enabled, dup_id=0x%x",
+			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 =
+			((new_frame->duplicate_identity >> 16) & 0xFFFF);
+		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);
+		if (rc < 0) {
+			rc = -EAGAIN;
+			pr_err("error getting buffer rc:%d\n", rc);
+			goto ERROR2;
+		}
+		new_frame->output_buffer_info[1].index = 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),
+			(new_frame->duplicate_identity & 0xFFFF));
+		if (!out_phyaddr1) {
+			pr_err("error gettting output physical address\n");
+			rc = -EINVAL;
+			goto ERROR3;
+		}
+		/* set duplicate enable bit */
+		cpp_frame_msg[5] |= 0x1;
+	}
 
 	num_stripes = ((cpp_frame_msg[12] >> 20) & 0x3FF) +
 		((cpp_frame_msg[12] >> 10) & 0x3FF) +
@@ -1031,10 +1115,10 @@
 
 	for (i = 0; i < num_stripes; i++) {
 		cpp_frame_msg[133 + i * 27] += (uint32_t) in_phyaddr;
-		cpp_frame_msg[139 + i * 27] += (uint32_t) out_phyaddr;
-		cpp_frame_msg[140 + i * 27] += (uint32_t) out_phyaddr;
-		cpp_frame_msg[141 + i * 27] += (uint32_t) out_phyaddr;
-		cpp_frame_msg[142 + i * 27] += (uint32_t) out_phyaddr;
+		cpp_frame_msg[139 + i * 27] += (uint32_t) out_phyaddr0;
+		cpp_frame_msg[140 + i * 27] += (uint32_t) out_phyaddr1;
+		cpp_frame_msg[141 + i * 27] += (uint32_t) out_phyaddr0;
+		cpp_frame_msg[142 + i * 27] += (uint32_t) out_phyaddr1;
 	}
 
 	frame_qcmd = kzalloc(sizeof(struct msm_queue_cmd), GFP_KERNEL);
@@ -1245,6 +1329,13 @@
 		kfree(event_qcmd);
 		break;
 	}
+	case MSM_SD_SHUTDOWN: {
+		mutex_unlock(&cpp_dev->mutex);
+		while (cpp_dev->cpp_open_cnt != 0)
+			cpp_close_node(sd, NULL);
+		rc = 0;
+		break;
+	}
 	}
 	mutex_unlock(&cpp_dev->mutex);
 	CPP_DBG("X\n");
@@ -1446,6 +1537,7 @@
 	cpp_dev->msm_sd.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV;
 	cpp_dev->msm_sd.sd.entity.group_id = MSM_CAMERA_SUBDEV_CPP;
 	cpp_dev->msm_sd.sd.entity.name = pdev->name;
+	cpp_dev->msm_sd.close_seq = MSM_SD_CLOSE_3RD_CATEGORY;
 	msm_sd_register(&cpp_dev->msm_sd);
 	msm_cpp_v4l2_subdev_fops.owner = v4l2_subdev_fops.owner;
 	msm_cpp_v4l2_subdev_fops.open = v4l2_subdev_fops.open;
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 e1b978f..b115738 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
@@ -629,6 +629,9 @@
 		return msm_actuator_get_subdev_id(a_ctrl, argp);
 	case VIDIOC_MSM_ACTUATOR_CFG:
 		return msm_actuator_config(a_ctrl, argp);
+	case MSM_SD_SHUTDOWN:
+		msm_actuator_close(sd, NULL);
+		return 0;
 	default:
 		return -ENOIOCTLCMD;
 	}
@@ -710,6 +713,7 @@
 	media_entity_init(&act_ctrl_t->msm_sd.sd.entity, 0, NULL, 0);
 	act_ctrl_t->msm_sd.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV;
 	act_ctrl_t->msm_sd.sd.entity.group_id = MSM_CAMERA_SUBDEV_ACTUATOR;
+	act_ctrl_t->msm_sd.close_seq = MSM_SD_CLOSE_2ND_CATEGORY | 0x2;
 	msm_sd_register(&act_ctrl_t->msm_sd);
 	CDBG("succeeded\n");
 	CDBG("Exit\n");
@@ -780,6 +784,7 @@
 	media_entity_init(&msm_actuator_t->msm_sd.sd.entity, 0, NULL, 0);
 	msm_actuator_t->msm_sd.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV;
 	msm_actuator_t->msm_sd.sd.entity.group_id = MSM_CAMERA_SUBDEV_ACTUATOR;
+	msm_actuator_t->msm_sd.close_seq = MSM_SD_CLOSE_2ND_CATEGORY | 0x2;
 	msm_sd_register(&msm_actuator_t->msm_sd);
 	CDBG("Exit\n");
 	return rc;
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 3409b3e..1c8662b 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
@@ -307,10 +307,10 @@
 	}
 
 	if (read_cfg->addr_type == MSM_CAMERA_I2C_BYTE_ADDR)
-		val = CCI_I2C_WRITE_CMD | (read_cfg->addr_type << 4) |
+		val = CCI_I2C_WRITE_DISABLE_P_CMD | (read_cfg->addr_type << 4) |
 			((read_cfg->addr & 0xFF) << 8);
 	if (read_cfg->addr_type == MSM_CAMERA_I2C_WORD_ADDR)
-		val = CCI_I2C_WRITE_CMD | (read_cfg->addr_type << 4) |
+		val = CCI_I2C_WRITE_DISABLE_P_CMD | (read_cfg->addr_type << 4) |
 			(((read_cfg->addr & 0xFF00) >> 8) << 8) |
 			((read_cfg->addr & 0xFF) << 16);
 	rc = msm_cci_write_i2c_queue(cci_dev, val, master, queue);
@@ -773,6 +773,12 @@
 	case VIDIOC_MSM_CCI_CFG:
 		rc = msm_cci_config(sd, arg);
 		break;
+	case MSM_SD_SHUTDOWN: {
+		struct msm_camera_cci_ctrl ctrl_cmd;
+		ctrl_cmd.cmd = MSM_CCI_RELEASE;
+		rc = msm_cci_config(sd, &ctrl_cmd);
+		break;
+	}
 	default:
 		rc = -ENOIOCTLCMD;
 	}
@@ -1007,6 +1013,7 @@
 		goto cci_release_mem;
 	}
 	disable_irq(new_cci_dev->irq->start);
+	new_cci_dev->msm_sd.close_seq = MSM_SD_CLOSE_2ND_CATEGORY | 0x6;
 	msm_sd_register(&new_cci_dev->msm_sd);
 	new_cci_dev->pdev = pdev;
 	msm_cci_init_cci_params(new_cci_dev);
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 33eaa69..4db6855 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
@@ -460,6 +460,7 @@
 		rc = msm_csid_cmd(csid_dev, arg);
 		break;
 	case VIDIOC_MSM_CSID_RELEASE:
+	case MSM_SD_SHUTDOWN:
 		rc = msm_csid_release(csid_dev);
 		break;
 	default:
@@ -552,6 +553,7 @@
 	media_entity_init(&new_csid_dev->msm_sd.sd.entity, 0, NULL, 0);
 	new_csid_dev->msm_sd.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV;
 	new_csid_dev->msm_sd.sd.entity.group_id = MSM_CAMERA_SUBDEV_CSID;
+	new_csid_dev->msm_sd.close_seq = MSM_SD_CLOSE_2ND_CATEGORY | 0x5;
 	msm_sd_register(&new_csid_dev->msm_sd);
 
 	rc = request_irq(new_csid_dev->irq->start, msm_csid_irq,
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 7d3a1fc..429d151 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.c
@@ -570,6 +570,7 @@
 		rc = msm_csiphy_cmd(csiphy_dev, arg);
 		break;
 	case VIDIOC_MSM_CSIPHY_RELEASE:
+	case MSM_SD_SHUTDOWN:
 		rc = msm_csiphy_release(csiphy_dev, arg);
 		break;
 	default:
@@ -665,7 +666,7 @@
 	media_entity_init(&new_csiphy_dev->msm_sd.sd.entity, 0, NULL, 0);
 	new_csiphy_dev->msm_sd.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV;
 	new_csiphy_dev->msm_sd.sd.entity.group_id = MSM_CAMERA_SUBDEV_CSIPHY;
-
+	new_csiphy_dev->msm_sd.close_seq = MSM_SD_CLOSE_2ND_CATEGORY | 0x4;
 	msm_sd_register(&new_csiphy_dev->msm_sd);
 	new_csiphy_dev->csiphy_state = CSIPHY_POWER_DOWN;
 	return 0;
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 9119a13..044fd31 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
@@ -81,6 +81,7 @@
 	media_entity_init(&fctrl->msm_sd.sd.entity, 0, NULL, 0);
 	fctrl->msm_sd.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV;
 	fctrl->msm_sd.sd.entity.group_id = MSM_CAMERA_SUBDEV_LED_FLASH;
+	fctrl->msm_sd.close_seq = MSM_SD_CLOSE_2ND_CATEGORY | 0x1;
 	msm_sd_register(&fctrl->msm_sd);
 
 	CDBG("probe success\n");
diff --git a/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.c b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.c
index 7c639d1..68c7d23 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.c
@@ -16,6 +16,9 @@
 #include "msm_cci.h"
 #include "msm_camera_io_util.h"
 #include "msm_camera_i2c_mux.h"
+#include <mach/rpm-regulator.h>
+#include <mach/rpm-regulator-smd.h>
+#include <linux/regulator/consumer.h>
 
 #undef CDBG
 #ifdef CONFIG_MSMB_CAMERA_DEBUG
@@ -613,7 +616,7 @@
 static int32_t msm_sensor_get_dt_data(struct platform_device *pdev,
 	struct msm_sensor_ctrl_t *s_ctrl)
 {
-	int32_t rc = 0, i = 0;
+	int32_t rc = 0, i = 0, ret = 0;
 	struct device_node *of_node = pdev->dev.of_node;
 	struct msm_camera_gpio_conf *gconf = NULL;
 	struct msm_camera_sensor_board_info *sensordata = NULL;
@@ -774,7 +777,14 @@
 	sensordata->slave_info->sensor_id_reg_addr = id_info[1];
 	sensordata->slave_info->sensor_id = id_info[2];
 
+	/*Optional property, don't return error if absent */
+	ret = of_property_read_string(of_node, "qcom,vdd-cx-name",
+		&sensordata->misc_regulator);
+	CDBG("%s qcom,misc_regulator %s, rc %d\n", __func__,
+		 sensordata->misc_regulator, ret);
+
 	kfree(gpio_array);
+
 	return rc;
 
 ERROR9:
@@ -799,6 +809,41 @@
 	return rc;
 }
 
+static void msm_sensor_misc_regulator(
+	struct msm_sensor_ctrl_t *sctrl, uint32_t enable)
+{
+	int32_t rc = 0;
+	if (enable) {
+		sctrl->misc_regulator = (void *)rpm_regulator_get(
+			&sctrl->pdev->dev, sctrl->sensordata->misc_regulator);
+		if (sctrl->misc_regulator) {
+			rc = rpm_regulator_set_mode(sctrl->misc_regulator,
+				RPM_REGULATOR_MODE_HPM);
+			if (rc < 0) {
+				pr_err("%s: Failed to set for rpm regulator on %s: %d\n",
+					__func__,
+					sctrl->sensordata->misc_regulator, rc);
+				rpm_regulator_put(sctrl->misc_regulator);
+			}
+		} else {
+			pr_err("%s: Failed to vote for rpm regulator on %s: %d\n",
+				__func__,
+				sctrl->sensordata->misc_regulator, rc);
+		}
+	} else {
+		if (sctrl->misc_regulator) {
+			rc = rpm_regulator_set_mode(
+				(struct rpm_regulator *)sctrl->misc_regulator,
+				RPM_REGULATOR_MODE_AUTO);
+			if (rc < 0)
+				pr_err("%s: Failed to set for rpm regulator on %s: %d\n",
+					__func__,
+					sctrl->sensordata->misc_regulator, rc);
+			rpm_regulator_put(sctrl->misc_regulator);
+		}
+	}
+}
+
 int32_t msm_sensor_free_sensor_data(struct msm_sensor_ctrl_t *s_ctrl)
 {
 	if (!s_ctrl->pdev)
@@ -1002,6 +1047,7 @@
 	struct msm_sensor_power_setting_array *power_setting_array = NULL;
 	struct msm_sensor_power_setting *power_setting = NULL;
 	struct msm_camera_sensor_board_info *data = s_ctrl->sensordata;
+	s_ctrl->stop_setting_valid = 0;
 
 	CDBG("%s:%d\n", __func__, __LINE__);
 	power_setting_array = &s_ctrl->power_setting_array;
@@ -1101,9 +1147,14 @@
 
 static void msm_sensor_stop_stream(struct msm_sensor_ctrl_t *s_ctrl)
 {
-	s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_write_table(
-		s_ctrl->sensor_i2c_client, &s_ctrl->stop_setting);
-	kfree(s_ctrl->stop_setting.reg_setting);
+	mutex_lock(s_ctrl->msm_sensor_mutex);
+	if (s_ctrl->sensor_state == MSM_SENSOR_POWER_UP) {
+		s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_write_table(
+			s_ctrl->sensor_i2c_client, &s_ctrl->stop_setting);
+		kfree(s_ctrl->stop_setting.reg_setting);
+		s_ctrl->stop_setting.reg_setting = NULL;
+	}
+	mutex_unlock(s_ctrl->msm_sensor_mutex);
 	return;
 }
 
@@ -1120,6 +1171,7 @@
 	case VIDIOC_MSM_SENSOR_CFG:
 		return s_ctrl->func_tbl->sensor_config(s_ctrl, argp);
 	case VIDIOC_MSM_SENSOR_RELEASE:
+	case MSM_SD_SHUTDOWN:
 		msm_sensor_stop_stream(s_ctrl);
 		return 0;
 	default:
@@ -1203,6 +1255,7 @@
 			power_setting_array->size *
 			sizeof(struct msm_sensor_power_setting))) {
 			pr_err("%s:%d failed\n", __func__, __LINE__);
+			kfree(power_setting_array->power_setting);
 			rc = -EFAULT;
 			break;
 		}
@@ -1234,6 +1287,13 @@
 		struct msm_camera_i2c_reg_setting conf_array;
 		struct msm_camera_i2c_reg_array *reg_setting = NULL;
 
+		if (s_ctrl->sensor_state != MSM_SENSOR_POWER_UP) {
+			pr_err("%s:%d failed: invalid state %d\n", __func__,
+				__LINE__, s_ctrl->sensor_state);
+			rc = -EFAULT;
+			break;
+		}
+
 		if (copy_from_user(&conf_array,
 			(void *)cdata->cfg.setting,
 			sizeof(struct msm_camera_i2c_reg_setting))) {
@@ -1264,10 +1324,138 @@
 		kfree(reg_setting);
 		break;
 	}
+	case CFG_SLAVE_READ_I2C: {
+		struct msm_camera_i2c_read_config read_config;
+		uint16_t local_data = 0;
+		uint16_t orig_slave_addr = 0, read_slave_addr = 0;
+		if (copy_from_user(&read_config,
+			(void *)cdata->cfg.setting,
+			sizeof(struct msm_camera_i2c_read_config))) {
+			pr_err("%s:%d failed\n", __func__, __LINE__);
+			rc = -EFAULT;
+			break;
+		}
+		read_slave_addr = read_config.slave_addr;
+		CDBG("%s:CFG_SLAVE_READ_I2C:", __func__);
+		CDBG("%s:slave_addr=0x%x reg_addr=0x%x, data_type=%d\n",
+			__func__, read_config.slave_addr,
+			read_config.reg_addr, read_config.data_type);
+		if (s_ctrl->sensor_i2c_client->cci_client) {
+			orig_slave_addr =
+				s_ctrl->sensor_i2c_client->cci_client->sid;
+			s_ctrl->sensor_i2c_client->cci_client->sid =
+				read_slave_addr >> 1;
+		} else if (s_ctrl->sensor_i2c_client->client) {
+			orig_slave_addr =
+				s_ctrl->sensor_i2c_client->client->addr;
+			s_ctrl->sensor_i2c_client->client->addr =
+				read_slave_addr >> 1;
+		} else {
+			pr_err("%s: error: no i2c/cci client found.", __func__);
+			rc = -EFAULT;
+			break;
+		}
+		CDBG("%s:orig_slave_addr=0x%x, new_slave_addr=0x%x",
+				__func__, orig_slave_addr,
+				read_slave_addr >> 1);
+		rc = s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_read(
+				s_ctrl->sensor_i2c_client,
+				read_config.reg_addr,
+				&local_data, read_config.data_type);
+		if (rc < 0) {
+			pr_err("%s:%d: i2c_read failed\n", __func__, __LINE__);
+			break;
+		}
+		if (copy_to_user((void __user *)read_config.data,
+			(void *)&local_data, sizeof(uint16_t))) {
+			pr_err("%s:%d copy failed\n", __func__, __LINE__);
+			rc = -EFAULT;
+			break;
+		}
+		break;
+	}
+	case CFG_SLAVE_WRITE_I2C_ARRAY: {
+		struct msm_camera_i2c_array_write_config write_config;
+		struct msm_camera_i2c_reg_array *reg_setting = NULL;
+		uint16_t write_slave_addr = 0;
+		uint16_t orig_slave_addr = 0;
+
+		if (copy_from_user(&write_config,
+			(void *)cdata->cfg.setting,
+			sizeof(struct msm_camera_i2c_array_write_config))) {
+			pr_err("%s:%d failed\n", __func__, __LINE__);
+			rc = -EFAULT;
+			break;
+		}
+		CDBG("%s:CFG_SLAVE_WRITE_I2C_ARRAY:", __func__);
+		CDBG("%s:slave_addr=0x%x, array_size=%d\n", __func__,
+			write_config.slave_addr,
+			write_config.conf_array.size);
+		reg_setting = kzalloc(write_config.conf_array.size *
+			(sizeof(struct msm_camera_i2c_reg_array)), GFP_KERNEL);
+		if (!reg_setting) {
+			pr_err("%s:%d failed\n", __func__, __LINE__);
+			rc = -ENOMEM;
+			break;
+		}
+		if (copy_from_user(reg_setting,
+				(void *)(write_config.conf_array.reg_setting),
+				write_config.conf_array.size *
+				sizeof(struct msm_camera_i2c_reg_array))) {
+			pr_err("%s:%d failed\n", __func__, __LINE__);
+			kfree(reg_setting);
+			rc = -EFAULT;
+			break;
+		}
+		write_config.conf_array.reg_setting = reg_setting;
+		write_slave_addr = write_config.slave_addr;
+		if (s_ctrl->sensor_i2c_client->cci_client) {
+			orig_slave_addr =
+				s_ctrl->sensor_i2c_client->cci_client->sid;
+			s_ctrl->sensor_i2c_client->cci_client->sid =
+				write_slave_addr >> 1;
+		} else if (s_ctrl->sensor_i2c_client->client) {
+			orig_slave_addr =
+				s_ctrl->sensor_i2c_client->client->addr;
+			s_ctrl->sensor_i2c_client->client->addr =
+				write_slave_addr >> 1;
+		} else {
+			pr_err("%s: error: no i2c/cci client found.", __func__);
+			kfree(reg_setting);
+			rc = -EFAULT;
+			break;
+		}
+		CDBG("%s:orig_slave_addr=0x%x, new_slave_addr=0x%x",
+				__func__, orig_slave_addr,
+				write_slave_addr >> 1);
+		rc = s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_write_table(
+			s_ctrl->sensor_i2c_client, &(write_config.conf_array));
+		if (s_ctrl->sensor_i2c_client->cci_client) {
+			s_ctrl->sensor_i2c_client->cci_client->sid =
+				orig_slave_addr;
+		} else if (s_ctrl->sensor_i2c_client->client) {
+			s_ctrl->sensor_i2c_client->client->addr =
+				orig_slave_addr;
+		} else {
+			pr_err("%s: error: no i2c/cci client found.", __func__);
+			kfree(reg_setting);
+			rc = -EFAULT;
+			break;
+		}
+		kfree(reg_setting);
+		break;
+	}
 	case CFG_WRITE_I2C_SEQ_ARRAY: {
 		struct msm_camera_i2c_seq_reg_setting conf_array;
 		struct msm_camera_i2c_seq_reg_array *reg_setting = NULL;
 
+		if (s_ctrl->sensor_state != MSM_SENSOR_POWER_UP) {
+			pr_err("%s:%d failed: invalid state %d\n", __func__,
+				__LINE__, s_ctrl->sensor_state);
+			rc = -EFAULT;
+			break;
+		}
+
 		if (copy_from_user(&conf_array,
 			(void *)cdata->cfg.setting,
 			sizeof(struct msm_camera_i2c_seq_reg_setting))) {
@@ -1302,18 +1490,56 @@
 	}
 
 	case CFG_POWER_UP:
-		if (s_ctrl->func_tbl->sensor_power_up)
-			rc = s_ctrl->func_tbl->sensor_power_up(s_ctrl);
-		else
+		if (s_ctrl->sensor_state != MSM_SENSOR_POWER_DOWN) {
+			pr_err("%s:%d failed: invalid state %d\n", __func__,
+				__LINE__, s_ctrl->sensor_state);
 			rc = -EFAULT;
+			break;
+		}
+		if (s_ctrl->func_tbl->sensor_power_up) {
+			if (s_ctrl->sensordata->misc_regulator)
+				msm_sensor_misc_regulator(s_ctrl, 1);
+
+			rc = s_ctrl->func_tbl->sensor_power_up(s_ctrl);
+			if (rc < 0) {
+				pr_err("%s:%d failed rc %ld\n", __func__,
+					__LINE__, rc);
+				break;
+			}
+			s_ctrl->sensor_state = MSM_SENSOR_POWER_UP;
+			pr_err("%s:%d sensor state %d\n", __func__, __LINE__,
+				s_ctrl->sensor_state);
+		} else {
+			rc = -EFAULT;
+		}
 		break;
 
 	case CFG_POWER_DOWN:
-		if (s_ctrl->func_tbl->sensor_power_down)
+		kfree(s_ctrl->stop_setting.reg_setting);
+		s_ctrl->stop_setting.reg_setting = NULL;
+		if (s_ctrl->sensor_state != MSM_SENSOR_POWER_UP) {
+			pr_err("%s:%d failed: invalid state %d\n", __func__,
+				__LINE__, s_ctrl->sensor_state);
+			rc = -EFAULT;
+			break;
+		}
+		if (s_ctrl->func_tbl->sensor_power_down) {
+			if (s_ctrl->sensordata->misc_regulator)
+				msm_sensor_misc_regulator(s_ctrl, 0);
+
 			rc = s_ctrl->func_tbl->sensor_power_down(
 				s_ctrl);
-		else
+			if (rc < 0) {
+				pr_err("%s:%d failed rc %ld\n", __func__,
+					__LINE__, rc);
+				break;
+			}
+			s_ctrl->sensor_state = MSM_SENSOR_POWER_DOWN;
+			pr_err("%s:%d sensor state %d\n", __func__, __LINE__,
+				s_ctrl->sensor_state);
+		} else {
 			rc = -EFAULT;
+		}
 		break;
 
 	case CFG_SET_STOP_STREAM_SETTING: {
@@ -1327,6 +1553,7 @@
 			rc = -EFAULT;
 			break;
 		}
+		s_ctrl->stop_setting_valid = 1;
 
 		reg_setting = stop_setting->reg_setting;
 		stop_setting->reg_setting = kzalloc(stop_setting->size *
@@ -1364,8 +1591,10 @@
 	int rc = 0;
 	struct msm_sensor_ctrl_t *s_ctrl = get_sctrl(sd);
 	mutex_lock(s_ctrl->msm_sensor_mutex);
-	if (!on)
-		rc = s_ctrl->func_tbl->sensor_power_down(s_ctrl);
+	if (!on && s_ctrl->sensor_state == MSM_SENSOR_POWER_UP) {
+		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;
@@ -1505,6 +1734,7 @@
 	rc = camera_init_v4l2(&s_ctrl->pdev->dev, &session_id);
 	CDBG("%s rc %d session_id %d\n", __func__, rc, session_id);
 	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__);
 
@@ -1596,6 +1826,7 @@
 		&session_id);
 	CDBG("%s rc %d session_id %d\n", __func__, rc, session_id);
 	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__);
 
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 6c36e47d..fe11a56 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.h
+++ b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.h
@@ -37,6 +37,11 @@
 
 struct msm_sensor_ctrl_t;
 
+enum msm_sensor_state_t {
+	MSM_SENSOR_POWER_DOWN,
+	MSM_SENSOR_POWER_UP,
+};
+
 struct msm_sensor_fn_t {
 	int (*sensor_config) (struct msm_sensor_ctrl_t *, void __user *);
 	int (*sensor_power_down)
@@ -62,9 +67,12 @@
 	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;
 };
 
 int32_t msm_sensor_config(struct msm_sensor_ctrl_t *s_ctrl,
diff --git a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c
index 5b385a0..790bbc1 100644
--- a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c
+++ b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c
@@ -4055,11 +4055,13 @@
 		pes_event.pes_end.start_gap = 0;
 		pes_event.data_length = 0;
 
-		/* Parse error indicators - TODO: these should be per filter */
+		/* Parse error indicators */
 		if (sts->error_indicators & SDMX_FILTER_ERR_INVALID_PES_LEN)
 			pes_event.pes_end.pes_length_mismatch = 1;
-		if (sts->error_indicators & SDMX_FILTER_ERR_CONT_CNT_INVALID)
-			pes_event.pes_end.disc_indicator_set = 0;
+		else
+			pes_event.pes_end.pes_length_mismatch = 0;
+
+		pes_event.pes_end.disc_indicator_set = 0;
 
 		pes_event.pes_end.stc = 0;
 		pes_event.pes_end.tei_counter = counters.transport_err_count;
@@ -4606,11 +4608,11 @@
 		mpq_demux->sdmx_filter_count, mpq_demux->filters_status);
 
 	process_end_time = current_kernel_time();
-	mpq_dmx_update_sdmx_stat(mpq_demux, prev_fill_count,
-		&process_start_time, &process_end_time);
-
 	bytes_read = prev_fill_count - fill_count;
 
+	mpq_dmx_update_sdmx_stat(mpq_demux, bytes_read,
+			&process_start_time, &process_end_time);
+
 	MPQ_DVB_DBG_PRINT(
 		"%s: SDMX result=%d, input_fill_count=%u, read_offset=%u, read %d bytes from input, status=0x%X, errors=0x%X\n",
 		__func__, sdmx_res, fill_count, read_offset, bytes_read,
diff --git a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_tspp_v1.c b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_tspp_v1.c
index 5e14d0c..a2ce428 100644
--- a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_tspp_v1.c
+++ b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_tspp_v1.c
@@ -54,14 +54,16 @@
 #define TSPP_RAW_TTS_SIZE		192
 #define TSPP_RAW_SIZE			188
 
-#define MAX_BAM_DESCRIPTOR_SIZE	(32*1024 - 1)
+#define MAX_BAM_DESCRIPTOR_SIZE	(32 * 1024 - 1)
+
+#define MAX_BAM_DESCRIPTOR_COUNT	(8 * 1024 - 2)
 
 #define TSPP_BUFFER_SIZE		(500 * 1024) /* 500KB */
 
 #define TSPP_DESCRIPTOR_SIZE	(TSPP_RAW_TTS_SIZE)
 
 #define TSPP_BUFFER_COUNT(buffer_size)	\
-	((buffer_size) / TSPP_RAW_TTS_SIZE)
+	((buffer_size) / TSPP_DESCRIPTOR_SIZE)
 
 /* When TSPP notifies demux that new packets are received.
  * Using max descriptor size (170 packets).
@@ -1799,6 +1801,11 @@
 		mpq_dmx_tspp_info.tsif[i].buffer_count =
 				TSPP_BUFFER_COUNT(tspp_out_buffer_size);
 
+		if (mpq_dmx_tspp_info.tsif[i].buffer_count >
+			MAX_BAM_DESCRIPTOR_COUNT)
+			mpq_dmx_tspp_info.tsif[i].buffer_count =
+				MAX_BAM_DESCRIPTOR_COUNT;
+
 		mpq_dmx_tspp_info.tsif[i].aggregate_ids =
 			vzalloc(mpq_dmx_tspp_info.tsif[i].buffer_count *
 				sizeof(int));
diff --git a/drivers/media/platform/msm/vidc/msm_venc.c b/drivers/media/platform/msm/vidc/msm_venc.c
index 20cb08d..8866b34 100644
--- a/drivers/media/platform/msm/vidc/msm_venc.c
+++ b/drivers/media/platform/msm/vidc/msm_venc.c
@@ -787,11 +787,10 @@
 
 		if (*num_buffers > VIDEO_MAX_FRAME) {
 			dprintk(VIDC_ERR,
-					"Failed : No of slices requested = %d"\
-					" Max supported slices = %d",
-					*num_buffers, VIDEO_MAX_FRAME);
-			rc = -EINVAL;
-			break;
+				"Changing buffers requested, from %d to max"\
+				" supported (%d) best effort encoding\n",
+				*num_buffers, VIDEO_MAX_FRAME);
+			*num_buffers = VIDEO_MAX_FRAME;
 		}
 		ctrl = v4l2_ctrl_find(&inst->ctrl_handler,
 				V4L2_CID_MPEG_VIDC_VIDEO_EXTRADATA);
@@ -1731,12 +1730,11 @@
 	}
 	case V4L2_CID_MPEG_VIDC_VIDEO_H264_VUI_TIMING_INFO:
 	{
-		struct v4l2_ctrl *rc_mode, *frame_rate;
+		struct v4l2_ctrl *rc_mode;
 		bool cfr = false;
 
 		property_id = HAL_PARAM_VENC_H264_VUI_TIMING_INFO;
 		rc_mode = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL);
-		frame_rate = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_FRAME_RATE);
 
 		switch (rc_mode->val) {
 		case V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_VBR_CFR:
@@ -1753,20 +1751,9 @@
 			vui_timing_info.enable = 0;
 			break;
 		case V4L2_MPEG_VIDC_VIDEO_H264_VUI_TIMING_INFO_ENABLED:
-			/* Only support this in CFR mode because we
-			 * don't really know how to fill out vui_timing_info.
-			 * time_scale in vfr mode.  The assumed framerate
-			 * might be incorrect. */
-			if (!cfr) {
-				dprintk(VIDC_ERR, "Can't set %x in VFR mode\n",
-						ctrl->id);
-				rc = -ENOTSUPP;
-				break;
-			}
-
 			vui_timing_info.enable = 1;
 			vui_timing_info.fixed_frame_rate = cfr;
-			vui_timing_info.time_scale = frame_rate->val;
+			vui_timing_info.time_scale = inst->prop.fps;
 		}
 
 		pdata = &vui_timing_info;
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c
index 91fcdb6..fd29994 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c
@@ -393,6 +393,7 @@
 {
 	struct msm_vidc_cb_cmd_done *response = data;
 	struct msm_vidc_inst *inst;
+	struct v4l2_control control = {0};
 	struct msm_vidc_cb_event *event_notify;
 	int event = V4L2_EVENT_SEQ_CHANGED_INSUFFICIENT;
 	int rc = 0;
@@ -401,7 +402,15 @@
 		event_notify = (struct msm_vidc_cb_event *) response->data;
 		switch (event_notify->hal_event_type) {
 		case HAL_EVENT_SEQ_CHANGED_SUFFICIENT_RESOURCES:
-			event = V4L2_EVENT_SEQ_CHANGED_SUFFICIENT;
+			event = V4L2_EVENT_SEQ_CHANGED_INSUFFICIENT;
+			control.id =
+				V4L2_CID_MPEG_VIDC_VIDEO_CONTINUE_DATA_TRANSFER;
+			rc = v4l2_g_ctrl(&inst->ctrl_handler, &control);
+			if (rc)
+				dprintk(VIDC_WARN,
+					"Failed to get Smooth streamng flag\n");
+			if (!rc && control.value == true)
+				event = V4L2_EVENT_SEQ_CHANGED_SUFFICIENT;
 			break;
 		case HAL_EVENT_SEQ_CHANGED_INSUFFICIENT_RESOURCES:
 			event = V4L2_EVENT_SEQ_CHANGED_INSUFFICIENT;
@@ -543,6 +552,7 @@
 	struct msm_vidc_cb_cmd_done *response = data;
 	struct msm_vidc_inst *inst = NULL ;
 	struct msm_vidc_core *core = NULL;
+	subsystem_crashed("venus");
 	if (response) {
 		core = get_vidc_core(response->device_id);
 		dprintk(VIDC_WARN, "SYS_ERROR received for core %p\n", core);
diff --git a/drivers/media/platform/msm/vidc/q6_hfi.c b/drivers/media/platform/msm/vidc/q6_hfi.c
index 123b654..577b2b5 100644
--- a/drivers/media/platform/msm/vidc/q6_hfi.c
+++ b/drivers/media/platform/msm/vidc/q6_hfi.c
@@ -362,17 +362,18 @@
 
 void q6_hfi_delete_device(void *device)
 {
-	struct q6_hfi_device *close, *dev;
+	struct q6_hfi_device *close, *tmp, *dev;
 
 	if (device) {
 		q6_hfi_deinit_resources(device);
 		dev = (struct q6_hfi_device *) device;
-		list_for_each_entry(close, &hal_ctxt.dev_head, list) {
+		list_for_each_entry_safe(close, tmp, &hal_ctxt.dev_head, list) {
 			if (close->device_id == dev->device_id) {
 				hal_ctxt.dev_count--;
 				list_del(&close->list);
 				destroy_workqueue(close->vidc_workq);
 				kfree(close);
+				break;
 			}
 		}
 
diff --git a/drivers/media/platform/msm/vidc/venus_hfi.c b/drivers/media/platform/msm/vidc/venus_hfi.c
index 74733c2..bc5adc11 100644
--- a/drivers/media/platform/msm/vidc/venus_hfi.c
+++ b/drivers/media/platform/msm/vidc/venus_hfi.c
@@ -2953,12 +2953,12 @@
 
 void venus_hfi_delete_device(void *device)
 {
-	struct venus_hfi_device *close, *dev;
+	struct venus_hfi_device *close, *tmp, *dev;
 
 	if (device) {
 		venus_hfi_deinit_resources(device);
 		dev = (struct venus_hfi_device *) device;
-		list_for_each_entry(close, &hal_ctxt.dev_head, list) {
+		list_for_each_entry_safe(close, tmp, &hal_ctxt.dev_head, list) {
 			if (close->hal_data->irq == dev->hal_data->irq) {
 				hal_ctxt.dev_count--;
 				free_irq(dev->hal_data->irq, close);
diff --git a/drivers/media/platform/msm/wfd/enc-venus-subdev.c b/drivers/media/platform/msm/wfd/enc-venus-subdev.c
index 722aa8f..e6568f1 100644
--- a/drivers/media/platform/msm/wfd/enc-venus-subdev.c
+++ b/drivers/media/platform/msm/wfd/enc-venus-subdev.c
@@ -19,6 +19,7 @@
 #include <linux/mutex.h>
 #include <linux/wait.h>
 #include <linux/slab.h>
+#include <linux/workqueue.h>
 #include <mach/iommu_domains.h>
 #include <media/msm_vidc.h>
 #include <media/v4l2-subdev.h>
@@ -48,6 +49,13 @@
 	bool callback_thread_running;
 	struct completion dq_complete, cmd_complete;
 	bool secure;
+	struct workqueue_struct *fill_buf_wq;
+};
+
+struct fill_buf_work {
+	struct venc_inst *inst;
+	struct mem_region *mregion;
+	struct work_struct work;
 };
 
 static const int subscribed_events[] = {
@@ -331,6 +339,14 @@
 	init_completion(&inst->dq_complete);
 	init_completion(&inst->cmd_complete);
 	mutex_init(&inst->lock);
+
+	inst->fill_buf_wq = create_singlethread_workqueue("venc_vidc_ftb_wq");
+	if (!inst->fill_buf_wq) {
+		WFD_MSG_ERR("Failed to create ftb wq\n");
+		rc = -ENOMEM;
+		goto vidc_wq_create_fail;
+	}
+
 	inst->vidc_context = msm_vidc_open(MSM_VIDC_CORE_0, MSM_VIDC_ENCODER);
 	if (!inst->vidc_context) {
 		WFD_MSG_ERR("Failed to create vidc context\n");
@@ -362,6 +378,8 @@
 vidc_subscribe_fail:
 	msm_vidc_close(inst->vidc_context);
 vidc_open_fail:
+	destroy_workqueue(inst->fill_buf_wq);
+vidc_wq_create_fail:
 	kfree(inst);
 venc_open_fail:
 	return rc;
@@ -385,6 +403,7 @@
 
 	wait_for_completion(&inst->cmd_complete);
 
+	destroy_workqueue(inst->fill_buf_wq);
 	if (inst->callback_thread && inst->callback_thread_running)
 		kthread_stop(inst->callback_thread);
 
@@ -551,6 +570,7 @@
 
 	inst = (struct venc_inst *)sd->dev_priv;
 
+	flush_workqueue(inst->fill_buf_wq);
 	rc = msm_vidc_streamoff(inst->vidc_context, BUF_TYPE_INPUT);
 	if (rc) {
 		WFD_MSG_ERR("Failed to streamoff vidc's input port");
@@ -938,25 +958,12 @@
 	return msm_vidc_s_parm(inst->vidc_context, &p);
 }
 
-static long venc_fill_outbuf(struct v4l2_subdev *sd, void *arg)
+static long fill_outbuf(struct venc_inst *inst, struct mem_region *mregion)
 {
-	struct venc_inst *inst = NULL;
-	struct mem_region *mregion = NULL;
 	struct v4l2_buffer buffer = {0};
 	struct v4l2_plane plane = {0};
 	int index = 0, rc = 0;
 
-	if (!sd) {
-		WFD_MSG_ERR("Subdevice required for %s\n", __func__);
-		return -EINVAL;
-	} else if (!arg) {
-		WFD_MSG_ERR("Invalid output buffer ot fill\n");
-		return -EINVAL;
-	}
-
-	inst = (struct venc_inst *)sd->dev_priv;
-	mregion = get_registered_mregion(&inst->registered_output_bufs, arg);
-
 	if (!mregion) {
 		WFD_MSG_ERR("Output buffer not registered\n");
 		return -ENOENT;
@@ -994,8 +1001,77 @@
 		mark_index_busy(&inst->free_output_indices, index);
 		mutex_unlock(&inst->lock);
 	}
-	return rc;
 
+	return rc;
+}
+
+static void fill_outbuf_helper(struct work_struct *work)
+{
+	int rc;
+	struct fill_buf_work *fbw =
+		container_of(work, struct fill_buf_work, work);
+
+	rc = fill_outbuf(fbw->inst, fbw->mregion);
+	if (rc) {
+		struct vb2_buffer *vb = NULL;
+
+		WFD_MSG_ERR("Failed to fill buffer async\n");
+		vb = (struct vb2_buffer *)fbw->mregion->cookie;
+		vb->v4l2_buf.flags = 0;
+		vb->v4l2_buf.timestamp = ns_to_timeval(-1);
+		vb->v4l2_planes[0].bytesused = 0;
+
+		fbw->inst->vmops.op_buffer_done(
+				fbw->inst->vmops.cbdata, rc, vb);
+	}
+
+	kfree(fbw);
+}
+
+static long venc_fill_outbuf(struct v4l2_subdev *sd, void *arg)
+{
+	struct fill_buf_work *fbw;
+	struct venc_inst *inst = NULL;
+	struct mem_region *mregion;
+
+	if (!sd) {
+		WFD_MSG_ERR("Subdevice required for %s\n", __func__);
+		return -EINVAL;
+	} else if (!arg) {
+		WFD_MSG_ERR("Invalid output buffer ot fill\n");
+		return -EINVAL;
+	}
+
+	inst = (struct venc_inst *)sd->dev_priv;
+	mregion = get_registered_mregion(&inst->registered_output_bufs, arg);
+	if (!mregion) {
+		WFD_MSG_ERR("Output buffer not registered\n");
+		return -ENOENT;
+	}
+
+	fbw = kzalloc(sizeof(*fbw), GFP_KERNEL);
+	if (!fbw) {
+		WFD_MSG_ERR("Couldn't allocate memory\n");
+		return -ENOMEM;
+	}
+
+	INIT_WORK(&fbw->work, fill_outbuf_helper);
+	fbw->inst = inst;
+	fbw->mregion = mregion;
+	/* XXX: The need for a wq to qbuf to vidc is necessitated as a
+	 * workaround for a bug in the v4l2 framework. VIDIOC_QBUF from
+	 * triggers a down_read(current->mm->mmap_sem).  There is another
+	 * _read(..) as msm_vidc_qbuf() depends on videobuf2 framework
+	 * as well. However, a _write(..) after the first _read() by a
+	 * different driver will prevent the second _read(...) from
+	 * suceeding.
+	 *
+	 * As we can't modify the framework, we're working around by issue
+	 * by queuing in a different thread effectively.
+	 */
+	queue_work(inst->fill_buf_wq, &fbw->work);
+
+	return 0;
 }
 
 static long venc_encode_frame(struct v4l2_subdev *sd, void *arg)
@@ -1127,6 +1203,8 @@
 
 	inst = (struct venc_inst *)sd->dev_priv;
 
+	flush_workqueue(inst->fill_buf_wq);
+
 	enc_cmd.cmd = V4L2_ENC_QCOM_CMD_FLUSH;
 	enc_cmd.flags = V4L2_QCOM_CMD_FLUSH_OUTPUT |
 		V4L2_QCOM_CMD_FLUSH_CAPTURE;
diff --git a/drivers/media/platform/msm/wfd/wfd-ioctl.c b/drivers/media/platform/msm/wfd/wfd-ioctl.c
index d44792c..cc309aa 100644
--- a/drivers/media/platform/msm/wfd/wfd-ioctl.c
+++ b/drivers/media/platform/msm/wfd/wfd-ioctl.c
@@ -1258,7 +1258,7 @@
 
 	WFD_MSG_DBG("yay!! got callback\n");
 	mutex_lock(&inst->vb2_lock);
-	vb2_buffer_done(buf, VB2_BUF_STATE_DONE);
+	vb2_buffer_done(buf, status ? VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE);
 	mutex_unlock(&inst->vb2_lock);
 }
 
diff --git a/drivers/media/radio/radio-tavarua.c b/drivers/media/radio/radio-tavarua.c
index 0c5534c..ea7032b 100644
--- a/drivers/media/radio/radio-tavarua.c
+++ b/drivers/media/radio/radio-tavarua.c
@@ -1001,9 +1001,15 @@
 			FMDBG("Search list has %d stations\n",
 						radio->registers[XFRCTRL+1]);
 			radio->xfr_bytes_left = radio->registers[XFRCTRL+1]*2;
-			if (radio->xfr_bytes_left > 14) {
+			if (!radio->registers[XFRCTRL+1]) {
 				copy_from_xfr(radio, TAVARUA_BUF_SRCH_LIST,
-							XFR_REG_NUM);
+									1);
+				tavarua_q_event(radio,
+						TAVARUA_EVT_NEW_SRCH_LIST);
+				radio->xfr_in_progress = 0;
+			} else if (radio->xfr_bytes_left > 14) {
+				copy_from_xfr(radio, TAVARUA_BUF_SRCH_LIST,
+							RX_STATIONS0_LEN);
 				request_read_xfr(radio,	RX_STATIONS_1);
 			} else if (radio->xfr_bytes_left) {
 				FMDBG("In else RX_STATIONS_0\n");
diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c
index f139b21..c60537a 100644
--- a/drivers/misc/qseecom.c
+++ b/drivers/misc/qseecom.c
@@ -45,7 +45,6 @@
 #include "qseecom_kernel.h"
 
 #define QSEECOM_DEV			"qseecom"
-#define QSEOS_VERSION_13		0x13
 #define QSEOS_VERSION_14		0x14
 #define QSEEE_VERSION_00		0x400000
 #define QSEE_VERSION_01			0x401000
@@ -90,11 +89,6 @@
 static dev_t qseecom_device_no;
 static struct cdev qseecom_cdev;
 
-/* Data structures used in legacy support */
-static void *pil;
-static uint32_t pil_ref_cnt;
-static DEFINE_MUTEX(pil_access_lock);
-
 static DEFINE_MUTEX(qsee_bw_mutex);
 static DEFINE_MUTEX(app_access_lock);
 static DEFINE_MUTEX(clk_access_lock);
@@ -278,63 +272,24 @@
 	svc->sb_virt = (char *) ion_map_kernel(qseecom.ion_clnt, svc->ihandle);
 	svc->sb_phys = pa;
 
-	if (qseecom.qseos_version == QSEOS_VERSION_14) {
-		req.qsee_cmd_id = QSEOS_REGISTER_LISTENER;
-		req.listener_id = svc->svc.listener_id;
-		req.sb_len = svc->sb_length;
-		req.sb_ptr = (void *)svc->sb_phys;
+	req.qsee_cmd_id = QSEOS_REGISTER_LISTENER;
+	req.listener_id = svc->svc.listener_id;
+	req.sb_len = svc->sb_length;
+	req.sb_ptr = (void *)svc->sb_phys;
 
-		resp.result = QSEOS_RESULT_INCOMPLETE;
+	resp.result = QSEOS_RESULT_INCOMPLETE;
 
-		ret = scm_call(SCM_SVC_TZSCHEDULER, 1,  &req,
+	ret = scm_call(SCM_SVC_TZSCHEDULER, 1,  &req,
 					sizeof(req), &resp, sizeof(resp));
-		if (ret) {
-			pr_err("qseecom_scm_call failed with err: %d\n", ret);
-			return -EINVAL;
-		}
+	if (ret) {
+		pr_err("qseecom_scm_call failed with err: %d\n", ret);
+		return -EINVAL;
+	}
 
-		if (resp.result != QSEOS_RESULT_SUCCESS) {
-			pr_err("Error SB registration req: resp.result = %d\n",
-					resp.result);
-			return -EPERM;
-		}
-	} else {
-		struct qseecom_command cmd;
-		struct qseecom_response resp;
-		struct qse_pr_init_sb_req_s sb_init_req;
-		struct qse_pr_init_sb_rsp_s sb_init_rsp;
-
-		svc->sb_reg_req = kzalloc((sizeof(sb_init_req) +
-					sizeof(sb_init_rsp)), GFP_KERNEL);
-
-		sb_init_req.pr_cmd = TZ_SCHED_CMD_ID_REGISTER_LISTENER;
-		sb_init_req.listener_id = svc->svc.listener_id;
-		sb_init_req.sb_len = svc->sb_length;
-		sb_init_req.sb_ptr = svc->sb_phys;
-
-		memcpy(svc->sb_reg_req, &sb_init_req, sizeof(sb_init_req));
-
-		/* It will always be a new cmd from this method */
-		cmd.cmd_type = TZ_SCHED_CMD_NEW;
-		cmd.sb_in_cmd_addr = (u8 *)(virt_to_phys(svc->sb_reg_req));
-		cmd.sb_in_cmd_len = sizeof(sb_init_req);
-
-		resp.cmd_status = TZ_SCHED_STATUS_INCOMPLETE;
-
-		ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &cmd, sizeof(cmd)
-				, &resp, sizeof(resp));
-
-		if (ret) {
-			pr_err("qseecom_scm_call failed with err: %d\n", ret);
-			return -EINVAL;
-		}
-
-		if (resp.cmd_status != TZ_SCHED_STATUS_COMPLETE) {
-			pr_err("SB registration fail resp.cmd_status %d\n",
-							resp.cmd_status);
-			return -EINVAL;
-		}
-		memset(svc->sb_virt, 0, svc->sb_length);
+	if (resp.result != QSEOS_RESULT_SUCCESS) {
+		pr_err("Error SB registration req: resp.result = %d\n",
+			resp.result);
+		return -EPERM;
 	}
 	return 0;
 }
@@ -396,56 +351,24 @@
 	struct qseecom_command_scm_resp resp;
 	struct ion_handle *ihandle = NULL;		/* Retrieve phy addr */
 
-	if (qseecom.qseos_version == QSEOS_VERSION_14) {
-		req.qsee_cmd_id = QSEOS_DEREGISTER_LISTENER;
-		req.listener_id = data->listener.id;
-		resp.result = QSEOS_RESULT_INCOMPLETE;
+	req.qsee_cmd_id = QSEOS_DEREGISTER_LISTENER;
+	req.listener_id = data->listener.id;
+	resp.result = QSEOS_RESULT_INCOMPLETE;
 
-		ret = scm_call(SCM_SVC_TZSCHEDULER, 1,  &req,
+	ret = scm_call(SCM_SVC_TZSCHEDULER, 1,  &req,
 					sizeof(req), &resp, sizeof(resp));
-		if (ret) {
-			pr_err("scm_call() failed with err: %d (lstnr id=%d)\n",
-					ret, data->listener.id);
-			return ret;
-		}
-
-		if (resp.result != QSEOS_RESULT_SUCCESS) {
-			pr_err("Failed resp.result=%d,(lstnr id=%d)\n",
-					resp.result, data->listener.id);
-			return -EPERM;
-		}
-	} else {
-		struct qse_pr_init_sb_req_s sb_init_req;
-		struct qseecom_command cmd;
-		struct qseecom_response resp;
-		struct qseecom_registered_listener_list *svc;
-
-		svc = __qseecom_find_svc(data->listener.id);
-		sb_init_req.pr_cmd = TZ_SCHED_CMD_ID_REGISTER_LISTENER;
-		sb_init_req.listener_id = data->listener.id;
-		sb_init_req.sb_len = 0;
-		sb_init_req.sb_ptr = 0;
-
-		memcpy(svc->sb_reg_req, &sb_init_req, sizeof(sb_init_req));
-
-		/* It will always be a new cmd from this method */
-		cmd.cmd_type = TZ_SCHED_CMD_NEW;
-		cmd.sb_in_cmd_addr = (u8 *)(virt_to_phys(svc->sb_reg_req));
-		cmd.sb_in_cmd_len = sizeof(sb_init_req);
-		resp.cmd_status = TZ_SCHED_STATUS_INCOMPLETE;
-
-		ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &cmd, sizeof(cmd),
-					&resp, sizeof(resp));
-		if (ret) {
-			pr_err("qseecom_scm_call failed with err: %d\n", ret);
-			return ret;
-		}
-		kzfree(svc->sb_reg_req);
-		if (resp.cmd_status != TZ_SCHED_STATUS_COMPLETE) {
-			pr_err("Error with SB initialization\n");
-			return -EPERM;
-		}
+	if (ret) {
+		pr_err("scm_call() failed with err: %d (lstnr id=%d)\n",
+				ret, data->listener.id);
+		return ret;
 	}
+
+	if (resp.result != QSEOS_RESULT_SUCCESS) {
+		pr_err("Failed resp.result=%d,(lstnr id=%d)\n",
+				resp.result, data->listener.id);
+		return -EPERM;
+	}
+
 	data->abort = 1;
 	spin_lock_irqsave(&qseecom.registered_listener_list_lock, flags);
 	list_for_each_entry(ptr_svc, &qseecom.registered_listener_list_head,
@@ -830,8 +753,7 @@
 	bool unload = false;
 	bool found_app = false;
 
-	if ((qseecom.qseos_version == QSEOS_VERSION_14) &&
-				(data->client.app_id > 0)) {
+	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) {
@@ -857,7 +779,7 @@
 		}
 	}
 
-	if ((unload) && (qseecom.qseos_version == QSEOS_VERSION_14)) {
+	if (unload) {
 		struct qseecom_unload_app_ireq req;
 
 		__qseecom_cleanup_app(data);
@@ -890,19 +812,6 @@
 			}
 		}
 	}
-
-	if (qseecom.qseos_version == QSEOS_VERSION_13) {
-		data->abort = 1;
-		wake_up_all(&qseecom.send_resp_wq);
-		while (atomic_read(&data->ioctl_count) > 0) {
-			if (wait_event_freezable(data->abort_wq,
-					atomic_read(&data->ioctl_count) <= 0)) {
-				pr_err("Interrupted from abort\n");
-				ret = -ERESTARTSYS;
-				break;
-			}
-		}
-	}
 	qseecom_unmap_ion_allocated_memory(data);
 	data->released = true;
 	return ret;
@@ -914,98 +823,6 @@
 	return data->client.sb_phys + (virt - data->client.user_virt_sb_base);
 }
 
-static int __qseecom_send_cmd_legacy(struct qseecom_dev_handle *data,
-				struct qseecom_send_cmd_req *req)
-{
-	int ret = 0;
-	unsigned long flags;
-	u32 reqd_len_sb_in = 0;
-	struct qseecom_command cmd;
-	struct qseecom_response resp;
-
-
-	if (req->cmd_req_buf == NULL || req->resp_buf == NULL) {
-		pr_err("cmd buffer or response buffer is null\n");
-		return -EINVAL;
-	}
-
-	if (req->cmd_req_len <= 0 ||
-		req->resp_len <= 0 ||
-		req->cmd_req_len > data->client.sb_length ||
-		req->resp_len > data->client.sb_length) {
-		pr_err("cmd buffer length or "
-				"response buffer length not valid\n");
-		return -EINVAL;
-	}
-
-	reqd_len_sb_in = req->cmd_req_len + req->resp_len;
-	if (reqd_len_sb_in > data->client.sb_length) {
-		pr_debug("Not enough memory to fit cmd_buf and "
-			"resp_buf. Required: %u, Available: %u\n",
-				reqd_len_sb_in, data->client.sb_length);
-		return -ENOMEM;
-	}
-	cmd.cmd_type = TZ_SCHED_CMD_NEW;
-	cmd.sb_in_cmd_addr = (u8 *) data->client.sb_phys;
-	cmd.sb_in_cmd_len = req->cmd_req_len;
-
-	resp.cmd_status = TZ_SCHED_STATUS_INCOMPLETE;
-	resp.sb_in_rsp_addr = (u8 *)data->client.sb_phys + req->cmd_req_len;
-	resp.sb_in_rsp_len = req->resp_len;
-
-	ret = scm_call(SCM_SVC_TZSCHEDULER, 1, (const void *)&cmd,
-					sizeof(cmd), &resp, sizeof(resp));
-
-	if (ret) {
-		pr_err("qseecom_scm_call_legacy failed with err: %d\n", ret);
-		return ret;
-	}
-
-	while (resp.cmd_status != TZ_SCHED_STATUS_COMPLETE) {
-		/*
-		 * If cmd is incomplete, get the callback cmd out from SB out
-		 * and put it on the list
-		 */
-		struct qseecom_registered_listener_list *ptr_svc = NULL;
-		/*
-		 * We don't know which service can handle the command. so we
-		 * wake up all blocking services and let them figure out if
-		 * they can handle the given command.
-		 */
-		spin_lock_irqsave(&qseecom.registered_listener_list_lock,
-					flags);
-		list_for_each_entry(ptr_svc,
-				&qseecom.registered_listener_list_head, list) {
-				ptr_svc->rcv_req_flag = 1;
-				wake_up_interruptible(&ptr_svc->rcv_req_wq);
-		}
-		spin_unlock_irqrestore(&qseecom.registered_listener_list_lock,
-				flags);
-
-		pr_debug("waking up rcv_req_wq and "
-				"waiting for send_resp_wq\n");
-		if (wait_event_freezable(qseecom.send_resp_wq,
-				__qseecom_listener_has_sent_rsp(data))) {
-			pr_warning("qseecom Interrupted: exiting send_cmd loop\n");
-			return -ERESTARTSYS;
-		}
-
-		if (data->abort) {
-			pr_err("Aborting driver\n");
-			return -ENODEV;
-		}
-		qseecom.send_resp_flag = 0;
-		cmd.cmd_type = TZ_SCHED_CMD_PENDING;
-		ret = scm_call(SCM_SVC_TZSCHEDULER, 1, (const void *)&cmd,
-					sizeof(cmd), &resp, sizeof(resp));
-		if (ret) {
-			pr_err("qseecom_scm_call failed with err: %d\n", ret);
-			return ret;
-		}
-	}
-	return ret;
-}
-
 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)
@@ -1171,10 +988,8 @@
 		pr_err("copy_from_user failed\n");
 		return ret;
 	}
-	if (qseecom.qseos_version == QSEOS_VERSION_14)
-		ret = __qseecom_send_cmd(data, &req);
-	else
-		ret = __qseecom_send_cmd_legacy(data, &req);
+	ret = __qseecom_send_cmd(data, &req);
+
 	if (ret)
 		return ret;
 
@@ -1183,27 +998,8 @@
 	return ret;
 }
 
-static int __qseecom_send_cmd_req_clean_up(
-			struct qseecom_send_modfd_cmd_req *req)
-{
-	char *field;
-	uint32_t *update;
-	int ret = 0;
-	int i = 0;
-
-	for (i = 0; i < MAX_ION_FD; i++) {
-		if (req->ifd_data[i].fd > 0) {
-			field = (char *)req->cmd_req_buf +
-					req->ifd_data[i].cmd_buf_offset;
-			update = (uint32_t *) field;
-			*update = 0;
-		}
-	}
-	return ret;
-}
-
-static int __qseecom_update_with_phy_addr(
-			struct qseecom_send_modfd_cmd_req *req)
+static int __qseecom_update_cmd_buf(struct qseecom_send_modfd_cmd_req *req,
+								bool cleanup)
 {
 	struct ion_handle *ihandle;
 	char *field;
@@ -1242,7 +1038,11 @@
 			if (sg_ptr->nents == 1) {
 				uint32_t *update;
 				update = (uint32_t *) field;
-				*update = (uint32_t)sg_dma_address(sg_ptr->sgl);
+				if (cleanup)
+					*update = 0;
+				else
+					*update = (uint32_t)sg_dma_address(
+								sg_ptr->sgl);
 			} else {
 				struct qseecom_sg_entry *update;
 				struct scatterlist *sg;
@@ -1250,9 +1050,14 @@
 				update = (struct qseecom_sg_entry *) field;
 				sg = sg_ptr->sgl;
 				for (j = 0; j < sg_ptr->nents; j++) {
-					update->phys_addr = (uint32_t)
-						sg_dma_address(sg);
-					update->len = (uint32_t)sg->length;
+					if (cleanup) {
+						update->phys_addr = 0;
+						update->len = 0;
+					} else {
+						update->phys_addr = (uint32_t)
+							sg_dma_address(sg);
+						update->len = sg->length;
+					}
 					update++;
 					sg = sg_next(sg);
 				}
@@ -1286,18 +1091,15 @@
 	send_cmd_req.resp_buf = req.resp_buf;
 	send_cmd_req.resp_len = req.resp_len;
 
-	ret = __qseecom_update_with_phy_addr(&req);
+	ret = __qseecom_update_cmd_buf(&req, false);
 	if (ret)
 		return ret;
-	if (qseecom.qseos_version == QSEOS_VERSION_14)
-		ret = __qseecom_send_cmd(data, &send_cmd_req);
-	else
-		ret = __qseecom_send_cmd_legacy(data, &send_cmd_req);
-	__qseecom_send_cmd_req_clean_up(&req);
-
+	ret = __qseecom_send_cmd(data, &send_cmd_req);
 	if (ret)
 		return ret;
-
+	ret = __qseecom_update_cmd_buf(&req, true);
+	if (ret)
+		return ret;
 	pr_debug("sending cmd_req->rsp size: %u, ptr: 0x%p\n",
 			req.resp_len, req.resp_buf);
 	return ret;
@@ -1333,12 +1135,7 @@
 			return -ENODEV;
 		}
 		this_lstnr->rcv_req_flag = 0;
-		if (qseecom.qseos_version == QSEOS_VERSION_13) {
-			if (*((uint32_t *)this_lstnr->sb_virt) != 0)
-				break;
-		} else {
-			break;
-		}
+		break;
 	}
 	return ret;
 }
@@ -1636,11 +1433,6 @@
 	uint32_t len;
 	ion_phys_addr_t pa;
 
-	if (qseecom.qseos_version == QSEOS_VERSION_13) {
-		pr_err("This functionality is UNSUPPORTED in version 1.3\n");
-		return -EINVAL;
-	}
-
 	*handle = kzalloc(sizeof(struct qseecom_handle), GFP_KERNEL);
 	if (!(*handle)) {
 		pr_err("failed to allocate memory for kernel client handle\n");
@@ -1675,34 +1467,26 @@
 		*handle = NULL;
 		return -EINVAL;
 	}
-
+	mutex_lock(&app_access_lock);
 	if (qseecom.qsee_version > QSEEE_VERSION_00) {
-		mutex_lock(&app_access_lock);
 		if (qseecom.commonlib_loaded == false) {
 			ret = qseecom_load_commonlib_image(data);
 			if (ret == 0)
 				qseecom.commonlib_loaded = true;
 		}
-		mutex_unlock(&app_access_lock);
 	}
-
 	if (ret) {
 		pr_err("Failed to load commonlib image\n");
-		kfree(data);
-		kfree(*handle);
-		*handle = NULL;
-		return -EIO;
+		ret = -EIO;
+		goto err;
 	}
 
 	app_ireq.qsee_cmd_id = QSEOS_APP_LOOKUP_COMMAND;
 	memcpy(app_ireq.app_name, app_name, MAX_APP_NAME_SIZE);
 	ret = __qseecom_check_app_exists(app_ireq);
-	if (ret < 0) {
-		kzfree(data);
-		kfree(*handle);
-		*handle = NULL;
-		return -EINVAL;
-	}
+	if (ret < 0)
+		goto err;
+
 	data->client.app_id = ret;
 	if (ret > 0) {
 		pr_warn("App id %d for [%s] app exists\n", ret,
@@ -1725,26 +1509,17 @@
 		/* load the app and get the app_id  */
 		pr_debug("%s: Loading app for the first time'\n",
 				qseecom.pdev->init_name);
-		mutex_lock(&app_access_lock);
 		ret = __qseecom_load_fw(data, app_name);
-		mutex_unlock(&app_access_lock);
-
-		if (ret < 0) {
-			kfree(*handle);
-			kfree(data);
-			*handle = NULL;
-			return ret;
-		}
+		if (ret < 0)
+			goto err;
 		data->client.app_id = ret;
 	}
 	if (!found_app) {
 		entry = kmalloc(sizeof(*entry), GFP_KERNEL);
 		if (!entry) {
-			pr_err("kmalloc failed\n");
-			kfree(data);
-			kfree(*handle);
-			*handle = NULL;
-			return -ENOMEM;
+			pr_err("kmalloc for app entry failed\n");
+			ret =  -ENOMEM;
+			goto err;
 		}
 		entry->app_id = ret;
 		entry->ref_cnt = 1;
@@ -1769,7 +1544,8 @@
 	kclient_entry = kzalloc(sizeof(*kclient_entry), GFP_KERNEL);
 	if (!kclient_entry) {
 		pr_err("kmalloc failed\n");
-		return -ENOMEM;
+		ret = -ENOMEM;
+		goto err;
 	}
 	kclient_entry->handle = *handle;
 
@@ -1778,7 +1554,15 @@
 			&qseecom.registered_kclient_list_head);
 	spin_unlock_irqrestore(&qseecom.registered_kclient_list_lock, flags);
 
+	mutex_unlock(&app_access_lock);
 	return 0;
+
+err:
+	kfree(data);
+	kfree(*handle);
+	*handle = NULL;
+	mutex_unlock(&app_access_lock);
+	return ret;
 }
 EXPORT_SYMBOL(qseecom_start_app);
 
@@ -1791,10 +1575,6 @@
 	unsigned long flags = 0;
 	bool found_handle = false;
 
-	if (qseecom.qseos_version == QSEOS_VERSION_13) {
-		pr_err("This functionality is UNSUPPORTED in version 1.3\n");
-		return -EINVAL;
-	}
 	if ((handle == NULL)  || (*handle == NULL)) {
 		pr_err("Handle is not initialized\n");
 		return -EINVAL;
@@ -1835,11 +1615,6 @@
 	struct qseecom_send_cmd_req req = {0, 0, 0, 0};
 	struct qseecom_dev_handle *data;
 
-	if (qseecom.qseos_version == QSEOS_VERSION_13) {
-		pr_err("This functionality is UNSUPPORTED in version 1.3\n");
-		return -EINVAL;
-	}
-
 	if (handle == NULL) {
 		pr_err("Handle is not initialized\n");
 		return -EINVAL;
@@ -2419,12 +2194,13 @@
 	case QSEOS_RESULT_SUCCESS:
 		break;
 	case QSEOS_RESULT_FAIL_KEY_ID_EXISTS:
+		pr_debug("process_incomplete_cmd return 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_warn("process_incomplete_cmd return Key ID exits.\n");
+				pr_debug("process_incomplete_cmd return Key ID exists.\n");
 				ret = 0;
 			} else {
 				pr_err("process_incomplete_cmd FAILED, resp.result %d\n",
@@ -2503,9 +2279,8 @@
 			return -EFAULT;
 	}
 
-	if (qseecom.qsee.instance == qseecom.ce_drv.instance)
-		__qseecom_enable_clk(CLK_QSEE);
-	else
+	__qseecom_enable_clk(CLK_QSEE);
+	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);
@@ -2529,6 +2304,9 @@
 				&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;
 	}
 
@@ -2548,9 +2326,8 @@
 		break;
 	}
 
-	if (qseecom.qsee.instance == qseecom.ce_drv.instance)
-		__qseecom_disable_clk(CLK_QSEE);
-	else
+	__qseecom_disable_clk(CLK_QSEE);
+	if (qseecom.qsee.instance != qseecom.ce_drv.instance)
 		__qseecom_disable_clk(CLK_CE_DRV);
 
 	return ret;
@@ -2866,11 +2643,6 @@
 	}
 	case QSEECOM_IOCTL_LOAD_EXTERNAL_ELF_REQ: {
 		data->released = true;
-		if (qseecom.qseos_version == QSEOS_VERSION_13) {
-			pr_err("Loading External elf image unsupported in rev 0x13\n");
-			ret = -EINVAL;
-			break;
-		}
 		mutex_lock(&app_access_lock);
 		atomic_inc(&data->ioctl_count);
 		ret = qseecom_load_external_elf(data, argp);
@@ -2882,11 +2654,6 @@
 	}
 	case QSEECOM_IOCTL_UNLOAD_EXTERNAL_ELF_REQ: {
 		data->released = true;
-		if (qseecom.qseos_version == QSEOS_VERSION_13) {
-			pr_err("Unloading External elf image unsupported in rev 0x13\n");
-			ret = -EINVAL;
-			break;
-		}
 		mutex_lock(&app_access_lock);
 		atomic_inc(&data->ioctl_count);
 		ret = qseecom_unload_external_elf(data);
@@ -2990,23 +2757,7 @@
 	data->released = false;
 	init_waitqueue_head(&data->abort_wq);
 	atomic_set(&data->ioctl_count, 0);
-	if (qseecom.qseos_version == QSEOS_VERSION_13) {
-		int pil_error;
-		mutex_lock(&pil_access_lock);
-		if (pil_ref_cnt == 0) {
-			pil = subsystem_get("tzapps");
-			if (IS_ERR(pil)) {
-				pr_err("Playready PIL image load failed\n");
-				pil_error = PTR_ERR(pil);
-				pil = NULL;
-				pr_debug("tzapps image load FAILED\n");
-				mutex_unlock(&pil_access_lock);
-				return pil_error;
-			}
-		}
-		pil_ref_cnt++;
-		mutex_unlock(&pil_access_lock);
-	}
+
 	return ret;
 }
 
@@ -3044,13 +2795,6 @@
 	if (data->perf_enabled == true)
 		qsee_disable_clock_vote(data, CLK_DFAB);
 
-	if (qseecom.qseos_version == QSEOS_VERSION_13) {
-		mutex_lock(&pil_access_lock);
-		if (pil_ref_cnt == 1)
-			subsystem_put(pil);
-		pil_ref_cnt--;
-		mutex_unlock(&pil_access_lock);
-	}
 	kfree(data);
 
 	return ret;
@@ -3255,10 +2999,10 @@
 		}
 		qseecom.qseos_version = QSEOS_VERSION_14;
 	} else {
-		qseecom.qseos_version = QSEOS_VERSION_13;
-		qseecom.qsee_version = 0;
-		pil = NULL;
-		pil_ref_cnt = 0;
+		pr_err("QSEE legacy version is not supported:");
+		pr_err("Support for TZ1.3 and earlier is deprecated\n");
+		rc = -EINVAL;
+		goto err;
 	}
 	qseecom.commonlib_loaded = false;
 	qseecom.pdev = class_dev;
diff --git a/drivers/misc/tspp.c b/drivers/misc/tspp.c
index 501da4c8..e0fffbd 100644
--- a/drivers/misc/tspp.c
+++ b/drivers/misc/tspp.c
@@ -62,9 +62,8 @@
 /*
  * BAM descriptor FIFO size (in number of descriptors).
  * Max number of descriptors allowed by SPS which is 8K-1.
- * Restrict it to half of this to save DMA memory.
  */
-#define TSPP_SPS_DESCRIPTOR_COUNT      (4 * 1024 - 1)
+#define TSPP_SPS_DESCRIPTOR_COUNT      (8 * 1024 - 1)
 #define TSPP_PACKET_LENGTH             188
 #define TSPP_MIN_BUFFER_SIZE           (TSPP_PACKET_LENGTH)
 
@@ -2236,6 +2235,12 @@
 		return -EINVAL;
 	}
 
+	if (count > TSPP_NUM_BUFFERS) {
+		pr_err("%s: tspp requires a maximum of %i buffers\n",
+			__func__, TSPP_NUM_BUFFERS);
+		return -EINVAL;
+	}
+
 	channel = &pdev->channels[channel_id];
 
 	/* allow buffer allocation only if there was no previous buffer
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index 21e65b9..f01ddab 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -3122,6 +3122,37 @@
 #endif
 }
 
+static void mmc_blk_shutdown(struct mmc_card *card)
+{
+	struct mmc_blk_data *part_md;
+	struct mmc_blk_data *md = mmc_get_drvdata(card);
+	int rc;
+
+	/* Silent the block layer */
+	if (md) {
+		rc = mmc_queue_suspend(&md->queue);
+		if (rc)
+			goto suspend_error;
+		list_for_each_entry(part_md, &md->part, part) {
+			rc = mmc_queue_suspend(&part_md->queue);
+			if (rc)
+				goto suspend_error;
+		}
+	}
+
+	/* send power off notification */
+	if (mmc_card_mmc(card)) {
+		mmc_rpm_hold(card->host, &card->dev);
+		mmc_send_long_pon(card);
+		mmc_rpm_release(card->host, &card->dev);
+	}
+	return;
+
+suspend_error:
+	pr_err("%s: mmc_queue_suspend returned error = %d",
+			mmc_hostname(card->host), rc);
+}
+
 #ifdef CONFIG_PM
 static int mmc_blk_suspend(struct mmc_card *card)
 {
@@ -3181,6 +3212,7 @@
 	.remove		= mmc_blk_remove,
 	.suspend	= mmc_blk_suspend,
 	.resume		= mmc_blk_resume,
+	.shutdown	= mmc_blk_shutdown,
 };
 
 static int __init mmc_blk_init(void)
diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
index 7b9e133..ac2ecbb 100644
--- a/drivers/mmc/core/bus.c
+++ b/drivers/mmc/core/bus.c
@@ -123,6 +123,15 @@
 	return 0;
 }
 
+static void mmc_bus_shutdown(struct device *dev)
+{
+	struct mmc_driver *drv = to_mmc_driver(dev->driver);
+	struct mmc_card *card = mmc_dev_to_card(dev);
+
+	if (drv->shutdown)
+		drv->shutdown(card);
+}
+
 #ifdef CONFIG_PM_SLEEP
 static int mmc_bus_suspend(struct device *dev)
 {
@@ -153,10 +162,18 @@
 {
 	struct mmc_card *card = mmc_dev_to_card(dev);
 
-	if (mmc_use_core_runtime_pm(card->host))
-		return 0;
-	else
+	if (mmc_use_core_runtime_pm(card->host)) {
+		/*
+		 * If idle time bkops is running on the card, let's not get
+		 * into suspend.
+		 */
+		if (mmc_card_doing_bkops(card) && mmc_card_is_prog_state(card))
+			return -EBUSY;
+		else
+			return 0;
+	} else {
 		return mmc_power_save_host(card->host);
+	}
 }
 
 static int mmc_runtime_resume(struct device *dev)
@@ -238,6 +255,7 @@
 	.uevent		= mmc_bus_uevent,
 	.probe		= mmc_bus_probe,
 	.remove		= mmc_bus_remove,
+	.shutdown        = mmc_bus_shutdown,
 	.pm		= &mmc_bus_pm_ops,
 };
 
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 9fc599b..3d525e1 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -487,11 +487,6 @@
 	mmc_card_clr_need_bkops(card);
 
 	mmc_card_set_doing_bkops(card);
-	pr_debug("%s: %s: starting the polling thread\n",
-		 mmc_hostname(card->host), __func__);
-	queue_work(system_nrt_wq,
-		   &card->bkops_info.poll_for_completion);
-
 out:
 	mmc_release_host(card->host);
 	mmc_rpm_release(card->host, &card->dev);
@@ -499,81 +494,6 @@
 EXPORT_SYMBOL(mmc_start_bkops);
 
 /**
- * mmc_bkops_completion_polling() - Poll on the card status to
- * wait for the non-blocking BKOPS completion
- * @work:	The completion polling work
- *
- * The on-going reading of the card status will prevent the card
- * from getting into suspend while it is in the middle of
- * performing BKOPS.
- * Since the non blocking BKOPS can be interrupted by a fetched
- * request we also check IF mmc_card_doing_bkops in each
- * iteration.
- */
-void mmc_bkops_completion_polling(struct work_struct *work)
-{
-	struct mmc_card *card = container_of(work, struct mmc_card,
-			bkops_info.poll_for_completion);
-	unsigned long timeout_jiffies = jiffies +
-		msecs_to_jiffies(BKOPS_COMPLETION_POLLING_TIMEOUT_MS);
-	u32 status;
-	int err;
-
-	/*
-	 * Wait for the BKOPs to complete. Keep reading the status to prevent
-	 * the host from getting into suspend
-	 */
-	do {
-		mmc_rpm_hold(card->host, &card->dev);
-		mmc_claim_host(card->host);
-
-		if (!mmc_card_doing_bkops(card))
-			goto out;
-
-		err = mmc_send_status(card, &status);
-		if (err) {
-			pr_err("%s: error %d requesting status\n",
-			       mmc_hostname(card->host), err);
-			goto out;
-		}
-
-		/*
-		 * Some cards mishandle the status bits, so make sure to check
-		 * both the busy indication and the card state.
-		 */
-		if ((status & R1_READY_FOR_DATA) &&
-		    (R1_CURRENT_STATE(status) != R1_STATE_PRG)) {
-			pr_debug("%s: %s: completed BKOPs, exit polling\n",
-				 mmc_hostname(card->host), __func__);
-			mmc_card_clr_doing_bkops(card);
-			card->bkops_info.sectors_changed = 0;
-			goto out;
-		}
-
-		mmc_release_host(card->host);
-		mmc_rpm_release(card->host, &card->dev);
-
-		/*
-		 * Sleep before checking the card status again to allow the
-		 * card to complete the BKOPs operation
-		 */
-		msleep(BKOPS_COMPLETION_POLLING_INTERVAL_MS);
-	} while (time_before(jiffies, timeout_jiffies));
-
-	pr_err("%s: %s: exit polling due to timeout, stop bkops\n",
-	       mmc_hostname(card->host), __func__);
-	err = mmc_stop_bkops(card);
-	if (err)
-		pr_err("%s: %s: mmc_stop_bkops failed, err=%d\n",
-			       mmc_hostname(card->host), __func__, err);
-
-	return;
-out:
-	mmc_release_host(card->host);
-	mmc_rpm_release(card->host, &card->dev);
-}
-
-/**
  * mmc_start_idle_time_bkops() - check if a non urgent BKOPS is
  * needed
  * @work:	The idle time BKOPS work
@@ -1066,6 +986,36 @@
 }
 EXPORT_SYMBOL(mmc_wait_for_req);
 
+bool mmc_card_is_prog_state(struct mmc_card *card)
+{
+	bool rc;
+	struct mmc_command cmd;
+
+	mmc_claim_host(card->host);
+	memset(&cmd, 0, sizeof(struct mmc_command));
+	cmd.opcode = MMC_SEND_STATUS;
+	if (!mmc_host_is_spi(card->host))
+		cmd.arg = card->rca << 16;
+	cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
+
+	rc = mmc_wait_for_cmd(card->host, &cmd, 0);
+	if (rc) {
+		pr_err("%s: Get card status fail. rc=%d\n",
+		       mmc_hostname(card->host), rc);
+		rc = false;
+		goto out;
+	}
+
+	if (R1_CURRENT_STATE(cmd.resp[0]) == R1_STATE_PRG)
+		rc = true;
+	else
+		rc = false;
+out:
+	mmc_release_host(card->host);
+	return rc;
+}
+EXPORT_SYMBOL(mmc_card_is_prog_state);
+
 /**
  *	mmc_interrupt_hpi - Issue for High priority Interrupt
  *	@card: the MMC card associated with the HPI transfer
@@ -1189,6 +1139,17 @@
 	if (!mmc_card_doing_bkops(card))
 		goto out;
 
+	/*
+	 * If idle time bkops is running on the card, let's not get into
+	 * suspend.
+	 */
+	if (!mmc_use_core_runtime_pm(card->host) && mmc_card_doing_bkops(card)
+	    && (card->host->parent->power.runtime_status == RPM_SUSPENDING)
+	    && mmc_card_is_prog_state(card)) {
+		err = -EBUSY;
+		goto out;
+	}
+
 	err = mmc_interrupt_hpi(card);
 
 	/*
diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c
index 6c03bfc..edd6a5d 100644
--- a/drivers/mmc/core/host.c
+++ b/drivers/mmc/core/host.c
@@ -253,11 +253,19 @@
  *	mmc_host_may_gate_card - check if this card may be gated
  *	@card: card to check.
  */
-static bool mmc_host_may_gate_card(struct mmc_card *card)
+bool mmc_host_may_gate_card(struct mmc_card *card)
 {
 	/* If there is no card we may gate it */
 	if (!card)
 		return true;
+
+	/*
+	 * SDIO3.0 card allows the clock to be gated off so check if
+	 * that is the case or not.
+	 */
+	if (mmc_card_sdio(card) && card->cccr.async_intr_sup)
+		return true;
+
 	/*
 	 * Don't gate SDIO cards! These need to be clocked at all times
 	 * since they may be independent systems generating interrupts
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 89f8c91..9b9c1ed 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -18,6 +18,7 @@
 #include <linux/mmc/card.h>
 #include <linux/mmc/mmc.h>
 #include <linux/pm_runtime.h>
+#include <linux/reboot.h>
 
 #include "core.h"
 #include "bus.h"
@@ -900,6 +901,20 @@
 	return err;
 }
 
+static int mmc_reboot_notify(struct notifier_block *notify_block,
+		unsigned long event, void *unused)
+{
+	struct mmc_card *card = container_of(
+			notify_block, struct mmc_card, reboot_notify);
+
+	if (event != SYS_RESTART)
+		card->issue_long_pon = true;
+	else
+		card->issue_long_pon = false;
+
+	return NOTIFY_OK;
+}
+
 /*
  * Handle the detection and initialisation of a card.
  *
@@ -979,6 +994,7 @@
 		card->type = MMC_TYPE_MMC;
 		card->rca = 1;
 		memcpy(card->raw_cid, cid, sizeof(card->raw_cid));
+		card->reboot_notify.notifier_call = mmc_reboot_notify;
 	}
 
 	/*
@@ -1400,8 +1416,6 @@
 		if (card->ext_csd.bkops_en) {
 			INIT_DELAYED_WORK(&card->bkops_info.dw,
 					  mmc_start_idle_time_bkops);
-			INIT_WORK(&card->bkops_info.poll_for_completion,
-				  mmc_bkops_completion_polling);
 
 			/*
 			 * Calculate the time to start the BKOPs checking.
@@ -1462,6 +1476,22 @@
 	return err;
 }
 
+int mmc_send_long_pon(struct mmc_card *card)
+{
+	int err = 0;
+	struct mmc_host *host = card->host;
+
+	mmc_claim_host(host);
+	if (card->issue_long_pon && mmc_can_poweroff_notify(card)) {
+		err = mmc_poweroff_notify(host->card, EXT_CSD_POWER_OFF_LONG);
+		if (err)
+			pr_warning("%s: error %d sending Long PON",
+					mmc_hostname(host), err);
+	}
+	mmc_release_host(host);
+	return err;
+}
+
 /*
  * Host is being removed. Free up the current card.
  */
@@ -1470,6 +1500,7 @@
 	BUG_ON(!host);
 	BUG_ON(!host->card);
 
+	unregister_reboot_notifier(&host->card->reboot_notify);
 	mmc_remove_card(host->card);
 
 	mmc_claim_host(host);
@@ -1736,6 +1767,8 @@
 
 	mmc_init_clk_scaling(host);
 
+	register_reboot_notifier(&host->card->reboot_notify);
+
 	return 0;
 
 remove_card:
diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c
index 4e76f61..91e23ca 100644
--- a/drivers/mmc/core/sdio.c
+++ b/drivers/mmc/core/sdio.c
@@ -187,6 +187,23 @@
 				card->sw_caps.sd3_drv_type |= SD_DRIVER_TYPE_C;
 			if (data & SDIO_DRIVE_SDTD)
 				card->sw_caps.sd3_drv_type |= SD_DRIVER_TYPE_D;
+
+			ret = mmc_io_rw_direct(card, 0, 0,
+				SDIO_CCCR_INTERRUPT_EXTENSION, 0, &data);
+			if (ret)
+				goto out;
+			if (data & SDIO_SUPPORT_ASYNC_INTR) {
+				if (card->host->caps2 &
+				    MMC_CAP2_ASYNC_SDIO_IRQ_4BIT_MODE) {
+					data |= SDIO_ENABLE_ASYNC_INTR;
+					ret = mmc_io_rw_direct(card, 1, 0,
+						SDIO_CCCR_INTERRUPT_EXTENSION,
+						data, NULL);
+					if (ret)
+						goto out;
+					card->cccr.async_intr_sup = 1;
+				}
+			}
 		}
 
 		/* if no uhs mode ensure we check for high speed */
diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c
index caf5fe4..d872254 100644
--- a/drivers/mmc/host/msm_sdcc.c
+++ b/drivers/mmc/host/msm_sdcc.c
@@ -3404,7 +3404,7 @@
 	else
 		clk |= MCI_CLK_WIDEBUS_1;
 
-	if (msmsdcc_is_pwrsave(host))
+	if (msmsdcc_is_pwrsave(host) && mmc_host_may_gate_card(host->mmc->card))
 		clk |= MCI_CLK_PWRSAVE;
 
 	clk |= MCI_CLK_FLOWENA;
@@ -6147,6 +6147,7 @@
 	mmc->caps2 |= MMC_CAP2_CACHE_CTRL;
 	mmc->caps2 |= MMC_CAP2_POWEROFF_NOTIFY;
 	mmc->caps2 |= MMC_CAP2_STOP_REQUEST;
+	mmc->caps2 |= MMC_CAP2_ASYNC_SDIO_IRQ_4BIT_MODE;
 
 	if (plat->nonremovable)
 		mmc->caps |= MMC_CAP_NONREMOVABLE;
diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
index 89730b0..3c0576e 100644
--- a/drivers/mmc/host/sdhci-msm.c
+++ b/drivers/mmc/host/sdhci-msm.c
@@ -1418,10 +1418,20 @@
 		return;
 
 	bw = sdhci_get_bw_required(host, ios);
-	if (enable)
+	if (enable) {
 		sdhci_msm_bus_cancel_work_and_set_vote(host, bw);
-	else
-		sdhci_msm_bus_queue_work(host);
+	} else {
+		/*
+		 * If clock gating is enabled, then remove the vote
+		 * immediately because clocks will be disabled only
+		 * after SDHCI_MSM_MMC_CLK_GATE_DELAY and thus no
+		 * additional delay is required to remove the bus vote.
+		 */
+		if (host->mmc->clkgate_delay)
+			sdhci_msm_bus_cancel_work_and_set_vote(host, 0);
+		else
+			sdhci_msm_bus_queue_work(host);
+	}
 }
 
 /* Regulator utility functions */
@@ -1942,12 +1952,15 @@
 	if (enable && !atomic_read(&msm_host->clks_on)) {
 		pr_debug("%s: request to enable clocks\n",
 				mmc_hostname(host->mmc));
+
+		sdhci_msm_bus_voting(host, 1);
+
 		if (!IS_ERR_OR_NULL(msm_host->bus_clk)) {
 			rc = clk_prepare_enable(msm_host->bus_clk);
 			if (rc) {
 				pr_err("%s: %s: failed to enable the bus-clock with error %d\n",
 					mmc_hostname(host->mmc), __func__, rc);
-				goto out;
+				goto remove_vote;
 			}
 		}
 		if (!IS_ERR(msm_host->pclk)) {
@@ -1976,6 +1989,8 @@
 			clk_disable_unprepare(msm_host->pclk);
 		if (!IS_ERR_OR_NULL(msm_host->bus_clk))
 			clk_disable_unprepare(msm_host->bus_clk);
+
+		sdhci_msm_bus_voting(host, 0);
 	}
 	atomic_set(&msm_host->clks_on, enable);
 	goto out;
@@ -1985,6 +2000,9 @@
 disable_bus_clk:
 	if (!IS_ERR_OR_NULL(msm_host->bus_clk))
 		clk_disable_unprepare(msm_host->bus_clk);
+remove_vote:
+	if (msm_host->msm_bus_vote.client_handle)
+		sdhci_msm_bus_cancel_work_and_set_vote(host, 0);
 out:
 	return rc;
 }
@@ -2031,6 +2049,11 @@
 		}
 		msm_host->clk_rate = sup_clock;
 		host->clock = clock;
+		/*
+		 * Update the bus vote in case of frequency change due to
+		 * clock scaling.
+		 */
+		sdhci_msm_bus_voting(host, 1);
 	}
 }
 
@@ -2122,7 +2145,6 @@
 	.toggle_cdr = sdhci_msm_toggle_cdr,
 	.get_max_segments = sdhci_msm_max_segs,
 	.set_clock = sdhci_msm_set_clock,
-	.platform_bus_voting = sdhci_msm_bus_voting,
 	.get_min_clock = sdhci_msm_get_min_clock,
 	.get_max_clock = sdhci_msm_get_max_clock,
 	.disable_data_xfer = sdhci_msm_disable_data_xfer,
@@ -2137,7 +2159,7 @@
 	int ret = 0, dead = 0;
 	u32 vdd_max_current;
 	u16 host_version;
-	u32 pwr;
+	u32 pwr, irq_status, irq_ctl;
 
 	pr_debug("%s: Enter %s\n", dev_name(&pdev->dev), __func__);
 	msm_host = devm_kzalloc(&pdev->dev, sizeof(struct sdhci_msm_host),
@@ -2226,11 +2248,20 @@
 	msm_host->clk_rate = sdhci_msm_get_min_clock(host);
 	atomic_set(&msm_host->clks_on, 1);
 
+	ret = sdhci_msm_bus_register(msm_host, pdev);
+	if (ret)
+		goto clk_disable;
+
+	if (msm_host->msm_bus_vote.client_handle)
+		INIT_DELAYED_WORK(&msm_host->msm_bus_vote.vote_work,
+				  sdhci_msm_bus_work);
+	sdhci_msm_bus_voting(host, 1);
+
 	/* Setup regulators */
 	ret = sdhci_msm_vreg_init(&pdev->dev, msm_host->pdata, true);
 	if (ret) {
 		dev_err(&pdev->dev, "Regulator setup failed (%d)\n", ret);
-		goto clk_disable;
+		goto bus_unregister;
 	}
 
 	/* Reset the core and Enable SDHC mode */
@@ -2265,6 +2296,27 @@
 	writel_relaxed(HC_MODE_EN, (msm_host->core_mem + CORE_HC_MODE));
 
 	/*
+	 * CORE_SW_RST above may trigger power irq if previous status of PWRCTL
+	 * was either BUS_ON or IO_HIGH_V. So before we enable the power irq
+	 * interrupt in GIC (by registering the interrupt handler), we need to
+	 * ensure that any pending power irq interrupt status is acknowledged
+	 * otherwise power irq interrupt handler would be fired prematurely.
+	 */
+	irq_status = readl_relaxed(msm_host->core_mem + CORE_PWRCTL_STATUS);
+	writel_relaxed(irq_status, (msm_host->core_mem + CORE_PWRCTL_CLEAR));
+	irq_ctl = readl_relaxed(msm_host->core_mem + CORE_PWRCTL_CTL);
+	if (irq_status & (CORE_PWRCTL_BUS_ON | CORE_PWRCTL_BUS_OFF))
+		irq_ctl |= CORE_PWRCTL_BUS_SUCCESS;
+	if (irq_status & (CORE_PWRCTL_IO_HIGH | CORE_PWRCTL_IO_LOW))
+		irq_ctl |= CORE_PWRCTL_IO_SUCCESS;
+	writel_relaxed(irq_ctl, (msm_host->core_mem + CORE_PWRCTL_CTL));
+	/*
+	 * Ensure that above writes are propogated before interrupt enablement
+	 * in GIC.
+	 */
+	mb();
+
+	/*
 	 * Following are the deviations from SDHC spec v3.0 -
 	 * 1. Card detection is handled using separate GPIO.
 	 * 2. Bus power control is handled by interacting with PMIC.
@@ -2356,14 +2408,6 @@
 
 	host->cpu_dma_latency_us = msm_host->pdata->cpu_dma_latency_us;
 
-	ret = sdhci_msm_bus_register(msm_host, pdev);
-	if (ret)
-		goto vreg_deinit;
-
-	if (msm_host->msm_bus_vote.client_handle)
-		INIT_DELAYED_WORK(&msm_host->msm_bus_vote.vote_work,
-				  sdhci_msm_bus_work);
-
 	init_completion(&msm_host->pwr_irq_completion);
 
 	if (gpio_is_valid(msm_host->pdata->status_gpio)) {
@@ -2372,7 +2416,7 @@
 		if (ret) {
 			dev_err(&pdev->dev, "%s: Failed to request card detection IRQ %d\n",
 					__func__, ret);
-			goto bus_unregister;
+			goto vreg_deinit;
 		}
 	}
 
@@ -2415,10 +2459,12 @@
 free_cd_gpio:
 	if (gpio_is_valid(msm_host->pdata->status_gpio))
 		mmc_cd_gpio_free(msm_host->mmc);
-bus_unregister:
-	sdhci_msm_bus_unregister(msm_host);
 vreg_deinit:
 	sdhci_msm_vreg_init(&pdev->dev, msm_host->pdata, false);
+bus_unregister:
+	if (msm_host->msm_bus_vote.client_handle)
+		sdhci_msm_bus_cancel_work_and_set_vote(host, 0);
+	sdhci_msm_bus_unregister(msm_host);
 clk_disable:
 	if (!IS_ERR(msm_host->clk))
 		clk_disable_unprepare(msm_host->clk);
@@ -2474,6 +2520,16 @@
 	disable_irq(host->irq);
 	disable_irq(msm_host->pwr_irq);
 
+	/*
+	 * Remove the vote immediately only if clocks are off in which
+	 * case we might have queued work to remove vote but it may not
+	 * be completed before runtime suspend or system suspend.
+	 */
+	if (!atomic_read(&msm_host->clks_on)) {
+		if (msm_host->msm_bus_vote.client_handle)
+			sdhci_msm_bus_cancel_work_and_set_vote(host, 0);
+	}
+
 	return 0;
 }
 
@@ -2507,9 +2563,6 @@
 		goto out;
 	}
 
-	if (msm_host->msm_bus_vote.client_handle)
-		sdhci_msm_bus_cancel_work_and_set_vote(host, 0);
-
 	return sdhci_msm_runtime_suspend(dev);
 out:
 	return ret;
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 3efea77..4f9bbad 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -51,6 +51,7 @@
 static void sdhci_finish_command(struct sdhci_host *);
 static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode);
 static void sdhci_tuning_timer(unsigned long data);
+static bool sdhci_check_state(struct sdhci_host *);
 
 #ifdef CONFIG_PM_RUNTIME
 static int sdhci_runtime_pm_get(struct sdhci_host *host);
@@ -292,7 +293,7 @@
 
 	spin_lock_irqsave(&host->lock, flags);
 
-	if (host->runtime_suspended)
+	if (host->runtime_suspended || sdhci_check_state(host))
 		goto out;
 
 	if (brightness == LED_OFF)
@@ -1395,7 +1396,8 @@
 	struct mmc_host *mmc = host->mmc;
 
 	if (!host->clock || !host->pwr ||
-	    pm_runtime_suspended(mmc->parent))
+	    (mmc_use_core_runtime_pm(mmc) ?
+	     pm_runtime_suspended(mmc->parent) : 0))
 		return true;
 	else
 		return false;
@@ -2887,6 +2889,8 @@
 	host = mmc_priv(mmc);
 	host->mmc = mmc;
 
+	spin_lock_init(&host->lock);
+
 	return host;
 }
 
@@ -3232,8 +3236,6 @@
 		return -ENODEV;
 	}
 
-	spin_lock_init(&host->lock);
-
 	/*
 	 * Maximum number of segments. Depends on if the hardware
 	 * can do scatter/gather or not.
diff --git a/drivers/mtd/devices/msm_qpic_nand.c b/drivers/mtd/devices/msm_qpic_nand.c
index 5fda343..efa09f6 100644
--- a/drivers/mtd/devices/msm_qpic_nand.c
+++ b/drivers/mtd/devices/msm_qpic_nand.c
@@ -89,6 +89,7 @@
 
 /* QPIC NANDc (NAND Controller) Register Set */
 #define MSM_NAND_REG(info, off)		    (info->nand_phys + off)
+#define MSM_NAND_QPIC_VERSION(info)	    MSM_NAND_REG(info, 0x20100)
 #define MSM_NAND_FLASH_CMD(info)	    MSM_NAND_REG(info, 0x30000)
 #define MSM_NAND_ADDR0(info)                MSM_NAND_REG(info, 0x30004)
 #define MSM_NAND_ADDR1(info)                MSM_NAND_REG(info, 0x30008)
@@ -138,7 +139,7 @@
 
 #define MSM_NAND_CTRL(info)		    MSM_NAND_REG(info, 0x30F00)
 #define BAM_MODE_EN	0
-
+#define MSM_NAND_VERSION(info)         MSM_NAND_REG(info, 0x30F08)
 #define MSM_NAND_READ_LOCATION_0(info)      MSM_NAND_REG(info, 0x30F20)
 #define MSM_NAND_READ_LOCATION_1(info)      MSM_NAND_REG(info, 0x30F24)
 
@@ -152,6 +153,12 @@
 #define MSM_NAND_CMD_BLOCK_ERASE        0x3A
 #define MSM_NAND_CMD_FETCH_ID           0x0B
 
+/* Version Mask */
+#define MSM_NAND_VERSION_MAJOR_MASK	0xF0000000
+#define MSM_NAND_VERSION_MAJOR_SHIFT	28
+#define MSM_NAND_VERSION_MINOR_MASK	0x0FFF0000
+#define MSM_NAND_VERSION_MINOR_SHIFT	16
+
 /* Structure that defines a NAND SPS command element */
 struct msm_nand_sps_cmd {
 	struct sps_command_element ce;
@@ -623,6 +630,48 @@
 	uint32_t ecc_bch_cfg;
 };
 
+struct version {
+	uint16_t nand_major;
+	uint16_t nand_minor;
+	uint16_t qpic_major;
+	uint16_t qpic_minor;
+};
+
+static int msm_nand_version_check(struct msm_nand_info *info,
+			struct version *nandc_version)
+{
+	uint32_t qpic_ver = 0, nand_ver = 0;
+	int err = 0;
+
+	/* Lookup the version to identify supported features */
+	err = msm_nand_flash_rd_reg(info, MSM_NAND_VERSION(info),
+		&nand_ver);
+	if (err) {
+		pr_err("Failed to read NAND_VERSION, err=%d\n", err);
+		goto out;
+	}
+	nandc_version->nand_major = (nand_ver & MSM_NAND_VERSION_MAJOR_MASK) >>
+		MSM_NAND_VERSION_MAJOR_SHIFT;
+	nandc_version->nand_minor = (nand_ver & MSM_NAND_VERSION_MINOR_MASK) >>
+		MSM_NAND_VERSION_MINOR_SHIFT;
+
+	err = msm_nand_flash_rd_reg(info, MSM_NAND_QPIC_VERSION(info),
+		&qpic_ver);
+	if (err) {
+		pr_err("Failed to read QPIC_VERSION, err=%d\n", err);
+		goto out;
+	}
+	nandc_version->qpic_major = (qpic_ver & MSM_NAND_VERSION_MAJOR_MASK) >>
+			MSM_NAND_VERSION_MAJOR_SHIFT;
+	nandc_version->qpic_minor = (qpic_ver & MSM_NAND_VERSION_MINOR_MASK) >>
+			MSM_NAND_VERSION_MINOR_SHIFT;
+	pr_info("nand_major:%d, nand_minor:%d, qpic_major:%d, qpic_minor:%d\n",
+		nandc_version->nand_major, nandc_version->nand_minor,
+		nandc_version->qpic_major, nandc_version->qpic_minor);
+out:
+	return err;
+}
+
 /*
  * Function to identify whether the attached NAND flash device is
  * complaint to ONFI spec or not. If yes, then it reads the ONFI parameter
@@ -661,6 +710,18 @@
 		uint32_t flash_status;
 	} *dma_buffer;
 
+
+	/* Lookup the version to identify supported features */
+	struct version nandc_version = {0};
+
+	ret = msm_nand_version_check(info, &nandc_version);
+	if (!ret && !(nandc_version.nand_major == 1 &&
+			nandc_version.nand_minor == 1 &&
+			nandc_version.qpic_major == 1 &&
+			nandc_version.qpic_minor == 1)) {
+		ret = -EPERM;
+		goto out;
+	}
 	wait_event(chip->dma_wait_queue, (onfi_param_info_buf =
 		msm_nand_get_dma_buffer(chip, ONFI_PARAM_INFO_LENGTH)));
 	dma_addr_param_info = msm_virt_to_dma(chip, onfi_param_info_buf);
@@ -839,6 +900,7 @@
 	msm_nand_release_dma_buffer(chip, dma_buffer, sizeof(*dma_buffer));
 	msm_nand_release_dma_buffer(chip, onfi_param_info_buf,
 			ONFI_PARAM_INFO_LENGTH);
+out:
 	return ret;
 }
 
diff --git a/drivers/mtd/nand/nand_ids.c b/drivers/mtd/nand/nand_ids.c
index af4fe8c..72ced9d 100644
--- a/drivers/mtd/nand/nand_ids.c
+++ b/drivers/mtd/nand/nand_ids.c
@@ -161,6 +161,7 @@
 	 BBT_AUTO_REFRESH
 	},
 
+	{"NAND 4GiB 1,8V 8-bit",       0xAC, 2048, 4096, 0x20000, 0},
 	{NULL,}
 };
 
diff --git a/drivers/net/wireless/wcnss/wcnss_vreg.c b/drivers/net/wireless/wcnss/wcnss_vreg.c
index 59a6b68..c02daa4 100644
--- a/drivers/net/wireless/wcnss/wcnss_vreg.c
+++ b/drivers/net/wireless/wcnss/wcnss_vreg.c
@@ -31,6 +31,7 @@
 static LIST_HEAD(power_on_lock_list);
 static DEFINE_MUTEX(list_lock);
 static DEFINE_SEMAPHORE(wcnss_power_on_lock);
+static int auto_detect;
 
 #define MSM_RIVA_PHYS           0x03204000
 #define MSM_PRONTO_PHYS         0xfb21b000
@@ -42,11 +43,17 @@
 #define PRONTO_SPARE_OFFSET     0x1088
 #define NVBIN_DLND_BIT          BIT(25)
 
+#define PRONTO_IRIS_REG_READ_OFFSET       0x1134
+#define PRONTO_IRIS_REG_CHIP_ID           0x04
+
 #define WCNSS_PMU_CFG_IRIS_XO_CFG          BIT(3)
 #define WCNSS_PMU_CFG_IRIS_XO_EN           BIT(4)
 #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_XO_READ         BIT(9)
+#define WCNSS_PMU_CFG_IRIS_XO_READ_STS     BIT(10)
+
 #define WCNSS_PMU_CFG_IRIS_XO_MODE         0x6
 #define WCNSS_PMU_CFG_IRIS_XO_MODE_48      (3 << 1)
 
@@ -56,6 +63,8 @@
 #define VREG_OPTIMUM_MODE_MASK      0x0004
 #define VREG_ENABLE_MASK            0x0008
 
+#define WCNSS_INVALID_IRIS_REG      0xbaadbaad
+
 struct vregs_info {
 	const char * const name;
 	int state;
@@ -110,10 +119,38 @@
 	struct list_head list;
 };
 
+enum {
+	WCNSS_XO_48MHZ = 1,
+	WCNSS_XO_19MHZ,
+	WCNSS_XO_INVALID,
+};
+
+enum {
+	IRIS_3660, /* also 3660A and 3680 */
+	IRIS_3620
+};
+
+
+int xo_auto_detect(u32 reg)
+{
+	reg >>= 30;
+
+	switch (reg) {
+	case IRIS_3660:
+		return WCNSS_XO_48MHZ;
+
+	case IRIS_3620:
+		return WCNSS_XO_19MHZ;
+
+	default:
+		return WCNSS_XO_INVALID;
+	}
+}
 
 static int configure_iris_xo(struct device *dev, bool use_48mhz_xo, int on)
 {
 	u32 reg = 0;
+	u32 iris_reg = WCNSS_INVALID_IRIS_REG;
 	int rc = 0;
 	int size = 0;
 	int pmu_offset = 0;
@@ -121,6 +158,7 @@
 	unsigned long wcnss_phys_addr;
 	void __iomem *pmu_conf_reg;
 	void __iomem *spare_reg;
+	void __iomem *iris_read_reg;
 	struct clk *clk;
 	struct clk *clk_rf = NULL;
 
@@ -136,14 +174,6 @@
 			return PTR_ERR(clk);
 		}
 
-		if (!use_48mhz_xo) {
-			clk_rf = clk_get(dev, "rf_clk");
-			if (IS_ERR(clk_rf)) {
-				pr_err("Couldn't get rf_clk\n");
-				clk_put(clk);
-				return PTR_ERR(clk_rf);
-			}
-		}
 	} else {
 		wcnss_phys_addr = MSM_RIVA_PHYS;
 		pmu_offset = RIVA_PMU_OFFSET;
@@ -187,10 +217,44 @@
 				WCNSS_PMU_CFG_IRIS_XO_EN;
 		writel_relaxed(reg, pmu_conf_reg);
 
+		if (wcnss_xo_auto_detect_enabled()) {
+			iris_read_reg = msm_wcnss_base +
+				PRONTO_IRIS_REG_READ_OFFSET;
+			iris_reg = readl_relaxed(iris_read_reg);
+		}
+
+		if (iris_reg != WCNSS_INVALID_IRIS_REG) {
+			iris_reg &= 0xffff;
+			iris_reg |= PRONTO_IRIS_REG_CHIP_ID;
+			writel_relaxed(iris_reg, iris_read_reg);
+
+			/* Iris read */
+			reg = readl_relaxed(pmu_conf_reg);
+			reg |= WCNSS_PMU_CFG_IRIS_XO_READ;
+			writel_relaxed(reg, pmu_conf_reg);
+
+			/* Wait for PMU_CFG.iris_reg_read_sts */
+			while (readl_relaxed(pmu_conf_reg) &
+					WCNSS_PMU_CFG_IRIS_XO_READ_STS)
+				cpu_relax();
+
+			iris_reg = readl_relaxed(iris_read_reg);
+			auto_detect = xo_auto_detect(iris_reg);
+
+			/* Reset iris read bit */
+			reg &= ~WCNSS_PMU_CFG_IRIS_XO_READ;
+
+		} else if (wcnss_xo_auto_detect_enabled())
+			/* Default to 48 MHZ */
+			auto_detect = WCNSS_XO_48MHZ;
+		else
+			auto_detect = WCNSS_XO_INVALID;
+
 		/* Clear XO_MODE[b2:b1] bits. Clear implies 19.2 MHz TCXO */
 		reg &= ~(WCNSS_PMU_CFG_IRIS_XO_MODE);
 
-		if (use_48mhz_xo)
+		if ((use_48mhz_xo && auto_detect == WCNSS_XO_INVALID)
+				|| auto_detect ==  WCNSS_XO_48MHZ)
 			reg |= WCNSS_PMU_CFG_IRIS_XO_MODE_48;
 
 		writel_relaxed(reg, pmu_conf_reg);
@@ -210,30 +274,41 @@
 		writel_relaxed(reg, pmu_conf_reg);
 		clk_disable_unprepare(clk);
 
-		if (!use_48mhz_xo) {
+		if ((!use_48mhz_xo && auto_detect == WCNSS_XO_INVALID)
+				|| auto_detect ==  WCNSS_XO_19MHZ) {
+
+			clk_rf = clk_get(dev, "rf_clk");
+			if (IS_ERR(clk_rf)) {
+				pr_err("Couldn't get rf_clk\n");
+				goto fail;
+			}
+
 			rc = clk_prepare_enable(clk_rf);
 			if (rc) {
 				pr_err("clk_rf enable failed\n");
 				goto fail;
 			}
 		}
-	}  else if (clk_rf != NULL && !use_48mhz_xo)
-			clk_disable_unprepare(clk_rf);
+
+	}  else if ((!use_48mhz_xo && auto_detect == WCNSS_XO_INVALID)
+			|| auto_detect ==  WCNSS_XO_19MHZ) {
+		clk_rf = clk_get(dev, "rf_clk");
+		if (IS_ERR(clk_rf)) {
+			pr_err("Couldn't get rf_clk\n");
+			goto fail;
+		}
+		clk_disable_unprepare(clk_rf);
+	}
+
 	/* Add some delay for XO to settle */
 	msleep(20);
 
+fail:
 	clk_put(clk);
 
-	if (wcnss_hardware_type() == WCNSS_PRONTO_HW) {
-		if (!use_48mhz_xo)
-			clk_put(clk_rf);
-	}
-
-	return rc;
-fail:
 	if (clk_rf != NULL)
 		clk_put(clk_rf);
-	clk_put(clk);
+
 	return rc;
 }
 
diff --git a/drivers/net/wireless/wcnss/wcnss_wlan.c b/drivers/net/wireless/wcnss/wcnss_wlan.c
index c30f46f..e8b8fc2 100644
--- a/drivers/net/wireless/wcnss/wcnss_wlan.c
+++ b/drivers/net/wireless/wcnss/wcnss_wlan.c
@@ -56,6 +56,10 @@
 module_param(has_calibrated_data, int, S_IWUSR | S_IRUGO);
 MODULE_PARM_DESC(has_calibrated_data, "whether calibrated data file available");
 
+static int has_autodetect_xo = WCNSS_CONFIG_UNSPECIFIED;
+module_param(has_autodetect_xo, int, S_IWUSR | S_IRUGO);
+MODULE_PARM_DESC(has_autodetect_xo, "Perform auto detect to configure IRIS XO");
+
 static int do_not_cancel_vote = WCNSS_CONFIG_UNSPECIFIED;
 module_param(do_not_cancel_vote, int, S_IWUSR | S_IRUGO);
 MODULE_PARM_DESC(do_not_cancel_vote, "Do not cancel votes for wcnss");
@@ -99,6 +103,8 @@
 #define CCU_PRONTO_LAST_ADDR1_OFFSET		0x10
 #define CCU_PRONTO_LAST_ADDR2_OFFSET		0x14
 
+#define WCNSS_DEF_WLAN_RX_BUFF_COUNT		1024
+
 #define WCNSS_CTRL_CHANNEL			"WCNSS_CTRL"
 #define WCNSS_MAX_FRAME_SIZE		(4*1024)
 #define WCNSS_VERSION_LEN			30
@@ -254,6 +260,7 @@
 	const struct dev_pm_ops *pm_ops;
 	int		triggered;
 	int		smd_channel_ready;
+	u32		wlan_rx_buff_count;
 	smd_channel_t	*smd_ch;
 	unsigned char	wcnss_version[WCNSS_VERSION_LEN];
 	unsigned char   fw_major;
@@ -873,6 +880,11 @@
 module_param_call(enable_wcnss_suspend_notify, enable_wcnss_suspend_notify_set,
 		param_get_int, &enable_wcnss_suspend_notify, S_IRUGO | S_IWUSR);
 
+int wcnss_xo_auto_detect_enabled(void)
+{
+	return (has_autodetect_xo == 1 ? 1 : 0);
+}
+
 
 void wcnss_suspend_notify(void)
 {
@@ -968,6 +980,17 @@
 		return -ENODEV;
 }
 
+u32 wcnss_get_wlan_rx_buff_count(void)
+{
+	if (penv)
+		return penv->wlan_rx_buff_count;
+	else
+		return WCNSS_DEF_WLAN_RX_BUFF_COUNT;
+
+}
+EXPORT_SYMBOL(wcnss_get_wlan_rx_buff_count);
+
+
 static int wcnss_smd_tx(void *data, int len)
 {
 	int ret = 0;
@@ -1026,6 +1049,8 @@
 	rc = wcnss_smd_tx(msg, rsphdr->msg_len);
 	if (rc < 0)
 		pr_err("wcnss: smd tx failed\n");
+
+	kfree(msg);
 }
 
 /* Collect calibrated data from WCNSS */
@@ -1487,7 +1512,12 @@
 	int size = 0;
 	struct resource *res;
 	int has_pronto_hw = of_property_read_bool(pdev->dev.of_node,
-									"qcom,has_pronto_hw");
+									"qcom,has-pronto-hw");
+
+	if (of_property_read_u32(pdev->dev.of_node,
+			"qcom,wlan-rx-buff-count", &penv->wlan_rx_buff_count)) {
+		penv->wlan_rx_buff_count = WCNSS_DEF_WLAN_RX_BUFF_COUNT;
+	}
 
 	/* make sure we are only triggered once */
 	if (penv->triggered)
@@ -1499,7 +1529,7 @@
 	if (WCNSS_CONFIG_UNSPECIFIED == has_48mhz_xo) {
 		if (has_pronto_hw) {
 			has_48mhz_xo = of_property_read_bool(pdev->dev.of_node,
-										"qcom,has_48mhz_xo");
+										"qcom,has-48mhz-xo");
 		} else {
 			has_48mhz_xo = pdata->has_48mhz_xo;
 		}
@@ -1507,6 +1537,11 @@
 	penv->wcnss_hw_type = (has_pronto_hw) ? WCNSS_PRONTO_HW : WCNSS_RIVA_HW;
 	penv->wlan_config.use_48mhz_xo = has_48mhz_xo;
 
+	if (WCNSS_CONFIG_UNSPECIFIED == has_autodetect_xo && has_pronto_hw) {
+		has_autodetect_xo = of_property_read_bool(pdev->dev.of_node,
+									"qcom,has-autodetect-xo");
+	}
+
 	penv->thermal_mitigation = 0;
 	strlcpy(penv->wcnss_version, "INVALID", WCNSS_VERSION_LEN);
 
@@ -1648,6 +1683,9 @@
 {
 	struct platform_device *pdev;
 
+	if (!penv)
+		return -EFAULT;
+
 	/* first open is only to trigger WCNSS platform driver */
 	if (!penv->triggered) {
 		pr_info(DEVICE " triggered by userspace\n");
@@ -1675,7 +1713,7 @@
 {
 	int rc = 0;
 
-	if (!penv->device_opened)
+	if (!penv || !penv->device_opened)
 		return -EFAULT;
 
 	rc = wait_event_interruptible(penv->read_wait, penv->fw_cal_rcvd
@@ -1714,7 +1752,7 @@
 	int rc = 0;
 	int size = 0;
 
-	if (!penv->device_opened || penv->user_cal_available)
+	if (!penv || !penv->device_opened || penv->user_cal_available)
 		return -EFAULT;
 
 	if (penv->user_cal_rcvd == 0 && count >= 4
diff --git a/drivers/platform/msm/ipa/a2_service.c b/drivers/platform/msm/ipa/a2_service.c
index fa71efc..0d77741 100644
--- a/drivers/platform/msm/ipa/a2_service.c
+++ b/drivers/platform/msm/ipa/a2_service.c
@@ -536,6 +536,8 @@
 				__func__);
 		return -EFAULT;
 	}
+	if (sps_ctrl_bam_dma_clk(true))
+		WARN_ON(1);
 	memset(&connect_params, 0, sizeof(struct ipa_sys_connect_params));
 	connect_params.client = IPA_CLIENT_A2_TETHERED_CONS;
 	connect_params.notify = ipa_tethered_notify;
@@ -606,6 +608,8 @@
 	ipa_bridge_teardown(IPA_BRIDGE_DIR_UL, IPA_BRIDGE_TYPE_TETHERED,
 			a2_mux_ctx->tethered_prod);
 bridge_tethered_ul_failed:
+	if (sps_ctrl_bam_dma_clk(false))
+		WARN_ON(1);
 	return ret;
 }
 
@@ -647,6 +651,8 @@
 				__func__, ret);
 		return ret;
 	}
+	if (sps_ctrl_bam_dma_clk(false))
+		WARN_ON(1);
 	verify_tx_queue_is_empty(__func__);
 	(void) ipa_rm_release_resource(IPA_RM_RESOURCE_A2_PROD);
 	if (a2_mux_ctx->disconnect_ack)
diff --git a/drivers/platform/msm/ipa/ipa.c b/drivers/platform/msm/ipa/ipa.c
index 35b2561..67c86b9 100644
--- a/drivers/platform/msm/ipa/ipa.c
+++ b/drivers/platform/msm/ipa/ipa.c
@@ -50,12 +50,6 @@
 #define IPA_AGGR_STR_IN_BYTES(str) \
 	(strnlen((str), IPA_AGGR_MAX_STR_LENGTH - 1) + 1)
 
-/*
- * This equals a timer value of 162.56us. This value was
- * determined empirically and shows good bi-directional
- * WLAN throughputs
- */
-#define IPA_HOLB_TMR_DEFAULT_VAL 0x7f
 
 static struct ipa_plat_drv_res ipa_res = {0, };
 static struct of_device_id ipa_plat_drv_match[] = {
@@ -1603,8 +1597,6 @@
 		result = -ENOMEM;
 		goto fail_mem;
 	}
-	ipa_ctx->hol_en = 0x1;
-	ipa_ctx->hol_timer = IPA_HOLB_TMR_DEFAULT_VAL;
 
 	IPADBG("polling_mode=%u delay_ms=%u\n", polling_mode, polling_delay_ms);
 	ipa_ctx->polling_mode = polling_mode;
@@ -1738,22 +1730,6 @@
 		result = -ENOMEM;
 		goto fail_rt_tbl_cache;
 	}
-	ipa_ctx->tx_pkt_wrapper_cache =
-	   kmem_cache_create("IPA TX PKT WRAPPER",
-			   sizeof(struct ipa_tx_pkt_wrapper), 0, 0, NULL);
-	if (!ipa_ctx->tx_pkt_wrapper_cache) {
-		IPAERR(":ipa tx pkt wrapper cache create failed\n");
-		result = -ENOMEM;
-		goto fail_tx_pkt_wrapper_cache;
-	}
-	ipa_ctx->rx_pkt_wrapper_cache =
-	   kmem_cache_create("IPA RX PKT WRAPPER",
-			   sizeof(struct ipa_rx_pkt_wrapper), 0, 0, NULL);
-	if (!ipa_ctx->rx_pkt_wrapper_cache) {
-		IPAERR(":ipa rx pkt wrapper cache create failed\n");
-		result = -ENOMEM;
-		goto fail_rx_pkt_wrapper_cache;
-	}
 	ipa_ctx->tree_node_cache =
 	   kmem_cache_create("IPA TREE", sizeof(struct ipa_tree_node), 0, 0,
 			   NULL);
@@ -1822,6 +1798,8 @@
 	mutex_init(&ipa_ctx->lock);
 	mutex_init(&ipa_ctx->nat_mem.lock);
 
+	skb_queue_head_init(&ipa_ctx->rx_list);
+
 	for (i = 0; i < IPA_A5_SYS_MAX; i++) {
 		INIT_LIST_HEAD(&ipa_ctx->sys[i].head_desc_list);
 		spin_lock_init(&ipa_ctx->sys[i].spinlock);
@@ -1835,15 +1813,15 @@
 			atomic_set(&ipa_ctx->sys[i].curr_polling_state, 0);
 	}
 
-	ipa_ctx->rx_wq = create_singlethread_workqueue("ipa rx wq");
+	ipa_ctx->rx_wq = alloc_workqueue("ipa rx wq", WQ_MEM_RECLAIM |
+			WQ_CPU_INTENSIVE, 1);
 	if (!ipa_ctx->rx_wq) {
 		IPAERR(":fail to create rx wq\n");
 		result = -ENOMEM;
 		goto fail_rx_wq;
 	}
 
-	ipa_ctx->tx_wq = alloc_workqueue("ipa tx wq", WQ_MEM_RECLAIM |
-			WQ_CPU_INTENSIVE, 2);
+	ipa_ctx->tx_wq = create_singlethread_workqueue("ipa tx wq");
 	if (!ipa_ctx->tx_wq) {
 		IPAERR(":fail to create tx wq\n");
 		result = -ENOMEM;
@@ -1996,10 +1974,6 @@
 fail_dma_pool:
 	kmem_cache_destroy(ipa_ctx->tree_node_cache);
 fail_tree_node_cache:
-	kmem_cache_destroy(ipa_ctx->rx_pkt_wrapper_cache);
-fail_rx_pkt_wrapper_cache:
-	kmem_cache_destroy(ipa_ctx->tx_pkt_wrapper_cache);
-fail_tx_pkt_wrapper_cache:
 	kmem_cache_destroy(ipa_ctx->rt_tbl_cache);
 fail_rt_tbl_cache:
 	kmem_cache_destroy(ipa_ctx->hdr_offset_cache);
diff --git a/drivers/platform/msm/ipa/ipa_bridge.c b/drivers/platform/msm/ipa/ipa_bridge.c
index 919a119..83c4db0 100644
--- a/drivers/platform/msm/ipa/ipa_bridge.c
+++ b/drivers/platform/msm/ipa/ipa_bridge.c
@@ -45,19 +45,23 @@
 #define IPA_UL_DESC_FIFO_SZ 0x530
 #define IPA_DL_DATA_FIFO_SZ 0x2400
 #define IPA_DL_DESC_FIFO_SZ 0x8a0
+#define IPA_DL_EMB_DATA_FIFO_SZ 0x1800
+#define IPA_DL_EMB_DESC_FIFO_SZ 0x4e8
 
-#define IPA_SMEM_UL_DATA_FIFO_OFST 0x3dd0
-#define IPA_SMEM_UL_DESC_FIFO_OFST 0x49d0
-#define IPA_SMEM_DL_DATA_FIFO_OFST 0x4f00
-#define IPA_SMEM_DL_DESC_FIFO_OFST 0x7300
+#define IPA_SMEM_UL_DATA_FIFO_OFST 0
+#define IPA_SMEM_UL_DESC_FIFO_OFST 0xc00
+#define IPA_SMEM_DL_DATA_FIFO_OFST 0x1130
+#define IPA_SMEM_DL_DESC_FIFO_OFST 0x3530
+#define IPA_SMEM_UL_EMB_DATA_FIFO_OFST 0x3dd0
+#define IPA_SMEM_UL_EMB_DESC_FIFO_OFST 0x49d0
 
-#define IPA_OCIMEM_UL_DATA_FIFO_OFST 0
-#define IPA_OCIMEM_UL_DESC_FIFO_OFST (IPA_OCIMEM_UL_DATA_FIFO_OFST + \
-		IPA_UL_DATA_FIFO_SZ)
-#define IPA_OCIMEM_DL_DATA_FIFO_OFST (IPA_OCIMEM_UL_DESC_FIFO_OFST + \
-		IPA_UL_DESC_FIFO_SZ)
-#define IPA_OCIMEM_DL_DESC_FIFO_OFST (IPA_OCIMEM_DL_DATA_FIFO_OFST + \
-		IPA_DL_DATA_FIFO_SZ)
+#define IPA_OCIMEM_DL_A2_DATA_FIFO_OFST 0
+#define IPA_OCIMEM_DL_A2_DESC_FIFO_OFST (IPA_OCIMEM_DL_A2_DATA_FIFO_OFST + \
+		IPA_DL_EMB_DATA_FIFO_SZ)
+#define IPA_OCIMEM_DL_IPA_DATA_FIFO_OFST (IPA_OCIMEM_DL_A2_DESC_FIFO_OFST + \
+		IPA_DL_EMB_DESC_FIFO_SZ)
+#define IPA_OCIMEM_DL_IPA_DESC_FIFO_OFST (IPA_OCIMEM_DL_IPA_DATA_FIFO_OFST + \
+		IPA_DL_EMB_DATA_FIFO_SZ)
 
 enum ipa_pipe_type {
 	IPA_DL_FROM_A2,
@@ -116,7 +120,7 @@
 		if (dir == IPA_BRIDGE_DIR_UL)
 			sz = IPA_UL_DESC_FIFO_SZ;
 		else
-			sz = IPA_DL_DESC_FIFO_SZ;
+			sz = IPA_DL_EMB_DESC_FIFO_SZ;
 	}
 
 	return sz;
@@ -136,7 +140,7 @@
 		if (dir == IPA_BRIDGE_DIR_UL)
 			sz = IPA_UL_DATA_FIFO_SZ;
 		else
-			sz = IPA_DL_DATA_FIFO_SZ;
+			sz = IPA_DL_EMB_DATA_FIFO_SZ;
 	}
 
 	return sz;
@@ -162,6 +166,38 @@
 	return ep;
 }
 
+int ipa_setup_ipa_dma_fifos(enum ipa_bridge_dir dir,
+		enum ipa_bridge_type type,
+		struct sps_mem_buffer *desc,
+		struct sps_mem_buffer *data)
+{
+	int ret;
+
+	ret = sps_setup_bam2bam_fifo(data,
+			IPA_OCIMEM_DL_IPA_DATA_FIFO_OFST,
+			ipa_get_data_fifo_sz(dir, type), 1);
+	if (ret) {
+		IPAERR("DAFIFO setup fail %d dir %d type %d\n",
+				ret, dir, type);
+		return ret;
+	}
+
+	ret = sps_setup_bam2bam_fifo(desc,
+			IPA_OCIMEM_DL_IPA_DESC_FIFO_OFST,
+			ipa_get_desc_fifo_sz(dir, type), 1);
+	if (ret) {
+		IPAERR("DEFIFO setup fail %d dir %d type %d\n",
+				ret, dir, type);
+		return ret;
+	}
+
+	IPADBG("dir=%d type=%d Dpa=%x Dsz=%u Dva=%p dpa=%x dsz=%u dva=%p\n",
+			dir, type, data->phys_base, data->size, data->base,
+			desc->phys_base, desc->size, desc->base);
+
+	return 0;
+}
+
 int ipa_setup_a2_dma_fifos(enum ipa_bridge_dir dir,
 		enum ipa_bridge_type type,
 		struct sps_mem_buffer *desc,
@@ -169,7 +205,7 @@
 {
 	int ret;
 
-	if (type == IPA_BRIDGE_TYPE_EMBEDDED) {
+	if (type == IPA_BRIDGE_TYPE_TETHERED) {
 		if (dir == IPA_BRIDGE_DIR_UL) {
 			desc->base = ipa_ctx->smem_pipe_mem +
 				IPA_SMEM_UL_DESC_FIFO_OFST;
@@ -191,26 +227,17 @@
 		}
 	} else {
 		if (dir == IPA_BRIDGE_DIR_UL) {
-			ret = sps_setup_bam2bam_fifo(data,
-					IPA_OCIMEM_UL_DATA_FIFO_OFST,
-					ipa_get_data_fifo_sz(dir, type), 1);
-			if (ret) {
-				IPAERR("DAFIFO setup fail %d dir %d type %d\n",
-						ret, dir, type);
-				return ret;
-			}
-
-			ret = sps_setup_bam2bam_fifo(desc,
-					IPA_OCIMEM_UL_DESC_FIFO_OFST,
-					ipa_get_desc_fifo_sz(dir, type), 1);
-			if (ret) {
-				IPAERR("DEFIFO setup fail %d dir %d type %d\n",
-						ret, dir, type);
-				return ret;
-			}
+			desc->base = ipa_ctx->smem_pipe_mem +
+				IPA_SMEM_UL_EMB_DESC_FIFO_OFST;
+			desc->phys_base = smem_virt_to_phys(desc->base);
+			desc->size = ipa_get_desc_fifo_sz(dir, type);
+			data->base = ipa_ctx->smem_pipe_mem +
+				IPA_SMEM_UL_EMB_DATA_FIFO_OFST;
+			data->phys_base = smem_virt_to_phys(data->base);
+			data->size = ipa_get_data_fifo_sz(dir, type);
 		} else {
 			ret = sps_setup_bam2bam_fifo(data,
-					IPA_OCIMEM_DL_DATA_FIFO_OFST,
+					IPA_OCIMEM_DL_A2_DATA_FIFO_OFST,
 					ipa_get_data_fifo_sz(dir, type), 1);
 			if (ret) {
 				IPAERR("DAFIFO setup fail %d dir %d type %d\n",
@@ -219,7 +246,7 @@
 			}
 
 			ret = sps_setup_bam2bam_fifo(desc,
-					IPA_OCIMEM_DL_DESC_FIFO_OFST,
+					IPA_OCIMEM_DL_A2_DESC_FIFO_OFST,
 					ipa_get_desc_fifo_sz(dir, type), 1);
 			if (ret) {
 				IPAERR("DEFIFO setup fail %d dir %d type %d\n",
@@ -289,6 +316,15 @@
 	ipa_in_params.desc_fifo_sz = ipa_get_desc_fifo_sz(dir, type);
 	ipa_in_params.data_fifo_sz = ipa_get_data_fifo_sz(dir, type);
 
+	if (type == IPA_BRIDGE_TYPE_EMBEDDED && dir == IPA_BRIDGE_DIR_DL) {
+		if (ipa_setup_ipa_dma_fifos(dir, type, &ipa_in_params.desc,
+					&ipa_in_params.data)) {
+			IPAERR("fail to setup IPA-DMA FIFOs dir=%d type=%d\n",
+					dir, type);
+			goto fail_get_a2_prop;
+		}
+	}
+
 	if (ipa_connect(&ipa_in_params, &sps_out_params, clnt_hdl)) {
 		IPAERR("ipa connect failed dir=%d type=%d\n", dir, type);
 		goto fail_get_a2_prop;
diff --git a/drivers/platform/msm/ipa/ipa_client.c b/drivers/platform/msm/ipa/ipa_client.c
index a95eafe..6c81504 100644
--- a/drivers/platform/msm/ipa/ipa_client.c
+++ b/drivers/platform/msm/ipa/ipa_client.c
@@ -13,6 +13,15 @@
 #include <linux/delay.h>
 #include "ipa_i.h"
 
+/*
+ * These values were determined empirically and shows good E2E bi-
+ * directional throughputs
+ */
+#define IPA_A2_HOLB_TMR_EN 0x1
+#define IPA_A2_HOLB_TMR_DEFAULT_VAL 0xff
+#define IPA_WLAN_HOLB_TMR_EN 0x1
+#define IPA_WLAN_HOLB_TMR_DEFAULT_VAL 0x7f
+
 static void ipa_enable_data_path(u32 clnt_hdl)
 {
 	if (ipa_ctx->ipa_hw_mode == IPA_HW_MODE_VIRTUAL) {
@@ -175,6 +184,26 @@
 	return 0;
 }
 
+static void ipa_program_holb(struct ipa_ep_context *ep, int ipa_ep_idx)
+{
+	struct ipa_ep_cfg_holb holb;
+
+	if (IPA_CLIENT_IS_PROD(ep->client))
+		return;
+
+	switch (ep->client) {
+	case IPA_CLIENT_A2_TETHERED_CONS:
+	case IPA_CLIENT_A2_EMBEDDED_CONS:
+		holb.en = IPA_A2_HOLB_TMR_EN;
+		holb.tmr_val = IPA_A2_HOLB_TMR_DEFAULT_VAL;
+		break;
+	default:
+		return;
+	}
+
+	ipa_cfg_ep_holb(ipa_ep_idx, &holb);
+}
+
 /**
  * ipa_connect() - low-level IPA client connect
  * @in:	[in] input parameters from client
@@ -222,6 +251,26 @@
 
 	memset(&ipa_ctx->ep[ipa_ep_idx], 0, sizeof(struct ipa_ep_context));
 
+	if (IPA_CLIENT_IS_CONS(in->client)) {
+		ep->cmd = kzalloc(sizeof(struct ipa_ip_packet_init),
+				GFP_KERNEL);
+		if (!ep->cmd) {
+			IPAERR("failed to alloc immediate command object\n");
+			result = -ENOMEM;
+			goto fail;
+		}
+		ep->cmd->destination_pipe_index = ipa_ep_idx;
+		ep->dma_addr = dma_map_single(NULL, ep->cmd,
+				sizeof(struct ipa_ip_packet_init),
+				DMA_TO_DEVICE);
+		if (ep->dma_addr == 0 || ep->dma_addr == ~0) {
+			IPAERR("failed to DMA MAP pkt_init\n");
+			result = -ENOMEM;
+			kfree(ep->cmd);
+			goto fail;
+		}
+	}
+
 	ep->valid = 1;
 	ep->client = in->client;
 	ep->client_notify = in->notify;
@@ -290,21 +339,7 @@
 	memcpy(&sps->desc, &ep->connect.desc, sizeof(struct sps_mem_buffer));
 	memcpy(&sps->data, &ep->connect.data, sizeof(struct sps_mem_buffer));
 
-	if (in->client == IPA_CLIENT_HSIC1_CONS ||
-			in->client == IPA_CLIENT_HSIC2_CONS ||
-			in->client == IPA_CLIENT_HSIC3_CONS ||
-			in->client == IPA_CLIENT_HSIC4_CONS ||
-			in->client == IPA_CLIENT_A2_TETHERED_CONS ||
-			in->client == IPA_CLIENT_A2_EMBEDDED_CONS) {
-		IPADBG("disable holb for ep=%d tmr=%d\n", ipa_ep_idx,
-			ipa_ctx->hol_timer);
-		ipa_write_reg(ipa_ctx->mmio,
-			IPA_ENDP_INIT_HOL_BLOCK_EN_n_OFST(ipa_ep_idx),
-			ipa_ctx->hol_en);
-		ipa_write_reg(ipa_ctx->mmio,
-			IPA_ENDP_INIT_HOL_BLOCK_TIMER_n_OFST(ipa_ep_idx),
-			ipa_ctx->hol_timer);
-	}
+	ipa_program_holb(ep, ipa_ep_idx);
 
 	IPADBG("client %d (ep: %d) connected\n", in->client, ipa_ep_idx);
 
@@ -412,6 +447,13 @@
 		return -EPERM;
 	}
 
+	if (IPA_CLIENT_IS_CONS(ep->client)) {
+		dma_unmap_single(NULL, ep->dma_addr,
+				sizeof(struct ipa_ip_packet_init),
+				DMA_TO_DEVICE);
+		kfree(ep->cmd);
+	}
+
 	ipa_enable_data_path(clnt_hdl);
 	memset(&ipa_ctx->ep[clnt_hdl], 0, sizeof(struct ipa_ep_context));
 
diff --git a/drivers/platform/msm/ipa/ipa_debugfs.c b/drivers/platform/msm/ipa/ipa_debugfs.c
index b11c7da..cec92e8 100644
--- a/drivers/platform/msm/ipa/ipa_debugfs.c
+++ b/drivers/platform/msm/ipa/ipa_debugfs.c
@@ -94,8 +94,7 @@
 static struct dentry *dent;
 static struct dentry *dfile_gen_reg;
 static struct dentry *dfile_ep_reg;
-static struct dentry *dfile_ep_hol_en;
-static struct dentry *dfile_ep_hol_timer;
+static struct dentry *dfile_ep_holb;
 static struct dentry *dfile_hdr;
 static struct dentry *dfile_ip4_rt;
 static struct dentry *dfile_ip6_rt;
@@ -147,11 +146,15 @@
 	return simple_read_from_buffer(ubuf, count, ppos, dbg_buff, nbytes);
 }
 
-static ssize_t ipa_write_ep_hol_en_reg(struct file *file,
+static ssize_t ipa_write_ep_holb(struct file *file,
 		const char __user *buf, size_t count, loff_t *ppos)
 {
-	u32 endp_reg_val;
+	struct ipa_ep_cfg_holb holb;
+	u32 en;
+	u32 tmr_val;
+	u32 ep_idx;
 	unsigned long missing;
+	char *sptr, *token;
 
 	if (sizeof(dbg_buff) < count + 1)
 		return -EFAULT;
@@ -161,40 +164,31 @@
 		return -EFAULT;
 
 	dbg_buff[count] = '\0';
-	if (kstrtou32(dbg_buff, 16, &endp_reg_val))
-		return -EFAULT;
 
-	ipa_write_reg(ipa_ctx->mmio,
-		IPA_ENDP_INIT_HOL_BLOCK_EN_n_OFST(ep_reg_idx),
-		endp_reg_val);
+	sptr = dbg_buff;
 
-	ipa_ctx->hol_en = endp_reg_val;
+	token = strsep(&sptr, " ");
+	if (!token)
+		return -EINVAL;
+	if (kstrtou32(token, 0, &ep_idx))
+		return -EINVAL;
 
-	return count;
-}
+	token = strsep(&sptr, " ");
+	if (!token)
+		return -EINVAL;
+	if (kstrtou32(token, 0, &en))
+		return -EINVAL;
 
-static ssize_t ipa_write_ep_hol_timer_reg(struct file *file,
-		const char __user *buf, size_t count, loff_t *ppos)
-{
-	u32 endp_reg_val;
-	unsigned long missing;
+	token = strsep(&sptr, " ");
+	if (!token)
+		return -EINVAL;
+	if (kstrtou32(token, 0, &tmr_val))
+		return -EINVAL;
 
-	if (sizeof(dbg_buff) < count + 1)
-		return -EFAULT;
+	holb.en = en;
+	holb.tmr_val = tmr_val;
 
-	missing = copy_from_user(dbg_buff, buf, count);
-	if (missing)
-		return -EFAULT;
-
-	dbg_buff[count] = '\0';
-	if (kstrtou32(dbg_buff, 16, &endp_reg_val))
-		return -EFAULT;
-
-	ipa_write_reg(ipa_ctx->mmio,
-		IPA_ENDP_INIT_HOL_BLOCK_TIMER_n_OFST(ep_reg_idx),
-		endp_reg_val);
-
-	ipa_ctx->hol_timer = endp_reg_val;
+	ipa_cfg_ep_holb(ep_idx, &holb);
 
 	return count;
 }
@@ -964,11 +958,8 @@
 	.write = ipa_write_ep_reg,
 };
 
-const struct file_operations ipa_ep_hol_en_ops = {
-	.write = ipa_write_ep_hol_en_reg,
-};
-const struct file_operations ipa_ep_hol_timer_ops = {
-	.write = ipa_write_ep_hol_timer_reg,
+const struct file_operations ipa_ep_holb_ops = {
+	.write = ipa_write_ep_holb,
 };
 
 const struct file_operations ipa_hdr_ops = {
@@ -1029,20 +1020,13 @@
 		goto fail;
 	}
 
-	dfile_ep_hol_en = debugfs_create_file("hol_en", write_only_mode, dent,
-			0, &ipa_ep_hol_en_ops);
-	if (!dfile_ep_hol_en || IS_ERR(dfile_ep_hol_en)) {
+	dfile_ep_holb = debugfs_create_file("holb", write_only_mode, dent,
+			0, &ipa_ep_holb_ops);
+	if (!dfile_ep_holb || IS_ERR(dfile_ep_holb)) {
 		IPAERR("fail to create file for debug_fs dfile_ep_hol_en\n");
 		goto fail;
 	}
 
-	dfile_ep_hol_timer = debugfs_create_file("hol_timer", write_only_mode,
-			dent, 0, &ipa_ep_hol_timer_ops);
-	if (!dfile_ep_hol_timer || IS_ERR(dfile_ep_hol_timer)) {
-		IPAERR("fail to create file for debug_fs dfile_ep_hol_timer\n");
-		goto fail;
-	}
-
 	dfile_hdr = debugfs_create_file("hdr", read_only_mode, dent, 0,
 			&ipa_hdr_ops);
 	if (!dfile_hdr || IS_ERR(dfile_hdr)) {
diff --git a/drivers/platform/msm/ipa/ipa_dp.c b/drivers/platform/msm/ipa/ipa_dp.c
index 1b6181f..c564922 100644
--- a/drivers/platform/msm/ipa/ipa_dp.c
+++ b/drivers/platform/msm/ipa/ipa_dp.c
@@ -19,18 +19,20 @@
 
 #define list_next_entry(pos, member) \
 	list_entry(pos->member.next, typeof(*pos), member)
-#define IPA_LAST_DESC_CNT 0xFFFF
 #define POLLING_INACTIVITY_RX 40
-#define POLLING_MIN_SLEEP_RX 950
-#define POLLING_MAX_SLEEP_RX 1050
-#define POLLING_INACTIVITY_TX 40
-#define POLLING_MIN_SLEEP_TX 400
-#define POLLING_MAX_SLEEP_TX 500
+#define POLLING_MIN_SLEEP_RX 2350
+#define POLLING_MAX_SLEEP_RX 2450
+#define POLLING_INACTIVITY_TX 10
+#define POLLING_MIN_SLEEP_TX 100
+#define POLLING_MAX_SLEEP_TX 200
+#define RX_MAX_IND 40
 
 static void replenish_rx_work_func(struct work_struct *work);
 static struct delayed_work replenish_rx_work;
 static void ipa_wq_handle_rx(struct work_struct *work);
 static DECLARE_WORK(rx_work, ipa_wq_handle_rx);
+static void ipa_wq_handle_tx(struct work_struct *work);
+static DECLARE_WORK(tx_work, ipa_wq_handle_tx);
 
 /**
  * ipa_write_done() - this function will be (eventually) called when a Tx
@@ -81,7 +83,7 @@
 	if (tx_pkt->callback)
 		tx_pkt->callback(tx_pkt->user1, tx_pkt->user2);
 
-	kmem_cache_free(ipa_ctx->tx_pkt_wrapper_cache, tx_pkt);
+	kfree(tx_pkt);
 }
 
 int ipa_handle_tx_core(struct ipa_sys_context *sys, bool process_all,
@@ -119,23 +121,13 @@
 
 		IPADBG("--curr_cnt=%d\n", sys->len);
 
-		if (unlikely(ipa_ctx->ipa_hw_type == IPA_HW_v1_0))
-			dma_pool_free(ipa_ctx->dma_pool,
-					tx_pkt->bounce,
-					tx_pkt->mem.phys_base);
-		else
+		if (tx_pkt->callback) {
 			dma_unmap_single(NULL, tx_pkt->mem.phys_base,
-					tx_pkt->mem.size,
-					DMA_TO_DEVICE);
-
-		if (tx_pkt->callback)
+					tx_pkt->mem.size, DMA_TO_DEVICE);
 			tx_pkt->callback(tx_pkt->user1, tx_pkt->user2);
+		}
 
-		if (tx_pkt->cnt > 1 && tx_pkt->cnt != IPA_LAST_DESC_CNT)
-			dma_pool_free(ipa_ctx->dma_pool, tx_pkt->mult.base,
-					tx_pkt->mult.phys_base);
-
-		kmem_cache_free(ipa_ctx->tx_pkt_wrapper_cache, tx_pkt);
+		kfree(tx_pkt);
 		cnt++;
 	};
 
@@ -154,11 +146,6 @@
 		goto fail;
 	}
 
-	ret = sps_get_config(sys->ep->ep_hdl, &sys->ep->connect);
-	if (ret) {
-		IPAERR("sps_get_config() failed %d\n", ret);
-		goto fail;
-	}
 	sys->event.options = SPS_O_EOT;
 	ret = sps_register_event(sys->ep->ep_hdl, &sys->event);
 	if (ret) {
@@ -205,9 +192,7 @@
 
 static void ipa_wq_handle_tx(struct work_struct *work)
 {
-	struct ipa_tx_pkt_wrapper *tx_pkt;
-	tx_pkt = container_of(work, struct ipa_tx_pkt_wrapper, work);
-	ipa_handle_tx(tx_pkt->sys);
+	ipa_handle_tx(&ipa_ctx->sys[IPA_A5_LAN_WAN_OUT]);
 }
 
 /**
@@ -240,7 +225,7 @@
 	if (unlikely(!in_atomic))
 		mem_flag = GFP_KERNEL;
 
-	tx_pkt = kmem_cache_zalloc(ipa_ctx->tx_pkt_wrapper_cache, mem_flag);
+	tx_pkt = kmalloc(sizeof(struct ipa_tx_pkt_wrapper), mem_flag);
 	if (!tx_pkt) {
 		IPAERR("failed to alloc tx wrapper\n");
 		goto fail_mem_alloc;
@@ -296,14 +281,11 @@
 		IPADBG("sending cmd=%d pyld_len=%d sps_flags=%x\n",
 				desc->opcode, desc->len, sps_flags);
 		IPA_DUMP_BUFF(desc->pyld, dma_address, desc->len);
-		INIT_WORK(&tx_pkt->work, ipa_wq_write_done);
 	} else {
 		len = desc->len;
-		INIT_WORK(&tx_pkt->work, ipa_wq_handle_tx);
 	}
 
-	if (unlikely(ipa_ctx->polling_mode))
-		INIT_WORK(&tx_pkt->work, ipa_wq_handle_tx);
+	INIT_WORK(&tx_pkt->work, ipa_wq_write_done);
 
 	spin_lock_irqsave(&sys->spinlock, irq_flags);
 	list_add_tail(&tx_pkt->link, &sys->head_desc_list);
@@ -327,192 +309,12 @@
 	else
 		dma_unmap_single(NULL, dma_address, desc->len, DMA_TO_DEVICE);
 fail_dma_map:
-	kmem_cache_free(ipa_ctx->tx_pkt_wrapper_cache, tx_pkt);
+	kfree(tx_pkt);
 fail_mem_alloc:
 	return -EFAULT;
 }
 
 /**
- * ipa_send() - Send multiple descriptors in one HW transaction
- * @sys: system pipe context
- * @num_desc: number of packets
- * @desc: packets to send (may be immediate command or data)
- * @in_atomic:  whether caller is in atomic context
- *
- * This function is used for system-to-bam connection.
- * - SPS driver expect struct sps_transfer which will contain all the data
- *   for a transaction
- * - The sps_transfer struct will be pointing to bounce buffers for
- *   its DMA command (immediate command and data)
- * - ipa_tx_pkt_wrapper will be used for each ipa
- *   descriptor (allocated from wrappers cache)
- * - The wrapper struct will be configured for each ipa-desc payload and will
- *   contain information which will be later used by the user callbacks
- * - each transfer will be made by calling to sps_transfer()
- * - Each packet (command or data) that will be sent will also be saved in
- *   ipa_sys_context for later check that all data was sent
- *
- * Return codes: 0: success, -EFAULT: failure
- */
-int ipa_send(struct ipa_sys_context *sys, u32 num_desc, struct ipa_desc *desc,
-		bool in_atomic)
-{
-	struct ipa_tx_pkt_wrapper *tx_pkt;
-	struct ipa_tx_pkt_wrapper *next_pkt;
-	struct sps_transfer transfer = { 0 };
-	struct sps_iovec *iovec;
-	unsigned long irq_flags;
-	dma_addr_t dma_addr;
-	int i = 0;
-	int j;
-	int result;
-	int fail_dma_wrap = 0;
-	uint size = num_desc * sizeof(struct sps_iovec);
-	u32 mem_flag = GFP_ATOMIC;
-
-	if (unlikely(!in_atomic))
-		mem_flag = GFP_KERNEL;
-
-	transfer.iovec = dma_pool_alloc(ipa_ctx->dma_pool, mem_flag, &dma_addr);
-	transfer.iovec_phys = dma_addr;
-	transfer.iovec_count = num_desc;
-	spin_lock_irqsave(&sys->spinlock, irq_flags);
-	if (!transfer.iovec) {
-		IPAERR("fail to alloc DMA mem for sps xfr buff\n");
-		goto failure_coherent;
-	}
-
-	for (i = 0; i < num_desc; i++) {
-		fail_dma_wrap = 0;
-		tx_pkt = kmem_cache_zalloc(ipa_ctx->tx_pkt_wrapper_cache,
-					   mem_flag);
-		if (!tx_pkt) {
-			IPAERR("failed to alloc tx wrapper\n");
-			goto failure;
-		}
-		/*
-		 * first desc of set is "special" as it holds the count and
-		 * other info
-		 */
-		if (i == 0) {
-			transfer.user = tx_pkt;
-			tx_pkt->mult.phys_base = dma_addr;
-			tx_pkt->mult.base = transfer.iovec;
-			tx_pkt->mult.size = size;
-			tx_pkt->cnt = num_desc;
-			INIT_WORK(&tx_pkt->work, ipa_wq_handle_tx);
-		}
-
-		iovec = &transfer.iovec[i];
-		iovec->flags = 0;
-
-		INIT_LIST_HEAD(&tx_pkt->link);
-		tx_pkt->type = desc[i].type;
-
-		tx_pkt->mem.base = desc[i].pyld;
-		tx_pkt->mem.size = desc[i].len;
-
-		if (unlikely(ipa_ctx->ipa_hw_type == IPA_HW_v1_0)) {
-			WARN_ON(tx_pkt->mem.size > 512);
-
-			/*
-			 * Due to a HW limitation, we need to make sure that the
-			 * packet does not cross a 1KB boundary
-			 */
-			tx_pkt->bounce =
-			   dma_pool_alloc(ipa_ctx->dma_pool,
-					   mem_flag,
-					   &tx_pkt->mem.phys_base);
-			if (!tx_pkt->bounce) {
-				tx_pkt->mem.phys_base = 0;
-			} else {
-				WARN_ON(!ipa_straddle_boundary(
-						(u32)tx_pkt->mem.phys_base,
-						(u32)tx_pkt->mem.phys_base +
-						tx_pkt->mem.size - 1, 1024));
-				memcpy(tx_pkt->bounce, tx_pkt->mem.base,
-						tx_pkt->mem.size);
-			}
-		} else {
-			tx_pkt->mem.phys_base =
-			   dma_map_single(NULL, tx_pkt->mem.base,
-					   tx_pkt->mem.size,
-					   DMA_TO_DEVICE);
-		}
-		if (!tx_pkt->mem.phys_base) {
-			IPAERR("failed to alloc tx wrapper\n");
-			fail_dma_wrap = 1;
-			goto failure;
-		}
-
-		tx_pkt->sys = sys;
-		tx_pkt->callback = desc[i].callback;
-		tx_pkt->user1 = desc[i].user1;
-		tx_pkt->user2 = desc[i].user2;
-
-		/*
-		 * Point the iovec to the bounce buffer and
-		 * add this packet to system pipe context.
-		 */
-		iovec->addr = tx_pkt->mem.phys_base;
-		list_add_tail(&tx_pkt->link, &sys->head_desc_list);
-
-		/*
-		 * Special treatment for immediate commands, where the structure
-		 * of the descriptor is different
-		 */
-		if (desc[i].type == IPA_IMM_CMD_DESC) {
-			iovec->size = desc[i].opcode;
-			iovec->flags |= SPS_IOVEC_FLAG_IMME;
-		} else {
-			iovec->size = desc[i].len;
-		}
-
-		if (i == (num_desc - 1)) {
-			iovec->flags |= SPS_IOVEC_FLAG_EOT;
-			/* "mark" the last desc */
-			tx_pkt->cnt = IPA_LAST_DESC_CNT;
-		}
-	}
-
-	result = sps_transfer(sys->ep->ep_hdl, &transfer);
-	if (result) {
-		IPAERR("sps_transfer failed rc=%d\n", result);
-		goto failure;
-	}
-
-	spin_unlock_irqrestore(&sys->spinlock, irq_flags);
-	return 0;
-
-failure:
-	tx_pkt = transfer.user;
-	for (j = 0; j < i; j++) {
-		next_pkt = list_next_entry(tx_pkt, link);
-		list_del(&tx_pkt->link);
-		if (unlikely(ipa_ctx->ipa_hw_type == IPA_HW_v1_0))
-			dma_pool_free(ipa_ctx->dma_pool,
-					tx_pkt->bounce,
-					tx_pkt->mem.phys_base);
-		else
-			dma_unmap_single(NULL, tx_pkt->mem.phys_base,
-					tx_pkt->mem.size,
-					DMA_TO_DEVICE);
-		kmem_cache_free(ipa_ctx->tx_pkt_wrapper_cache, tx_pkt);
-		tx_pkt = next_pkt;
-	}
-	if (i < num_desc)
-		/* last desc failed */
-		if (fail_dma_wrap)
-			kmem_cache_free(ipa_ctx->tx_pkt_wrapper_cache, tx_pkt);
-	if (transfer.iovec_phys)
-		dma_pool_free(ipa_ctx->dma_pool, transfer.iovec,
-				  transfer.iovec_phys);
-failure_coherent:
-	spin_unlock_irqrestore(&sys->spinlock, irq_flags);
-	return -EFAULT;
-}
-
-/**
  * ipa_sps_irq_cmd_ack - callback function which will be called by SPS driver after an
  * immediate command is complete.
  * @user1:	pointer to the descriptor of the transfer
@@ -543,7 +345,6 @@
  */
 int ipa_send_cmd(u16 num_desc, struct ipa_desc *descr)
 {
-	struct ipa_desc *desc;
 	int result = 0;
 
 	ipa_inc_client_enable_clks();
@@ -563,22 +364,10 @@
 		}
 		wait_for_completion(&descr->xfer_done);
 	} else {
-		desc = &descr[num_desc - 1];
-		init_completion(&desc->xfer_done);
-
-		if (desc->callback || desc->user1)
-			WARN_ON(1);
-
-		desc->callback = ipa_sps_irq_cmd_ack;
-		desc->user1 = desc;
-		if (ipa_send(&ipa_ctx->sys[IPA_A5_CMD], num_desc,
-					descr, false)) {
-			IPAERR("fail to send multiple immediate command set\n");
+		IPAERR("unsupported chaining multiple IC\n");
 			result = -EFAULT;
 			goto bail;
 		}
-		wait_for_completion(&desc->xfer_done);
-	}
 
 	IPA_STATS_INC_IC_CNT(num_desc, descr, ipa_ctx->stats.imm_cmds);
 bail:
@@ -597,21 +386,13 @@
 static void ipa_sps_irq_tx_notify(struct sps_event_notify *notify)
 {
 	struct ipa_sys_context *sys = &ipa_ctx->sys[IPA_A5_LAN_WAN_OUT];
-	struct ipa_tx_pkt_wrapper *tx_pkt;
 	int ret;
 
 	IPADBG("event %d notified\n", notify->event_id);
 
 	switch (notify->event_id) {
 	case SPS_EVENT_EOT:
-		tx_pkt = notify->data.transfer.user;
 		if (!atomic_read(&sys->curr_polling_state)) {
-			ret = sps_get_config(sys->ep->ep_hdl,
-					&sys->ep->connect);
-			if (ret) {
-				IPAERR("sps_get_config() failed %d\n", ret);
-				break;
-			}
 			sys->ep->connect.options = SPS_O_AUTO_ENABLE |
 				SPS_O_ACK_TRANSFERS | SPS_O_POLL;
 			ret = sps_set_config(sys->ep->ep_hdl,
@@ -621,7 +402,7 @@
 				break;
 			}
 			atomic_set(&sys->curr_polling_state, 1);
-			queue_work(ipa_ctx->tx_wq, &tx_pkt->work);
+			queue_work(ipa_ctx->tx_wq, &tx_work);
 		}
 		break;
 	default:
@@ -654,6 +435,47 @@
 	}
 }
 
+static void ipa_handle_tag_rsp(struct ipa_a5_mux_hdr *mux_hdr)
+{
+	struct completion *compl;
+	struct ipa_tree_node *node;
+
+	/* retrieve the compl object from tag value */
+	mux_hdr++;
+	compl = (struct completion *) ntohl(*((u32 *)mux_hdr));
+	IPADBG("%x %x %p\n", *(u32 *)mux_hdr, *((u32 *)mux_hdr + 1), compl);
+
+	mutex_lock(&ipa_ctx->lock);
+	node = ipa_search(&ipa_ctx->tag_tree, (u32)compl);
+	if (node) {
+		complete_all(compl);
+		rb_erase(&node->node, &ipa_ctx->tag_tree);
+		kmem_cache_free(ipa_ctx->tree_node_cache, node);
+	} else {
+		WARN_ON(1);
+	}
+	mutex_unlock(&ipa_ctx->lock);
+}
+
+static void ipa_dejitter(bool limit)
+{
+	struct sk_buff *skb;
+	int len = skb_queue_len(&ipa_ctx->rx_list);
+	int i;
+	void *cookie;
+	ipa_notify_cb cb;
+
+	if (limit && len >= RX_MAX_IND)
+		len = RX_MAX_IND;
+
+	for (i = len; i > 0; i--) {
+		skb = __skb_dequeue(&ipa_ctx->rx_list);
+		cb = (ipa_notify_cb)*(u32 *)&(skb->cb[0]);
+		cookie = (void *)*(u32 *)&(skb->cb[4]);
+		cb(cookie, IPA_RECEIVE, (unsigned long)skb);
+	}
+}
+
 /**
  * ipa_handle_rx_core() - The core functionality of packet reception. This
  * function is read from multiple code paths.
@@ -675,13 +497,9 @@
 	struct ipa_rx_pkt_wrapper *rx_pkt;
 	struct sk_buff *rx_skb;
 	struct sps_iovec iov;
-	unsigned int pull_len;
-	unsigned int padding;
 	int ret;
 	struct ipa_ep_context *ep;
 	int cnt = 0;
-	struct completion *compl;
-	struct ipa_tree_node *node;
 	unsigned int src_pipe;
 
 	while ((in_poll_state ? atomic_read(&sys->curr_polling_state) :
@@ -721,7 +539,7 @@
 		rx_skb->tail = rx_skb->data + rx_pkt->len;
 		rx_skb->len = rx_pkt->len;
 		rx_skb->truesize = rx_pkt->len + sizeof(struct sk_buff);
-		kmem_cache_free(ipa_ctx->rx_pkt_wrapper_cache, rx_pkt);
+		kfree(rx_pkt);
 
 		mux_hdr = (struct ipa_a5_mux_hdr *)rx_skb->data;
 
@@ -736,29 +554,9 @@
 		IPA_STATS_INC_CNT(ipa_ctx->stats.rx_pkts);
 		IPA_STATS_EXCP_CNT(mux_hdr->flags, ipa_ctx->stats.rx_excp_pkts);
 
-		if (unlikely(mux_hdr->flags & IPA_A5_MUX_HDR_EXCP_FLAG_TAG)) {
-			if (ipa_ctx->ipa_hw_mode != IPA_HW_MODE_VIRTUAL) {
-				/* retrieve the compl object from tag value */
-				mux_hdr++;
-				compl = (struct completion *)
-					ntohl(*((u32 *)mux_hdr));
-				IPADBG("%x %x %p\n", *(u32 *)mux_hdr,
-						*((u32 *)mux_hdr + 1), compl);
-
-				mutex_lock(&ipa_ctx->lock);
-				node = ipa_search(&ipa_ctx->tag_tree,
-						(u32)compl);
-				if (node) {
-					complete_all(compl);
-					rb_erase(&node->node,
-							&ipa_ctx->tag_tree);
-					kmem_cache_free(
-						ipa_ctx->tree_node_cache, node);
-				} else {
-					WARN_ON(1);
-				}
-				mutex_unlock(&ipa_ctx->lock);
-			}
+		if (mux_hdr->flags & IPA_A5_MUX_HDR_EXCP_FLAG_TAG) {
+			if (ipa_ctx->ipa_hw_mode != IPA_HW_MODE_VIRTUAL)
+				ipa_handle_tag_rsp(mux_hdr);
 			dev_kfree_skb(rx_skb);
 			ipa_replenish_rx_cache();
 			++cnt;
@@ -769,38 +567,22 @@
 		 * Any packets arriving over AMPDU_TX should be dispatched
 		 * to the regular WLAN RX data-path.
 		 */
-		if (unlikely(src_pipe == WLAN_AMPDU_TX_EP))
+		if (src_pipe == WLAN_AMPDU_TX_EP)
 			src_pipe = WLAN_PROD_TX_EP;
 
-		if (unlikely(src_pipe >= IPA_NUM_PIPES ||
-			!ipa_ctx->ep[src_pipe].valid ||
-			!ipa_ctx->ep[src_pipe].client_notify)) {
-			IPAERR("drop pipe=%d ep_valid=%d client_notify=%p\n",
-			  src_pipe, ipa_ctx->ep[src_pipe].valid,
-			  ipa_ctx->ep[src_pipe].client_notify);
-			dev_kfree_skb(rx_skb);
-			ipa_replenish_rx_cache();
-			++cnt;
-			continue;
-		}
+		WARN_ON(src_pipe >= IPA_NUM_PIPES);
 
 		ep = &ipa_ctx->ep[src_pipe];
-		pull_len = sizeof(struct ipa_a5_mux_hdr);
-
-		/*
-		 * IP packet starts on word boundary
-		 * remove the MUX header and any padding and pass the frame to
-		 * the client which registered a rx callback on the "src pipe"
-		 */
-		padding = ep->cfg.hdr.hdr_len & 0x3;
-		if (padding)
-			pull_len += 4 - padding;
-
-		IPADBG("pulling %d bytes from skb\n", pull_len);
-		skb_pull(rx_skb, pull_len);
+		IPADBG("pulling %d bytes from skb\n", ep->pull_len);
+		skb_pull(rx_skb, ep->pull_len);
 		ipa_replenish_rx_cache();
-		ep->client_notify(ep->priv, IPA_RECEIVE,
-				(unsigned long)(rx_skb));
+		if (ep->client_notify) {
+			__skb_queue_tail(&ipa_ctx->rx_list, rx_skb);
+			*(u32 *)&(rx_skb->cb[0]) = (u32)ep->client_notify;
+			*(u32 *)&(rx_skb->cb[4]) = (u32)ep->priv;
+		} else {
+			dev_kfree_skb(rx_skb);
+		}
 		cnt++;
 	};
 
@@ -819,11 +601,6 @@
 		goto fail;
 	}
 
-	ret = sps_get_config(sys->ep->ep_hdl, &sys->ep->connect);
-	if (ret) {
-		IPAERR("sps_get_config() failed %d\n", ret);
-		goto fail;
-	}
 	sys->event.options = SPS_O_EOT;
 	ret = sps_register_event(sys->ep->ep_hdl, &sys->event);
 	if (ret) {
@@ -870,12 +647,6 @@
 	switch (notify->event_id) {
 	case SPS_EVENT_EOT:
 		if (!atomic_read(&sys->curr_polling_state)) {
-			ret = sps_get_config(sys->ep->ep_hdl,
-					&sys->ep->connect);
-			if (ret) {
-				IPAERR("sps_get_config() failed %d\n", ret);
-				break;
-			}
 			sys->ep->connect.options = SPS_O_AUTO_ENABLE |
 				SPS_O_ACK_TRANSFERS | SPS_O_POLL;
 			ret = sps_set_config(sys->ep->ep_hdl,
@@ -925,8 +696,10 @@
 		} else {
 			inactive_cycles = 0;
 		}
+		ipa_dejitter(true);
 	} while (inactive_cycles <= POLLING_INACTIVITY_RX);
 
+	ipa_dejitter(false);
 	ipa_rx_switch_to_intr_mode(sys);
 	ipa_dec_client_disable_clks();
 }
@@ -1062,6 +835,7 @@
 		break;
 	case 2:
 		sys_idx = ipa_ep_idx;
+		ipa_ctx->sys[sys_idx].max_len = sys_in->desc_fifo_sz / 8 - 2;
 		INIT_DELAYED_WORK(&ipa_ctx->sys[sys_idx].switch_to_intr_work,
 				switch_to_intr_tx_work_func);
 		break;
@@ -1176,9 +950,87 @@
 		dev_kfree_skb(skb);
 }
 
-static void ipa_tx_cmd_comp(void *user1, void *user2)
+static int ipa_send_two(struct sk_buff *skb, struct ipa_sys_context *sys,
+		int dst_ep_idx)
 {
-	kfree(user1);
+	struct ipa_tx_pkt_wrapper *tx_pktc;
+	struct ipa_tx_pkt_wrapper *tx_pktd;
+	struct ipa_ep_context *ep = &ipa_ctx->ep[dst_ep_idx];
+	unsigned long irq_flags;
+	dma_addr_t dma_addrd;
+	int rc = -ENOMEM;
+
+	tx_pktc = kmalloc(sizeof(struct ipa_tx_pkt_wrapper), GFP_ATOMIC);
+	if (!tx_pktc) {
+		IPAERR("failed to alloc tx wrapper C\n");
+		goto fail_mem_alloc_c;
+	}
+
+	tx_pktd = kmalloc(sizeof(struct ipa_tx_pkt_wrapper), GFP_ATOMIC);
+	if (!tx_pktd) {
+		IPAERR("failed to alloc tx wrapper D\n");
+		goto fail_mem_alloc_d;
+	}
+
+	dma_addrd = dma_map_single(NULL, skb->data, skb->len, DMA_TO_DEVICE);
+	if (!dma_addrd) {
+		IPAERR("failed to DMA wrap\n");
+		goto fail_dma_map_d;
+	}
+
+	INIT_LIST_HEAD(&tx_pktc->link);
+	tx_pktc->callback = NULL;
+
+	INIT_LIST_HEAD(&tx_pktd->link);
+	tx_pktd->mem.phys_base = dma_addrd;
+	tx_pktd->mem.base = skb->data;
+	tx_pktd->mem.size = skb->len;
+	tx_pktd->callback = ipa_tx_comp_usr_notify_release;
+	tx_pktd->user1 = skb;
+	tx_pktd->user2 = (void *)dst_ep_idx;
+
+	spin_lock_irqsave(&sys->spinlock, irq_flags);
+	if (sys->len >= sys->max_len)
+		goto fail_oom;
+	list_add_tail(&tx_pktc->link, &sys->head_desc_list);
+	if (sps_transfer_one(sys->ep->ep_hdl, ep->dma_addr, IPA_IP_PACKET_INIT,
+			tx_pktc, SPS_IOVEC_FLAG_IMME |
+			SPS_IOVEC_FLAG_NO_SUBMIT))
+		IPAERR("sps_transfer_one 0 failed\n");
+	list_add_tail(&tx_pktd->link, &sys->head_desc_list);
+	if (sps_transfer_one(sys->ep->ep_hdl, dma_addrd, skb->len, tx_pktd,
+			SPS_IOVEC_FLAG_EOT | SPS_IOVEC_FLAG_INT))
+		IPAERR("sps_transfer_one 1 failed\n");
+	sys->len += 2;
+	spin_unlock_irqrestore(&sys->spinlock, irq_flags);
+	return 0;
+
+fail_oom:
+	dma_unmap_single(NULL, dma_addrd, skb->len, DMA_TO_DEVICE);
+fail_dma_map_d:
+	kfree(tx_pktd);
+fail_mem_alloc_d:
+	kfree(tx_pktc);
+fail_mem_alloc_c:
+	return rc;
+}
+
+static int ipa_send_data_hw_path(struct sk_buff *skb,
+		struct ipa_sys_context *sys, int dst_ep_idx)
+{
+	struct ipa_desc desc;
+
+	desc.pyld = skb->data;
+	desc.len = skb->len;
+	desc.type = IPA_DATA_DESC_SKB;
+	desc.callback = ipa_tx_comp_usr_notify_release;
+	desc.user1 = skb;
+	desc.user2 = (void *)dst_ep_idx;
+
+	if (ipa_send_one(sys, &desc, true))
+		return -EFAULT;
+
+	return 0;
 }
 
 /**
@@ -1211,76 +1063,42 @@
 int ipa_tx_dp(enum ipa_client_type dst, struct sk_buff *skb,
 		struct ipa_tx_meta *meta)
 {
-	struct ipa_desc desc[2];
 	int ipa_ep_idx;
-	struct ipa_ip_packet_init *cmd;
-
-	memset(&desc, 0, 2 * sizeof(struct ipa_desc));
 
 	ipa_ep_idx = ipa_get_ep_mapping(ipa_ctx->mode, dst);
 	if (unlikely(ipa_ep_idx == -1)) {
 		IPAERR("dest EP does not exist.\n");
-		goto fail_gen;
+		goto fail;
 	}
 
 	if (unlikely(ipa_ctx->ep[ipa_ep_idx].valid == 0)) {
 		IPAERR("dest EP not valid.\n");
-		goto fail_gen;
+		goto fail;
 	}
 
 	if (IPA_CLIENT_IS_CONS(dst)) {
-		cmd = kzalloc(sizeof(struct ipa_ip_packet_init), GFP_ATOMIC);
-		if (!cmd) {
-			IPAERR("failed to alloc immediate command object\n");
-			goto fail_mem_alloc;
-		}
-
-		cmd->destination_pipe_index = ipa_ep_idx;
-		if (meta && meta->mbim_stream_id_valid)
-			cmd->metadata = meta->mbim_stream_id;
-		desc[0].opcode = IPA_IP_PACKET_INIT;
-		desc[0].pyld = cmd;
-		desc[0].len = sizeof(struct ipa_ip_packet_init);
-		desc[0].type = IPA_IMM_CMD_DESC;
-		desc[0].callback = ipa_tx_cmd_comp;
-		desc[0].user1 = cmd;
-		desc[1].pyld = skb->data;
-		desc[1].len = skb->len;
-		desc[1].type = IPA_DATA_DESC_SKB;
-		desc[1].callback = ipa_tx_comp_usr_notify_release;
-		desc[1].user1 = skb;
-		desc[1].user2 = (void *)ipa_ep_idx;
-
-		if (ipa_send(&ipa_ctx->sys[IPA_A5_LAN_WAN_OUT], 2, desc,
-					true)) {
-			IPAERR("fail to send immediate command\n");
-			goto fail_send;
+		if (ipa_send_two(skb, &ipa_ctx->sys[IPA_A5_LAN_WAN_OUT],
+					ipa_ep_idx)) {
+			IPAERR("fail to send pkt_init+skb dst=%d skb=%p\n",
+					dst, skb);
+			goto fail;
 		}
 		IPA_STATS_INC_CNT(ipa_ctx->stats.imm_cmds[IPA_IP_PACKET_INIT]);
 	} else if (dst == IPA_CLIENT_A5_WLAN_AMPDU_PROD) {
-		desc[0].pyld = skb->data;
-		desc[0].len = skb->len;
-		desc[0].type = IPA_DATA_DESC_SKB;
-		desc[0].callback = ipa_tx_comp_usr_notify_release;
-		desc[0].user1 = skb;
-		desc[0].user2 = (void *)ipa_ep_idx;
-
-		if (ipa_send_one(&ipa_ctx->sys[IPA_A5_WLAN_AMPDU_OUT],
-					&desc[0], true)) {
-			IPAERR("fail to send skb\n");
-			goto fail_gen;
+		if (ipa_send_data_hw_path(skb,
+					&ipa_ctx->sys[IPA_A5_WLAN_AMPDU_OUT],
+					ipa_ep_idx)) {
+			IPAERR("fail to send skb dst=%d skb=%p\n", dst, skb);
+			goto fail;
 		}
 	} else {
 		IPAERR("%d PROD is not supported.\n", dst);
-		goto fail_gen;
+		goto fail;
 	}
 
 	return 0;
 
-fail_send:
-	kfree(cmd);
-fail_mem_alloc:
-fail_gen:
+fail:
 	return -EFAULT;
 }
 EXPORT_SYMBOL(ipa_tx_dp);
@@ -1316,8 +1134,7 @@
 	rx_len_cached = sys->len;
 
 	while (rx_len_cached < IPA_RX_POOL_CEIL) {
-		rx_pkt = kmem_cache_zalloc(ipa_ctx->rx_pkt_wrapper_cache,
-					   flag);
+		rx_pkt = kmalloc(sizeof(struct ipa_rx_pkt_wrapper), flag);
 		if (!rx_pkt) {
 			IPAERR("failed to alloc rx wrapper\n");
 			goto fail_kmem_cache_alloc;
@@ -1365,7 +1182,7 @@
 fail_dma_mapping:
 	dev_kfree_skb(rx_pkt->skb);
 fail_skb_alloc:
-	kmem_cache_free(ipa_ctx->rx_pkt_wrapper_cache, rx_pkt);
+	kfree(rx_pkt);
 fail_kmem_cache_alloc:
 	if (rx_len_cached == 0) {
 		IPA_STATS_INC_CNT(ipa_ctx->stats.rx_repl_repost);
@@ -1397,7 +1214,7 @@
 		dma_unmap_single(NULL, rx_pkt->dma_address, IPA_RX_SKB_SIZE,
 				 DMA_FROM_DEVICE);
 		dev_kfree_skb(rx_pkt->skb);
-		kmem_cache_free(ipa_ctx->rx_pkt_wrapper_cache, rx_pkt);
+		kfree(rx_pkt);
 	}
 }
 
diff --git a/drivers/platform/msm/ipa/ipa_i.h b/drivers/platform/msm/ipa/ipa_i.h
index b57194e..790898a 100644
--- a/drivers/platform/msm/ipa/ipa_i.h
+++ b/drivers/platform/msm/ipa/ipa_i.h
@@ -350,6 +350,7 @@
 	enum ipa_client_type client;
 	struct sps_pipe *ep_hdl;
 	struct ipa_ep_cfg cfg;
+	struct ipa_ep_cfg_holb holb;
 	u32 dst_pipe_index;
 	u32 rt_tbl_idx;
 	struct sps_connect connect;
@@ -363,6 +364,9 @@
 	bool desc_fifo_client_allocated;
 	bool data_fifo_client_allocated;
 	bool suspended;
+	unsigned int pull_len;
+	struct ipa_ip_packet_init *cmd;
+	dma_addr_t dma_addr;
 };
 
 /**
@@ -378,6 +382,7 @@
 struct ipa_sys_context {
 	struct list_head head_desc_list;
 	u32 len;
+	u32 max_len;
 	spinlock_t spinlock;
 	struct sps_register_event event;
 	struct ipa_ep_context *ep;
@@ -636,8 +641,6 @@
 	struct kmem_cache *hdr_cache;
 	struct kmem_cache *hdr_offset_cache;
 	struct kmem_cache *rt_tbl_cache;
-	struct kmem_cache *tx_pkt_wrapper_cache;
-	struct kmem_cache *rx_pkt_wrapper_cache;
 	struct kmem_cache *tree_node_cache;
 	unsigned long rt_idx_bitmap[IPA_IP_MAX];
 	struct mutex lock;
@@ -684,9 +687,7 @@
 	/* featurize if memory footprint becomes a concern */
 	struct ipa_stats stats;
 	void *smem_pipe_mem;
-	/* store HOLB configuration for WLAN TX pipes */
-	u32 hol_en;
-	u32 hol_timer;
+	struct sk_buff_head rx_list;
 };
 
 /**
@@ -775,8 +776,6 @@
 		u32 *consumer_handle);
 int ipa_send_one(struct ipa_sys_context *sys, struct ipa_desc *desc,
 		bool in_atomic);
-int ipa_send(struct ipa_sys_context *sys, u32 num_desc, struct ipa_desc *desc,
-		bool in_atomic);
 int ipa_get_ep_mapping(enum ipa_operating_mode mode,
 		       enum ipa_client_type client);
 int ipa_get_client_mapping(enum ipa_operating_mode mode, int pipe_idx);
diff --git a/drivers/platform/msm/ipa/ipa_rm_peers_list.c b/drivers/platform/msm/ipa/ipa_rm_peers_list.c
index 55f8239..4beb2b8 100644
--- a/drivers/platform/msm/ipa/ipa_rm_peers_list.c
+++ b/drivers/platform/msm/ipa/ipa_rm_peers_list.c
@@ -167,12 +167,12 @@
 bool ipa_rm_peers_list_has_last_peer(
 		struct ipa_rm_peers_list *peers_list)
 {
-	bool result = true;
+	bool result = false;
 	if (!peers_list)
 		goto bail;
 	read_lock(&peers_list->peers_lock);
 	if (peers_list->peers_count == 1)
-		result = false;
+		result = true;
 	read_unlock(&peers_list->peers_lock);
 bail:
 	return result;
diff --git a/drivers/platform/msm/ipa/ipa_rm_resource.c b/drivers/platform/msm/ipa/ipa_rm_resource.c
index 8655d89..fd67292 100644
--- a/drivers/platform/msm/ipa/ipa_rm_resource.c
+++ b/drivers/platform/msm/ipa/ipa_rm_resource.c
@@ -551,6 +551,9 @@
 {
 	int result = 0;
 	unsigned long flags;
+	unsigned long consumer_flags;
+	bool state_changed = false;
+	bool release_consumer = false;
 	if (!resource || !depends_on)
 		return -EINVAL;
 	IPADBG("IPA RM: %s from %d to %d ENTER\n",
@@ -565,38 +568,59 @@
 	spin_lock_irqsave(&resource->state_lock, flags);
 	switch (resource->state) {
 	case IPA_RM_RELEASED:
+		break;
 	case IPA_RM_GRANTED:
+		release_consumer = true;
 		break;
 	case IPA_RM_RELEASE_IN_PROGRESS:
 		if (((struct ipa_rm_resource_prod *)
-				resource)->pending_release > 0)
-			((struct ipa_rm_resource_prod *)
+			resource)->pending_release > 0)
+				((struct ipa_rm_resource_prod *)
 					resource)->pending_release--;
+		spin_lock_irqsave(&depends_on->state_lock, consumer_flags);
+		if (depends_on->state == IPA_RM_RELEASE_IN_PROGRESS &&
+			((struct ipa_rm_resource_prod *)
+			resource)->pending_release == 0) {
+			resource->state = IPA_RM_RELEASED;
+			state_changed = true;
+		}
+		spin_unlock_irqrestore(&depends_on->state_lock, consumer_flags);
 		break;
 	case IPA_RM_REQUEST_IN_PROGRESS:
+		release_consumer = true;
 		if (((struct ipa_rm_resource_prod *)
-				resource)->pending_request > 0)
-			((struct ipa_rm_resource_prod *)
+			resource)->pending_request > 0)
+				((struct ipa_rm_resource_prod *)
 					resource)->pending_request--;
+		spin_lock_irqsave(&depends_on->state_lock, consumer_flags);
+		if (depends_on->state == IPA_RM_REQUEST_IN_PROGRESS &&
+			((struct ipa_rm_resource_prod *)
+				resource)->pending_request == 0) {
+			resource->state = IPA_RM_GRANTED;
+			state_changed = true;
+		}
+		spin_unlock_irqrestore(&depends_on->state_lock, consumer_flags);
 		break;
 	default:
 		result = -EINVAL;
 		spin_unlock_irqrestore(&resource->state_lock, flags);
 		goto bail;
 	}
-	spin_unlock_irqrestore(&resource->state_lock, flags);
-	if (ipa_rm_peers_list_has_last_peer(resource->peers_list)) {
+	if (state_changed &&
+		ipa_rm_peers_list_has_last_peer(resource->peers_list)) {
 		(void) ipa_rm_wq_send_cmd(IPA_RM_WQ_NOTIFY_PROD,
 				resource->name,
-				IPA_RM_RESOURCE_RELEASED);
+				resource->state);
 		result = -EINPROGRESS;
 	}
+	spin_unlock_irqrestore(&resource->state_lock, flags);
 	ipa_rm_peers_list_remove_peer(resource->peers_list,
 			depends_on->name);
 	ipa_rm_peers_list_remove_peer(depends_on->peers_list,
 			resource->name);
-	(void) ipa_rm_resource_consumer_release(
-			(struct ipa_rm_resource_cons *)depends_on);
+	if (release_consumer)
+		(void) ipa_rm_resource_consumer_release(
+				(struct ipa_rm_resource_cons *)depends_on);
 	IPADBG("IPA RM: %s from %d to %d SUCCESS\n",
 		__func__,
 		resource->name,
diff --git a/drivers/platform/msm/ipa/ipa_utils.c b/drivers/platform/msm/ipa/ipa_utils.c
index 264de0d..912d93c 100644
--- a/drivers/platform/msm/ipa/ipa_utils.c
+++ b/drivers/platform/msm/ipa/ipa_utils.c
@@ -32,6 +32,24 @@
 	{ 19, -1, -1, -1, -1, 11, 15, 8, 6, 2, 1, 5, 14, 16, 17, 18, -1, 10, 9, 7, 3, 4 },
 };
 
+static unsigned int ipa_calc_pull_len(u32 hdr_len)
+{
+	unsigned int pull_len, padding;
+
+	pull_len = sizeof(struct ipa_a5_mux_hdr);
+
+	/*
+	 * IP packet starts on word boundary
+	 * remove the MUX header and any padding and pass the frame to
+	 * the client which registered a rx callback on the "src pipe"
+	 */
+	padding = hdr_len & 0x3;
+	if (padding)
+		pull_len += 4 - padding;
+
+	return pull_len;
+}
+
 /**
  * ipa_cfg_route() - configure IPA route
  * @route: IPA route
@@ -751,6 +769,9 @@
 		ipa_write_reg(ipa_ctx->mmio,
 			IPA_ENDP_INIT_HDR_n_OFST_v2(clnt_hdl), val);
 
+	if (IPA_CLIENT_IS_PROD(ep->client))
+		ep->pull_len = ipa_calc_pull_len(ipa_ep_cfg->hdr_len);
+
 	return 0;
 }
 EXPORT_SYMBOL(ipa_cfg_ep_hdr);
@@ -910,6 +931,73 @@
 EXPORT_SYMBOL(ipa_cfg_ep_route);
 
 /**
+ * ipa_cfg_ep_holb() - IPA end-point holb configuration
+ *
+ * If an IPA producer pipe is full, IPA HW by default will block
+ * indefinitely till space opens up. During this time no packets
+ * including those from unrelated pipes will be processed. Enabling
+ * HOLB means IPA HW will be allowed to drop packets as/when needed
+ * and indefinite blocking is avoided.
+ *
+ * @clnt_hdl:	[in] opaque client handle assigned by IPA to client
+ * @ipa_ep_cfg:	[in] IPA end-point configuration params
+ *
+ * Returns:	0 on success, negative on failure
+ */
+int ipa_cfg_ep_holb(u32 clnt_hdl, const struct ipa_ep_cfg_holb *ipa_ep_cfg)
+{
+	if (clnt_hdl >= IPA_NUM_PIPES || ipa_ctx->ep[clnt_hdl].valid == 0 ||
+			ipa_ep_cfg == NULL || ipa_ep_cfg->tmr_val > 511 ||
+			ipa_ep_cfg->en > 1) {
+		IPAERR("bad parm.\n");
+		return -EINVAL;
+	}
+
+	if (IPA_CLIENT_IS_PROD(ipa_ctx->ep[clnt_hdl].client)) {
+		IPAERR("HOLB does not apply to IPA in EP %d\n", clnt_hdl);
+		return -EINVAL;
+	}
+
+	if (ipa_ctx->ipa_hw_type == IPA_HW_v1_0) {
+		IPAERR("per EP HOLB not supported\n");
+		return -EPERM;
+	} else {
+		ipa_ctx->ep[clnt_hdl].holb = *ipa_ep_cfg;
+		ipa_write_reg(ipa_ctx->mmio,
+			IPA_ENDP_INIT_HOL_BLOCK_EN_n_OFST(clnt_hdl),
+			ipa_ep_cfg->en);
+		ipa_write_reg(ipa_ctx->mmio,
+			IPA_ENDP_INIT_HOL_BLOCK_TIMER_n_OFST(clnt_hdl),
+			ipa_ep_cfg->tmr_val);
+		IPAERR("cfg holb %u ep=%d tmr=%d\n", ipa_ep_cfg->en, clnt_hdl,
+				ipa_ep_cfg->tmr_val);
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(ipa_cfg_ep_holb);
+
+/**
+ * ipa_cfg_ep_holb_by_client() - IPA end-point holb configuration
+ *
+ * Wrapper function for ipa_cfg_ep_holb() with client name instead of
+ * client handle. This function is used for clients that does not have
+ * client handle.
+ *
+ * @client:	[in] client name
+ * @ipa_ep_cfg:	[in] IPA end-point configuration params
+ *
+ * Returns:	0 on success, negative on failure
+ */
+int ipa_cfg_ep_holb_by_client(enum ipa_client_type client,
+				const struct ipa_ep_cfg_holb *ipa_ep_cfg)
+{
+	return ipa_cfg_ep_holb(ipa_get_ep_mapping(ipa_ctx->mode, client),
+			       ipa_ep_cfg);
+}
+EXPORT_SYMBOL(ipa_cfg_ep_holb_by_client);
+
+/**
  * ipa_dump_buff_internal() - dumps buffer for debug purposes
  * @base: buffer base address
  * @phy_base: buffer physical base address
@@ -1263,4 +1351,3 @@
 	else
 		return 0;
 }
-
diff --git a/drivers/platform/msm/ipa/teth_bridge.c b/drivers/platform/msm/ipa/teth_bridge.c
index add9522..93f2366 100644
--- a/drivers/platform/msm/ipa/teth_bridge.c
+++ b/drivers/platform/msm/ipa/teth_bridge.c
@@ -1683,6 +1683,12 @@
 		return -EINVAL;
 	}
 
+	res = teth_request_resource();
+	if (res) {
+		TETH_ERR("request_resource() failed.\n");
+		return res;
+	}
+
 	memcpy(&teth_ctx->aggr_params,
 	       aggr_params,
 	       sizeof(struct teth_aggr_params));
@@ -1693,6 +1699,8 @@
 	res = teth_set_aggregation();
 	if (res)
 		TETH_ERR("Failed setting aggregation params\n");
+
+	ipa_rm_inactivity_timer_release_resource(IPA_RM_RESOURCE_BRIDGE_PROD);
 	TETH_DBG_FUNC_EXIT();
 
 	return res;
diff --git a/drivers/platform/msm/qpnp-power-on.c b/drivers/platform/msm/qpnp-power-on.c
index a85e31c..ac0b1d9 100644
--- a/drivers/platform/msm/qpnp-power-on.c
+++ b/drivers/platform/msm/qpnp-power-on.c
@@ -22,6 +22,10 @@
 #include <linux/interrupt.h>
 #include <linux/input.h>
 #include <linux/log2.h>
+#include <linux/qpnp/power-on.h>
+
+/* Common PNP defines */
+#define QPNP_PON_REVISION2(base)		(base + 0x01)
 
 /* PON common register addresses */
 #define QPNP_PON_RT_STS(base)			(base + 0x10)
@@ -38,6 +42,8 @@
 #define QPNP_PON_RESIN_S2_TIMER(base)		(base + 0x45)
 #define QPNP_PON_RESIN_S2_CNTL(base)		(base + 0x46)
 #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_WARM_RESET_TFT			BIT(4)
 
@@ -140,17 +146,31 @@
 int qpnp_pon_system_pwr_off(bool reset)
 {
 	int rc;
+	u8 reg;
+	u16 rst_en_reg;
 	struct qpnp_pon *pon = sys_reset_dev;
 
 	if (!pon)
 		return -ENODEV;
 
-	rc = qpnp_pon_masked_write(pon, QPNP_PON_PS_HOLD_RST_CTL(pon->base),
-							QPNP_PON_RESET_EN, 0);
+	rc = spmi_ext_register_readl(pon->spmi->ctrl, pon->spmi->sid,
+			QPNP_PON_REVISION2(pon->base), &reg, 1);
+	if (rc) {
+		dev_err(&pon->spmi->dev,
+			"Unable to read addr=%x, rc(%d)\n",
+			QPNP_PON_REVISION2(pon->base), rc);
+		return rc;
+	}
+
+	if (reg == 0x00)
+		rst_en_reg = QPNP_PON_PS_HOLD_RST_CTL(pon->base);
+	else
+		rst_en_reg = QPNP_PON_PS_HOLD_RST_CTL2(pon->base);
+
+	rc = qpnp_pon_masked_write(pon, rst_en_reg, QPNP_PON_RESET_EN, 0);
 	if (rc)
 		dev_err(&pon->spmi->dev,
-			"Unable to write to addr=%x, rc(%d)\n",
-				QPNP_PON_PS_HOLD_RST_CTL(pon->base), rc);
+			"Unable to write to addr=%x, rc(%d)\n", rst_en_reg, rc);
 
 	/*
 	 * We need 10 sleep clock cycles here. But since the clock is
@@ -167,13 +187,11 @@
 			"Unable to write to addr=%x, rc(%d)\n",
 				QPNP_PON_PS_HOLD_RST_CTL(pon->base), rc);
 
-	rc = qpnp_pon_masked_write(pon, QPNP_PON_PS_HOLD_RST_CTL(pon->base),
-							QPNP_PON_RESET_EN,
-							QPNP_PON_RESET_EN);
+	rc = qpnp_pon_masked_write(pon, rst_en_reg, QPNP_PON_RESET_EN,
+						    QPNP_PON_RESET_EN);
 	if (rc)
 		dev_err(&pon->spmi->dev,
-			"Unable to write to addr=%x, rc(%d)\n",
-				QPNP_PON_PS_HOLD_RST_CTL(pon->base), rc);
+			"Unable to write to addr=%x, rc(%d)\n", rst_en_reg, rc);
 
 	return rc;
 }
@@ -223,6 +241,39 @@
 }
 EXPORT_SYMBOL(qpnp_pon_is_warm_reset);
 
+/**
+ * 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
+ *
+ * This function configures the power-on trigger capability of a
+ * PON source. If a specific PON trigger is disabled it cannot act
+ * as a power-on source to the PMIC.
+ */
+
+int qpnp_pon_trigger_config(enum pon_trigger_source pon_src, bool enable)
+{
+	struct qpnp_pon *pon = sys_reset_dev;
+	int rc;
+
+	if (!pon)
+		return -EPROBE_DEFER;
+
+	if (pon_src < PON_SMPL || pon_src > PON_KPDPWR_N) {
+		dev_err(&pon->spmi->dev, "Invalid PON source\n");
+		return -EINVAL;
+	}
+
+	rc = qpnp_pon_masked_write(pon, QPNP_PON_TRIGGER_EN(pon->base),
+				BIT(pon_src), enable ? BIT(pon_src) : 0);
+	if (rc)
+		dev_err(&pon->spmi->dev, "Unable to write to addr=%x, rc(%d)\n",
+					QPNP_PON_TRIGGER_EN(pon->base), rc);
+
+	return rc;
+}
+EXPORT_SYMBOL(qpnp_pon_trigger_config);
+
 static struct qpnp_pon_config *
 qpnp_get_cfg(struct qpnp_pon *pon, u32 pon_type)
 {
diff --git a/drivers/platform/msm/qpnp-pwm.c b/drivers/platform/msm/qpnp-pwm.c
index 442d18f..be62408 100644
--- a/drivers/platform/msm/qpnp-pwm.c
+++ b/drivers/platform/msm/qpnp-pwm.c
@@ -914,7 +914,7 @@
 
 static inline int qpnp_enable_pwm_mode(struct qpnp_pwm_config *pwm_conf)
 {
-	if (pwm_conf->channel_id >= QPNP_GPLED_LPG_CHANNEL_RANGE_START ||
+	if (pwm_conf->channel_id >= QPNP_GPLED_LPG_CHANNEL_RANGE_START &&
 		pwm_conf->channel_id <= QPNP_GPLED_LPG_CHANNEL_RANGE_END)
 		return QPNP_ENABLE_PWM_MODE_GPLED_CHANNEL;
 	return QPNP_ENABLE_PWM_MODE;
diff --git a/drivers/platform/msm/sps/sps.c b/drivers/platform/msm/sps/sps.c
index 23c346a..2e77114 100644
--- a/drivers/platform/msm/sps/sps.c
+++ b/drivers/platform/msm/sps/sps.c
@@ -1583,10 +1583,7 @@
 	for (i = 0; i < transfer->iovec_count; i++) {
 		u32 flags = iovec->flags;
 
-		if (iovec->addr == 0) {
-			SPS_ERR("sps:%s:iovec address is invalid.\n", __func__);
-			return SPS_ERROR;
-		} else if (iovec->size > SPS_IOVEC_MAX_SIZE) {
+		if (iovec->size > SPS_IOVEC_MAX_SIZE) {
 			SPS_ERR("sps:%s:iovec size is invalid.\n", __func__);
 			return SPS_ERROR;
 		}
@@ -1988,6 +1985,35 @@
 EXPORT_SYMBOL(sps_get_unused_desc_num);
 
 /**
+ * Vote for or relinquish BAM DMA clock
+ *
+ */
+int sps_ctrl_bam_dma_clk(bool clk_on)
+{
+	int ret;
+
+	SPS_DBG("sps:%s.", __func__);
+
+	if (!sps->is_ready)
+		return -EPROBE_DEFER;
+
+	if (clk_on == true) {
+		SPS_DBG("sps:vote for bam dma clk.\n");
+		ret = clk_prepare_enable(sps->bamdma_clk);
+		if (ret) {
+			SPS_ERR("sps:fail to enable bamdma_clk:ret=%d\n", ret);
+			return ret;
+		}
+	} else {
+		SPS_DBG("sps:relinquish bam dma clk.\n");
+		clk_disable_unprepare(sps->bamdma_clk);
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(sps_ctrl_bam_dma_clk);
+
+/**
  * Register a BAM device
  *
  */
@@ -2528,11 +2554,13 @@
 		SPS_ERR("sps:sps_device_init err.");
 #ifdef CONFIG_SPS_SUPPORT_BAMDMA
 		clk_disable_unprepare(sps->dfab_clk);
+		clk_disable_unprepare(sps->bamdma_clk);
 #endif
 		goto sps_device_init_err;
 	}
 #ifdef CONFIG_SPS_SUPPORT_BAMDMA
 	clk_disable_unprepare(sps->dfab_clk);
+	clk_disable_unprepare(sps->bamdma_clk);
 #endif
 	sps->is_ready = true;
 
diff --git a/drivers/platform/msm/usb_bam.c b/drivers/platform/msm/usb_bam.c
index fc85dba..55cbfe9 100644
--- a/drivers/platform/msm/usb_bam.c
+++ b/drivers/platform/msm/usb_bam.c
@@ -133,11 +133,12 @@
 	enum ipa_rm_event cur_prod_state[MAX_BAMS];
 	enum ipa_rm_event cur_cons_state[MAX_BAMS];
 
-	int lpm_wait_handshake;
+	bool lpm_wait_handshake[MAX_BAMS];
 	int connect_complete;
 	bool lpm_wait_pipes;
 	int bus_suspend;
-	bool in_lpm;
+	bool disconnected;
+	bool in_lpm[MAX_BAMS];
 
 	int (*wake_cb)(void *);
 	void *wake_param;
@@ -169,8 +170,32 @@
 static struct usb_bam_pipe_connect *usb_bam_connections;
 static struct usb_bam_ctx_type ctx;
 
+static struct device *hsic_host_dev;
+static bool hsic_host_dev_resumed_from_cons_request;
+
 static int __usb_bam_register_wake_cb(u8 idx, int (*callback)(void *user),
 	void *param, bool trigger_cb_per_pipe);
+static void wait_for_prod_release(enum usb_bam cur_bam);
+static void wait_for_cons_release(enum usb_bam cur_bam);
+
+void msm_bam_set_hsic_host_dev(struct device *dev)
+{
+	if (dev) {
+		/* Hold the device until allowing lpm */
+		info.in_lpm[HSIC_BAM] = false;
+		pr_debug("%s: Getting hsic device %x\n", __func__,
+			(int)dev);
+		pm_runtime_get(dev);
+	} else if (hsic_host_dev) {
+		pr_debug("%s: Putting hsic device %x\n", __func__,
+			(int)hsic_host_dev);
+		/* Just free previous device*/
+		info.in_lpm[HSIC_BAM] = true;
+		pm_runtime_put(hsic_host_dev);
+	}
+
+	hsic_host_dev = dev;
+}
 
 static int get_bam_type_from_core_name(const char *name)
 {
@@ -209,6 +234,8 @@
 	struct sps_pipe *pipe = NULL;
 	int i;
 
+	pr_debug("%s: enter\n", __func__);
+
 	/*
 	 * Since we configure global incativity timer for all pipes
 	 * and not per each pipe, it is enough to use some pipe
@@ -217,14 +244,15 @@
 	 */
 	for (i = 0; i < ctx.max_connections; i++) {
 		pipe_connect = &usb_bam_connections[i];
-		if (pipe_connect->bam_type == bam) {
+		if (pipe_connect->bam_type == bam &&
+		    pipe_connect->enabled) {
 			pipe = ctx.usb_bam_sps.sps_pipes[i];
 			break;
 		}
 	}
 
 	if (!pipe) {
-		pr_err("%s: Bam %s has no pipes\n", __func__,
+		pr_warning("%s: Bam %s has no connected pipes\n", __func__,
 			bam_enable_strings[bam]);
 		return;
 	}
@@ -540,16 +568,6 @@
 		goto error;
 	}
 
-	spin_lock(&usb_bam_lock);
-
-	/* Set global inactivity timer upon first pipe connection */
-	if (ctx.pipes_enabled_per_bam[pipe_connect->bam_type] == 0 &&
-		ctx.inactivity_timer_ms[pipe_connect->bam_type] &&
-		pipe_connect->inactivity_notify)
-		usb_bam_set_inactivity_timer(pipe_connect->bam_type);
-
-	spin_unlock(&usb_bam_lock);
-
 	return 0;
 
 error:
@@ -622,7 +640,7 @@
 	BUG_ON(trans == NULL);
 		pr_debug("%s: Going to LPM\n", __func__);
 	spin_lock(&usb_bam_ipa_handshake_info_lock);
-	info.lpm_wait_handshake = false;
+	info.lpm_wait_handshake[HSUSB_BAM] = false;
 		info.lpm_wait_pipes = 0;
 	if (disconnect)
 		pm_runtime_put_noidle(trans->dev);
@@ -742,11 +760,19 @@
 
 	mutex_lock(&info.suspend_resume_mutex);
 
-	/* If resume was called don't finish this work */
 	spin_lock(&usb_bam_ipa_handshake_info_lock);
+	/* If cable was disconnected, let disconnection seq do everything */
+	if (info.disconnected || info.cons_stopped) {
+		spin_unlock(&usb_bam_ipa_handshake_info_lock);
+		mutex_unlock(&info.suspend_resume_mutex);
+		pr_debug("%s: Cable disconnected\n", __func__);
+		return;
+	}
+
+	/* If resume was called don't finish this work */
 	if (!info.bus_suspend) {
 		spin_unlock(&usb_bam_ipa_handshake_info_lock);
-		pr_err("%s: Bus suspend in progress\n", __func__);
+		pr_err("%s: Bus resume in progress\n", __func__);
 		goto no_lpm;
 	}
 	spin_unlock(&usb_bam_ipa_handshake_info_lock);
@@ -769,8 +795,8 @@
 				ipa_rm_resource_cons[cur_bam]);
 		}
 		ipa_suspend_pipes();
-		mutex_unlock(&info.suspend_resume_mutex);
 		usb_bam_start_lpm(0);
+		mutex_unlock(&info.suspend_resume_mutex);
 		return;
 	}
 
@@ -813,8 +839,40 @@
 	return;
 }
 
+static void usb_bam_resume_hsic_host(void)
+{
+	int i;
+	struct usb_bam_pipe_connect *pipe_iter;
+
+	spin_lock(&usb_bam_lock);
+
+	/* Exit from "full suspend" in case of hsic host */
+	if (hsic_host_dev && info.in_lpm[HSIC_BAM]) {
+		pr_debug("%s: Getting hsic device %x\n", __func__,
+			(int)hsic_host_dev);
+		pm_runtime_get(hsic_host_dev);
+		info.in_lpm[HSIC_BAM] = false;
+
+		for (i = 0; i < ctx.max_connections; i++) {
+			pipe_iter = &usb_bam_connections[i];
+			if (pipe_iter->bam_type == HSIC_BAM &&
+			    pipe_iter->enabled &&
+			    pipe_iter->suspended) {
+				spin_unlock(&usb_bam_lock);
+				ipa_resume(pipe_iter->ipa_clnt_hdl);
+				pipe_iter->suspended = false;
+				spin_lock(&usb_bam_lock);
+			}
+		}
+	}
+
+	spin_unlock(&usb_bam_lock);
+}
+
 static int cons_request_resource(enum usb_bam cur_bam)
 {
+	int ret = -EINPROGRESS;
+
 	pr_debug("%s: Request %s_CONS resource\n",
 			__func__, bam_enable_strings[cur_bam]);
 
@@ -823,29 +881,46 @@
 	complete_all(&info.cons_avail[cur_bam]);
 
 	spin_lock(&usb_bam_lock);
-	if (ctx.pipes_enabled_per_bam[cur_bam] && info.connect_complete &&
-				!info.bus_suspend && !info.prod_stopped) {
-		spin_unlock(&usb_bam_lock);
-		spin_unlock(&usb_bam_ipa_handshake_info_lock);
-		pr_debug("%s: ACK on cons_request", __func__);
-		return 0;
+
+	switch (cur_bam) {
+	case HSUSB_BAM:
+		if (ctx.pipes_enabled_per_bam[HSUSB_BAM] &&
+		    info.connect_complete &&
+			!info.cons_stopped && !info.prod_stopped) {
+			pr_debug("%s: ACK on cons_request", __func__);
+			ret = 0;
+		} else if (ctx.pipes_enabled_per_bam[HSUSB_BAM] &&
+				   info.connect_complete && info.bus_suspend) {
+			info.bus_suspend = 0;
+			if (info.wake_cb)
+				info.wake_cb(info.wake_param);
+		}
+
+		break;
+	case HSIC_BAM:
+			hsic_host_dev_resumed_from_cons_request = true;
+
+			usb_bam_resume_hsic_host();
+
+			/*
+			 * Return sucess if there are pipes connected
+			 * and not in lpm
+			 */
+			if (ctx.pipes_enabled_per_bam[cur_bam] &&
+			    !info.in_lpm[cur_bam])
+				ret = 0;
+		break;
+	case SSUSB_BAM:
+	default:
+		break;
 	}
 
-	/* A2 wakeup from LPM */
-	if (cur_bam == HSUSB_BAM && ctx.pipes_enabled_per_bam[cur_bam] &&
-		info.connect_complete && info.bus_suspend) {
-		info.bus_suspend = 0;
-		spin_unlock(&usb_bam_lock);
-		spin_unlock(&usb_bam_ipa_handshake_info_lock);
-		if (info.wake_cb)
-			info.wake_cb(info.wake_param);
-	} else {
-		spin_unlock(&usb_bam_lock);
-		spin_unlock(&usb_bam_ipa_handshake_info_lock);
-	}
+	spin_unlock(&usb_bam_ipa_handshake_info_lock);
+	spin_unlock(&usb_bam_lock);
 
-	pr_debug("%s: EINPROGRESS on cons_request", __func__);
-	return -EINPROGRESS;
+	if (ret == -EINPROGRESS)
+		pr_debug("%s: EINPROGRESS on cons_request", __func__);
+	return ret;
 }
 
 static int usb_cons_request_resource(void)
@@ -874,13 +949,29 @@
 	}
 	spin_unlock(&usb_bam_lock);
 
-	spin_lock(&usb_bam_ipa_handshake_info_lock);
-	if (cur_bam == HSUSB_BAM && info.bus_suspend)
-		queue_work(ctx.usb_bam_wq, &info.finish_suspend_work);
-	spin_unlock(&usb_bam_ipa_handshake_info_lock);
+	if (cur_bam == HSUSB_BAM) {
+		spin_lock(&usb_bam_ipa_handshake_info_lock);
+		if (info.bus_suspend)
+			queue_work(ctx.usb_bam_wq, &info.finish_suspend_work);
+		spin_unlock(&usb_bam_ipa_handshake_info_lock);
 
-	pr_debug("%s: EINPROGRESS cons_release", __func__);
-	return -EINPROGRESS;
+		pr_debug("%s: EINPROGRESS cons_release", __func__);
+		return -EINPROGRESS;
+	} else if (cur_bam == HSIC_BAM) {
+
+		/*
+		 * Allow to go to lpm for now. Actual state will be checked
+		 * in msm_bam_hsic_lpm_ok() just before going to lpm.
+		 */
+		if (hsic_host_dev && !info.in_lpm[HSIC_BAM]) {
+			pr_debug("%s: Putting hsic device %x\n", __func__,
+			(int)hsic_host_dev);
+			pm_runtime_put(hsic_host_dev);
+			info.in_lpm[HSIC_BAM] = true;
+		}
+	}
+
+	return 0;
 }
 
 static int hsic_cons_release_resource(void)
@@ -934,7 +1025,7 @@
 	}
 }
 
-static void wait_for_prod_granted(enum usb_bam cur_bam)
+static void wait_for_prod_granted(enum usb_bam cur_bam, bool start_cons)
 {
 	int ret;
 
@@ -948,7 +1039,8 @@
 			__func__);
 
 	init_completion(&info.prod_avail[cur_bam]);
-	init_completion(&info.cons_avail[cur_bam]);
+	if (start_cons)
+		init_completion(&info.cons_avail[cur_bam]);
 
 	ret = ipa_rm_request_resource(ipa_rm_resource_prod[cur_bam]);
 	if (!ret) {
@@ -970,7 +1062,7 @@
 	pr_debug("%s: Waiting for CONS\n", __func__);
 	if (info.cur_cons_state[cur_bam] != IPA_RM_RESOURCE_GRANTED) {
 		if (!wait_for_completion_timeout(&info.cons_avail[cur_bam],
-						USB_BAM_TIMEOUT*6))
+						USB_BAM_TIMEOUT))
 			pr_err("%s: Timeout wainting for CONS_REQUEST\n",
 			__func__);
 		pr_err("%s: Finished waiting for CONS\n", __func__);
@@ -1094,11 +1186,21 @@
 		spin_unlock(&usb_bam_ipa_handshake_info_lock);
 	}
 
+	spin_lock(&usb_bam_ipa_handshake_info_lock);
+	/* If cable was disconnected, let disconnection seq do everything */
+	if (info.disconnected) {
+		spin_unlock(&usb_bam_ipa_handshake_info_lock);
+		pr_debug("%s: Cable disconnected\n", __func__);
+		return;
+	}
+
 	/* Don't go to LPM if data in the pipes */
 	if (!check_pipes_empty(src_idx, dst_idx)) {
+		spin_unlock(&usb_bam_ipa_handshake_info_lock);
 		pr_err("%s: pipes not empty, won't start suspend", __func__);
 		return;
 	}
+	spin_unlock(&usb_bam_ipa_handshake_info_lock);
 
 	queue_work(ctx.usb_bam_wq, &info.suspend_work);
 }
@@ -1109,9 +1211,18 @@
 	mutex_lock(&info.suspend_resume_mutex);
 
 	spin_lock(&usb_bam_ipa_handshake_info_lock);
+	/* If cable was disconnected, let disconnection seq do everything */
+	if (info.disconnected) {
+		spin_unlock(&usb_bam_ipa_handshake_info_lock);
+		mutex_unlock(&info.suspend_resume_mutex);
+		pr_debug("%s: Cable disconnected\n", __func__);
+		return;
+	}
+
 	if (!info.bus_suspend) {
 		spin_unlock(&usb_bam_ipa_handshake_info_lock);
 		pr_err("%s: Resume started, not suspending", __func__);
+		mutex_unlock(&info.suspend_resume_mutex);
 		return;
 	}
 
@@ -1129,7 +1240,7 @@
 	}
 
 	spin_lock(&usb_bam_ipa_handshake_info_lock);
-	info.lpm_wait_handshake = true;
+	info.lpm_wait_handshake[HSUSB_BAM] = true;
 	spin_unlock(&usb_bam_ipa_handshake_info_lock);
 
 	wait_for_prod_release(HSUSB_BAM);
@@ -1156,10 +1267,10 @@
 		mutex_unlock(&info.suspend_resume_mutex);
 		return;
 	}
-	info.lpm_wait_handshake = true;
+	info.lpm_wait_handshake[HSUSB_BAM] = true;
 	spin_unlock(&usb_bam_ipa_handshake_info_lock);
 
-	wait_for_prod_granted(HSUSB_BAM);
+	wait_for_prod_granted(HSUSB_BAM, true);
 	wait_for_cons_granted(HSUSB_BAM);
 	if (info.cons_stopped) {
 		ipa_resume_pipes();
@@ -1213,13 +1324,110 @@
 	if (cur_bam != HSUSB_BAM)
 		return;
 
-	info.in_lpm = false;
+	info.in_lpm[HSUSB_BAM] = false;
 	spin_lock(&usb_bam_ipa_handshake_info_lock);
 	info.bus_suspend = 0;
 	spin_unlock(&usb_bam_ipa_handshake_info_lock);
 	queue_work(ctx.usb_bam_wq, &info.resume_work);
 }
 
+void msm_bam_wait_for_hsic_prod_granted(void)
+{
+	if (hsic_host_dev_resumed_from_cons_request)
+		return;
+
+	ctx.is_bam_inactivity[HSIC_BAM] = false;
+
+	/* Get back to resume state including wakeup ipa */
+	usb_bam_resume_hsic_host();
+
+	/* Ensure getting the producer resource */
+	wait_for_prod_granted(HSIC_BAM, false);
+}
+
+void msm_bam_hsic_notify_on_resume(void)
+{
+	/*
+	 * This function is called to notify the usb bam driver
+	 * that the hsic core and hsic bam hw are fully resumed
+	 * and clocked on. Therefore we can now set the inactivity
+	 * timer to the hsic bam hw.
+	 */
+	if (ctx.inactivity_timer_ms[HSIC_BAM] &&
+	    !hsic_host_dev_resumed_from_cons_request)
+		usb_bam_set_inactivity_timer(HSIC_BAM);
+
+	hsic_host_dev_resumed_from_cons_request = false;
+}
+
+bool msm_bam_hsic_lpm_ok(void)
+{
+	int i;
+	struct usb_bam_pipe_connect *pipe_iter;
+
+	if (hsic_host_dev) {
+
+		pr_debug("%s: Starting hsic full suspend sequence\n",
+			__func__);
+
+		/*
+		 * Start low power mode by releasing the device
+		 * only in case that indeed the resources were released
+		 * and we are still in inactivity state (wake event
+		 * have not been occured while we were waiting to the
+		 * resources release)
+		 */
+		spin_lock(&usb_bam_lock);
+
+		if (info.cur_cons_state[HSIC_BAM] ==
+			IPA_RM_RESOURCE_RELEASED &&
+		    info.cur_prod_state[HSIC_BAM] ==
+			IPA_RM_RESOURCE_RELEASED &&
+		    ctx.is_bam_inactivity[HSIC_BAM] && info.in_lpm[HSIC_BAM]) {
+
+			/* HSIC host will go now to lpm */
+			pr_debug("%s: vote for suspend hsic %x\n",
+				__func__, (int)hsic_host_dev);
+
+			for (i = 0; i < ctx.max_connections; i++) {
+				pipe_iter =
+					&usb_bam_connections[i];
+				if (pipe_iter->bam_type == HSIC_BAM &&
+				    pipe_iter->enabled &&
+				    !pipe_iter->suspended) {
+					spin_unlock(&usb_bam_lock);
+					ipa_suspend(
+					   pipe_iter->ipa_clnt_hdl);
+					pipe_iter->suspended = true;
+					spin_lock(&usb_bam_lock);
+				}
+			}
+
+			spin_unlock(&usb_bam_lock);
+			return true;
+		}
+
+		/* We don't allow lpm, therefore renew our vote here */
+		if (info.in_lpm[HSIC_BAM]) {
+			pr_err("%s: Not allow lpm while ref count=0\n",
+				__func__);
+			pr_err("%s: inactivity=%d, c_s=%d p_s=%d lpm=%d\n",
+				__func__, ctx.is_bam_inactivity[HSIC_BAM],
+				info.cur_cons_state[HSIC_BAM],
+				info.cur_prod_state[HSIC_BAM],
+				info.in_lpm[HSIC_BAM]);
+			pm_runtime_get(hsic_host_dev);
+			info.in_lpm[HSIC_BAM] = false;
+			spin_unlock(&usb_bam_lock);
+		} else
+			spin_unlock(&usb_bam_lock);
+
+		return false;
+	}
+
+	return true;
+}
+
 int usb_bam_connect_ipa(struct usb_bam_connect_ipa_params *ipa_params)
 {
 	u8 idx;
@@ -1255,52 +1463,78 @@
 	}
 
 	pr_debug("%s: enter", __func__);
-	mutex_lock(&info.suspend_resume_mutex);
 
-	spin_lock(&usb_bam_lock);
-	if (ctx.pipes_enabled_per_bam[cur_bam] == 0) {
-		spin_unlock(&usb_bam_lock);
-		if (cur_bam == HSUSB_BAM) {
+	if (cur_bam == HSUSB_BAM) {
+		mutex_lock(&info.suspend_resume_mutex);
+
+		spin_lock(&usb_bam_lock);
+		if (ctx.pipes_enabled_per_bam[HSUSB_BAM] == 0) {
+			spin_unlock(&usb_bam_lock);
 			spin_lock(&usb_bam_ipa_handshake_info_lock);
-			info.lpm_wait_handshake = 1;
+			info.lpm_wait_handshake[HSUSB_BAM] = true;
 			info.connect_complete = 0;
+			info.disconnected = 0;
 			info.lpm_wait_pipes = 1;
 			info.bus_suspend = 0;
 			info.cons_stopped = 0;
 			info.prod_stopped = 0;
 			spin_unlock(&usb_bam_ipa_handshake_info_lock);
-		}
-		usb_bam_resume_core(cur_bam);
-	} else
-		spin_unlock(&usb_bam_lock);
+			usb_bam_resume_core(cur_bam);
+		} else
+			spin_unlock(&usb_bam_lock);
+	}
 
 	 /* Check if BAM requires RESET before connect and reset first pipe */
 	 spin_lock(&usb_bam_lock);
 	 if ((pdata->reset_on_connect[cur_bam] == true) &&
-		 (ctx.pipes_enabled_per_bam[cur_bam] == 0))
-			sps_device_reset(ctx.h_bam[cur_bam]);
+	     (ctx.pipes_enabled_per_bam[cur_bam] == 0)) {
+		spin_unlock(&usb_bam_lock);
+		sps_device_reset(ctx.h_bam[cur_bam]);
+
+		/* On re-connect assume out from lpm for HSIC BAM */
+		if (cur_bam == HSIC_BAM && hsic_host_dev &&
+		    info.in_lpm[HSIC_BAM]) {
+			pr_debug("%s: Getting hsic device %x\n",
+					__func__, (int)hsic_host_dev);
+			pm_runtime_get(hsic_host_dev);
+		}
+
+		/* On re-connect assume out from lpm for all BAMs */
+		info.in_lpm[cur_bam] = false;
+	 } else
 		spin_unlock(&usb_bam_lock);
 
 	if (ipa_params->dir == USB_TO_PEER_PERIPHERAL) {
 		pr_debug("%s: Starting connect sequence\n", __func__);
-		wait_for_prod_granted(cur_bam);
+		wait_for_prod_granted(cur_bam, true);
 	}
 
 	ret = connect_pipe_ipa(idx, ipa_params);
 	if (ret) {
 		pr_err("%s: pipe connection failure\n", __func__);
-		mutex_unlock(&info.suspend_resume_mutex);
+		if (cur_bam == HSUSB_BAM)
+			mutex_unlock(&info.suspend_resume_mutex);
 		return ret;
 	}
 
 	spin_lock(&usb_bam_lock);
 	pipe_connect->enabled = 1;
+	pipe_connect->suspended = 0;
+
+	/* Set global inactivity timer upon first pipe connection */
+	if (ctx.pipes_enabled_per_bam[pipe_connect->bam_type] == 0 &&
+		ctx.inactivity_timer_ms[pipe_connect->bam_type] &&
+		pipe_connect->inactivity_notify)
+		usb_bam_set_inactivity_timer(pipe_connect->bam_type);
+
 	ctx.pipes_enabled_per_bam[cur_bam] += 1;
 	spin_unlock(&usb_bam_lock);
 	if (ipa_params->dir == PEER_PERIPHERAL_TO_USB && cur_bam == HSUSB_BAM)
 		wait_for_cons_granted(cur_bam);
 
-	mutex_unlock(&info.suspend_resume_mutex);
+	if (cur_bam == HSUSB_BAM)
+		mutex_unlock(&info.suspend_resume_mutex);
+
 	pr_debug("%s: done", __func__);
 
 	return 0;
@@ -1337,7 +1571,7 @@
 		container_of(w, struct usb_bam_event_info, event_w);
 	struct usb_bam_pipe_connect *pipe_connect =
 		container_of(event_info, struct usb_bam_pipe_connect, event);
-	struct usb_bam_pipe_connect *pipe_connect_iter;
+	struct usb_bam_pipe_connect *pipe_iter;
 	int (*callback)(void *priv);
 	void *param = NULL;
 
@@ -1347,8 +1581,33 @@
 
 		pr_debug("%s recieved USB_BAM_EVENT_WAKEUP\n", __func__);
 
+		/*
+		 * Make sure the PROD resource is granted before
+		 * wakeup hsic host class driver (done by the callback below)
+		 */
+		if (pipe_connect->peer_bam == IPA_P_BAM &&
+		    pipe_connect->bam_type == HSIC_BAM &&
+		    info.cur_prod_state[HSIC_BAM] != IPA_RM_RESOURCE_GRANTED) {
+			wait_for_prod_granted(HSIC_BAM, false);
+		}
+
+		/*
+		 * Check if need to resume the hsic host.
+		 * On one hand, since we got the wakeup interrupt
+		 * the hsic bam clocks are already enabled, so no need
+		 * to actualluy resume the hardware... However, we still need
+		 * to update the usb bam driver state (to set in_lpm=false),
+		 * and to wake ipa (ipa_resume) and to hold again the hsic host
+		 * device again to avoid it going to low poer mode next time
+		 * until we complete releasing the hsic consumer and producer
+		 * resources against the ipa resource manager.
+		 */
+		if (pipe_connect->bam_type == HSIC_BAM)
+			usb_bam_resume_hsic_host();
+
 		/* Notify about wakeup / activity of the bam */
-		event_info->callback(event_info->param);
+		if (event_info->callback)
+			event_info->callback(event_info->param);
 
 		/*
 		 * Reset inactivity timer counter if this pipe's bam
@@ -1359,12 +1618,14 @@
 			usb_bam_set_inactivity_timer(pipe_connect->bam_type);
 		spin_unlock(&usb_bam_lock);
 
-		/* A2 wakeup not from LPM (CONS was up) */
-		wait_for_prod_granted(pipe_connect->bam_type);
-		if (info.start) {
-			pr_debug("%s: Enqueue PROD transfer", __func__);
-			info.start(info.start_stop_param,
-					USB_TO_PEER_PERIPHERAL);
+		if (pipe_connect->bam_type == HSUSB_BAM) {
+			/* A2 wakeup not from LPM (CONS was up) */
+			wait_for_prod_granted(pipe_connect->bam_type, true);
+			if (info.start) {
+				pr_debug("%s: Enqueue PROD transfer", __func__);
+				info.start(info.start_stop_param,
+						USB_TO_PEER_PERIPHERAL);
+			}
 		}
 
 		break;
@@ -1389,24 +1650,44 @@
 		 */
 		spin_lock(&usb_bam_lock);
 		for (i = 0; i < ctx.max_connections; i++) {
-			pipe_connect_iter = &usb_bam_connections[i];
-			if (pipe_connect_iter->bam_type ==
+			pipe_iter = &usb_bam_connections[i];
+			if (pipe_iter->bam_type ==
 				pipe_connect->bam_type &&
-			    pipe_connect_iter->dir ==
+			    pipe_iter->dir ==
 				PEER_PERIPHERAL_TO_USB &&
-				pipe_connect_iter->enabled) {
+				pipe_iter->enabled) {
+				pr_debug("%s: Register wakeup on pipe %x\n",
+					__func__, (int)pipe_iter);
 				__usb_bam_register_wake_cb(i,
-					pipe_connect_iter->activity_notify,
-					pipe_connect_iter->priv,
+					pipe_iter->activity_notify,
+					pipe_iter->priv,
 					false);
 			}
 		}
 		spin_unlock(&usb_bam_lock);
 
-		/* Notify about the inactivity */
+		/* Notify about the inactivity to the USB class driver */
 		if (callback)
 			callback(param);
 
+		wait_for_prod_release(pipe_connect->bam_type);
+		pr_debug("%s: complete wait on hsic producer s=%d\n",
+			__func__, info.cur_prod_state[pipe_connect->bam_type]);
+
+		/*
+		 * Allow to go to lpm for now if also consumer is down.
+		 * If consumer is up, we will wait to the release consumer
+		 * notification.
+		 */
+		if (hsic_host_dev &&
+		    info.cur_cons_state[HSIC_BAM] ==
+		    IPA_RM_RESOURCE_RELEASED && !info.in_lpm[HSIC_BAM]) {
+			pr_debug("%s: Putting hsic device %x\n", __func__,
+			(int)hsic_host_dev);
+			pm_runtime_put(hsic_host_dev);
+			info.in_lpm[HSIC_BAM] = true;
+		}
+
 		break;
 	default:
 		pr_err("%s: unknown usb bam event type %d\n", __func__,
@@ -1422,13 +1703,14 @@
 		container_of(event_info,
 			     struct usb_bam_pipe_connect,
 			     event);
+	enum usb_bam bam = pipe_connect->bam_type;
 
 	spin_lock(&usb_bam_lock);
 
 	if (event_info->type == USB_BAM_EVENT_WAKEUP_PIPE)
 		queue_work(ctx.usb_bam_wq, &event_info->event_w);
 	else if (event_info->type == USB_BAM_EVENT_WAKEUP &&
-			ctx.is_bam_inactivity[pipe_connect->bam_type]) {
+			ctx.is_bam_inactivity[bam]) {
 
 		/*
 		 * Sps wake event is per pipe, so usb_bam_wake_cb is
@@ -1437,7 +1719,8 @@
 		 * Therefore, the first pipe that awaked will be considered
 		 * as global bam wake event.
 		 */
-		ctx.is_bam_inactivity[pipe_connect->bam_type] = false;
+		ctx.is_bam_inactivity[bam] = false;
+
 		queue_work(ctx.usb_bam_wq, &event_info->event_w);
 	}
 
@@ -1687,9 +1970,16 @@
 		idx = ipa_params->dst_idx;
 		pipe_connect = &usb_bam_connections[idx];
 
+		pipe_connect->activity_notify = NULL;
+		pipe_connect->inactivity_notify = NULL;
+		pipe_connect->priv = NULL;
+
 		/* Do the release handshake with the A2 via RM */
 		cur_bam = pipe_connect->bam_type;
 		info.lpm_wait_pipes = 1;
+		spin_lock(&usb_bam_ipa_handshake_info_lock);
+		info.disconnected = 1;
+		spin_unlock(&usb_bam_ipa_handshake_info_lock);
 		wait_for_prod_release(cur_bam);
 		/* close USB -> IPA pipe */
 		usb_bam_resume_core(cur_bam);
@@ -1716,6 +2006,11 @@
 	if (ipa_params->cons_clnt_hdl) {
 		idx = ipa_params->src_idx;
 		pipe_connect = &usb_bam_connections[idx];
+
+		pipe_connect->activity_notify = NULL;
+		pipe_connect->inactivity_notify = NULL;
+		pipe_connect->priv = NULL;
+
 		cur_bam = pipe_connect->bam_type;
 		wait_for_cons_release(cur_bam);
 		/* close IPA -> USB pipe */
@@ -1747,8 +2042,8 @@
 				ipa_rm_resource_cons[cur_bam]);
 		}
 		pr_debug("%s Ended disconnect sequence\n", __func__);
-		mutex_unlock(&info.suspend_resume_mutex);
 		usb_bam_start_lpm(1);
+		mutex_unlock(&info.suspend_resume_mutex);
 		return 0;
 	}
 
@@ -1839,9 +2134,11 @@
 
 			/*
 			 * Notify inactivity once, Since it is global
-			 * for all pipes on bam.
+			 * for all pipes on bam. Notify only if we have
+			 * connected pipes.
 			 */
-			if (pipe_connect->bam_type == bam) {
+			if (pipe_connect->bam_type == bam &&
+			    pipe_connect->enabled) {
 				event_info = &pipe_connect->event;
 				event_info->type = USB_BAM_EVENT_INACTIVITY;
 				event_info->param = pipe_connect->priv;
@@ -2073,6 +2370,7 @@
 	props.num_pipes = pdata->usb_bam_num_pipes;
 	props.callback = usb_bam_sps_events;
 	props.user = bam_enable_strings[bam_idx];
+	props.options = SPS_BAM_OPT_IRQ_WAKEUP;
 
 	/*
 	* HSUSB and HSIC Cores don't support RESET ACK signal to BAMs
@@ -2190,7 +2488,8 @@
 			/* Apply new timer setting if bam has running pipes */
 			if (ctx.inactivity_timer_ms[bam] != timer_d) {
 				ctx.inactivity_timer_ms[bam] = timer_d;
-				if (ctx.pipes_enabled_per_bam[bam] > 0)
+				if (ctx.pipes_enabled_per_bam[bam] > 0 &&
+				    !info.in_lpm[bam])
 					usb_bam_set_inactivity_timer(bam);
 			}
 
@@ -2263,6 +2562,7 @@
 		complete(&info.prod_released[i]);
 		info.cur_prod_state[i] = IPA_RM_RESOURCE_RELEASED;
 		info.cur_cons_state[i] = IPA_RM_RESOURCE_RELEASED;
+		info.lpm_wait_handshake[i] = false;
 	}
 
 	INIT_WORK(&info.resume_work, usb_bam_finish_resume);
@@ -2360,12 +2660,12 @@
 bool msm_bam_lpm_ok(void)
 {
 	spin_lock(&usb_bam_ipa_handshake_info_lock);
-	if (info.lpm_wait_handshake || info.lpm_wait_pipes) {
+	if (info.lpm_wait_handshake[HSUSB_BAM] || info.lpm_wait_pipes) {
 		spin_unlock(&usb_bam_ipa_handshake_info_lock);
 		pr_err("%s: Scheduling LPM for later\n", __func__);
 		return 0;
 	} else {
-		info.in_lpm = 1;
+		info.in_lpm[HSUSB_BAM] = true;
 		spin_unlock(&usb_bam_ipa_handshake_info_lock);
 		pr_err("%s: Going to LPM now\n", __func__);
 		return 1;
diff --git a/drivers/power/pm8921-bms.c b/drivers/power/pm8921-bms.c
index 9b3973b..e244df4 100644
--- a/drivers/power/pm8921-bms.c
+++ b/drivers/power/pm8921-bms.c
@@ -79,6 +79,14 @@
 	int		last_good_ocv_uv;
 };
 
+struct fcc_data {
+	int fcc_new;
+	int chargecycles;
+	int batt_temp;
+	int fcc_real;
+	int temp_real;
+};
+
 /**
  * struct pm8921_bms_chip -
  * @bms_output_lock:	lock to prevent concurrent bms reads
@@ -144,7 +152,16 @@
 	int			pon_ocv_uv;
 	int			last_cc_uah;
 	unsigned long		tm_sec;
+
 	int			enable_fcc_learning;
+	int			min_fcc_learning_soc;
+	int			min_fcc_ocv_pc;
+	int			max_fcc_learning_samples;
+	struct			fcc_data *fcc_table;
+	int			fcc_new;
+	int			start_real_soc;
+	int			pc_at_start_charge;
+
 	int			shutdown_soc;
 	int			shutdown_iavg_ua;
 	struct delayed_work	calculate_soc_delayed_work;
@@ -194,18 +211,28 @@
 #define DEFAULT_OCV_MICROVOLTS		3900000
 #define DEFAULT_CHARGE_CYCLES		0
 
+#define DELTA_FCC_PERCENT			5
+#define MIN_START_PERCENT_FOR_LEARNING		20
+#define MIN_START_OCV_PERCENT_FOR_LEARNING	30
+#define MAX_FCC_LEARNING_COUNT			5
+#define VALID_FCC_CHGCYL_RANGE			50
+
 static int last_usb_cal_delta_uv = 1800;
 module_param(last_usb_cal_delta_uv, int, 0644);
 
 static int last_chargecycles = DEFAULT_CHARGE_CYCLES;
 static int last_charge_increase;
+static int last_fcc_update_count;
+static int max_fcc_cycles = -EINVAL;
 module_param(last_chargecycles, int, 0644);
 module_param(last_charge_increase, int, 0644);
+module_param(last_fcc_update_count, int, 0644);
 
 static int calculated_soc = -EINVAL;
 static int last_soc = -EINVAL;
 static int last_real_fcc_mah = -EINVAL;
 static int last_real_fcc_batt_temp = -EINVAL;
+static int battery_removed;
 
 static int pm8921_battery_gauge_alarm_notify(struct notifier_block *nb,
 				unsigned long status, void *unused);
@@ -214,20 +241,20 @@
 	.notifier_call = pm8921_battery_gauge_alarm_notify,
 };
 
-static int bms_ops_set(const char *val, const struct kernel_param *kp)
+static int bms_ro_ops_set(const char *val, const struct kernel_param *kp)
 {
-	if (*(int *)kp->arg == -EINVAL)
-		return param_set_int(val, kp);
-	else
-		return 0;
+	return -EINVAL;
 }
 
 static struct kernel_param_ops bms_param_ops = {
-	.set = bms_ops_set,
+	.set = bms_ro_ops_set,
 	.get = param_get_int,
 };
-
+/* Make last_soc as read only as it is already calculated from shutdown_soc */
 module_param_cb(last_soc, &bms_param_ops, &last_soc, 0644);
+module_param_cb(battery_removed, &bms_param_ops, &battery_removed, 0644);
+module_param_cb(max_fcc_cycles, &bms_param_ops,
+				&max_fcc_cycles, 0644);
 
 /*
  * bms_fake_battery is set in setups where a battery emulator is used instead
@@ -245,11 +272,6 @@
 static int bms_end_ocv_uv;
 static int bms_end_cc_uah;
 
-static int bms_ro_ops_set(const char *val, const struct kernel_param *kp)
-{
-	return -EINVAL;
-}
-
 static struct kernel_param_ops bms_ro_param_ops = {
 	.set = bms_ro_ops_set,
 	.get = param_get_int,
@@ -267,6 +289,9 @@
 	struct single_row_lut *temp, *old;
 	int i, fcc, ratio;
 
+	if (!the_chip->enable_fcc_learning || battery_removed)
+		return;
+
 	if (!the_chip->fcc_temp_lut) {
 		pr_err("The static fcc lut table is NULL\n");
 		return;
@@ -301,6 +326,9 @@
 {
 	int rc = 0;
 
+	if (battery_removed)
+		return rc;
+
 	if (last_real_fcc_mah == -EINVAL)
 		rc = param_set_int(val, kp);
 	if (rc) {
@@ -323,6 +351,9 @@
 {
 	int rc = 0;
 
+	if (battery_removed)
+		return rc;
+
 	if (last_real_fcc_batt_temp == -EINVAL)
 		rc = param_set_int(val, kp);
 	if (rc) {
@@ -1552,33 +1583,6 @@
 	pr_debug("UUC = %uuAh\n", *unusable_charge_uah);
 }
 
-static int calculate_real_fcc_uah(struct pm8921_bms_chip *chip,
-				struct pm8921_soc_params *raw,
-				int batt_temp, int chargecycles,
-				int *ret_fcc_uah)
-{
-	int fcc_uah, unusable_charge_uah;
-	int remaining_charge_uah;
-	int cc_uah;
-	int real_fcc_uah;
-	int rbatt;
-	int iavg_ua;
-
-	calculate_soc_params(chip, raw, batt_temp, chargecycles,
-						&fcc_uah,
-						&unusable_charge_uah,
-						&remaining_charge_uah,
-						&cc_uah,
-						&rbatt,
-						&iavg_ua);
-
-	real_fcc_uah = remaining_charge_uah - cc_uah;
-	*ret_fcc_uah = fcc_uah;
-	pr_debug("real_fcc = %d, RC = %d CC = %d fcc = %d\n",
-			real_fcc_uah, remaining_charge_uah, cc_uah, fcc_uah);
-	return real_fcc_uah;
-}
-
 int pm8921_bms_get_simultaneous_battery_voltage_and_current(int *ibat_ua,
 								int *vbat_uv)
 {
@@ -2575,6 +2579,12 @@
 	/* store invalid soc */
 	pm8xxx_writeb(the_chip->dev->parent, TEMP_SOC_STORAGE, 0);
 
+	/* fcc learning cleanup */
+	if (the_chip->enable_fcc_learning) {
+		battery_removed = 1;
+		sysfs_notify(&the_chip->dev->kobj, NULL, "fcc_data");
+	}
+
 	/* UUC related data is left as is - use the same historical load avg */
 	update_power_supply(the_chip);
 }
@@ -2598,6 +2608,14 @@
 	int calculate_soc = 0;
 	struct pm8921_bms_chip *chip = the_chip;
 
+	/* clean up the fcc learning table */
+	if (!the_chip)
+		the_chip->adjusted_fcc_temp_lut = NULL;
+	last_fcc_update_count = 0;
+	last_real_fcc_mah = -EINVAL;
+	last_real_fcc_batt_temp = -EINVAL;
+	battery_removed = 1;
+
 	pr_debug("Invalidating shutdown soc - the battery was removed\n");
 	if (shutdown_soc_invalid)
 		return;
@@ -2719,6 +2737,20 @@
 	return calculate_fcc_uah(the_chip, batt_temp, last_chargecycles);
 }
 EXPORT_SYMBOL_GPL(pm8921_bms_get_fcc);
+
+static void calculate_real_soc(struct pm8921_bms_chip *chip, int *soc,
+		int batt_temp, struct pm8921_soc_params *raw, int cc_uah)
+{
+	int fcc_uah = 0, rc_uah = 0;
+
+	fcc_uah = calculate_fcc_uah(chip, batt_temp, last_chargecycles);
+	rc_uah = calculate_remaining_charge_uah(chip, raw,
+				fcc_uah, batt_temp, last_chargecycles);
+	*soc = ((rc_uah - cc_uah) * 100) / fcc_uah;
+	pr_debug("fcc = %d, rc = %d, cc = %d Real SOC = %d\n",
+				fcc_uah, rc_uah, cc_uah, *soc);
+}
+
 void pm8921_bms_charging_began(void)
 {
 	struct pm8921_soc_params raw;
@@ -2742,12 +2774,123 @@
 
 	the_chip->soc_at_cv = -EINVAL;
 	the_chip->prev_chg_soc = -EINVAL;
+	if (the_chip->enable_fcc_learning) {
+		calculate_real_soc(the_chip, &the_chip->start_real_soc,
+				batt_temp, &raw, bms_start_cc_uah);
+		the_chip->pc_at_start_charge =
+			interpolate_pc(the_chip->pc_temp_ocv_lut, batt_temp,
+						bms_start_ocv_uv / 1000);
+		pr_debug("Start real soc = %d, start pc = %d\n",
+			the_chip->start_real_soc, the_chip->pc_at_start_charge);
+	}
+
 	pr_debug("start_percent = %u%%\n", the_chip->start_percent);
 }
 EXPORT_SYMBOL_GPL(pm8921_bms_charging_began);
 
-#define DELTA_FCC_PERCENT	3
-#define MIN_START_PERCENT_FOR_LEARNING	30
+static void invalidate_fcc(struct pm8921_bms_chip *chip)
+{
+	memset(chip->fcc_table, 0, chip->max_fcc_learning_samples *
+					sizeof(*(chip->fcc_table)));
+	last_fcc_update_count = 0;
+	chip->adjusted_fcc_temp_lut = NULL;
+	last_real_fcc_mah = -EINVAL;
+	last_real_fcc_batt_temp = -EINVAL;
+	last_chargecycles = 0;
+	last_charge_increase = 0;
+}
+
+static void update_fcc_table_for_temp(struct pm8921_bms_chip *chip,
+						int batt_temp_final)
+{
+	int i, fcc_t1, fcc_t2, fcc_final;
+	struct fcc_data *ft;
+
+	/* Interpolate all the FCC entries to the same temperature */
+	for (i = 0; i < chip->max_fcc_learning_samples; i++) {
+		ft = &chip->fcc_table[i];
+		if (ft->batt_temp == batt_temp_final)
+			continue;
+		fcc_t1 = interpolate_fcc(chip->fcc_temp_lut, ft->batt_temp);
+		fcc_t2 = interpolate_fcc(chip->fcc_temp_lut, batt_temp_final);
+		fcc_final = (ft->fcc_new / fcc_t1) * fcc_t2;
+		ft->fcc_new = fcc_final;
+		ft->batt_temp = batt_temp_final;
+	}
+}
+
+static void update_fcc_learning_table(struct pm8921_bms_chip *chip,
+		int fcc_uah, int new_fcc_uah, int chargecycles, int batt_temp)
+{
+	int i, temp_fcc_avg = 0, new_fcc_avg = 0, temp_fcc_delta = 0, count;
+	struct fcc_data *ft;
+
+	count = last_fcc_update_count % chip->max_fcc_learning_samples;
+	ft = &chip->fcc_table[count];
+	ft->fcc_new = ft->fcc_real = new_fcc_uah;
+	ft->batt_temp = ft->temp_real = batt_temp;
+	ft->chargecycles = chargecycles;
+	chip->fcc_new = new_fcc_uah;
+	last_fcc_update_count++;
+	/* update userspace with the new data */
+	sysfs_notify(&chip->dev->kobj, NULL, "fcc_data");
+
+	pr_debug("Updated fcc table. new_fcc=%d, chargecycle=%d, temp=%d fcc_update_count=%d\n",
+		new_fcc_uah, chargecycles, batt_temp, last_fcc_update_count);
+
+	if (last_fcc_update_count < chip->max_fcc_learning_samples) {
+		pr_debug("Not enough FCC samples. Current count = %d\n",
+						last_fcc_update_count);
+		return; /* Not enough samples to update fcc */
+	}
+
+	/* reject entries if they are > 50 chargecycles apart */
+	for (i = 0; i < chip->max_fcc_learning_samples; i++) {
+		if ((chip->fcc_table[i].chargecycles + VALID_FCC_CHGCYL_RANGE)
+							< chargecycles) {
+			pr_debug("Charge cycle too old (> %d cycles apart)\n",
+							VALID_FCC_CHGCYL_RANGE);
+			return; /* Samples old, > 50 cycles apart*/
+		}
+	}
+	/* update the fcc table for temperature difference*/
+	update_fcc_table_for_temp(chip, batt_temp);
+
+	/* Calculate the avg. and SD for all the fcc entries */
+	for (i = 0; i < chip->max_fcc_learning_samples; i++)
+		temp_fcc_avg += chip->fcc_table[i].fcc_new;
+
+	temp_fcc_avg /= chip->max_fcc_learning_samples;
+	temp_fcc_delta = div_u64(temp_fcc_avg * DELTA_FCC_PERCENT, 100);
+
+	/* fix the fcc if its an outlier i.e. > 5% of the average */
+	for (i = 0; i < chip->max_fcc_learning_samples; i++) {
+		ft = &chip->fcc_table[i];
+		if (abs(ft->fcc_new - temp_fcc_avg) > temp_fcc_delta)
+			ft->fcc_new = temp_fcc_avg;
+		new_fcc_avg += ft->fcc_new;
+	}
+	new_fcc_avg /= chip->max_fcc_learning_samples;
+
+	last_real_fcc_mah = new_fcc_avg/1000;
+	last_real_fcc_batt_temp = batt_temp;
+
+	pr_debug("FCC update: last_real_fcc_mah=%d, last_real_fcc_batt_temp=%d\n",
+						new_fcc_avg, batt_temp);
+	readjust_fcc_table();
+}
+
+static bool is_new_fcc_valid(int new_fcc_uah, int fcc_uah)
+{
+	/* reject the new fcc if < 50% and > 105% of nominal fcc */
+	if ((new_fcc_uah >= (fcc_uah / 2)) &&
+			((new_fcc_uah * 100) <= (fcc_uah * 105)))
+		return true;
+
+	pr_debug("FCC rejected - not within valid limit\n");
+	return false;
+}
+
 void pm8921_bms_charging_end(int is_battery_full)
 {
 	int batt_temp;
@@ -2766,37 +2909,27 @@
 
 	bms_end_ocv_uv = raw.last_good_ocv_uv;
 
-	if (is_battery_full && the_chip->enable_fcc_learning
-		&& the_chip->start_percent <= MIN_START_PERCENT_FOR_LEARNING) {
-		int fcc_uah, new_fcc_uah, delta_fcc_uah;
+	pr_debug("battery_full = %d, fcc_learning = %d, pc_start_chg = %d\n",
+				is_battery_full, the_chip->enable_fcc_learning,
+						the_chip->pc_at_start_charge);
+	if (is_battery_full && the_chip->enable_fcc_learning &&
+		(the_chip->start_percent <= the_chip->min_fcc_learning_soc) &&
+		(the_chip->pc_at_start_charge <= the_chip->min_fcc_ocv_pc)) {
 
-		new_fcc_uah = calculate_real_fcc_uah(the_chip, &raw,
-						batt_temp, last_chargecycles,
-						&fcc_uah);
-		delta_fcc_uah = new_fcc_uah - fcc_uah;
-		if (delta_fcc_uah < 0)
-			delta_fcc_uah = -delta_fcc_uah;
+		int fcc_uah, new_fcc_uah, delta_cc_uah, delta_soc;
+		/* new_fcc = (cc_end - cc_start) / (end_soc - start_soc) */
+		delta_soc = 100 - the_chip->start_real_soc;
+		delta_cc_uah = abs(bms_end_cc_uah - bms_start_cc_uah);
+		new_fcc_uah = div_u64(delta_cc_uah * 100, delta_soc);
 
-		if (delta_fcc_uah * 100  > (DELTA_FCC_PERCENT * fcc_uah)) {
-			/* new_fcc_uah is outside the scope limit it */
-			if (new_fcc_uah > fcc_uah)
-				new_fcc_uah
-				= (fcc_uah +
-					(DELTA_FCC_PERCENT * fcc_uah) / 100);
-			else
-				new_fcc_uah
-				= (fcc_uah -
-					(DELTA_FCC_PERCENT * fcc_uah) / 100);
-
-			pr_debug("delta_fcc=%d > %d percent of fcc=%d"
-					"restring it to %d\n",
-					delta_fcc_uah, DELTA_FCC_PERCENT,
-					fcc_uah, new_fcc_uah);
-		}
-
-		last_real_fcc_mah = new_fcc_uah/1000;
-		last_real_fcc_batt_temp = batt_temp;
-		readjust_fcc_table();
+		fcc_uah = calculate_fcc_uah(the_chip, batt_temp,
+						last_chargecycles);
+		pr_info("start_real_soc = %d, end_real_soc = 100, start_cc = %d, end_cc = %d, nominal_fcc = %d, new_fcc = %d\n",
+			the_chip->start_real_soc, bms_start_cc_uah,
+			bms_end_cc_uah, fcc_uah, new_fcc_uah);
+		if (is_new_fcc_valid(new_fcc_uah, fcc_uah))
+			update_fcc_learning_table(the_chip, fcc_uah,
+				new_fcc_uah, last_chargecycles, batt_temp);
 	}
 
 	if (is_battery_full) {
@@ -3350,6 +3483,127 @@
 	}
 }
 
+static ssize_t fcc_data_set(struct device *dev, struct device_attribute *attr,
+						const char *buf, size_t count)
+{
+	struct pm8921_bms_chip *chip = dev_get_drvdata(dev);
+	static int i;
+	int fcc_new = 0, rc;
+
+	if (battery_removed) {
+		pr_debug("Invalid FCC table. Possible battery removal\n");
+		last_fcc_update_count = 0;
+		return count;
+	}
+
+	i %= chip->max_fcc_learning_samples;
+	rc = sscanf(buf, "%d", &fcc_new);
+	if (rc != 1)
+		return -EINVAL;
+	chip->fcc_table[i].fcc_new = fcc_new;
+	chip->fcc_table[i].fcc_real = fcc_new;
+	pr_debug("Rcvd: [%d] fcc_new=%d\n", i, fcc_new);
+	i++;
+
+	return count;
+}
+
+static ssize_t fcc_data_get(struct device *dev, struct device_attribute *attr,
+								char *buf)
+{
+	int count = 0;
+	struct pm8921_bms_chip *chip = dev_get_drvdata(dev);
+
+	if (battery_removed) {
+		pr_debug("Invalidate the fcc table\n");
+		invalidate_fcc(chip);
+		battery_removed = 0;
+		return count;
+	}
+
+	count = snprintf(buf, PAGE_SIZE, "%d", chip->fcc_new);
+
+	pr_debug("Sent: fcc_new=%d\n", chip->fcc_new);
+
+	return count;
+}
+
+static ssize_t fcc_temp_set(struct device *dev, struct device_attribute *attr,
+						const char *buf, size_t count)
+{
+	static int i;
+	int batt_temp = 0, rc;
+	struct pm8921_bms_chip *chip = dev_get_drvdata(dev);
+
+	i %= chip->max_fcc_learning_samples;
+	rc = sscanf(buf, "%d", &batt_temp);
+	if (rc != 1)
+		return -EINVAL;
+	chip->fcc_table[i].batt_temp = batt_temp;
+	chip->fcc_table[i].temp_real = batt_temp;
+	pr_debug("Rcvd: [%d] batt_temp=%d\n", i, batt_temp);
+	i++;
+
+	return count;
+}
+
+static ssize_t fcc_chgcyl_set(struct device *dev, struct device_attribute *attr,
+						const char *buf, size_t count)
+{
+	static int i;
+	int chargecycle = 0, rc;
+	struct pm8921_bms_chip *chip = dev_get_drvdata(dev);
+
+	i %= chip->max_fcc_learning_samples;
+	rc = sscanf(buf, "%d", &chargecycle);
+	if (rc != 1)
+		return -EINVAL;
+	chip->fcc_table[i].chargecycles = chargecycle;
+	pr_debug("Rcvd: [%d] chargecycle=%d\n", i, chargecycle);
+	i++;
+
+	return count;
+}
+
+static ssize_t fcc_list_get(struct device *dev, struct device_attribute *attr,
+								char *buf)
+{
+	struct pm8921_bms_chip *chip = dev_get_drvdata(dev);
+	struct fcc_data *ft;
+	int i = 0, j, count = 0;
+
+	if (last_fcc_update_count < chip->max_fcc_learning_samples)
+		i = last_fcc_update_count;
+	else
+		i = chip->max_fcc_learning_samples;
+
+	for (j = 0; j < i; j++) {
+		ft = &chip->fcc_table[j];
+		count += snprintf(buf + count, PAGE_SIZE - count,
+			"%d %d %d %d %d\n", ft->fcc_new, ft->chargecycles,
+			ft->batt_temp, ft->fcc_real, ft->temp_real);
+	}
+
+	return count;
+}
+
+static DEVICE_ATTR(fcc_data, 0664, fcc_data_get, fcc_data_set);
+static DEVICE_ATTR(fcc_temp, 0664, NULL, fcc_temp_set);
+static DEVICE_ATTR(fcc_chgcyl, 0664, NULL, fcc_chgcyl_set);
+static DEVICE_ATTR(fcc_list, 0664, fcc_list_get, NULL);
+
+static struct attribute *fcc_attrs[] = {
+	&dev_attr_fcc_data.attr,
+	&dev_attr_fcc_temp.attr,
+	&dev_attr_fcc_chgcyl.attr,
+	&dev_attr_fcc_list.attr,
+	NULL
+};
+
+static const struct attribute_group fcc_attr_group = {
+	.attrs = fcc_attrs,
+};
+
 #define REG_SBI_CONFIG		0x04F
 #define PAGE3_ENABLE_MASK	0x6
 #define PROGRAM_REV_MASK	0x0F
@@ -3477,6 +3731,34 @@
 	chip->batt_id_channel = pdata->bms_cdata.batt_id_channel;
 	chip->revision = pm8xxx_get_revision(chip->dev->parent);
 	chip->enable_fcc_learning = pdata->enable_fcc_learning;
+	chip->min_fcc_learning_soc = pdata->min_fcc_learning_soc;
+	chip->min_fcc_ocv_pc = pdata->min_fcc_ocv_pc;
+	chip->max_fcc_learning_samples = pdata->max_fcc_learning_samples;
+	if (chip->enable_fcc_learning) {
+		if (!chip->min_fcc_learning_soc)
+			chip->min_fcc_learning_soc =
+					MIN_START_PERCENT_FOR_LEARNING;
+		if (!chip->min_fcc_ocv_pc)
+			chip->min_fcc_ocv_pc =
+					MIN_START_OCV_PERCENT_FOR_LEARNING;
+		if (!chip->max_fcc_learning_samples ||
+			chip->max_fcc_learning_samples > MAX_FCC_LEARNING_COUNT)
+			chip->max_fcc_learning_samples = MAX_FCC_LEARNING_COUNT;
+
+		max_fcc_cycles = chip->max_fcc_learning_samples;
+		chip->fcc_table = kzalloc(sizeof(struct fcc_data) *
+				chip->max_fcc_learning_samples, GFP_KERNEL);
+		if (!chip->fcc_table) {
+			pr_err("Unable to allocate table for fcc learning\n");
+			rc = -ENOMEM;
+			goto free_chip;
+		}
+		rc = sysfs_create_group(&pdev->dev.kobj, &fcc_attr_group);
+		if (rc) {
+			pr_err("Unable to create sysfs entries\n");
+			goto free_chip;
+		}
+	}
 
 	chip->disable_flat_portion_ocv = pdata->disable_flat_portion_ocv;
 	chip->ocv_dis_high_soc = pdata->ocv_dis_high_soc;
diff --git a/drivers/power/qpnp-bms.c b/drivers/power/qpnp-bms.c
index 9a642d6..9a1fd71 100644
--- a/drivers/power/qpnp-bms.c
+++ b/drivers/power/qpnp-bms.c
@@ -168,6 +168,7 @@
 	uint16_t			ocv_reading_at_100;
 	uint16_t			prev_last_good_ocv_raw;
 	int				last_ocv_uv;
+	int				charging_adjusted_ocv;
 	int				last_ocv_temp;
 	int				last_cc_uah;
 	unsigned long			last_soc_change_sec;
@@ -229,6 +230,7 @@
 	POWER_SUPPLY_PROP_CAPACITY,
 	POWER_SUPPLY_PROP_CURRENT_NOW,
 	POWER_SUPPLY_PROP_RESISTANCE,
+	POWER_SUPPLY_PROP_CHARGE_COUNTER,
 	POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
 };
 
@@ -860,21 +862,23 @@
 }
 
 /**
- * calculate_cc-
+ * calculate_cc() - converts a hardware coulomb counter reading into uah
  * @chip:		the bms chip pointer
  * @cc:			the cc reading from bms h/w
- * @val:		return value
- * @coulomb_counter:	adjusted coulomb counter for 100%
+ * @clear_cc:		whether this function should clear the hardware counter
+ *			after reading
  *
- * RETURNS: in val pointer coulomb counter based charger in uAh
- *          (micro Amp hour)
+ * Converts the 64 bit hardware coulomb counter into microamp-hour by taking
+ * into account hardware resolution and adc errors.
+ *
+ * Return: the coulomb counter based charge in uAh (micro-amp hour)
  */
-static int calculate_cc(struct qpnp_bms_chip *chip, int64_t cc)
+static int calculate_cc(struct qpnp_bms_chip *chip, int64_t cc, bool clear_cc)
 {
 	struct qpnp_iadc_calib calibration;
 	struct qpnp_vadc_result result;
 	int64_t cc_voltage_uv, cc_pvh, cc_uah;
-	int ibat_ua, rc;
+	int rc;
 
 	rc = qpnp_vadc_read(DIE_TEMP, &result);
 	if (rc) {
@@ -882,12 +886,6 @@
 		return chip->software_cc_uah;
 	}
 
-	rc = get_battery_current(chip, &ibat_ua);
-	if (rc) {
-		pr_err("could not read battery current: %d\n", rc);
-		return chip->software_cc_uah;
-	}
-
 	qpnp_iadc_get_gain_and_offset(&calibration);
 	pr_debug("cc = %lld, die_temp = %lld\n", cc, result.physical);
 	cc_voltage_uv = cc_reading_to_uv(cc);
@@ -901,9 +899,14 @@
 	rc = qpnp_iadc_comp_result(&cc_uah);
 	if (rc)
 		pr_debug("error compensation failed: %d\n", rc);
-	chip->software_cc_uah += cc_uah;
-	reset_cc(chip);
-	return (int)chip->software_cc_uah;
+
+	if (clear_cc) {
+		chip->software_cc_uah += cc_uah;
+		reset_cc(chip);
+		return (int)chip->software_cc_uah;
+	} else {
+		return chip->software_cc_uah + cc_uah;
+	}
 }
 
 static int get_rbatt(struct qpnp_bms_chip *chip,
@@ -1232,7 +1235,7 @@
 	pr_debug("ocv_charge_uah = %uuAh\n", params->ocv_charge_uah);
 
 	/* calculate cc micro_volt_hour */
-	params->cc_uah = calculate_cc(chip, raw->cc);
+	params->cc_uah = calculate_cc(chip, raw->cc, true);
 	pr_debug("cc_uah = %duAh raw->cc = %llx\n", params->cc_uah, raw->cc);
 
 	soc_rbatt = ((params->ocv_charge_uah - params->cc_uah) * 100)
@@ -1242,10 +1245,10 @@
 	params->rbatt_mohm = get_rbatt(chip, soc_rbatt, batt_temp);
 	pr_debug("rbatt_mohm = %d\n", params->rbatt_mohm);
 
-	if (params->rbatt_mohm != chip->rbatt_mohm
-			&& chip->bms_psy.name != NULL) {
+	if (params->rbatt_mohm != chip->rbatt_mohm) {
 		chip->rbatt_mohm = params->rbatt_mohm;
-		power_supply_changed(&chip->bms_psy);
+		if (chip->bms_psy.name != NULL)
+			power_supply_changed(&chip->bms_psy);
 	}
 
 	calculate_iavg(chip, params->cc_uah, &params->iavg_ua,
@@ -1359,12 +1362,200 @@
 
 module_param_cb(bms_reset, &bms_reset_ops, &bms_reset, 0644);
 
+static void backup_soc_and_iavg(struct qpnp_bms_chip *chip, int batt_temp,
+				int soc)
+{
+	u8 temp;
+	int rc;
+	int iavg_ma = chip->prev_uuc_iavg_ma;
+
+	if (iavg_ma > IAVG_START)
+		temp = (iavg_ma - IAVG_START) / IAVG_STEP_SIZE_MA;
+	else
+		temp = 0;
+
+	rc = qpnp_write_wrapper(chip, &temp,
+			chip->base + IAVG_STORAGE_REG, 1);
+
+	temp = soc;
+
+	/* don't store soc if temperature is below 5degC */
+	if (batt_temp > IGNORE_SOC_TEMP_DECIDEG)
+		rc = qpnp_write_wrapper(chip, &temp,
+				chip->base + SOC_STORAGE_REG, 1);
+}
+
+static int scale_soc_while_chg(struct qpnp_bms_chip *chip, int chg_time_sec,
+				int catch_up_sec, int new_soc, int prev_soc)
+{
+	int scaled_soc;
+	int numerator;
+
+	/*
+	 * Don't report a high value immediately slowly scale the
+	 * value from prev_soc to the new soc based on a charge time
+	 * weighted average
+	 */
+	pr_debug("cts = %d catch_up_sec = %d\n", chg_time_sec, catch_up_sec);
+	if (catch_up_sec == 0)
+		return new_soc;
+
+	if (chg_time_sec > catch_up_sec)
+		return new_soc;
+
+	numerator = (catch_up_sec - chg_time_sec) * prev_soc
+			+ chg_time_sec * new_soc;
+	scaled_soc = numerator / catch_up_sec;
+
+	pr_debug("cts = %d new_soc = %d prev_soc = %d scaled_soc = %d\n",
+			chg_time_sec, new_soc, prev_soc, scaled_soc);
+
+	return scaled_soc;
+}
+
+/*
+ * bms_fake_battery is set in setups where a battery emulator is used instead
+ * of a real battery. This makes the bms driver report a different/fake value
+ * regardless of the calculated state of charge.
+ */
+static int bms_fake_battery = -EINVAL;
+module_param(bms_fake_battery, int, 0644);
+
+static int report_voltage_based_soc(struct qpnp_bms_chip *chip)
+{
+	pr_debug("Reported voltage based soc = %d\n",
+			chip->prev_voltage_based_soc);
+	return chip->prev_voltage_based_soc;
+}
+
+#define SOC_CATCHUP_SEC_MAX		600
+#define SOC_CATCHUP_SEC_PER_PERCENT	60
+#define MAX_CATCHUP_SOC	(SOC_CATCHUP_SEC_MAX / SOC_CATCHUP_SEC_PER_PERCENT)
+#define SOC_CHANGE_PER_SEC	20
+static int report_cc_based_soc(struct qpnp_bms_chip *chip)
+{
+	int soc, soc_change;
+	int time_since_last_change_sec, charge_time_sec = 0;
+	unsigned long last_change_sec;
+	struct timespec now;
+	struct qpnp_vadc_result result;
+	int batt_temp;
+	int rc;
+	bool charging, charging_since_last_report;
+
+	soc = chip->calculated_soc;
+
+	rc = qpnp_vadc_read(LR_MUX1_BATT_THERM, &result);
+
+	if (rc) {
+		pr_err("error reading adc channel = %d, rc = %d\n",
+					LR_MUX1_BATT_THERM, rc);
+		return rc;
+	}
+	pr_debug("batt_temp phy = %lld meas = 0x%llx\n", result.physical,
+						result.measurement);
+	batt_temp = (int)result.physical;
+
+	mutex_lock(&chip->last_soc_mutex);
+	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_since_last_report = charging || (chip->last_soc_unbound
+			&& chip->was_charging_at_sleep);
+	/*
+	 * account for charge time - limit it to SOC_CATCHUP_SEC to
+	 * avoid overflows when charging continues for extended periods
+	 */
+	if (charging) {
+		if (chip->charge_start_tm_sec == 0) {
+			/*
+			 * calculating soc for the first time
+			 * after start of chg. Initialize catchup time
+			 */
+			if (abs(soc - chip->last_soc) < MAX_CATCHUP_SOC)
+				chip->catch_up_time_sec =
+				(soc - chip->last_soc)
+					* SOC_CATCHUP_SEC_PER_PERCENT;
+			else
+				chip->catch_up_time_sec = SOC_CATCHUP_SEC_MAX;
+
+			if (chip->catch_up_time_sec < 0)
+				chip->catch_up_time_sec = 0;
+			chip->charge_start_tm_sec = last_change_sec;
+		}
+
+		charge_time_sec = min(SOC_CATCHUP_SEC_MAX, (int)last_change_sec
+				- chip->charge_start_tm_sec);
+
+		/* end catchup if calculated soc and last soc are same */
+		if (chip->last_soc == soc)
+			chip->catch_up_time_sec = 0;
+	}
+
+	if (chip->last_soc != -EINVAL) {
+		/*
+		 * last_soc < soc  ... if we have not been charging at all
+		 * since the last time this was called, report previous SoC.
+		 * Otherwise, scale and catch up.
+		 */
+		if (chip->last_soc < soc && !charging_since_last_report)
+			soc = chip->last_soc;
+		else if (chip->last_soc < soc && soc != 100)
+			soc = scale_soc_while_chg(chip, charge_time_sec,
+					chip->catch_up_time_sec,
+					soc, chip->last_soc);
+
+		soc_change = min((int)abs(chip->last_soc - soc),
+			time_since_last_change_sec / SOC_CHANGE_PER_SEC);
+		if (chip->last_soc_unbound) {
+			chip->last_soc_unbound = false;
+		} else {
+			/*
+			 * if soc have not been unbound by resume,
+			 * only change reported SoC by 1.
+			 */
+			soc_change = min(1, soc_change);
+		}
+
+		if (soc < chip->last_soc && soc != 0)
+			soc = chip->last_soc - soc_change;
+		if (soc > chip->last_soc && soc != 100)
+			soc = chip->last_soc + soc_change;
+	}
+
+	if (chip->last_soc != soc)
+		chip->last_soc_change_sec = last_change_sec;
+
+	pr_debug("last_soc = %d, calculated_soc = %d, soc = %d, time since last change = %d\n",
+			chip->last_soc, chip->calculated_soc,
+			soc, time_since_last_change_sec);
+	chip->last_soc = bound_soc(soc);
+	backup_soc_and_iavg(chip, batt_temp, chip->last_soc);
+	pr_debug("Reported SOC = %d\n", chip->last_soc);
+	chip->t_soc_queried = now;
+	mutex_unlock(&chip->last_soc_mutex);
+
+	return soc;
+}
+
+static int report_state_of_charge(struct qpnp_bms_chip *chip)
+{
+	if (bms_fake_battery != -EINVAL) {
+		pr_debug("Returning Fake SOC = %d%%\n", bms_fake_battery);
+		return bms_fake_battery;
+	} else if (chip->use_voltage_soc)
+		return report_voltage_based_soc(chip);
+	else
+		return report_cc_based_soc(chip);
+}
+
 #define VBATT_ERROR_MARGIN	20000
 static int charging_adjustments(struct qpnp_bms_chip *chip,
 				struct soc_params *params, int soc,
 				int vbat_uv, int ibat_ua, int batt_temp)
 {
-	int chg_soc, batt_terminal_uv;
+	int chg_soc, soc_ibat, batt_terminal_uv, weight_ibat, weight_cc;
 
 	batt_terminal_uv = vbat_uv + VBATT_ERROR_MARGIN
 				+ (ibat_ua * chip->r_conn_mohm) / 1000;
@@ -1402,10 +1593,16 @@
 		return chip->prev_chg_soc;
 	}
 
-	chg_soc = linear_interpolate(chip->soc_at_cv, chip->ibat_at_cv_ua,
+	soc_ibat = bound_soc(linear_interpolate(chip->soc_at_cv,
+					chip->ibat_at_cv_ua,
 					100, -1 * chip->chg_term_ua,
-					ibat_ua);
-	chg_soc = bound_soc(chg_soc);
+					ibat_ua));
+	weight_ibat = bound_soc(linear_interpolate(1, chip->soc_at_cv,
+					100, 100, chip->prev_chg_soc));
+	weight_cc = 100 - weight_ibat;
+	chg_soc = bound_soc((soc_ibat * weight_ibat + weight_cc * soc)/100);
+	pr_debug("weight_ibat = %d, weight_cc = %d, soc_ibat = %d, soc_cc = %d\n",
+			weight_ibat, weight_cc, soc_ibat, soc);
 
 	/* always report a higher soc */
 	if (chg_soc > chip->prev_chg_soc) {
@@ -1414,9 +1611,8 @@
 		chip->prev_chg_soc = chg_soc;
 
 		find_ocv_for_soc(chip, params, batt_temp, chg_soc, &new_ocv_uv);
-		chip->last_ocv_uv = new_ocv_uv;
-		pr_debug("CC CHG ADJ OCV = %d CHG SOC %d\n",
-				new_ocv_uv,
+		chip->charging_adjusted_ocv = new_ocv_uv;
+		pr_debug("CC CHG ADJ OCV = %d CHG SOC %d\n", new_ocv_uv,
 				chip->prev_chg_soc);
 	}
 
@@ -1736,12 +1932,6 @@
 					new_calculated_soc);
 
 done_calculating:
-	if (new_calculated_soc != chip->calculated_soc
-			&& chip->bms_psy.name != NULL) {
-		power_supply_changed(&chip->bms_psy);
-		pr_debug("power supply changed\n");
-	}
-
 	chip->calculated_soc = new_calculated_soc;
 	pr_debug("CC based calculated SOC = %d\n", chip->calculated_soc);
 	mutex_lock(&chip->last_soc_mutex);
@@ -1765,6 +1955,20 @@
 				params.delta_time_s);
 	}
 	mutex_unlock(&chip->last_soc_mutex);
+
+	if (new_calculated_soc != chip->calculated_soc
+			&& chip->bms_psy.name != NULL) {
+		power_supply_changed(&chip->bms_psy);
+		pr_debug("power supply changed\n");
+	} else {
+		/*
+		 * Call report state of charge anyways to periodically update
+		 * reported SoC. This prevents reported SoC from being stuck
+		 * when calculated soc doesn't change.
+		 */
+		report_state_of_charge(chip);
+	}
+
 	get_current_time(&chip->last_recalc_time);
 	chip->first_time_calc_soc = 0;
 	return chip->calculated_soc;
@@ -1861,196 +2065,6 @@
 			(chip->calculate_soc_ms)));
 }
 
-static void backup_soc_and_iavg(struct qpnp_bms_chip *chip, int batt_temp,
-				int soc)
-{
-	u8 temp;
-	int rc;
-	int iavg_ma = chip->prev_uuc_iavg_ma;
-
-	if (iavg_ma > IAVG_START)
-		temp = (iavg_ma - IAVG_START) / IAVG_STEP_SIZE_MA;
-	else
-		temp = 0;
-
-	rc = qpnp_write_wrapper(chip, &temp,
-			chip->base + IAVG_STORAGE_REG, 1);
-
-	temp = soc;
-
-	/* don't store soc if temperature is below 5degC */
-	if (batt_temp > IGNORE_SOC_TEMP_DECIDEG)
-		rc = qpnp_write_wrapper(chip, &temp,
-				chip->base + SOC_STORAGE_REG, 1);
-}
-
-#define SOC_CATCHUP_SEC_MAX		600
-#define SOC_CATCHUP_SEC_PER_PERCENT	60
-#define MAX_CATCHUP_SOC	(SOC_CATCHUP_SEC_MAX/SOC_CATCHUP_SEC_PER_PERCENT)
-static int scale_soc_while_chg(struct qpnp_bms_chip *chip, int chg_time_sec,
-				int catch_up_sec, int new_soc, int prev_soc)
-{
-	int scaled_soc;
-	int numerator;
-
-	/*
-	 * Don't report a high value immediately slowly scale the
-	 * value from prev_soc to the new soc based on a charge time
-	 * weighted average
-	 */
-	pr_debug("cts = %d catch_up_sec = %d\n", chg_time_sec, catch_up_sec);
-	if (catch_up_sec == 0)
-		return new_soc;
-	/*
-	 * if charging for more than catch_up time, simply return
-	 * new soc
-	 */
-	if (chg_time_sec > catch_up_sec)
-		return new_soc;
-
-	numerator = (catch_up_sec - chg_time_sec) * prev_soc
-			+ chg_time_sec * new_soc;
-	scaled_soc = numerator / catch_up_sec;
-
-	pr_debug("cts = %d new_soc = %d prev_soc = %d scaled_soc = %d\n",
-			chg_time_sec, new_soc, prev_soc, scaled_soc);
-
-	return scaled_soc;
-}
-
-/*
- * bms_fake_battery is set in setups where a battery emulator is used instead
- * of a real battery. This makes the bms driver report a different/fake value
- * regardless of the calculated state of charge.
- */
-static int bms_fake_battery = -EINVAL;
-module_param(bms_fake_battery, int, 0644);
-
-static int report_voltage_based_soc(struct qpnp_bms_chip *chip)
-{
-	pr_debug("Reported voltage based soc = %d\n",
-			chip->prev_voltage_based_soc);
-	return chip->prev_voltage_based_soc;
-}
-
-#define SOC_CHANGE_PER_SEC	20
-static int report_cc_based_soc(struct qpnp_bms_chip *chip)
-{
-	int soc, soc_change;
-	int time_since_last_change_sec, charge_time_sec = 0;
-	unsigned long last_change_sec;
-	struct timespec now;
-	struct qpnp_vadc_result result;
-	int batt_temp;
-	int rc;
-	bool charging, charging_since_last_report;
-
-	soc = chip->calculated_soc;
-
-	rc = qpnp_vadc_read(LR_MUX1_BATT_THERM, &result);
-
-	if (rc) {
-		pr_err("error reading adc channel = %d, rc = %d\n",
-					LR_MUX1_BATT_THERM, rc);
-		return rc;
-	}
-	pr_debug("batt_temp phy = %lld meas = 0x%llx\n", result.physical,
-						result.measurement);
-	batt_temp = (int)result.physical;
-
-	mutex_lock(&chip->last_soc_mutex);
-	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_since_last_report = charging || (chip->last_soc_unbound
-			&& chip->was_charging_at_sleep);
-	/*
-	 * account for charge time - limit it to SOC_CATCHUP_SEC to
-	 * avoid overflows when charging continues for extended periods
-	 */
-	if (charging) {
-		if (chip->charge_start_tm_sec == 0) {
-			/*
-			 * calculating soc for the first time
-			 * after start of chg. Initialize catchup time
-			 */
-			if (abs(soc - chip->last_soc) < MAX_CATCHUP_SOC)
-				chip->catch_up_time_sec =
-				(soc - chip->last_soc)
-					* SOC_CATCHUP_SEC_PER_PERCENT;
-			else
-				chip->catch_up_time_sec = SOC_CATCHUP_SEC_MAX;
-
-			if (chip->catch_up_time_sec < 0)
-				chip->catch_up_time_sec = 0;
-			chip->charge_start_tm_sec = last_change_sec;
-		}
-
-		charge_time_sec = min(SOC_CATCHUP_SEC_MAX, (int)last_change_sec
-				- chip->charge_start_tm_sec);
-
-		/* end catchup if calculated soc and last soc are same */
-		if (chip->last_soc == soc)
-			chip->catch_up_time_sec = 0;
-	}
-
-	if (chip->last_soc != -EINVAL) {
-		/* last_soc < soc  ... if we have not been charging at all
-		 * since the last time this was called, report previous SoC.
-		 * Otherwise, scale and catch up.
-		 */
-		if (chip->last_soc < soc && !charging_since_last_report)
-			soc = chip->last_soc;
-		else if (chip->last_soc < soc && soc != 100)
-			soc = scale_soc_while_chg(chip, charge_time_sec,
-					chip->catch_up_time_sec,
-					soc, chip->last_soc);
-
-		soc_change = min((int)abs(chip->last_soc - soc),
-			time_since_last_change_sec / SOC_CHANGE_PER_SEC);
-		if (chip->last_soc_unbound) {
-			chip->last_soc_unbound = false;
-		} else {
-			/*
-			 * if soc have not been unbound by resume,
-			 * only change reported SoC by 1.
-			 */
-			soc_change = min(1, soc_change);
-		}
-
-		if (soc < chip->last_soc && soc != 0)
-			soc = chip->last_soc - soc_change;
-		if (soc > chip->last_soc && soc != 100)
-			soc = chip->last_soc + soc_change;
-	}
-
-	if (chip->last_soc != soc)
-		chip->last_soc_change_sec = last_change_sec;
-
-	pr_debug("last_soc = %d, calculated_soc = %d, soc = %d, time since last change = %d\n",
-			chip->last_soc, chip->calculated_soc,
-			soc, time_since_last_change_sec);
-	chip->last_soc = bound_soc(soc);
-	backup_soc_and_iavg(chip, batt_temp, chip->last_soc);
-	pr_debug("Reported SOC = %d\n", chip->last_soc);
-	chip->t_soc_queried = now;
-	mutex_unlock(&chip->last_soc_mutex);
-
-	return soc;
-}
-
-static int report_state_of_charge(struct qpnp_bms_chip *chip)
-{
-	if (bms_fake_battery != -EINVAL) {
-		pr_debug("Returning Fake SOC = %d%%\n", bms_fake_battery);
-		return bms_fake_battery;
-	} else if (chip->use_voltage_soc)
-		return report_voltage_based_soc(chip);
-	else
-		return report_cc_based_soc(chip);
-}
-
 static void configure_vbat_monitor_low(struct qpnp_bms_chip *chip)
 {
 	mutex_lock(&chip->vbat_monitor_mutex);
@@ -2269,8 +2283,16 @@
 	mutex_lock(&chip->last_ocv_uv_mutex);
 	chip->soc_at_cv = -EINVAL;
 	chip->prev_chg_soc = -EINVAL;
-	if (get_battery_status(chip) == POWER_SUPPLY_STATUS_FULL)
+	if (get_battery_status(chip) == POWER_SUPPLY_STATUS_FULL) {
 		chip->done_charging = true;
+		chip->last_soc_invalid = true;
+	} else if (chip->charging_adjusted_ocv > 0) {
+		pr_debug("Charging stopped before full, adjusted OCV = %d\n",
+				chip->charging_adjusted_ocv);
+		chip->last_ocv_uv = chip->charging_adjusted_ocv;
+	}
+	chip->charging_adjusted_ocv = -EINVAL;
+
 	mutex_unlock(&chip->last_ocv_uv_mutex);
 }
 
@@ -2341,6 +2363,20 @@
 	return result_ua;
 }
 
+/* Returns coulomb counter in uAh */
+static int get_prop_bms_charge_counter(struct qpnp_bms_chip *chip)
+{
+	int64_t cc_raw;
+
+	mutex_lock(&chip->bms_output_lock);
+	lock_output_data(chip);
+	read_cc_raw(chip, &cc_raw);
+	unlock_output_data(chip);
+	mutex_unlock(&chip->bms_output_lock);
+
+	return calculate_cc(chip, cc_raw, false);
+}
+
 /* Returns full charge design in uAh */
 static int get_prop_bms_charge_full_design(struct qpnp_bms_chip *chip)
 {
@@ -2373,6 +2409,9 @@
 	case POWER_SUPPLY_PROP_RESISTANCE:
 		val->intval = get_prop_bms_batt_resistance(chip);
 		break;
+	case POWER_SUPPLY_PROP_CHARGE_COUNTER:
+		val->intval = get_prop_bms_charge_counter(chip);
+		break;
 	case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
 		val->intval = get_prop_bms_charge_full_design(chip);
 		break;
@@ -3015,7 +3054,7 @@
 {
 	int rc;
 	int soc_calc_period;
-	int time_until_next_recalc;
+	int time_until_next_recalc = 0;
 	unsigned long time_since_last_recalc;
 	unsigned long tm_now_sec;
 	struct qpnp_bms_chip *chip = dev_get_drvdata(dev);
@@ -3023,26 +3062,24 @@
 	rc = get_current_time(&tm_now_sec);
 	if (rc) {
 		pr_err("Could not read current time: %d\n", rc);
-	} else if (tm_now_sec > chip->last_recalc_time) {
-		time_since_last_recalc = tm_now_sec - chip->last_recalc_time;
-		pr_debug("Time since last recalc: %lu\n",
-				time_since_last_recalc);
+	} else {
 		if (chip->calculated_soc < chip->low_soc_calc_threshold)
 			soc_calc_period = chip->low_soc_calculate_soc_ms;
 		else
 			soc_calc_period = chip->calculate_soc_ms;
-
+		time_since_last_recalc = tm_now_sec - chip->last_recalc_time;
+		pr_debug("Time since last recalc: %lu\n",
+				time_since_last_recalc);
 		time_until_next_recalc = max(0, soc_calc_period
 				- (int)(time_since_last_recalc * 1000));
-
-		if (!wake_lock_active(&chip->soc_wake_lock)
-				&& time_until_next_recalc == 0)
-			wake_lock(&chip->soc_wake_lock);
-
-		schedule_delayed_work(&chip->calculate_soc_delayed_work,
-			round_jiffies_relative(msecs_to_jiffies
-			(time_until_next_recalc)));
 	}
+
+	if (!wake_lock_active(&chip->soc_wake_lock)
+			&& time_until_next_recalc == 0)
+		wake_lock(&chip->soc_wake_lock);
+	schedule_delayed_work(&chip->calculate_soc_delayed_work,
+		round_jiffies_relative(msecs_to_jiffies
+		(time_until_next_recalc)));
 	return 0;
 }
 
diff --git a/drivers/power/qpnp-charger.c b/drivers/power/qpnp-charger.c
index 624a42f..abda3c6 100644
--- a/drivers/power/qpnp-charger.c
+++ b/drivers/power/qpnp-charger.c
@@ -25,6 +25,9 @@
 #include <linux/power_supply.h>
 #include <linux/bitops.h>
 #include <linux/ratelimit.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/of_regulator.h>
+#include <linux/regulator/machine.h>
 
 /* Interrupt offsets */
 #define INT_RT_STS(base)			(base + 0x10)
@@ -92,8 +95,12 @@
 #define SEC_ACCESS				0xD0
 #define BAT_IF_VREF_BAT_THM_CTRL		0x4A
 #define BAT_IF_BPD_CTRL				0x48
+#define BOOST_VSET				0x41
+#define BOOST_ENABLE_CONTROL			0x46
+#define COMP_OVR1				0xEA
 
 #define REG_OFFSET_PERP_SUBTYPE			0x05
+
 /* SMBB peripheral subtype values */
 #define SMBB_CHGR_SUBTYPE			0x01
 #define SMBB_BUCK_SUBTYPE			0x02
@@ -132,6 +139,7 @@
 #define REV_BST_DETECTED		BIT(0)
 #define BAT_THM_EN			BIT(1)
 #define BAT_ID_EN			BIT(0)
+#define BOOST_PWR_EN			BIT(7)
 
 /* Interrupt definitions */
 /* smbb_chg_interrupts */
@@ -183,12 +191,18 @@
 
 /* Workaround flags */
 #define CHG_FLAGS_VCP_WA		BIT(0)
+#define BOOST_FLASH_WA			BIT(1)
 
 struct qpnp_chg_irq {
 	unsigned int		irq;
 	unsigned long		disabled;
 };
 
+struct qpnp_chg_regulator {
+	struct regulator_desc			rdesc;
+	struct regulator_dev			*rdev;
+};
+
 /**
  * struct qpnp_chg_chip - device information
  * @dev:			device pointer to access the parent
@@ -263,6 +277,7 @@
 	bool				batt_present;
 	bool				charging_disabled;
 	bool				use_default_batt_values;
+	bool				duty_cycle_100p;
 	unsigned int			bpd_detection;
 	unsigned int			max_bat_chg_current;
 	unsigned int			warm_bat_chg_ma;
@@ -295,6 +310,8 @@
 	struct delayed_work		arb_stop_work;
 	struct delayed_work		eoc_work;
 	struct wake_lock		eoc_wake_lock;
+	struct qpnp_chg_regulator	otg_vreg;
+	struct qpnp_chg_regulator	boost_vreg;
 };
 
 
@@ -303,20 +320,24 @@
 	{}
 };
 
-#define BPD_MAX		3
+enum bpd_type {
+	BPD_TYPE_BAT_ID,
+	BPD_TYPE_BAT_THM,
+	BPD_TYPE_BAT_THM_BAT_ID,
+};
 
-static const char *bpd_list[BPD_MAX] = {
-	"bpd_thm",
-	"bpd_id",
-	"bpd_thm_id",
+static const char * const bpd_label[] = {
+	[BPD_TYPE_BAT_ID] = "bpd_id",
+	[BPD_TYPE_BAT_THM] = "bpd_thm",
+	[BPD_TYPE_BAT_THM_BAT_ID] = "bpd_thm_id",
 };
 
 static inline int
 get_bpd(const char *name)
 {
 	int i = 0;
-	for (i = 0 ; i < BPD_MAX; i++) {
-		if (strcmp(name, bpd_list[i]) == 0)
+	for (i = 0; i < ARRAY_SIZE(bpd_label); i++) {
+		if (strcmp(bpd_label[i], name) == 0)
 			return i;
 	}
 	return -EINVAL;
@@ -425,6 +446,25 @@
 }
 
 static int
+qpnp_chg_is_boost_en_set(struct qpnp_chg_chip *chip)
+{
+	u8 boost_en_ctl;
+	int rc;
+
+	rc = qpnp_chg_read(chip, &boost_en_ctl,
+		chip->boost_base + BOOST_ENABLE_CONTROL, 1);
+	if (rc) {
+		pr_err("spmi read failed: addr=%03X, rc=%d\n",
+				chip->boost_base + BOOST_ENABLE_CONTROL, rc);
+		return rc;
+	}
+
+	pr_debug("boost en 0x%x\n", boost_en_ctl);
+
+	return (boost_en_ctl & BOOST_PWR_EN) ? 1 : 0;
+}
+
+static int
 qpnp_chg_is_batt_present(struct qpnp_chg_chip *chip)
 {
 	u8 batt_pres_rt_sts;
@@ -610,6 +650,32 @@
 			disable ? CHGR_ON_BAT_FORCE_BIT : 0, 1);
 }
 
+#define BUCK_DUTY_MASK_100P	0x30
+static int
+qpnp_buck_set_100_duty_cycle_enable(struct qpnp_chg_chip *chip, int enable)
+{
+	int rc;
+
+	pr_debug("enable: %d\n", enable);
+
+	rc = qpnp_chg_masked_write(chip,
+		chip->buck_base + SEC_ACCESS, 0xA5, 0xA5, 1);
+	if (rc) {
+		pr_debug("failed to write sec access rc=%d\n", rc);
+		return rc;
+	}
+
+	rc = qpnp_chg_masked_write(chip,
+		chip->buck_base + BUCK_TEST_SMBC_MODES,
+			BUCK_DUTY_MASK_100P, enable ? 0x00 : 0x10, 1);
+	if (rc) {
+		pr_debug("failed enable 100p duty cycle rc=%d\n", rc);
+		return rc;
+	}
+
+	return rc;
+}
+
 #define COMPATATOR_OVERRIDE_0	0x80
 static int
 qpnp_chg_toggle_chg_done_logic(struct qpnp_chg_chip *chip, int enable)
@@ -1153,7 +1219,6 @@
 get_prop_capacity(struct qpnp_chg_chip *chip)
 {
 	union power_supply_propval ret = {0,};
-	bool usb_online, dc_online;
 
 	if (chip->use_default_batt_values || !get_prop_batt_present(chip))
 		return DEFAULT_CAPACITY;
@@ -1162,11 +1227,8 @@
 		chip->bms_psy->get_property(chip->bms_psy,
 			  POWER_SUPPLY_PROP_CAPACITY, &ret);
 		if (ret.intval == 0) {
-			usb_online = chip->usb_psy->get_property(chip->usb_psy,
-					  POWER_SUPPLY_PROP_ONLINE, &ret);
-			dc_online = chip->dc_psy.get_property(&chip->dc_psy,
-					  POWER_SUPPLY_PROP_ONLINE, &ret);
-			if (!usb_online && !dc_online)
+			if (!qpnp_chg_is_usb_chg_plugged_in(chip)
+				&& !qpnp_chg_is_usb_chg_plugged_in(chip))
 				pr_warn_ratelimited("Battery 0, CHG absent\n");
 		}
 		return ret.intval;
@@ -1219,21 +1281,6 @@
 		chip->bms_psy = power_supply_get_by_name("bms");
 
 	chip->usb_psy->get_property(chip->usb_psy,
-			  POWER_SUPPLY_PROP_SCOPE, &ret);
-	if (ret.intval) {
-		if ((ret.intval == POWER_SUPPLY_SCOPE_SYSTEM)
-				&& !qpnp_chg_is_otg_en_set(chip)) {
-			switch_usb_to_host_mode(chip);
-			return;
-		}
-		if ((ret.intval == POWER_SUPPLY_SCOPE_DEVICE)
-				&& qpnp_chg_is_otg_en_set(chip)) {
-			switch_usb_to_charge_mode(chip);
-			return;
-		}
-	}
-
-	chip->usb_psy->get_property(chip->usb_psy,
 			  POWER_SUPPLY_PROP_ONLINE, &ret);
 
 	/* Only honour requests while USB is present */
@@ -1461,6 +1508,48 @@
 	return qpnp_chg_write(chip, &temp, chip->chgr_base + CHGR_VDD_MAX, 1);
 }
 
+#define BOOST_MIN_UV	4200000
+#define BOOST_MAX_UV	5500000
+#define BOOST_STEP_UV	50000
+#define BOOST_MIN	16
+#define N_BOOST_V	((BOOST_MAX_UV - BOOST_MIN_UV) / BOOST_STEP_UV + 1)
+static int
+qpnp_boost_vset(struct qpnp_chg_chip *chip, int voltage)
+{
+	u8 reg = 0;
+
+	if (voltage < BOOST_MIN_UV || voltage > BOOST_MAX_UV) {
+		pr_err("invalid voltage requested %d uV\n", voltage);
+		return -EINVAL;
+	}
+
+	reg = DIV_ROUND_UP(voltage - BOOST_MIN_UV, BOOST_STEP_UV) + BOOST_MIN;
+
+	pr_debug("voltage=%d setting %02x\n", voltage, reg);
+	return qpnp_chg_write(chip, &reg, chip->boost_base + BOOST_VSET, 1);
+}
+
+static int
+qpnp_boost_vget_uv(struct qpnp_chg_chip *chip)
+{
+	int rc;
+	u8 boost_reg;
+
+	rc = qpnp_chg_read(chip, &boost_reg,
+		 chip->boost_base + BOOST_VSET, 1);
+	if (rc) {
+		pr_err("failed to read BOOST_VSET rc=%d\n", rc);
+		return rc;
+	}
+
+	if (boost_reg < BOOST_MIN) {
+		pr_err("Invalid reading from 0x%x\n", boost_reg);
+		return -EINVAL;
+	}
+
+	return BOOST_MIN_UV + ((boost_reg - BOOST_MIN) * BOOST_STEP_UV);
+}
+
 /* JEITA compliance logic */
 static void
 qpnp_chg_set_appropriate_vddmax(struct qpnp_chg_chip *chip)
@@ -1523,6 +1612,228 @@
 	}
 }
 
+/* OTG regulator operations */
+static int
+qpnp_chg_regulator_otg_enable(struct regulator_dev *rdev)
+{
+	struct qpnp_chg_chip *chip = rdev_get_drvdata(rdev);
+
+	return switch_usb_to_host_mode(chip);
+}
+
+static int
+qpnp_chg_regulator_otg_disable(struct regulator_dev *rdev)
+{
+	struct qpnp_chg_chip *chip = rdev_get_drvdata(rdev);
+
+	return switch_usb_to_charge_mode(chip);
+}
+
+static int
+qpnp_chg_regulator_otg_is_enabled(struct regulator_dev *rdev)
+{
+	struct qpnp_chg_chip *chip = rdev_get_drvdata(rdev);
+
+	return qpnp_chg_is_otg_en_set(chip);
+}
+
+static int
+qpnp_chg_regulator_boost_enable(struct regulator_dev *rdev)
+{
+	struct qpnp_chg_chip *chip = rdev_get_drvdata(rdev);
+	int rc;
+
+	if (qpnp_chg_is_usb_chg_plugged_in(chip) &&
+			(chip->flags & BOOST_FLASH_WA)) {
+		qpnp_chg_usb_suspend_enable(chip, 1);
+
+		rc = qpnp_chg_masked_write(chip,
+			chip->usb_chgpth_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->usb_chgpth_base + COMP_OVR1,
+			0xFF,
+			0x2F, 1);
+		if (rc) {
+			pr_err("failed to write COMP_OVR1 rc=%d\n", rc);
+			return rc;
+		}
+	}
+
+	return qpnp_chg_masked_write(chip,
+		chip->boost_base + BOOST_ENABLE_CONTROL,
+		BOOST_PWR_EN,
+		BOOST_PWR_EN, 1);
+}
+
+/* Boost regulator operations */
+#define ABOVE_VBAT_WEAK		BIT(1)
+static int
+qpnp_chg_regulator_boost_disable(struct regulator_dev *rdev)
+{
+	struct qpnp_chg_chip *chip = rdev_get_drvdata(rdev);
+	int rc;
+	u8 vbat_sts;
+
+	rc = qpnp_chg_masked_write(chip,
+		chip->boost_base + BOOST_ENABLE_CONTROL,
+		BOOST_PWR_EN,
+		0, 1);
+	if (rc) {
+		pr_err("failed to disable boost rc=%d\n", rc);
+		return rc;
+	}
+
+	rc = qpnp_chg_read(chip, &vbat_sts,
+			chip->chgr_base + CHGR_VBAT_STATUS, 1);
+	if (rc) {
+		pr_err("failed to read bat sts rc=%d\n", rc);
+		return rc;
+	}
+
+	if (!(vbat_sts & ABOVE_VBAT_WEAK) && (chip->flags & BOOST_FLASH_WA)) {
+		rc = qpnp_chg_masked_write(chip,
+			chip->chgr_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->chgr_base + COMP_OVR1,
+			0xFF,
+			0x20, 1);
+		if (rc) {
+			pr_err("failed to write COMP_OVR1 rc=%d\n", rc);
+			return rc;
+		}
+
+		usleep(2000);
+
+		rc = qpnp_chg_masked_write(chip,
+			chip->chgr_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->chgr_base + COMP_OVR1,
+			0xFF,
+			0x00, 1);
+		if (rc) {
+			pr_err("failed to write COMP_OVR1 rc=%d\n", rc);
+			return rc;
+		}
+	}
+
+	if (qpnp_chg_is_usb_chg_plugged_in(chip)
+			&& (chip->flags & BOOST_FLASH_WA)) {
+		rc = qpnp_chg_masked_write(chip,
+			chip->usb_chgpth_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->usb_chgpth_base + COMP_OVR1,
+			0xFF,
+			0x00, 1);
+		if (rc) {
+			pr_err("failed to write COMP_OVR1 rc=%d\n", rc);
+			return rc;
+		}
+
+		usleep(1000);
+
+		qpnp_chg_usb_suspend_enable(chip, 0);
+	}
+
+	return rc;
+}
+
+static int
+qpnp_chg_regulator_boost_is_enabled(struct regulator_dev *rdev)
+{
+	struct qpnp_chg_chip *chip = rdev_get_drvdata(rdev);
+
+	return qpnp_chg_is_boost_en_set(chip);
+}
+
+static int
+qpnp_chg_regulator_boost_set_voltage(struct regulator_dev *rdev,
+		int min_uV, int max_uV, unsigned *selector)
+{
+	int uV = min_uV;
+	int rc;
+	struct qpnp_chg_chip *chip = rdev_get_drvdata(rdev);
+
+	if (uV < BOOST_MIN_UV && max_uV >= BOOST_MIN_UV)
+		uV = BOOST_MIN_UV;
+
+
+	if (uV < BOOST_MIN_UV || uV > BOOST_MAX_UV) {
+		pr_err("request %d uV is out of bounds\n", uV);
+		return -EINVAL;
+	}
+
+	*selector = DIV_ROUND_UP(uV - BOOST_MIN_UV, BOOST_STEP_UV);
+	if ((*selector * BOOST_STEP_UV + BOOST_MIN_UV) > max_uV) {
+		pr_err("no available setpoint [%d, %d] uV\n", min_uV, max_uV);
+		return -EINVAL;
+	}
+
+	rc = qpnp_boost_vset(chip, uV);
+
+	return rc;
+}
+
+static int
+qpnp_chg_regulator_boost_get_voltage(struct regulator_dev *rdev)
+{
+	struct qpnp_chg_chip *chip = rdev_get_drvdata(rdev);
+
+	return qpnp_boost_vget_uv(chip);
+}
+
+static int
+qpnp_chg_regulator_boost_list_voltage(struct regulator_dev *rdev,
+			unsigned selector)
+{
+	if (selector >= N_BOOST_V)
+		return 0;
+
+	return BOOST_MIN_UV + (selector * BOOST_STEP_UV);
+}
+
+static struct regulator_ops qpnp_chg_otg_reg_ops = {
+	.enable			= qpnp_chg_regulator_otg_enable,
+	.disable		= qpnp_chg_regulator_otg_disable,
+	.is_enabled		= qpnp_chg_regulator_otg_is_enabled,
+};
+
+static struct regulator_ops qpnp_chg_boost_reg_ops = {
+	.enable			= qpnp_chg_regulator_boost_enable,
+	.disable		= qpnp_chg_regulator_boost_disable,
+	.is_enabled		= qpnp_chg_regulator_boost_is_enabled,
+	.set_voltage		= qpnp_chg_regulator_boost_set_voltage,
+	.get_voltage		= qpnp_chg_regulator_boost_get_voltage,
+	.list_voltage		= qpnp_chg_regulator_boost_list_voltage,
+};
+
 #define CONSECUTIVE_COUNT	3
 static void
 qpnp_eoc_work(struct work_struct *work)
@@ -1709,6 +2020,8 @@
 {
 	if (chip->revision > 0 && chip->type == SMBB)
 		chip->flags |= CHG_FLAGS_VCP_WA;
+	if (chip->type == SMBB)
+		chip->flags |= BOOST_FLASH_WA;
 }
 
 static int
@@ -1910,6 +2223,8 @@
 {
 	int rc = 0;
 	u8 reg = 0;
+	struct regulator_init_data *init_data;
+	struct regulator_desc *rdesc;
 
 	switch (subtype) {
 	case SMBB_CHGR_SUBTYPE:
@@ -1989,10 +2304,20 @@
 	case SMBBP_BAT_IF_SUBTYPE:
 	case SMBCL_BAT_IF_SUBTYPE:
 		/* Select battery presence detection */
-		if (chip->bpd_detection == 1)
+		switch (chip->bpd_detection) {
+		case BPD_TYPE_BAT_THM:
+			reg = BAT_THM_EN;
+			break;
+		case BPD_TYPE_BAT_ID:
 			reg = BAT_ID_EN;
-		else if (chip->bpd_detection == 2)
-			reg = BAT_ID_EN | BAT_THM_EN;
+			break;
+		case BPD_TYPE_BAT_THM_BAT_ID:
+			reg = BAT_THM_EN | BAT_ID_EN;
+			break;
+		default:
+			reg = BAT_THM_EN;
+			break;
+		}
 
 		rc = qpnp_chg_masked_write(chip,
 			chip->bat_if_base + BAT_IF_BPD_CTRL,
@@ -2026,6 +2351,39 @@
 			}
 		}
 
+		init_data = of_get_regulator_init_data(chip->dev,
+						       spmi_resource->of_node);
+		if (!init_data) {
+			pr_err("unable to allocate memory\n");
+			return -ENOMEM;
+		}
+
+		if (init_data->constraints.name) {
+			if (of_get_property(chip->dev->of_node,
+						"otg-parent-supply", NULL))
+				init_data->supply_regulator = "otg-parent";
+
+			rdesc			= &(chip->otg_vreg.rdesc);
+			rdesc->owner		= THIS_MODULE;
+			rdesc->type		= REGULATOR_VOLTAGE;
+			rdesc->ops		= &qpnp_chg_otg_reg_ops;
+			rdesc->name		= init_data->constraints.name;
+
+			init_data->constraints.valid_ops_mask
+				|= REGULATOR_CHANGE_STATUS;
+
+			chip->otg_vreg.rdev = regulator_register(rdesc,
+					chip->dev, init_data, chip,
+					spmi_resource->of_node);
+			if (IS_ERR(chip->otg_vreg.rdev)) {
+				rc = PTR_ERR(chip->otg_vreg.rdev);
+				chip->otg_vreg.rdev = NULL;
+				if (rc != -EPROBE_DEFER)
+					pr_err("OTG reg failed, rc=%d\n", rc);
+				return rc;
+			}
+		}
+
 		rc = qpnp_chg_masked_write(chip,
 			chip->usb_chgpth_base + USB_OVP_CTL,
 			USB_VALID_DEB_20MS,
@@ -2051,6 +2409,39 @@
 		break;
 	case SMBB_BOOST_SUBTYPE:
 	case SMBBP_BOOST_SUBTYPE:
+		init_data = of_get_regulator_init_data(chip->dev,
+					       spmi_resource->of_node);
+		if (!init_data) {
+			pr_err("unable to allocate memory\n");
+			return -ENOMEM;
+		}
+
+		if (init_data->constraints.name) {
+			if (of_get_property(chip->dev->of_node,
+						"boost-parent-supply", NULL))
+				init_data->supply_regulator = "boost-parent";
+
+			rdesc			= &(chip->boost_vreg.rdesc);
+			rdesc->owner		= THIS_MODULE;
+			rdesc->type		= REGULATOR_VOLTAGE;
+			rdesc->ops		= &qpnp_chg_boost_reg_ops;
+			rdesc->name		= init_data->constraints.name;
+
+			init_data->constraints.valid_ops_mask
+				|= REGULATOR_CHANGE_STATUS
+					| REGULATOR_CHANGE_VOLTAGE;
+
+			chip->boost_vreg.rdev = regulator_register(rdesc,
+					chip->dev, init_data, chip,
+					spmi_resource->of_node);
+			if (IS_ERR(chip->boost_vreg.rdev)) {
+				rc = PTR_ERR(chip->boost_vreg.rdev);
+				chip->boost_vreg.rdev = NULL;
+				if (rc != -EPROBE_DEFER)
+					pr_err("boost reg failed, rc=%d\n", rc);
+				return rc;
+			}
+		}
 		break;
 	case SMBB_MISC_SUBTYPE:
 	case SMBBP_MISC_SUBTYPE:
@@ -2124,7 +2515,8 @@
 	rc = of_property_read_string(chip->spmi->dev.of_node,
 		"qcom,bpd-detection", &bpd);
 	if (rc) {
-		pr_debug("no bpd-detection specified, ignored\n");
+		/* Select BAT_THM as default BPD scheme */
+		chip->bpd_detection = BPD_TYPE_BAT_THM;
 	} else {
 		chip->bpd_detection = get_bpd(bpd);
 		if (chip->bpd_detection < 0) {
@@ -2153,6 +2545,18 @@
 	chip->charging_disabled = of_property_read_bool(chip->spmi->dev.of_node,
 					"qcom,charging-disabled");
 
+	/* Get the duty-cycle-100p property */
+	chip->duty_cycle_100p = of_property_read_bool(
+					chip->spmi->dev.of_node,
+					"qcom,duty-cycle-100p");
+	if (chip->duty_cycle_100p) {
+		rc = qpnp_buck_set_100_duty_cycle_enable(chip, 1);
+		if (rc) {
+			pr_err("failed to enable duty cycle %d\n", rc);
+			return rc;
+		}
+	}
+
 	/* Get the fake-batt-values property */
 	chip->use_default_batt_values =
 			of_property_read_bool(chip->spmi->dev.of_node,
@@ -2302,7 +2706,8 @@
 			chip->usb_chgpth_base = resource->start;
 			rc = qpnp_chg_hwinit(chip, subtype, spmi_resource);
 			if (rc) {
-				pr_err("Failed to init subtype 0x%x rc=%d\n",
+				if (rc != -EPROBE_DEFER)
+					pr_err("Failed to init subtype 0x%x rc=%d\n",
 						subtype, rc);
 				goto fail_chg_enable;
 			}
@@ -2321,7 +2726,8 @@
 			chip->boost_base = resource->start;
 			rc = qpnp_chg_hwinit(chip, subtype, spmi_resource);
 			if (rc) {
-				pr_err("Failed to init subtype 0x%x rc=%d\n",
+				if (rc != -EPROBE_DEFER)
+					pr_err("Failed to init subtype 0x%x rc=%d\n",
 						subtype, rc);
 				goto fail_chg_enable;
 			}
@@ -2457,6 +2863,8 @@
 	if (chip->bat_if_base)
 		power_supply_unregister(&chip->batt_psy);
 fail_chg_enable:
+	regulator_unregister(chip->otg_vreg.rdev);
+	regulator_unregister(chip->boost_vreg.rdev);
 	kfree(chip->thermal_mitigation);
 	kfree(chip);
 	dev_set_drvdata(&spmi->dev, NULL);
@@ -2474,6 +2882,9 @@
 	cancel_work_sync(&chip->adc_measure_work);
 	cancel_delayed_work_sync(&chip->eoc_work);
 
+	regulator_unregister(chip->otg_vreg.rdev);
+	regulator_unregister(chip->boost_vreg.rdev);
+
 	dev_set_drvdata(&spmi->dev, NULL);
 	kfree(chip);
 
diff --git a/drivers/rtc/alarm-dev.c b/drivers/rtc/alarm-dev.c
index bfcaebc..1d60e97 100644
--- a/drivers/rtc/alarm-dev.c
+++ b/drivers/rtc/alarm-dev.c
@@ -98,6 +98,8 @@
 				wake_unlock(&alarm_wake_lock);
 		}
 		alarm_enabled &= ~alarm_type_mask;
+		if (alarm_type == ANDROID_ALARM_RTC_WAKEUP)
+			set_power_on_alarm(0);
 		spin_unlock_irqrestore(&alarm_slock, flags);
 		break;
 
@@ -125,6 +127,10 @@
 		alarm_start_range(&alarms[alarm_type],
 			timespec_to_ktime(new_alarm_time),
 			timespec_to_ktime(new_alarm_time));
+		if ((alarm_type == ANDROID_ALARM_RTC_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);
 		if (ANDROID_ALARM_BASE_CMD(cmd) != ANDROID_ALARM_SET_AND_WAIT(0)
 		    && cmd != ANDROID_ALARM_SET_AND_WAIT_OLD)
diff --git a/drivers/rtc/alarm.c b/drivers/rtc/alarm.c
index 9340af7..e318ecf 100644
--- a/drivers/rtc/alarm.c
+++ b/drivers/rtc/alarm.c
@@ -68,6 +68,13 @@
 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)
+{
+	power_on_alarm = secs;
+}
+
 
 static void update_timer_locked(struct alarm_queue *base, bool head_removed)
 {
@@ -486,6 +493,45 @@
 	return 0;
 }
 
+static void alarm_shutdown(struct platform_device *dev)
+{
+	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;
+
+	spin_lock_irqsave(&alarm_slock, flags);
+
+	if (!power_on_alarm)
+		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;
+	if (alarm_time <= rtc_secs)
+		goto disable_alarm;
+
+	rtc_time_to_tm(alarm_time, &alarm.time);
+	alarm.enabled = 1;
+	rc = rtc_set_alarm(alarm_rtc_dev, &alarm);
+	if (rc)
+		pr_alarm(ERROR, "Unable to set power-on alarm\n");
+	else
+		pr_alarm(FLOW, "Power-on alarm set to %lu\n",
+				alarm_time);
+
+	spin_unlock_irqrestore(&alarm_slock, flags);
+	return;
+
+disable_alarm:
+	rtc_alarm_irq_enable(alarm_rtc_dev, 0);
+	spin_unlock_irqrestore(&alarm_slock, flags);
+}
+
 static struct rtc_task alarm_rtc_task = {
 	.func = alarm_triggered_func
 };
@@ -545,6 +591,7 @@
 static struct platform_driver alarm_driver = {
 	.suspend = alarm_suspend,
 	.resume = alarm_resume,
+	.shutdown = alarm_shutdown,
 	.driver = {
 		.name = "alarm"
 	}
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index c8fdc6b..5f21c7a 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -603,16 +603,11 @@
 	case UTP_CMD_TYPE_SCSI:
 	case UTP_CMD_TYPE_DEV_MANAGE:
 		ufshcd_prepare_req_desc(lrbp, &upiu_flags);
-		if (lrbp->cmd && lrbp->command_type == UTP_CMD_TYPE_SCSI)
+		if (lrbp->command_type == UTP_CMD_TYPE_SCSI)
 			ufshcd_prepare_utp_scsi_cmd_upiu(lrbp, upiu_flags);
-		else if (lrbp->cmd)
+		else
 			ufshcd_prepare_utp_query_req_upiu(hba, lrbp,
 								upiu_flags);
-		else {
-			dev_err(hba->dev, "%s: Invalid UPIU request\n",
-				__func__);
-			ret = -EINVAL;
-		}
 		break;
 	case UTP_CMD_TYPE_UFS:
 		/* For UFS native command implementation */
@@ -725,8 +720,7 @@
 	bool sdev_lookup = true;
 
 	if (!hba || !query || !response) {
-		dev_err(hba->dev,
-			"%s: NULL pointer hba = %p, query = %p response = %p\n",
+		pr_err("%s: NULL pointer hba = %p, query = %p response = %p\n",
 			__func__, hba, query, response);
 		return -EINVAL;
 	}
diff --git a/drivers/spi/spi_qsd.c b/drivers/spi/spi_qsd.c
index c5aa7e5..18dd054 100644
--- a/drivers/spi/spi_qsd.c
+++ b/drivers/spi/spi_qsd.c
@@ -39,11 +39,16 @@
 #include <linux/sched.h>
 #include <linux/mutex.h>
 #include <linux/atomic.h>
+#include <linux/pm_runtime.h>
 #include <mach/msm_spi.h>
 #include <mach/sps.h>
 #include <mach/dma.h>
 #include "spi_qsd.h"
 
+static int msm_spi_pm_resume_runtime(struct device *device);
+static int msm_spi_pm_suspend_runtime(struct device *device);
+
+
 static inline int msm_spi_configure_gsbi(struct msm_spi *dd,
 					struct platform_device *pdev)
 {
@@ -859,6 +864,10 @@
 	u32 op, ret = IRQ_NONE;
 	struct msm_spi *dd = dev_id;
 
+	if (pm_runtime_suspended(dd->dev)) {
+		dev_warn(dd->dev, "QUP: pm runtime suspend, irq:%d\n", irq);
+		return ret;
+	}
 	if (readl_relaxed(dd->base + SPI_ERROR_FLAGS) ||
 	    readl_relaxed(dd->base + QUP_ERROR_FLAGS)) {
 		struct spi_master *master = dev_get_drvdata(dd->dev);
@@ -1705,36 +1714,22 @@
 		container_of(work, struct msm_spi, work_data);
 	unsigned long        flags;
 	u32                  status_error = 0;
-	int                  rc = 0;
+
+	pm_runtime_get_sync(dd->dev);
 
 	mutex_lock(&dd->core_lock);
 
-	/* Don't allow power collapse until we release mutex */
-	if (pm_qos_request_active(&qos_req_list))
-		pm_qos_update_request(&qos_req_list,
-				  dd->pm_lat);
+	/*
+	 * Counter-part of system-suspend when runtime-pm is not enabled.
+	 * This way, resume can be left empty and device will be put in
+	 * active mode only if client requests anything on the bus
+	 */
+	if (!pm_runtime_enabled(dd->dev))
+		msm_spi_pm_resume_runtime(dd->dev);
+
 	if (dd->use_rlock)
 		remote_mutex_lock(&dd->r_lock);
 
-	/* Configure the spi clk, miso, mosi and cs gpio */
-	if (dd->pdata->gpio_config) {
-		rc = dd->pdata->gpio_config();
-		if (rc) {
-			dev_err(dd->dev,
-					"%s: error configuring GPIOs\n",
-					__func__);
-			status_error = 1;
-		}
-	}
-
-	rc = msm_spi_request_gpios(dd);
-	if (rc)
-		status_error = 1;
-
-	clk_prepare_enable(dd->clk);
-	clk_prepare_enable(dd->pclk);
-	msm_spi_enable_irqs(dd);
-
 	if (!msm_spi_is_valid_state(dd)) {
 		dev_err(dd->dev, "%s: SPI operational state not valid\n",
 			__func__);
@@ -1742,6 +1737,7 @@
 	}
 
 	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);
@@ -1758,24 +1754,14 @@
 	dd->transfer_pending = 0;
 	spin_unlock_irqrestore(&dd->queue_lock, flags);
 
-	msm_spi_disable_irqs(dd);
-	clk_disable_unprepare(dd->clk);
-	clk_disable_unprepare(dd->pclk);
-
-	/* Free  the spi clk, miso, mosi, cs gpio */
-	if (!rc && dd->pdata && dd->pdata->gpio_release)
-		dd->pdata->gpio_release();
-	if (!rc)
-		msm_spi_free_gpios(dd);
-
 	if (dd->use_rlock)
 		remote_mutex_unlock(&dd->r_lock);
 
-	if (pm_qos_request_active(&qos_req_list))
-		pm_qos_update_request(&qos_req_list,
-				  PM_QOS_DEFAULT_VALUE);
-
 	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 (dd->suspended)
@@ -1789,8 +1775,6 @@
 	struct spi_transfer *tr;
 
 	dd = spi_master_get_devdata(spi->master);
-	if (dd->suspended)
-		return -EBUSY;
 
 	if (list_empty(&msg->transfers) || !msg->complete)
 		return -EINVAL;
@@ -1810,11 +1794,6 @@
 	}
 
 	spin_lock_irqsave(&dd->queue_lock, flags);
-	if (dd->suspended) {
-		spin_unlock_irqrestore(&dd->queue_lock, flags);
-		return -EBUSY;
-	}
-	dd->transfer_pending = 1;
 	list_add_tail(&msg->queue, &dd->queue);
 	spin_unlock_irqrestore(&dd->queue_lock, flags);
 	queue_work(dd->workqueue, &dd->work_data);
@@ -1845,7 +1824,14 @@
 
 	dd = spi_master_get_devdata(spi->master);
 
+	pm_runtime_get_sync(dd->dev);
+
 	mutex_lock(&dd->core_lock);
+
+	/* Counter-part of system-suspend when runtime-pm is not enabled. */
+	if (!pm_runtime_enabled(dd->dev))
+		msm_spi_pm_resume_runtime(dd->dev);
+
 	if (dd->suspended) {
 		mutex_unlock(&dd->core_lock);
 		return -EBUSY;
@@ -1854,27 +1840,6 @@
 	if (dd->use_rlock)
 		remote_mutex_lock(&dd->r_lock);
 
-	/* Configure the spi clk, miso, mosi, cs gpio */
-	if (dd->pdata->gpio_config) {
-		rc = dd->pdata->gpio_config();
-		if (rc) {
-			dev_err(&spi->dev,
-					"%s: error configuring GPIOs\n",
-					__func__);
-			rc = -ENXIO;
-			goto err_setup_gpio;
-		}
-	}
-
-	rc = msm_spi_request_gpios(dd);
-	if (rc) {
-		rc = -ENXIO;
-		goto err_setup_gpio;
-	}
-
-	clk_prepare_enable(dd->clk);
-	clk_prepare_enable(dd->pclk);
-
 	spi_ioc = readl_relaxed(dd->base + SPI_IO_CONTROL);
 	mask = SPI_IO_C_CS_N_POLARITY_0 << spi->chip_select;
 	if (spi->mode & SPI_CS_HIGH)
@@ -1892,18 +1857,19 @@
 
 	/* Ensure previous write completed before disabling the clocks */
 	mb();
-	clk_disable_unprepare(dd->clk);
-	clk_disable_unprepare(dd->pclk);
 
-	/* Free  the spi clk, miso, mosi, cs gpio */
-	if (dd->pdata && dd->pdata->gpio_release)
-		dd->pdata->gpio_release();
-	msm_spi_free_gpios(dd);
-
-err_setup_gpio:
 	if (dd->use_rlock)
 		remote_mutex_unlock(&dd->r_lock);
+
+	/* Counter-part of system-resume when runtime-pm is not enabled. */
+	if (!pm_runtime_enabled(dd->dev))
+		msm_spi_pm_suspend_runtime(dd->dev);
+
 	mutex_unlock(&dd->core_lock);
+
+	pm_runtime_mark_last_busy(dd->dev);
+	pm_runtime_put_autosuspend(dd->dev);
+
 err_setup_exit:
 	return rc;
 }
@@ -2729,7 +2695,7 @@
 	clk_enabled = 0;
 	pclk_enabled = 0;
 
-	dd->suspended = 0;
+	dd->suspended = 1;
 	dd->transfer_pending = 0;
 	dd->multi_xfr = 0;
 	dd->mode = SPI_MODE_NONE;
@@ -2745,6 +2711,10 @@
 	mutex_unlock(&dd->core_lock);
 	locked = 0;
 
+	pm_runtime_set_autosuspend_delay(&pdev->dev, MSEC_PER_SEC);
+	pm_runtime_use_autosuspend(&pdev->dev);
+	pm_runtime_enable(&pdev->dev);
+
 	rc = spi_register_master(master);
 	if (rc)
 		goto err_probe_reg_master;
@@ -2762,6 +2732,7 @@
 err_attrs:
 	spi_unregister_master(master);
 err_probe_reg_master:
+	pm_runtime_disable(&pdev->dev);
 err_probe_irq:
 err_probe_state:
 	if (dd->dma_teardown)
@@ -2795,48 +2766,130 @@
 }
 
 #ifdef CONFIG_PM
-static int msm_spi_suspend(struct platform_device *pdev, pm_message_t state)
+static int msm_spi_pm_suspend_runtime(struct device *device)
 {
+	struct platform_device *pdev = to_platform_device(device);
 	struct spi_master *master = platform_get_drvdata(pdev);
-	struct msm_spi    *dd;
-	unsigned long      flags;
+	struct msm_spi	  *dd;
+	unsigned long	   flags;
 
+	dev_dbg(device, "pm_runtime: suspending...\n");
 	if (!master)
 		goto suspend_exit;
 	dd = spi_master_get_devdata(master);
 	if (!dd)
 		goto suspend_exit;
 
-	/* Make sure nothing is added to the queue while we're suspending */
+	if (dd->suspended)
+		return 0;
+
+	/*
+	 * Make sure nothing is added to the queue while we're
+	 * suspending
+	 */
 	spin_lock_irqsave(&dd->queue_lock, flags);
 	dd->suspended = 1;
 	spin_unlock_irqrestore(&dd->queue_lock, flags);
 
 	/* Wait for transactions to end, or time out */
-	wait_event_interruptible(dd->continue_suspend, !dd->transfer_pending);
+	wait_event_interruptible(dd->continue_suspend,
+		!dd->transfer_pending);
 
+	msm_spi_disable_irqs(dd);
+	clk_disable_unprepare(dd->clk);
+	clk_disable_unprepare(dd->pclk);
+
+	/* Free  the spi clk, miso, mosi, cs gpio */
+	if (dd->pdata && dd->pdata->gpio_release)
+		dd->pdata->gpio_release();
+
+	msm_spi_free_gpios(dd);
+
+	if (pm_qos_request_active(&qos_req_list))
+		pm_qos_update_request(&qos_req_list,
+				PM_QOS_DEFAULT_VALUE);
 suspend_exit:
 	return 0;
 }
 
-static int msm_spi_resume(struct platform_device *pdev)
+static int msm_spi_pm_resume_runtime(struct device *device)
 {
+	struct platform_device *pdev = to_platform_device(device);
 	struct spi_master *master = platform_get_drvdata(pdev);
-	struct msm_spi    *dd;
+	struct msm_spi	  *dd;
+	int ret = 0;
 
+	dev_dbg(device, "pm_runtime: resuming...\n");
 	if (!master)
 		goto resume_exit;
 	dd = spi_master_get_devdata(master);
 	if (!dd)
 		goto resume_exit;
 
+	if (!dd->suspended)
+		return 0;
+
+	if (pm_qos_request_active(&qos_req_list))
+		pm_qos_update_request(&qos_req_list,
+				  dd->pm_lat);
+
+	/* Configure the spi clk, miso, mosi and cs gpio */
+	if (dd->pdata->gpio_config) {
+		ret = dd->pdata->gpio_config();
+		if (ret) {
+			dev_err(dd->dev,
+					"%s: error configuring GPIOs\n",
+					__func__);
+			return ret;
+		}
+	}
+
+	ret = msm_spi_request_gpios(dd);
+	if (ret)
+		return ret;
+
+	clk_prepare_enable(dd->clk);
+	clk_prepare_enable(dd->pclk);
+	msm_spi_enable_irqs(dd);
 	dd->suspended = 0;
 resume_exit:
 	return 0;
 }
+
+static int msm_spi_suspend(struct device *device)
+{
+	if (!pm_runtime_enabled(device) || !pm_runtime_suspended(device)) {
+		struct platform_device *pdev = to_platform_device(device);
+		struct spi_master *master = platform_get_drvdata(pdev);
+		struct msm_spi   *dd;
+
+		dev_dbg(device, "system suspend");
+		if (!master)
+			goto suspend_exit;
+		dd = spi_master_get_devdata(master);
+		if (!dd)
+			goto suspend_exit;
+		msm_spi_pm_suspend_runtime(device);
+	}
+suspend_exit:
+	return 0;
+}
+
+static int msm_spi_resume(struct device *device)
+{
+	/*
+	 * Rely on runtime-PM to call resume in case it is enabled
+	 * Even if it's not enabled, rely on 1st client transaction to do
+	 * clock ON and gpio configuration
+	 */
+	dev_dbg(device, "system resume");
+	return 0;
+}
 #else
 #define msm_spi_suspend NULL
 #define msm_spi_resume NULL
+#define msm_spi_pm_suspend_runtime NULL
+#define msm_spi_pm_resume_runtime NULL
 #endif /* CONFIG_PM */
 
 static int __devexit msm_spi_remove(struct platform_device *pdev)
@@ -2850,6 +2903,8 @@
 
 	if (dd->dma_teardown)
 		dd->dma_teardown(dd);
+	pm_runtime_disable(&pdev->dev);
+	pm_runtime_set_suspended(&pdev->dev);
 	clk_put(dd->clk);
 	clk_put(dd->pclk);
 	destroy_workqueue(dd->workqueue);
@@ -2867,14 +2922,19 @@
 	{}
 };
 
+static const struct dev_pm_ops msm_spi_dev_pm_ops = {
+	SET_SYSTEM_SLEEP_PM_OPS(msm_spi_suspend, msm_spi_resume)
+	SET_RUNTIME_PM_OPS(msm_spi_pm_suspend_runtime,
+			msm_spi_pm_resume_runtime, NULL)
+};
+
 static struct platform_driver msm_spi_driver = {
 	.driver		= {
 		.name	= SPI_DRV_NAME,
 		.owner	= THIS_MODULE,
+		.pm		= &msm_spi_dev_pm_ops,
 		.of_match_table = msm_spi_dt_match,
 	},
-	.suspend        = msm_spi_suspend,
-	.resume         = msm_spi_resume,
 	.remove		= __exit_p(msm_spi_remove),
 };
 
diff --git a/drivers/spmi/spmi.c b/drivers/spmi/spmi.c
index 49a27c7..f5c9d2f 100644
--- a/drivers/spmi/spmi.c
+++ b/drivers/spmi/spmi.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
@@ -31,7 +31,6 @@
 
 static DEFINE_MUTEX(board_lock);
 static LIST_HEAD(board_list);
-static LIST_HEAD(spmi_ctrl_list);
 static DEFINE_IDR(ctrl_idr);
 static struct device_type spmi_ctrl_type = { 0 };
 
@@ -51,14 +50,10 @@
 	struct spmi_controller *ctrl;
 
 	mutex_lock(&board_lock);
-	list_for_each_entry(ctrl, &spmi_ctrl_list, list) {
-		if (bus_num == ctrl->nr) {
-			mutex_unlock(&board_lock);
-			return ctrl;
-		}
-	}
+	ctrl = idr_find(&ctrl_idr, bus_num);
 	mutex_unlock(&board_lock);
-	return NULL;
+
+	return ctrl;
 }
 EXPORT_SYMBOL_GPL(spmi_busnum_to_ctrl);
 
@@ -90,7 +85,7 @@
 	mutex_lock(&board_lock);
 	status = idr_get_new_above(&ctrl_idr, ctrl, ctrl->nr, &id);
 	if (status == 0 && id != ctrl->nr) {
-		status = -EAGAIN;
+		status = -EBUSY;
 		idr_remove(&ctrl_idr, id);
 	}
 	mutex_unlock(&board_lock);
@@ -259,7 +254,6 @@
 }
 EXPORT_SYMBOL_GPL(spmi_remove_device);
 
-/* If controller is not present, only add to boards list */
 static void spmi_match_ctrl_to_boardinfo(struct spmi_controller *ctrl,
 				struct spmi_boardinfo *bi)
 {
@@ -278,27 +272,29 @@
  * @n: number of entries.
  * API enumerates respective devices on corresponding controller.
  * Called from board-init function.
+ * If controller is not present, only add to boards list
  */
 int spmi_register_board_info(int busnum,
 			struct spmi_boardinfo const *info, unsigned n)
 {
 	int i;
 	struct spmii_boardinfo *bi;
+	struct spmi_controller *ctrl;
 
 	bi = kzalloc(n * sizeof(*bi), GFP_KERNEL);
 	if (!bi)
 		return -ENOMEM;
 
+	ctrl = spmi_busnum_to_ctrl(busnum);
+
 	for (i = 0; i < n; i++, bi++, info++) {
-		struct spmi_controller *ctrl;
 
 		memcpy(&bi->board_info, info, sizeof(*info));
 		mutex_lock(&board_lock);
 		list_add_tail(&bi->list, &board_list);
-		list_for_each_entry(ctrl, &spmi_ctrl_list, list)
-			if (ctrl->nr == busnum)
-				spmi_match_ctrl_to_boardinfo(ctrl,
-							&bi->board_info);
+
+		if (ctrl)
+			spmi_match_ctrl_to_boardinfo(ctrl, &bi->board_info);
 		mutex_unlock(&board_lock);
 	}
 	return 0;
@@ -753,10 +749,6 @@
 	dev_dbg(&ctrl->dev, "Bus spmi-%d registered: dev:%x\n",
 					ctrl->nr, (u32)&ctrl->dev);
 
-	mutex_lock(&board_lock);
-	list_add_tail(&ctrl->list, &spmi_ctrl_list);
-	mutex_unlock(&board_lock);
-
 	spmi_dfs_add_controller(ctrl);
 	return 0;
 
diff --git a/drivers/staging/android/logger.c b/drivers/staging/android/logger.c
index eb3d4ca..e1e886c 100644
--- a/drivers/staging/android/logger.c
+++ b/drivers/staging/android/logger.c
@@ -728,10 +728,10 @@
 	.size = SIZE, \
 };
 
-DEFINE_LOGGER_DEVICE(log_main, LOGGER_LOG_MAIN, 256*1024)
-DEFINE_LOGGER_DEVICE(log_events, LOGGER_LOG_EVENTS, 256*1024)
-DEFINE_LOGGER_DEVICE(log_radio, LOGGER_LOG_RADIO, 256*1024)
-DEFINE_LOGGER_DEVICE(log_system, LOGGER_LOG_SYSTEM, 256*1024)
+DEFINE_LOGGER_DEVICE(log_main, LOGGER_LOG_MAIN, 64*1024)
+DEFINE_LOGGER_DEVICE(log_events, LOGGER_LOG_EVENTS, 64*1024)
+DEFINE_LOGGER_DEVICE(log_radio, LOGGER_LOG_RADIO, 64*1024)
+DEFINE_LOGGER_DEVICE(log_system, LOGGER_LOG_SYSTEM, 64*1024)
 
 static struct logger_log *get_log_from_minor(int minor)
 {
diff --git a/drivers/thermal/msm8974-tsens.c b/drivers/thermal/msm8974-tsens.c
index f01a078..52608af 100644
--- a/drivers/thermal/msm8974-tsens.c
+++ b/drivers/thermal/msm8974-tsens.c
@@ -17,6 +17,7 @@
 #include <linux/platform_device.h>
 #include <linux/thermal.h>
 #include <linux/interrupt.h>
+#include <linux/workqueue.h>
 #include <linux/delay.h>
 #include <linux/kernel.h>
 #include <linux/io.h>
@@ -258,6 +259,7 @@
 
 struct tsens_tm_device {
 	struct platform_device		*pdev;
+	struct workqueue_struct		*tsens_wq;
 	bool				prev_reading_avail;
 	bool				calibration_less_mode;
 	bool				tsens_local_init;
@@ -655,7 +657,7 @@
 		}
 		if (upper_thr || lower_thr) {
 			/* Notify user space */
-			schedule_work(&tm->sensor[i].work);
+			queue_work(tm->tsens_wq, &tm->sensor[i].work);
 			rc = tsens_get_sw_id_mapping(
 					tm->sensor[i].sensor_hw_num,
 					&sensor_sw_id);
@@ -673,7 +675,7 @@
 
 static irqreturn_t tsens_isr(int irq, void *data)
 {
-	schedule_work(&tmdev->tsens_work);
+	queue_work(tmdev->tsens_wq, &tmdev->tsens_work);
 
 	return IRQ_HANDLED;
 }
@@ -1506,6 +1508,12 @@
 		return -ENODEV;
 
 	tmdev->pdev = pdev;
+	tmdev->tsens_wq = alloc_workqueue("tsens_wq", WQ_HIGHPRI, 0);
+	if (!tmdev->tsens_wq) {
+		rc = -ENOMEM;
+		goto fail;
+	}
+
 	rc = tsens_calib_sensors();
 	if (rc < 0) {
 		pr_err("Calibration failed\n");
@@ -1520,6 +1528,8 @@
 
 	return 0;
 fail:
+	if (tmdev->tsens_wq)
+		destroy_workqueue(tmdev->tsens_wq);
 	if (tmdev->tsens_calib_addr)
 		iounmap(tmdev->tsens_calib_addr);
 	if (tmdev->res_calib_mem)
@@ -1610,6 +1620,7 @@
 		release_mem_region(tmdev->res_tsens_mem->start,
 			tmdev->tsens_len);
 	free_irq(tmdev->tsens_irq, tmdev);
+	destroy_workqueue(tmdev->tsens_wq);
 	platform_set_drvdata(pdev, NULL);
 
 	return 0;
diff --git a/drivers/thermal/msm_thermal.c b/drivers/thermal/msm_thermal.c
index 814817b..51a11a4 100644
--- a/drivers/thermal/msm_thermal.c
+++ b/drivers/thermal/msm_thermal.c
@@ -596,7 +596,14 @@
 		pr_info("%s: Max frequency reset for cpu%d\n",
 				KBUILD_MODNAME, cpu);
 
-	ret = cpufreq_update_policy(cpu);
+	if (cpu_online(cpu)) {
+		struct cpufreq_policy *policy = cpufreq_cpu_get(cpu);
+		if (!policy)
+			return ret;
+		ret = cpufreq_driver_target(policy, policy->cur,
+				CPUFREQ_RELATION_H);
+		cpufreq_cpu_put(policy);
+	}
 
 	return ret;
 }
@@ -748,14 +755,56 @@
 	return ret;
 }
 
+static void __cpuinit do_freq_control(long temp)
+{
+	int ret = 0;
+	int cpu = 0;
+	uint32_t max_freq = limited_max_freq;
+
+	if (temp >= msm_thermal_info.limit_temp_degC) {
+		if (limit_idx == limit_idx_low)
+			return;
+
+		limit_idx -= msm_thermal_info.freq_step;
+		if (limit_idx < limit_idx_low)
+			limit_idx = limit_idx_low;
+		max_freq = table[limit_idx].frequency;
+	} else if (temp < msm_thermal_info.limit_temp_degC -
+		 msm_thermal_info.temp_hysteresis_degC) {
+		if (limit_idx == limit_idx_high)
+			return;
+
+		limit_idx += msm_thermal_info.freq_step;
+		if (limit_idx >= limit_idx_high) {
+			limit_idx = limit_idx_high;
+			max_freq = MSM_CPUFREQ_NO_LIMIT;
+		} else
+			max_freq = table[limit_idx].frequency;
+	}
+
+	if (max_freq == limited_max_freq)
+		return;
+
+	/* Update new limits */
+	for_each_possible_cpu(cpu) {
+		if (!(msm_thermal_info.freq_control_mask & BIT(cpu)))
+			continue;
+		ret = update_cpu_max_freq(cpu, max_freq);
+		if (ret)
+			pr_debug(
+			"%s: Unable to limit cpu%d max freq to %d\n",
+					KBUILD_MODNAME, cpu, max_freq);
+	}
+
+}
+
 static void __cpuinit check_temp(struct work_struct *work)
 {
 	static int limit_init;
 	struct tsens_device tsens_dev;
 	long temp = 0;
-	uint32_t max_freq = limited_max_freq;
-	int cpu = 0;
 	int ret = 0;
+
 	tsens_dev.sensor_num = msm_thermal_info.sensor_id;
 	ret = tsens_get_temp(&tsens_dev, &temp);
 	if (ret) {
@@ -775,38 +824,7 @@
 	do_core_control(temp);
 	do_vdd_restriction();
 	do_psm();
-
-	if (temp >= msm_thermal_info.limit_temp_degC) {
-		if (limit_idx == limit_idx_low)
-			goto reschedule;
-
-		limit_idx -= msm_thermal_info.freq_step;
-		if (limit_idx < limit_idx_low)
-			limit_idx = limit_idx_low;
-		max_freq = table[limit_idx].frequency;
-	} else if (temp < msm_thermal_info.limit_temp_degC -
-		 msm_thermal_info.temp_hysteresis_degC) {
-		if (limit_idx == limit_idx_high)
-			goto reschedule;
-
-		limit_idx += msm_thermal_info.freq_step;
-		if (limit_idx >= limit_idx_high) {
-			limit_idx = limit_idx_high;
-			max_freq = MSM_CPUFREQ_NO_LIMIT;
-		} else
-			max_freq = table[limit_idx].frequency;
-	}
-	if (max_freq == limited_max_freq)
-		goto reschedule;
-
-	/* Update new limits */
-	for_each_possible_cpu(cpu) {
-		ret = update_cpu_max_freq(cpu, max_freq);
-		if (ret)
-			pr_debug(
-			"%s: Unable to limit cpu%d max freq to %d\n",
-					KBUILD_MODNAME, cpu, max_freq);
-	}
+	do_freq_control(temp);
 
 reschedule:
 	if (enabled)
@@ -1417,6 +1435,8 @@
 	char *key = NULL;
 	struct device_node *child_node = NULL;
 
+	rails = NULL;
+
 	key = "qcom,vdd-restriction-temp";
 	ret = of_property_read_u32(node, key, &data->vdd_rstr_temp_degC);
 	if (ret)
@@ -1513,6 +1533,8 @@
 	int j = 0;
 	char *key = NULL;
 
+	psm_rails = NULL;
+
 	key = "qcom,pmic-sw-mode-temp";
 	ret = of_property_read_u32(node, key, &data->psm_temp_degC);
 	if (ret)
@@ -1599,6 +1621,9 @@
 	if (ret)
 		goto fail;
 
+	key = "qcom,freq-control-mask";
+	ret = of_property_read_u32(node, key, &data.freq_control_mask);
+
 	key = "qcom,core-limit-temp";
 	ret = of_property_read_u32(node, key, &data.core_limit_temp_degC);
 
diff --git a/drivers/tty/n_smux.c b/drivers/tty/n_smux.c
index 8760603..d1545dc 100644
--- a/drivers/tty/n_smux.c
+++ b/drivers/tty/n_smux.c
@@ -1,6 +1,6 @@
 /* drivers/tty/n_smux.c
  *
- * Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
@@ -259,6 +259,8 @@
 	unsigned powerdown_enabled;
 	unsigned power_ctl_remote_req_received;
 	struct list_head power_queue;
+	unsigned remote_initiated_wakeup_count;
+	unsigned local_initiated_wakeup_count;
 };
 
 
@@ -279,6 +281,7 @@
 	[SMUX_CMD_CLOSE_LCH] = "CLOSE",
 	[SMUX_CMD_STATUS] = "STATUS",
 	[SMUX_CMD_PWR_CTL] = "PWR",
+	[SMUX_CMD_DELAY] = "DELAY",
 	[SMUX_CMD_BYTE] = "Raw Byte",
 };
 
@@ -1908,6 +1911,7 @@
 		/* wakeup system */
 		SMUX_PWR("smux: %s: Power %d->%d\n", __func__,
 				smux.power_state, SMUX_PWR_ON);
+		smux.remote_initiated_wakeup_count++;
 		smux.power_state = SMUX_PWR_ON;
 		queue_work(smux_tx_wq, &smux_wakeup_work);
 		queue_work(smux_tx_wq, &smux_tx_work);
@@ -2163,6 +2167,62 @@
 }
 
 /**
+ * Sends a delay command to the remote side.
+ *
+ * @ms: Time in milliseconds for the remote side to delay
+ *
+ * This command defines the delay that the remote side will use
+ * to slow the response time for DATA commands.
+ */
+void smux_set_loopback_data_reply_delay(uint32_t ms)
+{
+	struct smux_lch_t *ch = &smux_lch[SMUX_TEST_LCID];
+	struct smux_pkt_t *pkt;
+
+	pkt = smux_alloc_pkt();
+	if (!pkt) {
+		pr_err("%s: unable to allocate packet\n", __func__);
+		return;
+	}
+
+	pkt->hdr.lcid = ch->lcid;
+	pkt->hdr.cmd = SMUX_CMD_DELAY;
+	pkt->hdr.flags = 0;
+	pkt->hdr.payload_len = sizeof(uint32_t);
+	pkt->hdr.pad_len = 0;
+
+	if (smux_alloc_pkt_payload(pkt)) {
+		pr_err("%s: unable to allocate payload\n", __func__);
+		smux_free_pkt(pkt);
+		return;
+	}
+	memcpy(pkt->payload, &ms, sizeof(uint32_t));
+
+	smux_tx_queue(pkt, ch, 1);
+}
+
+/**
+ * Retrieve wakeup counts.
+ *
+ * @local_cnt: Pointer to local wakeup count
+ * @remote_cnt: Pointer to remote wakeup count
+ */
+void smux_get_wakeup_counts(int *local_cnt, int *remote_cnt)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&smux.tx_lock_lha2, flags);
+
+	if (local_cnt)
+		*local_cnt = smux.local_initiated_wakeup_count;
+
+	if (remote_cnt)
+		*remote_cnt = smux.remote_initiated_wakeup_count;
+
+	spin_unlock_irqrestore(&smux.tx_lock_lha2, flags);
+}
+
+/**
  * Add channel to transmit-ready list and trigger transmit worker.
  *
  * @ch Channel to add
@@ -2744,6 +2804,7 @@
 				SMUX_PWR("smux: %s: Power %d->%d\n", __func__,
 						smux.power_state,
 						SMUX_PWR_TURNING_ON);
+				smux.local_initiated_wakeup_count++;
 				smux.power_state = SMUX_PWR_TURNING_ON;
 				spin_unlock_irqrestore(&smux.tx_lock_lha2,
 						flags);
diff --git a/drivers/tty/serial/msm_serial_hs.c b/drivers/tty/serial/msm_serial_hs.c
index 890a897..4d464c1 100644
--- a/drivers/tty/serial/msm_serial_hs.c
+++ b/drivers/tty/serial/msm_serial_hs.c
@@ -1974,7 +1974,8 @@
 	switch (msm_uport->clk_state) {
 	case MSM_HS_CLK_OFF:
 		wake_lock(&msm_uport->dma_wake_lock);
-		disable_irq_nosync(msm_uport->wakeup.irq);
+		if (use_low_power_wakeup(msm_uport))
+			disable_irq_nosync(msm_uport->wakeup.irq);
 		spin_unlock_irqrestore(&uport->lock, flags);
 
 		/* Vote for PNOC BUS Scaling */
@@ -2348,7 +2349,8 @@
 free_uart_irq:
 	free_irq(uport->irq, msm_uport);
 free_wake_irq:
-	irq_set_irq_wake(msm_uport->wakeup.irq, 0);
+	if (use_low_power_wakeup(msm_uport))
+		irq_set_irq_wake(msm_uport->wakeup.irq, 0);
 sps_disconnect_rx:
 	if (is_blsp_uart(msm_uport))
 		sps_disconnect(sps_pipe_handle_rx);
diff --git a/drivers/tty/smux_private.h b/drivers/tty/smux_private.h
index 8fdec86..b9a2e89 100644
--- a/drivers/tty/smux_private.h
+++ b/drivers/tty/smux_private.h
@@ -1,6 +1,6 @@
 /* drivers/tty/smux_private.h
  *
- * Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
@@ -122,6 +122,7 @@
 	SMUX_CMD_CLOSE_LCH = 0x2,
 	SMUX_CMD_STATUS = 0x3,
 	SMUX_CMD_PWR_CTL = 0x4,
+	SMUX_CMD_DELAY = 0x5,
 
 	SMUX_CMD_BYTE, /* for internal usage */
 	SMUX_NUM_COMMANDS
@@ -181,6 +182,8 @@
 void smuxld_receive_buf(struct tty_struct *tty, const unsigned char *cp,
 			   char *fp, int count);
 bool smux_remote_is_active(void);
+void smux_set_loopback_data_reply_delay(uint32_t ms);
+void smux_get_wakeup_counts(int *local_cnt, int *remote_cnt);
 
 /* testing parameters */
 extern int smux_byte_loopback;
diff --git a/drivers/tty/smux_test.c b/drivers/tty/smux_test.c
index e1d9975..8d17674 100644
--- a/drivers/tty/smux_test.c
+++ b/drivers/tty/smux_test.c
@@ -1,6 +1,6 @@
 /* drivers/tty/smux_test.c
  *
- * Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
@@ -20,11 +20,17 @@
 #include <linux/delay.h>
 #include <linux/completion.h>
 #include <linux/termios.h>
+#include <linux/sched.h>
 #include <linux/smux.h>
 #include <mach/subsystem_restart.h>
 #include "smux_private.h"
 
 #define DEBUG_BUFMAX 4096
+#define RED_ZONE_SIZE	16
+#define RED_ZONE_PRE_CH	0xAB
+#define RED_ZONE_POS_CH	0xBA
+#define SMUX_REMOTE_INACTIVITY_TIME_MS	50
+#define SMUX_REMOTE_DELAY_TIME_MS		250
 
 /**
  * Unit test assertion for logging test cases.
@@ -138,7 +144,7 @@
 /**
  * Allocates a new buffer for SMUX for every call.
  */
-int get_rx_buffer(void *priv, void **pkt_priv, void **buffer, int size)
+static int get_rx_buffer(void *priv, void **pkt_priv, void **buffer, int size)
 {
 	void *rx_buf;
 
@@ -216,7 +222,7 @@
  *
  * @cb  Mock callback data
  */
-void mock_cb_data_init(struct smux_mock_callback *cb)
+static void mock_cb_data_init(struct smux_mock_callback *cb)
 {
 	init_completion(&cb->cb_completion);
 	spin_lock_init(&cb->lock);
@@ -232,7 +238,7 @@
  *
  * All packets are freed and counters reset to zero.
  */
-void mock_cb_data_reset(struct smux_mock_callback *cb)
+static void mock_cb_data_reset(struct smux_mock_callback *cb)
 {
 	cb->cb_count = 0;
 	INIT_COMPLETION(cb->cb_completion);
@@ -341,7 +347,7 @@
  * Mock object event callback.  Used to logs events for analysis in the unit
  * tests.
  */
-void smux_mock_cb(void *priv, int event, const void *metadata)
+static void smux_mock_cb(void *priv, int event, const void *metadata)
 {
 	struct smux_mock_callback *cb_data_ptr;
 	struct mock_write_event *write_event_meta;
@@ -518,12 +524,17 @@
 		for (; vectors->data != NULL; ++vectors) {
 			const char *test_data = vectors->data;
 			const unsigned test_len = vectors->len;
+			unsigned long long start_t;
+			unsigned long long end_t;
+			unsigned long long val;
+			unsigned long rem;
 
 			i += scnprintf(buf + i, max - i,
-					"Writing vector %p len %d\n",
+					"Writing vector %p len %d: ",
 					test_data, test_len);
 
 			/* write data */
+			start_t = sched_clock();
 			msm_smux_write(SMUX_TEST_LCID, (void *)0xCAFEFACE,
 					test_data, test_len);
 			UT_ASSERT_INT(ret, ==, 0);
@@ -538,6 +549,7 @@
 					(int)wait_for_completion_timeout(
 						&cb_data.cb_completion, HZ),
 					>, 0);
+			end_t = sched_clock();
 
 			UT_ASSERT_INT(cb_data.cb_count, >=, 1);
 			UT_ASSERT_INT(cb_data.event_write_done, ==, 1);
@@ -569,16 +581,28 @@
 				hex_dump_to_buffer(test_data, test_len,
 					16, 1, linebuff, sizeof(linebuff), 1);
 				i += scnprintf(buf + i, max - i,
-						"Expected:\n%s\n\n", linebuff);
+					"Failed\nExpected:\n%s\n\n", linebuff);
 
 				hex_dump_to_buffer(read_event->meta.buffer,
 					read_event->meta.len,
 					16, 1, linebuff, sizeof(linebuff), 1);
 				i += scnprintf(buf + i, max - i,
-						"Actual:\n%s\n", linebuff);
+					"Failed\nActual:\n%s\n", linebuff);
 				failed = 1;
 				break;
 			}
+
+			/* calculate throughput stats */
+			val = end_t - start_t;
+			rem = do_div(val, 1000);
+			i += scnprintf(buf + i, max - i,
+				"OK - %u us",
+				(unsigned int)val);
+
+			val = 1000000000LL * 2 * test_len;
+			rem = do_div(val, end_t - start_t);
+			i += scnprintf(buf + i, max - i,
+				" (%u kB/sec)\n", (unsigned int)val);
 			mock_cb_data_reset(&cb_data);
 		}
 
@@ -682,7 +706,7 @@
  * Run a basic loopback test followed by a subsystem restart and then another
  * loopback test.
  */
-static int smux_ut_remote_ssr_basic(char *buf, int max)
+static int smux_ut_ssr_remote_basic(char *buf, int max)
 {
 	const struct test_vector test_data[] = {
 		{"hello\0world\n", sizeof("hello\0world\n")},
@@ -723,7 +747,7 @@
 /**
  * Verify Subsystem Restart Support During Port Open
  */
-static int smux_ut_remote_ssr_open(char *buf, int max)
+static int smux_ut_ssr_remote_open(char *buf, int max)
 {
 	static struct smux_mock_callback cb_data;
 	static int cb_initialized;
@@ -805,7 +829,7 @@
  *
  * @returns Number of bytes written to @buf
  */
-static int smux_ut_remote_ssr_rx_buff_retry(char *buf, int max)
+static int smux_ut_ssr_remote_rx_buff_retry(char *buf, int max)
 {
 	static struct smux_mock_callback cb_data;
 	static int cb_initialized;
@@ -897,9 +921,10 @@
 	mock_cb_data_reset(&cb_data);
 	return i;
 }
+
 /**
  * Fill test pattern into provided buffer including an optional
- * redzone 16 bytes before and 16 bytes after the buffer.
+ * redzone before and after the buffer.
  *
  * buf ---------
  *      redzone
@@ -909,70 +934,75 @@
  *      redzone
  *     ---------
  *
- * @buf  Pointer to the buffer of size len or len+32 (redzone)
- * @len  Length of the *data* buffer (excluding 32-byte redzone)
+ * @buf  Pointer to the buffer of size len or len+2*RED_ZONE_SIZE (redzone)
+ * @len  Length of the *data* buffer (excluding the extra redzone buffers)
  * @redzone If true, adds redzone data
  *
- * @returns pointer to buffer (buf + 16 if redzone enabled)
+ * @returns pointer to buffer (buf + RED_ZONE_SIZE if redzone enabled)
  */
-uint8_t *test_pattern_fill(char *buf, int len, int redzone)
+static uint8_t *test_pattern_fill(char *buf, int len, int redzone)
 {
-	void *ret;
+	char *buf_ptr;
 	uint8_t ch;
 
-	ret = buf;
 	if (redzone) {
-		memset((char *)buf, 0xAB, 16);
-		memset((char *)buf + len, 0xBA, 16);
-		ret += 16;
+		memset(buf, RED_ZONE_PRE_CH, RED_ZONE_SIZE);
+		buf += RED_ZONE_SIZE;
+		memset(buf + len, RED_ZONE_POS_CH, RED_ZONE_SIZE);
 	}
 
-	/* fill with test pattern */
-	for (ch = 0; len > 0; --len, ++ch)
-		*buf++ = (char)ch;
+	for (ch = 0, buf_ptr = buf; len > 0; --len, ++ch)
+		*buf_ptr++ = (char)ch;
 
-	return ret;
+	return buf;
 }
 
 /**
  * Verify test pattern generated by test_pattern_fill.
  *
  * @buf_ptr    Pointer to buffer pointer
- * @len        Length of the *data* buffer (excluding 32-byte redzone)
+ * @len        Length of the *data* buffer (excluding redzone bytes)
  * @redzone    If true, verifies redzone and adjusts *buf_ptr
  * @errmsg     Buffer for error message
  * @errmsg_max Size of error message buffer
  *
  * @returns    0 for success; length of error message otherwise
  */
-unsigned test_pattern_verify(char **buf_ptr, int len, int redzone,
+static unsigned test_pattern_verify(char **buf_ptr, int len, int redzone,
 					char *errmsg, int errmsg_max)
 {
 	int n;
 	int i = 0;
 	char linebuff[80];
+	char *zone_ptr;
 
 	if (redzone) {
-		*buf_ptr -= 16;
+		*buf_ptr -= RED_ZONE_SIZE;
+		zone_ptr = *buf_ptr;
 
 		/* verify prefix redzone */
-		for (n = 0; n < 16; ++n) {
-			if (*buf_ptr[n] != 0xAB) {
-				hex_dump_to_buffer(*buf_ptr, 16,
-					16, 1, linebuff, sizeof(linebuff), 1);
+		for (n = 0; n < RED_ZONE_SIZE; ++n) {
+			if (zone_ptr[n] != RED_ZONE_PRE_CH) {
+				hex_dump_to_buffer(zone_ptr, RED_ZONE_SIZE,
+					RED_ZONE_SIZE, 1, linebuff,
+					sizeof(linebuff), 1);
 				i += scnprintf(errmsg + i, errmsg_max - i,
-					"Redzone violation: %s\n", linebuff);
+					"Pre-redzone violation: %s\n",
+					linebuff);
 				break;
 			}
 		}
 
 		/* verify postfix redzone */
-		for (n = 0; n < 16; ++n) {
-			if (*buf_ptr[len + n] != 0xBA) {
-				hex_dump_to_buffer(&(*buf_ptr)[len], 16,
-					16, 1, linebuff, sizeof(linebuff), 1);
+		zone_ptr = *buf_ptr + RED_ZONE_SIZE + len;
+		for (n = 0; n < RED_ZONE_SIZE; ++n) {
+			if (zone_ptr[n] != RED_ZONE_POS_CH) {
+				hex_dump_to_buffer(zone_ptr, RED_ZONE_SIZE,
+					RED_ZONE_SIZE, 1, linebuff,
+					sizeof(linebuff), 1);
 				i += scnprintf(errmsg + i, errmsg_max - i,
-					"Redzone violation: %s\n", linebuff);
+					"Post-redzone violation: %s\n",
+					linebuff);
 				break;
 			}
 		}
@@ -1001,6 +1031,7 @@
 		{0, 256},
 		{0, 512},
 		{0, 1024},
+		{0, 1500},
 		{0, 2048},
 		{0, 4096},
 		{0, 0},
@@ -1011,9 +1042,7 @@
 
 	/* generate test data */
 	for (tv = test_data; tv->len > 0; ++tv) {
-		tv->data = kmalloc(tv->len + 32, GFP_KERNEL);
-		pr_err("%s: allocating %p len %d\n",
-				__func__, tv->data, tv->len);
+		tv->data = kmalloc(tv->len + 2 * RED_ZONE_SIZE, GFP_KERNEL);
 		if (!tv->data) {
 			i += scnprintf(buf + i, max - i,
 					"%s: Unable to allocate %d bytes\n",
@@ -1021,7 +1050,7 @@
 			failed = 1;
 			goto out;
 		}
-		test_pattern_fill((uint8_t *)tv->data, tv->len, 1);
+		tv->data = test_pattern_fill((uint8_t *)tv->data, tv->len, 1);
 	}
 
 	/* run test */
@@ -1038,11 +1067,9 @@
 	}
 
 	for (tv = test_data; tv->len > 0; ++tv) {
-		if (!tv->data) {
+		if (tv->data) {
 			i += test_pattern_verify((char **)&tv->data,
 						tv->len, 1, buf + i, max - i);
-			pr_err("%s: freeing %p len %d\n", __func__,
-							tv->data, tv->len);
 			kfree(tv->data);
 		}
 	}
@@ -1112,6 +1139,59 @@
 }
 
 /**
+ * Run a large packet test for throughput metrics.
+ *
+ * Repeatedly send a packet for 100 iterations to get throughput metrics.
+ */
+static int smux_ut_remote_throughput(char *buf, int max)
+{
+	struct test_vector test_data[] = {
+		{0, 1500},
+		{0, 0},
+	};
+	int failed = 0;
+	int i = 0;
+	int loop = 0;
+	struct test_vector *tv;
+	int ret;
+
+	/* generate test data */
+	for (tv = test_data; tv->len > 0; ++tv) {
+		tv->data = kmalloc(tv->len, GFP_KERNEL);
+		if (!tv->data) {
+			i += scnprintf(buf + i, max - i,
+					"%s: Unable to allocate %d bytes\n",
+					__func__, tv->len);
+			failed = 1;
+			goto out;
+		}
+		test_pattern_fill((uint8_t *)tv->data, tv->len, 0);
+	}
+
+	/* run test */
+	i += scnprintf(buf + i, max - i, "Running %s\n", __func__);
+	while (!failed && loop < 100) {
+		ret = msm_smux_set_ch_option(SMUX_TEST_LCID,
+				SMUX_CH_OPTION_REMOTE_LOOPBACK, 0);
+		UT_ASSERT_INT(ret, ==, 0);
+
+		i += smux_ut_basic_core(buf + i, max - i, test_data, __func__);
+		++loop;
+	}
+
+out:
+	if (failed) {
+		pr_err("%s: Failed\n", __func__);
+		i += scnprintf(buf + i, max - i, "\tFailed\n");
+	}
+
+	for (tv = test_data; tv->len > 0; ++tv)
+			kfree(tv->data);
+
+	return i;
+}
+
+/**
  * Verify set and get operations for each TIOCM bit.
  *
  * @buf  Buffer for status message
@@ -2083,6 +2163,126 @@
 	return i;
 }
 
+/**
+ * Verify Remote-initiated wakeup test case.
+ *
+ * @buf       Output buffer for failure/status messages
+ * @max       Size of @buf
+ */
+static int smux_ut_remote_initiated_wakeup(char *buf, int max)
+{
+	int i = 0;
+	int failed = 0;
+	static struct smux_mock_callback cb_data;
+	static int cb_initialized;
+	int ret;
+
+	if (!cb_initialized)
+		mock_cb_data_init(&cb_data);
+
+	smux_set_loopback_data_reply_delay(SMUX_REMOTE_DELAY_TIME_MS);
+	mock_cb_data_reset(&cb_data);
+	do {
+		unsigned long start_j;
+		unsigned transfer_time;
+		unsigned lwakeups_start;
+		unsigned rwakeups_start;
+		unsigned lwakeups_end;
+		unsigned rwakeups_end;
+		unsigned lwakeup_delta;
+		unsigned rwakeup_delta;
+
+		/* open port */
+		ret = msm_smux_open(SMUX_TEST_LCID, &cb_data, smux_mock_cb,
+					get_rx_buffer);
+		UT_ASSERT_INT(ret, ==, 0);
+		UT_ASSERT_INT(
+			(int)wait_for_completion_timeout(
+					&cb_data.cb_completion, HZ), >, 0);
+		UT_ASSERT_INT(cb_data.cb_count, ==, 1);
+		UT_ASSERT_INT(cb_data.event_connected, ==, 1);
+		mock_cb_data_reset(&cb_data);
+
+		/* do local wakeup test and send echo packet */
+		msleep(SMUX_REMOTE_INACTIVITY_TIME_MS);
+		smux_get_wakeup_counts(&lwakeups_start, &rwakeups_start);
+		msm_smux_write(SMUX_TEST_LCID, (void *)0x12345678,
+				"Hello", 5);
+		UT_ASSERT_INT(ret, ==, 0);
+		UT_ASSERT_INT(
+			(int)wait_for_completion_timeout(
+					&cb_data.cb_completion, HZ), >, 0);
+		UT_ASSERT_INT(cb_data.cb_count, ==, 1);
+		UT_ASSERT_INT(cb_data.event_write_done, ==, 1);
+		mock_cb_data_reset(&cb_data);
+
+		/* verify local initiated wakeup */
+		smux_get_wakeup_counts(&lwakeups_end, &rwakeups_end);
+		if (lwakeups_end > lwakeups_start)
+			i += scnprintf(buf + i, max - i,
+					"\tGood - have Apps-initiated wakeup\n");
+		else
+			i += scnprintf(buf + i, max - i,
+					"\tBad - no Apps-initiated wakeup\n");
+
+		/* verify remote wakeup and echo response */
+		smux_get_wakeup_counts(&lwakeups_start, &rwakeups_start);
+		start_j = jiffies;
+		INIT_COMPLETION(cb_data.cb_completion);
+		if (!cb_data.event_read_done)
+			UT_ASSERT_INT(
+				(int)wait_for_completion_timeout(
+					&cb_data.cb_completion,
+					SMUX_REMOTE_DELAY_TIME_MS * 2),
+				>, 0);
+		transfer_time = (unsigned)jiffies_to_msecs(jiffies - start_j);
+		UT_ASSERT_INT(cb_data.event_read_done, ==, 1);
+		UT_ASSERT_INT_IN_RANGE(transfer_time,
+			SMUX_REMOTE_DELAY_TIME_MS -
+			SMUX_REMOTE_INACTIVITY_TIME_MS,
+			SMUX_REMOTE_DELAY_TIME_MS +
+			SMUX_REMOTE_INACTIVITY_TIME_MS);
+		smux_get_wakeup_counts(&lwakeups_end, &rwakeups_end);
+
+		lwakeup_delta = lwakeups_end - lwakeups_end;
+		rwakeup_delta = rwakeups_end - rwakeups_end;
+		if (rwakeup_delta && lwakeup_delta) {
+			i += scnprintf(buf + i, max - i,
+					"\tBoth local and remote wakeup - re-run test (transfer time %d ms)\n",
+					transfer_time);
+			failed = 1;
+			break;
+		} else if (lwakeup_delta) {
+			i += scnprintf(buf + i, max - i,
+					"\tLocal wakeup only (transfer time %d ms) - FAIL\n",
+					transfer_time);
+			failed = 1;
+			break;
+		} else {
+			i += scnprintf(buf + i, max - i,
+					"\tRemote wakeup verified (transfer time %d ms) - OK\n",
+					transfer_time);
+		}
+	} while (0);
+
+	if (!failed) {
+		i += scnprintf(buf + i, max - i, "\tOK\n");
+	} else {
+		pr_err("%s: Failed\n", __func__);
+		i += scnprintf(buf + i, max - i, "\tFailed\n");
+		i += mock_cb_data_print(&cb_data, buf + i, max - i);
+	}
+
+	mock_cb_data_reset(&cb_data);
+	msm_smux_close(SMUX_TEST_LCID);
+	wait_for_completion_timeout(&cb_data.cb_completion, HZ);
+
+	mock_cb_data_reset(&cb_data);
+	smux_set_loopback_data_reply_delay(0);
+
+	return i;
+}
+
 static char debug_buffer[DEBUG_BUFMAX];
 
 static ssize_t debug_read(struct file *file, char __user *buf,
@@ -2148,15 +2348,18 @@
 			smux_ut_local_get_rx_buff_retry);
 	debug_create("ut_local_get_rx_buff_retry_auto", 0444, dent,
 			smux_ut_local_get_rx_buff_retry_auto);
-	debug_create("ut_remote_ssr_basic", 0444, dent,
-			smux_ut_remote_ssr_basic);
-	debug_create("ut_remote_ssr_open", 0444, dent,
-			smux_ut_remote_ssr_open);
-	debug_create("ut_remote_ssr_rx_buff_retry", 0444, dent,
-			smux_ut_remote_ssr_rx_buff_retry);
+	debug_create("ut_ssr_remote_basic", 0444, dent,
+			smux_ut_ssr_remote_basic);
+	debug_create("ut_ssr_remote_open", 0444, dent,
+			smux_ut_ssr_remote_open);
+	debug_create("ut_ssr_remote_rx_buff_retry", 0444, dent,
+			smux_ut_ssr_remote_rx_buff_retry);
 	debug_create("ut_remote_tx_stop", 0444, dent,
 			smux_ut_remote_tx_stop);
-
+	debug_create("ut_remote_throughput", 0444, dent,
+			smux_ut_remote_throughput);
+	debug_create("ut_remote_initiated_wakeup", 0444, dent,
+			smux_ut_remote_initiated_wakeup);
 	return 0;
 }
 
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index fab5219..04da6f8 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -241,7 +241,13 @@
 	for (i = 0; i < num; i++) {
 		struct dwc3_event_buffer	*evt;
 
-		evt = dwc3_alloc_one_event_buffer(dwc, length);
+		/*
+		 * As SW workaround, allocate 8 bytes more than size of event
+		 * buffer given to USB Controller to avoid possible memory
+		 * corruption caused by event buffer overflow when Hw writes
+		 * Vendor Device test event which could be of 12 bytes.
+		 */
+		evt = dwc3_alloc_one_event_buffer(dwc, (length + 8));
 		if (IS_ERR(evt)) {
 			dev_err(dwc->dev, "can't allocate event buffer\n");
 			return PTR_ERR(evt);
@@ -276,7 +282,7 @@
 		dwc3_writel(dwc->regs, DWC3_GEVNTADRHI(n),
 				upper_32_bits(evt->dma));
 		dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(n),
-				evt->length & 0xffff);
+				(evt->length - 8) & 0xffff);
 		dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(n), 0);
 	}
 
diff --git a/drivers/usb/gadget/android.c b/drivers/usb/gadget/android.c
index bc1fa07..36a43c3 100644
--- a/drivers/usb/gadget/android.c
+++ b/drivers/usb/gadget/android.c
@@ -91,6 +91,7 @@
 #include "u_uac1.c"
 #include "f_uac1.c"
 #endif
+#include "f_ncm.c"
 
 MODULE_AUTHOR("Mike Lockwood");
 MODULE_DESCRIPTION("Android Composite USB Driver");
@@ -524,7 +525,7 @@
 
 	data->opened = false;
 
-	if (data->enabled)
+	if (data->enabled && dev)
 		android_disable(dev);
 
 	data->dev = NULL;
@@ -792,7 +793,103 @@
 	.bind_config	= gps_function_bind_config,
 };
 
+/* ncm */
+struct ncm_function_config {
+	u8      ethaddr[ETH_ALEN];
+};
+static int
+ncm_function_init(struct android_usb_function *f, struct usb_composite_dev *c)
+{
+	f->config = kzalloc(sizeof(struct ncm_function_config), GFP_KERNEL);
+	if (!f->config)
+		return -ENOMEM;
 
+	return 0;
+}
+
+static void ncm_function_cleanup(struct android_usb_function *f)
+{
+	kfree(f->config);
+	f->config = NULL;
+}
+
+static int
+ncm_function_bind_config(struct android_usb_function *f,
+				struct usb_configuration *c)
+{
+	struct ncm_function_config *ncm = f->config;
+	int ret;
+
+	if (!ncm) {
+		pr_err("%s: ncm config is null\n", __func__);
+		return -EINVAL;
+	}
+
+	pr_info("%s MAC: %02X:%02X:%02X:%02X:%02X:%02X\n", __func__,
+		ncm->ethaddr[0], ncm->ethaddr[1], ncm->ethaddr[2],
+		ncm->ethaddr[3], ncm->ethaddr[4], ncm->ethaddr[5]);
+
+	ret = gether_setup_name(c->cdev->gadget, ncm->ethaddr, "ncm");
+	if (ret) {
+		pr_err("%s: gether setup failed err:%d\n", __func__, ret);
+		return ret;
+	}
+
+	ret = ncm_bind_config(c, ncm->ethaddr);
+	if (ret) {
+		pr_err("%s: ncm bind config failed err:%d", __func__, ret);
+		gether_cleanup();
+		return ret;
+	}
+
+	return ret;
+}
+
+static void ncm_function_unbind_config(struct android_usb_function *f,
+						struct usb_configuration *c)
+{
+	gether_cleanup();
+}
+
+static ssize_t ncm_ethaddr_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct android_usb_function *f = dev_get_drvdata(dev);
+	struct ncm_function_config *ncm = f->config;
+	return snprintf(buf, PAGE_SIZE, "%02x:%02x:%02x:%02x:%02x:%02x\n",
+		ncm->ethaddr[0], ncm->ethaddr[1], ncm->ethaddr[2],
+		ncm->ethaddr[3], ncm->ethaddr[4], ncm->ethaddr[5]);
+}
+
+static ssize_t ncm_ethaddr_store(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t size)
+{
+	struct android_usb_function *f = dev_get_drvdata(dev);
+	struct ncm_function_config *ncm = f->config;
+
+	if (sscanf(buf, "%02x:%02x:%02x:%02x:%02x:%02x\n",
+		    (int *)&ncm->ethaddr[0], (int *)&ncm->ethaddr[1],
+		    (int *)&ncm->ethaddr[2], (int *)&ncm->ethaddr[3],
+		    (int *)&ncm->ethaddr[4], (int *)&ncm->ethaddr[5]) == 6)
+		return size;
+	return -EINVAL;
+}
+
+static DEVICE_ATTR(ncm_ethaddr, S_IRUGO | S_IWUSR, ncm_ethaddr_show,
+					       ncm_ethaddr_store);
+static struct device_attribute *ncm_function_attributes[] = {
+	&dev_attr_ncm_ethaddr,
+	NULL
+};
+
+static struct android_usb_function ncm_function = {
+	.name		= "ncm",
+	.init		= ncm_function_init,
+	.cleanup	= ncm_function_cleanup,
+	.bind_config	= ncm_function_bind_config,
+	.unbind_config	= ncm_function_unbind_config,
+	.attributes	= ncm_function_attributes,
+};
 /* ecm transport string */
 static char ecm_transports[MAX_XPORT_STR_LEN];
 
@@ -1857,6 +1954,7 @@
 	&rndis_function,
 	&rndis_qc_function,
 	&ecm_function,
+	&ncm_function,
 	&mass_storage_function,
 	&accessory_function,
 #ifdef CONFIG_SND_PCM
diff --git a/drivers/usb/gadget/ci13xxx_udc.c b/drivers/usb/gadget/ci13xxx_udc.c
index 80e9e87..a258c30 100644
--- a/drivers/usb/gadget/ci13xxx_udc.c
+++ b/drivers/usb/gadget/ci13xxx_udc.c
@@ -79,7 +79,7 @@
  *****************************************************************************/
 
 #define DMA_ADDR_INVALID	(~(dma_addr_t)0)
-#define USB_MAX_TIMEOUT		100 /* 100msec timeout */
+#define USB_MAX_TIMEOUT		25 /* 25msec timeout */
 #define EP_PRIME_CHECK_DELAY	(jiffies + msecs_to_jiffies(1000))
 #define MAX_PRIME_CHECK_RETRY	3 /*Wait for 3sec for EP prime failure */
 
@@ -2275,8 +2275,11 @@
 	gadget->otg_srp_reqd = 0;
 
 	udc->driver->disconnect(gadget);
+
+	spin_lock_irqsave(udc->lock, flags);
 	_ep_nuke(&udc->ep0out);
 	_ep_nuke(&udc->ep0in);
+	spin_unlock_irqrestore(udc->lock, flags);
 
 	if (udc->ep0in.last_zptr) {
 		dma_pool_free(udc->ep0in.td_pool, udc->ep0in.last_zptr,
@@ -3278,7 +3281,13 @@
 	del_timer(&mEp->prime_timer);
 	mEp->prime_timer_count = 0;
 	dbg_event(_usb_addr(mEp), "FFLUSH", 0);
-	hw_ep_flush(mEp->num, mEp->dir);
+	/*
+	 * _ep_nuke() takes care of flushing the endpoint.
+	 * some function drivers expect udc to retire all
+	 * pending requests upon flushing an endpoint.  There
+	 * is no harm in doing it.
+	 */
+	_ep_nuke(mEp);
 
 	spin_unlock_irqrestore(mEp->lock, flags);
 }
@@ -3793,9 +3802,7 @@
 	pm_runtime_no_callbacks(&udc->gadget.dev);
 	pm_runtime_enable(&udc->gadget.dev);
 
-	retval = register_trace_usb_daytona_invalid_access(dump_usb_info,
-								NULL);
-	if (retval)
+	if (register_trace_usb_daytona_invalid_access(dump_usb_info, NULL))
 		pr_err("Registering trace failed\n");
 
 	_udc = udc;
diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c
index 87a3fd5..2f35315 100644
--- a/drivers/usb/gadget/f_mass_storage.c
+++ b/drivers/usb/gadget/f_mass_storage.c
@@ -728,12 +728,18 @@
 			rc = -EINTR;
 			break;
 		}
-		if (common->thread_wakeup_needed)
+		spin_lock_irq(&common->lock);
+		if (common->thread_wakeup_needed) {
+			spin_unlock_irq(&common->lock);
 			break;
+		}
+		spin_unlock_irq(&common->lock);
 		schedule();
 	}
 	__set_current_state(TASK_RUNNING);
+	spin_lock_irq(&common->lock);
 	common->thread_wakeup_needed = 0;
+	spin_unlock_irq(&common->lock);
 	return rc;
 }
 
@@ -796,12 +802,17 @@
 			     curlun->file_length - file_offset);
 
 		/* Wait for the next buffer to become available */
+		spin_lock_irq(&common->lock);
 		bh = common->next_buffhd_to_fill;
 		while (bh->state != BUF_STATE_EMPTY) {
+			spin_unlock_irq(&common->lock);
 			rc = sleep_thread(common);
 			if (rc)
 				return rc;
+
+			spin_lock_irq(&common->lock);
 		}
+		spin_unlock_irq(&common->lock);
 
 		/*
 		 * If we were asked to read past the end of file,
@@ -813,8 +824,10 @@
 			curlun->sense_data_info =
 					file_offset >> curlun->blkbits;
 			curlun->info_valid = 1;
+			spin_lock_irq(&common->lock);
 			bh->inreq->length = 0;
 			bh->state = BUF_STATE_FULL;
+			spin_unlock_irq(&common->lock);
 			break;
 		}
 
@@ -854,8 +867,10 @@
 		 * equal to the buffer size, which is divisible by the
 		 * bulk-in maxpacket size.
 		 */
+		spin_lock_irq(&common->lock);
 		bh->inreq->length = nread;
 		bh->state = BUF_STATE_FULL;
+		spin_unlock_irq(&common->lock);
 
 		/* If an error occurred, report it and its position */
 		if (nread < amount) {
@@ -1814,12 +1829,17 @@
 	u32			sd, sdinfo = 0;
 
 	/* Wait for the next buffer to become available */
+	spin_lock_irq(&common->lock);
 	bh = common->next_buffhd_to_fill;
 	while (bh->state != BUF_STATE_EMPTY) {
+		spin_unlock_irq(&common->lock);
 		rc = sleep_thread(common);
 		if (rc)
 			return rc;
+
+		spin_lock_irq(&common->lock);
 	}
+	spin_unlock_irq(&common->lock);
 
 	if (curlun) {
 		sd = curlun->sense_data;
@@ -2029,13 +2049,19 @@
 	dump_cdb(common);
 
 	/* Wait for the next buffer to become available for data or status */
+	spin_lock_irq(&common->lock);
 	bh = common->next_buffhd_to_fill;
 	common->next_buffhd_to_drain = bh;
 	while (bh->state != BUF_STATE_EMPTY) {
+		spin_unlock_irq(&common->lock);
 		rc = sleep_thread(common);
 		if (rc)
 			return rc;
+
+		spin_lock_irq(&common->lock);
 	}
+	spin_unlock_irq(&common->lock);
+
 	common->phase_error = 0;
 	common->short_packet_received = 0;
 
@@ -2376,12 +2402,17 @@
 	int			rc = 0;
 
 	/* Wait for the next buffer to become available */
+	spin_lock_irq(&common->lock);
 	bh = common->next_buffhd_to_fill;
 	while (bh->state != BUF_STATE_EMPTY) {
+		spin_unlock_irq(&common->lock);
 		rc = sleep_thread(common);
 		if (rc)
 			return rc;
+
+		spin_lock_irq(&common->lock);
 	}
+	spin_unlock_irq(&common->lock);
 
 	/* Queue a request to read a Bulk-only CBW */
 	set_bulk_out_req_length(common, bh, US_BULK_CB_WRAP_LEN);
@@ -2396,14 +2427,23 @@
 	 */
 
 	/* Wait for the CBW to arrive */
+	spin_lock_irq(&common->lock);
 	while (bh->state != BUF_STATE_FULL) {
+		spin_unlock_irq(&common->lock);
 		rc = sleep_thread(common);
 		if (rc)
 			return rc;
+
+		spin_lock_irq(&common->lock);
 	}
+	spin_unlock_irq(&common->lock);
+
 	smp_rmb();
 	rc = fsg_is_set(common) ? received_cbw(common->fsg, bh) : -EIO;
+
+	spin_lock_irq(&common->lock);
 	bh->state = BUF_STATE_EMPTY;
+	spin_unlock_irq(&common->lock);
 
 	return rc;
 }
@@ -2586,10 +2626,13 @@
 		/* Wait until everything is idle */
 		for (;;) {
 			int num_active = 0;
+			spin_lock_irq(&common->lock);
 			for (i = 0; i < fsg_num_buffers; ++i) {
 				bh = &common->buffhds[i];
 				num_active += bh->inreq_busy + bh->outreq_busy;
 			}
+			spin_unlock_irq(&common->lock);
+
 			if (num_active == 0)
 				break;
 			if (sleep_thread(common))
diff --git a/drivers/usb/gadget/f_mbim.c b/drivers/usb/gadget/f_mbim.c
index a1b02be..aaacd43 100644
--- a/drivers/usb/gadget/f_mbim.c
+++ b/drivers/usb/gadget/f_mbim.c
@@ -63,10 +63,10 @@
 };
 
 enum mbim_notify_state {
-	NCM_NOTIFY_NONE,
-	NCM_NOTIFY_CONNECT,
-	NCM_NOTIFY_SPEED,
-	NCM_NOTIFY_RESPONSE_AVAILABLE,
+	MBIM_NOTIFY_NONE,
+	MBIM_NOTIFY_CONNECT,
+	MBIM_NOTIFY_SPEED,
+	MBIM_NOTIFY_RESPONSE_AVAILABLE,
 };
 
 struct f_mbim {
@@ -95,7 +95,7 @@
 	u8				ctrl_id, data_id;
 	u8				data_alt_int;
 
-	struct ndp_parser_opts		*parser_opts;
+	struct mbim_ndp_parser_opts	*parser_opts;
 
 	spinlock_t			lock;
 
@@ -140,24 +140,24 @@
 
 /*-------------------------------------------------------------------------*/
 
-#define NTB_DEFAULT_IN_SIZE	(0x4000)
-#define NTB_OUT_SIZE		(0x1000)
-#define NDP_IN_DIVISOR		(0x4)
+#define MBIM_NTB_DEFAULT_IN_SIZE	(0x4000)
+#define MBIM_NTB_OUT_SIZE		(0x1000)
+#define MBIM_NDP_IN_DIVISOR		(0x4)
 
 #define NTB_DEFAULT_IN_SIZE_IPA	(0x2000)
-#define NTB_OUT_SIZE_IPA		(0x2000)
+#define MBIM_NTB_OUT_SIZE_IPA		(0x2000)
 
-#define FORMATS_SUPPORTED	USB_CDC_NCM_NTB16_SUPPORTED
+#define MBIM_FORMATS_SUPPORTED	USB_CDC_NCM_NTB16_SUPPORTED
 
-static struct usb_cdc_ncm_ntb_parameters ntb_parameters = {
-	.wLength = sizeof ntb_parameters,
-	.bmNtbFormatsSupported = cpu_to_le16(FORMATS_SUPPORTED),
-	.dwNtbInMaxSize = cpu_to_le32(NTB_DEFAULT_IN_SIZE),
-	.wNdpInDivisor = cpu_to_le16(NDP_IN_DIVISOR),
+static struct usb_cdc_ncm_ntb_parameters mbim_ntb_parameters = {
+	.wLength = sizeof mbim_ntb_parameters,
+	.bmNtbFormatsSupported = cpu_to_le16(MBIM_FORMATS_SUPPORTED),
+	.dwNtbInMaxSize = cpu_to_le32(MBIM_NTB_DEFAULT_IN_SIZE),
+	.wNdpInDivisor = cpu_to_le16(MBIM_NDP_IN_DIVISOR),
 	.wNdpInPayloadRemainder = cpu_to_le16(0),
 	.wNdpInAlignment = cpu_to_le16(4),
 
-	.dwNtbOutMaxSize = cpu_to_le32(NTB_OUT_SIZE),
+	.dwNtbOutMaxSize = cpu_to_le32(MBIM_NTB_OUT_SIZE),
 	.wNdpOutDivisor = cpu_to_le16(4),
 	.wNdpOutPayloadRemainder = cpu_to_le16(0),
 	.wNdpOutAlignment = cpu_to_le16(4),
@@ -444,7 +444,7 @@
  * and switch pointers to the structures when the format is changed.
  */
 
-struct ndp_parser_opts {
+struct mbim_ndp_parser_opts {
 	u32		nth_sign;
 	u32		ndp_sign;
 	unsigned	nth_size;
@@ -487,8 +487,8 @@
 	.next_fp_index = 2,				\
 }
 
-static struct ndp_parser_opts ndp16_opts = INIT_NDP16_OPTS;
-static struct ndp_parser_opts ndp32_opts = INIT_NDP32_OPTS;
+static struct mbim_ndp_parser_opts mbim_ndp16_opts = INIT_NDP16_OPTS;
+static struct mbim_ndp_parser_opts mbim_ndp32_opts = INIT_NDP32_OPTS;
 
 static inline int mbim_lock(atomic_t *excl)
 {
@@ -630,7 +630,7 @@
 		return 0;
 	}
 
-	if (dev->not_port.notify_state != NCM_NOTIFY_RESPONSE_AVAILABLE) {
+	if (dev->not_port.notify_state != MBIM_NOTIFY_RESPONSE_AVAILABLE) {
 		pr_err("dev:%p state=%d, recover!!\n", dev,
 			dev->not_port.notify_state);
 		mbim_free_ctrl_pkt(cpkt);
@@ -670,12 +670,14 @@
 	int ret = 0;
 
 	aggr_params.dl.aggr_prot = TETH_AGGR_PROTOCOL_MBIM;
-	aggr_params.dl.max_datagrams = ntb_parameters.wNtbOutMaxDatagrams;
-	aggr_params.dl.max_transfer_size_byte = ntb_parameters.dwNtbInMaxSize;
+	aggr_params.dl.max_datagrams = mbim_ntb_parameters.wNtbOutMaxDatagrams;
+	aggr_params.dl.max_transfer_size_byte =
+			mbim_ntb_parameters.dwNtbInMaxSize;
 
 	aggr_params.ul.aggr_prot = TETH_AGGR_PROTOCOL_MBIM;
-	aggr_params.ul.max_datagrams = ntb_parameters.wNtbOutMaxDatagrams;
-	aggr_params.ul.max_transfer_size_byte = ntb_parameters.dwNtbOutMaxSize;
+	aggr_params.ul.max_datagrams = mbim_ntb_parameters.wNtbOutMaxDatagrams;
+	aggr_params.ul.max_transfer_size_byte =
+			mbim_ntb_parameters.dwNtbOutMaxSize;
 
 	ret = teth_bridge_set_aggr_params(&aggr_params);
 	if (ret)
@@ -731,9 +733,9 @@
 
 static inline void mbim_reset_values(struct f_mbim *mbim)
 {
-	mbim->parser_opts = &ndp16_opts;
+	mbim->parser_opts = &mbim_ndp16_opts;
 
-	mbim->ntb_input_size = NTB_DEFAULT_IN_SIZE;
+	mbim->ntb_input_size = MBIM_NTB_DEFAULT_IN_SIZE;
 
 	atomic_set(&mbim->online, 0);
 }
@@ -809,15 +811,15 @@
 
 	switch (mbim->not_port.notify_state) {
 
-	case NCM_NOTIFY_NONE:
+	case MBIM_NOTIFY_NONE:
 		if (atomic_read(&mbim->not_port.notify_count) > 0)
-			pr_err("Pending notifications in NCM_NOTIFY_NONE\n");
+			pr_err("Pending notifications in MBIM_NOTIFY_NONE\n");
 		else
 			pr_debug("No pending notifications\n");
 
 		return;
 
-	case NCM_NOTIFY_RESPONSE_AVAILABLE:
+	case MBIM_NOTIFY_RESPONSE_AVAILABLE:
 		pr_debug("Notification %02x sent\n", event->bNotificationType);
 
 		if (atomic_read(&mbim->not_port.notify_count) <= 0) {
@@ -874,7 +876,7 @@
 	case -ECONNRESET:
 	case -ESHUTDOWN:
 		/* connection gone */
-		mbim->not_port.notify_state = NCM_NOTIFY_NONE;
+		mbim->not_port.notify_state = MBIM_NOTIFY_NONE;
 		atomic_set(&mbim->not_port.notify_count, 0);
 		pr_info("ESHUTDOWN/ECONNRESET, connection gone");
 		spin_unlock(&mbim->lock);
@@ -913,7 +915,7 @@
 	if (req->length == 4) {
 		in_size = get_unaligned_le32(req->buf);
 		if (in_size < USB_CDC_NCM_NTB_MIN_IN_SIZE ||
-		    in_size > le32_to_cpu(ntb_parameters.dwNtbInMaxSize)) {
+		    in_size > le32_to_cpu(mbim_ntb_parameters.dwNtbInMaxSize)) {
 			pr_err("Illegal INPUT SIZE (%d) from host\n", in_size);
 			goto invalid;
 		}
@@ -921,7 +923,7 @@
 		ntb = (struct mbim_ntb_input_size *)req->buf;
 		in_size = get_unaligned_le32(&(ntb->ntb_input_size));
 		if (in_size < USB_CDC_NCM_NTB_MIN_IN_SIZE ||
-		    in_size > le32_to_cpu(ntb_parameters.dwNtbInMaxSize)) {
+		    in_size > le32_to_cpu(mbim_ntb_parameters.dwNtbInMaxSize)) {
 			pr_err("Illegal INPUT SIZE (%d) from host\n", in_size);
 			goto invalid;
 		}
@@ -1080,9 +1082,9 @@
 		if (w_length == 0 || w_value != 0 || w_index != mbim->ctrl_id)
 			break;
 
-		value = w_length > sizeof ntb_parameters ?
-			sizeof ntb_parameters : w_length;
-		memcpy(req->buf, &ntb_parameters, value);
+		value = w_length > sizeof mbim_ntb_parameters ?
+			sizeof mbim_ntb_parameters : w_length;
+		memcpy(req->buf, &mbim_ntb_parameters, value);
 		break;
 
 	case ((USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
@@ -1129,7 +1131,7 @@
 		if (w_length < 2 || w_value != 0 || w_index != mbim->ctrl_id)
 			break;
 
-		format = (mbim->parser_opts == &ndp16_opts) ? 0x0000 : 0x0001;
+		format = (mbim->parser_opts == &mbim_ndp16_opts) ? 0 : 1;
 		put_unaligned_le16(format, req->buf);
 		value = 2;
 		pr_debug("NTB FORMAT: sending %d\n", format);
@@ -1145,11 +1147,11 @@
 			break;
 		switch (w_value) {
 		case 0x0000:
-			mbim->parser_opts = &ndp16_opts;
+			mbim->parser_opts = &mbim_ndp16_opts;
 			pr_debug("NCM16 selected\n");
 			break;
 		case 0x0001:
-			mbim->parser_opts = &ndp32_opts;
+			mbim->parser_opts = &mbim_ndp32_opts;
 			pr_debug("NCM32 selected\n");
 			break;
 		default:
@@ -1343,7 +1345,7 @@
 
 		mbim->data_alt_int = alt;
 		spin_lock(&mbim->lock);
-		mbim->not_port.notify_state = NCM_NOTIFY_RESPONSE_AVAILABLE;
+		mbim->not_port.notify_state = MBIM_NOTIFY_RESPONSE_AVAILABLE;
 		spin_unlock(&mbim->lock);
 	} else {
 		goto fail;
@@ -1387,7 +1389,7 @@
 	pr_info("SET DEVICE OFFLINE");
 	atomic_set(&mbim->online, 0);
 
-	mbim->not_port.notify_state = NCM_NOTIFY_NONE;
+	mbim->not_port.notify_state = MBIM_NOTIFY_NONE;
 
 	mbim_clear_queues(mbim);
 	mbim_reset_function_queue(mbim);
@@ -1497,6 +1499,11 @@
 	mbim->not_port.notify_req->context = mbim;
 	mbim->not_port.notify_req->complete = mbim_notify_complete;
 
+	if (mbim->xport == USB_GADGET_XPORT_BAM2BAM_IPA)
+		mbb_desc.wMaxSegmentSize = cpu_to_le16(0x800);
+	else
+		mbb_desc.wMaxSegmentSize = cpu_to_le16(0xfe0);
+
 	/* copy descriptors, and track endpoint copies */
 	f->descriptors = usb_copy_descriptors(mbim_fs_function);
 	if (!f->descriptors)
@@ -1650,12 +1657,13 @@
 		mbim->xport = USB_GADGET_XPORT_BAM2BAM;
 	} else  {
 		/* For IPA we use limit of 16 */
-		ntb_parameters.wNtbOutMaxDatagrams = 16;
+		mbim_ntb_parameters.wNtbOutMaxDatagrams = 16;
 		/* For IPA this is proven to give maximum throughput */
-		ntb_parameters.dwNtbInMaxSize =
+		mbim_ntb_parameters.dwNtbInMaxSize =
 		cpu_to_le32(NTB_DEFAULT_IN_SIZE_IPA);
-		ntb_parameters.dwNtbOutMaxSize = cpu_to_le32(NTB_OUT_SIZE_IPA);
-		ntb_parameters.wNdpInDivisor = 1;
+		mbim_ntb_parameters.dwNtbOutMaxSize =
+				cpu_to_le32(MBIM_NTB_OUT_SIZE_IPA);
+		mbim_ntb_parameters.wNdpInDivisor = 1;
 	}
 
 	INIT_LIST_HEAD(&mbim->cpkt_req_q);
diff --git a/drivers/usb/gadget/f_mtp.c b/drivers/usb/gadget/f_mtp.c
index 0c0d58a..37189d8 100644
--- a/drivers/usb/gadget/f_mtp.c
+++ b/drivers/usb/gadget/f_mtp.c
@@ -50,7 +50,7 @@
 #define STATE_ERROR                 4   /* error from completion routine */
 
 /* number of tx and rx requests to allocate */
-#define TX_REQ_MAX 4
+#define MTP_TX_REQ_MAX 8
 #define RX_REQ_MAX 2
 #define INTR_REQ_MAX 5
 
@@ -70,6 +70,12 @@
 unsigned int mtp_rx_req_len = MTP_BULK_BUFFER_SIZE;
 module_param(mtp_rx_req_len, uint, S_IRUGO | S_IWUSR);
 
+unsigned int mtp_tx_req_len = MTP_BULK_BUFFER_SIZE;
+module_param(mtp_tx_req_len, uint, S_IRUGO | S_IWUSR);
+
+unsigned int mtp_tx_reqs = MTP_TX_REQ_MAX;
+module_param(mtp_tx_reqs, uint, S_IRUGO | S_IWUSR);
+
 static const char mtp_shortname[] = "mtp_usb";
 
 struct mtp_dev {
@@ -488,11 +494,22 @@
 	ep->driver_data = dev;		/* claim the endpoint */
 	dev->ep_intr = ep;
 
+retry_tx_alloc:
+	if (mtp_tx_req_len > MTP_BULK_BUFFER_SIZE)
+		mtp_tx_reqs = 4;
+
 	/* now allocate requests for our endpoints */
-	for (i = 0; i < TX_REQ_MAX; i++) {
-		req = mtp_request_new(dev->ep_in, MTP_BULK_BUFFER_SIZE);
-		if (!req)
-			goto fail;
+	for (i = 0; i < mtp_tx_reqs; i++) {
+		req = mtp_request_new(dev->ep_in, mtp_tx_req_len);
+		if (!req) {
+			if (mtp_tx_req_len <= MTP_BULK_BUFFER_SIZE)
+				goto fail;
+			while ((req = mtp_req_get(dev, &dev->tx_idle)))
+				mtp_request_free(req, dev->ep_in);
+			mtp_tx_req_len = MTP_BULK_BUFFER_SIZE;
+			mtp_tx_reqs = MTP_TX_REQ_MAX;
+			goto retry_tx_alloc;
+		}
 		req->complete = mtp_complete_in;
 		mtp_req_put(dev, &dev->tx_idle, req);
 	}
diff --git a/drivers/usb/gadget/f_ncm.c b/drivers/usb/gadget/f_ncm.c
index aab8ede..cdf86fd 100644
--- a/drivers/usb/gadget/f_ncm.c
+++ b/drivers/usb/gadget/f_ncm.c
@@ -24,6 +24,21 @@
 
 #include "u_ether.h"
 
+#undef DBG
+#undef VDBG
+#undef ERROR
+#undef INFO
+
+#define DBG(d, fmt, args...) \
+	dev_dbg(&(d)->gadget->dev , fmt , ## args)
+#define VDBG(d, fmt, args...) \
+	dev_vdbg(&(d)->gadget->dev , fmt , ## args)
+#define ERROR(d, fmt, args...) \
+	dev_err(&(d)->gadget->dev , fmt , ## args)
+#define WARNING(d, fmt, args...) \
+	dev_warn(&(d)->gadget->dev , fmt , ## args)
+#define INFO(d, fmt, args...) \
+	dev_info(&(d)->gadget->dev , fmt , ## args)
 /*
  * This function is a "CDC Network Control Model" (CDC NCM) Ethernet link.
  * NCM is intended to be used with high-speed network attachments.
@@ -124,7 +139,7 @@
 #define LOG2_STATUS_INTERVAL_MSEC	5	/* 1 << 5 == 32 msec */
 #define NCM_STATUS_BYTECOUNT		16	/* 8 byte header + data */
 
-static struct usb_interface_assoc_descriptor ncm_iad_desc __initdata = {
+static struct usb_interface_assoc_descriptor ncm_iad_desc = {
 	.bLength =		sizeof ncm_iad_desc,
 	.bDescriptorType =	USB_DT_INTERFACE_ASSOCIATION,
 
@@ -138,7 +153,7 @@
 
 /* interface descriptor: */
 
-static struct usb_interface_descriptor ncm_control_intf __initdata = {
+static struct usb_interface_descriptor ncm_control_intf = {
 	.bLength =		sizeof ncm_control_intf,
 	.bDescriptorType =	USB_DT_INTERFACE,
 
@@ -150,7 +165,7 @@
 	/* .iInterface = DYNAMIC */
 };
 
-static struct usb_cdc_header_desc ncm_header_desc __initdata = {
+static struct usb_cdc_header_desc ncm_header_desc = {
 	.bLength =		sizeof ncm_header_desc,
 	.bDescriptorType =	USB_DT_CS_INTERFACE,
 	.bDescriptorSubType =	USB_CDC_HEADER_TYPE,
@@ -158,7 +173,7 @@
 	.bcdCDC =		cpu_to_le16(0x0110),
 };
 
-static struct usb_cdc_union_desc ncm_union_desc __initdata = {
+static struct usb_cdc_union_desc ncm_union_desc = {
 	.bLength =		sizeof(ncm_union_desc),
 	.bDescriptorType =	USB_DT_CS_INTERFACE,
 	.bDescriptorSubType =	USB_CDC_UNION_TYPE,
@@ -166,8 +181,8 @@
 	/* .bSlaveInterface0 =	DYNAMIC */
 };
 
-static struct usb_cdc_ether_desc ecm_desc __initdata = {
-	.bLength =		sizeof ecm_desc,
+static struct usb_cdc_ether_desc necm_desc = {
+	.bLength =		sizeof necm_desc,
 	.bDescriptorType =	USB_DT_CS_INTERFACE,
 	.bDescriptorSubType =	USB_CDC_ETHERNET_TYPE,
 
@@ -181,7 +196,7 @@
 
 #define NCAPS	(USB_CDC_NCM_NCAP_ETH_FILTER | USB_CDC_NCM_NCAP_CRC_MODE)
 
-static struct usb_cdc_ncm_desc ncm_desc __initdata = {
+static struct usb_cdc_ncm_desc ncm_desc = {
 	.bLength =		sizeof ncm_desc,
 	.bDescriptorType =	USB_DT_CS_INTERFACE,
 	.bDescriptorSubType =	USB_CDC_NCM_TYPE,
@@ -193,7 +208,7 @@
 
 /* the default data interface has no endpoints ... */
 
-static struct usb_interface_descriptor ncm_data_nop_intf __initdata = {
+static struct usb_interface_descriptor ncm_data_nop_intf = {
 	.bLength =		sizeof ncm_data_nop_intf,
 	.bDescriptorType =	USB_DT_INTERFACE,
 
@@ -208,7 +223,7 @@
 
 /* ... but the "real" data interface has two bulk endpoints */
 
-static struct usb_interface_descriptor ncm_data_intf __initdata = {
+static struct usb_interface_descriptor ncm_data_intf = {
 	.bLength =		sizeof ncm_data_intf,
 	.bDescriptorType =	USB_DT_INTERFACE,
 
@@ -223,7 +238,7 @@
 
 /* full speed support: */
 
-static struct usb_endpoint_descriptor fs_ncm_notify_desc __initdata = {
+static struct usb_endpoint_descriptor fs_ncm_notify_desc = {
 	.bLength =		USB_DT_ENDPOINT_SIZE,
 	.bDescriptorType =	USB_DT_ENDPOINT,
 
@@ -233,7 +248,7 @@
 	.bInterval =		1 << LOG2_STATUS_INTERVAL_MSEC,
 };
 
-static struct usb_endpoint_descriptor fs_ncm_in_desc __initdata = {
+static struct usb_endpoint_descriptor fs_ncm_in_desc = {
 	.bLength =		USB_DT_ENDPOINT_SIZE,
 	.bDescriptorType =	USB_DT_ENDPOINT,
 
@@ -241,7 +256,7 @@
 	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
 };
 
-static struct usb_endpoint_descriptor fs_ncm_out_desc __initdata = {
+static struct usb_endpoint_descriptor fs_ncm_out_desc = {
 	.bLength =		USB_DT_ENDPOINT_SIZE,
 	.bDescriptorType =	USB_DT_ENDPOINT,
 
@@ -249,13 +264,13 @@
 	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
 };
 
-static struct usb_descriptor_header *ncm_fs_function[] __initdata = {
+static struct usb_descriptor_header *ncm_fs_function[] = {
 	(struct usb_descriptor_header *) &ncm_iad_desc,
 	/* CDC NCM control descriptors */
 	(struct usb_descriptor_header *) &ncm_control_intf,
 	(struct usb_descriptor_header *) &ncm_header_desc,
 	(struct usb_descriptor_header *) &ncm_union_desc,
-	(struct usb_descriptor_header *) &ecm_desc,
+	(struct usb_descriptor_header *) &necm_desc,
 	(struct usb_descriptor_header *) &ncm_desc,
 	(struct usb_descriptor_header *) &fs_ncm_notify_desc,
 	/* data interface, altsettings 0 and 1 */
@@ -268,7 +283,7 @@
 
 /* high speed support: */
 
-static struct usb_endpoint_descriptor hs_ncm_notify_desc __initdata = {
+static struct usb_endpoint_descriptor hs_ncm_notify_desc = {
 	.bLength =		USB_DT_ENDPOINT_SIZE,
 	.bDescriptorType =	USB_DT_ENDPOINT,
 
@@ -277,7 +292,7 @@
 	.wMaxPacketSize =	cpu_to_le16(NCM_STATUS_BYTECOUNT),
 	.bInterval =		LOG2_STATUS_INTERVAL_MSEC + 4,
 };
-static struct usb_endpoint_descriptor hs_ncm_in_desc __initdata = {
+static struct usb_endpoint_descriptor hs_ncm_in_desc = {
 	.bLength =		USB_DT_ENDPOINT_SIZE,
 	.bDescriptorType =	USB_DT_ENDPOINT,
 
@@ -286,7 +301,7 @@
 	.wMaxPacketSize =	cpu_to_le16(512),
 };
 
-static struct usb_endpoint_descriptor hs_ncm_out_desc __initdata = {
+static struct usb_endpoint_descriptor hs_ncm_out_desc = {
 	.bLength =		USB_DT_ENDPOINT_SIZE,
 	.bDescriptorType =	USB_DT_ENDPOINT,
 
@@ -295,13 +310,13 @@
 	.wMaxPacketSize =	cpu_to_le16(512),
 };
 
-static struct usb_descriptor_header *ncm_hs_function[] __initdata = {
+static struct usb_descriptor_header *ncm_hs_function[] = {
 	(struct usb_descriptor_header *) &ncm_iad_desc,
 	/* CDC NCM control descriptors */
 	(struct usb_descriptor_header *) &ncm_control_intf,
 	(struct usb_descriptor_header *) &ncm_header_desc,
 	(struct usb_descriptor_header *) &ncm_union_desc,
-	(struct usb_descriptor_header *) &ecm_desc,
+	(struct usb_descriptor_header *) &necm_desc,
 	(struct usb_descriptor_header *) &ncm_desc,
 	(struct usb_descriptor_header *) &hs_ncm_notify_desc,
 	/* data interface, altsettings 0 and 1 */
@@ -316,13 +331,13 @@
 
 #define STRING_CTRL_IDX	0
 #define STRING_MAC_IDX	1
-#define STRING_DATA_IDX	2
+#define NCM_STRING_DATA_IDX	2
 #define STRING_IAD_IDX	3
 
 static struct usb_string ncm_string_defs[] = {
 	[STRING_CTRL_IDX].s = "CDC Network Control Model (NCM)",
 	[STRING_MAC_IDX].s = NULL /* DYNAMIC */,
-	[STRING_DATA_IDX].s = "CDC Network Data",
+	[NCM_STRING_DATA_IDX].s = "CDC Network Data",
 	[STRING_IAD_IDX].s = "CDC NCM",
 	{  } /* end of list */
 };
@@ -1148,7 +1163,7 @@
 
 /* ethernet function driver setup/binding */
 
-static int __init
+static int
 ncm_bind(struct usb_configuration *c, struct usb_function *f)
 {
 	struct usb_composite_dev *cdev = c->cdev;
@@ -1299,7 +1314,7 @@
  * Caller must have called @gether_setup().  Caller is also responsible
  * for calling @gether_cleanup() before module unload.
  */
-int __init ncm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN])
+int ncm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN])
 {
 	struct f_ncm	*ncm;
 	int		status;
@@ -1321,7 +1336,7 @@
 		status = usb_string_id(c->cdev);
 		if (status < 0)
 			return status;
-		ncm_string_defs[STRING_DATA_IDX].id = status;
+		ncm_string_defs[NCM_STRING_DATA_IDX].id = status;
 		ncm_data_nop_intf.iInterface = status;
 		ncm_data_intf.iInterface = status;
 
@@ -1330,7 +1345,7 @@
 		if (status < 0)
 			return status;
 		ncm_string_defs[STRING_MAC_IDX].id = status;
-		ecm_desc.iMACAddress = status;
+		necm_desc.iMACAddress = status;
 
 		/* IAD */
 		status = usb_string_id(c->cdev);
diff --git a/drivers/usb/gadget/f_qc_ecm.c b/drivers/usb/gadget/f_qc_ecm.c
index 5e68296..a6b443f 100644
--- a/drivers/usb/gadget/f_qc_ecm.c
+++ b/drivers/usb/gadget/f_qc_ecm.c
@@ -75,6 +75,7 @@
 	struct usb_request		*notify_req;
 	u8				notify_state;
 	bool				is_open;
+	struct data_port		bam_port;
 };
 
 static struct ecm_ipa_params ipa_params;
@@ -111,8 +112,9 @@
 #define ECM_QC_LOG2_STATUS_INTERVAL_MSEC	5	/* 1 << 5 == 32 msec */
 #define ECM_QC_STATUS_BYTECOUNT		16	/* 8 byte header + data */
 
-/* currently only one std ecm instance is supported */
+/* Currently only one std ecm instance is supported - port index 0. */
 #define ECM_QC_NO_PORTS						1
+#define ECM_QC_ACTIVE_PORT					0
 
 /* interface descriptor: */
 
@@ -296,8 +298,6 @@
 	NULL,
 };
 
-static struct data_port ecm_qc_bam_port;
-
 static void ecm_qc_do_notify(struct f_ecm_qc *ecm)
 {
 	struct usb_request		*req = ecm->notify_req;
@@ -388,9 +388,10 @@
 	enum peer_bam peer_bam = (dev->xport == USB_GADGET_XPORT_BAM2BAM_IPA) ?
 		IPA_P_BAM : A2_P_BAM;
 
-	ecm_qc_bam_port.cdev = cdev;
-	ecm_qc_bam_port.in = dev->port.in_ep;
-	ecm_qc_bam_port.out = dev->port.out_ep;
+	dev->bam_port.cdev = cdev;
+	dev->bam_port.func = &dev->port.func;
+	dev->bam_port.in = dev->port.in_ep;
+	dev->bam_port.out = dev->port.out_ep;
 
 	/* currently we use the first connection */
 	src_connection_idx = usb_bam_get_connection_idx(gadget->name, peer_bam,
@@ -401,7 +402,7 @@
 		pr_err("%s: usb_bam_get_connection_idx failed\n", __func__);
 		return ret;
 	}
-	ret = bam_data_connect(&ecm_qc_bam_port, 0, dev->xport,
+	ret = bam_data_connect(&dev->bam_port, 0, dev->xport,
 		src_connection_idx, dst_connection_idx, USB_FUNC_ECM);
 	if (ret) {
 		pr_err("bam_data_connect failed: err:%d\n", ret);
@@ -420,7 +421,7 @@
 {
 	pr_debug("dev:%p. Disconnect BAM.\n", dev);
 
-	bam_data_disconnect(&ecm_qc_bam_port, 0);
+	bam_data_disconnect(&dev->bam_port, 0);
 
 	return 0;
 }
@@ -655,6 +656,20 @@
 	}
 }
 
+static void ecm_qc_suspend(struct usb_function *f)
+{
+	pr_debug("ecm suspended\n");
+
+	bam_data_suspend(ECM_QC_ACTIVE_PORT);
+}
+
+static void ecm_qc_resume(struct usb_function *f)
+{
+	pr_debug("ecm resumed\n");
+
+	bam_data_resume(ECM_QC_ACTIVE_PORT);
+}
+
 /*-------------------------------------------------------------------------*/
 
 /*
@@ -938,6 +953,8 @@
 	ecm->port.func.get_alt = ecm_qc_get_alt;
 	ecm->port.func.setup = ecm_qc_setup;
 	ecm->port.func.disable = ecm_qc_disable;
+	ecm->port.func.suspend = ecm_qc_suspend;
+	ecm->port.func.resume = ecm_qc_resume;
 
 	status = usb_add_function(c, &ecm->port.func);
 	if (status) {
diff --git a/drivers/usb/gadget/f_qc_rndis.c b/drivers/usb/gadget/f_qc_rndis.c
index baea664..267cf53 100644
--- a/drivers/usb/gadget/f_qc_rndis.c
+++ b/drivers/usb/gadget/f_qc_rndis.c
@@ -426,6 +426,7 @@
 	struct usb_gadget *gadget = cdev->gadget;
 
 	dev->bam_port.cdev = cdev;
+	dev->bam_port.func = &dev->port.func;
 	dev->bam_port.in = dev->port.in_ep;
 	dev->bam_port.out = dev->port.out_ep;
 
diff --git a/drivers/usb/gadget/f_rndis.c b/drivers/usb/gadget/f_rndis.c
index 1288bfd..7903764 100644
--- a/drivers/usb/gadget/f_rndis.c
+++ b/drivers/usb/gadget/f_rndis.c
@@ -66,12 +66,12 @@
  *   - MS-Windows drivers sometimes emit undocumented requests.
  */
 
-static bool rndis_multipacket_dl_disable;
-module_param(rndis_multipacket_dl_disable, bool, S_IRUGO|S_IWUSR);
-MODULE_PARM_DESC(rndis_multipacket_dl_disable,
-	"Disable RNDIS Multi-packet support in DownLink");
+static unsigned int rndis_dl_max_pkt_per_xfer = 3;
+module_param(rndis_dl_max_pkt_per_xfer, uint, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(rndis_dl_max_pkt_per_xfer,
+	"Maximum packets per transfer for DL aggregation");
 
-static unsigned int rndis_ul_max_pkt_per_xfer = 1;
+static unsigned int rndis_ul_max_pkt_per_xfer = 3;
 module_param(rndis_ul_max_pkt_per_xfer, uint, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(rndis_ul_max_pkt_per_xfer,
 	"Maximum packets per transfer for UL aggregation");
@@ -488,7 +488,7 @@
 				__func__, buf->MaxTransferSize,
 				rndis->port.multi_pkt_xfer ? "enabled" :
 							    "disabled");
-		if (rndis_multipacket_dl_disable)
+		if (rndis_dl_max_pkt_per_xfer <= 1)
 			rndis->port.multi_pkt_xfer = 0;
 	}
 //	spin_unlock(&dev->lock);
@@ -952,6 +952,7 @@
 	rndis->port.wrap = rndis_add_header;
 	rndis->port.unwrap = rndis_rm_hdr;
 	rndis->port.ul_max_pkts_per_xfer = rndis_ul_max_pkt_per_xfer;
+	rndis->port.dl_max_pkts_per_xfer = rndis_dl_max_pkt_per_xfer;
 
 	rndis->port.func.name = "rndis";
 	rndis->port.func.strings = rndis_strings;
diff --git a/drivers/usb/gadget/rndis.c b/drivers/usb/gadget/rndis.c
index bff7eb1..e662bfc 100644
--- a/drivers/usb/gadget/rndis.c
+++ b/drivers/usb/gadget/rndis.c
@@ -1074,14 +1074,6 @@
 		struct sk_buff		*skb2;
 		u32		msg_len, data_offset, data_len;
 
-		/* some rndis hosts send extra byte to avoid zlp, ignore it */
-		if (skb->len == 1) {
-			if (num_pkts > rndis_ul_max_pkt_per_xfer_rcvd)
-				rndis_ul_max_pkt_per_xfer_rcvd = num_pkts;
-			dev_kfree_skb_any(skb);
-			return 0;
-		}
-
 		if (skb->len < sizeof *hdr) {
 			pr_err("invalid rndis pkt: skblen:%u hdr_len:%u",
 					skb->len, sizeof *hdr);
@@ -1115,7 +1107,8 @@
 
 		skb_pull(skb, data_offset + 8);
 
-		if (msg_len == skb->len) {
+		if (data_len == skb->len ||
+				data_len == (skb->len - 1)) {
 			skb_trim(skb, data_len);
 			break;
 		}
diff --git a/drivers/usb/gadget/u_bam_data.c b/drivers/usb/gadget/u_bam_data.c
index 081a09c..c638164 100644
--- a/drivers/usb/gadget/u_bam_data.c
+++ b/drivers/usb/gadget/u_bam_data.c
@@ -178,6 +178,15 @@
 reenable_eps:
 	/* Re-Enable the relevant EPs, if EPs were originally enabled */
 	if (reenable_eps) {
+		if (config_ep_by_speed(port->port_usb->cdev->gadget,
+			port->port_usb->func, port->port_usb->in) ||
+		    config_ep_by_speed(port->port_usb->cdev->gadget,
+			port->port_usb->func, port->port_usb->out)) {
+			pr_err("%s: config_ep_by_speed failed", __func__);
+				port->port_usb->in->desc = NULL;
+				port->port_usb->out->desc = NULL;
+				return -EINVAL;
+		}
 		ret = usb_ep_enable(port->port_usb->in);
 		if (ret) {
 			pr_err("%s: usb_ep_enable failed eptype:IN ep:%p",
diff --git a/drivers/usb/gadget/u_bam_data.h b/drivers/usb/gadget/u_bam_data.h
index 486191b5..5ce678d 100644
--- a/drivers/usb/gadget/u_bam_data.h
+++ b/drivers/usb/gadget/u_bam_data.h
@@ -23,6 +23,7 @@
 
 struct data_port {
 	struct usb_composite_dev	*cdev;
+	struct usb_function		*func;
 	struct usb_ep			*in;
 	struct usb_ep			*out;
 };
diff --git a/drivers/usb/gadget/u_ether.c b/drivers/usb/gadget/u_ether.c
index dbffa4e..9961d00 100644
--- a/drivers/usb/gadget/u_ether.c
+++ b/drivers/usb/gadget/u_ether.c
@@ -71,6 +71,7 @@
 
 	unsigned		header_len;
 	unsigned int		ul_max_pkts_per_xfer;
+	unsigned int		dl_max_pkts_per_xfer;
 	struct sk_buff		*(*wrap)(struct gether *, struct sk_buff *skb);
 	int			(*unwrap)(struct gether *,
 						struct sk_buff *skb,
@@ -585,12 +586,12 @@
 	return cdc_filter & USB_CDC_PACKET_TYPE_PROMISCUOUS;
 }
 
-static void alloc_tx_buffer(struct eth_dev *dev)
+static int alloc_tx_buffer(struct eth_dev *dev)
 {
 	struct list_head	*act;
 	struct usb_request	*req;
 
-	dev->tx_req_bufsize = (TX_SKB_HOLD_THRESHOLD *
+	dev->tx_req_bufsize = (dev->dl_max_pkts_per_xfer *
 				(dev->net->mtu
 				+ sizeof(struct ethhdr)
 				/* size of rndis_packet_msg_type */
@@ -602,7 +603,19 @@
 		if (!req->buf)
 			req->buf = kmalloc(dev->tx_req_bufsize,
 						GFP_ATOMIC);
+			if (!req->buf)
+				goto free_buf;
 	}
+	return 0;
+
+free_buf:
+	/* tx_req_bufsize = 0 retries mem alloc on next eth_start_xmit */
+	dev->tx_req_bufsize = 0;
+	list_for_each(act, &dev->tx_reqs) {
+		req = container_of(act, struct usb_request, list);
+		kfree(req->buf);
+	}
+	return -ENOMEM;
 }
 
 static netdev_tx_t eth_start_xmit(struct sk_buff *skb,
@@ -634,8 +647,11 @@
 	}
 
 	/* Allocate memory for tx_reqs to support multi packet transfer */
-	if (multi_pkt_xfer && !dev->tx_req_bufsize)
-		alloc_tx_buffer(dev);
+	if (multi_pkt_xfer && !dev->tx_req_bufsize) {
+		retval = alloc_tx_buffer(dev);
+		if (retval < 0)
+			return -ENOMEM;
+	}
 
 	/* apply outgoing CDC or RNDIS filters */
 	if (!is_promisc(cdc_filter)) {
@@ -704,7 +720,7 @@
 		dev_kfree_skb_any(skb);
 
 		spin_lock_irqsave(&dev->req_lock, flags);
-		if (dev->tx_skb_hold_count < TX_SKB_HOLD_THRESHOLD) {
+		if (dev->tx_skb_hold_count < dev->dl_max_pkts_per_xfer) {
 			if (dev->no_tx_req_used > TX_REQ_THRESHOLD) {
 				list_add(&req->list, &dev->tx_reqs);
 				spin_unlock_irqrestore(&dev->req_lock, flags);
@@ -1082,6 +1098,7 @@
 		dev->unwrap = link->unwrap;
 		dev->wrap = link->wrap;
 		dev->ul_max_pkts_per_xfer = link->ul_max_pkts_per_xfer;
+		dev->dl_max_pkts_per_xfer = link->dl_max_pkts_per_xfer;
 
 		spin_lock(&dev->lock);
 		dev->tx_skb_hold_count = 0;
diff --git a/drivers/usb/gadget/u_ether.h b/drivers/usb/gadget/u_ether.h
index 7040ab0..05984d8 100644
--- a/drivers/usb/gadget/u_ether.h
+++ b/drivers/usb/gadget/u_ether.h
@@ -55,8 +55,7 @@
 	u32				fixed_in_len;
 
 	unsigned			ul_max_pkts_per_xfer;
-/* Max number of SKB packets to be used to create Multi Packet RNDIS */
-#define TX_SKB_HOLD_THRESHOLD		3
+	unsigned			dl_max_pkts_per_xfer;
 	bool				multi_pkt_xfer;
 	struct sk_buff			*(*wrap)(struct gether *port,
 						struct sk_buff *skb);
diff --git a/drivers/usb/gadget/u_rmnet_ctrl_smd.c b/drivers/usb/gadget/u_rmnet_ctrl_smd.c
index caea4ef..5a34679 100644
--- a/drivers/usb/gadget/u_rmnet_ctrl_smd.c
+++ b/drivers/usb/gadget/u_rmnet_ctrl_smd.c
@@ -604,6 +604,11 @@
 
 	pr_debug("%s: requested ports:%d\n", __func__, count);
 
+	if (client_num >= NR_CTRL_CLIENTS) {
+		pr_err("%s: Invalid client:%d\n", __func__, client_num);
+		return -EINVAL;
+	}
+
 	if (!count || count > MAX_CTRL_PER_CLIENT) {
 		pr_err("%s: Invalid num of ports count:%d\n",
 				__func__, count);
diff --git a/drivers/usb/gadget/u_sdio.c b/drivers/usb/gadget/u_sdio.c
index a0cdde2..52b707e 100644
--- a/drivers/usb/gadget/u_sdio.c
+++ b/drivers/usb/gadget/u_sdio.c
@@ -232,7 +232,7 @@
 {
 	unsigned	avail;
 	char		*packet;
-	unsigned	size = req->actual;
+	unsigned	size;
 	unsigned	n;
 	int		ret = 0;
 
@@ -271,6 +271,7 @@
 		return -ENODEV;
 	}
 
+	size = req->actual;
 	packet = req->buf;
 	n = port->n_read;
 	if (n) {
diff --git a/drivers/usb/host/ehci-msm-hsic.c b/drivers/usb/host/ehci-msm-hsic.c
index d1d0f91..c5304e1 100644
--- a/drivers/usb/host/ehci-msm-hsic.c
+++ b/drivers/usb/host/ehci-msm-hsic.c
@@ -752,6 +752,19 @@
 		return -EBUSY;
 	}
 
+	if (pdata->consider_ipa_handshake) {
+		dev_dbg(mehci->dev, "%s:Wait for resources release\n",
+			__func__);
+		if (!msm_bam_hsic_lpm_ok()) {
+			dev_dbg(mehci->dev, "%s:Prod+Cons not released\n",
+			__func__);
+			enable_irq(hcd->irq);
+			return -EBUSY;
+		}
+		dev_dbg(mehci->dev, "%s:Prod+Cons resources released\n",
+			__func__);
+	}
+
 	/*
 	 * PHY may take some time or even fail to enter into low power
 	 * mode (LPM). Hence poll for 500 msec and reset the PHY and link
@@ -829,7 +842,7 @@
 
 	wake_unlock(&mehci->wlock);
 
-	dev_dbg(mehci->dev, "HSIC-USB in low power mode\n");
+	dev_info(mehci->dev, "HSIC-USB in low power mode\n");
 
 	return 0;
 }
@@ -848,6 +861,14 @@
 		return 0;
 	}
 
+	if (pdata->consider_ipa_handshake) {
+		dev_dbg(mehci->dev, "%s:Wait for producer resource\n",
+			__func__);
+		msm_bam_wait_for_hsic_prod_granted();
+		dev_dbg(mehci->dev, "%s:Producer resource obtained\n",
+			__func__);
+	}
+
 	/* Handles race with Async interrupt */
 	disable_irq(hcd->irq);
 
@@ -933,7 +954,13 @@
 	}
 
 	enable_irq(hcd->irq);
-	dev_dbg(mehci->dev, "HSIC-USB exited from low power mode\n");
+	dev_info(mehci->dev, "HSIC-USB exited from low power mode\n");
+
+	if (pdata->consider_ipa_handshake) {
+		dev_dbg(mehci->dev, "%s:Notify usb bam on resume complete\n",
+			__func__);
+		msm_bam_hsic_notify_on_resume();
+	}
 
 	return 0;
 }
@@ -1035,6 +1062,7 @@
 {
 	struct ehci_hcd *ehci = hcd_to_ehci(hcd);
 	struct msm_hsic_hcd *mehci = hcd_to_hsic(hcd);
+	struct msm_hsic_host_platform_data *pdata = mehci->dev->platform_data;
 	int retval;
 
 	mehci->timer = USB_HS_GPTIMER_BASE;
@@ -1065,8 +1093,14 @@
 
 	/* bursts of unspecified length. */
 	writel_relaxed(0, USB_AHBBURST);
-	/* Use the AHB transactor */
-	writel_relaxed(0x08, USB_AHBMODE);
+
+	/* Use the AHB transactor and configure async bridge bypass */
+#define MSM_USB_ASYNC_BRIDGE_BYPASS BIT(31)
+	if (pdata->ahb_async_bridge_bypass)
+		writel_relaxed(0x08 | MSM_USB_ASYNC_BRIDGE_BYPASS, USB_AHBMODE);
+	else
+		writel_relaxed(0x08, USB_AHBMODE);
+
 	/* Disable streaming mode and select host mode */
 	writel_relaxed(0x13, USB_USBMODE);
 
@@ -1853,6 +1887,10 @@
 				"qcom,enable-hbm");
 	pdata->disable_park_mode = (of_property_read_bool(node,
 				"qcom,disable-park-mode"));
+	pdata->consider_ipa_handshake = (of_property_read_bool(node,
+				"hsic,consider-ipa-handshake"));
+	pdata->ahb_async_bridge_bypass = of_property_read_bool(node,
+				"qcom,ahb-async-bridge-bypass");
 
 	return pdata;
 }
@@ -2092,6 +2130,8 @@
 	if (mehci->enable_hbm)
 		hbm_init(hcd, pdata->disable_park_mode);
 
+	msm_bam_set_hsic_host_dev(&pdev->dev);
+
 	return 0;
 
 destroy_wq:
@@ -2115,6 +2155,8 @@
 	struct msm_hsic_hcd *mehci = hcd_to_hsic(hcd);
 	struct msm_hsic_host_platform_data *pdata = mehci->dev->platform_data;
 
+	msm_bam_set_hsic_host_dev(NULL);
+
 	/* 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);
diff --git a/drivers/video/msm/mdss/dsi_panel_v2.c b/drivers/video/msm/mdss/dsi_panel_v2.c
index e46ea3b..bb5d3ca 100644
--- a/drivers/video/msm/mdss/dsi_panel_v2.c
+++ b/drivers/video/msm/mdss/dsi_panel_v2.c
@@ -104,8 +104,14 @@
 
 	kfree(panel_private->on_cmds);
 	kfree(panel_private->off_cmds);
+
 	kfree(panel_private);
 	panel_private = NULL;
+
+	if (bl_led_trigger) {
+		led_trigger_unregister_simple(bl_led_trigger);
+		bl_led_trigger = NULL;
+	}
 }
 int dsi_panel_power(int enable)
 {
diff --git a/drivers/video/msm/mdss/mdp3.c b/drivers/video/msm/mdss/mdp3.c
index 5223e66..65c9e90 100644
--- a/drivers/video/msm/mdss/mdp3.c
+++ b/drivers/video/msm/mdss/mdp3.c
@@ -290,12 +290,16 @@
 static void mdp3_bus_scale_unregister(void)
 {
 	int i;
+
+	if (!mdp3_res->bus_handle)
+		return;
+
 	for (i = 0; i < MDP3_BUS_HANDLE_MAX; i++) {
 		pr_debug("unregister index=%d bus_handle=%x\n",
 			i, mdp3_res->bus_handle[i].handle);
 		if (mdp3_res->bus_handle[i].handle) {
 			msm_bus_scale_unregister_client(
-			   mdp3_res->bus_handle[i].handle);
+				mdp3_res->bus_handle[i].handle);
 			mdp3_res->bus_handle[i].handle = 0;
 		}
 	}
@@ -484,11 +488,20 @@
 
 static void mdp3_clk_remove(void)
 {
-	clk_put(mdp3_res->clocks[MDP3_CLK_AHB]);
-	clk_put(mdp3_res->clocks[MDP3_CLK_CORE]);
-	clk_put(mdp3_res->clocks[MDP3_CLK_VSYNC]);
-	clk_put(mdp3_res->clocks[MDP3_CLK_LCDC]);
-	clk_put(mdp3_res->clocks[MDP3_CLK_DSI]);
+	if (!IS_ERR_OR_NULL(mdp3_res->clocks[MDP3_CLK_AHB]))
+		clk_put(mdp3_res->clocks[MDP3_CLK_AHB]);
+
+	if (!IS_ERR_OR_NULL(mdp3_res->clocks[MDP3_CLK_CORE]))
+		clk_put(mdp3_res->clocks[MDP3_CLK_CORE]);
+
+	if (!IS_ERR_OR_NULL(mdp3_res->clocks[MDP3_CLK_VSYNC]))
+		clk_put(mdp3_res->clocks[MDP3_CLK_VSYNC]);
+
+	if (!IS_ERR_OR_NULL(mdp3_res->clocks[MDP3_CLK_LCDC]))
+		clk_put(mdp3_res->clocks[MDP3_CLK_LCDC]);
+
+	if (!IS_ERR_OR_NULL(mdp3_res->clocks[MDP3_CLK_DSI]))
+		clk_put(mdp3_res->clocks[MDP3_CLK_DSI]);
 }
 
 int mdp3_clk_enable(int enable)
@@ -519,6 +532,7 @@
 		return ret;
 	}
 	disable_irq(mdp3_res->irq);
+	mdp3_res->irq_registered = true;
 	return 0;
 }
 
@@ -556,7 +570,8 @@
 	struct mdp3_iommu_ctx_map *context_map;
 	struct mdp3_iommu_domain_map *domain_map;
 
-	if (context >= MDP3_IOMMU_CTX_MAX)
+	if (!mdp3_res->iommu_contexts ||
+		context >= MDP3_IOMMU_CTX_MAX)
 		return -EINVAL;
 
 	context_map = mdp3_res->iommu_contexts + context;
@@ -595,10 +610,13 @@
 
 		mdp3_iommu_domains[i].domain_idx = domain_idx;
 		mdp3_iommu_domains[i].domain = msm_get_iommu_domain(domain_idx);
-		if (!mdp3_iommu_domains[i].domain) {
+		if (IS_ERR_OR_NULL(mdp3_iommu_domains[i].domain)) {
 			pr_err("unable to get iommu domain(%d)\n",
 				domain_idx);
-			return -EINVAL;
+			if (!mdp3_iommu_domains[i].domain)
+				return -EINVAL;
+			else
+				return PTR_ERR(mdp3_iommu_domains[i].domain);
 		}
 		iommu_set_fault_handler(mdp3_iommu_domains[i].domain,
 					mdp3_iommu_fault_handler,
@@ -623,10 +641,13 @@
 		mdp3_iommu_contexts[i].ctx =
 			msm_iommu_get_ctx(mdp3_iommu_contexts[i].ctx_name);
 
-		if (!mdp3_iommu_contexts[i].ctx) {
+		if (IS_ERR_OR_NULL(mdp3_iommu_contexts[i].ctx)) {
 			pr_warn("unable to get iommu ctx(%s)\n",
 				mdp3_iommu_contexts[i].ctx_name);
-			return -EINVAL;
+			if (!mdp3_iommu_contexts[i].ctx)
+				return -EINVAL;
+			else
+				return PTR_ERR(mdp3_iommu_contexts[i].ctx);
 		}
 	}
 
@@ -653,6 +674,19 @@
 	return ret;
 }
 
+void mdp3_iommu_deinit(void)
+{
+	int i;
+
+	if (!mdp3_res->domains)
+		return;
+
+	for (i = 0; i < MDP3_IOMMU_DOMAIN_MAX; i++) {
+		if (!IS_ERR_OR_NULL(mdp3_res->domains[i].domain))
+			msm_unregister_domain(mdp3_res->domains[i].domain);
+	}
+}
+
 static int mdp3_check_version(void)
 {
 	int rc;
@@ -742,6 +776,21 @@
 	return rc;
 }
 
+static void mdp3_res_deinit(void)
+{
+	mdp3_bus_scale_unregister();
+	mdp3_iommu_dettach(MDP3_IOMMU_CTX_DMA_0);
+	mdp3_iommu_deinit();
+
+	if (!IS_ERR_OR_NULL(mdp3_res->ion_client))
+		ion_client_destroy(mdp3_res->ion_client);
+
+	mdp3_clk_remove();
+
+	if (mdp3_res->irq_registered)
+		devm_free_irq(&mdp3_res->pdev->dev, mdp3_res->irq, mdp3_res);
+}
+
 static int mdp3_parse_dt(struct platform_device *pdev)
 {
 	struct resource *res;
@@ -847,7 +896,10 @@
 		data->srcp_ihdl = ion_import_dma_buf(iclient, img->memory_id);
 		if (IS_ERR_OR_NULL(data->srcp_ihdl)) {
 			pr_err("error on ion_import_fd\n");
-			ret = PTR_ERR(data->srcp_ihdl);
+			if (!data->srcp_ihdl)
+				ret = -EINVAL;
+			else
+				ret = PTR_ERR(data->srcp_ihdl);
 			data->srcp_ihdl = NULL;
 			return ret;
 		}
@@ -1002,6 +1054,11 @@
 
 probe_done:
 	if (IS_ERR_VALUE(rc)) {
+		mdp3_res_deinit();
+
+		if (mdp3_res->mdp_base)
+			devm_iounmap(&pdev->dev, mdp3_res->mdp_base);
+
 		devm_kfree(&pdev->dev, mdp3_res);
 		mdp3_res = NULL;
 	}
diff --git a/drivers/video/msm/mdss/mdp3.h b/drivers/video/msm/mdss/mdp3.h
index 878fe25..e52f7bc 100644
--- a/drivers/video/msm/mdss/mdp3.h
+++ b/drivers/video/msm/mdss/mdp3.h
@@ -119,6 +119,8 @@
 	u32 irq_mask;
 	struct mdp3_intr_cb callbacks[MDP3_MAX_INTR];
 
+	int irq_registered;
+
 	struct early_suspend suspend_handler;
 };
 
diff --git a/drivers/video/msm/mdss/mdp3_ctrl.c b/drivers/video/msm/mdss/mdp3_ctrl.c
index 3d990c2..9c572a5 100644
--- a/drivers/video/msm/mdss/mdp3_ctrl.c
+++ b/drivers/video/msm/mdss/mdp3_ctrl.c
@@ -24,10 +24,12 @@
 #include "mdp3.h"
 #include "mdp3_ppp.h"
 
+#define MDP_CORE_CLK_RATE	100000000
 #define MDP_VSYNC_CLK_RATE	19200000
 #define VSYNC_PERIOD 16
 
 static void mdp3_ctrl_pan_display(struct msm_fb_data_type *mfd);
+static int mdp3_overlay_unset(struct msm_fb_data_type *mfd, int ndx);
 
 static void mdp3_bufq_init(struct mdp3_buffer_queue *bufq)
 {
@@ -191,13 +193,9 @@
 
 	mdp3_session = (struct mdp3_session_data *)mfd->mdp.private1;
 
-	rc = wait_for_completion_interruptible_timeout(
-				&mdp3_session->vsync_comp,
-				msecs_to_jiffies(VSYNC_PERIOD * 5));
-	if (rc <= 0) {
-		pr_warn("vsync wait on fb%d interrupted (%d)\n",
-			mfd->index, rc);
-	}
+	rc = wait_for_completion_interruptible(&mdp3_session->vsync_comp);
+	if (rc < 0)
+		return rc;
 
 	spin_lock_irqsave(&mdp3_session->vsync_lock, flag);
 	vsync_ticks = ktime_to_ns(mdp3_session->vsync_time);
@@ -240,17 +238,8 @@
 {
 	int rc = 0;
 	if (status) {
-		struct mdss_panel_info *panel_info = mfd->panel_info;
-		unsigned long core_clk;
-		int vtotal;
-		vtotal = panel_info->lcdc.v_back_porch +
-			panel_info->lcdc.v_front_porch +
-			panel_info->lcdc.v_pulse_width +
-			panel_info->yres;
-		core_clk = panel_info->xres * panel_info->yres;
-		core_clk *= panel_info->mipi.frame_rate;
-		core_clk = (core_clk / panel_info->yres) * vtotal;
-		mdp3_clk_set_rate(MDP3_CLK_CORE, core_clk);
+
+		mdp3_clk_set_rate(MDP3_CLK_CORE, MDP_CORE_CLK_RATE);
 		mdp3_clk_set_rate(MDP3_CLK_VSYNC, MDP_VSYNC_CLK_RATE);
 
 		rc = mdp3_clk_enable(true);
@@ -515,8 +504,9 @@
 		pr_err("mdp clock resource release failed\n");
 off_error:
 	mdp3_session->status = 0;
-
 	mutex_unlock(&mdp3_session->lock);
+	if (mdp3_session->overlay.id != MSMFB_NEW_REQUEST)
+		mdp3_overlay_unset(mfd, mdp3_session->overlay.id);
 	return 0;
 }
 
diff --git a/drivers/video/msm/mdss/mdp3_dma.c b/drivers/video/msm/mdss/mdp3_dma.c
index a09f503..fa2e9eb 100644
--- a/drivers/video/msm/mdss/mdp3_dma.c
+++ b/drivers/video/msm/mdss/mdp3_dma.c
@@ -218,7 +218,7 @@
 	 * NOTE: MDP_DMA_P_FETCH_CFG: max_burst_size need to use value 4, not
 	 * the default 16 for MDP hang issue workaround
 	 */
-	MDP3_REG_WRITE(MDP3_REG_DMA_P_FETCH_CFG, 0x10);
+	MDP3_REG_WRITE(MDP3_REG_DMA_P_FETCH_CFG, 0x20);
 	MDP3_REG_WRITE(MDP3_REG_PRIMARY_RD_PTR_IRQ, 0x10);
 
 	dma->source_config = *source_config;
@@ -809,6 +809,7 @@
 		temp |= BIT(2);
 	MDP3_REG_WRITE(MDP3_REG_DSI_VIDEO_CTL_POLARITY, temp);
 
+	MDP3_REG_WRITE(MDP3_REG_DSI_VIDEO_UNDERFLOW_CTL, 0x800000ff);
 	return 0;
 }
 
diff --git a/drivers/video/msm/mdss/mdss_debug.c b/drivers/video/msm/mdss/mdss_debug.c
index 0918db1..13fba26 100644
--- a/drivers/video/msm/mdss/mdss_debug.c
+++ b/drivers/video/msm/mdss/mdss_debug.c
@@ -14,6 +14,7 @@
 #define pr_fmt(fmt)	"%s: " fmt, __func__
 
 #include <linux/debugfs.h>
+#include <linux/iopoll.h>
 #include <linux/kernel.h>
 #include <linux/list.h>
 #include <linux/printk.h>
@@ -438,3 +439,151 @@
 
 	return 0;
 }
+
+static struct mdss_mdp_misr_map {
+	u32 ctrl_reg;
+	u32 value_reg;
+	u32 crc_op_mode;
+	u32 crc_index;
+	u32 crc_value[MISR_CRC_BATCH_SIZE];
+} mdss_mdp_misr_table[DISPLAY_MISR_MAX] = {
+	[DISPLAY_MISR_DSI0] = {
+		.ctrl_reg = MDSS_MDP_LP_MISR_CTRL_DSI0,
+		.value_reg = MDSS_MDP_LP_MISR_SIGN_DSI0,
+	},
+	[DISPLAY_MISR_DSI1] = {
+		.ctrl_reg = MDSS_MDP_LP_MISR_CTRL_DSI1,
+		.value_reg = MDSS_MDP_LP_MISR_SIGN_DSI1,
+	},
+	[DISPLAY_MISR_EDP] = {
+		.ctrl_reg = MDSS_MDP_LP_MISR_CTRL_EDP,
+		.value_reg = MDSS_MDP_LP_MISR_SIGN_EDP,
+	},
+	[DISPLAY_MISR_HDMI] = {
+		.ctrl_reg = MDSS_MDP_LP_MISR_CTRL_HDMI,
+		.value_reg = MDSS_MDP_LP_MISR_SIGN_HDMI,
+	},
+};
+
+static inline struct mdss_mdp_misr_map *mdss_misr_get_map(u32 block_id)
+{
+	struct mdss_mdp_misr_map *map;
+
+	if (block_id > DISPLAY_MISR_LCDC) {
+		pr_err("MISR Block id (%d) out of range\n", block_id);
+		return NULL;
+	}
+
+	map = mdss_mdp_misr_table + block_id;
+	if ((map->ctrl_reg == 0) || (map->value_reg == 0)) {
+		pr_err("MISR Block id (%d) config not found\n", block_id);
+		return NULL;
+	}
+
+	return map;
+}
+
+int mdss_misr_crc_set(struct mdss_data_type *mdata, struct mdp_misr *req)
+{
+	struct mdss_mdp_misr_map *map;
+	u32 config = 0;
+
+	map = mdss_misr_get_map(req->block_id);
+	if (!map) {
+		pr_err("Invalid MISR Block=%d\n", req->block_id);
+		return -EINVAL;
+	}
+
+	map->crc_op_mode = req->crc_op_mode;
+	memset(map->crc_value, 0, sizeof(map->crc_value));
+
+	pr_debug("MISR Config (BlockId %d) (Frame Count = %d)\n",
+		req->block_id, req->frame_count);
+
+	config = (MDSS_MDP_LP_MISR_CTRL_FRAME_COUNT_MASK & req->frame_count) |
+			(MDSS_MDP_LP_MISR_CTRL_ENABLE);
+
+	writel_relaxed(MDSS_MDP_LP_MISR_CTRL_STATUS_CLEAR,
+			mdata->mdp_base + map->ctrl_reg);
+	/* ensure clear is done */
+	wmb();
+	if (MISR_OP_BM == map->crc_op_mode) {
+		writel_relaxed(MISR_CRC_BATCH_CFG,
+			mdata->mdp_base + map->ctrl_reg);
+	} else {
+		writel_relaxed(config,
+			mdata->mdp_base + map->ctrl_reg);
+
+		config = readl_relaxed(mdata->mdp_base + map->ctrl_reg);
+		pr_debug("MISR_CTRL = 0x%x", config);
+	}
+	return 0;
+}
+
+int mdss_misr_crc_get(struct mdss_data_type *mdata, struct mdp_misr *resp)
+{
+	struct mdss_mdp_misr_map *map;
+	u32 status;
+	int ret = 0;
+	int i;
+
+	map = mdss_misr_get_map(resp->block_id);
+	if (!map) {
+		pr_err("Invalid MISR Block=%d\n", resp->block_id);
+		return -EINVAL;
+	}
+
+	switch (map->crc_op_mode) {
+	case MISR_OP_SFM:
+	case MISR_OP_MFM:
+		ret = readl_poll_timeout(mdata->mdp_base + map->ctrl_reg,
+				status, status & MDSS_MDP_LP_MISR_CTRL_STATUS,
+				MISR_POLL_SLEEP, MISR_POLL_TIMEOUT);
+
+		pr_debug("Status of Get MISR_CTRL = 0x%x", status);
+		if (ret == 0) {
+			resp->crc_value[0] =
+				readl_relaxed(mdata->mdp_base + map->value_reg);
+			pr_debug("CRC %d=0x%x\n", resp->block_id,
+					resp->crc_value[0]);
+		} else {
+			pr_warn("MISR %d busy with status 0x%x\n",
+					resp->block_id, status);
+		}
+		break;
+	case MISR_OP_BM:
+		for (i = 0; i < MISR_CRC_BATCH_SIZE; i++)
+			resp->crc_value[i] = map->crc_value[i];
+		map->crc_index = 0;
+		break;
+	default:
+		ret = -ENOSYS;
+		break;
+	}
+
+	return ret;
+}
+
+/* This function is expected to be called from interrupt context */
+void mdss_misr_crc_collect(struct mdss_data_type *mdata, int block_id)
+{
+	struct mdss_mdp_misr_map *map;
+	u32 status, config;
+
+	map = mdss_misr_get_map(block_id);
+	if (!map || (map->crc_op_mode != MISR_OP_BM))
+		return;
+
+	config = MISR_CRC_BATCH_CFG;
+
+	status = readl_relaxed(mdata->mdp_base + map->ctrl_reg);
+	if (status & MDSS_MDP_LP_MISR_CTRL_STATUS) {
+		map->crc_value[map->crc_index] =
+			readl_relaxed(mdata->mdp_base + map->value_reg);
+		map->crc_index++;
+		if (map->crc_index == MISR_CRC_BATCH_SIZE)
+			map->crc_index = 0;
+		config |= MDSS_MDP_LP_MISR_CTRL_STATUS_CLEAR;
+	}
+	writel_relaxed(config, mdata->mdp_base + map->ctrl_reg);
+}
diff --git a/drivers/video/msm/mdss/mdss_debug.h b/drivers/video/msm/mdss/mdss_debug.h
index 167fa8a..29eb16c 100644
--- a/drivers/video/msm/mdss/mdss_debug.h
+++ b/drivers/video/msm/mdss/mdss_debug.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
@@ -16,24 +16,30 @@
 
 #include "mdss.h"
 
+#define MISR_POLL_SLEEP			2000
+#define MISR_POLL_TIMEOUT		32000
+#define MISR_CRC_BATCH_SIZE		32
+#define MISR_CRC_BATCH_CFG		0x101
+
 #ifdef CONFIG_DEBUG_FS
 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,
 				    size_t max_offset);
+int mdss_misr_crc_set(struct mdss_data_type *mdata, struct mdp_misr *req);
+int mdss_misr_crc_get(struct mdss_data_type *mdata, struct mdp_misr *resp);
+void mdss_misr_crc_collect(struct mdss_data_type *mdata, int block_id);
 #else
-static inline int mdss_debugfs_init(struct mdss_data_type *mdata)
-{
-	return 0;
-}
+static inline int mdss_debugfs_init(struct mdss_data_type *mdata) { return 0; }
 static inline int mdss_debugfs_remove(struct mdss_data_type *mdata)
-{
-	return 0;
-}
+{ return 0; }
 static inline int mdss_debug_register_base(const char *name, void __iomem *base,
-				    size_t max_offset)
-{
-	return 0;
-}
+			     size_t max_offset) { return 0; }
+static inline int mdss_misr_crc_set(struct mdss_data_type *mdata,
+		      struct mdp_misr *reg) { return 0; }
+static inline int mdss_misr_crc_get(struct mdss_data_type *mdata,
+		      struct mdp_misr *resp) { return 0; }
+static inline void mdss_misr_crc_collect(struct mdss_data_type *mdata,
+			   int block_id) { }
 #endif
 #endif /* MDSS_DEBUG_H */
diff --git a/drivers/video/msm/mdss/mdss_dsi.c b/drivers/video/msm/mdss/mdss_dsi.c
index c663170..afabc20 100644
--- a/drivers/video/msm/mdss/mdss_dsi.c
+++ b/drivers/video/msm/mdss/mdss_dsi.c
@@ -418,6 +418,9 @@
 
 	/* disable DSI phy */
 	mdss_dsi_phy_enable(ctrl_pdata->ctrl_base, 0);
+
+	mdss_dsi_disable_bus_clocks(ctrl_pdata);
+
 	ret = mdss_dsi_panel_power_on(pdata, 0);
 	if (ret) {
 		pr_err("%s: Panel power off failed\n", __func__);
@@ -429,42 +432,6 @@
 	return ret;
 }
 
-int mdss_dsi_cont_splash_on(struct mdss_panel_data *pdata)
-{
-	int ret = 0;
-	struct mipi_panel_info *mipi;
-	struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
-
-	pr_info("%s:%d DSI on for continuous splash.\n", __func__, __LINE__);
-
-	if (pdata == NULL) {
-		pr_err("%s: Invalid input data\n", __func__);
-		return -EINVAL;
-	}
-
-	mipi = &pdata->panel_info.mipi;
-
-	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);
-
-	WARN(ctrl_pdata->panel_state != UNKNOWN_STATE,
-			"incorrect panel state=%d\n", ctrl_pdata->panel_state);
-
-	mdss_dsi_sw_reset(pdata);
-	mdss_dsi_host_init(mipi, pdata);
-
-	mdss_dsi_op_mode_config(mipi->mode, pdata);
-
-	ctrl_pdata->panel_state = PANEL_ON;
-
-	pr_debug("%s-:End\n", __func__);
-	return ret;
-}
-
-
 int mdss_dsi_on(struct mdss_panel_data *pdata)
 {
 	int ret = 0;
@@ -502,6 +469,14 @@
 
 	pdata->panel_info.panel_power_on = 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);
+		return ret;
+	}
+
 	mdss_dsi_phy_sw_reset((ctrl_pdata->ctrl_base));
 	mdss_dsi_phy_init(pdata);
 
@@ -607,14 +582,14 @@
 				panel_data);
 	mipi  = &pdata->panel_info.mipi;
 
-	if (ctrl_pdata->panel_state != PANEL_ON) {
+	if (!(ctrl_pdata->ctrl_state & CTRL_STATE_PANEL_INIT)) {
 		ret = ctrl_pdata->on(pdata);
 		if (ret) {
 			pr_err("%s: unable to initialize the panel\n",
 							__func__);
 			return ret;
 		}
-		ctrl_pdata->panel_state = PANEL_ON;
+		ctrl_pdata->ctrl_state |= CTRL_STATE_PANEL_INIT;
 	}
 	mdss_dsi_op_mode_config(mipi->mode, pdata);
 
@@ -640,18 +615,58 @@
 
 	mdss_dsi_op_mode_config(DSI_CMD_MODE, pdata);
 
-	if (ctrl_pdata->panel_state == PANEL_ON) {
+	if (ctrl_pdata->ctrl_state & CTRL_STATE_PANEL_INIT) {
 		ret = ctrl_pdata->off(pdata);
 		if (ret) {
 			pr_err("%s: Panel OFF failed\n", __func__);
 			return ret;
 		}
-		ctrl_pdata->panel_state = PANEL_OFF;
+		ctrl_pdata->ctrl_state &= ~CTRL_STATE_PANEL_INIT;
 	}
 	pr_debug("%s-:End\n", __func__);
 	return ret;
 }
 
+int mdss_dsi_cont_splash_on(struct mdss_panel_data *pdata)
+{
+	int ret = 0;
+	struct mipi_panel_info *mipi;
+	struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
+
+	pr_info("%s:%d DSI on for continuous splash.\n", __func__, __LINE__);
+
+	if (pdata == NULL) {
+		pr_err("%s: Invalid input data\n", __func__);
+		return -EINVAL;
+	}
+
+	mipi = &pdata->panel_info.mipi;
+
+	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);
+
+	WARN((ctrl_pdata->ctrl_state & CTRL_STATE_PANEL_INIT),
+		"Incorrect Ctrl state=0x%x\n", ctrl_pdata->ctrl_state);
+
+	mdss_dsi_sw_reset(pdata);
+	mdss_dsi_host_init(mipi, pdata);
+
+	if (ctrl_pdata->on_cmds.link_state == DSI_LP_MODE) {
+		mdss_dsi_op_mode_config(DSI_CMD_MODE, pdata);
+		ret = mdss_dsi_unblank(pdata);
+		if (ret) {
+			pr_err("%s: unblank failed\n", __func__);
+			return ret;
+		}
+	}
+
+	pr_debug("%s-:End\n", __func__);
+	return ret;
+}
+
 static int mdss_dsi_event_handler(struct mdss_panel_data *pdata,
 				  int event, void *arg)
 {
@@ -673,6 +688,7 @@
 			rc = mdss_dsi_unblank(pdata);
 		break;
 	case MDSS_EVENT_PANEL_ON:
+		ctrl_pdata->ctrl_state |= CTRL_STATE_MDP_ACTIVE;
 		if (ctrl_pdata->on_cmds.link_state == DSI_HS_MODE)
 			rc = mdss_dsi_unblank(pdata);
 		break;
@@ -681,11 +697,13 @@
 			rc = mdss_dsi_blank(pdata);
 		break;
 	case MDSS_EVENT_PANEL_OFF:
+		ctrl_pdata->ctrl_state &= ~CTRL_STATE_MDP_ACTIVE;
 		if (ctrl_pdata->off_cmds.link_state == DSI_LP_MODE)
 			rc = mdss_dsi_blank(pdata);
 		rc = mdss_dsi_off(pdata);
 		break;
 	case MDSS_EVENT_CONT_SPLASH_FINISH:
+		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 {
@@ -701,6 +719,12 @@
 	case MDSS_EVENT_DSI_CMDLIST_KOFF:
 		mdss_dsi_cmdlist_commit(ctrl_pdata, 1);
 		break;
+	case MDSS_EVENT_CONT_SPLASH_BEGIN:
+		if (ctrl_pdata->off_cmds.link_state == DSI_HS_MODE) {
+			/* Panel is Enabled in Bootloader */
+			rc = mdss_dsi_blank(pdata);
+		}
+		break;
 	default:
 		pr_debug("%s: unhandled event=%d\n", __func__, event);
 		break;
@@ -1094,6 +1118,12 @@
 	 * register in mdp driver
 	 */
 
+	ctrl_pdata->pclk_rate = dsi_pclk_rate;
+	ctrl_pdata->byte_clk_rate = panel_data->panel_info.clk_rate / 8;
+	pr_debug("%s: pclk=%d, bclk=%d\n", __func__,
+			ctrl_pdata->pclk_rate, ctrl_pdata->byte_clk_rate);
+
+	ctrl_pdata->ctrl_state = CTRL_STATE_UNKNOWN;
 	cont_splash_enabled = of_property_read_bool(pdev->dev.of_node,
 			"qcom,cont-splash-enabled");
 	if (!cont_splash_enabled) {
@@ -1112,15 +1142,20 @@
 			pr_err("%s: Panel power on failed\n", __func__);
 			return rc;
 		}
-	}
 
-	ctrl_pdata->pclk_rate = dsi_pclk_rate;
-	ctrl_pdata->byte_clk_rate = panel_data->panel_info.clk_rate / 8;
-	pr_debug("%s: pclk=%d, bclk=%d\n", __func__,
-			ctrl_pdata->pclk_rate, ctrl_pdata->byte_clk_rate);
+		rc = mdss_dsi_enable_bus_clocks(ctrl_pdata);
+		if (rc) {
+			pr_err("%s: failed to enable bus clocks. rc=%d\n",
+				__func__, rc);
+			rc = mdss_dsi_panel_power_on(
+				&(ctrl_pdata->panel_data), 0);
+			return rc;
+		}
 
-	if (ctrl_pdata->panel_data.panel_info.cont_splash_enabled)
 		mdss_dsi_clk_ctrl(ctrl_pdata, 1);
+		ctrl_pdata->ctrl_state |=
+			(CTRL_STATE_PANEL_INIT | CTRL_STATE_MDP_ACTIVE);
+	}
 
 	rc = mdss_register_panel(ctrl_pdev, &(ctrl_pdata->panel_data));
 	if (rc) {
@@ -1145,7 +1180,6 @@
 		ctrl_pdata->ndx = 1;
 	}
 
-	ctrl_pdata->panel_state = UNKNOWN_STATE;
 	pr_debug("%s: Panal data initialized\n", __func__);
 	return 0;
 }
diff --git a/drivers/video/msm/mdss/mdss_dsi.h b/drivers/video/msm/mdss/mdss_dsi.h
index 602ed9e..f612751 100644
--- a/drivers/video/msm/mdss/mdss_dsi.h
+++ b/drivers/video/msm/mdss/mdss_dsi.h
@@ -84,16 +84,14 @@
 	UNKNOWN_CTRL,
 };
 
-enum dsi_ctrl_state {
+enum dsi_ctrl_op_mode {
 	DSI_LP_MODE,
 	DSI_HS_MODE,
 };
 
-enum dsi_panel_state {
-	UNKNOWN_STATE,
-	PANEL_ON,
-	PANEL_OFF,
-};
+#define CTRL_STATE_UNKNOWN		0x00
+#define CTRL_STATE_PANEL_INIT		BIT(0)
+#define CTRL_STATE_MDP_ACTIVE		BIT(1)
 
 #define DSI_NON_BURST_SYNCH_PULSE	0
 #define DSI_NON_BURST_SYNCH_EVENT	1
@@ -327,10 +325,12 @@
 	unsigned char *ctrl_base;
 	int reg_size;
 	u32 clk_cnt;
+	struct clk *ahb_clk;
+	struct clk *axi_clk;
 	struct clk *byte_clk;
 	struct clk *esc_clk;
 	struct clk *pixel_clk;
-	u8 panel_state;
+	u8 ctrl_state;
 	int irq_cnt;
 	int mdss_dsi_clk_on;
 	int rst_gpio;
@@ -409,6 +409,8 @@
 void mdss_dsi_clk_deinit(struct mdss_dsi_ctrl_pdata *ctrl_pdata);
 void mdss_dsi_prepare_clocks(struct mdss_dsi_ctrl_pdata *ctrl_pdata);
 void mdss_dsi_unprepare_clocks(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(unsigned char *ctrl_base, int on);
 void mdss_dsi_phy_init(struct mdss_panel_data *pdata);
diff --git a/drivers/video/msm/mdss/mdss_dsi_panel.c b/drivers/video/msm/mdss/mdss_dsi_panel.c
index 6b0f68e..05a84e3 100644
--- a/drivers/video/msm/mdss/mdss_dsi_panel.c
+++ b/drivers/video/msm/mdss/mdss_dsi_panel.c
@@ -189,6 +189,12 @@
 		msleep(20);
 		if (gpio_is_valid(ctrl_pdata->disp_en_gpio))
 			gpio_set_value((ctrl_pdata->disp_en_gpio), 1);
+		if (ctrl_pdata->ctrl_state & CTRL_STATE_PANEL_INIT) {
+			pr_debug("%s: Panel Not properly turned OFF\n",
+						__func__);
+			ctrl_pdata->ctrl_state &= ~CTRL_STATE_PANEL_INIT;
+			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))
diff --git a/drivers/video/msm/mdss/mdss_fb.c b/drivers/video/msm/mdss/mdss_fb.c
index e2d8cf6..fbd9ef6 100644
--- a/drivers/video/msm/mdss/mdss_fb.c
+++ b/drivers/video/msm/mdss/mdss_fb.c
@@ -127,7 +127,6 @@
 	return (ret > 0) ? 0 : ret;
 }
 
-#define MAX_BACKLIGHT_BRIGHTNESS 255
 static int lcd_backlight_registered;
 
 static void mdss_fb_set_bl_brightness(struct led_classdev *led_cdev,
@@ -136,13 +135,13 @@
 	struct msm_fb_data_type *mfd = dev_get_drvdata(led_cdev->dev->parent);
 	int bl_lvl;
 
-	if (value > MAX_BACKLIGHT_BRIGHTNESS)
-		value = MAX_BACKLIGHT_BRIGHTNESS;
+	if (value > MDSS_MAX_BL_BRIGHTNESS)
+		value = MDSS_MAX_BL_BRIGHTNESS;
 
 	/* This maps android backlight level 0 to 255 into
 	   driver backlight level 0 to bl_max with rounding */
 	bl_lvl = (2 * value * mfd->panel_info->bl_max +
-		  MAX_BACKLIGHT_BRIGHTNESS) / (2 * MAX_BACKLIGHT_BRIGHTNESS);
+		  MDSS_MAX_BL_BRIGHTNESS) / (2 * MDSS_MAX_BL_BRIGHTNESS);
 
 	if (!bl_lvl && value)
 		bl_lvl = 1;
@@ -154,7 +153,7 @@
 
 static struct led_classdev backlight_led = {
 	.name           = "lcd-backlight",
-	.brightness     = MAX_BACKLIGHT_BRIGHTNESS,
+	.brightness     = MDSS_MAX_BL_BRIGHTNESS,
 	.brightness_set = mdss_fb_set_bl_brightness,
 };
 
@@ -1725,7 +1724,7 @@
 
 	if (!mdp_instance) {
 		pr_err("mdss mdp resource not initialized yet\n");
-		return -ENODEV;
+		return -EPROBE_DEFER;
 	}
 
 	node = of_parse_phandle(pdev->dev.of_node, "qcom,mdss-fb-map", 0);
diff --git a/drivers/video/msm/mdss/mdss_hdmi_tx.c b/drivers/video/msm/mdss/mdss_hdmi_tx.c
index ab91320..287f2cd 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_tx.c
+++ b/drivers/video/msm/mdss/mdss_hdmi_tx.c
@@ -391,6 +391,10 @@
 		return rc;
 	}
 
+	if (hdmi_ctrl->mhl_max_pclk && hpd &&
+	    (!hdmi_ctrl->mhl_hpd_on || hdmi_ctrl->hpd_feature_on))
+		return 0;
+
 	if (0 == hpd && hdmi_ctrl->hpd_feature_on) {
 		rc = hdmi_tx_sysfs_enable_hpd(hdmi_ctrl, false);
 	} else if (1 == hpd && !hdmi_ctrl->hpd_feature_on) {
@@ -614,6 +618,37 @@
 	}
 } /* hdmi_tx_set_audio_switch_node */
 
+static int hdmi_tx_config_avmute(struct hdmi_tx_ctrl *hdmi_ctrl, int set)
+{
+	struct dss_io_data *io;
+
+	if (!hdmi_ctrl) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		return -EINVAL;
+	}
+
+	io = &hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO];
+	if (!io->base) {
+		DEV_ERR("%s: Core io is not initialized\n", __func__);
+		return -EINVAL;
+	}
+
+	if (set)
+		DSS_REG_W(io, HDMI_GC,
+			DSS_REG_R(io, HDMI_GC) | BIT(0));
+	else
+		DSS_REG_W(io, HDMI_GC,
+			DSS_REG_R(io, HDMI_GC) & ~BIT(0));
+
+	/* Enable AV Mute tranmission here */
+	DSS_REG_W(io, HDMI_VBI_PKT_CTRL,
+		DSS_REG_R(io, HDMI_VBI_PKT_CTRL) | (BIT(4) & BIT(5)));
+
+	DEV_DBG("%s: AVMUTE %s\n", __func__, set ? "set" : "cleared");
+
+	return 0;
+} /* hdmi_tx_config_avmute */
+
 void hdmi_tx_hdcp_cb(void *ptr, enum hdmi_hdcp_state status)
 {
 	int rc = 0;
@@ -629,13 +664,25 @@
 
 	switch (status) {
 	case HDCP_STATE_AUTHENTICATED:
-		if (hdmi_ctrl->hpd_state)
+		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);
 			hdmi_tx_set_audio_switch_node(hdmi_ctrl, 1, false);
+		}
 		break;
 	case HDCP_STATE_AUTH_FAIL:
 		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);
+
 			DEV_DBG("%s: Reauthenticating\n", __func__);
 			rc = hdmi_hdcp_reauthenticate(
 				hdmi_ctrl->feature_data[HDMI_TX_FEAT_HDCP]);
@@ -2465,6 +2512,9 @@
 		return -EINVAL;
 	}
 
+	/* mhl status should override */
+	hdmi_ctrl->mhl_hpd_on = on;
+
 	if (!on && hdmi_ctrl->hpd_feature_on) {
 		rc = hdmi_tx_sysfs_enable_hpd(hdmi_ctrl, false);
 	} else if (on && !hdmi_ctrl->hpd_feature_on) {
@@ -2743,6 +2793,12 @@
 
 	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);
+
 			DEV_DBG("%s: Starting HDCP authentication\n", __func__);
 			rc = hdmi_hdcp_authenticate(
 				hdmi_ctrl->feature_data[HDMI_TX_FEAT_HDCP]);
diff --git a/drivers/video/msm/mdss/mdss_hdmi_tx.h b/drivers/video/msm/mdss/mdss_hdmi_tx.h
index ce3c00c..d4f8e67 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-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -62,6 +62,7 @@
 	u32 hpd_initialized;
 	u8  timing_gen_on;
 	u32 mhl_max_pclk;
+	u8  mhl_hpd_on;
 	struct completion hpd_done;
 	struct work_struct hpd_int_work;
 
diff --git a/drivers/video/msm/mdss/mdss_io_util.c b/drivers/video/msm/mdss/mdss_io_util.c
index ff52e4c..809db43 100644
--- a/drivers/video/msm/mdss/mdss_io_util.c
+++ b/drivers/video/msm/mdss/mdss_io_util.c
@@ -276,15 +276,17 @@
 			DEV_DBG("%pS->%s: %s disable\n",
 				__builtin_return_address(0), __func__,
 				in_gpio[i].gpio_name);
-
-			gpio_free(in_gpio[i].gpio);
+			if (in_gpio[i].gpio)
+				gpio_free(in_gpio[i].gpio);
 		}
 	}
 	return rc;
 
 disable_gpio:
 	for (i--; i >= 0; i--)
-		gpio_free(in_gpio[i].gpio);
+		if (in_gpio[i].gpio)
+			gpio_free(in_gpio[i].gpio);
+
 	return rc;
 } /* msm_dss_enable_gpio */
 
diff --git a/drivers/video/msm/mdss/mdss_mdp.c b/drivers/video/msm/mdss/mdss_mdp.c
index 772545f..d8ca555 100644
--- a/drivers/video/msm/mdss/mdss_mdp.c
+++ b/drivers/video/msm/mdss/mdss_mdp.c
@@ -977,6 +977,7 @@
 		goto probe_done;
 	}
 	mdata->irq = res->start;
+	mdss_mdp_hw.ptr = mdata;
 
 	/*populate hw iomem base info from device tree*/
 	rc = mdss_mdp_parse_dt(pdev);
@@ -1023,6 +1024,7 @@
 
 probe_done:
 	if (IS_ERR_VALUE(rc)) {
+		mdss_mdp_hw.ptr = NULL;
 		mdss_res = NULL;
 		mdss_mdp_pp_term(&pdev->dev);
 	}
diff --git a/drivers/video/msm/mdss/mdss_mdp.h b/drivers/video/msm/mdss/mdss_mdp.h
index f3b5acec..2a86dbc 100644
--- a/drivers/video/msm/mdss/mdss_mdp.h
+++ b/drivers/video/msm/mdss/mdss_mdp.h
@@ -157,6 +157,7 @@
 	int (*prepare_fnc) (struct mdss_mdp_ctl *ctl, void *arg);
 	int (*display_fnc) (struct mdss_mdp_ctl *ctl, void *arg);
 	int (*wait_fnc) (struct mdss_mdp_ctl *ctl, void *arg);
+	int (*wait_pingpong) (struct mdss_mdp_ctl *ctl, void *arg);
 	u32 (*read_line_cnt_fnc) (struct mdss_mdp_ctl *);
 	int (*add_vsync_handler) (struct mdss_mdp_ctl *,
 					struct mdss_mdp_vsync_handler *);
@@ -264,6 +265,9 @@
 	u32 last_str;
 	u32 last_bl;
 	u32 calc_itr;
+	uint32_t bl_bright_shift;
+	uint32_t bl_lin[AD_BL_LIN_LEN];
+	uint32_t bl_lin_inv[AD_BL_LIN_LEN];
 };
 
 struct pp_sts_type {
@@ -436,6 +440,7 @@
 int mdss_mdp_mixer_pipe_unstage(struct mdss_mdp_pipe *pipe);
 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);
 int mdss_mdp_display_wakeup_time(struct mdss_mdp_ctl *ctl,
 				 ktime_t *wakeup_time);
 
@@ -536,6 +541,7 @@
 
 int mdss_panel_register_done(struct mdss_panel_data *pdata);
 int mdss_mdp_limited_lut_igc_config(struct mdss_mdp_ctl *ctl);
+int mdss_mdp_calib_config(struct mdp_calib_config_data *cfg, u32 *copyback);
 
 #define mfd_to_mdp5_data(mfd) (mfd->mdp.private1)
 #define mfd_to_mdata(mfd) (((struct mdss_overlay_private *)\
diff --git a/drivers/video/msm/mdss/mdss_mdp_ctl.c b/drivers/video/msm/mdss/mdss_mdp_ctl.c
index e346082..5d9050c 100644
--- a/drivers/video/msm/mdss/mdss_mdp_ctl.c
+++ b/drivers/video/msm/mdss/mdss_mdp_ctl.c
@@ -1442,6 +1442,27 @@
 	return ret;
 }
 
+int mdss_mdp_display_wait4pingpong(struct mdss_mdp_ctl *ctl)
+{
+	int ret;
+
+	ret = mutex_lock_interruptible(&ctl->lock);
+	if (ret)
+		return ret;
+
+	if (!ctl->power_on) {
+		mutex_unlock(&ctl->lock);
+		return 0;
+	}
+
+	if (ctl->wait_pingpong)
+		ret = ctl->wait_pingpong(ctl, NULL);
+
+	mutex_unlock(&ctl->lock);
+
+	return ret;
+}
+
 int mdss_mdp_display_commit(struct mdss_mdp_ctl *ctl, void *arg)
 {
 	struct mdss_mdp_ctl *sctl = NULL;
@@ -1505,7 +1526,6 @@
 	mdss_mdp_pp_setup_locked(ctl);
 	mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_FLUSH, ctl->flush_bits);
 	if (sctl) {
-		mdss_mdp_pp_setup_locked(sctl);
 		mdss_mdp_ctl_write(sctl, MDSS_MDP_REG_CTL_FLUSH,
 			sctl->flush_bits);
 	}
diff --git a/drivers/video/msm/mdss/mdss_mdp_hwio.h b/drivers/video/msm/mdss/mdss_mdp_hwio.h
index 6ec5b63..741c7a7 100644
--- a/drivers/video/msm/mdss/mdss_mdp_hwio.h
+++ b/drivers/video/msm/mdss/mdss_mdp_hwio.h
@@ -515,4 +515,33 @@
 	MDSS_MDP_SMP_CLIENT_RGB2_FETCH,
 };
 
-#endif /* MDSS_MDP_HWIO_H */
+#define MDSS_MDP_LP_MISR_SEL			0x450
+#define MDSS_MDP_LP_MISR_CTRL_MDP		0x454
+#define MDSS_MDP_LP_MISR_CTRL_HDMI		0x458
+#define MDSS_MDP_LP_MISR_CTRL_EDP		0x45C
+#define MDSS_MDP_LP_MISR_CTRL_DSI0		0x460
+#define MDSS_MDP_LP_MISR_CTRL_DSI1		0x464
+
+#define MDSS_MDP_LP_MISR_SIGN_MDP		0x468
+#define MDSS_MDP_LP_MISR_SIGN_EDP		0x46C
+#define MDSS_MDP_LP_MISR_SIGN_HDMI		0x470
+#define MDSS_MDP_LP_MISR_SIGN_DSI0		0x474
+#define MDSS_MDP_LP_MISR_SIGN_DSI1		0x478
+
+#define MDSS_MDP_LP_MISR_CTRL_FRAME_COUNT_MASK	0xFF
+#define MDSS_MDP_LP_MISR_CTRL_ENABLE		BIT(8)
+#define MDSS_MDP_LP_MISR_CTRL_STATUS		BIT(9)
+#define MDSS_MDP_LP_MISR_CTRL_STATUS_CLEAR	BIT(10)
+
+#define MDSS_MDP_LP_MISR_SEL_LMIX0_BLEND	0x08
+#define MDSS_MDP_LP_MISR_SEL_LMIX0_GC		0x09
+#define MDSS_MDP_LP_MISR_SEL_LMIX1_BLEND	0x0A
+#define MDSS_MDP_LP_MISR_SEL_LMIX1_GC		0x0B
+#define MDSS_MDP_LP_MISR_SEL_LMIX2_BLEND	0x0C
+#define MDSS_MDP_LP_MISR_SEL_LMIX2_GC		0x0D
+#define MDSS_MDP_LP_MISR_SEL_LMIX3_BLEND	0x0E
+#define MDSS_MDP_LP_MISR_SEL_LMIX3_GC		0x0F
+#define MDSS_MDP_LP_MISR_SEL_LMIX4_BLEND	0x10
+#define MDSS_MDP_LP_MISR_SEL_LMIX4_GC		0x11
+
+#endif
diff --git a/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c b/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c
index afbbe55..238170d 100644
--- a/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c
+++ b/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c
@@ -335,32 +335,12 @@
 	mutex_unlock(&ctx->clk_mtx);
 }
 
-static int mdss_mdp_cmd_wait4comp(struct mdss_mdp_ctl *ctl, void *arg)
-{
-	struct mdss_mdp_cmd_ctx *ctx;
-	int rc;
-
-	ctx = (struct mdss_mdp_cmd_ctx *) ctl->priv_data;
-	if (!ctx) {
-		pr_err("invalid ctx\n");
-		return -ENODEV;
-	}
-
-	pr_debug("%s: intf_num=%d ctx=%p\n", __func__, ctl->intf_num, ctx);
-
-	rc = wait_for_completion_interruptible_timeout(&ctx->vsync_comp,
-			KOFF_TIMEOUT);
-	WARN(rc <= 0, "cmd kickoff timed out (%d) ctl=%d\n", rc, ctl->num);
-
-	return 0;
-}
-
-int mdss_mdp_cmd_kickoff(struct mdss_mdp_ctl *ctl, void *arg)
+static int mdss_mdp_cmd_wait4pingpong(struct mdss_mdp_ctl *ctl, void *arg)
 {
 	struct mdss_mdp_cmd_ctx *ctx;
 	unsigned long flags;
 	int need_wait = 0;
-	int rc;
+	int rc = 0;
 
 	ctx = (struct mdss_mdp_cmd_ctx *) ctl->priv_data;
 	if (!ctx) {
@@ -377,11 +357,29 @@
 			__func__, need_wait, ctl->intf_num, ctx);
 
 	if (need_wait) {
-		rc = wait_for_completion_interruptible_timeout(
+		rc = wait_for_completion_timeout(
 				&ctx->pp_comp, KOFF_TIMEOUT);
 
-		WARN(rc <= 0, "cmd kickoff timed out (%d) ctl=%d\n",
+		if (rc <= 0) {
+			WARN(1, "cmd kickoff timed out (%d) ctl=%d\n",
 						rc, ctl->num);
+			rc = -EPERM;
+		} else
+			rc = 0;
+	}
+
+	return rc;
+}
+
+int mdss_mdp_cmd_kickoff(struct mdss_mdp_ctl *ctl, void *arg)
+{
+	struct mdss_mdp_cmd_ctx *ctx;
+	int rc;
+
+	ctx = (struct mdss_mdp_cmd_ctx *) ctl->priv_data;
+	if (!ctx) {
+		pr_err("invalid ctx\n");
+		return -ENODEV;
 	}
 
 	if (ctx->panel_on == 0) {
@@ -456,6 +454,12 @@
 	ret = mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_PANEL_OFF, NULL);
 	WARN(ret, "intf %d unblank error (%d)\n", ctl->intf_num, ret);
 
+	ctl->stop_fnc = NULL;
+	ctl->display_fnc = NULL;
+	ctl->wait_pingpong = NULL;
+	ctl->add_vsync_handler = NULL;
+	ctl->remove_vsync_handler = NULL;
+
 	pr_debug("%s:-\n", __func__);
 
 	return 0;
@@ -519,7 +523,7 @@
 
 	ctl->stop_fnc = mdss_mdp_cmd_stop;
 	ctl->display_fnc = mdss_mdp_cmd_kickoff;
-	ctl->wait_fnc = mdss_mdp_cmd_wait4comp;
+	ctl->wait_pingpong = mdss_mdp_cmd_wait4pingpong;
 	ctl->add_vsync_handler = mdss_mdp_cmd_vsync_ctrl;
 	ctl->remove_vsync_handler = mdss_mdp_cmd_vsync_ctrl;
 
diff --git a/drivers/video/msm/mdss/mdss_mdp_intf_video.c b/drivers/video/msm/mdss/mdss_mdp_intf_video.c
index 72cbed9..ab028e4 100644
--- a/drivers/video/msm/mdss/mdss_mdp_intf_video.c
+++ b/drivers/video/msm/mdss/mdss_mdp_intf_video.c
@@ -562,6 +562,13 @@
 
 	pdata->panel_info.cont_splash_enabled = 0;
 
+	ret = mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_CONT_SPLASH_BEGIN,
+				      NULL);
+	if (ret) {
+		pr_err("%s: Failed to handle 'CONT_SPLASH_BEGIN' event\n",
+					__func__);
+		return ret;
+	}
 
 	mdss_mdp_ctl_write(ctl, 0, MDSS_MDP_LM_BORDER_COLOR);
 	off = MDSS_MDP_REG_INTF_OFFSET(ctl->intf_num);
diff --git a/drivers/video/msm/mdss/mdss_mdp_overlay.c b/drivers/video/msm/mdss/mdss_mdp_overlay.c
index c96464a..0152d87 100644
--- a/drivers/video/msm/mdss/mdss_mdp_overlay.c
+++ b/drivers/video/msm/mdss/mdss_mdp_overlay.c
@@ -27,6 +27,7 @@
 #include <mach/event_timer.h>
 
 #include "mdss.h"
+#include "mdss_debug.h"
 #include "mdss_fb.h"
 #include "mdss_mdp.h"
 #include "mdss_mdp_rotator.h"
@@ -701,6 +702,14 @@
 
 	mutex_lock(&mdp5_data->ov_lock);
 	mutex_lock(&mfd->lock);
+
+	ret = mdss_mdp_display_wait4pingpong(mdp5_data->ctl);
+	if (ret) {
+		mutex_unlock(&mfd->lock);
+		mutex_unlock(&mdp5_data->ov_lock);
+		return ret;
+	}
+
 	list_for_each_entry(pipe, &mdp5_data->pipes_used, used_list) {
 		struct mdss_mdp_data *buf;
 		if (pipe->back_buf.num_planes) {
@@ -1286,20 +1295,14 @@
 	struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
 	unsigned long flags;
 	u64 vsync_ticks;
-	unsigned long timeout;
 	int ret;
 
 	if (!mdp5_data->ctl || !mdp5_data->ctl->power_on)
 		return 0;
 
-	timeout = msecs_to_jiffies(VSYNC_PERIOD * 5);
-	ret = wait_for_completion_interruptible_timeout(&mdp5_data->vsync_comp,
-			timeout);
-	if (ret <= 0) {
-		pr_debug("Sending current time as vsync timestamp for fb%d\n",
-				mfd->index);
-		mdp5_data->vsync_time = ktime_get();
-	}
+	ret = wait_for_completion_interruptible(&mdp5_data->vsync_comp);
+	if (ret < 0)
+		return ret;
 
 	spin_lock_irqsave(&mdp5_data->vsync_lock, flags);
 	vsync_ticks = ktime_to_ns(mdp5_data->vsync_time);
@@ -1554,8 +1557,13 @@
 			copyback = 1;
 		}
 		break;
+	case mdp_op_calib_cfg:
+		ret = mdss_mdp_calib_config((struct mdp_calib_config_data *)
+					 &mdp_pp.data.calib_cfg, &copyback);
+		break;
 	default:
-		pr_err("Unsupported request to MDP_PP IOCTL.\n");
+		pr_err("Unsupported request to MDP_PP IOCTL. %d = op\n",
+								mdp_pp.op);
 		ret = -EINVAL;
 		break;
 	}
@@ -1614,6 +1622,7 @@
 static int mdss_fb_set_metadata(struct msm_fb_data_type *mfd,
 				struct msmfb_metadata *metadata)
 {
+	struct mdss_data_type *mdata = mfd_to_mdata(mfd);
 	int ret = 0;
 	switch (metadata->op) {
 	case metadata_op_vic:
@@ -1623,6 +1632,11 @@
 		else
 			ret = -EINVAL;
 		break;
+	case metadata_op_crc:
+		if (!mfd->panel_power_on)
+			return -EPERM;
+		ret = mdss_misr_crc_set(mdata, &metadata->data.misr_request);
+		break;
 	default:
 		pr_warn("unsupported request to MDP META IOCTL\n");
 		ret = -EINVAL;
@@ -1649,6 +1663,7 @@
 static int mdss_fb_get_metadata(struct msm_fb_data_type *mfd,
 				struct msmfb_metadata *metadata)
 {
+	struct mdss_data_type *mdata = mfd_to_mdata(mfd);
 	int ret = 0;
 	switch (metadata->op) {
 	case metadata_op_frame_rate:
@@ -1658,6 +1673,11 @@
 	case metadata_op_get_caps:
 		ret = mdss_fb_get_hw_caps(mfd, &metadata->data.caps);
 		break;
+	case metadata_op_crc:
+		if (!mfd->panel_power_on)
+			return -EPERM;
+		ret = mdss_misr_crc_get(mdata, &metadata->data.misr_request);
+		break;
 	default:
 		pr_warn("Unsupported request to MDP META IOCTL.\n");
 		ret = -EINVAL;
diff --git a/drivers/video/msm/mdss/mdss_mdp_pp.c b/drivers/video/msm/mdss/mdss_mdp_pp.c
index fcc1c1a..13c01af 100644
--- a/drivers/video/msm/mdss/mdss_mdp_pp.c
+++ b/drivers/video/msm/mdss/mdss_mdp_pp.c
@@ -190,6 +190,7 @@
 #define PP_AD_STATE_DATA	0x8
 #define PP_AD_STATE_RUN		0x10
 #define PP_AD_STATE_VSYNC	0x20
+#define PP_AD_STATE_BL_LIN	0x40
 
 #define PP_AD_STATE_IS_INITCFG(st)	(((st) & PP_AD_STATE_INIT) &&\
 						((st) & PP_AD_STATE_CFG))
@@ -217,6 +218,8 @@
 #define MDSS_AD_MODE_DATA_MATCH(mode, data) ((1 << (mode)) & (data))
 #define MDSS_AD_RUNNING_AUTO_BL(ad) (((ad)->state & PP_AD_STATE_RUN) &&\
 				((ad)->cfg.mode == MDSS_AD_MODE_AUTO_BL))
+#define MDSS_AD_RUNNING_AUTO_STR(ad) (((ad)->state & PP_AD_STATE_RUN) &&\
+				((ad)->cfg.mode == MDSS_AD_MODE_AUTO_STR))
 
 #define SHARP_STRENGTH_DEFAULT	32
 #define SHARP_EDGE_THR_DEFAULT	112
@@ -888,14 +891,19 @@
 	return ret;
 }
 
-static int pp_mixer_setup(u32 disp_num, struct mdss_mdp_ctl *ctl,
+static int pp_mixer_setup(u32 disp_num,
 		struct mdss_mdp_mixer *mixer)
 {
 	u32 flags, offset, dspp_num, opmode = 0;
 	struct mdp_pgc_lut_data *pgc_config;
 	struct pp_sts_type *pp_sts;
+	struct mdss_mdp_ctl *ctl;
 	dspp_num = mixer->num;
 
+	if (!mixer || !mixer->ctl)
+		return -EINVAL;
+	ctl = mixer->ctl;
+
 	/* no corresponding dspp */
 	if ((mixer->type != MDSS_MDP_MIXER_TYPE_INTF) ||
 		(dspp_num >= MDSS_MDP_MAX_DSPP))
@@ -1003,8 +1011,7 @@
 	return ret;
 }
 
-static int pp_dspp_setup(u32 disp_num, struct mdss_mdp_ctl *ctl,
-				struct mdss_mdp_mixer *mixer)
+static int pp_dspp_setup(u32 disp_num, struct mdss_mdp_mixer *mixer)
 {
 	u32 flags, base, offset, dspp_num, opmode = 0;
 	struct mdp_dither_cfg_data *dither_cfg;
@@ -1014,12 +1021,12 @@
 	char __iomem *basel;
 	int i, ret = 0;
 	struct mdss_data_type *mdata;
+	struct mdss_mdp_ctl *ctl;
 
-	mdata = ctl->mdata;
-
-	if (!mixer || !ctl || !mdata)
+	if (!mixer || !mixer->ctl || !mixer->ctl->mdata)
 		return -EINVAL;
-
+	ctl = mixer->ctl;
+	mdata = ctl->mdata;
 	dspp_num = mixer->num;
 	/* no corresponding dspp */
 	if ((mixer->type != MDSS_MDP_MIXER_TYPE_INTF) ||
@@ -1174,12 +1181,12 @@
 
 	mutex_lock(&mdss_pp_mutex);
 	if (ctl->mixer_left) {
-		pp_mixer_setup(disp_num, ctl, ctl->mixer_left);
-		pp_dspp_setup(disp_num, ctl, ctl->mixer_left);
+		pp_mixer_setup(disp_num, ctl->mixer_left);
+		pp_dspp_setup(disp_num, ctl->mixer_left);
 	}
 	if (ctl->mixer_right) {
-		pp_mixer_setup(disp_num, ctl, ctl->mixer_right);
-		pp_dspp_setup(disp_num, ctl, ctl->mixer_right);
+		pp_mixer_setup(disp_num, ctl->mixer_right);
+		pp_dspp_setup(disp_num, ctl->mixer_right);
 	}
 	/* clear dirty flag */
 	if (disp_num < MDSS_BLOCK_DISP_NUM)
@@ -1195,7 +1202,7 @@
  */
 int mdss_mdp_pp_resume(struct mdss_mdp_ctl *ctl, u32 dspp_num)
 {
-	u32 flags = 0, disp_num;
+	u32 flags = 0, disp_num, bl;
 	struct pp_sts_type pp_sts;
 	struct mdss_ad_info *ad;
 	struct mdss_data_type *mdata = ctl->mdata;
@@ -1212,8 +1219,15 @@
 			pp_ad_cfg_write(ad);
 		if (PP_AD_STATE_INIT & ad->state)
 			pp_ad_init_write(ad);
-		if (PP_AD_STATE_DATA & ad->state)
-			pp_ad_input_write(ad, ctl->mfd->bl_level);
+		if (PP_AD_STATE_DATA & ad->state) {
+			bl = ctl->mfd->bl_level;
+			ad->last_bl = bl;
+			if (ad->state & PP_AD_STATE_BL_LIN) {
+				bl = ad->bl_lin[bl >> ad->bl_bright_shift];
+				bl = bl << ad->bl_bright_shift;
+			}
+			pp_ad_input_write(ad, bl);
+		}
 		if ((PP_AD_STATE_VSYNC & ad->state) && ad->calc_itr)
 			ctl->add_vsync_handler(ctl, &ad->handle);
 	}
@@ -1648,6 +1662,9 @@
 		(config->block >= MDP_BLOCK_MAX))
 		return -EINVAL;
 
+	if (config->len != IGC_LUT_ENTRIES)
+		return -EINVAL;
+
 	mutex_lock(&mdss_pp_mutex);
 	disp_num = config->block - MDP_LOGICAL_BLOCK_DISP_0;
 
@@ -2740,7 +2757,7 @@
 	struct mdss_ad_input input;
 
 	ad = mdss_mdp_get_ad(mfd);
-	if (!ad)
+	if (!ad || ad->cfg.mode == MDSS_AD_MODE_AUTO_BL)
 		return -EINVAL;
 
 	pr_debug("backlight level changed, trigger update to AD");
@@ -2758,6 +2775,8 @@
 {
 	struct mdss_ad_info *ad;
 	struct mdss_mdp_ctl *ctl;
+	int lin_ret = -1, inv_ret = -1, ret = 0;
+	u32 ratio_temp, shift = 0;
 
 	ad = mdss_mdp_get_ad(mfd);
 	if (!ad)
@@ -2767,6 +2786,29 @@
 	if (init_cfg->ops & MDP_PP_AD_INIT) {
 		memcpy(&ad->init, &init_cfg->params.init,
 				sizeof(struct mdss_ad_init));
+		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));
+			inv_ret = copy_from_user(&ad->bl_lin_inv,
+				init_cfg->params.init.bl_lin_inv,
+				AD_BL_LIN_LEN * sizeof(uint32_t));
+			if (lin_ret || inv_ret)
+				ret = -ENOMEM;
+			ratio_temp =  mfd->panel_info->bl_max / AD_BL_LIN_LEN;
+			while (ratio_temp > 0) {
+				ratio_temp = ratio_temp >> 1;
+				shift++;
+			}
+			ad->bl_bright_shift = shift;
+		} else if (init_cfg->params.init.bl_lin_len) {
+			ret = -EINVAL;
+		}
+		if (!lin_ret && !inv_ret)
+			ad->state |= PP_AD_STATE_BL_LIN;
+		else
+			ad->state &= !PP_AD_STATE_BL_LIN;
+
 		ad->sts |= PP_AD_STS_DIRTY_INIT;
 	} else if (init_cfg->ops & MDP_PP_AD_CFG) {
 		memcpy(&ad->cfg, &init_cfg->params.cfg,
@@ -2779,17 +2821,21 @@
 		ad->sts |= PP_AD_STS_DIRTY_CFG;
 	}
 
-	if (init_cfg->ops & MDP_PP_OPS_DISABLE) {
+	if (!ret && (init_cfg->ops & MDP_PP_OPS_DISABLE)) {
 		ad->sts &= ~PP_STS_ENABLE;
+		mutex_unlock(&ad->lock);
+		cancel_work_sync(&ad->calc_work);
+		mutex_lock(&ad->lock);
 		ad->mfd = NULL;
-	} else if (init_cfg->ops & MDP_PP_OPS_ENABLE) {
+	} else if (!ret && (init_cfg->ops & MDP_PP_OPS_ENABLE)) {
 		ad->sts |= PP_STS_ENABLE;
 		ad->mfd = mfd;
 	}
 	mutex_unlock(&ad->lock);
 	ctl = mfd_to_ctl(mfd);
-	mdss_mdp_pp_setup(ctl);
-	return 0;
+	if (!ret)
+		mdss_mdp_pp_setup(ctl);
+	return ret;
 }
 
 int mdss_mdp_ad_input(struct msm_fb_data_type *mfd,
@@ -2988,7 +3034,7 @@
 	struct mdss_ad_info *ad;
 	struct mdss_mdp_ctl *ctl = mfd_to_ctl(mfd);
 	char __iomem *base;
-	u32 bypass = MDSS_PP_AD_BYPASS_DEF;
+	u32 bypass = MDSS_PP_AD_BYPASS_DEF, bl;
 
 	ad = mdss_mdp_get_ad(mfd);
 	if (!ad)
@@ -3004,9 +3050,7 @@
 								ad->state);
 	}
 	if (!PP_AD_STS_IS_DIRTY(ad->sts) &&
-		(ad->sts & PP_AD_STS_DIRTY_DATA ||
-			(ad->state & PP_AD_STATE_RUN &&
-				(ad->cfg.mode == MDSS_AD_MODE_AUTO_STR)))) {
+		(ad->sts & PP_AD_STS_DIRTY_DATA)) {
 		/*
 		 * Write inputs to regs when the data has been updated or
 		 * Assertive Display is up and running as long as there are
@@ -3014,12 +3058,22 @@
 		 */
 		ad->sts &= ~PP_AD_STS_DIRTY_DATA;
 		ad->state |= PP_AD_STATE_DATA;
-		if (mfd->bl_level != ad->last_bl) {
-			ad->last_bl = mfd->bl_level;
-			ad->calc_itr = ad->cfg.stab_itr;
-			ad->sts |= PP_AD_STS_DIRTY_VSYNC;
+		bl = 0;
+		if (MDSS_AD_RUNNING_AUTO_STR(ad) || ad->last_bl == 0) {
+			mutex_lock(&mfd->bl_lock);
+			bl = mfd->bl_level;
+			if (bl != ad->last_bl) {
+				ad->last_bl = bl;
+				ad->calc_itr = ad->cfg.stab_itr;
+				ad->sts |= PP_AD_STS_DIRTY_VSYNC;
+			}
+			if (ad->state & PP_AD_STATE_BL_LIN) {
+				bl = ad->bl_lin[bl >> ad->bl_bright_shift];
+				bl = bl << ad->bl_bright_shift;
+			}
+			mutex_unlock(&mfd->bl_lock);
 		}
-		pp_ad_input_write(ad, mfd->bl_level);
+		pp_ad_input_write(ad, bl);
 	}
 
 	if (ad->sts & PP_AD_STS_DIRTY_CFG) {
@@ -3051,7 +3105,23 @@
 	} else {
 		if (ad->state & PP_AD_STATE_RUN) {
 			ret = 1;
+			/* Clear state and regs when going to off state*/
+			ad->sts = 0;
 			ad->sts |= PP_AD_STS_DIRTY_VSYNC;
+			ad->state &= !PP_AD_STATE_INIT;
+			ad->state &= !PP_AD_STATE_CFG;
+			ad->state &= !PP_AD_STATE_DATA;
+			ad->state &= !PP_AD_STATE_BL_LIN;
+			ad->bl_bright_shift = 0;
+			ad->ad_data = 0;
+			ad->ad_data_mode = 0;
+			ad->calc_itr = 0;
+			memset(&ad->bl_lin, 0, sizeof(uint32_t) *
+								AD_BL_LIN_LEN);
+			memset(&ad->bl_lin_inv, 0, sizeof(uint32_t) *
+								AD_BL_LIN_LEN);
+			memset(&ad->init, 0, sizeof(struct mdss_ad_init));
+			memset(&ad->cfg, 0, sizeof(struct mdss_ad_cfg));
 			mutex_lock(&mfd->bl_lock);
 			mfd->mdp.update_ad_input = NULL;
 			mutex_unlock(&mfd->bl_lock);
@@ -3063,7 +3133,8 @@
 	if (PP_AD_STS_DIRTY_VSYNC & ad->sts) {
 		pr_debug("dirty vsync, calc_itr = %d", ad->calc_itr);
 		ad->sts &= ~PP_AD_STS_DIRTY_VSYNC;
-		if (!(PP_AD_STATE_VSYNC & ad->state) && ad->calc_itr) {
+		if (!(PP_AD_STATE_VSYNC & ad->state) && ad->calc_itr &&
+					(ad->state & PP_AD_STATE_RUN)) {
 			ctl->add_vsync_handler(ctl, &ad->handle);
 			ad->state |= PP_AD_STATE_VSYNC;
 		} else if ((PP_AD_STATE_VSYNC & ad->state) &&
@@ -3088,11 +3159,18 @@
 {
 	struct mdss_ad_info *ad;
 	struct mdss_mdp_ctl *ctl;
+	struct msm_fb_data_type *mfd;
 	u32 bl, calc_done = 0;
 	ad = container_of(work, struct mdss_ad_info, calc_work);
-	ctl = mfd_to_ctl(ad->mfd);
 
 	mutex_lock(&ad->lock);
+	if (!ad->mfd || !(ad->sts & PP_STS_ENABLE)) {
+		mutex_unlock(&ad->lock);
+		return;
+	}
+	mfd = ad->mfd;
+	ctl = mfd_to_ctl(ad->mfd);
+
 	if (PP_AD_STATE_RUN & ad->state) {
 		/* Kick off calculation */
 		ad->calc_itr--;
@@ -3111,6 +3189,13 @@
 			if (MDSS_AD_RUNNING_AUTO_BL(ad)) {
 				bl = 0xFFFF & readl_relaxed(ad->base +
 						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 = ad->bl_lin_inv[bl];
+					bl = bl << ad->bl_bright_shift;
+				}
 				pr_debug("calc bl = %d", bl);
 				ad->last_str |= bl << 16;
 				mutex_lock(&ad->mfd->bl_lock);
@@ -3131,9 +3216,9 @@
 		ctl->remove_vsync_handler(ctl, &ad->handle);
 	}
 	mutex_unlock(&ad->lock);
-	mutex_lock(&ad->mfd->lock);
+	mutex_lock(&mfd->lock);
 	mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_FLUSH, BIT(13 + ad->num));
-	mutex_unlock(&ad->mfd->lock);
+	mutex_unlock(&mfd->lock);
 }
 
 #define PP_AD_LUT_LEN 33
@@ -3177,3 +3262,88 @@
 	}
 	return rc;
 }
+
+static int is_valid_calib_addr(void *addr)
+{
+	int ret = 0;
+	unsigned int ptr;
+	ptr = (unsigned int) addr;
+	/* if request is outside the MDP reg-map or is not aligned 4 */
+	if (ptr == 0x0 || ptr > 0x5138 || ptr % 0x4)
+		goto end;
+	if (ptr >= 0x100 && ptr <= 0x5138) {
+		/* if ptr is in dspp range */
+		if (ptr >= 0x4600 && ptr <= 0x5138) {
+			/* if ptr is in dspp0 range*/
+			if (ptr >= 0x4600 && ptr <= 0x4938)
+				ptr -= 0x4600;
+			/* if ptr is in dspp1 range */
+			else if (ptr >= 0x4a00 && ptr <= 0x4d38)
+				ptr -= 0x4a00;
+			/* if ptr is in dspp2 range */
+			else if (ptr >= 0x4e00 && ptr <= 0x5138)
+				ptr -= 0x4e00;
+			/* if ptr is in pcc plane rgb coeff.range */
+			if (ptr >= 0x30 && ptr <= 0xe8)
+				ret = 1;
+			/* if ptr is in ARLUT red range */
+			else if (ptr >= 0x2b0 && ptr <= 0x2b8)
+				ret = 1;
+			/* if ptr is in PA range */
+			else if (ptr >= 0x238 && ptr <= 0x244)
+				ret = 1;
+			 /* if ptr is in ARLUT green range */
+			else if (ptr >= 0x2c0 && ptr <= 0x2c8)
+				ret = 1;
+			/* if ptr is in ARLUT blue range or
+			    gamut map table range */
+			else if (ptr >= 0x2d0 && ptr <= 0x338)
+				ret = 1;
+			/* if ptr is dspp0,dspp1,dspp2 op mode
+						register */
+			else if (ptr == 0)
+				ret = 1;
+		} else if (ptr >= 0x600 && ptr <= 0x608)
+				ret = 1;
+		else if (ptr >= 0x400 && ptr <= 0x408)
+				ret = 1;
+		else if ((ptr == 0x1830) || (ptr == 0x1c30) ||
+				(ptr == 0x1430) || (ptr == 0x1e38))
+				ret = 1;
+		else if ((ptr == 0x1e3c) || (ptr == 0x1e30))
+				ret = 1;
+		else if (ptr >= 0x3220 && ptr <= 0x3228)
+				ret = 1;
+		else if (ptr >= 0x3200 || ptr == 0x100)
+				ret = 1;
+	}
+end:
+	return ret;
+}
+
+
+
+
+int mdss_mdp_calib_config(struct mdp_calib_config_data *cfg, u32 *copyback)
+{
+	int ret = -1;
+	void *ptr = (void *) cfg->addr;
+
+	if (is_valid_calib_addr(ptr))
+		ret = 0;
+	else
+		return ret;
+	ptr = (void *)(((unsigned int) ptr) + (mdss_res->mdp_base));
+	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+
+	if (cfg->ops & MDP_PP_OPS_READ) {
+		cfg->data = readl_relaxed(ptr);
+		*copyback = 1;
+		ret = 0;
+	} else if (cfg->ops & MDP_PP_OPS_WRITE) {
+		writel_relaxed(cfg->data, ptr);
+		ret = 0;
+	}
+	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+	return ret;
+}
diff --git a/drivers/video/msm/mdss/mdss_mdp_util.c b/drivers/video/msm/mdss/mdss_mdp_util.c
index d1f0c8d..e010ba5 100644
--- a/drivers/video/msm/mdss/mdss_mdp_util.c
+++ b/drivers/video/msm/mdss/mdss_mdp_util.c
@@ -27,7 +27,7 @@
 #include "mdss_fb.h"
 #include "mdss_mdp.h"
 #include "mdss_mdp_formats.h"
-
+#include "mdss_debug.h"
 #define DEFAULT_FRAME_RATE	60
 
 enum {
@@ -124,6 +124,7 @@
 
 irqreturn_t mdss_mdp_isr(int irq, void *ptr)
 {
+	struct mdss_data_type *mdata = ptr;
 	u32 isr, mask, hist_isr, hist_mask;
 
 
@@ -172,17 +173,25 @@
 	if (isr & MDSS_MDP_INTR_PING_PONG_2_RD_PTR)
 		mdss_mdp_intr_done(MDP_INTR_PING_PONG_2_RD_PTR);
 
-	if (isr & MDSS_MDP_INTR_INTF_0_VSYNC)
+	if (isr & MDSS_MDP_INTR_INTF_0_VSYNC) {
 		mdss_mdp_intr_done(MDP_INTR_VSYNC_INTF_0);
+		mdss_misr_crc_collect(mdata, DISPLAY_MISR_EDP);
+	}
 
-	if (isr & MDSS_MDP_INTR_INTF_1_VSYNC)
+	if (isr & MDSS_MDP_INTR_INTF_1_VSYNC) {
 		mdss_mdp_intr_done(MDP_INTR_VSYNC_INTF_1);
+		mdss_misr_crc_collect(mdata, DISPLAY_MISR_DSI0);
+	}
 
-	if (isr & MDSS_MDP_INTR_INTF_2_VSYNC)
+	if (isr & MDSS_MDP_INTR_INTF_2_VSYNC) {
 		mdss_mdp_intr_done(MDP_INTR_VSYNC_INTF_2);
+		mdss_misr_crc_collect(mdata, DISPLAY_MISR_DSI1);
+	}
 
-	if (isr & MDSS_MDP_INTR_INTF_3_VSYNC)
+	if (isr & MDSS_MDP_INTR_INTF_3_VSYNC) {
 		mdss_mdp_intr_done(MDP_INTR_VSYNC_INTF_3);
+		mdss_misr_crc_collect(mdata, DISPLAY_MISR_HDMI);
+	}
 
 	if (isr & MDSS_MDP_INTR_WB_0_DONE)
 		mdss_mdp_intr_done(MDP_INTR_WB_0);
diff --git a/drivers/video/msm/mdss/mdss_panel.h b/drivers/video/msm/mdss/mdss_panel.h
index f138420..1bf414f 100644
--- a/drivers/video/msm/mdss/mdss_panel.h
+++ b/drivers/video/msm/mdss/mdss_panel.h
@@ -76,8 +76,13 @@
  *				 - negative if the configuration is invalid
  *				 - 0 if there is no panel reconfig needed
  *				 - 1 if reconfig is needed to take effect
+ * @MDSS_EVENT_CONT_SPLASH_BEGIN: Special event used to handle transition of
+ *				display state from boot loader to panel driver.
+ *				The event handler will disable the panel.
  * @MDSS_EVENT_CONT_SPLASH_FINISH: Special event used to handle transition of
  *				display state from boot loader to panel driver.
+ *				The event handler will enable the panel and
+ *				vote for the display clocks.
  * @MDSS_EVENT_FB_REGISTERED:	Called after fb dev driver has been registered,
  *				panel driver gets ptr to struct fb_info which
  *				holds fb dev information.
@@ -96,6 +101,7 @@
 	MDSS_EVENT_SUSPEND,
 	MDSS_EVENT_RESUME,
 	MDSS_EVENT_CHECK_PARAMS,
+	MDSS_EVENT_CONT_SPLASH_BEGIN,
 	MDSS_EVENT_CONT_SPLASH_FINISH,
 	MDSS_EVENT_FB_REGISTERED,
 	MDSS_EVENT_PANEL_CLK_CTRL,
diff --git a/drivers/video/msm/mdss/mhl_msc.c b/drivers/video/msm/mdss/mhl_msc.c
index 08d0693..15811bb 100644
--- a/drivers/video/msm/mdss/mhl_msc.c
+++ b/drivers/video/msm/mdss/mhl_msc.c
@@ -201,6 +201,22 @@
 	return 0;
 }
 
+int mhl_msc_clear(struct mhl_tx_ctrl *mhl_ctrl)
+{
+	if (!mhl_ctrl)
+		return -EFAULT;
+
+	memset(mhl_ctrl->devcap, 0, 16);
+	mhl_ctrl->devcap_state = 0;
+	mhl_ctrl->path_en_state = 0;
+	mhl_ctrl->status[0] = 0;
+	mhl_ctrl->status[1] = 0;
+	mhl_ctrl->scrpd_busy = 0;
+	mhl_ctrl->wr_burst_pending = 0;
+
+	return 0;
+}
+
 int mhl_msc_command_done(struct mhl_tx_ctrl *mhl_ctrl,
 			 struct msc_command_struct *req)
 {
@@ -541,7 +557,7 @@
 		 * connected device bits
 		 * changed and DEVCAP READY
 		 */
-		if (((value ^ mhl_ctrl->devcap_state) &
+		if (((value ^ mhl_ctrl->status[offset]) &
 		     MHL_STATUS_DCAP_RDY)) {
 			if (value & MHL_STATUS_DCAP_RDY) {
 				mhl_ctrl->devcap_state = 0;
@@ -563,7 +579,7 @@
 		 * bit set
 		 */
 		tmds_en = mhl_check_tmds_enabled(mhl_ctrl);
-		if ((value ^ mhl_ctrl->path_en_state)
+		if ((value ^ mhl_ctrl->status[offset])
 		    & MHL_STATUS_PATH_ENABLED) {
 			if (value & MHL_STATUS_PATH_ENABLED) {
 				if (tmds_en &&
@@ -593,7 +609,7 @@
 		}
 		break;
 	}
-	mhl_ctrl->path_en_state = value;
+	mhl_ctrl->status[offset] = value;
 	return 0;
 }
 
diff --git a/drivers/video/msm/mdss/mhl_msc.h b/drivers/video/msm/mdss/mhl_msc.h
index 8a1fd39..3137f17 100644
--- a/drivers/video/msm/mdss/mhl_msc.h
+++ b/drivers/video/msm/mdss/mhl_msc.h
@@ -25,6 +25,8 @@
 
 /******************************************************************/
 /* the below APIs are implemented by the MSC functionality */
+int mhl_msc_clear(struct mhl_tx_ctrl *mhl_ctrl);
+
 int mhl_msc_command_done(struct mhl_tx_ctrl *mhl_ctrl,
 			 struct msc_command_struct *req);
 
diff --git a/drivers/video/msm/mdss/mhl_sii8334.c b/drivers/video/msm/mdss/mhl_sii8334.c
index 3c11317..9cae431 100644
--- a/drivers/video/msm/mdss/mhl_sii8334.c
+++ b/drivers/video/msm/mdss/mhl_sii8334.c
@@ -361,7 +361,7 @@
 	pr_debug("%s:%u\n", __func__, __LINE__);
 	INIT_COMPLETION(mhl_ctrl->rgnd_done);
 	timeout = wait_for_completion_interruptible_timeout
-		(&mhl_ctrl->rgnd_done, HZ/2);
+		(&mhl_ctrl->rgnd_done, HZ);
 	if (!timeout) {
 		/* most likely nothing plugged in USB */
 		/* USB HOST connected or already in USB mode */
@@ -377,6 +377,12 @@
 {
 	int rc;
 	struct mhl_tx_ctrl *mhl_ctrl = data;
+	struct i2c_client *client = mhl_ctrl->i2c_handle;
+	unsigned long flags;
+
+	enable_irq(client->irq);
+	/* wait for i2c interrupt line to be activated */
+	msleep(300);
 
 	if (id) {
 		/* When MHL cable is disconnected we get a sii8334
@@ -396,11 +402,16 @@
 		mhl_ctrl->notify_usb_online = usb_notify_cb;
 
 	if (!mhl_ctrl->disc_enabled) {
+		spin_lock_irqsave(&mhl_ctrl->lock, flags);
+		mhl_ctrl->tx_powered_off = false;
+		spin_unlock_irqrestore(&mhl_ctrl->lock, flags);
 		mhl_sii_reset_pin(mhl_ctrl, 0);
 		msleep(50);
 		mhl_sii_reset_pin(mhl_ctrl, 1);
-		/* TX PR-guide requires a 100 ms wait here */
-		msleep(100);
+		/* chipset PR recommends waiting for at least 100 ms
+		 * the chipset needs longer to come out of D3 state.
+		 */
+		msleep(300);
 		mhl_init_reg_settings(mhl_ctrl, true);
 		rc = mhl_sii_wait_for_rgnd(mhl_ctrl);
 	} else {
@@ -690,8 +701,8 @@
 
 	MHL_SII_PAGE3_WR(0x3C, 0x80);
 
-	if (mhl_ctrl->cur_state != POWER_STATE_D3)
-		MHL_SII_REG_NAME_MOD(REG_INT_CTRL, BIT6 | BIT5 | BIT4, BIT4);
+	MHL_SII_REG_NAME_MOD(REG_INT_CTRL,
+			     (BIT6 | BIT5 | BIT4), (BIT6 | BIT4));
 
 	/* Enable Auto Soft RESET */
 	MHL_SII_REG_NAME_WR(REG_SRST, 0x084);
@@ -858,18 +869,14 @@
 static void mhl_msm_disconnection(struct mhl_tx_ctrl *mhl_ctrl)
 {
 	struct i2c_client *client = mhl_ctrl->i2c_handle;
-	unsigned long flags;
-
-	spin_lock_irqsave(&mhl_ctrl->lock, flags);
-	mhl_ctrl->dwnstream_hpd &= ~BIT6;
-	spin_unlock_irqrestore(&mhl_ctrl->lock, flags);
 
 	/* disabling Tx termination */
 	MHL_SII_REG_NAME_WR(REG_MHLTX_CTL1, 0xD0);
 	switch_mode(mhl_ctrl, POWER_STATE_D3, true);
+	mhl_msc_clear(mhl_ctrl);
 }
 
-static int  mhl_msm_read_rgnd_int(struct mhl_tx_ctrl *mhl_ctrl)
+static int mhl_msm_read_rgnd_int(struct mhl_tx_ctrl *mhl_ctrl)
 {
 	uint8_t rgnd_imp;
 	struct i2c_client *client = mhl_ctrl->i2c_handle;
@@ -966,12 +973,12 @@
 
 	if ((0x00 == status) &&\
 	    (mhl_ctrl->cur_state == POWER_STATE_D3)) {
-		pr_err("%s: invalid intr\n", __func__);
+		pr_warn("%s: invalid intr\n", __func__);
 		return 0;
 	}
 
 	if (0xFF == status) {
-		pr_debug("%s: invalid intr 0xff\n", __func__);
+		pr_warn("%s: invalid intr 0xff\n", __func__);
 		MHL_SII_REG_NAME_WR(REG_INTR4, status);
 		return 0;
 	}
@@ -998,13 +1005,14 @@
 		power_supply_changed(&mhl_ctrl->mhl_psy);
 		if (mhl_ctrl->notify_usb_online)
 			mhl_ctrl->notify_usb_online(0);
-		return -EACCES;
+		return 0;
 	}
 
 	if (status & BIT5) {
 		/* clr intr - reg int4 */
 		pr_debug("%s: mhl discon: int4 st=%02X\n", __func__,
 			 (int)status);
+		mhl_ctrl->mhl_det_discon = true;
 
 		reg = MHL_SII_REG_NAME_RD(REG_INTR4);
 		MHL_SII_REG_NAME_WR(REG_INTR4, reg);
@@ -1012,7 +1020,7 @@
 		power_supply_changed(&mhl_ctrl->mhl_psy);
 		if (mhl_ctrl->notify_usb_online)
 			mhl_ctrl->notify_usb_online(0);
-		return -EACCES;
+		return 0;
 	}
 
 	if ((mhl_ctrl->cur_state != POWER_STATE_D0_NO_MHL) &&\
@@ -1053,6 +1061,32 @@
 	MHL_SII_REG_NAME_WR(REG_INTR5,  intr_5_stat);
 }
 
+static void mhl_tx_down(struct mhl_tx_ctrl *mhl_ctrl)
+{
+	struct i2c_client *client = mhl_ctrl->i2c_handle;
+	unsigned long flags;
+	uint8_t reg;
+
+	switch_mode(mhl_ctrl, POWER_STATE_D3, true);
+
+	reg = MHL_SII_REG_NAME_RD(REG_INTR1);
+	MHL_SII_REG_NAME_WR(REG_INTR1, reg);
+
+	reg = MHL_SII_REG_NAME_RD(REG_INTR4);
+	MHL_SII_REG_NAME_WR(REG_INTR4, reg);
+
+	/* disable INTR1 and INTR4 */
+	MHL_SII_REG_NAME_MOD(REG_INTR1_MASK, BIT6, 0x0);
+	MHL_SII_REG_NAME_MOD(REG_INTR4_MASK,
+		(BIT0 | BIT1 | BIT2 | BIT3 | BIT4 | BIT5 | BIT6), 0x0);
+
+	MHL_SII_PAGE1_MOD(0x003D, BIT0, 0x00);
+	spin_lock_irqsave(&mhl_ctrl->lock, flags);
+	mhl_ctrl->tx_powered_off = true;
+	spin_unlock_irqrestore(&mhl_ctrl->lock, flags);
+	pr_debug("%s: disabled\n", __func__);
+	disable_irq_nosync(client->irq);
+}
 
 static void mhl_hpd_stat_isr(struct mhl_tx_ctrl *mhl_ctrl)
 {
@@ -1084,20 +1118,24 @@
 
 		spin_lock_irqsave(&mhl_ctrl->lock, flags);
 		t = mhl_ctrl->dwnstream_hpd;
+		pr_debug("%s: %u: dwnstrm_hpd=0x%02x\n",
+			 __func__, __LINE__, mhl_ctrl->dwnstream_hpd);
 		spin_unlock_irqrestore(&mhl_ctrl->lock, flags);
 
 		if (BIT6 & (cbus_stat ^ t)) {
 			u8 status = cbus_stat & BIT6;
 			mhl_drive_hpd(mhl_ctrl, status ? HPD_UP : HPD_DOWN);
-			if (!status) {
-				MHL_SII_PAGE1_MOD(0x003D, BIT0, 0x00);
-				spin_lock_irqsave(&mhl_ctrl->lock, flags);
-				mhl_ctrl->tx_powered_off = true;
-				spin_unlock_irqrestore(&mhl_ctrl->lock, flags);
+			if (!status && mhl_ctrl->mhl_det_discon) {
+				pr_debug("%s:%u: power_down\n",
+					 __func__, __LINE__);
+				mhl_tx_down(mhl_ctrl);
 			}
 			spin_lock_irqsave(&mhl_ctrl->lock, flags);
 			mhl_ctrl->dwnstream_hpd = cbus_stat;
+			pr_debug("%s: %u: dwnstrm_hpd=0x%02x\n",
+				 __func__, __LINE__, mhl_ctrl->dwnstream_hpd);
 			spin_unlock_irqrestore(&mhl_ctrl->lock, flags);
+			mhl_ctrl->mhl_det_discon = false;
 		}
 	}
 }
@@ -1251,6 +1289,7 @@
 	uint8_t cmd_data = 0x0;
 	int msc_msg_recved = 0;
 	int rc = -1;
+	unsigned long flags;
 	struct i2c_client *client = mhl_ctrl->i2c_handle;
 
 	regval = MHL_SII_REG_NAME_RD(REG_CBUS_INTR_STATUS);
@@ -1291,6 +1330,14 @@
 		intr = MHL_SII_REG_NAME_RD(REG_CBUS_SET_INT_0);
 		MHL_SII_REG_NAME_WR(REG_CBUS_SET_INT_0, intr);
 		mhl_msc_recv_set_int(mhl_ctrl, 0, intr);
+		if (intr & MHL_INT_DCAP_CHG) {
+			/* No need to go to low power mode */
+			spin_lock_irqsave(&mhl_ctrl->lock, flags);
+			mhl_ctrl->dwnstream_hpd = 0x00;
+			pr_debug("%s: %u: dwnstrm_hpd=0x%02x\n",
+				 __func__, __LINE__, mhl_ctrl->dwnstream_hpd);
+			spin_unlock_irqrestore(&mhl_ctrl->lock, flags);
+		}
 
 		pr_debug("%s: MHL_INT_0 = %02x\n", __func__, intr);
 		intr = MHL_SII_REG_NAME_RD(REG_CBUS_SET_INT_1);
@@ -1336,8 +1383,18 @@
 {
 	int rc;
 	struct mhl_tx_ctrl *mhl_ctrl = (struct mhl_tx_ctrl *)data;
+	unsigned long flags;
+
 	pr_debug("%s: Getting Interrupts\n", __func__);
 
+	spin_lock_irqsave(&mhl_ctrl->lock, flags);
+	if (mhl_ctrl->tx_powered_off) {
+		pr_warn("%s: powered off\n", __func__);
+		spin_unlock_irqrestore(&mhl_ctrl->lock, flags);
+		return IRQ_HANDLED;
+	}
+	spin_unlock_irqrestore(&mhl_ctrl->lock, flags);
+
 	/*
 	 * Check RGND, MHL_EST, CBUS_LOCKOUT, SCDT
 	 * interrupts. In D3, we get only RGND
@@ -1397,6 +1454,8 @@
 	 */
 	mhl_init_reg_settings(mhl_ctrl, true);
 	switch_mode(mhl_ctrl, POWER_STATE_D3, true);
+	pr_debug("%s:%u: power_down\n", __func__, __LINE__);
+	mhl_tx_down(mhl_ctrl);
 	return 0;
 }
 
diff --git a/drivers/video/msm/mdss/msm_mdss_io_8974.c b/drivers/video/msm/mdss/msm_mdss_io_8974.c
index 12bc5e0..d4eb716 100644
--- a/drivers/video/msm/mdss/msm_mdss_io_8974.c
+++ b/drivers/video/msm/mdss/msm_mdss_io_8974.c
@@ -32,6 +32,7 @@
 	struct mdss_dsi_ctrl_pdata *ctrl_pdata)
 {
 	struct device *dev = NULL;
+	int rc = 0;
 
 	if (!pdev) {
 		pr_err("%s: Invalid pdev\n", __func__);
@@ -39,32 +40,53 @@
 	}
 
 	dev = &pdev->dev;
+	ctrl_pdata->ahb_clk = clk_get(dev, "iface_clk");
+	if (IS_ERR(ctrl_pdata->ahb_clk)) {
+		rc = PTR_ERR(ctrl_pdata->ahb_clk);
+		pr_err("%s: Unable to get mdss ahb clk. rc=%d\n",
+			__func__, rc);
+		goto mdss_dsi_clk_err;
+	}
+
+	ctrl_pdata->axi_clk = clk_get(dev, "bus_clk");
+	if (IS_ERR(ctrl_pdata->axi_clk)) {
+		rc = PTR_ERR(ctrl_pdata->axi_clk);
+		pr_err("%s: Unable to get axi bus 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)) {
-		pr_err("can't find dsi_byte_clk\n");
+		rc = PTR_ERR(ctrl_pdata->byte_clk);
+		pr_err("%s: can't find dsi_byte_clk. rc=%d\n",
+			__func__, rc);
 		ctrl_pdata->byte_clk = NULL;
 		goto mdss_dsi_clk_err;
 	}
 
 	ctrl_pdata->pixel_clk = clk_get(dev, "pixel_clk");
 	if (IS_ERR(ctrl_pdata->pixel_clk)) {
-		pr_err("can't find dsi_pixel_clk\n");
+		rc = PTR_ERR(ctrl_pdata->pixel_clk);
+		pr_err("%s: can't find dsi_pixel_clk. rc=%d\n",
+			__func__, rc);
 		ctrl_pdata->pixel_clk = NULL;
 		goto mdss_dsi_clk_err;
 	}
 
 	ctrl_pdata->esc_clk = clk_get(dev, "core_clk");
 	if (IS_ERR(ctrl_pdata->esc_clk)) {
-		pr_err("can't find dsi_esc_clk\n");
+		rc = PTR_ERR(ctrl_pdata->esc_clk);
+		pr_err("%s: can't find dsi_esc_clk. rc=%d\n",
+			__func__, rc);
 		ctrl_pdata->esc_clk = NULL;
 		goto mdss_dsi_clk_err;
 	}
 
-	return 0;
-
 mdss_dsi_clk_err:
-	mdss_dsi_clk_deinit(ctrl_pdata);
-	return -EPERM;
+	if (rc)
+		mdss_dsi_clk_deinit(ctrl_pdata);
+	return rc;
 }
 
 void mdss_dsi_clk_deinit(struct mdss_dsi_ctrl_pdata  *ctrl_pdata)
@@ -75,6 +97,10 @@
 		clk_put(ctrl_pdata->esc_clk);
 	if (ctrl_pdata->pixel_clk)
 		clk_put(ctrl_pdata->pixel_clk);
+	if (ctrl_pdata->axi_clk)
+		clk_put(ctrl_pdata->axi_clk);
+	if (ctrl_pdata->ahb_clk)
+		clk_put(ctrl_pdata->ahb_clk);
 }
 
 #define PREF_DIV_RATIO 27
@@ -156,6 +182,33 @@
 	return 0;
 }
 
+int mdss_dsi_enable_bus_clocks(struct mdss_dsi_ctrl_pdata *ctrl_pdata)
+{
+	int rc = 0;
+
+	rc = clk_prepare_enable(ctrl_pdata->ahb_clk);
+	if (rc) {
+		pr_err("%s: failed to enable ahb clock. rc=%d\n", __func__, rc);
+		goto error;
+	}
+
+	rc = clk_prepare_enable(ctrl_pdata->axi_clk);
+	if (rc) {
+		pr_err("%s: failed to enable ahb clock. rc=%d\n", __func__, rc);
+		clk_disable_unprepare(ctrl_pdata->ahb_clk);
+		goto error;
+	}
+
+error:
+	return rc;
+}
+
+void mdss_dsi_disable_bus_clocks(struct mdss_dsi_ctrl_pdata *ctrl_pdata)
+{
+	clk_disable_unprepare(ctrl_pdata->axi_clk);
+	clk_disable_unprepare(ctrl_pdata->ahb_clk);
+}
+
 void mdss_dsi_prepare_clocks(struct mdss_dsi_ctrl_pdata  *ctrl_pdata)
 {
 	clk_prepare(ctrl_pdata->byte_clk);
diff --git a/include/linux/android_alarm.h b/include/linux/android_alarm.h
index cbfeafc..096f777 100644
--- a/include/linux/android_alarm.h
+++ b/include/linux/android_alarm.h
@@ -70,6 +70,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);
 ktime_t alarm_get_elapsed_realtime(void);
 
 /* set rtc while preserving elapsed realtime */
diff --git a/include/linux/mfd/pm8xxx/pm8921-bms.h b/include/linux/mfd/pm8xxx/pm8921-bms.h
index a19c0b6..7562166 100644
--- a/include/linux/mfd/pm8xxx/pm8921-bms.h
+++ b/include/linux/mfd/pm8xxx/pm8921-bms.h
@@ -37,6 +37,12 @@
  *			is considered empty(mV)
  * @enable_fcc_learning:	if set the driver will learn full charge
  *				capacity of the battery upon end of charge
+ * @min_fcc_learning_soc:	minimum SOC as which CC counting for FCC
+ *				learning can start
+ * @min_fcc_ocv_pc:		minimum PC (lookup(OCV)) at which CC counting
+ *				for FCC learning can start
+ * @max_fcc_learning_samples:	Maximum number of FCC measurement cycles to be
+ *				used for FCC update
  * @normal_voltage_calc_ms:	The period of soc calculation in ms when battery
  *				voltage higher than cutoff voltage
  * @low_voltage_calc_ms:	The period of soc calculation in ms when battery
@@ -66,6 +72,9 @@
 	unsigned int			alarm_low_mv;
 	unsigned int			alarm_high_mv;
 	int				enable_fcc_learning;
+	int				min_fcc_learning_soc;
+	int				min_fcc_ocv_pc;
+	int				max_fcc_learning_samples;
 	int				shutdown_soc_valid_limit;
 	int				ignore_shutdown_soc;
 	int				adjust_soc_low_threshold;
diff --git a/include/linux/mhl_8334.h b/include/linux/mhl_8334.h
index a66a411..7297ff3 100644
--- a/include/linux/mhl_8334.h
+++ b/include/linux/mhl_8334.h
@@ -146,6 +146,7 @@
 	struct completion msc_cmd_done;
 	uint8_t devcap[16];
 	uint8_t devcap_state;
+	uint8_t status[2];
 	uint8_t path_en_state;
 	void *hdmi_mhl_ops;
 	struct work_struct mhl_msc_send_work;
@@ -161,6 +162,7 @@
 	spinlock_t lock;
 	bool tx_powered_off;
 	uint8_t dwnstream_hpd;
+	bool mhl_det_discon;
 };
 
 int mhl_i2c_reg_read(struct i2c_client *client,
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index 9a4e61d..2cb297e 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -13,6 +13,7 @@
 #include <linux/device.h>
 #include <linux/mmc/core.h>
 #include <linux/mod_devicetable.h>
+#include <linux/notifier.h>
 
 struct mmc_cid {
 	unsigned int		manfid;
@@ -173,7 +174,8 @@
 				wide_bus:1,
 				high_power:1,
 				high_speed:1,
-				disable_cd:1;
+				disable_cd:1,
+				async_intr_sup:1;
 };
 
 struct sdio_cis {
@@ -276,7 +278,6 @@
  *        percentage of sectors that should issue check for
  *        BKOPS need
  * @bkops_stats: BKOPS statistics
- * @poll_for_completion:	Poll on BKOPS completion
  * @cancel_delayed_work: A flag to indicate if the delayed work
  *        should be cancelled
  * @sectors_changed:  number of  sectors written or
@@ -294,10 +295,6 @@
  * is idle.
  */
 #define MMC_IDLE_BKOPS_TIME_MS 200
-	struct work_struct	poll_for_completion;
-/* Polling timeout and interval for waiting on non-blocking BKOPs completion */
-#define BKOPS_COMPLETION_POLLING_TIMEOUT_MS (4 * 60 * 1000) /* in ms */
-#define BKOPS_COMPLETION_POLLING_INTERVAL_MS 1000 /* in ms */
 	bool			cancel_delayed_work;
 	unsigned int		sectors_changed;
 /*
@@ -388,6 +385,8 @@
 
 	struct device_attribute rpm_attrib;
 	unsigned int		idle_timeout;
+	struct notifier_block        reboot_notify;
+	bool issue_long_pon;
 };
 
 /*
@@ -608,6 +607,7 @@
 	void (*remove)(struct mmc_card *);
 	int (*suspend)(struct mmc_card *);
 	int (*resume)(struct mmc_card *);
+	void (*shutdown)(struct mmc_card *);
 };
 
 extern int mmc_register_driver(struct mmc_driver *);
@@ -619,4 +619,5 @@
 			struct mmc_card *card);
 extern void mmc_blk_init_packed_statistics(struct mmc_card *card);
 extern void mmc_blk_disable_wr_packing(struct mmc_queue *mq);
+extern int mmc_send_long_pon(struct mmc_card *card);
 #endif /* LINUX_MMC_CARD_H */
diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h
index 995f8a2..f548721 100644
--- a/include/linux/mmc/core.h
+++ b/include/linux/mmc/core.h
@@ -146,6 +146,7 @@
 
 extern int mmc_stop_bkops(struct mmc_card *);
 extern int mmc_read_bkops_status(struct mmc_card *);
+extern bool mmc_card_is_prog_state(struct mmc_card *);
 extern struct mmc_async_req *mmc_start_req(struct mmc_host *,
 					   struct mmc_async_req *, int *);
 extern int mmc_interrupt_hpi(struct mmc_card *);
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index 48be19a..27b0c4b 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -292,6 +292,8 @@
 #define MMC_CAP2_STOP_REQUEST	(1 << 18)	/* Allow stop ongoing request */
 /* Use runtime PM framework provided by MMC core */
 #define MMC_CAP2_CORE_RUNTIME_PM (1 << 19)
+/* Allows Asynchronous SDIO irq while card is in 4-bit mode */
+#define MMC_CAP2_ASYNC_SDIO_IRQ_4BIT_MODE (1 << 20)
 	mmc_pm_flag_t		pm_caps;	/* supported pm features */
 
 	int			clk_requests;	/* internal reference counter */
@@ -414,6 +416,7 @@
 };
 
 extern struct mmc_host *mmc_alloc_host(int extra, struct device *);
+extern bool mmc_host_may_gate_card(struct mmc_card *);
 extern int mmc_add_host(struct mmc_host *);
 extern void mmc_remove_host(struct mmc_host *);
 extern void mmc_free_host(struct mmc_host *);
diff --git a/include/linux/mmc/sdio.h b/include/linux/mmc/sdio.h
index 58e52d4..961a4e1 100644
--- a/include/linux/mmc/sdio.h
+++ b/include/linux/mmc/sdio.h
@@ -162,6 +162,10 @@
 #define  SDIO_DTSx_SET_TYPE_A	(1 << SDIO_DRIVE_DTSx_SHIFT)
 #define  SDIO_DTSx_SET_TYPE_C	(2 << SDIO_DRIVE_DTSx_SHIFT)
 #define  SDIO_DTSx_SET_TYPE_D	(3 << SDIO_DRIVE_DTSx_SHIFT)
+
+#define SDIO_CCCR_INTERRUPT_EXTENSION	0x16
+#define	SDIO_SUPPORT_ASYNC_INTR		(1<<0)
+#define	SDIO_ENABLE_ASYNC_INTR		(1<<1)
 /*
  * Function Basic Registers (FBR)
  */
diff --git a/include/linux/msm_kgsl.h b/include/linux/msm_kgsl.h
index e8de769..ae88807 100644
--- a/include/linux/msm_kgsl.h
+++ b/include/linux/msm_kgsl.h
@@ -781,6 +781,27 @@
 
 #define IOCTL_KGSL_PERFCOUNTER_READ \
 	_IOWR(KGSL_IOC_TYPE, 0x3B, struct kgsl_perfcounter_read)
+/*
+ * struct kgsl_gpumem_sync_cache_bulk - argument to
+ * IOCTL_KGSL_GPUMEM_SYNC_CACHE_BULK
+ * @id_list: list of GPU buffer ids of the buffers to sync
+ * @count: number of GPU buffer ids in id_list
+ * @op: a mask of KGSL_GPUMEM_CACHE_* values
+ *
+ * Sync the cache for memory headed to and from the GPU. Certain
+ * optimizations can be made on the cache operation based on the total
+ * size of the working set of memory to be managed.
+ */
+struct kgsl_gpumem_sync_cache_bulk {
+	unsigned int *id_list;
+	unsigned int count;
+	unsigned int op;
+/* private: reserved for future use */
+	unsigned int __pad[2]; /* For future binary compatibility */
+};
+
+#define IOCTL_KGSL_GPUMEM_SYNC_CACHE_BULK \
+	_IOWR(KGSL_IOC_TYPE, 0x3C, struct kgsl_gpumem_sync_cache_bulk)
 
 #ifdef __KERNEL__
 #ifdef CONFIG_MSM_KGSL_DRM
diff --git a/include/linux/msm_mdp.h b/include/linux/msm_mdp.h
index e4df414..58fb5c1 100644
--- a/include/linux/msm_mdp.h
+++ b/include/linux/msm_mdp.h
@@ -436,6 +436,31 @@
 	uint32_t *b;
 };
 
+enum {
+	DISPLAY_MISR_EDP,
+	DISPLAY_MISR_DSI0,
+	DISPLAY_MISR_DSI1,
+	DISPLAY_MISR_HDMI,
+	DISPLAY_MISR_LCDC,
+	DISPLAY_MISR_ATV,
+	DISPLAY_MISR_DSI_CMD,
+	DISPLAY_MISR_MAX
+};
+
+enum {
+	MISR_OP_NONE,
+	MISR_OP_SFM,
+	MISR_OP_MFM,
+	MISR_OP_BM,
+	MISR_OP_MAX
+};
+
+struct mdp_misr {
+	uint32_t block_id;
+	uint32_t frame_count;
+	uint32_t crc_op_mode;
+	uint32_t crc_value[32];
+};
 
 /*
 
@@ -574,6 +599,9 @@
 	uint32_t data;
 };
 
+#define MDSS_MAX_BL_BRIGHTNESS 255
+#define AD_BL_LIN_LEN (MDSS_MAX_BL_BRIGHTNESS + 1)
+
 #define MDSS_AD_MODE_AUTO_BL	0x0
 #define MDSS_AD_MODE_AUTO_STR	0x1
 #define MDSS_AD_MODE_TARG_STR	0x3
@@ -600,6 +628,9 @@
 	uint16_t frame_h;
 	uint8_t logo_v;
 	uint8_t logo_h;
+	uint32_t bl_lin_len;
+	uint32_t *bl_lin;
+	uint32_t *bl_lin_inv;
 };
 
 struct mdss_ad_cfg {
@@ -635,6 +666,11 @@
 	uint32_t output;
 };
 
+struct mdss_calib_cfg {
+	uint32_t ops;
+	uint32_t calib_mask;
+};
+
 enum {
 	mdp_op_pcc_cfg,
 	mdp_op_csc_cfg,
@@ -647,6 +683,7 @@
 	mdp_op_calib_cfg,
 	mdp_op_ad_cfg,
 	mdp_op_ad_input,
+	mdp_op_calib_mode,
 	mdp_op_max,
 };
 
@@ -672,6 +709,7 @@
 		struct mdp_gamut_cfg_data gamut_cfg_data;
 		struct mdp_calib_config_data calib_cfg;
 		struct mdss_ad_init_cfg ad_init_cfg;
+		struct mdss_calib_cfg mdss_calib_cfg;
 		struct mdss_ad_input ad_input;
 	} data;
 };
@@ -684,6 +722,7 @@
 	metadata_op_vic,
 	metadata_op_wb_format,
 	metadata_op_get_caps,
+	metadata_op_crc,
 	metadata_op_max
 };
 
@@ -708,6 +747,7 @@
 	uint32_t op;
 	uint32_t flags;
 	union {
+		struct mdp_misr misr_request;
 		struct mdp_blend_cfg blend_cfg;
 		struct mdp_mixer_cfg mixer_cfg;
 		uint32_t panel_frame_rate;
diff --git a/include/linux/msm_thermal.h b/include/linux/msm_thermal.h
index f14cc52..2c1fa11 100644
--- a/include/linux/msm_thermal.h
+++ b/include/linux/msm_thermal.h
@@ -20,6 +20,7 @@
 	int32_t limit_temp_degC;
 	int32_t temp_hysteresis_degC;
 	uint32_t freq_step;
+	uint32_t freq_control_mask;
 	int32_t core_limit_temp_degC;
 	int32_t core_temp_hysteresis_degC;
 	uint32_t core_control_mask;
diff --git a/include/linux/qpnp/power-on.h b/include/linux/qpnp/power-on.h
index 6394988..5e87259 100644
--- a/include/linux/qpnp/power-on.h
+++ b/include/linux/qpnp/power-on.h
@@ -15,12 +15,38 @@
 
 #include <linux/errno.h>
 
+/**
+ * enum pon_trigger_source: List of PON trigger sources
+ * %PON_SMPL:		PON triggered by SMPL - Sudden Momentary Power Loss
+ * %PON_RTC:		PON triggered by RTC alarm
+ * %PON_DC_CHG:		PON triggered by insertion of DC charger
+ * %PON_USB_CHG:	PON triggered by insertion of USB
+ * %PON_PON1:		PON triggered by other PMIC (multi-PMIC option)
+ * %PON_CBLPWR_N:	PON triggered by power-cable insertion
+ * %PON_KPDPWR_N:	PON triggered by long press of the power-key
+ */
+enum pon_trigger_source {
+	PON_SMPL = 1,
+	PON_RTC,
+	PON_DC_CHG,
+	PON_USB_CHG,
+	PON_PON1,
+	PON_CBLPWR_N,
+	PON_KPDPWR_N,
+};
+
 #ifdef CONFIG_QPNP_POWER_ON
 int qpnp_pon_system_pwr_off(bool reset);
 int qpnp_pon_is_warm_reset(void);
+int qpnp_pon_trigger_config(enum pon_trigger_source pon_src, bool enable);
 #else
 static int qpnp_pon_system_pwr_off(bool reset) { return -ENODEV; }
 static inline int qpnp_pon_is_warm_reset(void) { return -ENODEV; }
+static inline int qpnp_pon_trigger_config(enum pon_trigger_source pon_src,
+							bool enable)
+{
+	return -ENODEV;
+}
 #endif
 
 #endif
diff --git a/include/linux/spmi.h b/include/linux/spmi.h
index d179eab..25d937a 100644
--- a/include/linux/spmi.h
+++ b/include/linux/spmi.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
@@ -54,7 +54,6 @@
 struct spmi_controller {
 	struct device		dev;
 	unsigned int		nr;
-	struct list_head	list;
 	int		(*cmd)(struct spmi_controller *, u8 opcode, u8 sid);
 	int		(*read_cmd)(struct spmi_controller *,
 				u8 opcode, u8 sid, u16 addr, u8 bc, u8 *buf);
diff --git a/include/linux/topology.h b/include/linux/topology.h
index 92a89f0..c2d9c17 100644
--- a/include/linux/topology.h
+++ b/include/linux/topology.h
@@ -118,7 +118,7 @@
 #define SD_MC_INIT (struct sched_domain) {				\
 	.min_interval		= 1,					\
 	.max_interval		= 4,					\
-	.busy_factor		= 64,					\
+	.busy_factor		= 1,					\
 	.imbalance_pct		= 125,					\
 	.cache_nice_tries	= 1,					\
 	.busy_idx		= 2,					\
diff --git a/include/linux/usb/msm_hsusb.h b/include/linux/usb/msm_hsusb.h
index 4ae3b79..f9729c4 100644
--- a/include/linux/usb/msm_hsusb.h
+++ b/include/linux/usb/msm_hsusb.h
@@ -424,6 +424,8 @@
 	bool pool_64_bit_align;
 	bool enable_hbm;
 	bool disable_park_mode;
+	bool consider_ipa_handshake;
+	bool ahb_async_bridge_bypass;
 };
 
 struct msm_usb_host_platform_data {
@@ -465,8 +467,16 @@
 };
 #ifdef CONFIG_USB_BAM
 bool msm_bam_lpm_ok(void);
+void msm_bam_set_hsic_host_dev(struct device *dev);
+void msm_bam_wait_for_hsic_prod_granted(void);
+bool msm_bam_hsic_lpm_ok(void);
+void msm_bam_hsic_notify_on_resume(void);
 #else
 static inline bool msm_bam_lpm_ok(void) { return true; }
+static inline void msm_bam_set_hsic_host_dev(struct device *dev) {}
+static inline void msm_bam_wait_for_hsic_prod_granted(void) {}
+static inline bool msm_bam_hsic_lpm_ok(void) { return true; }
+static inline void msm_bam_hsic_notify_on_resume(void) {}
 #endif
 #ifdef CONFIG_USB_CI13XXX_MSM
 void msm_hw_bam_disable(bool bam_disable);
diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
index 323f1e7..e883ad7 100644
--- a/include/linux/videodev2.h
+++ b/include/linux/videodev2.h
@@ -1671,13 +1671,6 @@
 
 /*  MPEG-class control IDs specific to the Samsung MFC 5.1 driver as defined by V4L2 */
 #define V4L2_CID_MPEG_MFC51_BASE				(V4L2_CTRL_CLASS_MPEG | 0x1100)
-#define V4L2_CID_MPEG_QCOM_BASE	(V4L2_CTRL_CLASS_MPEG | 0x2100)
-
-#define V4L2_CID_MPEG_QCOM_SET_PERF_LEVEL (V4L2_CID_MPEG_QCOM_BASE + 0)
-enum v3l2_mpeg_qcom_perf_level {
-	V4L2_CID_MPEG_QCOM_PERF_LEVEL_PERFORMANCE		= 0,
-	V4L2_CID_MPEG_QCOM_PERF_LEVEL_TURBO			= 1,
-};
 
 #define V4L2_CID_MPEG_MFC51_VIDEO_DECODER_H264_DISPLAY_DELAY		(V4L2_CID_MPEG_MFC51_BASE+0)
 #define V4L2_CID_MPEG_MFC51_VIDEO_DECODER_H264_DISPLAY_DELAY_ENABLE	(V4L2_CID_MPEG_MFC51_BASE+1)
diff --git a/include/linux/wcnss_wlan.h b/include/linux/wcnss_wlan.h
index 4711ec8..2ba585e 100644
--- a/include/linux/wcnss_wlan.h
+++ b/include/linux/wcnss_wlan.h
@@ -34,6 +34,7 @@
 #define HAVE_WCNSS_SUSPEND_RESUME_NOTIFY 1
 #define HAVE_WCNSS_RESET_INTR 1
 #define HAVE_WCNSS_CAL_DOWNLOAD 1
+#define HAVE_WCNSS_RX_BUFF_COUNT 1
 
 struct device *wcnss_wlan_get_device(void);
 struct resource *wcnss_wlan_get_memory_map(struct device *dev);
@@ -68,6 +69,8 @@
 void wcnss_pronto_log_debug_regs(void);
 int wcnss_device_ready(void);
 void wcnss_riva_dump_pmic_regs(void);
+int wcnss_xo_auto_detect_enabled(void);
+u32 wcnss_get_wlan_rx_buff_count(void);
 
 #define wcnss_wlan_get_drvdata(dev) dev_get_drvdata(dev)
 #define wcnss_wlan_set_drvdata(dev, data) dev_set_drvdata((dev), (data))
diff --git a/include/media/msm_cam_sensor.h b/include/media/msm_cam_sensor.h
index 47cf184..31798d6 100644
--- a/include/media/msm_cam_sensor.h
+++ b/include/media/msm_cam_sensor.h
@@ -184,6 +184,18 @@
 	uint16_t delay;
 };
 
+struct msm_camera_i2c_array_write_config {
+	struct msm_camera_i2c_reg_setting conf_array;
+	uint16_t slave_addr;
+};
+
+struct msm_camera_i2c_read_config {
+	uint16_t slave_addr;
+	uint16_t reg_addr;
+	enum msm_camera_i2c_data_type data_type;
+	uint16_t *data;
+};
+
 struct msm_camera_csid_vc_cfg {
 	uint8_t cid;
 	uint8_t dt;
@@ -320,7 +332,9 @@
 
 enum msm_sensor_cfg_type_t {
 	CFG_SET_SLAVE_INFO,
+	CFG_SLAVE_READ_I2C,
 	CFG_WRITE_I2C_ARRAY,
+	CFG_SLAVE_WRITE_I2C_ARRAY,
 	CFG_WRITE_I2C_SEQ_ARRAY,
 	CFG_POWER_UP,
 	CFG_POWER_DOWN,
diff --git a/include/media/msmb_pproc.h b/include/media/msmb_pproc.h
index aead2d2..6cd4995 100644
--- a/include/media/msmb_pproc.h
+++ b/include/media/msmb_pproc.h
@@ -112,9 +112,10 @@
 	struct timeval in_time, out_time;
 	void *cookie;
 	int32_t *status;
-
+	int32_t duplicate_output;
+	uint32_t duplicate_identity;
 	struct msm_cpp_buffer_info_t input_buffer_info;
-	struct msm_cpp_buffer_info_t output_buffer_info;
+	struct msm_cpp_buffer_info_t output_buffer_info[2];
 };
 
 struct cpp_hw_info {
diff --git a/include/media/tavarua.h b/include/media/tavarua.h
index 881b851..fea09dd 100644
--- a/include/media/tavarua.h
+++ b/include/media/tavarua.h
@@ -18,6 +18,7 @@
 #define BYTES_PER_BLOCK             (3)
 #define MAX_PS_LENGTH              (96)
 #define MAX_RT_LENGTH              (64)
+#define RX_STATIONS0_LEN           (15)
 
 #define XFRDAT0                    (0x20)
 #define XFRDAT1                    (0x21)
diff --git a/include/sound/Kbuild b/include/sound/Kbuild
index edadaa9..60847b0 100644
--- a/include/sound/Kbuild
+++ b/include/sound/Kbuild
@@ -12,3 +12,4 @@
 header-y += compress_params.h
 header-y += compress_offload.h
 header-y += lsm_params.h
+header-y += voice_params.h
diff --git a/include/sound/q6adm-v2.h b/include/sound/q6adm-v2.h
index 449694e..795bb99 100644
--- a/include/sound/q6adm-v2.h
+++ b/include/sound/q6adm-v2.h
@@ -54,6 +54,8 @@
 
 int adm_connect_afe_port(int mode, int session_id, int port_id);
 
+void adm_ec_ref_rx_id(int  port_id);
+
 int adm_get_copp_id(int port_id);
 
 void adm_set_multi_ch_map(char *channel_map);
diff --git a/include/sound/voice_params.h b/include/sound/voice_params.h
new file mode 100644
index 0000000..43e3b9d
--- /dev/null
+++ b/include/sound/voice_params.h
@@ -0,0 +1,14 @@
+#ifndef __VOICE_PARAMS_H__
+#define __VOICE_PARAMS_H__
+
+#include <linux/types.h>
+#include <sound/asound.h>
+
+enum voice_lch_mode {
+	VOICE_LCH_START = 1,
+	VOICE_LCH_STOP
+};
+
+#define SNDRV_VOICE_IOCTL_LCH _IOW('U', 0x00, enum voice_lch_mode)
+
+#endif
diff --git a/kernel/sched/rt.c b/kernel/sched/rt.c
index f8317df..8f32475 100644
--- a/kernel/sched/rt.c
+++ b/kernel/sched/rt.c
@@ -1604,7 +1604,6 @@
 	struct task_struct *next_task;
 	struct rq *lowest_rq;
 	int ret = 0;
-	bool moved = false;
 
 	if (!rq->rt.overloaded)
 		return 0;
@@ -1674,7 +1673,6 @@
 
 	deactivate_task(rq, next_task, 0);
 	set_task_cpu(next_task, lowest_rq->cpu);
-	moved = true;
 	activate_task(lowest_rq, next_task, 0);
 	ret = 1;
 
@@ -1685,11 +1683,6 @@
 out:
 	put_task_struct(next_task);
 
-	if (moved && task_notify_on_migrate(next_task))
-		atomic_notifier_call_chain(&migration_notifier_head,
-					   cpu_of(lowest_rq),
-					   (void *)cpu_of(rq));
-
 	return ret;
 }
 
@@ -1703,10 +1696,8 @@
 static int pull_rt_task(struct rq *this_rq)
 {
 	int this_cpu = this_rq->cpu, ret = 0, cpu;
-	struct task_struct *p = NULL;
+	struct task_struct *p;
 	struct rq *src_rq;
-	bool moved = false;
-	int src_cpu = 0;
 
 	if (likely(!rt_overloaded(this_rq)))
 		return 0;
@@ -1767,10 +1758,6 @@
 			deactivate_task(src_rq, p, 0);
 			set_task_cpu(p, this_cpu);
 			activate_task(this_rq, p, 0);
-
-			moved = true;
-			src_cpu = cpu_of(src_rq);
-
 			/*
 			 * We continue with the search, just in
 			 * case there's an even higher prio task
@@ -1782,11 +1769,6 @@
 		double_unlock_balance(this_rq, src_rq);
 	}
 
-	if (moved && task_notify_on_migrate(p))
-		atomic_notifier_call_chain(&migration_notifier_head,
-					   this_cpu,
-					   (void *)src_cpu);
-
 	return ret;
 }
 
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 155585a..8d6dee3 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -456,4 +456,8 @@
 	tristate
 
 config SND_SOC_MSM_HDMI_CODEC_RX
-	tristate
+	bool "HDMI Audio Playback"
+	depends on FB_MSM_MDSS_HDMI_PANEL && SND_SOC_MSM8974
+	help
+	HDMI audio drivers should be built only if the platform
+        supports hdmi panel.
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index f0cd026..c0469e3 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -104,7 +104,7 @@
 
 snd-soc-timpani-objs := timpani.o
 snd-soc-msm-stub-objs := msm_stub.o
-snd-soc-msm-hdmi-rx-objs := msm_hdmi_codec_rx.o
+obj-$(CONFIG_SND_SOC_MSM_HDMI_CODEC_RX) := msm_hdmi_codec_rx.o
 
 # Amp
 snd-soc-max9877-objs := max9877.o
@@ -214,7 +214,6 @@
 obj-$(CONFIG_SND_SOC_WM9713)	+= snd-soc-wm9713.o
 obj-$(CONFIG_SND_SOC_WM_HUBS)	+= snd-soc-wm-hubs.o
 obj-$(CONFIG_SND_SOC_MSM_STUB)  += snd-soc-msm-stub.o
-obj-$(CONFIG_SND_SOC_MSM_HDMI_CODEC_RX)  += snd-soc-msm-hdmi-rx.o
 
 # Amp
 obj-$(CONFIG_SND_SOC_MAX9877)	+= snd-soc-max9877.o
diff --git a/sound/soc/codecs/msm8x10-wcd.c b/sound/soc/codecs/msm8x10-wcd.c
index e1a904f..435f285 100644
--- a/sound/soc/codecs/msm8x10-wcd.c
+++ b/sound/soc/codecs/msm8x10-wcd.c
@@ -616,7 +616,7 @@
 				    0x00);
 		snd_soc_update_bits(codec,
 				    MSM8X10_WCD_A_CDC_CLK_OTHR_RESET_B1_CTL,
-				    0x01, 0x01);
+				    0x01, 0x00);
 		snd_soc_update_bits(codec,
 				    MSM8X10_WCD_A_CP_STATIC, 0x08, 0x00);
 		break;
@@ -1784,9 +1784,7 @@
 	} else {
 		snd_soc_update_bits(codec, MSM8X10_WCD_A_CDC_TOP_CLK_CTL,
 				    0x0f, 0x00);
-		snd_soc_update_bits(codec, MSM8X10_WCD_A_CDC_CLK_MCLK_CTL,
-				    0x01, 0x01);
-		snd_soc_update_bits(codec, MSM8X10_WCD_A_CDC_CLK_MCLK_CTL,
+		snd_soc_update_bits(codec, MSM8X10_WCD_A_CDC_CLK_PDM_CTL,
 				    0x03, 0x00);
 	}
 	return 0;
@@ -2282,7 +2280,6 @@
 	/* Reduce LINE DAC bias to 70% */
 	MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_RX_LINE_BIAS_PA, 0x78),
 
-
 	/* Disable TX7 internal biasing path which can cause leakage */
 	MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_BIAS_CURR_CTL_2, 0x04),
 	MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_MICB_CFILT_1_VAL, 0x60),
@@ -2290,6 +2287,13 @@
 	MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_TX_COM_BIAS, 0xE0),
 	MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_TX_1_EN, 0x32),
 	MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_TX_2_EN, 0x32),
+
+	/* ClassG fine tuning setting for 16 ohm HPH */
+	MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_CDC_CLSG_FREQ_THRESH_B1_CTL, 0x05),
+	MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_CDC_CLSG_FREQ_THRESH_B2_CTL, 0x0C),
+	MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_CDC_CLSG_FREQ_THRESH_B3_CTL, 0x1A),
+	MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_CDC_CLSG_FREQ_THRESH_B4_CTL, 0x47),
+	MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_CDC_CLSG_GAIN_THRESH_CTL, 0x23),
 };
 
 static void msm8x10_wcd_update_reg_defaults(struct snd_soc_codec *codec)
diff --git a/sound/soc/codecs/wcd9306.c b/sound/soc/codecs/wcd9306.c
index 669f8e3..6cdbb8c 100644
--- a/sound/soc/codecs/wcd9306.c
+++ b/sound/soc/codecs/wcd9306.c
@@ -67,14 +67,12 @@
 
 #define TAPAN_I2S_MASTER_MODE_MASK 0x08
 #define TAPAN_MCLK_CLK_12P288MHZ 12288000
-#define TAPAN_MCLK_CLK_9P6HZ 9600000
+#define TAPAN_MCLK_CLK_9P6MHZ 9600000
 
 #define TAPAN_SLIM_CLOSE_TIMEOUT 1000
 #define TAPAN_SLIM_IRQ_OVERFLOW (1 << 0)
 #define TAPAN_SLIM_IRQ_UNDERFLOW (1 << 1)
 #define TAPAN_SLIM_IRQ_PORT_CLOSED (1 << 2)
-#define TAPAN_MCLK_CLK_12P288MHZ 12288000
-#define TAPAN_MCLK_CLK_9P6HZ 9600000
 enum {
 	AIF1_PB = 0,
 	AIF1_CAP,
@@ -1867,7 +1865,7 @@
 		release_firmware(fw);
 
 		break;
-	case SND_SOC_DAPM_POST_PMD:
+	case SND_SOC_DAPM_PRE_PMD:
 		msleep(40);
 		snd_soc_update_bits(codec, TAPAN_A_CDC_ANC1_B1_CTL, 0x01, 0x00);
 		snd_soc_update_bits(codec, TAPAN_A_CDC_ANC2_B1_CTL, 0x02, 0x00);
@@ -2339,12 +2337,11 @@
 			snd_soc_update_bits(codec,
 					TAPAN_A_RX_HPH_CNP_EN, 0x30, 0x00);
 			msleep(40);
-		}
-		if (w->shift == 5) {
 			snd_soc_update_bits(codec,
 					TAPAN_A_TX_7_MBHC_EN, 0x80, 00);
 			ret |= tapan_codec_enable_anc(w, kcontrol, event);
 		}
+		break;
 	case SND_SOC_DAPM_POST_PMD:
 		ret = tapan_hph_pa_event(w, kcontrol, event);
 		break;
@@ -4271,9 +4268,6 @@
 	 */
 	TAPAN_REG_VAL(TAPAN_A_MICB_2_MBHC, 0x41),
 
-	/* not needed if MBHC is not needed */
-	/* Disable TX7 internal biasing path which can cause leakage */
-	TAPAN_REG_VAL(TAPAN_A_TX_SUP_SWITCH_CTRL_1, 0xBF),
 };
 
 static const struct tapan_reg_mask_val tapan_2_x_reg_reset_values[] = {
@@ -4449,7 +4443,7 @@
 	struct wcd9xxx *wcd9xxx;
 	struct snd_soc_dapm_context *dapm = &codec->dapm;
 	int ret = 0;
-	int i;
+	int i, rco_clk_rate;
 	void *ptr = NULL;
 
 	codec->control_data = dev_get_drvdata(codec->dev->parent);
@@ -4485,8 +4479,14 @@
 		return ret;
 	}
 
-	ret = wcd9xxx_mbhc_init(&tapan->mbhc, &tapan->resmgr, codec,
-				WCD9XXX_MBHC_VERSION_TAPAN);
+	if (TAPAN_IS_1_0(control->version))
+		rco_clk_rate = TAPAN_MCLK_CLK_12P288MHZ;
+	else
+		rco_clk_rate = TAPAN_MCLK_CLK_9P6MHZ;
+
+	ret = wcd9xxx_mbhc_init(&tapan->mbhc, &tapan->resmgr, codec, NULL,
+				WCD9XXX_MBHC_VERSION_TAPAN,
+				rco_clk_rate);
 	if (ret) {
 		pr_err("%s: mbhc init failed %d\n", __func__, ret);
 		return ret;
@@ -4510,7 +4510,7 @@
 		snd_soc_update_bits(codec, TAPAN_A_CHIP_CTL, 0x06, 0x0);
 		snd_soc_update_bits(codec, TAPAN_A_RX_COM_TIMER_DIV, 0x01,
 				0x01);
-	} else if (wcd9xxx->mclk_rate == TAPAN_MCLK_CLK_9P6HZ) {
+	} else if (wcd9xxx->mclk_rate == TAPAN_MCLK_CLK_9P6MHZ) {
 		snd_soc_update_bits(codec, TAPAN_A_CHIP_CTL, 0x06, 0x2);
 	}
 	tapan_codec_init_reg(codec);
diff --git a/sound/soc/codecs/wcd9320-tables.c b/sound/soc/codecs/wcd9320-tables.c
index 0885c09..e834b80 100644
--- a/sound/soc/codecs/wcd9320-tables.c
+++ b/sound/soc/codecs/wcd9320-tables.c
@@ -671,6 +671,16 @@
 	[TAIKO_A_CDC_MAD_BEACON_CTL_8] = 1,
 	[TAIKO_A_CDC_MAD_BEACON_IIR_CTL_PTR] = 1,
 	[TAIKO_A_CDC_MAD_BEACON_IIR_CTL_VAL] = 1,
+	[TAIKO_A_CDC_SPKR_CLIPDET_B1_CTL] = 1,
+	[TAIKO_A_CDC_SPKR_CLIPDET_VAL0] = 1,
+	[TAIKO_A_CDC_SPKR_CLIPDET_VAL1] = 1,
+	[TAIKO_A_CDC_SPKR_CLIPDET_VAL2] = 1,
+	[TAIKO_A_CDC_SPKR_CLIPDET_VAL3] = 1,
+	[TAIKO_A_CDC_SPKR_CLIPDET_VAL4] = 1,
+	[TAIKO_A_CDC_SPKR_CLIPDET_VAL5] = 1,
+	[TAIKO_A_CDC_SPKR_CLIPDET_VAL6] = 1,
+	[TAIKO_A_CDC_SPKR_CLIPDET_VAL7] = 1,
+
 };
 
 const u8 taiko_reset_reg_defaults[TAIKO_CACHE_SIZE] = {
@@ -1356,4 +1366,14 @@
 	    TAIKO_A_CDC_MAD_BEACON_IIR_CTL_PTR__POR,
 	[TAIKO_A_CDC_MAD_BEACON_IIR_CTL_VAL] =
 	    TAIKO_A_CDC_MAD_BEACON_IIR_CTL_VAL__POR,
+	[TAIKO_A_CDC_SPKR_CLIPDET_B1_CTL] =
+		TAIKO_A_CDC_SPKR_CLIPDET_B1_CTL__POR,
+	[TAIKO_A_CDC_SPKR_CLIPDET_VAL0] = TAIKO_A_CDC_SPKR_CLIPDET_VAL0__POR,
+	[TAIKO_A_CDC_SPKR_CLIPDET_VAL1] = TAIKO_A_CDC_SPKR_CLIPDET_VAL1__POR,
+	[TAIKO_A_CDC_SPKR_CLIPDET_VAL2] = TAIKO_A_CDC_SPKR_CLIPDET_VAL2__POR,
+	[TAIKO_A_CDC_SPKR_CLIPDET_VAL3] = TAIKO_A_CDC_SPKR_CLIPDET_VAL3__POR,
+	[TAIKO_A_CDC_SPKR_CLIPDET_VAL4] = TAIKO_A_CDC_SPKR_CLIPDET_VAL4__POR,
+	[TAIKO_A_CDC_SPKR_CLIPDET_VAL5] = TAIKO_A_CDC_SPKR_CLIPDET_VAL5__POR,
+	[TAIKO_A_CDC_SPKR_CLIPDET_VAL6] = TAIKO_A_CDC_SPKR_CLIPDET_VAL6__POR,
+	[TAIKO_A_CDC_SPKR_CLIPDET_VAL7] = TAIKO_A_CDC_SPKR_CLIPDET_VAL7__POR,
 };
diff --git a/sound/soc/codecs/wcd9320.c b/sound/soc/codecs/wcd9320.c
index 99e5237..703b8b8 100644
--- a/sound/soc/codecs/wcd9320.c
+++ b/sound/soc/codecs/wcd9320.c
@@ -41,10 +41,14 @@
 
 #define TAIKO_MAD_SLIMBUS_TX_PORT 12
 #define TAIKO_MAD_AUDIO_FIRMWARE_PATH "wcd9320/wcd9320_mad_audio.bin"
+#define TAIKO_VALIDATE_RX_SBPORT_RANGE(port) ((port >= 16) && (port <= 22))
+#define TAIKO_CONVERT_RX_SBPORT_ID(port) (port - 16) /* RX1 port ID = 0 */
 
 #define TAIKO_HPH_PA_SETTLE_COMP_ON 3000
 #define TAIKO_HPH_PA_SETTLE_COMP_OFF 13000
 
+#define DAPM_MICBIAS2_EXTERNAL_STANDALONE "MIC BIAS2 External Standalone"
+
 static atomic_t kp_taiko_priv;
 static int spkr_drv_wrnd_param_set(const char *val,
 				   const struct kernel_param *kp);
@@ -318,7 +322,7 @@
 #define TAIKO_SLIM_IRQ_UNDERFLOW (1 << 1)
 #define TAIKO_SLIM_IRQ_PORT_CLOSED (1 << 2)
 #define TAIKO_MCLK_CLK_12P288MHZ 12288000
-#define TAIKO_MCLK_CLK_9P6HZ 9600000
+#define TAIKO_MCLK_CLK_9P6MHZ 9600000
 
 #define TAIKO_FORMATS_S16_S24_LE (SNDRV_PCM_FMTBIT_S16_LE | \
 			SNDRV_PCM_FORMAT_S24_LE)
@@ -467,6 +471,8 @@
 	s32 dmic_1_2_clk_cnt;
 	s32 dmic_3_4_clk_cnt;
 	s32 dmic_5_6_clk_cnt;
+	s32 ldo_h_users;
+	s32 micb_2_users;
 
 	u32 anc_slot;
 	bool anc_func;
@@ -2659,16 +2665,26 @@
 		else if (strnstr(w->name, internal3_text, 30))
 			snd_soc_update_bits(codec, micb_int_reg, 0x3, 0x3);
 
-		if (taiko->mbhc_started &&
-		    taiko->resmgr.pdata->micbias.bias2_is_headset_only &&
-		    micb_ctl_reg == TAIKO_A_MICB_2_CTL)
-			wcd9xxx_resmgr_add_cond_update_bits(&taiko->resmgr,
-						  WCD9XXX_COND_HPH_MIC,
-						  micb_ctl_reg, w->shift,
-						  false);
-		else
+		if (taiko->mbhc_started && micb_ctl_reg == TAIKO_A_MICB_2_CTL) {
+			if (++taiko->micb_2_users == 1) {
+				if (taiko->resmgr.pdata->
+				    micbias.bias2_is_headset_only)
+					wcd9xxx_resmgr_add_cond_update_bits(
+							 &taiko->resmgr,
+							 WCD9XXX_COND_HPH_MIC,
+							 micb_ctl_reg, w->shift,
+							 false);
+				else
+					snd_soc_update_bits(codec, micb_ctl_reg,
+							    1 << w->shift,
+							    1 << w->shift);
+			}
+			pr_debug("%s: micb_2_users %d\n", __func__,
+				 taiko->micb_2_users);
+		} else {
 			snd_soc_update_bits(codec, micb_ctl_reg, 1 << w->shift,
 					    1 << w->shift);
+		}
 		break;
 	case SND_SOC_DAPM_POST_PMU:
 		usleep_range(20000, 20000);
@@ -2676,15 +2692,27 @@
 		wcd9xxx_resmgr_notifier_call(&taiko->resmgr, e_post_on);
 		break;
 	case SND_SOC_DAPM_POST_PMD:
-		if (taiko->mbhc_started &&
-		    taiko->resmgr.pdata->micbias.bias2_is_headset_only &&
-		    micb_ctl_reg == TAIKO_A_MICB_2_CTL)
-			wcd9xxx_resmgr_rm_cond_update_bits(&taiko->resmgr,
-						  WCD9XXX_COND_HPH_MIC,
-						  micb_ctl_reg, 7, false);
-		else
+		if (taiko->mbhc_started && micb_ctl_reg == TAIKO_A_MICB_2_CTL) {
+			if (--taiko->micb_2_users == 0) {
+				if (taiko->resmgr.pdata->
+				    micbias.bias2_is_headset_only)
+					wcd9xxx_resmgr_rm_cond_update_bits(
+							&taiko->resmgr,
+							WCD9XXX_COND_HPH_MIC,
+							micb_ctl_reg, 7, false);
+				else
+					snd_soc_update_bits(codec, micb_ctl_reg,
+							    1 << w->shift, 0);
+			}
+			pr_debug("%s: micb_2_users %d\n", __func__,
+				 taiko->micb_2_users);
+			WARN(taiko->micb_2_users < 0,
+			     "Unexpected micbias users %d\n",
+			     taiko->micb_2_users);
+		} else {
 			snd_soc_update_bits(codec, micb_ctl_reg, 1 << w->shift,
 					    0);
+		}
 
 		/* Let MBHC module know so micbias switch to be off */
 		wcd9xxx_resmgr_notifier_call(&taiko->resmgr, e_post_off);
@@ -2704,6 +2732,22 @@
 	return 0;
 }
 
+/* called under codec_resource_lock acquisition */
+static int taiko_enable_mbhc_micbias(struct snd_soc_codec *codec, bool enable)
+{
+	int rc;
+
+	if (enable)
+		rc = snd_soc_dapm_force_enable_pin(&codec->dapm,
+					     DAPM_MICBIAS2_EXTERNAL_STANDALONE);
+	else
+		rc = snd_soc_dapm_disable_pin(&codec->dapm,
+					     DAPM_MICBIAS2_EXTERNAL_STANDALONE);
+	if (!rc)
+		snd_soc_dapm_sync(&codec->dapm);
+	pr_debug("%s: leave ret %d\n", __func__, rc);
+	return rc;
+}
 
 static void tx_hpf_corner_freq_callback(struct work_struct *work)
 {
@@ -2935,18 +2979,65 @@
 	return 0;
 }
 
-static int taiko_codec_enable_ldo_h(struct snd_soc_dapm_widget *w,
-	struct snd_kcontrol *kcontrol, int event)
+/* called under codec_resource_lock acquisition */
+static int __taiko_codec_enable_ldo_h(struct snd_soc_dapm_widget *w,
+				      struct snd_kcontrol *kcontrol, int event)
 {
+	struct snd_soc_codec *codec = w->codec;
+	struct taiko_priv *priv = snd_soc_codec_get_drvdata(codec);
+
+	pr_debug("%s: enter\n", __func__);
 	switch (event) {
-	case SND_SOC_DAPM_POST_PMU:
+	case SND_SOC_DAPM_PRE_PMU:
+		if (++priv->ldo_h_users == 1) {
+			wcd9xxx_resmgr_get_bandgap(&priv->resmgr,
+						   WCD9XXX_BANDGAP_AUDIO_MODE);
+			wcd9xxx_resmgr_get_clk_block(&priv->resmgr,
+						     WCD9XXX_CLK_RCO);
+			snd_soc_update_bits(codec, TAIKO_A_LDO_H_MODE_1, 1 << 7,
+					    1 << 7);
+			wcd9xxx_resmgr_put_clk_block(&priv->resmgr,
+						     WCD9XXX_CLK_RCO);
+			pr_debug("%s: ldo_h_users %d\n", __func__,
+				 priv->ldo_h_users);
+			/* LDO enable requires 1ms to settle down */
+			usleep_range(1000, 1000);
+		}
+		break;
 	case SND_SOC_DAPM_POST_PMD:
-		usleep_range(1000, 1000);
+		if (--priv->ldo_h_users == 0) {
+			wcd9xxx_resmgr_get_clk_block(&priv->resmgr,
+						     WCD9XXX_CLK_RCO);
+			snd_soc_update_bits(codec, TAIKO_A_LDO_H_MODE_1, 1 << 7,
+					    0);
+			wcd9xxx_resmgr_put_clk_block(&priv->resmgr,
+						     WCD9XXX_CLK_RCO);
+			wcd9xxx_resmgr_put_bandgap(&priv->resmgr,
+						   WCD9XXX_BANDGAP_AUDIO_MODE);
+			pr_debug("%s: ldo_h_users %d\n", __func__,
+				 priv->ldo_h_users);
+		}
+		WARN(priv->ldo_h_users < 0, "Unexpected ldo_h users %d\n",
+		     priv->ldo_h_users);
 		break;
 	}
+	pr_debug("%s: leave\n", __func__);
 	return 0;
 }
 
+static int taiko_codec_enable_ldo_h(struct snd_soc_dapm_widget *w,
+				    struct snd_kcontrol *kcontrol, int event)
+{
+	int rc;
+	struct snd_soc_codec *codec = w->codec;
+	struct taiko_priv *priv = snd_soc_codec_get_drvdata(codec);
+
+	WCD9XXX_BCL_LOCK(&priv->resmgr);
+	rc = __taiko_codec_enable_ldo_h(w, kcontrol, event);
+	WCD9XXX_BCL_UNLOCK(&priv->resmgr);
+	return rc;
+}
+
 static int taiko_codec_enable_rx_bias(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
@@ -3106,7 +3197,7 @@
 		}
 		release_firmware(fw);
 		break;
-	case SND_SOC_DAPM_POST_PMD:
+	case SND_SOC_DAPM_PRE_PMD:
 		msleep(40);
 		snd_soc_update_bits(codec, TAIKO_A_CDC_ANC1_B1_CTL, 0x01, 0x00);
 		snd_soc_update_bits(codec, TAIKO_A_CDC_ANC2_B1_CTL, 0x02, 0x00);
@@ -3207,8 +3298,6 @@
 			snd_soc_update_bits(codec,
 					TAIKO_A_RX_HPH_CNP_EN, 0x30, 0x00);
 			msleep(40);
-		}
-		if (w->shift == 5) {
 			snd_soc_update_bits(codec,
 					TAIKO_A_TX_7_MBHC_EN, 0x80, 00);
 			ret |= taiko_codec_enable_anc(w, kcontrol, event);
@@ -3696,13 +3785,15 @@
 	{"RX7 MIX1 INP2", "RX6", "SLIM RX6"},
 	{"RX7 MIX1 INP2", "RX7", "SLIM RX7"},
 	{"RX7 MIX1 INP2", "IIR1", "IIR1"},
+	{"RX7 MIX1 INP2", "IIR2", "IIR2"},
+
+	/* IIR1, IIR2 inputs to Second RX Mixer on RX1, RX2 and RX7 chains. */
 	{"RX1 MIX2 INP1", "IIR1", "IIR1"},
 	{"RX1 MIX2 INP2", "IIR1", "IIR1"},
 	{"RX2 MIX2 INP1", "IIR1", "IIR1"},
 	{"RX2 MIX2 INP2", "IIR1", "IIR1"},
 	{"RX7 MIX2 INP1", "IIR1", "IIR1"},
 	{"RX7 MIX2 INP2", "IIR1", "IIR1"},
-	{"RX7 MIX1 INP2", "IIR2", "IIR2"},
 	{"RX1 MIX2 INP1", "IIR2", "IIR2"},
 	{"RX1 MIX2 INP2", "IIR2", "IIR2"},
 	{"RX2 MIX2 INP1", "IIR2", "IIR2"},
@@ -3780,6 +3871,13 @@
 	{"IIR1 INP1 MUX", "DEC8", "DEC8 MUX"},
 	{"IIR1 INP1 MUX", "DEC9", "DEC9 MUX"},
 	{"IIR1 INP1 MUX", "DEC10", "DEC10 MUX"},
+	{"IIR1 INP1 MUX", "RX1", "SLIM RX1"},
+	{"IIR1 INP1 MUX", "RX2", "SLIM RX2"},
+	{"IIR1 INP1 MUX", "RX3", "SLIM RX3"},
+	{"IIR1 INP1 MUX", "RX4", "SLIM RX4"},
+	{"IIR1 INP1 MUX", "RX5", "SLIM RX5"},
+	{"IIR1 INP1 MUX", "RX6", "SLIM RX6"},
+	{"IIR1 INP1 MUX", "RX7", "SLIM RX7"},
 
 	{"IIR2", NULL, "IIR2 INP1 MUX"},
 	{"IIR2 INP1 MUX", "DEC1", "DEC1 MUX"},
@@ -3792,6 +3890,13 @@
 	{"IIR2 INP1 MUX", "DEC8", "DEC8 MUX"},
 	{"IIR2 INP1 MUX", "DEC9", "DEC9 MUX"},
 	{"IIR2 INP1 MUX", "DEC10", "DEC10 MUX"},
+	{"IIR2 INP1 MUX", "RX1", "SLIM RX1"},
+	{"IIR2 INP1 MUX", "RX2", "SLIM RX2"},
+	{"IIR2 INP1 MUX", "RX3", "SLIM RX3"},
+	{"IIR2 INP1 MUX", "RX4", "SLIM RX4"},
+	{"IIR2 INP1 MUX", "RX5", "SLIM RX5"},
+	{"IIR2 INP1 MUX", "RX6", "SLIM RX6"},
+	{"IIR2 INP1 MUX", "RX7", "SLIM RX7"},
 
 	{"MIC BIAS1 Internal1", NULL, "LDO_H"},
 	{"MIC BIAS1 Internal2", NULL, "LDO_H"},
@@ -3804,7 +3909,7 @@
 	{"MIC BIAS3 Internal2", NULL, "LDO_H"},
 	{"MIC BIAS3 External", NULL, "LDO_H"},
 	{"MIC BIAS4 External", NULL, "LDO_H"},
-
+	{DAPM_MICBIAS2_EXTERNAL_STANDALONE, NULL, "LDO_H Standalone"},
 };
 
 static int taiko_readable(struct snd_soc_codec *ssc, unsigned int reg)
@@ -4275,6 +4380,65 @@
 	return 0;
 }
 
+static void taiko_set_rxsb_port_format(struct snd_pcm_hw_params *params,
+				       struct snd_soc_dai *dai)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	struct taiko_priv *taiko_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;
+		taiko_p->dai[dai->id].bit_width = 16;
+		break;
+	case SNDRV_PCM_FORMAT_S24_LE:
+		bit_sel = 0x0;
+		taiko_p->dai[dai->id].bit_width = 24;
+		break;
+	default:
+		dev_err(codec->dev, "Invalid format\n");
+		return;
+	}
+
+	cdc_dai = &taiko_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) ||
+		    !TAIKO_VALIDATE_RX_SBPORT_RANGE(port)) {
+			dev_warn(codec->dev,
+				 "%s: invalid port ID %d returned for RX DAI\n",
+				 __func__, port);
+			return;
+		}
+
+		port = TAIKO_CONVERT_RX_SBPORT_ID(port);
+
+		if (port <= 3) {
+			sb_ctl_reg = TAIKO_A_CDC_CONN_RX_SB_B1_CTL;
+			field_shift = port << 1;
+		} else if (port <= 6) {
+			sb_ctl_reg = TAIKO_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",
+			__func__, sb_ctl_reg, field_shift);
+		snd_soc_update_bits(codec, sb_ctl_reg, 0x3 << field_shift,
+				    bit_sel << field_shift);
+	}
+}
+
 static int taiko_hw_params(struct snd_pcm_substream *substream,
 			    struct snd_pcm_hw_params *params,
 			    struct snd_soc_dai *dai)
@@ -4389,29 +4553,7 @@
 			snd_soc_update_bits(codec, TAIKO_A_CDC_CLK_RX_I2S_CTL,
 					    0x03, (rx_fs_rate >> 0x05));
 		} else {
-			switch (params_format(params)) {
-			case SNDRV_PCM_FORMAT_S16_LE:
-				snd_soc_update_bits(codec,
-					TAIKO_A_CDC_CONN_RX_SB_B1_CTL,
-					0xFF, 0xAA);
-				snd_soc_update_bits(codec,
-					TAIKO_A_CDC_CONN_RX_SB_B2_CTL,
-					0xFF, 0x2A);
-				taiko->dai[dai->id].bit_width = 16;
-				break;
-			case SNDRV_PCM_FORMAT_S24_LE:
-				snd_soc_update_bits(codec,
-					TAIKO_A_CDC_CONN_RX_SB_B1_CTL,
-					0xFF, 0x00);
-				snd_soc_update_bits(codec,
-					TAIKO_A_CDC_CONN_RX_SB_B2_CTL,
-					0xFF, 0x00);
-				taiko->dai[dai->id].bit_width = 24;
-				break;
-			default:
-				dev_err(codec->dev, "Invalid format\n");
-				break;
-			}
+			taiko_set_rxsb_port_format(params, dai);
 			taiko->dai[dai->id].rate   = params_rate(params);
 		}
 		break;
@@ -5122,8 +5264,17 @@
 	SND_SOC_DAPM_SUPPLY("CDC_CONN", WCD9XXX_A_CDC_CLK_OTHR_CTL, 2, 0, NULL,
 		0),
 
-	SND_SOC_DAPM_SUPPLY("LDO_H", TAIKO_A_LDO_H_MODE_1, 7, 0,
-		taiko_codec_enable_ldo_h, SND_SOC_DAPM_POST_PMU),
+	SND_SOC_DAPM_SUPPLY("LDO_H", SND_SOC_NOPM, 7, 0,
+			    taiko_codec_enable_ldo_h,
+			    SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	/*
+	 * DAPM 'LDO_H Standalone' is to be powered by mbhc driver after
+	 * acquring codec_resource lock.
+	 * So call __taiko_codec_enable_ldo_h instead and avoid deadlock.
+	 */
+	SND_SOC_DAPM_SUPPLY("LDO_H Standalone", SND_SOC_NOPM, 7, 0,
+			    __taiko_codec_enable_ldo_h,
+			    SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
 
 	SND_SOC_DAPM_SUPPLY("COMP0_CLK", SND_SOC_NOPM, 0, 0,
 		taiko_config_compander, SND_SOC_DAPM_PRE_PMU |
@@ -5228,6 +5379,10 @@
 	SND_SOC_DAPM_MUX("ANC1 FB MUX", SND_SOC_NOPM, 0, 0, &anc1_fb_mux),
 
 	SND_SOC_DAPM_INPUT("AMIC2"),
+	SND_SOC_DAPM_MICBIAS_E(DAPM_MICBIAS2_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 BIAS2 External", SND_SOC_NOPM, 7, 0,
 			       taiko_codec_enable_micbias,
 			       SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
@@ -5339,10 +5494,10 @@
 
 	/* Sidetone */
 	SND_SOC_DAPM_MUX("IIR1 INP1 MUX", SND_SOC_NOPM, 0, 0, &iir1_inp1_mux),
-	SND_SOC_DAPM_PGA("IIR1", TAIKO_A_CDC_CLK_SD_CTL, 0, 0, NULL, 0),
+	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_PGA("IIR2", TAIKO_A_CDC_CLK_SD_CTL, 1, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("IIR2", TAIKO_A_CDC_CLK_SD_CTL, 1, 0, NULL, 0),
 
 	/* AUX PGA */
 	SND_SOC_DAPM_ADC_E("AUX_PGA_Left", NULL, TAIKO_A_RX_AUX_SW_CTL, 7, 0,
@@ -5586,7 +5741,7 @@
 	snd_soc_update_bits(codec, TAIKO_A_MICB_4_CTL, 0x1E, value);
 
 	/* Set the DMIC sample rate */
-	if (pdata->mclk_rate == TAIKO_MCLK_CLK_9P6HZ) {
+	if (pdata->mclk_rate == TAIKO_MCLK_CLK_9P6MHZ) {
 		switch (pdata->dmic_sample_rate) {
 		case TAIKO_DMIC_SAMPLE_RATE_2P4MHZ:
 			dmic_sample_rate_value = TAIKO_DMIC_SAMPLE_RATE_DIV_4;
@@ -6009,6 +6164,7 @@
 	int ret = 0;
 	struct snd_soc_codec *codec;
 	struct taiko_priv *taiko;
+	int rco_clk_rate;
 
 	codec = (struct snd_soc_codec *)(wcd9xxx->ssr_priv);
 	taiko = snd_soc_codec_get_drvdata(codec);
@@ -6039,8 +6195,16 @@
 	if (taiko->mbhc_started) {
 		wcd9xxx_mbhc_deinit(&taiko->mbhc);
 		taiko->mbhc_started = false;
+
+		if (TAIKO_IS_1_0(wcd9xxx->version))
+			rco_clk_rate = TAIKO_MCLK_CLK_12P288MHZ;
+		else
+			rco_clk_rate = TAIKO_MCLK_CLK_9P6MHZ;
+
 		ret = wcd9xxx_mbhc_init(&taiko->mbhc, &taiko->resmgr, codec,
-					WCD9XXX_MBHC_VERSION_TAIKO);
+					taiko_enable_mbhc_micbias,
+					WCD9XXX_MBHC_VERSION_TAIKO,
+					rco_clk_rate);
 		if (ret) {
 			pr_err("%s: mbhc init failed %d\n", __func__, ret);
 		} else {
@@ -6172,7 +6336,7 @@
 	struct wcd9xxx *wcd9xxx;
 	struct snd_soc_dapm_context *dapm = &codec->dapm;
 	int ret = 0;
-	int i;
+	int i, rco_clk_rate;
 	void *ptr = NULL;
 	struct wcd9xxx *core = dev_get_drvdata(codec->dev->parent);
 
@@ -6210,9 +6374,16 @@
 	taiko->clsh_d.buck_mv = taiko_codec_get_buck_mv(codec);
 	wcd9xxx_clsh_init(&taiko->clsh_d, &taiko->resmgr);
 
+	if (TAIKO_IS_1_0(core->version))
+		rco_clk_rate = TAIKO_MCLK_CLK_12P288MHZ;
+	else
+		rco_clk_rate = TAIKO_MCLK_CLK_9P6MHZ;
+
 	/* init and start mbhc */
 	ret = wcd9xxx_mbhc_init(&taiko->mbhc, &taiko->resmgr, codec,
-				WCD9XXX_MBHC_VERSION_TAIKO);
+				taiko_enable_mbhc_micbias,
+				WCD9XXX_MBHC_VERSION_TAIKO,
+				rco_clk_rate);
 	if (ret) {
 		pr_err("%s: mbhc init failed %d\n", __func__, ret);
 		goto err_init;
@@ -6227,11 +6398,13 @@
 	taiko->aux_pga_cnt = 0;
 	taiko->aux_l_gain = 0x1F;
 	taiko->aux_r_gain = 0x1F;
+	taiko->ldo_h_users = 0;
+	taiko->micb_2_users = 0;
 	taiko_update_reg_defaults(codec);
 	pr_debug("%s: MCLK Rate = %x\n", __func__, wcd9xxx->mclk_rate);
 	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_9P6HZ)
+	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);
 	ret = taiko_handle_pdata(taiko);
diff --git a/sound/soc/codecs/wcd9xxx-mbhc.c b/sound/soc/codecs/wcd9xxx-mbhc.c
index cc22fd4..887a324 100644
--- a/sound/soc/codecs/wcd9xxx-mbhc.c
+++ b/sound/soc/codecs/wcd9xxx-mbhc.c
@@ -9,7 +9,6 @@
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
  */
-
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/firmware.h>
@@ -47,7 +46,7 @@
 				  SND_JACK_BTN_6 | SND_JACK_BTN_7)
 
 #define NUM_DCE_PLUG_DETECT 3
-#define NUM_DCE_PLUG_INS_DETECT 4
+#define NUM_DCE_PLUG_INS_DETECT 5
 #define NUM_ATTEMPTS_INSERT_DETECT 25
 #define NUM_ATTEMPTS_TO_REPORT 5
 
@@ -75,7 +74,6 @@
 
 #define MCLK_RATE_12288KHZ 12288000
 #define MCLK_RATE_9600KHZ 9600000
-#define WCD9XXX_RCO_CLK_RATE MCLK_RATE_12288KHZ
 
 #define DEFAULT_DCE_STA_WAIT 55
 #define DEFAULT_DCE_WAIT 60000
@@ -83,20 +81,23 @@
 
 #define VDDIO_MICBIAS_MV 1800
 
+#define WCD9XXX_MICBIAS_PULLDOWN_SETTLE_US 5000
+
 #define WCD9XXX_HPHL_STATUS_READY_WAIT_US 1000
-#define WCD9XXX_MUX_SWITCH_READY_WAIT_US 100
+#define WCD9XXX_MUX_SWITCH_READY_WAIT_MS 50
 #define WCD9XXX_MEAS_DELTA_MAX_MV 50
 #define WCD9XXX_MEAS_INVALD_RANGE_LOW_MV 20
 #define WCD9XXX_MEAS_INVALD_RANGE_HIGH_MV 80
 #define WCD9XXX_GM_SWAP_THRES_MIN_MV 150
 #define WCD9XXX_GM_SWAP_THRES_MAX_MV 650
+#define WCD9XXX_THRESHOLD_MIC_THRESHOLD 200
 
 #define WCD9XXX_USLEEP_RANGE_MARGIN_US 1000
 
 #define WCD9XXX_IRQ_MBHC_JACK_SWITCH_TAIKO 28
 #define WCD9XXX_IRQ_MBHC_JACK_SWITCH_TAPAN 21
 
-static bool detect_use_vddio_switch;
+static bool detect_use_vddio_switch = true;
 
 struct wcd9xxx_mbhc_detect {
 	u16 dce;
@@ -278,6 +279,11 @@
 
 	codec = mbhc->codec;
 
+	if (mbhc->micbias_enable) {
+		pr_debug("%s: micbias is already on\n", __func__);
+		return;
+	}
+
 	if (vddio_switch && !mbhc->mbhc_micbias_switched &&
 	    (!checkpolling || mbhc->polling_active)) {
 		if (restartpolling)
@@ -802,6 +808,12 @@
 			mbhc->buttons_pressed &=
 				~WCD9XXX_JACK_BUTTON_MASK;
 		}
+
+		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 = false;
+		}
 		pr_debug("%s: Reporting removal %d(%x)\n", __func__,
 			 jack_type, mbhc->hph_status);
 		wcd9xxx_jack_report(mbhc, &mbhc->headset_jack, mbhc->hph_status,
@@ -815,8 +827,17 @@
 		if (mbhc->mbhc_cfg->detect_extn_cable) {
 			/* Report removal of current jack type */
 			if (mbhc->hph_status && mbhc->hph_status != jack_type) {
+				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 = false;
+				}
 				pr_debug("%s: Reporting removal (%x)\n",
-					 __func__, mbhc->hph_status);
+						__func__, mbhc->hph_status);
 				wcd9xxx_jack_report(mbhc, &mbhc->headset_jack,
 						    0, WCD9XXX_JACK_MASK);
 				mbhc->hph_status = 0;
@@ -835,6 +856,11 @@
 		} else if (jack_type == SND_JACK_LINEOUT) {
 			mbhc->current_plug = PLUG_TYPE_HIGH_HPH;
 		}
+
+		if (mbhc->micbias_enable && mbhc->micbias_enable_cb) {
+			pr_debug("%s: Enabling micbias\n", __func__);
+			mbhc->micbias_enable_cb(mbhc->codec, true);
+		}
 		pr_debug("%s: Reporting insertion %d(%x)\n", __func__,
 			 jack_type, mbhc->hph_status);
 		wcd9xxx_jack_report(mbhc, &mbhc->headset_jack,
@@ -882,9 +908,9 @@
 	vddio_k = wcd9xxx_resmgr_get_k_val(mbhc->resmgr, VDDIO_MICBIAS_MV);
 	mb_k = wcd9xxx_resmgr_get_k_val(mbhc->resmgr, mbhc->mbhc_data.micb_mv);
 	if (tovddio)
-		r = v * vddio_k / mb_k;
+		r = v * (vddio_k + 4) / (mb_k + 4);
 	else
-		r = v * mb_k / vddio_k;
+		r = v * (mb_k + 4) / (vddio_k + 4);
 	return r;
 }
 
@@ -988,19 +1014,17 @@
 	return __wcd9xxx_codec_sta_dce(mbhc, dce, false, norel);
 }
 
-static s32 wcd9xxx_codec_sta_dce_v(struct wcd9xxx_mbhc *mbhc, s8 dce,
-				   u16 bias_value)
+static s32 __wcd9xxx_codec_sta_dce_v(struct wcd9xxx_mbhc *mbhc, s8 dce,
+				     u16 bias_value, s16 z)
 {
-	s16 value, z, mb;
+	s16 value, mb;
 	s32 mv;
 
 	value = bias_value;
 	if (dce) {
-		z = (mbhc->mbhc_data.dce_z);
 		mb = (mbhc->mbhc_data.dce_mb);
 		mv = (value - z) * (s32)mbhc->mbhc_data.micb_mv / (mb - z);
 	} else {
-		z = (mbhc->mbhc_data.sta_z);
 		mb = (mbhc->mbhc_data.sta_mb);
 		mv = (value - z) * (s32)mbhc->mbhc_data.micb_mv / (mb - z);
 	}
@@ -1008,6 +1032,14 @@
 	return mv;
 }
 
+static s32 wcd9xxx_codec_sta_dce_v(struct wcd9xxx_mbhc *mbhc, s8 dce,
+				   u16 bias_value)
+{
+	s16 z;
+	z = dce ? (s16)mbhc->mbhc_data.dce_z : (s16)mbhc->mbhc_data.sta_z;
+	return __wcd9xxx_codec_sta_dce_v(mbhc, dce, bias_value, z);
+}
+
 /* called only from interrupt which is under codec_resource_lock acquisition */
 static short wcd9xxx_mbhc_setup_hs_polling(struct wcd9xxx_mbhc *mbhc)
 {
@@ -1080,7 +1112,7 @@
 
 	snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x2, 0x2);
 	snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_B1_CTL, 0x6, 0x0);
-	snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.mbhc_reg, 0x80, 0x00);
+	__wcd9xxx_switch_micbias(mbhc, 0, false, false);
 
 	usleep_range(generic->t_shutdown_plug_rem,
 		     generic->t_shutdown_plug_rem);
@@ -1117,6 +1149,7 @@
 
 static void wcd9xxx_onoff_vddio_switch(struct wcd9xxx_mbhc *mbhc, bool on)
 {
+	pr_debug("%s: vddio %d\n", __func__, on);
 	if (on) {
 		snd_soc_update_bits(mbhc->codec, mbhc->mbhc_bias_regs.mbhc_reg,
 				    1 << 7, 1 << 7);
@@ -1160,7 +1193,7 @@
 	int ch;
 	enum wcd9xxx_mbhc_plug_type type;
 	int vdce;
-	struct wcd9xxx_mbhc_detect *d, *dprev, *dgnd = NULL;
+	struct wcd9xxx_mbhc_detect *d, *dprev, *dgnd = NULL, *dvddio = NULL;
 	int maxv = 0, minv = 0;
 	const struct wcd9xxx_mbhc_plug_type_cfg *plug_type =
 	    WCD9XXX_MBHC_CAL_PLUG_TYPE_PTR(mbhc->mbhc_cfg->calibration);
@@ -1182,7 +1215,7 @@
 			d->_type = PLUG_TYPE_HIGH_HPH;
 
 		ch += d->hphl_status & 0x01;
-		if (!d->swap_gnd && !d->hwvalue) {
+		if (!d->swap_gnd && !d->hwvalue && !d->vddio) {
 			if (maxv < d->_vdces)
 				maxv = d->_vdces;
 			if (!minv || minv > d->_vdces)
@@ -1215,6 +1248,11 @@
 	}
 
 	for (i = 0, d = dt; i < size; i++, d++) {
+		if (d->vddio) {
+			dvddio = d;
+			continue;
+		}
+
 		if ((i > 0) && (d->_type != dprev->_type)) {
 			pr_debug("%s: Invalid, inconsistent types\n", __func__);
 			type = PLUG_TYPE_INVALID;
@@ -1249,11 +1287,69 @@
 		    __func__, type);
 		type = PLUG_TYPE_INVALID;
 	}
+	if (type == PLUG_TYPE_HEADSET && dvddio) {
+		if ((dvddio->_vdces > hs_max) ||
+		    (dvddio->_vdces > minv + WCD9XXX_THRESHOLD_MIC_THRESHOLD)) {
+			pr_debug("%s: Headset with threshold on MIC detected\n",
+				 __func__);
+			if (mbhc->mbhc_cfg->micbias_enable_flags &
+			    (1 << MBHC_MICBIAS_ENABLE_THRESHOLD_HEADSET))
+				mbhc->micbias_enable = true;
+		} else {
+			pr_debug("%s: Headset with regular MIC detected\n",
+				 __func__);
+			if (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);
+	pr_debug("%s: Plug type %d detected, micbias_enable %d\n", __func__,
+		 type, mbhc->micbias_enable);
 	return type;
 }
 
+/*
+ * Pull down MBHC micbias for provided duration in microsecond.
+ */
+static int wcd9xxx_pull_down_micbias(struct wcd9xxx_mbhc *mbhc, int us)
+{
+	bool micbiasconn = false;
+	struct snd_soc_codec *codec = mbhc->codec;
+	const u16 ctlreg = mbhc->mbhc_bias_regs.ctl_reg;
+
+	/*
+	 * Disable MBHC to micbias connection to pull down
+	 * micbias and pull down micbias for a moment.
+	 */
+	if ((snd_soc_read(mbhc->codec, ctlreg) & 0x01)) {
+		WARN_ONCE(1, "MBHC micbias is already pulled down unexpectedly\n");
+		return -EFAULT;
+	}
+
+	if ((snd_soc_read(mbhc->codec, WCD9XXX_A_MAD_ANA_CTRL) & 1 << 4)) {
+		snd_soc_update_bits(mbhc->codec, WCD9XXX_A_MAD_ANA_CTRL,
+				    1 << 4, 0);
+		micbiasconn = true;
+	}
+
+	snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.ctl_reg, 0x01, 0x01);
+
+	/*
+	 * Pull down for 1ms to discharge bias. Give small margin (10us) to be
+	 * able to get consistent result across DCEs.
+	 */
+	usleep_range(1000, 1000 + 10);
+
+	if (micbiasconn)
+		snd_soc_update_bits(mbhc->codec, WCD9XXX_A_MAD_ANA_CTRL,
+				    1 << 4, 1 << 4);
+	snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.ctl_reg, 0x01, 0x00);
+	usleep_range(us, us + WCD9XXX_USLEEP_RANGE_MARGIN_US);
+
+	return 0;
+}
+
 static enum wcd9xxx_mbhc_plug_type
 wcd9xxx_codec_get_plug_type(struct wcd9xxx_mbhc *mbhc, bool highhph)
 {
@@ -1275,6 +1371,12 @@
 	plug_type_ptr =
 	    WCD9XXX_MBHC_CAL_PLUG_TYPE_PTR(mbhc->mbhc_cfg->calibration);
 
+	/*
+	 * cfilter in fast mode requires 1ms to charge up and down micbias
+	 * fully.
+	 */
+	(void) wcd9xxx_pull_down_micbias(mbhc,
+					 WCD9XXX_MICBIAS_PULLDOWN_SETTLE_US);
 	rt[0].hphl_status = wcd9xxx_hphl_status(mbhc);
 	rt[0].dce = wcd9xxx_mbhc_setup_hs_polling(mbhc);
 	rt[0].swap_gnd = false;
@@ -1283,7 +1385,7 @@
 	for (i = 1; i < NUM_DCE_PLUG_INS_DETECT; i++) {
 		rt[i].swap_gnd = (i == NUM_DCE_PLUG_INS_DETECT - 2);
 		if (detect_use_vddio_switch)
-			rt[i].vddio = (i == NUM_DCE_PLUG_INS_DETECT - 1);
+			rt[i].vddio = (i == 1);
 		else
 			rt[i].vddio = false;
 		rt[i].hphl_status = wcd9xxx_hphl_status(mbhc);
@@ -1292,6 +1394,15 @@
 			wcd9xxx_codec_hphr_gnd_switch(codec, true);
 		if (rt[i].vddio)
 			wcd9xxx_onoff_vddio_switch(mbhc, true);
+		/*
+		 * Pull down micbias to detect headset with mic which has
+		 * threshold and to have more consistent voltage measurements.
+		 *
+		 * cfilter in fast mode requires 1ms to charge up and down
+		 * micbias fully.
+		 */
+		(void) wcd9xxx_pull_down_micbias(mbhc,
+					    WCD9XXX_MICBIAS_PULLDOWN_SETTLE_US);
 		rt[i].dce = __wcd9xxx_codec_sta_dce(mbhc, 1, true, true);
 		if (rt[i].vddio)
 			wcd9xxx_onoff_vddio_switch(mbhc, false);
@@ -1490,6 +1601,11 @@
 		 */
 		wcd9xxx_report_plug(mbhc, 1, SND_JACK_HEADSET);
 		msleep(100);
+
+		/* 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);
 		wcd9xxx_start_hs_polling(mbhc);
 	} else if (plug_type == PLUG_TYPE_HIGH_HPH) {
 		if (mbhc->mbhc_cfg->detect_extn_cable) {
@@ -1551,6 +1667,9 @@
 		wcd9xxx_report_plug(mbhc, 1, SND_JACK_HEADPHONE);
 		wcd9xxx_schedule_hs_detect_plug(mbhc,
 						&mbhc->correct_plug_swch);
+	} else if (plug_type == PLUG_TYPE_HIGH_HPH) {
+		wcd9xxx_schedule_hs_detect_plug(mbhc,
+						&mbhc->correct_plug_swch);
 	} else {
 		pr_debug("%s: Valid plug found, determine plug type %d\n",
 			 __func__, plug_type);
@@ -1809,7 +1928,6 @@
 
 static irqreturn_t wcd9xxx_hs_remove_irq(int irq, void *data)
 {
-	bool vddio;
 	struct wcd9xxx_mbhc *mbhc = data;
 
 	pr_debug("%s: enter, removal interrupt\n", __func__);
@@ -1828,25 +1946,12 @@
 						WCD9XXX_COND_HPH, false);
 	}
 
-	vddio = (mbhc->mbhc_data.micb_mv != VDDIO_MICBIAS_MV &&
-		 mbhc->mbhc_micbias_switched);
-	if (vddio)
-		__wcd9xxx_switch_micbias(mbhc, 0, false, true);
-
 	if (mbhc->mbhc_cfg->detect_extn_cable &&
 	    !wcd9xxx_swch_level_remove(mbhc))
 		wcd9xxx_hs_remove_irq_noswch(mbhc);
 	else
 		wcd9xxx_hs_remove_irq_swch(mbhc);
 
-	/*
-	 * if driver turned off vddio switch and headset is not removed,
-	 * turn on the vddio switch back, if headset is removed then vddio
-	 * switch is off by time now and shouldn't be turn on again from here
-	 */
-	if (vddio && (mbhc->current_plug == PLUG_TYPE_HEADSET))
-		__wcd9xxx_switch_micbias(mbhc, 1, true, true);
-
 	if (mbhc->current_plug == PLUG_TYPE_HEADSET) {
 		wcd9xxx_resmgr_cond_update_cond(mbhc->resmgr,
 						WCD9XXX_COND_HPH, true);
@@ -2151,6 +2256,9 @@
 				wcd9xxx_report_plug(mbhc, 1,
 						    SND_JACK_HEADPHONE);
 			}
+		} else if (plug_type == PLUG_TYPE_HIGH_HPH) {
+			pr_debug("%s: High HPH detected, continue polling\n",
+				  __func__);
 		} else {
 			if (plug_type == PLUG_TYPE_GND_MIC_SWAP) {
 				pt_gnd_mic_swap_cnt++;
@@ -2189,6 +2297,11 @@
 		}
 	}
 
+	if (plug_type == PLUG_TYPE_HIGH_HPH) {
+		pr_debug("%s: polling is done, still HPH, so enabling MIC trigger\n",
+			 __func__);
+		wcd9xxx_find_plug_and_report(mbhc, plug_type);
+	}
 	/* Turn off override */
 	if (!correction)
 		wcd9xxx_turn_onoff_override(codec, false);
@@ -2446,18 +2559,45 @@
 	return mask;
 }
 
+void wcd9xxx_get_z(struct wcd9xxx_mbhc *mbhc, s16 *dce_z, s16 *sta_z)
+{
+	s16 reg0, reg1;
+	struct snd_soc_codec *codec = mbhc->codec;
+
+	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);
+
+	/* Disconnect override from micbias */
+	snd_soc_update_bits(codec, WCD9XXX_A_MAD_ANA_CTRL, 1 << 4, 1 << 0);
+	usleep_range(1000, 1000 + 1000);
+	*sta_z = wcd9xxx_codec_sta_dce(mbhc, 0, false);
+	*dce_z = wcd9xxx_codec_sta_dce(mbhc, 1, false);
+
+	/* Connect override from micbias */
+	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);
+}
+
 irqreturn_t wcd9xxx_dce_handler(int irq, void *data)
 {
 	int i, mask;
-	short dce, sta;
-	s32 mv, mv_s, stamv_s;
 	bool vddio;
 	u8 mbhc_status;
+	s16 dce_z, sta_z;
 	int btn = -1, meas = 0;
 	struct wcd9xxx_mbhc *mbhc = data;
 	const struct wcd9xxx_mbhc_btn_detect_cfg *d =
 	    WCD9XXX_MBHC_CAL_BTN_DET_PTR(mbhc->mbhc_cfg->calibration);
 	short btnmeas[d->n_btn_meas + 1];
+	short dce[d->n_btn_meas + 1], sta;
+	s32 mv[d->n_btn_meas + 1], mv_s[d->n_btn_meas + 1];
+	s32 stamv, stamv_s;
 	struct snd_soc_codec *codec = mbhc->codec;
 	struct wcd9xxx *core = mbhc->resmgr->core;
 	int n_btn_meas = d->n_btn_meas;
@@ -2481,9 +2621,6 @@
 		goto done;
 	}
 
-	dce = wcd9xxx_read_dce_result(codec);
-	mv = wcd9xxx_codec_sta_dce_v(mbhc, 1, dce);
-
 	/* If switch nterrupt already kicked in, ignore button press */
 	if (mbhc->in_swch_irq_handler) {
 		pr_debug("%s: Swtich level changed, ignore button press\n",
@@ -2495,13 +2632,10 @@
 	/* Measure scaled HW DCE */
 	vddio = (mbhc->mbhc_data.micb_mv != VDDIO_MICBIAS_MV &&
 		 mbhc->mbhc_micbias_switched);
-	mv_s = vddio ? scale_v_micb_vddio(mbhc, mv, false) : mv;
 
 	/* Measure scaled HW STA */
+	dce[0] = wcd9xxx_read_dce_result(codec);
 	sta = wcd9xxx_read_sta_result(codec);
-	stamv_s = wcd9xxx_codec_sta_dce_v(mbhc, 0, sta);
-	if (vddio)
-		stamv_s = scale_v_micb_vddio(mbhc, stamv_s, false);
 	if (mbhc_status != STATUS_REL_DETECTION) {
 		if (mbhc->mbhc_last_resume &&
 		    !time_after(jiffies, mbhc->mbhc_last_resume + HZ)) {
@@ -2511,30 +2645,55 @@
 		} else {
 			pr_debug("%s: Button is released without resume",
 				 __func__);
-			btn = wcd9xxx_determine_button(mbhc, mv_s);
+			wcd9xxx_get_z(mbhc, &dce_z, &sta_z);
+			stamv = __wcd9xxx_codec_sta_dce_v(mbhc, 0, sta, sta_z);
+			if (vddio)
+				stamv_s = scale_v_micb_vddio(mbhc, stamv,
+							     false);
+			else
+				stamv_s = stamv;
+			mv[0] = __wcd9xxx_codec_sta_dce_v(mbhc, 1, dce[0],
+							  dce_z);
+			mv_s[0] = vddio ? scale_v_micb_vddio(mbhc, mv[0],
+							     false) : mv[0];
+			btn = wcd9xxx_determine_button(mbhc, mv_s[0]);
 			if (btn != wcd9xxx_determine_button(mbhc, stamv_s))
 				btn = -1;
 			goto done;
 		}
 	}
 
+	for (meas = 1; ((d->n_btn_meas) && (meas < (d->n_btn_meas + 1)));
+	     meas++)
+		dce[meas] = wcd9xxx_codec_sta_dce(mbhc, 1, false);
+
+	wcd9xxx_get_z(mbhc, &dce_z, &sta_z);
+
+	stamv = __wcd9xxx_codec_sta_dce_v(mbhc, 0, sta, sta_z);
+	if (vddio)
+		stamv_s = scale_v_micb_vddio(mbhc, stamv, false);
+	else
+		stamv_s = stamv;
 	pr_debug("%s: Meas HW - STA 0x%x,%d,%d\n", __func__,
-		 sta & 0xFFFF, wcd9xxx_codec_sta_dce_v(mbhc, 0, sta), stamv_s);
+		 sta & 0xFFFF, stamv, stamv_s);
 
 	/* determine pressed button */
-	btnmeas[meas++] = wcd9xxx_determine_button(mbhc, mv_s);
+	mv[0] = __wcd9xxx_codec_sta_dce_v(mbhc, 1, dce[0], dce_z);
+	mv_s[0] = vddio ? scale_v_micb_vddio(mbhc, mv[0], false) : mv[0];
+	btnmeas[0] = wcd9xxx_determine_button(mbhc, mv_s[0]);
 	pr_debug("%s: Meas HW - DCE 0x%x,%d,%d button %d\n", __func__,
-		 dce & 0xFFFF, mv, mv_s, btnmeas[meas - 1]);
+		 dce[0] & 0xFFFF, mv[0], mv_s[0], btnmeas[0]);
 	if (n_btn_meas == 0)
 		btn = btnmeas[0];
-	for (; ((d->n_btn_meas) && (meas < (d->n_btn_meas + 1))); meas++) {
-		dce = wcd9xxx_codec_sta_dce(mbhc, 1, false);
-		mv = wcd9xxx_codec_sta_dce_v(mbhc, 1, dce);
-		mv_s = vddio ? scale_v_micb_vddio(mbhc, mv, false) : mv;
-
-		btnmeas[meas] = wcd9xxx_determine_button(mbhc, mv_s);
+	for (meas = 1; (n_btn_meas && d->n_btn_meas &&
+			(meas < (d->n_btn_meas + 1))); meas++) {
+		mv[meas] = __wcd9xxx_codec_sta_dce_v(mbhc, 1, dce[meas], dce_z);
+		mv_s[meas] = vddio ? scale_v_micb_vddio(mbhc, mv[meas], false) :
+				     mv[meas];
+		btnmeas[meas] = wcd9xxx_determine_button(mbhc, mv_s[meas]);
 		pr_debug("%s: Meas %d - DCE 0x%x,%d,%d button %d\n",
-			 __func__, meas, dce & 0xFFFF, mv, mv_s, btnmeas[meas]);
+			 __func__, meas, dce[meas] & 0xFFFF, mv[meas],
+			 mv_s[meas], btnmeas[meas]);
 		/*
 		 * if large enough measurements are collected,
 		 * start to check if last all n_btn_con measurements were
@@ -2808,9 +2967,11 @@
 	ret = wcd9xxx_enable_mux_bias_block(codec, mbhc);
 	if (ret)
 		goto gen_err;
-	usleep_range(WCD9XXX_MUX_SWITCH_READY_WAIT_US,
-		     WCD9XXX_MUX_SWITCH_READY_WAIT_US +
-		     WCD9XXX_USLEEP_RANGE_MARGIN_US);
+	/*
+	 * Hardware that has external cap can delay mic bias ramping down up
+	 * to 50ms.
+	 */
+	msleep(WCD9XXX_MUX_SWITCH_READY_WAIT_MS);
 	/* DCE measurement for 0 voltage */
 	snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x0A);
 	snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x02);
@@ -2830,7 +2991,11 @@
 	ret = wcd9xxx_enable_mux_bias_block(codec, mbhc);
 	if (ret)
 		goto gen_err;
-	usleep_range(100, 100);
+	/*
+	 * Hardware that has external cap can delay mic bias ramping down up
+	 * to 50ms.
+	 */
+	msleep(WCD9XXX_MUX_SWITCH_READY_WAIT_MS);
 	snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_EN_CTL, 0x04);
 	usleep_range(mbhc->mbhc_data.t_dce, mbhc->mbhc_data.t_dce);
 	mbhc->mbhc_data.dce_mb = wcd9xxx_read_dce_result(codec);
@@ -2843,7 +3008,11 @@
 	ret = wcd9xxx_enable_mux_bias_block(codec, mbhc);
 	if (ret)
 		goto gen_err;
-	usleep_range(100, 100);
+	/*
+	 * Hardware that has external cap can delay mic bias ramping down up
+	 * to 50ms.
+	 */
+	msleep(WCD9XXX_MUX_SWITCH_READY_WAIT_MS);
 	snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_EN_CTL, 0x02);
 	usleep_range(mbhc->mbhc_data.t_sta, mbhc->mbhc_data.t_sta);
 	mbhc->mbhc_data.sta_mb = wcd9xxx_read_sta_result(codec);
@@ -3081,8 +3250,8 @@
 	const s16 v_br_h =
 	    wcd9xxx_get_current_v(mbhc, WCD9XXX_CURRENT_V_BR_H);
 
-	n = scnprintf(buffer, size - n, "dce_z = %x(%dmv)\n",  p->dce_z,
-		      wcd9xxx_codec_sta_dce_v(mbhc, 1, p->dce_z));
+	n = scnprintf(buffer, size - n, "dce_z = %x(%dmv)\n",
+		      p->dce_z, wcd9xxx_codec_sta_dce_v(mbhc, 1, p->dce_z));
 	n += scnprintf(buffer + n, size - n, "dce_mb = %x(%dmv)\n",
 		       p->dce_mb, wcd9xxx_codec_sta_dce_v(mbhc, 1, p->dce_mb));
 	n += scnprintf(buffer + n, size - n, "sta_z = %x(%dmv)\n",
@@ -3229,18 +3398,31 @@
 	enum wcd9xxx_micbias_num ret;
 	switch (event) {
 	case WCD9XXX_EVENT_PRE_MICBIAS_1_ON:
+	case WCD9XXX_EVENT_PRE_MICBIAS_1_OFF:
+	case WCD9XXX_EVENT_POST_MICBIAS_1_ON:
+	case WCD9XXX_EVENT_POST_MICBIAS_1_OFF:
 		ret = MBHC_MICBIAS1;
 		break;
 	case WCD9XXX_EVENT_PRE_MICBIAS_2_ON:
+	case WCD9XXX_EVENT_PRE_MICBIAS_2_OFF:
+	case WCD9XXX_EVENT_POST_MICBIAS_2_ON:
+	case WCD9XXX_EVENT_POST_MICBIAS_2_OFF:
 		ret = MBHC_MICBIAS2;
 		break;
 	case WCD9XXX_EVENT_PRE_MICBIAS_3_ON:
+	case WCD9XXX_EVENT_PRE_MICBIAS_3_OFF:
+	case WCD9XXX_EVENT_POST_MICBIAS_3_ON:
+	case WCD9XXX_EVENT_POST_MICBIAS_3_OFF:
 		ret = MBHC_MICBIAS3;
 		break;
 	case WCD9XXX_EVENT_PRE_MICBIAS_4_ON:
+	case WCD9XXX_EVENT_PRE_MICBIAS_4_OFF:
+	case WCD9XXX_EVENT_POST_MICBIAS_4_ON:
+	case WCD9XXX_EVENT_POST_MICBIAS_4_OFF:
 		ret = MBHC_MICBIAS4;
 		break;
 	default:
+		WARN_ONCE(1, "Cannot convert event %d to micbias\n", event);
 		ret = MBHC_MICBIAS_INVALID;
 		break;
 	}
@@ -3338,33 +3520,41 @@
 	case WCD9XXX_EVENT_POST_MICBIAS_4_OFF:
 		if (mbhc->mbhc_cfg->micbias ==
 		    wcd9xxx_event_to_micbias(event) &&
-		    wcd9xxx_is_hph_pa_on(codec))
+		    (mbhc->event_state &
+		     (1 << MBHC_EVENT_PA_HPHL | 1 << MBHC_EVENT_PA_HPHR)))
 			wcd9xxx_switch_micbias(mbhc, 1);
 		break;
 	/* PA usage change */
 	case WCD9XXX_EVENT_PRE_HPHL_PA_ON:
+		set_bit(MBHC_EVENT_PA_HPHL, &mbhc->event_state);
 		if (!(snd_soc_read(codec, mbhc->mbhc_bias_regs.ctl_reg) & 0x80))
-			/* if micbias is enabled, switch to vddio */
+			/* if micbias is not enabled, switch to vddio */
 			wcd9xxx_switch_micbias(mbhc, 1);
 		break;
 	case WCD9XXX_EVENT_PRE_HPHR_PA_ON:
-		/* Not used now */
+		set_bit(MBHC_EVENT_PA_HPHR, &mbhc->event_state);
 		break;
 	case WCD9XXX_EVENT_POST_HPHL_PA_OFF:
+		clear_bit(MBHC_EVENT_PA_HPHL, &mbhc->event_state);
 		/* if HPH PAs are off, report OCP and switch back to CFILT */
 		clear_bit(WCD9XXX_HPHL_PA_OFF_ACK, &mbhc->hph_pa_dac_state);
 		clear_bit(WCD9XXX_HPHL_DAC_OFF_ACK, &mbhc->hph_pa_dac_state);
 		if (mbhc->hph_status & SND_JACK_OC_HPHL)
 			hphlocp_off_report(mbhc, SND_JACK_OC_HPHL);
-		wcd9xxx_switch_micbias(mbhc, 0);
+		if (!(mbhc->event_state &
+		      (1 << MBHC_EVENT_PA_HPHL | 1 << MBHC_EVENT_PA_HPHR)))
+			wcd9xxx_switch_micbias(mbhc, 0);
 		break;
 	case WCD9XXX_EVENT_POST_HPHR_PA_OFF:
+		clear_bit(MBHC_EVENT_PA_HPHR, &mbhc->event_state);
 		/* if HPH PAs are off, report OCP and switch back to CFILT */
 		clear_bit(WCD9XXX_HPHR_PA_OFF_ACK, &mbhc->hph_pa_dac_state);
 		clear_bit(WCD9XXX_HPHR_DAC_OFF_ACK, &mbhc->hph_pa_dac_state);
 		if (mbhc->hph_status & SND_JACK_OC_HPHR)
 			hphrocp_off_report(mbhc, SND_JACK_OC_HPHL);
-		wcd9xxx_switch_micbias(mbhc, 0);
+		if (!(mbhc->event_state &
+		      (1 << MBHC_EVENT_PA_HPHL | 1 << MBHC_EVENT_PA_HPHR)))
+			wcd9xxx_switch_micbias(mbhc, 0);
 		break;
 	/* Clock usage change */
 	case WCD9XXX_EVENT_PRE_MCLK_ON:
@@ -3395,7 +3585,7 @@
 		snd_soc_update_bits(codec, WCD9XXX_A_TX_COM_BIAS, 1 << 4,
 				    0 << 4);
 		/* Re-calibrate clock rate dependent values */
-		wcd9xxx_update_mbhc_clk_rate(mbhc, WCD9XXX_RCO_CLK_RATE);
+		wcd9xxx_update_mbhc_clk_rate(mbhc, mbhc->rco_clk_rate);
 		/* If clock source changes, stop and restart polling */
 		if (wcd9xxx_mbhc_polling(mbhc)) {
 			wcd9xxx_calibrate_hs_polling(mbhc);
@@ -3461,7 +3651,10 @@
  * NOTE: mbhc->mbhc_cfg is not YET configure so shouldn't be used
  */
 int wcd9xxx_mbhc_init(struct wcd9xxx_mbhc *mbhc, struct wcd9xxx_resmgr *resmgr,
-		      struct snd_soc_codec *codec, int version)
+		      struct snd_soc_codec *codec,
+		      int (*micbias_enable_cb) (struct snd_soc_codec*,  bool),
+		      int version,
+		      int rco_clk_rate)
 {
 	int ret;
 	void *core;
@@ -3484,7 +3677,9 @@
 	mbhc->codec = codec;
 	mbhc->resmgr = resmgr;
 	mbhc->resmgr->mbhc = mbhc;
+	mbhc->micbias_enable_cb = micbias_enable_cb;
 	mbhc->mbhc_version = version;
+	mbhc->rco_clk_rate = rco_clk_rate;
 
 	if (mbhc->headset_jack.jack == NULL) {
 		ret = snd_soc_jack_new(codec, "Headset Jack", WCD9XXX_JACK_MASK,
diff --git a/sound/soc/codecs/wcd9xxx-mbhc.h b/sound/soc/codecs/wcd9xxx-mbhc.h
index 4f8f3cf..71a62b2 100644
--- a/sound/soc/codecs/wcd9xxx-mbhc.h
+++ b/sound/soc/codecs/wcd9xxx-mbhc.h
@@ -34,6 +34,12 @@
 	MBHC_V_IDX_NUM,
 };
 
+enum mbhc_cal_type {
+	MBHC_CAL_MCLK,
+	MBHC_CAL_RCO,
+	MBHC_CAL_NUM,
+};
+
 /* Data used by MBHC */
 struct mbhc_internal_cal_data {
 	u16 dce_z;
@@ -78,6 +84,11 @@
 	MBHC_MICBIAS4,
 };
 
+enum wcd9xx_mbhc_micbias_enable_bits {
+	MBHC_MICBIAS_ENABLE_THRESHOLD_HEADSET,
+	MBHC_MICBIAS_ENABLE_REGULAR_HEADSET,
+};
+
 enum wcd9xxx_mbhc_state {
 	MBHC_STATE_NONE = -1,
 	MBHC_STATE_POTENTIAL,
@@ -99,6 +110,11 @@
 	TAIKO_NUM_CLK_FREQS,
 };
 
+enum wcd9xxx_mbhc_event_state {
+	MBHC_EVENT_PA_HPHL,
+	MBHC_EVENT_PA_HPHR,
+};
+
 struct wcd9xxx_mbhc_general_cfg {
 	u8 t_ldoh;
 	u8 t_bg_fast_settle;
@@ -196,6 +212,8 @@
 	int gpio_level_insert;
 	bool insert_detect; /* codec has own MBHC_INSERT_DETECT */
 	bool detect_extn_cable;
+	/* bit mask of enum wcd9xx_mbhc_micbias_enable_bits */
+	unsigned long micbias_enable_flags;
 	/* swap_gnd_mic returns true if extern GND/MIC swap switch toggled */
 	bool (*swap_gnd_mic) (struct snd_soc_codec *);
 };
@@ -241,8 +259,13 @@
 
 	bool no_mic_headset_override;
 
-	/* track PA/DAC state */
+	/* track PA/DAC state to sync with userspace */
 	unsigned long hph_pa_dac_state;
+	/*
+	 * save codec's state with resmgr event notification
+	 * bit flags of enum wcd9xxx_mbhc_event_state
+	 */
+	unsigned long event_state;
 
 	unsigned long mbhc_last_resume; /* in jiffies */
 
@@ -253,8 +276,13 @@
 
 	struct notifier_block nblock;
 
+	bool micbias_enable;
+	int (*micbias_enable_cb) (struct snd_soc_codec*,  bool);
+
 	enum wcd9xxx_mbhc_version mbhc_version;
 
+	u32 rco_clk_rate;
+
 #ifdef CONFIG_DEBUG_FS
 	struct dentry *debugfs_poke;
 	struct dentry *debugfs_mbhc;
@@ -319,7 +347,10 @@
 int wcd9xxx_mbhc_start(struct wcd9xxx_mbhc *mbhc,
 		       struct wcd9xxx_mbhc_config *mbhc_cfg);
 int wcd9xxx_mbhc_init(struct wcd9xxx_mbhc *mbhc, struct wcd9xxx_resmgr *resmgr,
-		      struct snd_soc_codec *codec, int version);
+		      struct snd_soc_codec *codec,
+		      int (*micbias_enable_cb) (struct snd_soc_codec*,  bool),
+		      int version,
+		      int rco_clk_rate);
 void wcd9xxx_mbhc_deinit(struct wcd9xxx_mbhc *mbhc);
 void *wcd9xxx_mbhc_cal_btn_det_mp(
 			    const struct wcd9xxx_mbhc_btn_detect_cfg *btn_det,
diff --git a/sound/soc/codecs/wcd9xxx-resmgr.c b/sound/soc/codecs/wcd9xxx-resmgr.c
index 60a76a2..77dbd36 100644
--- a/sound/soc/codecs/wcd9xxx-resmgr.c
+++ b/sound/soc/codecs/wcd9xxx-resmgr.c
@@ -659,7 +659,6 @@
 	bool set;
 
 	pr_debug("%s: enter\n", __func__);
-	WCD9XXX_BCL_ASSERT_LOCKED(resmgr);
 	set = !!test_bit(cond, &resmgr->cond_flags);
 	list_for_each(l, &resmgr->update_bit_cond_h) {
 		e = list_entry(l, struct wcd9xxx_resmgr_cond_entry, list);
@@ -675,13 +674,14 @@
 void wcd9xxx_resmgr_cond_update_cond(struct wcd9xxx_resmgr *resmgr,
 				     enum wcd9xxx_resmgr_cond cond, bool set)
 {
-	WCD9XXX_BCL_ASSERT_LOCKED(resmgr);
+	mutex_lock(&resmgr->update_bit_cond_lock);
 	if ((set && !test_and_set_bit(cond, &resmgr->cond_flags)) ||
 	    (!set && test_and_clear_bit(cond, &resmgr->cond_flags))) {
 		pr_debug("%s: Resource %d condition changed to %s\n", __func__,
 			 cond, set ? "set" : "clear");
 		wcd9xxx_resmgr_cond_trigger_cond(resmgr, cond);
 	}
+	mutex_unlock(&resmgr->update_bit_cond_lock);
 }
 
 int wcd9xxx_resmgr_add_cond_update_bits(struct wcd9xxx_resmgr *resmgr,
@@ -700,11 +700,11 @@
 	entry->shift = shift;
 	entry->invert = invert;
 
-	WCD9XXX_BCL_LOCK(resmgr);
+	mutex_lock(&resmgr->update_bit_cond_lock);
 	list_add_tail(&entry->list, &resmgr->update_bit_cond_h);
 
 	wcd9xxx_resmgr_cond_trigger_cond(resmgr, cond);
-	WCD9XXX_BCL_UNLOCK(resmgr);
+	mutex_unlock(&resmgr->update_bit_cond_lock);
 
 	return 0;
 }
@@ -722,7 +722,7 @@
 	struct wcd9xxx_resmgr_cond_entry *e = NULL;
 
 	pr_debug("%s: enter\n", __func__);
-	WCD9XXX_BCL_LOCK(resmgr);
+	mutex_lock(&resmgr->update_bit_cond_lock);
 	list_for_each_safe(l, next, &resmgr->update_bit_cond_h) {
 		e = list_entry(l, struct wcd9xxx_resmgr_cond_entry, list);
 		if (e->reg == reg && e->shift == shift && e->invert == invert) {
@@ -730,12 +730,12 @@
 					    1 << e->shift,
 					    e->invert << e->shift);
 			list_del(&e->list);
-			WCD9XXX_BCL_UNLOCK(resmgr);
+			mutex_unlock(&resmgr->update_bit_cond_lock);
 			kfree(e);
 			return 0;
 		}
 	}
-	WCD9XXX_BCL_UNLOCK(resmgr);
+	mutex_unlock(&resmgr->update_bit_cond_lock);
 	pr_err("%s: Cannot find update bit entry reg 0x%x, shift %d\n",
 	       __func__, e ? e->reg : 0, e ? e->shift : 0);
 
@@ -776,12 +776,14 @@
 	BLOCKING_INIT_NOTIFIER_HEAD(&resmgr->notifier);
 
 	mutex_init(&resmgr->codec_resource_lock);
+	mutex_init(&resmgr->update_bit_cond_lock);
 
 	return 0;
 }
 
 void wcd9xxx_resmgr_deinit(struct wcd9xxx_resmgr *resmgr)
 {
+	mutex_destroy(&resmgr->update_bit_cond_lock);
 	mutex_destroy(&resmgr->codec_resource_lock);
 }
 
diff --git a/sound/soc/codecs/wcd9xxx-resmgr.h b/sound/soc/codecs/wcd9xxx-resmgr.h
index 8acc816..b5f950c 100644
--- a/sound/soc/codecs/wcd9xxx-resmgr.h
+++ b/sound/soc/codecs/wcd9xxx-resmgr.h
@@ -127,6 +127,7 @@
 
 	unsigned long cond_flags;
 	struct list_head update_bit_cond_h;
+	struct mutex update_bit_cond_lock;
 
 	/*
 	 * Currently, only used for mbhc purpose, to protect
diff --git a/sound/soc/msm/Kconfig b/sound/soc/msm/Kconfig
index 66c475f..40661ff 100644
--- a/sound/soc/msm/Kconfig
+++ b/sound/soc/msm/Kconfig
@@ -180,7 +180,6 @@
 	select SND_SOC_MSM_STUB
 	select SND_SOC_MSM_HOSTLESS_PCM
 	select SND_SOC_WCD9320
-	select SND_SOC_MSM_HDMI_CODEC_RX
 	select SND_DYNAMIC_MINORS
 	select AUDIO_OCMEM
 	select DOLBY_DAP
@@ -191,6 +190,23 @@
 	 the machine drivers and the corresponding
 	 DAI-links.
 
+config SND_SOC_APQ8074
+	tristate "SoC Machine driver for APQ8O74 boards"
+	depends on ARCH_MSM8974
+	select SND_SOC_QDSP6V2
+	select SND_SOC_MSM_STUB
+	select SND_SOC_MSM_HOSTLESS_PCM
+	select SND_SOC_WCD9320
+	select SND_SOC_MSM_HDMI_CODEC_RX
+	select SND_DYNAMIC_MINORS
+	select AUDIO_OCMEM
+	help
+	 To add support for SoC audio on APQ8074.
+	 This will enable sound soc drivers which
+	 interfaces with DSP, also it will enable
+	 the machine drivers and the corresponding
+	 DAI-links.
+
 config SND_SOC_MSM8226
 	tristate "SoC Machine driver for MSM8226 boards"
 	depends on ARCH_MSM8226
diff --git a/sound/soc/msm/Makefile b/sound/soc/msm/Makefile
index 7ab4811..e206812 100644
--- a/sound/soc/msm/Makefile
+++ b/sound/soc/msm/Makefile
@@ -84,6 +84,10 @@
 snd-soc-qdsp6v2-objs := msm-dai-fe.o
 obj-$(CONFIG_SND_SOC_QDSP6V2) += snd-soc-qdsp6v2.o
 
+# for APQ 8074 sound card driver
+snd-soc-apq8074-objs := apq8074.o
+obj-$(CONFIG_SND_SOC_APQ8074) += snd-soc-apq8074.o
+
 #for MDM9625 sound card driver
 snd-soc-mdm9625-objs := mdm9625.o
 obj-$(CONFIG_SND_SOC_MDM9625) += snd-soc-mdm9625.o
diff --git a/sound/soc/msm/apq8074.c b/sound/soc/msm/apq8074.c
new file mode 100644
index 0000000..9a2f83b
--- /dev/null
+++ b/sound/soc/msm/apq8074.c
@@ -0,0 +1,2486 @@
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/mfd/pm8xxx/pm8921.h>
+#include <linux/qpnp/clkdiv.h>
+#include <linux/regulator/consumer.h>
+#include <sound/core.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/pcm.h>
+#include <sound/jack.h>
+#include <sound/q6afe-v2.h>
+#include <asm/mach-types.h>
+#include <mach/socinfo.h>
+#include <sound/pcm_params.h>
+#include "qdsp6v2/msm-pcm-routing-v2.h"
+#include "../codecs/wcd9320.h"
+#include <linux/io.h>
+
+#define DRV_NAME "apq8074-asoc-taiko"
+
+#define APQ8074_SPK_ON 1
+#define APQ8074_SPK_OFF 0
+
+#define MSM_SLIM_0_RX_MAX_CHANNELS		2
+#define MSM_SLIM_0_TX_MAX_CHANNELS		4
+
+#define BTSCO_RATE_8KHZ 8000
+#define BTSCO_RATE_16KHZ 16000
+
+static int slim0_rx_bit_format = SNDRV_PCM_FORMAT_S16_LE;
+static int hdmi_rx_bit_format = SNDRV_PCM_FORMAT_S16_LE;
+
+#define SAMPLING_RATE_48KHZ 48000
+#define SAMPLING_RATE_96KHZ 96000
+#define SAMPLING_RATE_192KHZ 192000
+
+static int apq8074_auxpcm_rate = 8000;
+#define LO_1_SPK_AMP	0x1
+#define LO_3_SPK_AMP	0x2
+#define LO_2_SPK_AMP	0x4
+#define LO_4_SPK_AMP	0x8
+
+#define LPAIF_OFFSET 0xFE000000
+#define LPAIF_PRI_MODE_MUXSEL (LPAIF_OFFSET + 0x2B000)
+#define LPAIF_SEC_MODE_MUXSEL (LPAIF_OFFSET + 0x2C000)
+#define LPAIF_TER_MODE_MUXSEL (LPAIF_OFFSET + 0x2D000)
+#define LPAIF_QUAD_MODE_MUXSEL (LPAIF_OFFSET + 0x2E000)
+
+#define I2S_PCM_SEL 1
+#define I2S_PCM_SEL_OFFSET 1
+
+
+#define WCD9XXX_MBHC_DEF_BUTTONS 8
+#define WCD9XXX_MBHC_DEF_RLOADS 5
+#define TAIKO_EXT_CLK_RATE 9600000
+
+/* It takes about 13ms for Class-D PAs to ramp-up */
+#define EXT_CLASS_D_EN_DELAY 13000
+#define EXT_CLASS_D_DIS_DELAY 3000
+#define EXT_CLASS_D_DELAY_DELTA 2000
+
+/* It takes about 13ms for Class-AB PAs to ramp-up */
+#define EXT_CLASS_AB_EN_DELAY 10000
+#define EXT_CLASS_AB_DIS_DELAY 1000
+#define EXT_CLASS_AB_DELAY_DELTA 1000
+
+#define NUM_OF_AUXPCM_GPIOS 4
+
+static inline int param_is_mask(int p)
+{
+	return ((p >= SNDRV_PCM_HW_PARAM_FIRST_MASK) &&
+			(p <= SNDRV_PCM_HW_PARAM_LAST_MASK));
+}
+
+static inline struct snd_mask *param_to_mask(struct snd_pcm_hw_params *p, int n)
+{
+	return &(p->masks[n - SNDRV_PCM_HW_PARAM_FIRST_MASK]);
+}
+
+static void param_set_mask(struct snd_pcm_hw_params *p, int n, unsigned bit)
+{
+	if (bit >= SNDRV_MASK_MAX)
+		return;
+	if (param_is_mask(n)) {
+		struct snd_mask *m = param_to_mask(p, n);
+		m->bits[0] = 0;
+		m->bits[1] = 0;
+		m->bits[bit >> 5] |= (1 << (bit & 31));
+	}
+}
+
+static const char *const auxpcm_rate_text[] = {"rate_8000", "rate_16000"};
+static const struct soc_enum apq8074_auxpcm_enum[] = {
+		SOC_ENUM_SINGLE_EXT(2, auxpcm_rate_text),
+};
+
+static void *def_taiko_mbhc_cal(void);
+static int msm_snd_enable_codec_ext_clk(struct snd_soc_codec *codec, int enable,
+					bool dapm);
+
+static struct wcd9xxx_mbhc_config mbhc_cfg = {
+	.read_fw_bin = false,
+	.calibration = NULL,
+	.micbias = MBHC_MICBIAS2,
+	.mclk_cb_fn = msm_snd_enable_codec_ext_clk,
+	.mclk_rate = TAIKO_EXT_CLK_RATE,
+	.gpio = 0,
+	.gpio_irq = 0,
+	.gpio_level_insert = 1,
+	.detect_extn_cable = true,
+	.insert_detect = true,
+	.swap_gnd_mic = NULL,
+};
+
+struct msm_auxpcm_gpio {
+	unsigned gpio_no;
+	const char *gpio_name;
+};
+
+struct msm_auxpcm_ctrl {
+	struct msm_auxpcm_gpio *pin_data;
+	u32 cnt;
+};
+
+struct apq8074_asoc_mach_data {
+	int mclk_gpio;
+	u32 mclk_freq;
+	int us_euro_gpio;
+	struct msm_auxpcm_ctrl *pri_auxpcm_ctrl;
+};
+
+#define GPIO_NAME_INDEX 0
+#define DT_PARSE_INDEX  1
+
+static char *msm_prim_auxpcm_gpio_name[][2] = {
+	{"PRIM_AUXPCM_CLK",       "qcom,prim-auxpcm-gpio-clk"},
+	{"PRIM_AUXPCM_SYNC",      "qcom,prim-auxpcm-gpio-sync"},
+	{"PRIM_AUXPCM_DIN",       "qcom,prim-auxpcm-gpio-din"},
+	{"PRIM_AUXPCM_DOUT",      "qcom,prim-auxpcm-gpio-dout"},
+};
+
+static void *lpaif_pri_muxsel_virt_addr;
+
+struct apq8074_liquid_dock_dev {
+	int dock_plug_gpio;
+	int dock_plug_irq;
+	struct snd_soc_dapm_context *dapm;
+	struct work_struct irq_work;
+};
+
+static struct apq8074_liquid_dock_dev *apq8074_liquid_dock_dev;
+static int dock_plug_det = -1;
+
+/* Shared channel numbers for Slimbus ports that connect APQ to MDM. */
+enum {
+	SLIM_1_RX_1 = 145, /* BT-SCO and USB TX */
+	SLIM_1_TX_1 = 146, /* BT-SCO and USB RX */
+	SLIM_2_RX_1 = 147, /* HDMI RX */
+	SLIM_3_RX_1 = 148, /* In-call recording RX */
+	SLIM_3_RX_2 = 149, /* In-call recording RX */
+	SLIM_4_TX_1 = 150, /* In-call musid delivery TX */
+};
+
+static struct platform_device *spdev;
+static struct regulator *ext_spk_amp_regulator;
+static int ext_spk_amp_gpio = -1;
+static int ext_ult_spk_amp_gpio = -1;
+static int apq8074_spk_control = 1;
+static int apq8074_ext_spk_pamp;
+static int msm_slim_0_rx_ch = 1;
+static int msm_slim_0_tx_ch = 1;
+
+static int msm_btsco_rate = BTSCO_RATE_8KHZ;
+static int msm_btsco_ch = 1;
+static int msm_hdmi_rx_ch = 2;
+static int slim0_rx_sample_rate = SAMPLING_RATE_48KHZ;
+static int msm_proxy_rx_ch = 2;
+
+static struct mutex cdc_mclk_mutex;
+static struct clk *codec_clk;
+static int clk_users;
+static atomic_t prim_auxpcm_rsc_ref;
+
+static int apq8074_liquid_ext_spk_power_amp_init(void)
+{
+	int ret = 0;
+
+	ext_spk_amp_gpio = of_get_named_gpio(spdev->dev.of_node,
+		"qcom,ext-spk-amp-gpio", 0);
+	if (ext_spk_amp_gpio >= 0) {
+		ret = gpio_request(ext_spk_amp_gpio, "ext_spk_amp_gpio");
+		if (ret) {
+			pr_err("%s: gpio_request failed for ext_spk_amp_gpio.\n",
+				__func__);
+			return -EINVAL;
+		}
+		gpio_direction_output(ext_spk_amp_gpio, 0);
+
+		if (ext_spk_amp_regulator == NULL) {
+			ext_spk_amp_regulator = regulator_get(&spdev->dev,
+									"qcom,ext-spk-amp");
+
+			if (IS_ERR(ext_spk_amp_regulator)) {
+				pr_err("%s: Cannot get regulator %s.\n",
+					__func__, "qcom,ext-spk-amp");
+
+				gpio_free(ext_spk_amp_gpio);
+				return PTR_ERR(ext_spk_amp_regulator);
+			}
+		}
+	}
+
+	ext_ult_spk_amp_gpio = of_get_named_gpio(spdev->dev.of_node,
+		"qcom,ext-ult-spk-amp-gpio", 0);
+
+	if (ext_ult_spk_amp_gpio >= 0) {
+		ret = gpio_request(ext_ult_spk_amp_gpio,
+						   "ext_ult_spk_amp_gpio");
+		if (ret) {
+			pr_err("%s: gpio_request failed for ext-ult_spk-amp-gpio.\n",
+				__func__);
+			return -EINVAL;
+		}
+		gpio_direction_output(ext_ult_spk_amp_gpio, 0);
+	}
+
+	return 0;
+}
+
+static void apq8074_liquid_ext_ult_spk_power_amp_enable(u32 on)
+{
+	if (on) {
+		regulator_enable(ext_spk_amp_regulator);
+		gpio_direction_output(ext_ult_spk_amp_gpio, 1);
+		/* time takes enable the external power class AB amplifier */
+		usleep_range(EXT_CLASS_AB_EN_DELAY,
+			     EXT_CLASS_AB_EN_DELAY + EXT_CLASS_AB_DELAY_DELTA);
+	} else {
+		gpio_direction_output(ext_ult_spk_amp_gpio, 0);
+		regulator_disable(ext_spk_amp_regulator);
+		/* time takes disable the external power class AB amplifier */
+		usleep_range(EXT_CLASS_AB_DIS_DELAY,
+			     EXT_CLASS_AB_DIS_DELAY + EXT_CLASS_AB_DELAY_DELTA);
+	}
+
+	pr_debug("%s: %s external ultrasound SPKR_DRV PAs.\n", __func__,
+			on ? "Enable" : "Disable");
+}
+
+static void apq8074_liquid_ext_spk_power_amp_enable(u32 on)
+{
+	if (on) {
+		regulator_enable(ext_spk_amp_regulator);
+		gpio_direction_output(ext_spk_amp_gpio, on);
+		/*time takes enable the external power amplifier*/
+		usleep_range(EXT_CLASS_D_EN_DELAY,
+			     EXT_CLASS_D_EN_DELAY + EXT_CLASS_D_DELAY_DELTA);
+	} else {
+		gpio_direction_output(ext_spk_amp_gpio, on);
+		regulator_disable(ext_spk_amp_regulator);
+		/*time takes disable the external power amplifier*/
+		usleep_range(EXT_CLASS_D_DIS_DELAY,
+			     EXT_CLASS_D_DIS_DELAY + EXT_CLASS_D_DELAY_DELTA);
+	}
+
+	pr_debug("%s: %s external speaker PAs.\n", __func__,
+			on ? "Enable" : "Disable");
+}
+
+static void apq8074_liquid_docking_irq_work(struct work_struct *work)
+{
+	struct apq8074_liquid_dock_dev *dock_dev =
+		container_of(work,
+					 struct apq8074_liquid_dock_dev,
+					 irq_work);
+
+	struct snd_soc_dapm_context *dapm = dock_dev->dapm;
+
+
+	mutex_lock(&dapm->codec->mutex);
+	dock_plug_det =
+		gpio_get_value(dock_dev->dock_plug_gpio);
+
+
+	if (0 == dock_plug_det) {
+		if ((apq8074_ext_spk_pamp & LO_1_SPK_AMP) &&
+			(apq8074_ext_spk_pamp & LO_3_SPK_AMP) &&
+			(apq8074_ext_spk_pamp & LO_2_SPK_AMP) &&
+			(apq8074_ext_spk_pamp & LO_4_SPK_AMP))
+			apq8074_liquid_ext_spk_power_amp_enable(1);
+	} else {
+		if ((apq8074_ext_spk_pamp & LO_1_SPK_AMP) &&
+			(apq8074_ext_spk_pamp & LO_3_SPK_AMP) &&
+			(apq8074_ext_spk_pamp & LO_2_SPK_AMP) &&
+			(apq8074_ext_spk_pamp & LO_4_SPK_AMP))
+			apq8074_liquid_ext_spk_power_amp_enable(0);
+	}
+
+	mutex_unlock(&dapm->codec->mutex);
+
+}
+
+static irqreturn_t apq8074_liquid_docking_irq_handler(int irq, void *dev)
+{
+	struct apq8074_liquid_dock_dev *dock_dev = dev;
+
+	/* switch speakers should not run in interrupt context */
+	schedule_work(&dock_dev->irq_work);
+
+	return IRQ_HANDLED;
+}
+
+static int apq8074_liquid_init_docking(struct snd_soc_dapm_context *dapm)
+{
+	int ret = 0;
+	int dock_plug_gpio = 0;
+
+	/* plug in docking speaker+plug in device OR unplug one of them */
+	u32 dock_plug_irq_flags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING;
+
+	dock_plug_det = 0;
+	dock_plug_gpio = of_get_named_gpio(spdev->dev.of_node,
+					   "qcom,dock-plug-det-irq", 0);
+
+	if (dock_plug_gpio >= 0) {
+
+		apq8074_liquid_dock_dev =
+		 kzalloc(sizeof(*apq8074_liquid_dock_dev), GFP_KERNEL);
+
+		if (!apq8074_liquid_dock_dev) {
+			pr_err("apq8074_liquid_dock_dev alloc fail.\n");
+			return -ENOMEM;
+		}
+
+		apq8074_liquid_dock_dev->dock_plug_gpio = dock_plug_gpio;
+
+		ret = gpio_request(apq8074_liquid_dock_dev->dock_plug_gpio,
+					   "dock-plug-det-irq");
+		if (ret) {
+			pr_err("%s:failed request apq8074_liquid_dock_plug_gpio.\n",
+				__func__);
+			return -EINVAL;
+		}
+
+		dock_plug_det =
+			gpio_get_value(apq8074_liquid_dock_dev->dock_plug_gpio);
+
+		apq8074_liquid_dock_dev->dock_plug_irq =
+			gpio_to_irq(apq8074_liquid_dock_dev->dock_plug_gpio);
+
+		apq8074_liquid_dock_dev->dapm = dapm;
+
+		ret = request_irq(apq8074_liquid_dock_dev->dock_plug_irq,
+				  apq8074_liquid_docking_irq_handler,
+				  dock_plug_irq_flags,
+				  "liquid_dock_plug_irq",
+				  apq8074_liquid_dock_dev);
+
+		INIT_WORK(
+			&apq8074_liquid_dock_dev->irq_work,
+			apq8074_liquid_docking_irq_work);
+	}
+
+	return 0;
+}
+
+static int apq8074_liquid_ext_spk_power_amp_on(u32 spk)
+{
+	int rc;
+
+	if (spk & (LO_1_SPK_AMP | LO_3_SPK_AMP | LO_2_SPK_AMP | LO_4_SPK_AMP)) {
+		pr_debug("%s: External speakers are already on. spk = 0x%x\n",
+			 __func__, spk);
+
+		apq8074_ext_spk_pamp |= spk;
+		if ((apq8074_ext_spk_pamp & LO_1_SPK_AMP) &&
+		    (apq8074_ext_spk_pamp & LO_3_SPK_AMP) &&
+		    (apq8074_ext_spk_pamp & LO_2_SPK_AMP) &&
+		    (apq8074_ext_spk_pamp & LO_4_SPK_AMP))
+			if (ext_spk_amp_gpio >= 0 &&
+				dock_plug_det == 0)
+				apq8074_liquid_ext_spk_power_amp_enable(1);
+		rc = 0;
+	} else  {
+		pr_err("%s: Invalid external speaker ampl. spk = 0x%x\n",
+		       __func__, spk);
+		rc = -EINVAL;
+	}
+
+	return rc;
+}
+
+
+static void apq8074_ext_spk_power_amp_on(u32 spk)
+{
+	if (gpio_is_valid(ext_spk_amp_gpio))
+		apq8074_liquid_ext_spk_power_amp_on(spk);
+}
+
+static void apq8074_liquid_ext_spk_power_amp_off(u32 spk)
+{
+
+	if (spk & (LO_1_SPK_AMP |
+		   LO_3_SPK_AMP |
+		   LO_2_SPK_AMP |
+		   LO_4_SPK_AMP)) {
+
+		pr_debug("%s Left and right speakers case spk = 0x%08x",
+				  __func__, spk);
+
+		if (!apq8074_ext_spk_pamp) {
+			if (ext_spk_amp_gpio >= 0 &&
+				dock_plug_det == 0)
+				apq8074_liquid_ext_spk_power_amp_enable(0);
+			apq8074_ext_spk_pamp = 0;
+		}
+
+	} else  {
+
+		pr_err("%s: ERROR : Invalid Ext Spk Ampl. spk = 0x%08x\n",
+			__func__, spk);
+		return;
+	}
+}
+
+static void apq8074_ext_spk_power_amp_off(u32 spk)
+{
+	if (gpio_is_valid(ext_spk_amp_gpio))
+		apq8074_liquid_ext_spk_power_amp_off(spk);
+}
+
+static void apq8074_ext_control(struct snd_soc_codec *codec)
+{
+	struct snd_soc_dapm_context *dapm = &codec->dapm;
+
+	mutex_lock(&dapm->codec->mutex);
+
+	pr_debug("%s: apq8074_spk_control = %d", __func__, apq8074_spk_control);
+	if (apq8074_spk_control == APQ8074_SPK_ON) {
+		snd_soc_dapm_enable_pin(dapm, "Lineout_1 amp");
+		snd_soc_dapm_enable_pin(dapm, "Lineout_3 amp");
+		snd_soc_dapm_enable_pin(dapm, "Lineout_2 amp");
+		snd_soc_dapm_enable_pin(dapm, "Lineout_4 amp");
+	} else {
+		snd_soc_dapm_disable_pin(dapm, "Lineout_1 amp");
+		snd_soc_dapm_disable_pin(dapm, "Lineout_3 amp");
+		snd_soc_dapm_disable_pin(dapm, "Lineout_2 amp");
+		snd_soc_dapm_disable_pin(dapm, "Lineout_4 amp");
+	}
+
+	snd_soc_dapm_sync(dapm);
+	mutex_unlock(&dapm->codec->mutex);
+}
+
+static int apq8074_get_spk(struct snd_kcontrol *kcontrol,
+		       struct snd_ctl_elem_value *ucontrol)
+{
+	pr_debug("%s: apq8074_spk_control = %d", __func__, apq8074_spk_control);
+	ucontrol->value.integer.value[0] = apq8074_spk_control;
+	return 0;
+}
+
+static int apq8074_set_spk(struct snd_kcontrol *kcontrol,
+		       struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+
+	pr_debug("%s()\n", __func__);
+	if (apq8074_spk_control == ucontrol->value.integer.value[0])
+		return 0;
+
+	apq8074_spk_control = ucontrol->value.integer.value[0];
+	apq8074_ext_control(codec);
+	return 1;
+}
+
+
+static int msm_ext_spkramp_event(struct snd_soc_dapm_widget *w,
+			     struct snd_kcontrol *k, int event)
+{
+	pr_debug("%s()\n", __func__);
+
+	if (SND_SOC_DAPM_EVENT_ON(event)) {
+		if (!strncmp(w->name, "Lineout_1 amp", 14))
+			apq8074_ext_spk_power_amp_on(LO_1_SPK_AMP);
+		else if (!strncmp(w->name, "Lineout_3 amp", 14))
+			apq8074_ext_spk_power_amp_on(LO_3_SPK_AMP);
+		else if (!strncmp(w->name, "Lineout_2 amp", 14))
+			apq8074_ext_spk_power_amp_on(LO_2_SPK_AMP);
+		else if  (!strncmp(w->name, "Lineout_4 amp", 14))
+			apq8074_ext_spk_power_amp_on(LO_4_SPK_AMP);
+		else {
+			pr_err("%s() Invalid Speaker Widget = %s\n",
+					__func__, w->name);
+			return -EINVAL;
+		}
+	} else {
+		if (!strncmp(w->name, "Lineout_1 amp", 14))
+			apq8074_ext_spk_power_amp_off(LO_1_SPK_AMP);
+		else if (!strncmp(w->name, "Lineout_3 amp", 14))
+			apq8074_ext_spk_power_amp_off(LO_3_SPK_AMP);
+		else if (!strncmp(w->name, "Lineout_2 amp", 14))
+			apq8074_ext_spk_power_amp_off(LO_2_SPK_AMP);
+		else if  (!strncmp(w->name, "Lineout_4 amp", 14))
+			apq8074_ext_spk_power_amp_off(LO_4_SPK_AMP);
+		else {
+			pr_err("%s() Invalid Speaker Widget = %s\n",
+					__func__, w->name);
+			return -EINVAL;
+		}
+	}
+
+	return 0;
+
+}
+
+static int msm_ext_spkramp_ultrasound_event(struct snd_soc_dapm_widget *w,
+			     struct snd_kcontrol *k, int event)
+{
+
+	pr_debug("%s()\n", __func__);
+
+	if (!strncmp(w->name, "SPK_ultrasound amp", 19)) {
+		if (!gpio_is_valid(ext_ult_spk_amp_gpio)) {
+			pr_err("%s: ext_ult_spk_amp_gpio isn't configured\n",
+				__func__);
+			return -EINVAL;
+		}
+
+		if (SND_SOC_DAPM_EVENT_ON(event))
+			apq8074_liquid_ext_ult_spk_power_amp_enable(1);
+		else
+			apq8074_liquid_ext_ult_spk_power_amp_enable(0);
+
+	} else {
+			pr_err("%s() Invalid Speaker Widget = %s\n",
+					__func__, w->name);
+			return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int msm_snd_enable_codec_ext_clk(struct snd_soc_codec *codec, int enable,
+					bool dapm)
+{
+	int ret = 0;
+	pr_debug("%s: enable = %d clk_users = %d\n",
+		__func__, enable, clk_users);
+
+	mutex_lock(&cdc_mclk_mutex);
+	if (enable) {
+		if (!codec_clk) {
+			dev_err(codec->dev, "%s: did not get Taiko MCLK\n",
+				__func__);
+			ret = -EINVAL;
+			goto exit;
+		}
+
+		clk_users++;
+		if (clk_users != 1)
+			goto exit;
+
+		if (codec_clk) {
+			clk_set_rate(codec_clk, TAIKO_EXT_CLK_RATE);
+			clk_prepare_enable(codec_clk);
+			taiko_mclk_enable(codec, 1, dapm);
+		} else {
+			pr_err("%s: Error setting Taiko MCLK\n", __func__);
+			clk_users--;
+			goto exit;
+		}
+	} else {
+		if (clk_users > 0) {
+			clk_users--;
+			if (clk_users == 0) {
+				taiko_mclk_enable(codec, 0, dapm);
+				clk_disable_unprepare(codec_clk);
+			}
+		} else {
+			pr_err("%s: Error releasing Taiko MCLK\n", __func__);
+			ret = -EINVAL;
+			goto exit;
+		}
+	}
+exit:
+	mutex_unlock(&cdc_mclk_mutex);
+	return ret;
+}
+
+static int apq8074_mclk_event(struct snd_soc_dapm_widget *w,
+		struct snd_kcontrol *kcontrol, int event)
+{
+	pr_debug("%s: event = %d\n", __func__, event);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		return msm_snd_enable_codec_ext_clk(w->codec, 1, true);
+	case SND_SOC_DAPM_POST_PMD:
+		return msm_snd_enable_codec_ext_clk(w->codec, 0, true);
+	}
+
+	return 0;
+}
+
+static const struct snd_soc_dapm_widget apq8074_dapm_widgets[] = {
+
+	SND_SOC_DAPM_SUPPLY("MCLK",  SND_SOC_NOPM, 0, 0,
+	apq8074_mclk_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_SPK("Lineout_1 amp", msm_ext_spkramp_event),
+	SND_SOC_DAPM_SPK("Lineout_3 amp", msm_ext_spkramp_event),
+
+	SND_SOC_DAPM_SPK("Lineout_2 amp", msm_ext_spkramp_event),
+	SND_SOC_DAPM_SPK("Lineout_4 amp", msm_ext_spkramp_event),
+	SND_SOC_DAPM_SPK("SPK_ultrasound amp",
+					 msm_ext_spkramp_ultrasound_event),
+
+	SND_SOC_DAPM_MIC("Handset Mic", NULL),
+	SND_SOC_DAPM_MIC("Headset Mic", NULL),
+	SND_SOC_DAPM_MIC("ANCRight Headset Mic", NULL),
+	SND_SOC_DAPM_MIC("ANCLeft Headset Mic", NULL),
+	SND_SOC_DAPM_MIC("Analog Mic4", NULL),
+	SND_SOC_DAPM_MIC("Analog Mic6", NULL),
+	SND_SOC_DAPM_MIC("Analog Mic7", NULL),
+
+	SND_SOC_DAPM_MIC("Digital Mic1", NULL),
+	SND_SOC_DAPM_MIC("Digital Mic2", NULL),
+	SND_SOC_DAPM_MIC("Digital Mic3", NULL),
+	SND_SOC_DAPM_MIC("Digital Mic4", NULL),
+	SND_SOC_DAPM_MIC("Digital Mic5", NULL),
+	SND_SOC_DAPM_MIC("Digital Mic6", NULL),
+};
+
+static const char *const spk_function[] = {"Off", "On"};
+static const char *const slim0_rx_ch_text[] = {"One", "Two"};
+static const char *const slim0_tx_ch_text[] = {"One", "Two", "Three", "Four",
+						"Five"};
+static char const *hdmi_rx_ch_text[] = {"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 char *const proxy_rx_ch_text[] = {"One", "Two", "Three", "Four",
+	"Five",	"Six", "Seven", "Eight"};
+
+static const char *const btsco_rate_text[] = {"8000", "16000"};
+static const struct soc_enum msm_btsco_enum[] = {
+	SOC_ENUM_SINGLE_EXT(2, btsco_rate_text),
+};
+
+static 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;
+	}
+
+	pr_debug("%s: slim0_rx_sample_rate = %d\n", __func__,
+			slim0_rx_sample_rate);
+
+	return 0;
+}
+
+static int slim0_rx_bit_format_get(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+
+	switch (slim0_rx_bit_format) {
+	case SNDRV_PCM_FORMAT_S24_LE:
+		ucontrol->value.integer.value[0] = 1;
+		break;
+
+	case SNDRV_PCM_FORMAT_S16_LE:
+	default:
+		ucontrol->value.integer.value[0] = 0;
+		break;
+	}
+
+	pr_debug("%s: slim0_rx_bit_format = %d, ucontrol value = %ld\n",
+			 __func__, slim0_rx_bit_format,
+			ucontrol->value.integer.value[0]);
+
+	return 0;
+}
+
+static int slim0_rx_bit_format_put(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	switch (ucontrol->value.integer.value[0]) {
+	case 1:
+		slim0_rx_bit_format = SNDRV_PCM_FORMAT_S24_LE;
+		break;
+	case 0:
+	default:
+		slim0_rx_bit_format = SNDRV_PCM_FORMAT_S16_LE;
+		break;
+	}
+	return 0;
+}
+
+static int msm_slim_0_rx_ch_get(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	pr_debug("%s: msm_slim_0_rx_ch  = %d\n", __func__,
+		 msm_slim_0_rx_ch);
+	ucontrol->value.integer.value[0] = msm_slim_0_rx_ch - 1;
+	return 0;
+}
+
+static int msm_slim_0_rx_ch_put(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	msm_slim_0_rx_ch = ucontrol->value.integer.value[0] + 1;
+
+	pr_debug("%s: msm_slim_0_rx_ch = %d\n", __func__,
+		 msm_slim_0_rx_ch);
+	return 1;
+}
+
+static int msm_slim_0_tx_ch_get(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	pr_debug("%s: msm_slim_0_tx_ch  = %d\n", __func__,
+		 msm_slim_0_tx_ch);
+	ucontrol->value.integer.value[0] = msm_slim_0_tx_ch - 1;
+	return 0;
+}
+
+static int msm_slim_0_tx_ch_put(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	msm_slim_0_tx_ch = ucontrol->value.integer.value[0] + 1;
+
+	pr_debug("%s: msm_slim_0_tx_ch = %d\n", __func__, msm_slim_0_tx_ch);
+	return 1;
+}
+
+static int msm_btsco_rate_get(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	pr_debug("%s: msm_btsco_rate  = %d", __func__, msm_btsco_rate);
+	ucontrol->value.integer.value[0] = msm_btsco_rate;
+	return 0;
+}
+
+static int msm_btsco_rate_put(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	switch (ucontrol->value.integer.value[0]) {
+	case 0:
+		msm_btsco_rate = BTSCO_RATE_8KHZ;
+		break;
+	case 1:
+		msm_btsco_rate = BTSCO_RATE_16KHZ;
+		break;
+	default:
+		msm_btsco_rate = BTSCO_RATE_8KHZ;
+		break;
+	}
+	pr_debug("%s: msm_btsco_rate = %d\n", __func__, msm_btsco_rate);
+	return 0;
+}
+
+static int hdmi_rx_bit_format_get(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+
+	switch (hdmi_rx_bit_format) {
+	case SNDRV_PCM_FORMAT_S24_LE:
+		ucontrol->value.integer.value[0] = 1;
+		break;
+
+	case SNDRV_PCM_FORMAT_S16_LE:
+	default:
+		ucontrol->value.integer.value[0] = 0;
+		break;
+	}
+
+	pr_debug("%s: hdmi_rx_bit_format = %d, ucontrol value = %ld\n",
+			 __func__, hdmi_rx_bit_format,
+			ucontrol->value.integer.value[0]);
+
+	return 0;
+}
+
+static int hdmi_rx_bit_format_put(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	switch (ucontrol->value.integer.value[0]) {
+	case 1:
+		hdmi_rx_bit_format = SNDRV_PCM_FORMAT_S24_LE;
+		break;
+	case 0:
+	default:
+		hdmi_rx_bit_format = SNDRV_PCM_FORMAT_S16_LE;
+		break;
+	}
+	pr_debug("%s: hdmi_rx_bit_format = %d, ucontrol value = %ld\n",
+			 __func__, hdmi_rx_bit_format,
+			ucontrol->value.integer.value[0]);
+	return 0;
+}
+
+static int msm_hdmi_rx_ch_get(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	pr_debug("%s: msm_hdmi_rx_ch  = %d\n", __func__,
+			msm_hdmi_rx_ch);
+	ucontrol->value.integer.value[0] = msm_hdmi_rx_ch - 2;
+
+	return 0;
+}
+
+static int msm_hdmi_rx_ch_put(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	msm_hdmi_rx_ch = ucontrol->value.integer.value[0] + 2;
+	if (msm_hdmi_rx_ch > 8) {
+		pr_err("%s: channels exceeded 8.Limiting to max channels-8\n",
+			__func__);
+		msm_hdmi_rx_ch = 8;
+	}
+	pr_debug("%s: msm_hdmi_rx_ch = %d\n", __func__, msm_hdmi_rx_ch);
+
+	return 1;
+}
+
+static const struct snd_kcontrol_new int_btsco_rate_mixer_controls[] = {
+	SOC_ENUM_EXT("Internal BTSCO SampleRate", msm_btsco_enum[0],
+		     msm_btsco_rate_get, msm_btsco_rate_put),
+};
+
+static int msm_btsco_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+					struct snd_pcm_hw_params *params)
+{
+	struct snd_interval *rate = hw_param_interval(params,
+					SNDRV_PCM_HW_PARAM_RATE);
+
+	struct snd_interval *channels = hw_param_interval(params,
+					SNDRV_PCM_HW_PARAM_CHANNELS);
+
+	rate->min = rate->max = msm_btsco_rate;
+	channels->min = channels->max = msm_btsco_ch;
+
+	return 0;
+}
+
+static int apq8074_auxpcm_rate_get(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	ucontrol->value.integer.value[0] = apq8074_auxpcm_rate;
+	return 0;
+}
+
+static int apq8074_auxpcm_rate_put(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	switch (ucontrol->value.integer.value[0]) {
+	case 0:
+		apq8074_auxpcm_rate = 8000;
+		break;
+	case 1:
+		apq8074_auxpcm_rate = 16000;
+		break;
+	default:
+		apq8074_auxpcm_rate = 8000;
+		break;
+	}
+	return 0;
+}
+static int msm_proxy_rx_ch_get(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	pr_debug("%s: msm_proxy_rx_ch = %d\n", __func__,
+						msm_proxy_rx_ch);
+	ucontrol->value.integer.value[0] = msm_proxy_rx_ch - 1;
+	return 0;
+}
+
+static int msm_proxy_rx_ch_put(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	msm_proxy_rx_ch = ucontrol->value.integer.value[0] + 1;
+	pr_debug("%s: msm_proxy_rx_ch = %d\n", __func__,
+						msm_proxy_rx_ch);
+	return 1;
+}
+
+static int msm_auxpcm_be_params_fixup(struct snd_soc_pcm_runtime *rtd,
+					struct snd_pcm_hw_params *params)
+{
+	struct snd_interval *rate =
+	    hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
+
+	struct snd_interval *channels =
+	    hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
+
+	rate->min = rate->max = apq8074_auxpcm_rate;
+	channels->min = channels->max = 1;
+
+	return 0;
+}
+
+static int msm_proxy_rx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+					struct snd_pcm_hw_params *params)
+{
+	struct snd_interval *rate = hw_param_interval(params,
+					SNDRV_PCM_HW_PARAM_RATE);
+
+	struct snd_interval *channels = hw_param_interval(params,
+					SNDRV_PCM_HW_PARAM_CHANNELS);
+
+	pr_debug("%s: msm_proxy_rx_ch =%d\n", __func__, msm_proxy_rx_ch);
+
+	if (channels->max < 2)
+		channels->min = channels->max = 2;
+	channels->min = channels->max = msm_proxy_rx_ch;
+	rate->min = rate->max = 48000;
+	return 0;
+}
+
+static int msm_proxy_tx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+					struct snd_pcm_hw_params *params)
+{
+	struct snd_interval *rate = hw_param_interval(params,
+					SNDRV_PCM_HW_PARAM_RATE);
+
+	rate->min = rate->max = 48000;
+	return 0;
+}
+
+static int apq8074_hdmi_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+					struct snd_pcm_hw_params *params)
+{
+	struct snd_interval *rate = hw_param_interval(params,
+					SNDRV_PCM_HW_PARAM_RATE);
+
+	struct snd_interval *channels = hw_param_interval(params,
+					SNDRV_PCM_HW_PARAM_CHANNELS);
+
+	pr_debug("%s channels->min %u channels->max %u ()\n", __func__,
+			channels->min, channels->max);
+
+	param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+				hdmi_rx_bit_format);
+	if (channels->max < 2)
+		channels->min = channels->max = 2;
+	rate->min = rate->max = 48000;
+	channels->min = channels->max = msm_hdmi_rx_ch;
+
+	return 0;
+}
+
+static int msm_aux_pcm_get_gpios(struct msm_auxpcm_ctrl *auxpcm_ctrl)
+{
+	struct msm_auxpcm_gpio *pin_data = NULL;
+	int ret = 0;
+	int i;
+	int j;
+
+	pin_data = auxpcm_ctrl->pin_data;
+	for (i = 0; i < auxpcm_ctrl->cnt; i++, pin_data++) {
+		ret = gpio_request(pin_data->gpio_no,
+				pin_data->gpio_name);
+		pr_debug("%s: gpio = %d, gpio name = %s\n"
+			"ret = %d\n", __func__,
+			pin_data->gpio_no,
+			pin_data->gpio_name,
+			ret);
+		if (ret) {
+			pr_err("%s: Failed to request gpio %d\n",
+				__func__, pin_data->gpio_no);
+			/* Release all GPIOs on failure */
+			for (j = i; j >= 0; j--)
+				gpio_free(pin_data->gpio_no);
+			return ret;
+		}
+	}
+	return 0;
+}
+
+static int msm_aux_pcm_free_gpios(struct msm_auxpcm_ctrl *auxpcm_ctrl)
+{
+	struct msm_auxpcm_gpio *pin_data = NULL;
+	int i;
+	int ret = 0;
+
+	if (auxpcm_ctrl == NULL || auxpcm_ctrl->pin_data == NULL) {
+		pr_err("%s: Ctrl pointers are NULL\n", __func__);
+		ret = -EINVAL;
+		goto err;
+	}
+
+	pin_data = auxpcm_ctrl->pin_data;
+	for (i = 0; i < auxpcm_ctrl->cnt; i++, pin_data++) {
+		gpio_free(pin_data->gpio_no);
+		pr_debug("%s: gpio = %d, gpio_name = %s\n",
+			__func__, pin_data->gpio_no,
+			pin_data->gpio_name);
+	}
+err:
+	return ret;
+}
+
+static int msm_prim_auxpcm_startup(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_card *card = rtd->card;
+	struct apq8074_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
+	struct msm_auxpcm_ctrl *auxpcm_ctrl = NULL;
+	int ret = 0;
+
+	pr_debug("%s(): substream = %s, prim_auxpcm_rsc_ref counter = %d\n",
+		__func__, substream->name, atomic_read(&prim_auxpcm_rsc_ref));
+
+	auxpcm_ctrl = pdata->pri_auxpcm_ctrl;
+
+	if (auxpcm_ctrl == NULL || auxpcm_ctrl->pin_data == NULL) {
+		pr_err("%s: Ctrl pointers are NULL\n", __func__);
+		ret = -EINVAL;
+		goto err;
+	}
+	if (atomic_inc_return(&prim_auxpcm_rsc_ref) == 1) {
+		if (lpaif_pri_muxsel_virt_addr != NULL)
+			iowrite32(I2S_PCM_SEL << I2S_PCM_SEL_OFFSET,
+				lpaif_pri_muxsel_virt_addr);
+		else
+			pr_err("%s lpaif_pri_muxsel_virt_addr is NULL\n",
+				 __func__);
+		ret = msm_aux_pcm_get_gpios(auxpcm_ctrl);
+	}
+	if (ret < 0) {
+		pr_err("%s: Aux PCM GPIO request failed\n", __func__);
+		return -EINVAL;
+	}
+err:
+	return ret;
+}
+
+static void msm_prim_auxpcm_shutdown(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_card *card = rtd->card;
+	struct apq8074_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
+	struct msm_auxpcm_ctrl *auxpcm_ctrl = NULL;
+
+	pr_debug("%s(): substream = %s, prim_auxpcm_rsc_ref counter = %d\n",
+		__func__, substream->name, atomic_read(&prim_auxpcm_rsc_ref));
+
+	auxpcm_ctrl = pdata->pri_auxpcm_ctrl;
+
+	if (atomic_dec_return(&prim_auxpcm_rsc_ref) == 0)
+		msm_aux_pcm_free_gpios(auxpcm_ctrl);
+}
+static struct snd_soc_ops msm_auxpcm_be_ops = {
+	.startup = msm_prim_auxpcm_startup,
+	.shutdown = msm_prim_auxpcm_shutdown,
+};
+
+static int msm_slim_0_rx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+					    struct snd_pcm_hw_params *params)
+{
+	struct snd_interval *rate = hw_param_interval(params,
+	SNDRV_PCM_HW_PARAM_RATE);
+
+	struct snd_interval *channels =
+	    hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
+
+	pr_debug("%s()\n", __func__);
+	param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+				   slim0_rx_bit_format);
+	rate->min = rate->max = slim0_rx_sample_rate;
+	channels->min = channels->max = msm_slim_0_rx_ch;
+
+	 pr_debug("%s: format = %d, rate = %d, channels = %d\n",
+			  __func__, params_format(params), params_rate(params),
+			  msm_slim_0_rx_ch);
+
+	return 0;
+}
+
+static int msm_slim_0_tx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+					    struct snd_pcm_hw_params *params)
+{
+	struct snd_interval *rate = hw_param_interval(params,
+	SNDRV_PCM_HW_PARAM_RATE);
+
+	struct snd_interval *channels = hw_param_interval(params,
+			SNDRV_PCM_HW_PARAM_CHANNELS);
+
+	pr_debug("%s()\n", __func__);
+	rate->min = rate->max = 48000;
+	channels->min = channels->max = msm_slim_0_tx_ch;
+
+	return 0;
+}
+
+static int msm_slim_5_tx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+					    struct snd_pcm_hw_params *params)
+{
+	int rc;
+	void *config;
+	struct snd_soc_codec *codec = rtd->codec;
+	struct snd_interval *rate =
+	    hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
+	struct snd_interval *channels =
+	    hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
+
+	pr_debug("%s enter\n", __func__);
+	rate->min = rate->max = 16000;
+	channels->min = channels->max = 1;
+
+	config = taiko_get_afe_config(codec, AFE_SLIMBUS_SLAVE_PORT_CONFIG);
+	rc = afe_set_config(AFE_SLIMBUS_SLAVE_PORT_CONFIG, config,
+			    SLIMBUS_5_TX);
+	if (rc) {
+		pr_err("%s: Failed to set slimbus slave port config %d\n",
+		       __func__, rc);
+		return rc;
+	}
+
+	return 0;
+}
+
+static int msm_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+				struct snd_pcm_hw_params *params)
+{
+	struct snd_interval *rate = hw_param_interval(params,
+					SNDRV_PCM_HW_PARAM_RATE);
+
+	pr_debug("%s()\n", __func__);
+	rate->min = rate->max = 48000;
+
+	return 0;
+}
+
+static const struct soc_enum msm_snd_enum[] = {
+	SOC_ENUM_SINGLE_EXT(2, spk_function),
+	SOC_ENUM_SINGLE_EXT(2, slim0_rx_ch_text),
+	SOC_ENUM_SINGLE_EXT(5, slim0_tx_ch_text),
+	SOC_ENUM_SINGLE_EXT(7, hdmi_rx_ch_text),
+	SOC_ENUM_SINGLE_EXT(2, rx_bit_format_text),
+	SOC_ENUM_SINGLE_EXT(3, slim0_rx_sample_rate_text),
+	SOC_ENUM_SINGLE_EXT(8, proxy_rx_ch_text),
+};
+
+static const struct snd_kcontrol_new msm_snd_controls[] = {
+	SOC_ENUM_EXT("Speaker Function", msm_snd_enum[0], apq8074_get_spk,
+			apq8074_set_spk),
+	SOC_ENUM_EXT("SLIM_0_RX Channels", msm_snd_enum[1],
+			msm_slim_0_rx_ch_get, msm_slim_0_rx_ch_put),
+	SOC_ENUM_EXT("SLIM_0_TX Channels", msm_snd_enum[2],
+			msm_slim_0_tx_ch_get, msm_slim_0_tx_ch_put),
+	SOC_ENUM_EXT("AUX PCM SampleRate", apq8074_auxpcm_enum[0],
+			apq8074_auxpcm_rate_get, apq8074_auxpcm_rate_put),
+	SOC_ENUM_EXT("HDMI_RX Channels", msm_snd_enum[3],
+			msm_hdmi_rx_ch_get, msm_hdmi_rx_ch_put),
+	SOC_ENUM_EXT("SLIM_0_RX Format", msm_snd_enum[4],
+			slim0_rx_bit_format_get, slim0_rx_bit_format_put),
+	SOC_ENUM_EXT("SLIM_0_RX SampleRate", msm_snd_enum[5],
+			slim0_rx_sample_rate_get, slim0_rx_sample_rate_put),
+	SOC_ENUM_EXT("HDMI_RX Bit Format", msm_snd_enum[4],
+			hdmi_rx_bit_format_get, hdmi_rx_bit_format_put),
+	SOC_ENUM_EXT("PROXY_RX Channels", msm_snd_enum[6],
+			msm_proxy_rx_ch_get, msm_proxy_rx_ch_put),
+};
+
+static bool apq8074_swap_gnd_mic(struct snd_soc_codec *codec)
+{
+	struct snd_soc_card *card = codec->card;
+	struct apq8074_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
+	int value = gpio_get_value_cansleep(pdata->us_euro_gpio);
+	pr_debug("%s: swap select switch %d to %d\n", __func__, value, !value);
+	gpio_set_value_cansleep(pdata->us_euro_gpio, !value);
+	return true;
+}
+
+static int msm_audrx_init(struct snd_soc_pcm_runtime *rtd)
+{
+	int err;
+	void *config_data;
+	struct snd_soc_codec *codec = rtd->codec;
+	struct snd_soc_dapm_context *dapm = &codec->dapm;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+	struct snd_soc_dai *codec_dai = rtd->codec_dai;
+
+	/* Taiko SLIMBUS configuration
+	 * RX1, RX2, RX3, RX4, RX5, RX6, RX7, RX8, RX9, RX10, RX11, RX12, RX13
+	 * TX1, TX2, TX3, TX4, TX5, TX6, TX7, TX8, TX9, TX10, TX11, TX12, TX13
+	 * TX14, TX15, TX16
+	 */
+	unsigned int rx_ch[TAIKO_RX_MAX] = {144, 145, 146, 147, 148, 149, 150,
+					    151, 152, 153, 154, 155, 156};
+	unsigned int tx_ch[TAIKO_TX_MAX]  = {128, 129, 130, 131, 132, 133,
+					     134, 135, 136, 137, 138, 139,
+					     140, 141, 142, 143};
+
+
+	pr_info("%s(), dev_name%s\n", __func__, dev_name(cpu_dai->dev));
+
+	rtd->pmdown_time = 0;
+
+	err = snd_soc_add_codec_controls(codec, msm_snd_controls,
+					 ARRAY_SIZE(msm_snd_controls));
+	if (err < 0)
+		return err;
+
+	err = apq8074_liquid_ext_spk_power_amp_init();
+	if (err) {
+		pr_err("%s: LiQUID 8974 CLASS_D PAs init failed (%d)\n",
+			__func__, err);
+		return err;
+	}
+
+	err = apq8074_liquid_init_docking(dapm);
+	if (err) {
+		pr_err("%s: LiQUID 8974 init Docking stat IRQ failed (%d)\n",
+			   __func__, err);
+		return err;
+	}
+
+	snd_soc_dapm_new_controls(dapm, apq8074_dapm_widgets,
+				ARRAY_SIZE(apq8074_dapm_widgets));
+
+	snd_soc_dapm_enable_pin(dapm, "Lineout_1 amp");
+	snd_soc_dapm_enable_pin(dapm, "Lineout_3 amp");
+	snd_soc_dapm_enable_pin(dapm, "Lineout_2 amp");
+	snd_soc_dapm_enable_pin(dapm, "Lineout_4 amp");
+
+
+	snd_soc_dapm_sync(dapm);
+
+	codec_clk = clk_get(cpu_dai->dev, "osr_clk");
+
+	snd_soc_dai_set_channel_map(codec_dai, ARRAY_SIZE(tx_ch),
+				    tx_ch, ARRAY_SIZE(rx_ch), rx_ch);
+
+
+	config_data = taiko_get_afe_config(codec, AFE_CDC_REGISTERS_CONFIG);
+	err = afe_set_config(AFE_CDC_REGISTERS_CONFIG, config_data, 0);
+	if (err) {
+		pr_err("%s: Failed to set codec registers config %d\n",
+		       __func__, err);
+		goto out;
+	}
+
+	config_data = taiko_get_afe_config(codec, AFE_SLIMBUS_SLAVE_CONFIG);
+	err = afe_set_config(AFE_SLIMBUS_SLAVE_CONFIG, config_data, 0);
+	if (err) {
+		pr_err("%s: Failed to set slimbus slave config %d\n", __func__,
+		       err);
+		goto out;
+	}
+
+	config_data = taiko_get_afe_config(codec, AFE_AANC_VERSION);
+	err = afe_set_config(AFE_AANC_VERSION, config_data, 0);
+	if (err) {
+		pr_err("%s: Failed to set aanc version %d\n",
+			__func__, err);
+		goto out;
+	}
+	config_data = taiko_get_afe_config(codec,
+				AFE_CDC_CLIP_REGISTERS_CONFIG);
+	if (config_data) {
+		err = afe_set_config(AFE_CDC_CLIP_REGISTERS_CONFIG,
+					config_data, 0);
+		if (err) {
+			pr_err("%s: Failed to set clip registers %d\n",
+				__func__, err);
+			return err;
+		}
+	}
+	config_data = taiko_get_afe_config(codec, AFE_CLIP_BANK_SEL);
+	if (config_data) {
+		err = afe_set_config(AFE_CLIP_BANK_SEL, config_data, 0);
+		if (err) {
+			pr_err("%s: Failed to set AFE bank selection %d\n",
+				__func__, err);
+			return err;
+		}
+	}
+	/* start mbhc */
+	mbhc_cfg.calibration = def_taiko_mbhc_cal();
+	if (mbhc_cfg.calibration) {
+		err = taiko_hs_detect(codec, &mbhc_cfg);
+		if (err)
+			goto out;
+		else
+			return err;
+	} else {
+		err = -ENOMEM;
+		goto out;
+	}
+out:
+	clk_put(codec_clk);
+	return err;
+}
+
+static int apq8074_snd_startup(struct snd_pcm_substream *substream)
+{
+	pr_debug("%s(): substream = %s  stream = %d\n", __func__,
+		 substream->name, substream->stream);
+	return 0;
+}
+
+static void *def_taiko_mbhc_cal(void)
+{
+	void *taiko_cal;
+	struct wcd9xxx_mbhc_btn_detect_cfg *btn_cfg;
+	u16 *btn_low, *btn_high;
+	u8 *n_ready, *n_cic, *gain;
+
+	taiko_cal = kzalloc(WCD9XXX_MBHC_CAL_SIZE(WCD9XXX_MBHC_DEF_BUTTONS,
+						WCD9XXX_MBHC_DEF_RLOADS),
+			    GFP_KERNEL);
+	if (!taiko_cal) {
+		pr_err("%s: out of memory\n", __func__);
+		return NULL;
+	}
+
+#define S(X, Y) ((WCD9XXX_MBHC_CAL_GENERAL_PTR(taiko_cal)->X) = (Y))
+	S(t_ldoh, 100);
+	S(t_bg_fast_settle, 100);
+	S(t_shutdown_plug_rem, 255);
+	S(mbhc_nsa, 4);
+	S(mbhc_navg, 4);
+#undef S
+#define S(X, Y) ((WCD9XXX_MBHC_CAL_PLUG_DET_PTR(taiko_cal)->X) = (Y))
+	S(mic_current, TAIKO_PID_MIC_5_UA);
+	S(hph_current, TAIKO_PID_MIC_5_UA);
+	S(t_mic_pid, 100);
+	S(t_ins_complete, 250);
+	S(t_ins_retry, 200);
+#undef S
+#define S(X, Y) ((WCD9XXX_MBHC_CAL_PLUG_TYPE_PTR(taiko_cal)->X) = (Y))
+	S(v_no_mic, 30);
+	S(v_hs_max, 2400);
+#undef S
+#define S(X, Y) ((WCD9XXX_MBHC_CAL_BTN_DET_PTR(taiko_cal)->X) = (Y))
+	S(c[0], 62);
+	S(c[1], 124);
+	S(nc, 1);
+	S(n_meas, 3);
+	S(mbhc_nsc, 11);
+	S(n_btn_meas, 1);
+	S(n_btn_con, 2);
+	S(num_btn, WCD9XXX_MBHC_DEF_BUTTONS);
+	S(v_btn_press_delta_sta, 100);
+	S(v_btn_press_delta_cic, 50);
+#undef S
+	btn_cfg = WCD9XXX_MBHC_CAL_BTN_DET_PTR(taiko_cal);
+	btn_low = wcd9xxx_mbhc_cal_btn_det_mp(btn_cfg, MBHC_BTN_DET_V_BTN_LOW);
+	btn_high = wcd9xxx_mbhc_cal_btn_det_mp(btn_cfg,
+					       MBHC_BTN_DET_V_BTN_HIGH);
+	btn_low[0] = -50;
+	btn_high[0] = 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] = 269;
+	btn_low[7] = 270;
+	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;
+	n_cic = wcd9xxx_mbhc_cal_btn_det_mp(btn_cfg, MBHC_BTN_DET_N_CIC);
+	n_cic[0] = 60;
+	n_cic[1] = 47;
+	gain = wcd9xxx_mbhc_cal_btn_det_mp(btn_cfg, MBHC_BTN_DET_GAIN);
+	gain[0] = 11;
+	gain[1] = 9;
+
+	return taiko_cal;
+}
+
+static int msm_snd_hw_params(struct snd_pcm_substream *substream,
+			     struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *codec_dai = rtd->codec_dai;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+	int ret = 0;
+	unsigned int rx_ch[SLIM_MAX_RX_PORTS], tx_ch[SLIM_MAX_TX_PORTS];
+	unsigned int rx_ch_cnt = 0, tx_ch_cnt = 0;
+	unsigned int user_set_tx_ch = 0;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		pr_debug("%s: rx_0_ch=%d\n", __func__, msm_slim_0_rx_ch);
+		ret = snd_soc_dai_get_channel_map(codec_dai,
+					&tx_ch_cnt, tx_ch, &rx_ch_cnt , rx_ch);
+		if (ret < 0) {
+			pr_err("%s: failed to get codec chan map\n", __func__);
+			goto end;
+		}
+
+		ret = snd_soc_dai_set_channel_map(cpu_dai, 0, 0,
+						  msm_slim_0_rx_ch, rx_ch);
+		if (ret < 0) {
+			pr_err("%s: failed to set cpu chan map\n", __func__);
+			goto end;
+		}
+	} else {
+
+		pr_debug("%s: %s_tx_dai_id_%d_ch=%d\n", __func__,
+			 codec_dai->name, codec_dai->id, user_set_tx_ch);
+
+		ret = snd_soc_dai_get_channel_map(codec_dai,
+					 &tx_ch_cnt, tx_ch, &rx_ch_cnt , rx_ch);
+		if (ret < 0) {
+			pr_err("%s: failed to get codec chan map\n", __func__);
+			goto end;
+		}
+		/* For tabla_tx1 case */
+		if (codec_dai->id == 1)
+			user_set_tx_ch = msm_slim_0_tx_ch;
+		/* For tabla_tx2 case */
+		else if (codec_dai->id == 3)
+			user_set_tx_ch = params_channels(params);
+		else
+			user_set_tx_ch = tx_ch_cnt;
+
+		pr_debug("%s: msm_slim_0_tx_ch(%d)user_set_tx_ch(%d)tx_ch_cnt(%d)\n",
+			 __func__, msm_slim_0_tx_ch, user_set_tx_ch, tx_ch_cnt);
+
+		ret = snd_soc_dai_set_channel_map(cpu_dai,
+						  user_set_tx_ch, tx_ch, 0 , 0);
+		if (ret < 0) {
+			pr_err("%s: failed to set cpu chan map\n", __func__);
+			goto end;
+		}
+	}
+end:
+	return ret;
+}
+
+static void apq8074_snd_shudown(struct snd_pcm_substream *substream)
+{
+	pr_debug("%s(): substream = %s stream = %d\n", __func__,
+		 substream->name, substream->stream);
+
+}
+
+static struct snd_soc_ops apq8074_be_ops = {
+	.startup = apq8074_snd_startup,
+	.hw_params = msm_snd_hw_params,
+	.shutdown = apq8074_snd_shudown,
+};
+
+
+
+static int apq8074_slimbus_2_hw_params(struct snd_pcm_substream *substream,
+				struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *codec_dai = rtd->codec_dai;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+	int ret = 0;
+	unsigned int rx_ch[SLIM_MAX_RX_PORTS], tx_ch[SLIM_MAX_TX_PORTS];
+	unsigned int rx_ch_cnt = 0, tx_ch_cnt = 0;
+	unsigned int num_tx_ch = 0;
+	unsigned int num_rx_ch = 0;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+
+		num_rx_ch =  params_channels(params);
+
+		pr_debug("%s: %s rx_dai_id = %d  num_ch = %d\n", __func__,
+			codec_dai->name, codec_dai->id, num_rx_ch);
+
+		ret = snd_soc_dai_get_channel_map(codec_dai,
+				&tx_ch_cnt, tx_ch, &rx_ch_cnt , rx_ch);
+		if (ret < 0) {
+			pr_err("%s: failed to get codec chan map\n", __func__);
+			goto end;
+		}
+
+		ret = snd_soc_dai_set_channel_map(cpu_dai, 0, 0,
+				num_rx_ch, rx_ch);
+		if (ret < 0) {
+			pr_err("%s: failed to set cpu chan map\n", __func__);
+			goto end;
+		}
+	} else {
+
+		num_tx_ch =  params_channels(params);
+
+		pr_debug("%s: %s  tx_dai_id = %d  num_ch = %d\n", __func__,
+			codec_dai->name, codec_dai->id, num_tx_ch);
+
+		ret = snd_soc_dai_get_channel_map(codec_dai,
+				&tx_ch_cnt, tx_ch, &rx_ch_cnt , rx_ch);
+		if (ret < 0) {
+			pr_err("%s: failed to get codec chan map\n", __func__);
+			goto end;
+		}
+
+		ret = snd_soc_dai_set_channel_map(cpu_dai,
+				num_tx_ch, tx_ch, 0 , 0);
+		if (ret < 0) {
+			pr_err("%s: failed to set cpu chan map\n", __func__);
+			goto end;
+		}
+	}
+end:
+	return ret;
+}
+
+
+static struct snd_soc_ops apq8074_slimbus_2_be_ops = {
+	.startup = apq8074_snd_startup,
+	.hw_params = apq8074_slimbus_2_hw_params,
+	.shutdown = apq8074_snd_shudown,
+};
+
+/* Digital audio interface glue - connects codec <---> CPU */
+static struct snd_soc_dai_link apq8074_common_dai_links[] = {
+	/* FrontEnd DAI Links */
+	{
+		.name = "MSM8974 Media1",
+		.stream_name = "MultiMedia1",
+		.cpu_dai_name	= "MultiMedia1",
+		.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_MULTIMEDIA1
+	},
+	{
+		.name = "MSM8974 Media2",
+		.stream_name = "MultiMedia2",
+		.cpu_dai_name   = "MultiMedia2",
+		.platform_name  = "msm-pcm-dsp.0",
+		.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,
+		/* this dainlink has playback support */
+		.ignore_pmdown_time = 1,
+		.be_id = MSM_FRONTEND_DAI_MULTIMEDIA2,
+	},
+	{
+		.name = "Circuit-Switch Voice",
+		.stream_name = "CS-Voice",
+		.cpu_dai_name   = "CS-VOICE",
+		.platform_name  = "msm-pcm-voice",
+		.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},
+		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+		.ignore_suspend = 1,
+		/* this dainlink has playback support */
+		.ignore_pmdown_time = 1,
+		.be_id = MSM_FRONTEND_DAI_CS_VOICE,
+	},
+	{
+		.name = "MSM VoIP",
+		.stream_name = "VoIP",
+		.cpu_dai_name	= "VoIP",
+		.platform_name  = "msm-voip-dsp",
+		.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_VOIP,
+	},
+	{
+		.name = "MSM8974 LPA",
+		.stream_name = "LPA",
+		.cpu_dai_name	= "MultiMedia3",
+		.platform_name  = "msm-pcm-lpa",
+		.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_MULTIMEDIA3,
+	},
+	/* Hostless PCM purpose */
+	{
+		.name = "SLIMBUS_0 Hostless",
+		.stream_name = "SLIMBUS_0 Hostless",
+		.cpu_dai_name = "SLIMBUS0_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,
+		.ignore_pmdown_time = 1, /* dai link has playback support */
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.codec_name = "snd-soc-dummy",
+	},
+	{
+		.name = "INT_FM Hostless",
+		.stream_name = "INT_FM Hostless",
+		.cpu_dai_name	= "INT_FM_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 dainlink has playback support */
+		.ignore_pmdown_time = 1,
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.codec_name = "snd-soc-dummy",
+	},
+	{
+		.name = "MSM AFE-PCM RX",
+		.stream_name = "AFE-PROXY RX",
+		.cpu_dai_name = "msm-dai-q6-dev.241",
+		.codec_name = "msm-stub-codec.1",
+		.codec_dai_name = "msm-stub-rx",
+		.platform_name  = "msm-pcm-afe",
+		.ignore_suspend = 1,
+		/* this dainlink has playback support */
+		.ignore_pmdown_time = 1,
+	},
+	{
+		.name = "MSM AFE-PCM TX",
+		.stream_name = "AFE-PROXY TX",
+		.cpu_dai_name = "msm-dai-q6-dev.240",
+		.codec_name = "msm-stub-codec.1",
+		.codec_dai_name = "msm-stub-tx",
+		.platform_name  = "msm-pcm-afe",
+		.ignore_suspend = 1,
+	},
+	{
+		.name = "MSM8974 Compr",
+		.stream_name = "COMPR",
+		.cpu_dai_name	= "MultiMedia4",
+		.platform_name  = "msm-compr-dsp",
+		.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,
+		.ignore_pmdown_time = 1,
+		 /* this dainlink has playback support */
+		.be_id = MSM_FRONTEND_DAI_MULTIMEDIA4,
+	},
+	{
+		.name = "AUXPCM Hostless",
+		.stream_name = "AUXPCM Hostless",
+		.cpu_dai_name   = "AUXPCM_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 dainlink has playback support */
+		.ignore_pmdown_time = 1,
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.codec_name = "snd-soc-dummy",
+	},
+	{
+		.name = "SLIMBUS_1 Hostless",
+		.stream_name = "SLIMBUS_1 Hostless",
+		.cpu_dai_name = "SLIMBUS1_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,
+		.ignore_pmdown_time = 1, /* dai link has playback support */
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.codec_name = "snd-soc-dummy",
+	},
+	{
+		.name = "SLIMBUS_3 Hostless",
+		.stream_name = "SLIMBUS_3 Hostless",
+		.cpu_dai_name = "SLIMBUS3_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,
+		.ignore_pmdown_time = 1, /* dai link has playback support */
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.codec_name = "snd-soc-dummy",
+	},
+	{
+		.name = "SLIMBUS_4 Hostless",
+		.stream_name = "SLIMBUS_4 Hostless",
+		.cpu_dai_name = "SLIMBUS4_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,
+		.ignore_pmdown_time = 1, /* dai link has playback support */
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.codec_name = "snd-soc-dummy",
+	},
+	{
+		.name = "VoLTE",
+		.stream_name = "VoLTE",
+		.cpu_dai_name   = "VoLTE",
+		.platform_name  = "msm-pcm-voice",
+		.dynamic = 1,
+		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
+			    SND_SOC_DPCM_TRIGGER_POST},
+		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+		.ignore_suspend = 1,
+		/* this dainlink has playback support */
+		.ignore_pmdown_time = 1,
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.codec_name = "snd-soc-dummy",
+		.be_id = MSM_FRONTEND_DAI_VOLTE,
+	},
+	{
+		.name = "MSM8974 LowLatency",
+		.stream_name = "MultiMedia5",
+		.cpu_dai_name   = "MultiMedia5",
+		.platform_name  = "msm-pcm-dsp.1",
+		.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,
+		/* this dainlink has playback support */
+		.ignore_pmdown_time = 1,
+		.be_id = MSM_FRONTEND_DAI_MULTIMEDIA5,
+	},
+	/* LSM FE */
+	{
+		.name = "Listen Audio Service",
+		.stream_name = "Listen Audio Service",
+		.cpu_dai_name = "LSM",
+		.platform_name = "msm-lsm-client",
+		.dynamic = 1,
+		.trigger = { SND_SOC_DPCM_TRIGGER_POST,
+			     SND_SOC_DPCM_TRIGGER_POST },
+		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+		.ignore_suspend = 1,
+		.ignore_pmdown_time = 1,
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.codec_name = "snd-soc-dummy",
+		.be_id = MSM_FRONTEND_DAI_LSM1,
+	},
+	/* Backend BT/FM DAI Links */
+	{
+		.name = LPASS_BE_INT_BT_SCO_RX,
+		.stream_name = "Internal BT-SCO Playback",
+		.cpu_dai_name = "msm-dai-q6-dev.12288",
+		.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_INT_BT_SCO_RX,
+		.be_hw_params_fixup = msm_btsco_be_hw_params_fixup,
+		/* this dainlink has playback support */
+		.ignore_pmdown_time = 1,
+		.ignore_suspend = 1,
+	},
+	{
+		.name = LPASS_BE_INT_BT_SCO_TX,
+		.stream_name = "Internal BT-SCO Capture",
+		.cpu_dai_name = "msm-dai-q6-dev.12289",
+		.platform_name = "msm-pcm-routing",
+		.codec_name = "msm-stub-codec.1",
+		.codec_dai_name	= "msm-stub-tx",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_INT_BT_SCO_TX,
+		.be_hw_params_fixup = msm_btsco_be_hw_params_fixup,
+		.ignore_suspend = 1,
+	},
+	{
+		.name = LPASS_BE_INT_FM_RX,
+		.stream_name = "Internal FM Playback",
+		.cpu_dai_name = "msm-dai-q6-dev.12292",
+		.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_INT_FM_RX,
+		.be_hw_params_fixup = msm_be_hw_params_fixup,
+		/* this dainlink has playback support */
+		.ignore_pmdown_time = 1,
+		.ignore_suspend = 1,
+	},
+	{
+		.name = LPASS_BE_INT_FM_TX,
+		.stream_name = "Internal FM Capture",
+		.cpu_dai_name = "msm-dai-q6-dev.12293",
+		.platform_name = "msm-pcm-routing",
+		.codec_name = "msm-stub-codec.1",
+		.codec_dai_name = "msm-stub-tx",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_INT_FM_TX,
+		.be_hw_params_fixup = msm_be_hw_params_fixup,
+		.ignore_suspend = 1,
+	},
+	/* Backend AFE DAI Links */
+	{
+		.name = LPASS_BE_AFE_PCM_RX,
+		.stream_name = "AFE Playback",
+		.cpu_dai_name = "msm-dai-q6-dev.224",
+		.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_AFE_PCM_RX,
+		.be_hw_params_fixup = msm_proxy_rx_be_hw_params_fixup,
+		/* this dainlink has playback support */
+		.ignore_pmdown_time = 1,
+		.ignore_suspend = 1,
+	},
+	{
+		.name = LPASS_BE_AFE_PCM_TX,
+		.stream_name = "AFE Capture",
+		.cpu_dai_name = "msm-dai-q6-dev.225",
+		.platform_name = "msm-pcm-routing",
+		.codec_name = "msm-stub-codec.1",
+		.codec_dai_name = "msm-stub-tx",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_AFE_PCM_TX,
+		.be_hw_params_fixup = msm_proxy_tx_be_hw_params_fixup,
+		.ignore_suspend = 1,
+	},
+	/* HDMI Hostless */
+	{
+		.name = "HDMI_RX_HOSTLESS",
+		.stream_name = "HDMI_RX_HOSTLESS",
+		.cpu_dai_name = "HDMI_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,
+		.ignore_pmdown_time = 1,
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.codec_name = "snd-soc-dummy",
+	},
+	/* AUX PCM Backend DAI Links */
+	{
+		.name = LPASS_BE_AUXPCM_RX,
+		.stream_name = "AUX PCM Playback",
+		.cpu_dai_name = "msm-dai-q6.4106",
+		.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_AUXPCM_RX,
+		.be_hw_params_fixup = msm_auxpcm_be_params_fixup,
+		.ops = &msm_auxpcm_be_ops,
+		.ignore_pmdown_time = 1,
+		.ignore_suspend = 1,
+		/* this dainlink has playback support */
+	},
+	{
+		.name = LPASS_BE_AUXPCM_TX,
+		.stream_name = "AUX PCM Capture",
+		.cpu_dai_name = "msm-dai-q6.4107",
+		.platform_name = "msm-pcm-routing",
+		.codec_name = "msm-stub-codec.1",
+		.codec_dai_name = "msm-stub-tx",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_AUXPCM_TX,
+		.be_hw_params_fixup = msm_auxpcm_be_params_fixup,
+		.ops = &msm_auxpcm_be_ops,
+		.ignore_suspend = 1,
+	},
+	/* Backend DAI Links */
+	{
+		.name = LPASS_BE_SLIMBUS_0_RX,
+		.stream_name = "Slimbus Playback",
+		.cpu_dai_name = "msm-dai-q6-dev.16384",
+		.platform_name = "msm-pcm-routing",
+		.codec_name = "taiko_codec",
+		.codec_dai_name	= "taiko_rx1",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_SLIMBUS_0_RX,
+		.init = &msm_audrx_init,
+		.be_hw_params_fixup = msm_slim_0_rx_be_hw_params_fixup,
+		.ops = &apq8074_be_ops,
+		.ignore_pmdown_time = 1, /* dai link has playback support */
+		.ignore_suspend = 1,
+	},
+	{
+		.name = LPASS_BE_SLIMBUS_0_TX,
+		.stream_name = "Slimbus Capture",
+		.cpu_dai_name = "msm-dai-q6-dev.16385",
+		.platform_name = "msm-pcm-routing",
+		.codec_name = "taiko_codec",
+		.codec_dai_name	= "taiko_tx1",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_SLIMBUS_0_TX,
+		.be_hw_params_fixup = msm_slim_0_tx_be_hw_params_fixup,
+		.ops = &apq8074_be_ops,
+		.ignore_suspend = 1,
+	},
+	{
+		.name = LPASS_BE_SLIMBUS_1_RX,
+		.stream_name = "Slimbus1 Playback",
+		.cpu_dai_name = "msm-dai-q6-dev.16386",
+		.platform_name = "msm-pcm-routing",
+		.codec_name = "taiko_codec",
+		.codec_dai_name	= "taiko_rx1",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_SLIMBUS_1_RX,
+		.be_hw_params_fixup = msm_slim_0_rx_be_hw_params_fixup,
+		.ops = &apq8074_be_ops,
+		/* dai link has playback support */
+		.ignore_pmdown_time = 1,
+		.ignore_suspend = 1,
+	},
+	{
+		.name = LPASS_BE_SLIMBUS_1_TX,
+		.stream_name = "Slimbus1 Capture",
+		.cpu_dai_name = "msm-dai-q6-dev.16387",
+		.platform_name = "msm-pcm-routing",
+		.codec_name = "taiko_codec",
+		.codec_dai_name	= "taiko_tx1",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_SLIMBUS_1_TX,
+		.be_hw_params_fixup = msm_slim_0_tx_be_hw_params_fixup,
+		.ops = &apq8074_be_ops,
+		.ignore_suspend = 1,
+	},
+	{
+		.name = LPASS_BE_SLIMBUS_3_RX,
+		.stream_name = "Slimbus3 Playback",
+		.cpu_dai_name = "msm-dai-q6-dev.16390",
+		.platform_name = "msm-pcm-routing",
+		.codec_name = "taiko_codec",
+		.codec_dai_name	= "taiko_rx1",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_SLIMBUS_3_RX,
+		.be_hw_params_fixup = msm_slim_0_rx_be_hw_params_fixup,
+		.ops = &apq8074_be_ops,
+		/* dai link has playback support */
+		.ignore_pmdown_time = 1,
+		.ignore_suspend = 1,
+	},
+	{
+		.name = LPASS_BE_SLIMBUS_3_TX,
+		.stream_name = "Slimbus3 Capture",
+		.cpu_dai_name = "msm-dai-q6-dev.16391",
+		.platform_name = "msm-pcm-routing",
+		.codec_name = "taiko_codec",
+		.codec_dai_name	= "taiko_tx1",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_SLIMBUS_3_TX,
+		.be_hw_params_fixup = msm_slim_0_tx_be_hw_params_fixup,
+		.ops = &apq8074_be_ops,
+		.ignore_suspend = 1,
+	},
+	{
+		.name = LPASS_BE_SLIMBUS_4_RX,
+		.stream_name = "Slimbus4 Playback",
+		.cpu_dai_name = "msm-dai-q6-dev.16392",
+		.platform_name = "msm-pcm-routing",
+		.codec_name = "taiko_codec",
+		.codec_dai_name	= "taiko_rx1",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_SLIMBUS_4_RX,
+		.be_hw_params_fixup = msm_slim_0_rx_be_hw_params_fixup,
+		.ops = &apq8074_be_ops,
+		/* dai link has playback support */
+		.ignore_pmdown_time = 1,
+		.ignore_suspend = 1,
+	},
+	{
+		.name = LPASS_BE_SLIMBUS_4_TX,
+		.stream_name = "Slimbus4 Capture",
+		.cpu_dai_name = "msm-dai-q6-dev.16393",
+		.platform_name = "msm-pcm-hostless",
+		.codec_name = "taiko_codec",
+		.codec_dai_name	= "taiko_vifeedback",
+		.be_id = MSM_BACKEND_DAI_SLIMBUS_4_TX,
+		.be_hw_params_fixup = msm_slim_0_tx_be_hw_params_fixup,
+		.ops = &apq8074_be_ops,
+		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+		.ignore_suspend = 1,
+	},
+	/* Incall Record Uplink BACK END DAI Link */
+	{
+		.name = LPASS_BE_INCALL_RECORD_TX,
+		.stream_name = "Voice Uplink Capture",
+		.cpu_dai_name = "msm-dai-q6-dev.32772",
+		.platform_name = "msm-pcm-routing",
+		.codec_name     = "msm-stub-codec.1",
+		.codec_dai_name = "msm-stub-tx",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_INCALL_RECORD_TX,
+		.be_hw_params_fixup = msm_be_hw_params_fixup,
+		.ignore_suspend = 1,
+	},
+	/* Incall Record Downlink BACK END DAI Link */
+	{
+		.name = LPASS_BE_INCALL_RECORD_RX,
+		.stream_name = "Voice Downlink Capture",
+		.cpu_dai_name = "msm-dai-q6-dev.32771",
+		.platform_name = "msm-pcm-routing",
+		.codec_name     = "msm-stub-codec.1",
+		.codec_dai_name = "msm-stub-tx",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_INCALL_RECORD_RX,
+		.be_hw_params_fixup = msm_be_hw_params_fixup,
+		.ignore_suspend = 1,
+	},
+	/* MAD BE */
+	{
+		.name = LPASS_BE_SLIMBUS_5_TX,
+		.stream_name = "Slimbus5 Capture",
+		.cpu_dai_name = "msm-dai-q6-dev.16395",
+		.platform_name = "msm-pcm-routing",
+		.codec_name = "taiko_codec",
+		.codec_dai_name = "taiko_mad1",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_SLIMBUS_5_TX,
+		.be_hw_params_fixup = msm_slim_5_tx_be_hw_params_fixup,
+		.ops = &apq8074_be_ops,
+	},
+	/* Incall Music BACK END DAI Link */
+	{
+		.name = LPASS_BE_VOICE_PLAYBACK_TX,
+		.stream_name = "Voice Farend Playback",
+		.cpu_dai_name = "msm-dai-q6-dev.32773",
+		.platform_name = "msm-pcm-routing",
+		.codec_name     = "msm-stub-codec.1",
+		.codec_dai_name = "msm-stub-rx",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_VOICE_PLAYBACK_TX,
+		.be_hw_params_fixup = msm_be_hw_params_fixup,
+		.ignore_suspend = 1,
+	},
+	/* Ultrasound RX Back End DAI Link */
+	{
+		.name = "SLIMBUS_2 Hostless Playback",
+		.stream_name = "SLIMBUS_2 Hostless Playback",
+		.cpu_dai_name = "msm-dai-q6-dev.16388",
+		.platform_name = "msm-pcm-hostless",
+		.codec_name = "taiko_codec",
+		.codec_dai_name = "taiko_rx2",
+		.ignore_suspend = 1,
+		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+		.ops = &apq8074_slimbus_2_be_ops,
+	},
+	/* Ultrasound TX Back End DAI Link */
+	{
+		.name = "SLIMBUS_2 Hostless Capture",
+		.stream_name = "SLIMBUS_2 Hostless Capture",
+		.cpu_dai_name = "msm-dai-q6-dev.16389",
+		.platform_name = "msm-pcm-hostless",
+		.codec_name = "taiko_codec",
+		.codec_dai_name = "taiko_tx2",
+		.ignore_suspend = 1,
+		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+		.ops = &apq8074_slimbus_2_be_ops,
+	},
+};
+
+static struct snd_soc_dai_link apq8074_hdmi_dai_link[] = {
+/* HDMI BACK END DAI Link */
+	{
+		.name = LPASS_BE_HDMI,
+		.stream_name = "HDMI Playback",
+		.cpu_dai_name = "msm-dai-q6-hdmi.8",
+		.platform_name = "msm-pcm-routing",
+		.codec_name     = "msm-hdmi-audio-codec-rx",
+		.codec_dai_name = "msm_hdmi_audio_codec_rx_dai",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_HDMI_RX,
+		.be_hw_params_fixup = apq8074_hdmi_be_hw_params_fixup,
+		.ignore_pmdown_time = 1,
+		.ignore_suspend = 1,
+	},
+};
+
+static struct snd_soc_dai_link apq8074_dai_links[
+					 ARRAY_SIZE(apq8074_common_dai_links) +
+					 ARRAY_SIZE(apq8074_hdmi_dai_link)];
+
+struct snd_soc_card snd_soc_card_apq8074 = {
+	.name		= "apq8074-taiko-snd-card",
+};
+
+static int apq8074_dtparse_auxpcm(struct platform_device *pdev,
+				struct msm_auxpcm_ctrl **auxpcm_ctrl,
+				char *msm_auxpcm_gpio_name[][2])
+{
+	int ret = 0;
+	int i = 0;
+	struct msm_auxpcm_gpio *pin_data = NULL;
+	struct msm_auxpcm_ctrl *ctrl;
+	unsigned int gpio_no[NUM_OF_AUXPCM_GPIOS];
+	enum of_gpio_flags flags = OF_GPIO_ACTIVE_LOW;
+	int auxpcm_cnt = 0;
+
+	pin_data = devm_kzalloc(&pdev->dev, (ARRAY_SIZE(gpio_no) *
+				sizeof(struct msm_auxpcm_gpio)),
+				GFP_KERNEL);
+	if (!pin_data) {
+		dev_err(&pdev->dev, "No memory for gpio\n");
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(gpio_no); i++) {
+		gpio_no[i] = of_get_named_gpio_flags(pdev->dev.of_node,
+				msm_auxpcm_gpio_name[i][DT_PARSE_INDEX],
+				0, &flags);
+
+		if (gpio_no[i] > 0) {
+			pin_data[i].gpio_name =
+			     msm_auxpcm_gpio_name[auxpcm_cnt][GPIO_NAME_INDEX];
+			pin_data[i].gpio_no = gpio_no[i];
+			dev_dbg(&pdev->dev, "%s:GPIO gpio[%s] =\n"
+				"0x%x\n", __func__,
+				pin_data[i].gpio_name,
+				pin_data[i].gpio_no);
+			auxpcm_cnt++;
+		} else {
+			dev_err(&pdev->dev, "%s:Invalid AUXPCM GPIO[%s]= %x\n",
+				 __func__,
+				msm_auxpcm_gpio_name[i][GPIO_NAME_INDEX],
+				gpio_no[i]);
+			ret = -ENODEV;
+			goto err;
+		}
+	}
+
+	ctrl = devm_kzalloc(&pdev->dev,
+				sizeof(struct msm_auxpcm_ctrl), GFP_KERNEL);
+	if (!ctrl) {
+		dev_err(&pdev->dev, "No memory for gpio\n");
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	ctrl->pin_data = pin_data;
+	ctrl->cnt = auxpcm_cnt;
+	*auxpcm_ctrl = ctrl;
+	return ret;
+
+err:
+	if (pin_data)
+		devm_kfree(&pdev->dev, pin_data);
+	return ret;
+}
+
+static int apq8074_prepare_codec_mclk(struct snd_soc_card *card)
+{
+	struct apq8074_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
+	int ret;
+	if (pdata->mclk_gpio) {
+		ret = gpio_request(pdata->mclk_gpio, "TAIKO_CODEC_PMIC_MCLK");
+		if (ret) {
+			dev_err(card->dev,
+				"%s: Failed to request taiko mclk gpio %d\n",
+				__func__, pdata->mclk_gpio);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static int apq8074_prepare_us_euro(struct snd_soc_card *card)
+{
+	struct apq8074_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
+	int ret;
+	if (pdata->us_euro_gpio) {
+		dev_dbg(card->dev, "%s : us_euro gpio request %d", __func__,
+			pdata->us_euro_gpio);
+		ret = gpio_request(pdata->us_euro_gpio, "TAIKO_CODEC_US_EURO");
+		if (ret) {
+			dev_err(card->dev,
+				"%s: Failed to request taiko US/EURO gpio %d error %d\n",
+				__func__, pdata->us_euro_gpio, ret);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static __devinit int apq8074_asoc_machine_probe(struct platform_device *pdev)
+{
+	struct snd_soc_card *card = &snd_soc_card_apq8074;
+	struct apq8074_asoc_mach_data *pdata;
+	int ret;
+	const char *auxpcm_pri_gpio_set = NULL;
+
+	if (!pdev->dev.of_node) {
+		dev_err(&pdev->dev, "No platform supplied from device tree\n");
+		return -EINVAL;
+	}
+
+	pdata = devm_kzalloc(&pdev->dev,
+			sizeof(struct apq8074_asoc_mach_data), GFP_KERNEL);
+	if (!pdata) {
+		dev_err(&pdev->dev, "Can't allocate apq8074_asoc_mach_data\n");
+		return -ENOMEM;
+	}
+
+	/* Parse  AUXPCM info from DT */
+	ret = apq8074_dtparse_auxpcm(pdev, &pdata->pri_auxpcm_ctrl,
+					msm_prim_auxpcm_gpio_name);
+	if (ret) {
+		dev_err(&pdev->dev,
+		"%s: Auxpcm pin data parse failed\n", __func__);
+		goto err;
+	}
+
+	card->dev = &pdev->dev;
+	platform_set_drvdata(pdev, card);
+	snd_soc_card_set_drvdata(card, pdata);
+
+	ret = snd_soc_of_parse_card_name(card, "qcom,model");
+	if (ret)
+		goto err;
+
+	ret = snd_soc_of_parse_audio_routing(card,
+			"qcom,audio-routing");
+	if (ret)
+		goto err;
+
+	ret = of_property_read_u32(pdev->dev.of_node,
+			"qcom,taiko-mclk-clk-freq", &pdata->mclk_freq);
+	if (ret) {
+		dev_err(&pdev->dev, "Looking up %s property in node %s failed",
+			"qcom,taiko-mclk-clk-freq",
+			pdev->dev.of_node->full_name);
+		goto err;
+	}
+
+	if (pdata->mclk_freq != 9600000) {
+		dev_err(&pdev->dev, "unsupported taiko mclk freq %u\n",
+			pdata->mclk_freq);
+		ret = -EINVAL;
+		goto err;
+	}
+
+	pdata->mclk_gpio = of_get_named_gpio(pdev->dev.of_node,
+				"qcom,cdc-mclk-gpios", 0);
+	if (pdata->mclk_gpio < 0) {
+		dev_err(&pdev->dev,
+			"Looking up %s property in node %s failed %d\n",
+			"qcom, cdc-mclk-gpios", pdev->dev.of_node->full_name,
+			pdata->mclk_gpio);
+		ret = -ENODEV;
+		goto err;
+	}
+
+
+	ret = apq8074_prepare_codec_mclk(card);
+	if (ret)
+		goto err;
+
+	if (of_property_read_bool(pdev->dev.of_node, "qcom,hdmi-audio-rx")) {
+		dev_info(&pdev->dev, "%s(): hdmi audio support present\n",
+				__func__);
+
+		memcpy(apq8074_dai_links, apq8074_common_dai_links,
+			sizeof(apq8074_common_dai_links));
+
+		memcpy(apq8074_dai_links + ARRAY_SIZE(apq8074_common_dai_links),
+			apq8074_hdmi_dai_link, sizeof(apq8074_hdmi_dai_link));
+
+		card->dai_link	= apq8074_dai_links;
+		card->num_links	= ARRAY_SIZE(apq8074_dai_links);
+	} else {
+		dev_info(&pdev->dev, "%s(): No hdmi audio support\n", __func__);
+
+		card->dai_link	= apq8074_common_dai_links;
+		card->num_links	= ARRAY_SIZE(apq8074_common_dai_links);
+	}
+
+	pdata->us_euro_gpio = of_get_named_gpio(pdev->dev.of_node,
+				"qcom,us-euro-gpios", 0);
+	if (pdata->us_euro_gpio < 0) {
+		dev_err(&pdev->dev, "Looking up %s property in node %s failed",
+			"qcom,us-euro-gpios",
+			pdev->dev.of_node->full_name);
+	} else {
+		dev_dbg(&pdev->dev, "%s detected %d",
+			"qcom,us-euro-gpios", pdata->us_euro_gpio);
+		mbhc_cfg.swap_gnd_mic = apq8074_swap_gnd_mic;
+	}
+
+	ret = apq8074_prepare_us_euro(card);
+	if (ret)
+		dev_err(&pdev->dev, "apq8074_prepare_us_euro failed (%d)\n",
+			ret);
+
+	mutex_init(&cdc_mclk_mutex);
+	atomic_set(&prim_auxpcm_rsc_ref, 0);
+	spdev = pdev;
+	ext_spk_amp_regulator = NULL;
+	apq8074_liquid_dock_dev = NULL;
+
+	ret = snd_soc_register_card(card);
+	if (ret) {
+		dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n",
+			ret);
+		goto err;
+	}
+
+	ret = of_property_read_string(pdev->dev.of_node,
+			"qcom,prim-auxpcm-gpio-set", &auxpcm_pri_gpio_set);
+	if (ret) {
+		dev_err(&pdev->dev, "Looking up %s property in node %s failed",
+			"qcom,prim-auxpcm-gpio-set",
+			pdev->dev.of_node->full_name);
+		goto err;
+	}
+	if (!strcmp(auxpcm_pri_gpio_set, "prim-gpio-prim")) {
+		lpaif_pri_muxsel_virt_addr =
+				ioremap(LPAIF_PRI_MODE_MUXSEL, 4);
+	} else if (!strcmp(auxpcm_pri_gpio_set, "prim-gpio-tert")) {
+		lpaif_pri_muxsel_virt_addr =
+				ioremap(LPAIF_TER_MODE_MUXSEL, 4);
+	} else {
+		dev_err(&pdev->dev, "Invalid value %s for AUXPCM GPIO set\n",
+			auxpcm_pri_gpio_set);
+		ret = -EINVAL;
+		goto err;
+	}
+	if (lpaif_pri_muxsel_virt_addr == NULL) {
+		pr_err("%s Pri muxsel virt addr is null\n", __func__);
+		ret = -EINVAL;
+		goto err;
+	}
+	return 0;
+
+err:
+	if (pdata->mclk_gpio > 0) {
+		dev_dbg(&pdev->dev, "%s free gpio %d\n",
+			__func__, pdata->mclk_gpio);
+		gpio_free(pdata->mclk_gpio);
+		pdata->mclk_gpio = 0;
+	}
+	if (pdata->us_euro_gpio > 0) {
+		dev_dbg(&pdev->dev, "%s free us_euro gpio %d\n",
+			__func__, pdata->us_euro_gpio);
+		gpio_free(pdata->us_euro_gpio);
+		pdata->us_euro_gpio = 0;
+	}
+	devm_kfree(&pdev->dev, pdata);
+	return ret;
+}
+
+static int __devexit apq8074_asoc_machine_remove(struct platform_device *pdev)
+{
+	struct snd_soc_card *card = platform_get_drvdata(pdev);
+	struct apq8074_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
+
+	if (ext_spk_amp_regulator)
+		regulator_put(ext_spk_amp_regulator);
+
+	if (gpio_is_valid(ext_ult_spk_amp_gpio))
+		gpio_free(ext_ult_spk_amp_gpio);
+
+	gpio_free(pdata->mclk_gpio);
+	gpio_free(pdata->us_euro_gpio);
+	if (gpio_is_valid(ext_spk_amp_gpio))
+		gpio_free(ext_spk_amp_gpio);
+
+	if (apq8074_liquid_dock_dev != NULL) {
+		if (apq8074_liquid_dock_dev->dock_plug_gpio)
+			gpio_free(apq8074_liquid_dock_dev->dock_plug_gpio);
+
+		if (apq8074_liquid_dock_dev->dock_plug_irq)
+			free_irq(apq8074_liquid_dock_dev->dock_plug_irq,
+				 apq8074_liquid_dock_dev);
+
+		kfree(apq8074_liquid_dock_dev);
+		apq8074_liquid_dock_dev = NULL;
+	}
+
+	iounmap(lpaif_pri_muxsel_virt_addr);
+	snd_soc_unregister_card(card);
+
+	return 0;
+}
+
+static const struct of_device_id apq8074_asoc_machine_of_match[]  = {
+	{ .compatible = "qcom,apq8074-audio-taiko", },
+	{},
+};
+
+static struct platform_driver apq8074_asoc_machine_driver = {
+	.driver = {
+		.name = DRV_NAME,
+		.owner = THIS_MODULE,
+		.pm = &snd_soc_pm_ops,
+		.of_match_table = apq8074_asoc_machine_of_match,
+	},
+	.probe = apq8074_asoc_machine_probe,
+	.remove = __devexit_p(apq8074_asoc_machine_remove),
+};
+module_platform_driver(apq8074_asoc_machine_driver);
+
+MODULE_DESCRIPTION("ALSA SoC msm");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:" DRV_NAME);
+MODULE_DEVICE_TABLE(of, apq8074_asoc_machine_of_match);
diff --git a/sound/soc/msm/mdm9625.c b/sound/soc/msm/mdm9625.c
index f3ccb33..fd21c38 100644
--- a/sound/soc/msm/mdm9625.c
+++ b/sound/soc/msm/mdm9625.c
@@ -309,18 +309,18 @@
 			pr_err("set format for codec dai failed\n");
 			return ret;
 		}
-	}
-	/* This sets the CONFIG PARAMETER WS_SRC.
-	 * 1 means internal clock master mode.
-	 * 0 means external clock slave mode.
-	 */
-	ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_CBS_CFS);
-	if (ret < 0)
-		pr_err("set fmt cpu dai failed\n");
+		/* This sets the CONFIG PARAMETER WS_SRC.
+		 * 1 means internal clock master mode.
+		 * 0 means external clock slave mode.
+		 */
+		ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_CBS_CFS);
+		if (ret < 0)
+			pr_err("set fmt cpu dai failed\n");
 
-	ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_CBS_CFS);
-	if (ret < 0)
-		pr_err("set fmt for codec dai failed\n");
+		ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_CBS_CFS);
+		if (ret < 0)
+			pr_err("set fmt for codec dai failed\n");
+	}
 
 	return ret;
 }
diff --git a/sound/soc/msm/msm-compr-q6.c b/sound/soc/msm/msm-compr-q6.c
index e54f8b7..373090e 100644
--- a/sound/soc/msm/msm-compr-q6.c
+++ b/sound/soc/msm/msm-compr-q6.c
@@ -1302,7 +1302,7 @@
 			}
 			rc = wait_event_timeout(the_locks.flush_wait,
 				prtd->cmd_ack, 5 * HZ);
-			if (rc < 0)
+			if (!rc)
 				pr_err("Flush cmd timeout\n");
 			prtd->pcm_irq_pos = 0;
 		}
diff --git a/sound/soc/msm/msm-lowlatency-pcm-q6.c b/sound/soc/msm/msm-lowlatency-pcm-q6.c
index d5281e4..28e112c 100644
--- a/sound/soc/msm/msm-lowlatency-pcm-q6.c
+++ b/sound/soc/msm/msm-lowlatency-pcm-q6.c
@@ -434,7 +434,7 @@
 				__func__, atomic_read(&prtd->out_count));
 	ret = wait_event_timeout(the_locks.write_wait,
 			(atomic_read(&prtd->out_count)), 5 * HZ);
-	if (ret < 0) {
+	if (!ret) {
 		pr_err("%s: wait_event_timeout failed\n", __func__);
 		goto fail;
 	}
@@ -487,7 +487,7 @@
 	dir = IN;
 	ret = wait_event_timeout(the_locks.eos_wait,
 				prtd->cmd_ack, 5 * HZ);
-	if (ret < 0)
+	if (!ret)
 		pr_err("%s: CMD_EOS failed\n", __func__);
 	q6asm_cmd(prtd->audio_client, CMD_CLOSE);
 	q6asm_audio_client_buf_free_contiguous(dir,
@@ -525,7 +525,7 @@
 
 	ret = wait_event_timeout(the_locks.read_wait,
 			(atomic_read(&prtd->in_count)), 5 * HZ);
-	if (ret < 0) {
+	if (!ret) {
 		pr_debug("%s: wait_event_timeout failed\n", __func__);
 		goto fail;
 	}
diff --git a/sound/soc/msm/msm-multi-ch-pcm-q6.c b/sound/soc/msm/msm-multi-ch-pcm-q6.c
index 26bf3d9..d620099 100644
--- a/sound/soc/msm/msm-multi-ch-pcm-q6.c
+++ b/sound/soc/msm/msm-multi-ch-pcm-q6.c
@@ -537,7 +537,7 @@
 				__func__, atomic_read(&prtd->out_count));
 	ret = wait_event_timeout(the_locks.write_wait,
 			(atomic_read(&prtd->out_count)), 5 * HZ);
-	if (ret < 0) {
+	if (!ret) {
 		pr_err("%s: wait_event_timeout failed\n", __func__);
 		goto fail;
 	}
@@ -590,7 +590,7 @@
 	dir = IN;
 	ret = wait_event_timeout(the_locks.eos_wait,
 				prtd->cmd_ack, 5 * HZ);
-	if (ret < 0)
+	if (!ret)
 		pr_err("%s: CMD_EOS failed\n", __func__);
 	q6asm_cmd(prtd->audio_client, CMD_CLOSE);
 	q6asm_audio_client_buf_free_contiguous(dir,
@@ -629,7 +629,7 @@
 
 	ret = wait_event_timeout(the_locks.read_wait,
 			(atomic_read(&prtd->in_count)), 5 * HZ);
-	if (ret < 0) {
+	if (!ret) {
 		pr_debug("%s: wait_event_timeout failed\n", __func__);
 		goto fail;
 	}
diff --git a/sound/soc/msm/msm-pcm-lpa.c b/sound/soc/msm/msm-pcm-lpa.c
index 95c5cd7..bfab124 100644
--- a/sound/soc/msm/msm-pcm-lpa.c
+++ b/sound/soc/msm/msm-pcm-lpa.c
@@ -382,7 +382,7 @@
 		pr_debug("%s\n", __func__);
 		rc = wait_event_timeout(the_locks.eos_wait,
 			prtd->cmd_ack, 5 * HZ);
-		if (rc < 0)
+		if (!rc)
 			pr_err("EOS cmd timeout\n");
 		prtd->pcm_irq_pos = 0;
 	}
@@ -537,7 +537,7 @@
 			pr_err("%s: flush cmd failed rc=%d\n", __func__, rc);
 		rc = wait_event_timeout(the_locks.eos_wait,
 			prtd->cmd_ack, 5 * HZ);
-		if (rc < 0)
+		if (!rc)
 			pr_err("Flush cmd timeout\n");
 		prtd->pcm_irq_pos = 0;
 		break;
diff --git a/sound/soc/msm/msm-pcm-q6.c b/sound/soc/msm/msm-pcm-q6.c
index 1d15c11..c37e932 100644
--- a/sound/soc/msm/msm-pcm-q6.c
+++ b/sound/soc/msm/msm-pcm-q6.c
@@ -419,7 +419,7 @@
 				__func__, atomic_read(&prtd->out_count));
 	ret = wait_event_timeout(the_locks.write_wait,
 			(atomic_read(&prtd->out_count)), 5 * HZ);
-	if (ret < 0) {
+	if (!ret) {
 		pr_err("%s: wait_event_timeout failed\n", __func__);
 		goto fail;
 	}
@@ -472,7 +472,7 @@
 	dir = IN;
 	ret = wait_event_timeout(the_locks.eos_wait,
 				prtd->cmd_ack, 5 * HZ);
-	if (ret < 0)
+	if (!ret)
 		pr_err("%s: CMD_EOS failed\n", __func__);
 	q6asm_cmd(prtd->audio_client, CMD_CLOSE);
 	q6asm_audio_client_buf_free_contiguous(dir,
@@ -510,7 +510,7 @@
 
 	ret = wait_event_timeout(the_locks.read_wait,
 			(atomic_read(&prtd->in_count)), 5 * HZ);
-	if (ret < 0) {
+	if (!ret) {
 		pr_debug("%s: wait_event_timeout failed\n", __func__);
 		goto fail;
 	}
diff --git a/sound/soc/msm/msm8226.c b/sound/soc/msm/msm8226.c
index 86e3d75..1d3779f 100644
--- a/sound/soc/msm/msm8226.c
+++ b/sound/soc/msm/msm8226.c
@@ -72,6 +72,7 @@
 	.gpio_irq = 0,
 	.gpio_level_insert = 0,
 	.detect_extn_cable = true,
+	.micbias_enable_flags = 0,
 	.insert_detect = true,
 	.swap_gnd_mic = NULL,
 };
@@ -90,6 +91,7 @@
 	int mclk_gpio;
 	u32 mclk_freq;
 	struct msm_auxpcm_ctrl *auxpcm_ctrl;
+	u32 us_euro_gpio;
 };
 
 #define GPIO_NAME_INDEX 0
@@ -638,7 +640,7 @@
 #undef S
 #define S(X, Y) ((WCD9XXX_MBHC_CAL_PLUG_TYPE_PTR(tapan_cal)->X) = (Y))
 	S(v_no_mic, 30);
-	S(v_hs_max, 1650);
+	S(v_hs_max, 2450);
 #undef S
 #define S(X, Y) ((WCD9XXX_MBHC_CAL_BTN_DET_PTR(tapan_cal)->X) = (Y))
 	S(c[0], 62);
@@ -1352,6 +1354,44 @@
 	return 0;
 }
 
+static bool msm8226_swap_gnd_mic(struct snd_soc_codec *codec)
+{
+	struct snd_soc_card *card = codec->card;
+	struct msm8226_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
+	int value = gpio_get_value_cansleep(pdata->us_euro_gpio);
+
+	pr_debug("%s: swap select switch %d to %d\n", __func__, value, !value);
+	gpio_direction_output(pdata->us_euro_gpio, !value);
+
+	return true;
+}
+
+static int msm8226_setup_hs_jack(struct platform_device *pdev,
+		struct msm8226_asoc_mach_data *pdata)
+{
+	int rc;
+
+	pdata->us_euro_gpio = of_get_named_gpio(pdev->dev.of_node,
+				"qcom,cdc-us-euro-gpios", 0);
+	if (pdata->us_euro_gpio < 0) {
+		dev_info(&pdev->dev,
+			"property %s in node %s not found %d\n",
+			"qcom,cdc-us-euro-gpios", pdev->dev.of_node->full_name,
+			pdata->us_euro_gpio);
+	} else {
+		rc = gpio_request(pdata->us_euro_gpio,
+						  "TAPAN_CODEC_US_EURO_GPIO");
+		if (rc) {
+			dev_err(&pdev->dev,
+				"%s: Failed to request tapan us-euro gpio %d\n",
+				__func__, pdata->us_euro_gpio);
+		} else {
+			mbhc_cfg.swap_gnd_mic = msm8226_swap_gnd_mic;
+		}
+	}
+	return 0;
+}
+
 static __devinit int msm8226_asoc_machine_probe(struct platform_device *pdev)
 {
 	struct snd_soc_card *card = &snd_soc_card_msm8226;
@@ -1441,6 +1481,7 @@
 
 	mbhc_cfg.gpio_level_insert = of_property_read_bool(pdev->dev.of_node,
 					"qcom,headset-jack-type-NO");
+	msm8226_setup_hs_jack(pdev, pdata);
 
 	ret = msm8226_prepare_codec_mclk(card);
 	if (ret)
@@ -1504,6 +1545,9 @@
 
 	gpio_free(pdata->mclk_gpio);
 	gpio_free(vdd_spkr_gpio);
+	if (pdata->us_euro_gpio > 0)
+		gpio_free(pdata->us_euro_gpio);
+
 	vdd_spkr_gpio = -1;
 	snd_soc_unregister_card(card);
 
diff --git a/sound/soc/msm/msm8974.c b/sound/soc/msm/msm8974.c
index ae92ca4..5d9aa53 100644
--- a/sound/soc/msm/msm8974.c
+++ b/sound/soc/msm/msm8974.c
@@ -124,6 +124,7 @@
 	.gpio_irq = 0,
 	.gpio_level_insert = 1,
 	.detect_extn_cable = true,
+	.micbias_enable_flags = 1 << MBHC_MICBIAS_ENABLE_THRESHOLD_HEADSET,
 	.insert_detect = true,
 	.swap_gnd_mic = NULL,
 };
diff --git a/sound/soc/msm/msm8x10.c b/sound/soc/msm/msm8x10.c
index 4db3ea5..96f78d9 100644
--- a/sound/soc/msm/msm8x10.c
+++ b/sound/soc/msm/msm8x10.c
@@ -38,6 +38,7 @@
 static int msm_btsco_ch = 1;
 
 static int msm_proxy_rx_ch = 2;
+static struct snd_soc_jack hs_jack;
 
 #define MSM8X10_DINO_LPASS_AUDIO_CORE_DIG_CODEC_CLK_SEL	0xFE03B004
 #define MSM8X10_DINO_LPASS_DIGCODEC_CMD_RCGR			0xFE02C000
@@ -386,6 +387,15 @@
 	snd_soc_dapm_sync(dapm);
 	ret =  msm_enable_mclk_root(AFE_PORT_ID_SECONDARY_MI2S_RX,
 				    &digital_cdc_clk);
+
+	ret = snd_soc_jack_new(codec, "Headset Jack",
+			SND_JACK_HEADSET, &hs_jack);
+
+	if (ret) {
+		pr_err("%s: Failed to create headset jack\n", __func__);
+		return ret;
+	}
+
 exit:
 	return ret;
 }
@@ -613,6 +623,21 @@
 		.ignore_pmdown_time = 1,
 		.be_id = MSM_FRONTEND_DAI_MULTIMEDIA5,
 	},
+	{/* hw:x,13 */
+		.name = "Voice2",
+		.stream_name = "Voice2",
+		.cpu_dai_name   = "Voice2",
+		.platform_name  = "msm-pcm-voice",
+		.dynamic = 1,
+		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
+			    SND_SOC_DPCM_TRIGGER_POST},
+		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+		.ignore_suspend = 1,
+		/* this dainlink has playback support */
+		.ignore_pmdown_time = 1,
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.codec_name = "snd-soc-dummy",
+	},
 	/* Backend I2S DAI Links */
 	{
 		.name = LPASS_BE_SEC_MI2S_RX,
@@ -637,7 +662,6 @@
 		.codec_dai_name = "msm8x10_wcd_i2s_tx1",
 		.no_pcm = 1,
 		.be_id = MSM_BACKEND_DAI_PRI_MI2S_TX,
-		.init = &msm_audrx_init,
 		.be_hw_params_fixup = msm_be_hw_params_fixup,
 		.ops = &msm8x10_mi2s_be_ops,
 		.ignore_suspend = 1,
diff --git a/sound/soc/msm/qdsp6/q6afe.c b/sound/soc/msm/qdsp6/q6afe.c
index 9558fa4..c4851f3 100644
--- a/sound/soc/msm/qdsp6/q6afe.c
+++ b/sound/soc/msm/qdsp6/q6afe.c
@@ -840,7 +840,7 @@
 	ret = wait_event_timeout(this_afe.wait,
 		(atomic_read(&this_afe.state) == 0),
 			msecs_to_jiffies(TIMEOUT_MS));
-	if (ret < 0) {
+	if (!ret) {
 		pr_err("%s: wait_event timeout\n", __func__);
 		ret = -EINVAL;
 		goto fail_cmd;
@@ -918,7 +918,7 @@
 	ret = wait_event_timeout(this_afe.wait,
 		(atomic_read(&this_afe.state) == 0),
 			msecs_to_jiffies(TIMEOUT_MS));
-	if (ret < 0) {
+	if (!ret) {
 		pr_err("%s: wait_event timeout\n", __func__);
 		ret = -EINVAL;
 		goto fail_cmd;
@@ -979,7 +979,7 @@
 	ret = wait_event_timeout(this_afe.wait,
 		(atomic_read(&this_afe.state) == 0),
 			msecs_to_jiffies(TIMEOUT_MS));
-	if (ret < 0) {
+	if (!ret) {
 		pr_err("%s: wait_event timeout\n", __func__);
 		ret = -EINVAL;
 		goto fail_cmd;
@@ -1731,7 +1731,7 @@
 	ret = wait_event_timeout(this_afe.wait,
 		(atomic_read(&this_afe.state) == 0),
 			msecs_to_jiffies(TIMEOUT_MS));
-	if (ret < 0) {
+	if (!ret) {
 		pr_err("%s: wait_event timeout\n", __func__);
 		ret = -EINVAL;
 		goto fail_cmd;
diff --git a/sound/soc/msm/qdsp6/q6voice.c b/sound/soc/msm/qdsp6/q6voice.c
index bb13695..60f4669 100644
--- a/sound/soc/msm/qdsp6/q6voice.c
+++ b/sound/soc/msm/qdsp6/q6voice.c
@@ -1058,7 +1058,9 @@
 	}
 	/* Set encoder properties. */
 	switch (common.mvs_info.media_type) {
-	case VSS_MEDIA_ID_EVRC_MODEM: {
+	case VSS_MEDIA_ID_EVRC_MODEM:
+	case VSS_MEDIA_ID_4GV_NB_MODEM:
+	case VSS_MEDIA_ID_4GV_WB_MODEM: {
 		struct cvs_set_cdma_enc_minmax_rate_cmd cvs_set_cdma_rate;
 
 		pr_debug("Setting EVRC min-max rate\n");
diff --git a/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c
index 620f667..a1c1aef 100644
--- a/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c
@@ -125,7 +125,6 @@
 	int i = 0;
 	int time_stamp_flag = 0;
 	int buffer_length = 0;
-	int stop_playback = 0;
 
 	pr_debug("%s opcode =%08x\n", __func__, opcode);
 	switch (opcode) {
@@ -150,15 +149,9 @@
 		/*
 		 * check for underrun
 		 */
-		snd_pcm_stream_lock_irq(substream);
-		if (snd_pcm_playback_empty(substream)) {
+		if (runtime->status->hw_ptr >= runtime->control->appl_ptr) {
+			pr_err("render stopped");
 			runtime->render_flag |= SNDRV_RENDER_STOPPED;
-			stop_playback = 1;
-		}
-		snd_pcm_stream_unlock_irq(substream);
-
-		if (stop_playback) {
-			pr_err("%s empty buffer, stop writes\n", __func__);
 			break;
 		}
 
@@ -493,15 +486,6 @@
 	switch (cmd) {
 	case SNDRV_PCM_TRIGGER_START:
 		prtd->pcm_irq_pos = 0;
-		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-			if (!atomic_cmpxchg(&compressed_audio.audio_ocmem_req,
-									0, 1))
-				audio_ocmem_process_req(AUDIO, true);
-			else
-				atomic_inc(&compressed_audio.audio_ocmem_req);
-			pr_debug("%s: req: %d\n", __func__,
-			atomic_read(&compressed_audio.audio_ocmem_req));
-		}
 
 		if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
 			switch (compr->info.codec_param.codec.id) {
@@ -624,17 +608,32 @@
 	runtime->private_data = compr;
 	atomic_set(&prtd->eos, 0);
 	compressed_audio.prtd =  &compr->prtd;
-
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		if (!atomic_cmpxchg(&compressed_audio.audio_ocmem_req, 0, 1))
+			audio_ocmem_process_req(AUDIO, true);
+		else
+			atomic_inc(&compressed_audio.audio_ocmem_req);
+		pr_debug("%s: req: %d\n", __func__,
+			atomic_read(&compressed_audio.audio_ocmem_req));
+	}
 	return 0;
 }
 
 int compressed_set_volume(unsigned volume)
 {
 	int rc = 0;
+	int avg_vol = 0;
 	if (compressed_audio.prtd && compressed_audio.prtd->audio_client) {
-		rc = q6asm_set_lrgain(compressed_audio.prtd->audio_client,
-						(volume >> 16) & 0xFFFF,
-						volume & 0xFFFF);
+		if (compressed_audio.prtd->channel_mode > 2) {
+			avg_vol = (((volume >> 16) & 0xFFFF) +
+				   (volume & 0xFFFF)) / 2;
+			rc = q6asm_set_volume(
+				compressed_audio.prtd->audio_client, avg_vol);
+		} else {
+			rc = q6asm_set_lrgain(
+				compressed_audio.prtd->audio_client,
+				(volume >> 16) & 0xFFFF, volume & 0xFFFF);
+		}
 		if (rc < 0) {
 			pr_err("%s: Send Volume command failed rc=%d\n",
 						__func__, rc);
@@ -742,9 +741,17 @@
 	struct msm_audio *prtd = runtime->private_data;
 	struct audio_client *ac = prtd->audio_client;
 	struct audio_port_data *apd = ac->port;
-	struct audio_buffer *ab = &(apd[IN].buf[0]);
+	struct audio_buffer *ab;
+	int dir = -1;
+
 	prtd->mmap_flag = 1;
 
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		dir = IN;
+	else
+		dir = OUT;
+	ab = &(apd[dir].buf[0]);
+
 	return msm_audio_ion_mmap(ab, vma);
 }
 
@@ -794,6 +801,11 @@
 			prtd->audio_client->perf_mode,
 			prtd->session_id,
 			substream->stream);
+		/* the number of channels are required to call volume api
+		   accoridngly. So, get channels from hw params */
+		if ((params_channels(params) > 0) &&
+		    (params_periods(params) <= runtime->hw.channels_max))
+			prtd->channel_mode = params_channels(params);
 
 		ret = compressed_set_volume(0);
 		if (ret < 0)
@@ -1047,7 +1059,7 @@
 			}
 			rc = wait_event_timeout(the_locks.flush_wait,
 				prtd->cmd_ack, 5 * HZ);
-			if (rc < 0)
+			if (!rc)
 				pr_err("Flush cmd timeout\n");
 			prtd->pcm_irq_pos = 0;
 		}
diff --git a/sound/soc/msm/qdsp6v2/msm-dolby-dap-config.c b/sound/soc/msm/qdsp6v2/msm-dolby-dap-config.c
index e6934f6..9ace410 100644
--- a/sound/soc/msm/qdsp6v2/msm-dolby-dap-config.c
+++ b/sound/soc/msm/qdsp6v2/msm-dolby-dap-config.c
@@ -641,7 +641,7 @@
 		DOLBY_PARAM_PAYLOAD_SIZE * sizeof(uint32_t);
 	int port_id = dolby_dap_params_states.port_id;
 	if (port_id == DOLBY_INVALID_PORT_ID) {
-		pr_err("%s, port_id not set, returning error", __func__);
+		pr_debug("%s, port_id not set, returning error", __func__);
 		ucontrol->value.integer.value[0] = 0;
 		return -EINVAL;
 	}
diff --git a/sound/soc/msm/qdsp6v2/msm-multi-ch-pcm-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-multi-ch-pcm-q6-v2.c
index a078042..4297ddb 100644
--- a/sound/soc/msm/qdsp6v2/msm-multi-ch-pcm-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-multi-ch-pcm-q6-v2.c
@@ -454,7 +454,7 @@
 				__func__, atomic_read(&prtd->out_count));
 	ret = wait_event_timeout(the_locks.write_wait,
 			(atomic_read(&prtd->out_count)), 5 * HZ);
-	if (ret < 0) {
+	if (!ret) {
 		pr_err("%s: wait_event_timeout failed\n", __func__);
 		goto fail;
 	}
@@ -507,7 +507,7 @@
 	dir = IN;
 	ret = wait_event_timeout(the_locks.eos_wait,
 				prtd->cmd_ack, 5 * HZ);
-	if (ret < 0)
+	if (!ret)
 		pr_err("%s: CMD_EOS failed\n", __func__);
 	q6asm_cmd(prtd->audio_client, CMD_CLOSE);
 	q6asm_audio_client_buf_free_contiguous(dir,
@@ -546,7 +546,7 @@
 
 	ret = wait_event_timeout(the_locks.read_wait,
 			(atomic_read(&prtd->in_count)), 5 * HZ);
-	if (ret < 0) {
+	if (!ret) {
 		pr_debug("%s: wait_event_timeout failed\n", __func__);
 		goto fail;
 	}
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-afe-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-afe-v2.c
index 2a64ae2..c4b44fe 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-afe-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-afe-v2.c
@@ -20,6 +20,7 @@
 #include <linux/platform_device.h>
 #include <linux/slab.h>
 #include <linux/dma-mapping.h>
+#include <linux/msm_audio_ion.h>
 
 #include <sound/core.h>
 #include <sound/soc.h>
@@ -517,21 +518,21 @@
 {
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct pcm_afe_info *prtd = runtime->private_data;
-	int result = 0;
+	struct afe_audio_client *ac = prtd->audio_client;
+	struct afe_audio_port_data *apd = ac->port;
+	struct afe_audio_buffer *ab;
+	int dir = -1;
 
 	pr_debug("%s\n", __func__);
 	prtd->mmap_flag = 1;
-	if (runtime->dma_addr && runtime->dma_bytes) {
-		vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
-		result = remap_pfn_range(vma, vma->vm_start,
-				runtime->dma_addr >> PAGE_SHIFT,
-				runtime->dma_bytes,
-				vma->vm_page_prot);
-	} else {
-		pr_err("Physical address or size of buf is NULL");
-		return -EINVAL;
-	}
-	return result;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		dir = IN;
+	else
+		dir = OUT;
+	ab = &(apd[dir].buf[0]);
+
+	return msm_audio_ion_mmap((struct audio_buffer *)ab, vma);
 }
 static int msm_afe_trigger(struct snd_pcm_substream *substream, int cmd)
 {
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-lpa-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-lpa-v2.c
index 7055c57..4459bc8 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-lpa-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-lpa-v2.c
@@ -364,7 +364,7 @@
 		pr_debug("%s\n", __func__);
 		rc = wait_event_timeout(the_locks.eos_wait,
 			prtd->cmd_ack, 5 * HZ);
-		if (rc < 0)
+		if (!rc)
 			pr_err("EOS cmd timeout\n");
 		prtd->pcm_irq_pos = 0;
 	}
@@ -427,9 +427,17 @@
 	struct msm_audio *prtd = runtime->private_data;
 	struct audio_client *ac = prtd->audio_client;
 	struct audio_port_data *apd = ac->port;
-	struct audio_buffer *ab = &(apd[IN].buf[0]);
+	struct audio_buffer *ab;
+	int dir = -1;
+
 	prtd->mmap_flag = 1;
 
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		dir = IN;
+	else
+		dir = OUT;
+	ab = &(apd[dir].buf[0]);
+
 	return msm_audio_ion_mmap(ab, vma);
 }
 
@@ -565,7 +573,7 @@
 			pr_err("%s: flush cmd failed rc=%d\n", __func__, rc);
 		rc = wait_event_timeout(the_locks.eos_wait,
 			prtd->cmd_ack, 5 * HZ);
-		if (rc < 0)
+		if (!rc)
 			pr_err("Flush cmd timeout\n");
 		prtd->pcm_irq_pos = 0;
 		break;
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
index f4ca5b8..0ae393c 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
@@ -410,7 +410,7 @@
 				__func__, atomic_read(&prtd->out_count));
 	ret = wait_event_timeout(the_locks.write_wait,
 			(atomic_read(&prtd->out_count)), 5 * HZ);
-	if (ret < 0) {
+	if (!ret) {
 		pr_err("%s: wait_event_timeout failed\n", __func__);
 		goto fail;
 	}
@@ -470,7 +470,7 @@
 		dir = IN;
 		ret = wait_event_timeout(the_locks.eos_wait,
 					prtd->cmd_ack, 5 * HZ);
-		if (ret < 0)
+		if (!ret)
 			pr_err("%s: CMD_EOS failed\n", __func__);
 		q6asm_cmd(prtd->audio_client, CMD_CLOSE);
 		q6asm_audio_client_buf_free_contiguous(dir,
@@ -509,7 +509,7 @@
 
 	ret = wait_event_timeout(the_locks.read_wait,
 			(atomic_read(&prtd->in_count)), 5 * HZ);
-	if (ret < 0) {
+	if (!ret) {
 		pr_debug("%s: wait_event_timeout failed\n", __func__);
 		goto fail;
 	}
@@ -633,9 +633,17 @@
 	struct msm_audio *prtd = runtime->private_data;
 	struct audio_client *ac = prtd->audio_client;
 	struct audio_port_data *apd = ac->port;
-	struct audio_buffer *ab = &(apd[IN].buf[0]);
+	struct audio_buffer *ab;
+	int dir = -1;
+
 	prtd->mmap_flag = 1;
 
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		dir = IN;
+	else
+		dir = OUT;
+	ab = &(apd[dir].buf[0]);
+
 	return msm_audio_ion_mmap(ab, vma);
 }
 
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
index 500a467..997946d 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
@@ -58,6 +58,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 */
 
 enum {
 	MADNONE,
@@ -385,6 +386,10 @@
 			else if (msm_bedais[i].format ==
 						SNDRV_PCM_FORMAT_S24_LE)
 				bits_per_sample = 24;
+
+			if (msm_bedais[i].port_id == VOICE_RECORD_RX ||
+			    msm_bedais[i].port_id == VOICE_RECORD_TX)
+				topology = DEFAULT_COPP_TOPOLOGY;
 			if ((stream_type == SNDRV_PCM_STREAM_PLAYBACK) &&
 				(channels > 0))
 				adm_multi_ch_copp_open(msm_bedais[i].port_id,
@@ -406,7 +411,8 @@
 				msm_bedais[i].port_id;
 			port_id = srs_port_id = msm_bedais[i].port_id;
 			srs_send_params(srs_port_id, 1, 0);
-			if (DOLBY_ADM_COPP_TOPOLOGY_ID == topology)
+			if ((DOLBY_ADM_COPP_TOPOLOGY_ID == topology) &&
+			    (!perf_mode))
 				if (dolby_dap_init(port_id,
 						msm_bedais[i].channel) < 0)
 					pr_err("%s: Err init dolby dap\n",
@@ -449,7 +455,8 @@
 		   (test_bit(fedai_id, &msm_bedais[i].fe_sessions))) {
 			adm_close(msm_bedais[i].port_id,
 				test_bit(fedai_id, &msm_bedais[i].perf_mode));
-			if (DOLBY_ADM_COPP_TOPOLOGY_ID == topology)
+			if ((DOLBY_ADM_COPP_TOPOLOGY_ID == topology) &&
+			    (!test_bit(fedai_id, &msm_bedais[i].perf_mode)))
 				dolby_dap_deinit(msm_bedais[i].port_id);
 		}
 	}
@@ -514,6 +521,10 @@
 			if (msm_bedais[reg].format == SNDRV_PCM_FORMAT_S24_LE)
 				bits_per_sample = 24;
 
+			if (msm_bedais[reg].port_id == VOICE_RECORD_RX ||
+			    msm_bedais[reg].port_id == VOICE_RECORD_TX)
+				topology = DEFAULT_COPP_TOPOLOGY;
+
 			if ((session_type == SESSION_TYPE_RX) &&
 				(channels > 0)) {
 				perf_mode = test_bit(val,
@@ -536,7 +547,8 @@
 				perf_mode);
 			port_id = srs_port_id = msm_bedais[reg].port_id;
 			srs_send_params(srs_port_id, 1, 0);
-			if (DOLBY_ADM_COPP_TOPOLOGY_ID == topology)
+			if ((DOLBY_ADM_COPP_TOPOLOGY_ID == topology) &&
+			    (!perf_mode))
 				if (dolby_dap_init(port_id, channels) < 0)
 					pr_err("%s: Err init dolby dap\n",
 						__func__);
@@ -550,7 +562,8 @@
 			INVALID_SESSION) {
 			perf_mode = test_bit(val, &msm_bedais[reg].perf_mode);
 			adm_close(msm_bedais[reg].port_id, perf_mode);
-			if (DOLBY_ADM_COPP_TOPOLOGY_ID == topology)
+			if ((DOLBY_ADM_COPP_TOPOLOGY_ID == topology) &&
+			    (!perf_mode))
 				dolby_dap_deinit(msm_bedais[reg].port_id);
 			msm_pcm_routing_build_matrix(val,
 				fe_dai_map[val][session_type], path_type,
@@ -1335,6 +1348,51 @@
 	return 0;
 }
 
+static int msm_routing_ec_ref_rx_get(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	pr_debug("%s: ec_ref_rx  = %d", __func__, msm_route_ec_ref_rx);
+	ucontrol->value.integer.value[0] = msm_route_ec_ref_rx;
+	return 0;
+}
+
+static int msm_routing_ec_ref_rx_put(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	int ec_ref_port_id;
+	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;
+		break;
+	case 1:
+		msm_route_ec_ref_rx = 1;
+		ec_ref_port_id = PRIMARY_I2S_RX;
+		break;
+	default:
+		msm_route_ec_ref_rx = 3; /* NONE */
+		ec_ref_port_id = -1;
+		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);
+	return 0;
+}
+
+static const char *const ec_ref_rx[] = { "SLIM_RX", "I2S_RX", "PROXY_RX",
+	"NONE" };
+static const struct soc_enum msm_route_ec_ref_rx_enum[] = {
+	SOC_ENUM_SINGLE_EXT(4, 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 pri_i2s_rx_mixer_controls[] = {
 	SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_PRI_I2S_RX ,
 	MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
@@ -1885,6 +1943,9 @@
 	SOC_SINGLE_EXT("Voip", MSM_BACKEND_DAI_SLIMBUS_0_RX ,
 	MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer,
 	msm_routing_put_voice_mixer),
+	SOC_SINGLE_EXT("Voice Stub", MSM_BACKEND_DAI_SLIMBUS_0_RX,
+	MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+	msm_routing_put_voice_stub_mixer),
 	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),
@@ -2149,6 +2210,15 @@
 	SOC_SINGLE_EXT("MI2S_TX", MSM_BACKEND_DAI_MI2S_TX,
 	MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
 	msm_routing_put_voice_stub_mixer),
+	SOC_SINGLE_EXT("AUX_PCM_UL_TX", MSM_BACKEND_DAI_AUXPCM_TX,
+	MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+	msm_routing_put_voice_stub_mixer),
+	SOC_SINGLE_EXT("SEC_AUX_PCM_UL_TX", MSM_BACKEND_DAI_SEC_AUXPCM_TX,
+	MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+	msm_routing_put_voice_stub_mixer),
+	SOC_SINGLE_EXT("SLIM_0_TX", MSM_BACKEND_DAI_SLIMBUS_0_TX,
+	MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+	msm_routing_put_voice_stub_mixer),
 };
 
 static const struct snd_kcontrol_new sbus_0_rx_port_mixer_controls[] = {
@@ -2167,6 +2237,9 @@
 	SOC_SINGLE_EXT("MI2S_TX", MSM_BACKEND_DAI_SLIMBUS_0_RX,
 	MSM_BACKEND_DAI_MI2S_TX, 1, 0, msm_routing_get_port_mixer,
 	msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX", MSM_BACKEND_DAI_SLIMBUS_0_RX,
+	MSM_BACKEND_DAI_INT_BT_SCO_TX, 1, 0, msm_routing_get_port_mixer,
+	msm_routing_put_port_mixer),
 };
 
 static const struct snd_kcontrol_new auxpcm_rx_port_mixer_controls[] = {
@@ -2205,6 +2278,9 @@
 	SOC_SINGLE_EXT("SLIM_1_TX", MSM_BACKEND_DAI_INT_BT_SCO_RX,
 	MSM_BACKEND_DAI_SLIMBUS_1_TX, 1, 0, msm_routing_get_port_mixer,
 	msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("SLIM_0_TX", MSM_BACKEND_DAI_INT_BT_SCO_RX,
+	MSM_BACKEND_DAI_SLIMBUS_0_TX, 1, 0, msm_routing_get_port_mixer,
+	msm_routing_put_port_mixer),
 };
 
 static const struct snd_kcontrol_new afe_pcm_rx_port_mixer_controls[] = {
@@ -3180,6 +3256,7 @@
 	{"SLIM_0_RX_Voice Mixer", "VoLTE", "VoLTE_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"},
 	{"SLIMBUS_0_RX", NULL, "SLIM_0_RX_Voice Mixer"},
 
 	{"INTERNAL_BT_SCO_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
@@ -3201,12 +3278,14 @@
 	{"AUX_PCM_RX_Voice Mixer", "VoLTE", "VoLTE_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"},
 	{"AUX_PCM_RX", NULL, "AUX_PCM_RX_Voice Mixer"},
 
 	{"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", "Voip", "VOIP_DL"},
 	{"SEC_AUX_PCM_RX_Voice Mixer", "DTMF", "DTMF_DL_HL"},
+	{"SEC_AUX_PCM_RX_Voice Mixer", "Voice Stub", "VOICE_STUB_DL"},
 	{"SEC_AUX_PCM_RX", NULL, "SEC_AUX_PCM_RX_Voice Mixer"},
 
 	{"HDMI_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
@@ -3298,6 +3377,7 @@
 	{"SLIMBUS_0_RX Port Mixer", "AUX_PCM_UL_TX", "AUX_PCM_TX"},
 	{"SLIMBUS_0_RX Port Mixer", "SEC_AUX_PCM_UL_TX", "SEC_AUX_PCM_TX"},
 	{"SLIMBUS_0_RX Port Mixer", "MI2S_TX", "MI2S_TX"},
+	{"SLIMBUS_0_RX Port Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
 	{"SLIMBUS_0_RX", NULL, "SLIMBUS_0_RX Port Mixer"},
 	{"AFE_PCM_RX Port Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
 	{"PCM_RX", NULL, "AFE_PCM_RX Port Mixer"},
@@ -3314,7 +3394,10 @@
 	{"Voice Stub Tx Mixer", "SLIM_1_TX", "SLIMBUS_1_TX"},
 	{"Voice Stub Tx Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
 	{"Voice Stub Tx Mixer", "STUB_1_TX_HL", "STUB_1_TX"},
+	{"Voice Stub Tx Mixer", "AUX_PCM_UL_TX", "AUX_PCM_TX"},
+	{"Voice Stub Tx Mixer", "SEC_AUX_PCM_UL_TX", "SEC_AUX_PCM_TX"},
 	{"Voice Stub Tx Mixer", "MI2S_TX", "MI2S_TX"},
+	{"Voice Stub Tx Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
 	{"VOICE_STUB_UL", NULL, "Voice Stub Tx Mixer"},
 
 	{"STUB_RX Mixer", "Voice Stub", "VOICE_STUB_DL"},
@@ -3328,6 +3411,7 @@
 	{"SLIMBUS_1_RX Port Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
 	{"SLIMBUS_1_RX", NULL, "SLIMBUS_1_RX Port Mixer"},
 	{"INTERNAL_BT_SCO_RX Port Mixer", "SLIM_1_TX", "SLIMBUS_1_TX"},
+	{"INTERNAL_BT_SCO_RX Port Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
 	{"INT_BT_SCO_RX", NULL, "INTERNAL_BT_SCO_RX Port Mixer"},
 	{"SLIMBUS_3_RX Port Mixer", "INTERNAL_BT_SCO_RX", "INT_BT_SCO_RX"},
 	{"SLIMBUS_3_RX Port Mixer", "MI2S_TX", "MI2S_TX"},
@@ -3443,9 +3527,10 @@
 			adm_close(bedai->port_id,
 				test_bit(i, &(bedai->perf_mode)));
 			srs_port_id = -1;
-			clear_bit(i, &(bedai->perf_mode));
-			if (DOLBY_ADM_COPP_TOPOLOGY_ID == topology)
+			if ((DOLBY_ADM_COPP_TOPOLOGY_ID == topology) &&
+			    (!test_bit(i, &(bedai->perf_mode))))
 				dolby_dap_deinit(bedai->port_id);
+			clear_bit(i, &(bedai->perf_mode));
 		}
 	}
 
@@ -3504,6 +3589,10 @@
 			if (bedai->format == SNDRV_PCM_FORMAT_S24_LE)
 				bits_per_sample = 24;
 
+			if (bedai->port_id == VOICE_RECORD_RX ||
+			    bedai->port_id == VOICE_RECORD_TX)
+				topology = DEFAULT_COPP_TOPOLOGY;
+
 			if ((playback) && (channels > 0)) {
 				perf_mode = test_bit(i, &(bedai->perf_mode));
 				adm_multi_ch_copp_open(bedai->port_id,
@@ -3527,7 +3616,8 @@
 				perf_mode);
 			port_id = srs_port_id = bedai->port_id;
 			srs_send_params(srs_port_id, 1, 0);
-			if (DOLBY_ADM_COPP_TOPOLOGY_ID == topology)
+			if ((DOLBY_ADM_COPP_TOPOLOGY_ID == topology) &&
+			    (!perf_mode))
 				if (dolby_dap_init(port_id, channels) < 0)
 					pr_err("%s: Err init dolby dap\n",
 						__func__);
@@ -3646,6 +3736,9 @@
 				dolby_dap_param_end_point_controls,
 			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));
 	return 0;
 }
 
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-voice-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-voice-v2.c
index 25bb72f..5485440 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-voice-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-voice-v2.c
@@ -281,6 +281,58 @@
 	return ret;
 }
 
+static int msm_pcm_ioctl(struct snd_pcm_substream *substream,
+			 unsigned int cmd, void *arg)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_voice *prtd = runtime->private_data;
+	uint16_t session_id = get_session_id(prtd);
+	enum voice_lch_mode lch_mode;
+	int ret = 0;
+
+	switch (cmd) {
+	case SNDRV_VOICE_IOCTL_LCH:
+		if (copy_from_user(&lch_mode, (void *)arg,
+				   sizeof(enum voice_lch_mode))) {
+			pr_err("%s: Copy from user failed, size %d\n", __func__,
+			       sizeof(enum voice_lch_mode));
+
+			ret = -EFAULT;
+			break;
+		}
+
+		pr_debug("%s: %s lch_mode:%d\n",
+			 __func__, substream->pcm->id, lch_mode);
+
+		switch (lch_mode) {
+		case VOICE_LCH_START:
+		case VOICE_LCH_STOP:
+			ret = voc_set_lch(session_id, lch_mode);
+			break;
+
+		default:
+			pr_err("%s: Invalid LCH MODE %d\n", __func__, lch_mode);
+
+			ret = -EFAULT;
+		}
+
+		break;
+	default:
+		pr_debug("%s: Falling into default snd_lib_ioctl cmd 0x%x\n",
+			 __func__, cmd);
+
+		ret = snd_pcm_lib_ioctl(substream, cmd, arg);
+		break;
+	}
+
+	if (!ret)
+		pr_debug("%s: ret %d\n", __func__, ret);
+	else
+		pr_err("%s: cmd 0x%x failed %d\n", __func__, cmd, ret);
+
+	return ret;
+}
+
 static int msm_voice_volume_get(struct snd_kcontrol *kcontrol,
 				struct snd_ctl_elem_value *ucontrol)
 {
@@ -476,29 +528,6 @@
 
 	return 0;
 }
-static int msm_voice_widevoice_put(struct snd_kcontrol *kcontrol,
-				struct snd_ctl_elem_value *ucontrol)
-{
-	int wv_enable = ucontrol->value.integer.value[0];
-
-	pr_debug("%s: wv enable=%d\n", __func__, wv_enable);
-
-	voc_set_widevoice_enable(voc_get_session_id(VOICE_SESSION_NAME),
-				 wv_enable);
-	voc_set_widevoice_enable(voc_get_session_id(VOICE2_SESSION_NAME),
-				 wv_enable);
-
-	return 0;
-}
-
-static int msm_voice_widevoice_get(struct snd_kcontrol *kcontrol,
-				struct snd_ctl_elem_value *ucontrol)
-{
-	ucontrol->value.integer.value[0] =
-	       voc_get_widevoice_enable(voc_get_session_id(VOICE_SESSION_NAME));
-	return 0;
-}
-
 
 static int msm_voice_slowtalk_put(struct snd_kcontrol *kcontrol,
 			struct snd_ctl_elem_value *ucontrol)
@@ -524,30 +553,6 @@
 	return 0;
 }
 
-static int msm_voice_fens_put(struct snd_kcontrol *kcontrol,
-			struct snd_ctl_elem_value *ucontrol)
-{
-	int fens_enable = ucontrol->value.integer.value[0];
-
-	pr_debug("%s: fens enable=%d\n", __func__, fens_enable);
-
-	voc_set_pp_enable(voc_get_session_id(VOICE_SESSION_NAME),
-			  MODULE_ID_VOICE_MODULE_FENS, fens_enable);
-	voc_set_pp_enable(voc_get_session_id(VOICE2_SESSION_NAME),
-			  MODULE_ID_VOICE_MODULE_FENS, fens_enable);
-
-	return 0;
-}
-
-static int msm_voice_fens_get(struct snd_kcontrol *kcontrol,
-			struct snd_ctl_elem_value *ucontrol)
-{
-	ucontrol->value.integer.value[0] =
-		voc_get_pp_enable(voc_get_session_id(VOICE_SESSION_NAME),
-				MODULE_ID_VOICE_MODULE_FENS);
-	return 0;
-}
-
 static struct snd_kcontrol_new msm_voice_controls[] = {
 	SOC_SINGLE_EXT("Voice Rx Device Mute", SND_SOC_NOPM, 0, 1, 0,
 				msm_voice_rx_device_mute_get,
@@ -558,12 +563,8 @@
 				msm_voice_volume_get, msm_voice_volume_put),
 	SOC_ENUM_EXT("TTY Mode", msm_tty_mode_enum[0], msm_voice_tty_mode_get,
 				msm_voice_tty_mode_put),
-	SOC_SINGLE_EXT("Widevoice Enable", SND_SOC_NOPM, 0, 1, 0,
-			msm_voice_widevoice_get, msm_voice_widevoice_put),
 	SOC_SINGLE_EXT("Slowtalk Enable", SND_SOC_NOPM, 0, 1, 0,
 				msm_voice_slowtalk_get, msm_voice_slowtalk_put),
-	SOC_SINGLE_EXT("FENS Enable", SND_SOC_NOPM, 0, 1, 0,
-				msm_voice_fens_get, msm_voice_fens_put),
 	SOC_SINGLE_EXT("VoLTE Rx Device Mute", SND_SOC_NOPM, 0, 1, 0,
 			msm_volte_rx_device_mute_get,
 			msm_volte_rx_device_mute_put),
@@ -581,11 +582,12 @@
 };
 
 static struct snd_pcm_ops msm_pcm_ops = {
-	.open           = msm_pcm_open,
-	.hw_params	= msm_pcm_hw_params,
-	.close          = msm_pcm_close,
-	.prepare        = msm_pcm_prepare,
-	.trigger	= msm_pcm_trigger,
+	.open			= msm_pcm_open,
+	.hw_params		= msm_pcm_hw_params,
+	.close			= msm_pcm_close,
+	.prepare		= msm_pcm_prepare,
+	.trigger		= msm_pcm_trigger,
+	.ioctl			= msm_pcm_ioctl,
 };
 
 
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-voip-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-voip-v2.c
index b5ce28f..f17fe5b 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-voip-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-voip-v2.c
@@ -109,10 +109,9 @@
 	wait_queue_head_t in_wait;
 
 	struct mutex lock;
-	struct mutex in_lock;
-	struct mutex out_lock;
 
 	spinlock_t dsp_lock;
+	spinlock_t dsp_ul_lock;
 
 	uint32_t mode;
 	uint32_t rate_type;
@@ -272,7 +271,7 @@
 		return;
 
 	/* Copy up-link packet into out_queue. */
-	spin_lock_irqsave(&prtd->dsp_lock, dsp_flags);
+	spin_lock_irqsave(&prtd->dsp_ul_lock, dsp_flags);
 
 	/* discarding UL packets till start is received */
 	if (!list_empty(&prtd->free_out_queue) && prtd->capture_start) {
@@ -325,10 +324,10 @@
 		pr_debug("ul_pkt: pkt_len =%d, frame.len=%d\n", pkt_len,
 			buf_node->frame.len);
 		prtd->pcm_capture_irq_pos += prtd->pcm_capture_count;
-		spin_unlock_irqrestore(&prtd->dsp_lock, dsp_flags);
+		spin_unlock_irqrestore(&prtd->dsp_ul_lock, dsp_flags);
 		snd_pcm_period_elapsed(prtd->capture_substream);
 	} else {
-		spin_unlock_irqrestore(&prtd->dsp_lock, dsp_flags);
+		spin_unlock_irqrestore(&prtd->dsp_ul_lock, dsp_flags);
 		pr_err("UL data dropped\n");
 	}
 
@@ -526,6 +525,7 @@
 	struct voip_buf_node *buf_node = NULL;
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct voip_drv_info *prtd = runtime->private_data;
+	unsigned long dsp_flags;
 
 	int count = frames_to_bytes(runtime, frames);
 	pr_debug("%s: count = %d, frames=%d\n", __func__, count, (int)frames);
@@ -535,12 +535,13 @@
 				prtd->state == VOIP_STOPPED),
 				1 * HZ);
 	if (ret > 0) {
-		mutex_lock(&prtd->in_lock);
 		if (count <= VOIP_MAX_VOC_PKT_SIZE) {
+			spin_lock_irqsave(&prtd->dsp_lock, dsp_flags);
 			buf_node =
 				list_first_entry(&prtd->free_in_queue,
 						struct voip_buf_node, list);
 			list_del(&buf_node->list);
+			spin_unlock_irqrestore(&prtd->dsp_lock, dsp_flags);
 			if (prtd->mode == MODE_PCM) {
 				ret = copy_from_user(&buf_node->frame.voc_pkt,
 							buf, count);
@@ -548,14 +549,15 @@
 			} else
 				ret = copy_from_user(&buf_node->frame,
 							buf, count);
+			spin_lock_irqsave(&prtd->dsp_lock, dsp_flags);
 			list_add_tail(&buf_node->list, &prtd->in_queue);
+			spin_unlock_irqrestore(&prtd->dsp_lock, dsp_flags);
 		} else {
 			pr_err("%s: Write cnt %d is > VOIP_MAX_VOC_PKT_SIZE\n",
 				__func__, count);
 			ret = -ENOMEM;
 		}
 
-		mutex_unlock(&prtd->in_lock);
 	} else if (ret == 0) {
 		pr_err("%s: No free DL buffs\n", __func__);
 		ret = -ETIMEDOUT;
@@ -574,6 +576,7 @@
 	struct voip_buf_node *buf_node = NULL;
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct voip_drv_info *prtd = runtime->private_data;
+	unsigned long dsp_flags;
 
 	count = frames_to_bytes(runtime, frames);
 
@@ -585,12 +588,13 @@
 				1 * HZ);
 
 	if (ret > 0) {
-		mutex_lock(&prtd->out_lock);
 
 		if (count <= VOIP_MAX_VOC_PKT_SIZE) {
+			spin_lock_irqsave(&prtd->dsp_ul_lock, dsp_flags);
 			buf_node = list_first_entry(&prtd->out_queue,
 					struct voip_buf_node, list);
 			list_del(&buf_node->list);
+			spin_unlock_irqrestore(&prtd->dsp_ul_lock, dsp_flags);
 			if (prtd->mode == MODE_PCM)
 				ret = copy_to_user(buf,
 						   &buf_node->frame.voc_pkt,
@@ -604,15 +608,17 @@
 					__func__, ret);
 				ret = -EFAULT;
 			}
+			spin_lock_irqsave(&prtd->dsp_ul_lock, dsp_flags);
 			list_add_tail(&buf_node->list,
 						&prtd->free_out_queue);
+			spin_unlock_irqrestore(&prtd->dsp_ul_lock, dsp_flags);
+
 		} else {
 			pr_err("%s: Read count %d > VOIP_MAX_VOC_PKT_SIZE\n",
 				__func__, count);
 			ret = -ENOMEM;
 		}
 
-		mutex_unlock(&prtd->out_lock);
 
 	} else if (ret == 0) {
 		pr_err("%s: No UL data available\n", __func__);
@@ -646,6 +652,7 @@
 	struct snd_pcm_substream *p_substream, *c_substream;
 	struct snd_pcm_runtime *runtime;
 	struct voip_drv_info *prtd;
+	unsigned long dsp_flags;
 
 	if (substream == NULL) {
 		pr_err("substream is NULL\n");
@@ -684,7 +691,7 @@
 			goto capt;
 		}
 		if (p_dma_buf->area != NULL) {
-			mutex_lock(&prtd->in_lock);
+			spin_lock_irqsave(&prtd->dsp_lock, dsp_flags);
 			list_for_each_safe(ptr, next, &prtd->in_queue) {
 				buf_node = list_entry(ptr,
 						struct voip_buf_node, list);
@@ -695,11 +702,11 @@
 						struct voip_buf_node, list);
 				list_del(&buf_node->list);
 			}
+			spin_unlock_irqrestore(&prtd->dsp_lock, dsp_flags);
 			dma_free_coherent(p_substream->pcm->card->dev,
 				runtime->hw.buffer_bytes_max, p_dma_buf->area,
 				p_dma_buf->addr);
 			p_dma_buf->area = NULL;
-			mutex_unlock(&prtd->in_lock);
 		}
 		/* release out_queue and free_out_queue */
 capt:		c_substream = prtd->capture_substream;
@@ -713,7 +720,7 @@
 			goto done;
 		}
 		if (c_dma_buf->area != NULL) {
-			mutex_lock(&prtd->out_lock);
+			spin_lock_irqsave(&prtd->dsp_ul_lock, dsp_flags);
 			list_for_each_safe(ptr, next, &prtd->out_queue) {
 				buf_node = list_entry(ptr,
 						struct voip_buf_node, list);
@@ -724,11 +731,11 @@
 						struct voip_buf_node, list);
 				list_del(&buf_node->list);
 			}
+			spin_unlock_irqrestore(&prtd->dsp_ul_lock, dsp_flags);
 			dma_free_coherent(c_substream->pcm->card->dev,
 				runtime->hw.buffer_bytes_max, c_dma_buf->area,
 				c_dma_buf->addr);
 			c_dma_buf->area = NULL;
-			mutex_unlock(&prtd->out_lock);
 		}
 done:
 		prtd->capture_substream = NULL;
@@ -899,19 +906,15 @@
 		for (i = 0; i < VOIP_MAX_Q_LEN; i++) {
 			buf_node = (void *)dma_buf->area + offset;
 
-			mutex_lock(&voip_info.in_lock);
 			list_add_tail(&buf_node->list,
 					&voip_info.free_in_queue);
-			mutex_unlock(&voip_info.in_lock);
 			offset = offset + sizeof(struct voip_buf_node);
 		}
 	} else {
 		for (i = 0; i < VOIP_MAX_Q_LEN; i++) {
 			buf_node = (void *) dma_buf->area + offset;
-			mutex_lock(&voip_info.out_lock);
 			list_add_tail(&buf_node->list,
 					&voip_info.free_out_queue);
-			mutex_unlock(&voip_info.out_lock);
 			offset = offset + sizeof(struct voip_buf_node);
 		}
 	}
@@ -1145,6 +1148,7 @@
 
 static const struct of_device_id msm_voip_dt_match[] = {
 	{.compatible = "qcom,msm-voip-dsp"},
+	{}
 };
 MODULE_DEVICE_TABLE(of, msm_voip_dt_match);
 
@@ -1163,10 +1167,9 @@
 	memset(&voip_info, 0, sizeof(voip_info));
 	voip_info.mode = MODE_PCM;
 	mutex_init(&voip_info.lock);
-	mutex_init(&voip_info.in_lock);
-	mutex_init(&voip_info.out_lock);
 
 	spin_lock_init(&voip_info.dsp_lock);
+	spin_lock_init(&voip_info.dsp_ul_lock);
 
 	init_waitqueue_head(&voip_info.out_wait);
 	init_waitqueue_head(&voip_info.in_wait);
diff --git a/sound/soc/msm/qdsp6v2/q6adm.c b/sound/soc/msm/qdsp6v2/q6adm.c
index ed4e090..bdb0e13 100644
--- a/sound/soc/msm/qdsp6v2/q6adm.c
+++ b/sound/soc/msm/qdsp6v2/q6adm.c
@@ -55,6 +55,7 @@
 	atomic_t mem_map_cal_index;
 
 	int set_custom_topology;
+	int ec_ref_rx;
 };
 
 static struct adm_ctl			this_adm;
@@ -965,7 +966,13 @@
 
 		open.mode_of_operation = path;
 		open.endpoint_id_1 = tmp_port;
-		open.endpoint_id_2 = 0xFFFF;
+
+		if (this_adm.ec_ref_rx == -1) {
+			open.endpoint_id_2 = 0xFFFF;
+		} else if (this_adm.ec_ref_rx && (path != 1)) {
+			open.endpoint_id_2 = this_adm.ec_ref_rx;
+			this_adm.ec_ref_rx = -1;
+		}
 
 		open.topology_id = topology;
 		if ((open.topology_id == VPM_TX_SM_ECNS_COPP_TOPOLOGY) ||
@@ -1187,24 +1194,7 @@
 		ret = -EINVAL;
 		goto fail_cmd;
 	}
-	if (perf_mode) {
-		for (i = 0; i < num_copps; i++) {
-			int tmp;
-
-			tmp = afe_get_port_index(port_id[i]);
-			if (tmp >= 0 && tmp < AFE_MAX_PORTS) {
-				rtac_add_adm_device(port_id[i], atomic_read(
-					&this_adm.copp_low_latency_id[tmp]),
-					path, session_id);
-				pr_debug("%s, copp_id: %d\n", __func__,
-					atomic_read(
-					&this_adm.copp_low_latency_id[tmp]));
-			} else {
-				pr_debug("%s: Invalid port index %d",
-					__func__, tmp);
-			}
-		}
-	} else {
+	if (!perf_mode) {
 		for (i = 0; i < num_copps; i++)
 			send_adm_cal(port_id[i], path);
 
@@ -1383,6 +1373,12 @@
 	return atomic_read(&this_adm.copp_id[port_index]);
 }
 
+void adm_ec_ref_rx_id(int port_id)
+{
+	this_adm.ec_ref_rx = port_id;
+	pr_debug("%s ec_ref_rx:%d", __func__, this_adm.ec_ref_rx);
+}
+
 int adm_close(int port_id, bool perf_mode)
 {
 	struct apr_hdr close;
@@ -1473,8 +1469,8 @@
 			goto fail_cmd;
 		}
 	}
-	if (!atomic_read(&this_adm.copp_cnt[index]) &&
-		!atomic_read(&this_adm.copp_low_latency_cnt[index])) {
+
+	if (!perf_mode) {
 		pr_debug("%s: remove adm device from rtac\n", __func__);
 		rtac_remove_adm_device(port_id);
 	}
@@ -1488,6 +1484,7 @@
 	int i = 0;
 	this_adm.apr = NULL;
 	this_adm.set_custom_topology = 1;
+	this_adm.ec_ref_rx = -1;
 
 	for (i = 0; i < AFE_MAX_PORTS; i++) {
 		atomic_set(&this_adm.copp_id[i], RESET_COPP_ID);
diff --git a/sound/soc/msm/qdsp6v2/q6afe.c b/sound/soc/msm/qdsp6v2/q6afe.c
index f05f772..7de058d 100644
--- a/sound/soc/msm/qdsp6v2/q6afe.c
+++ b/sound/soc/msm/qdsp6v2/q6afe.c
@@ -1948,6 +1948,7 @@
 		goto fail_cmd;
 	}
 	pr_debug("%s: mmap handle 0x%x\n", __func__, this_afe.mmap_handle);
+	kfree(mmap_region_cmd);
 	return 0;
 fail_cmd:
 	kfree(mmap_region_cmd);
@@ -2013,6 +2014,7 @@
 	if (ret)
 		pr_err("%s: AFE memory map cmd failed %d\n",
 		       __func__, ret);
+	kfree(mmap_region_cmd);
 	return ret;
 }
 int q6afe_audio_client_buf_free_contiguous(unsigned int dir,
@@ -2537,7 +2539,7 @@
 	ret = wait_event_timeout(this_afe.wait[index],
 		(atomic_read(&this_afe.state) == 0),
 			msecs_to_jiffies(TIMEOUT_MS));
-	if (ret < 0) {
+	if (!ret) {
 		pr_err("%s: wait_event timeout\n", __func__);
 		ret = -EINVAL;
 		goto fail_cmd;
diff --git a/sound/soc/msm/qdsp6v2/q6asm.c b/sound/soc/msm/qdsp6v2/q6asm.c
index ac26d0c..5136cb9 100644
--- a/sound/soc/msm/qdsp6v2/q6asm.c
+++ b/sound/soc/msm/qdsp6v2/q6asm.c
@@ -578,7 +578,8 @@
 
 void *q6asm_mmap_apr_reg(void)
 {
-	if (atomic_read(&this_mmap.ref_cnt) == 0) {
+	if ((atomic_read(&this_mmap.ref_cnt) == 0) ||
+	    (this_mmap.apr == NULL)) {
 		this_mmap.apr = apr_register("ADSP", "ASM", \
 					(apr_fn)q6asm_mmapcallback,\
 					0x0FFFFFFFF, &this_mmap);
diff --git a/sound/soc/msm/qdsp6v2/q6voice.c b/sound/soc/msm/qdsp6v2/q6voice.c
index 5f89e4a..8888e41 100644
--- a/sound/soc/msm/qdsp6v2/q6voice.c
+++ b/sound/soc/msm/qdsp6v2/q6voice.c
@@ -56,7 +56,7 @@
 static int voice_send_disable_vocproc_cmd(struct voice_data *v);
 static int voice_send_vol_index_cmd(struct voice_data *v);
 static int voice_send_mvm_unmap_memory_physical_cmd(struct voice_data *v,
-						    unsigned int bufcnt);
+						    uint32_t mem_handle);
 static int voice_send_mvm_cal_network_cmd(struct voice_data *v);
 static int voice_send_mvm_media_type_cmd(struct voice_data *v);
 static int voice_send_cvs_data_exchange_mode_cmd(struct voice_data *v);
@@ -82,7 +82,6 @@
 static int32_t qdsp_cvs_callback(struct apr_client_data *data, void *priv);
 static int32_t qdsp_cvp_callback(struct apr_client_data *data, void *priv);
 
-static int voice_send_set_widevoice_enable_cmd(struct voice_data *v);
 static int voice_send_set_pp_enable_cmd(struct voice_data *v,
 					uint32_t module_id, int enable);
 
@@ -228,6 +227,29 @@
 	return (session_id == common.voice[VOC_PATH_VOICE2_PASSIVE].session_id);
 }
 
+static bool is_other_session_active(u16 session_id)
+{
+	int i;
+	bool ret = false;
+
+	/* Check if there is other active session except the input one */
+	for (i = 0; i < MAX_VOC_SESSIONS; i++) {
+		if (common.voice[i].session_id == session_id)
+			continue;
+
+		if ((common.voice[i].voc_state == VOC_RUN) ||
+		    (common.voice[i].voc_state == VOC_CHANGE) ||
+		    (common.voice[i].voc_state == VOC_STANDBY)) {
+			ret = true;
+			break;
+		}
+	}
+	pr_debug("%s: ret %d\n", __func__, ret);
+
+	return ret;
+
+}
+
 static int voice_apr_register(void)
 {
 	void *modem_mvm, *modem_cvs, *modem_cvp;
@@ -677,7 +699,7 @@
 	cvs_handle = voice_get_cvs_handle(v);
 
 	/* MVM, CVS sessions are destroyed only for Full control sessions. */
-	if (is_voip_session(v->session_id) || v->voc_state == VOC_ERROR) {
+	if (is_voip_session(v->session_id)) {
 		pr_debug("%s: MVM detach stream, VOC_STATE: %d\n", __func__,
 				v->voc_state);
 
@@ -699,6 +721,7 @@
 		if (ret < 0) {
 			pr_err("%s: Error %d sending DETACH_STREAM\n",
 			       __func__, ret);
+
 			goto fail;
 		}
 		ret = wait_event_timeout(v->mvm_wait,
@@ -706,9 +729,25 @@
 					 msecs_to_jiffies(TIMEOUT_MS));
 		if (!ret) {
 			pr_err("%s: wait event timeout\n", __func__);
+
 			goto fail;
 		}
 
+		/* Unmap memory */
+		if (v->shmem_info.mem_handle != 0) {
+			ret = voice_send_mvm_unmap_memory_physical_cmd(v,
+						v->shmem_info.mem_handle);
+			if (ret < 0) {
+				pr_err("%s Memory_unmap for voip failed %d\n",
+				       __func__, ret);
+
+				goto fail;
+			}
+			v->shmem_info.mem_handle = 0;
+		}
+	}
+
+	if (is_voip_session(v->session_id) || v->voc_state == VOC_ERROR) {
 		/* Destroy CVS. */
 		pr_debug("%s: CVS destroy session\n", __func__);
 
@@ -727,6 +766,7 @@
 		if (ret < 0) {
 			pr_err("%s: Error %d sending CVS DESTROY\n",
 			       __func__, ret);
+
 			goto fail;
 		}
 		ret = wait_event_timeout(v->cvs_wait,
@@ -740,11 +780,21 @@
 		cvs_handle = 0;
 		voice_set_cvs_handle(v, cvs_handle);
 
-		ret = voice_send_mvm_unmap_memory_physical_cmd(v,
-							       NUM_OF_BUFFERS);
-		if (ret < 0) {
-			pr_err("%s CMD Memory_unmap_regions failed %d\n",
-				__func__, ret);
+		/* Unmap physical memory for calibration */
+		pr_debug("%s: cal_mem_handle %d\n", __func__,
+			 common.cal_mem_handle);
+
+		if (!is_other_session_active(v->session_id) &&
+					    (common.cal_mem_handle != 0)) {
+			ret = voice_send_mvm_unmap_memory_physical_cmd(v,
+							common.cal_mem_handle);
+			if (ret < 0) {
+				pr_err("%s Fail at cal mem unmap %d\n",
+				       __func__, ret);
+
+				goto fail;
+			}
+			common.cal_mem_handle = 0;
 		}
 
 		/* Destroy MVM. */
@@ -841,56 +891,6 @@
 	return -EINVAL;
 }
 
-static int voice_send_set_widevoice_enable_cmd(struct voice_data *v)
-{
-	struct mvm_set_widevoice_enable_cmd mvm_set_wv_cmd;
-	int ret = 0;
-	void *apr_mvm;
-	u16 mvm_handle;
-
-	if (v == NULL) {
-		pr_err("%s: v is NULL\n", __func__);
-		return -EINVAL;
-	}
-	apr_mvm = common.apr_q6_mvm;
-
-	if (!apr_mvm) {
-		pr_err("%s: apr_mvm is NULL.\n", __func__);
-		return -EINVAL;
-	}
-	mvm_handle = voice_get_mvm_handle(v);
-
-	mvm_set_wv_cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
-						     APR_HDR_LEN(APR_HDR_SIZE),
-						     APR_PKT_VER);
-	mvm_set_wv_cmd.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
-						   sizeof(mvm_set_wv_cmd) -
-						   APR_HDR_SIZE);
-	mvm_set_wv_cmd.hdr.src_port = v->session_id;
-	mvm_set_wv_cmd.hdr.dest_port = mvm_handle;
-	mvm_set_wv_cmd.hdr.token = 0;
-	mvm_set_wv_cmd.hdr.opcode = VSS_IWIDEVOICE_CMD_SET_WIDEVOICE;
-
-	mvm_set_wv_cmd.vss_set_wv.enable = v->wv_enable;
-
-	v->mvm_state = CMD_STATUS_FAIL;
-	ret = apr_send_pkt(apr_mvm, (uint32_t *) &mvm_set_wv_cmd);
-	if (ret < 0) {
-		pr_err("Fail: sending mvm set widevoice enable,\n");
-		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:
-	return -EINVAL;
-}
-
 static int voice_send_set_pp_enable_cmd(struct voice_data *v,
 					uint32_t module_id, int enable)
 {
@@ -1444,6 +1444,34 @@
 	return -EINVAL;
 }
 
+static void voc_get_tx_rx_topology(struct voice_data *v,
+				   uint32_t *tx_topology_id,
+				   uint32_t *rx_topology_id)
+{
+	uint32_t tx_id = 0;
+	uint32_t rx_id = 0;
+
+	if (v->lch_mode == VOICE_LCH_START) {
+		pr_debug("%s: Setting TX and RX topology to NONE for LCH\n",
+			 __func__);
+
+		tx_id = VSS_IVOCPROC_TOPOLOGY_ID_NONE;
+		rx_id = VSS_IVOCPROC_TOPOLOGY_ID_NONE;
+	} else {
+		/* Use default topology if invalid value in ACDB */
+		tx_id = get_voice_tx_topology();
+		if (tx_id == 0)
+			tx_id = VSS_IVOCPROC_TOPOLOGY_ID_TX_SM_ECNS;
+
+		rx_id = get_voice_rx_topology();
+		if (rx_id == 0)
+			rx_id = VSS_IVOCPROC_TOPOLOGY_ID_RX_DEFAULT;
+	}
+
+	*tx_topology_id = tx_id;
+	*rx_topology_id = rx_id;
+}
+
 static int voice_send_set_device_cmd(struct voice_data *v)
 {
 	struct cvp_set_device_cmd  cvp_setdev_cmd;
@@ -1474,26 +1502,22 @@
 	cvp_setdev_cmd.hdr.src_port = v->session_id;
 	cvp_setdev_cmd.hdr.dest_port = cvp_handle;
 	cvp_setdev_cmd.hdr.token = 0;
-	cvp_setdev_cmd.hdr.opcode = VSS_IVOCPROC_CMD_SET_DEVICE;
+	cvp_setdev_cmd.hdr.opcode = VSS_IVOCPROC_CMD_SET_DEVICE_V2;
 
-	/* Use default topology if invalid value in ACDB */
-	cvp_setdev_cmd.cvp_set_device.tx_topology_id =
-				get_voice_tx_topology();
-	if (cvp_setdev_cmd.cvp_set_device.tx_topology_id == 0)
-		cvp_setdev_cmd.cvp_set_device.tx_topology_id =
-				VSS_IVOCPROC_TOPOLOGY_ID_TX_SM_ECNS;
+	voc_get_tx_rx_topology(v,
+			&cvp_setdev_cmd.cvp_set_device_v2.tx_topology_id,
+			&cvp_setdev_cmd.cvp_set_device_v2.rx_topology_id);
 
-	cvp_setdev_cmd.cvp_set_device.rx_topology_id =
-				get_voice_rx_topology();
-	if (cvp_setdev_cmd.cvp_set_device.rx_topology_id == 0)
-		cvp_setdev_cmd.cvp_set_device.rx_topology_id =
-				VSS_IVOCPROC_TOPOLOGY_ID_RX_DEFAULT;
-	cvp_setdev_cmd.cvp_set_device.tx_port_id = v->dev_tx.port_id;
-	cvp_setdev_cmd.cvp_set_device.rx_port_id = v->dev_rx.port_id;
+	cvp_setdev_cmd.cvp_set_device_v2.tx_port_id = v->dev_tx.port_id;
+	cvp_setdev_cmd.cvp_set_device_v2.rx_port_id = v->dev_rx.port_id;
+	cvp_setdev_cmd.cvp_set_device_v2.vocproc_mode =
+				    VSS_IVOCPROC_VOCPROC_MODE_EC_INT_MIXING;
+	cvp_setdev_cmd.cvp_set_device_v2.ec_ref_port_id =
+				    VSS_IVOCPROC_PORT_ID_NONE;
 	pr_debug("topology=%d , tx_port_id=%d, rx_port_id=%d\n",
-		cvp_setdev_cmd.cvp_set_device.tx_topology_id,
-		cvp_setdev_cmd.cvp_set_device.tx_port_id,
-		cvp_setdev_cmd.cvp_set_device.rx_port_id);
+		cvp_setdev_cmd.cvp_set_device_v2.tx_topology_id,
+		cvp_setdev_cmd.cvp_set_device_v2.tx_port_id,
+		cvp_setdev_cmd.cvp_set_device_v2.rx_port_id);
 
 	v->cvp_state = CMD_STATUS_FAIL;
 	ret = apr_send_pkt(apr_cvp, (uint32_t *) &cvp_setdev_cmd);
@@ -2249,18 +2273,9 @@
 	cvp_session_cmd.hdr.opcode =
 			VSS_IVOCPROC_CMD_CREATE_FULL_CONTROL_SESSION_V2;
 
-	/* Use default topology if invalid value in ACDB */
-	cvp_session_cmd.cvp_session.tx_topology_id =
-				get_voice_tx_topology();
-	if (cvp_session_cmd.cvp_session.tx_topology_id == 0)
-		cvp_session_cmd.cvp_session.tx_topology_id =
-			VSS_IVOCPROC_TOPOLOGY_ID_TX_SM_ECNS;
-
-	cvp_session_cmd.cvp_session.rx_topology_id =
-				get_voice_rx_topology();
-	if (cvp_session_cmd.cvp_session.rx_topology_id == 0)
-		cvp_session_cmd.cvp_session.rx_topology_id =
-			VSS_IVOCPROC_TOPOLOGY_ID_RX_DEFAULT;
+	voc_get_tx_rx_topology(v,
+			&cvp_session_cmd.cvp_session.tx_topology_id,
+			&cvp_session_cmd.cvp_session.rx_topology_id);
 
 	cvp_session_cmd.cvp_session.direction = 2; /*tx and rx*/
 	cvp_session_cmd.cvp_session.tx_port_id = v->dev_tx.port_id;
@@ -2329,20 +2344,11 @@
 		voice_send_netid_timing_cmd(v);
 	}
 
-	/* enable widevoice if wv_enable is set */
-	if (v->wv_enable)
-		voice_send_set_widevoice_enable_cmd(v);
-
 	/* enable slowtalk if st_enable is set */
 	if (v->st_enable)
 		voice_send_set_pp_enable_cmd(v,
 					     MODULE_ID_VOICE_MODULE_ST,
 					     v->st_enable);
-
-	voice_send_set_pp_enable_cmd(v,
-				     MODULE_ID_VOICE_MODULE_FENS,
-				     v->fens_enable);
-
 	/* Start in-call music delivery if this feature is enabled */
 	if (v->music_info.play_enable)
 		voice_cvs_start_playback(v);
@@ -2645,6 +2651,9 @@
 	if (v->dtmf_rx_detect_en)
 		voice_send_dtmf_rx_detection_cmd(v, 0);
 
+	/* reset LCH mode */
+	v->lch_mode = 0;
+
 	/* detach VOCPROC and wait for response from mvm */
 	mvm_d_vocproc_cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
 						APR_HDR_LEN(APR_HDR_SIZE),
@@ -2715,7 +2724,7 @@
 }
 
 static int voice_send_mvm_unmap_memory_physical_cmd(struct voice_data *v,
-							 unsigned int bufcnt)
+						    uint32_t mem_handle)
 {
 	struct vss_imemory_cmd_unmap_t mem_unmap;
 	int ret = 0;
@@ -2743,7 +2752,7 @@
 	mem_unmap.hdr.dest_port = mvm_handle;
 	mem_unmap.hdr.token = 0;
 	mem_unmap.hdr.opcode = VSS_IMEMORY_CMD_UNMAP;
-	mem_unmap.mem_handle = v->shmem_info.mem_handle;
+	mem_unmap.mem_handle = mem_handle;
 
 	pr_debug("%s: mem_handle: ox%x\n", __func__, mem_unmap.mem_handle);
 
@@ -2884,7 +2893,7 @@
 	return -EINVAL;
 }
 
-static int voice_send_mute_cmd(struct voice_data *v)
+static int voice_send_stream_mute_cmd(struct voice_data *v)
 {
 	struct cvs_set_mute_cmd cvs_mute_cmd;
 	int ret = 0;
@@ -2912,7 +2921,7 @@
 	cvs_mute_cmd.hdr.token = 0;
 	cvs_mute_cmd.hdr.opcode = VSS_IVOLUME_CMD_MUTE_V2;
 	cvs_mute_cmd.cvs_set_mute.direction = VSS_IVOLUME_DIRECTION_TX;
-	cvs_mute_cmd.cvs_set_mute.mute_flag = v->dev_tx.mute;
+	cvs_mute_cmd.cvs_set_mute.mute_flag = v->stream_tx.stream_mute;
 	cvs_mute_cmd.cvs_set_mute.ramp_duration_ms = DEFAULT_MUTE_RAMP_DURATION;
 
 	v->cvs_state = CMD_STATUS_FAIL;
@@ -2937,7 +2946,8 @@
 	return -EINVAL;
 }
 
-static int voice_send_rx_device_mute_cmd(struct voice_data *v)
+static int voice_send_device_mute_cmd(struct voice_data *v, uint16_t direction,
+				      uint16_t mute_flag)
 {
 	struct cvp_set_mute_cmd cvp_mute_cmd;
 	int ret = 0;
@@ -2963,8 +2973,8 @@
 	cvp_mute_cmd.hdr.dest_port = voice_get_cvp_handle(v);
 	cvp_mute_cmd.hdr.token = 0;
 	cvp_mute_cmd.hdr.opcode = VSS_IVOLUME_CMD_MUTE_V2;
-	cvp_mute_cmd.cvp_set_mute.direction = VSS_IVOLUME_DIRECTION_RX;
-	cvp_mute_cmd.cvp_set_mute.mute_flag = v->dev_rx.mute;
+	cvp_mute_cmd.cvp_set_mute.direction = direction;
+	cvp_mute_cmd.cvp_set_mute.mute_flag = mute_flag;
 	cvp_mute_cmd.cvp_set_mute.ramp_duration_ms = DEFAULT_MUTE_RAMP_DURATION;
 
 	v->cvp_state = CMD_STATUS_FAIL;
@@ -3493,7 +3503,7 @@
 	int ret = 0;
 
 	if (v == NULL) {
-		pr_err("%s: invalid session_id 0x%x\n", __func__, session_id);
+		pr_err("%s: Invalid session_id 0x%x\n", __func__, session_id);
 
 		return -EINVAL;
 	}
@@ -3503,7 +3513,7 @@
 	if (v->voc_state == VOC_CHANGE) {
 		ret = voice_send_set_device_cmd(v);
 		if (ret < 0) {
-			pr_err("%s:  set device failed\n", __func__);
+			pr_err("%s:  Set device failed\n", __func__);
 			goto fail;
 		}
 
@@ -3511,31 +3521,45 @@
 		voice_send_cvp_register_cal_cmd(v);
 		voice_send_cvp_register_vol_cal_cmd(v);
 
+		if (v->lch_mode == VOICE_LCH_START) {
+			pr_debug("%s: TX and RX mute ON\n", __func__);
+
+			voice_send_device_mute_cmd(v,
+						   VSS_IVOLUME_DIRECTION_TX,
+						   VSS_IVOLUME_MUTE_ON);
+			voice_send_device_mute_cmd(v,
+						   VSS_IVOLUME_DIRECTION_RX,
+						   VSS_IVOLUME_MUTE_ON);
+		} else if (v->lch_mode == VOICE_LCH_STOP) {
+			pr_debug("%s: TX and RX mute OFF\n", __func__);
+
+			voice_send_device_mute_cmd(v,
+						   VSS_IVOLUME_DIRECTION_TX,
+						   VSS_IVOLUME_MUTE_OFF);
+			voice_send_device_mute_cmd(v,
+						   VSS_IVOLUME_DIRECTION_RX,
+						   VSS_IVOLUME_MUTE_OFF);
+			/* Reset lch mode when VOICE_LCH_STOP is recieved */
+			v->lch_mode = 0;
+		} else {
+			pr_debug("%s: Mute commands not sent for lch_mode=%d\n",
+				 __func__, v->lch_mode);
+		}
+
 		ret = voice_send_enable_vocproc_cmd(v);
 		if (ret < 0) {
-			pr_err("%s: enable vocproc failed %d\n", __func__, ret);
+			pr_err("%s: Enable vocproc failed %d\n", __func__, ret);
+
 			goto fail;
 		}
 
 		/* Send tty mode if tty device is used */
 		voice_send_tty_mode_cmd(v);
-
-		/* enable widevoice if wv_enable is set */
-		if (v->wv_enable)
-			voice_send_set_widevoice_enable_cmd(v);
-
 		/* enable slowtalk */
 		if (v->st_enable)
 			voice_send_set_pp_enable_cmd(v,
 					     MODULE_ID_VOICE_MODULE_ST,
 					     v->st_enable);
-
-		/* enable FENS */
-		if (v->fens_enable)
-			voice_send_set_pp_enable_cmd(v,
-					     MODULE_ID_VOICE_MODULE_FENS,
-					     v->fens_enable);
-
 		rtac_add_voice(voice_get_cvs_handle(v),
 			voice_get_cvp_handle(v),
 			v->dev_rx.port_id, v->dev_tx.port_id,
@@ -3593,12 +3617,12 @@
 
 	mutex_lock(&v->lock);
 
-	v->dev_tx.mute = mute;
+	v->stream_tx.stream_mute = mute;
 
 	if ((v->voc_state == VOC_RUN) ||
 	    (v->voc_state == VOC_CHANGE) ||
 	    (v->voc_state == VOC_STANDBY))
-		ret = voice_send_mute_cmd(v);
+		ret = voice_send_stream_mute_cmd(v);
 
 	mutex_unlock(&v->lock);
 
@@ -3618,10 +3642,12 @@
 
 	mutex_lock(&v->lock);
 
-	v->dev_rx.mute = mute;
+	v->dev_rx.dev_mute = mute;
 
 	if (v->voc_state == VOC_RUN)
-		ret = voice_send_rx_device_mute_cmd(v);
+		ret = voice_send_device_mute_cmd(v,
+						 VSS_IVOLUME_DIRECTION_RX,
+						 v->dev_rx.dev_mute);
 
 	mutex_unlock(&v->lock);
 
@@ -3641,7 +3667,7 @@
 
 	mutex_lock(&v->lock);
 
-	ret = v->dev_rx.mute;
+	ret = v->dev_rx.dev_mute;
 
 	mutex_unlock(&v->lock);
 
@@ -3688,51 +3714,6 @@
 	return ret;
 }
 
-int voc_set_widevoice_enable(uint16_t session_id, uint32_t wv_enable)
-{
-	struct voice_data *v = voice_get_session(session_id);
-	u16 mvm_handle;
-	int ret = 0;
-
-	if (v == NULL) {
-		pr_err("%s: invalid session_id 0x%x\n", __func__, session_id);
-
-		return -EINVAL;
-	}
-
-	mutex_lock(&v->lock);
-
-	v->wv_enable = wv_enable;
-
-	mvm_handle = voice_get_mvm_handle(v);
-	if (mvm_handle != 0)
-		voice_send_set_widevoice_enable_cmd(v);
-
-	mutex_unlock(&v->lock);
-
-	return ret;
-}
-
-uint32_t voc_get_widevoice_enable(uint16_t session_id)
-{
-	struct voice_data *v = voice_get_session(session_id);
-	int ret = 0;
-
-	if (v == NULL) {
-		pr_err("%s: invalid session_id 0x%x\n", __func__, session_id);
-
-		return -EINVAL;
-	}
-
-	mutex_lock(&v->lock);
-
-	ret = v->wv_enable;
-
-	mutex_unlock(&v->lock);
-
-	return ret;
-}
-
 int voc_set_pp_enable(uint16_t session_id, uint32_t module_id, uint32_t enable)
 {
 	struct voice_data *v = voice_get_session(session_id);
@@ -3747,18 +3728,12 @@
 	mutex_lock(&v->lock);
 	if (module_id == MODULE_ID_VOICE_MODULE_ST)
 		v->st_enable = enable;
-	else if (module_id == MODULE_ID_VOICE_MODULE_FENS)
-		v->fens_enable = enable;
 
 	if (v->voc_state == VOC_RUN) {
 		if (module_id == MODULE_ID_VOICE_MODULE_ST)
 			ret = voice_send_set_pp_enable_cmd(v,
 						MODULE_ID_VOICE_MODULE_ST,
 						enable);
-		else if (module_id == MODULE_ID_VOICE_MODULE_FENS)
-			ret = voice_send_set_pp_enable_cmd(v,
-						MODULE_ID_VOICE_MODULE_FENS,
-						enable);
 	}
 
 	mutex_unlock(&v->lock);
@@ -3780,9 +3755,6 @@
 	mutex_lock(&v->lock);
 	if (module_id == MODULE_ID_VOICE_MODULE_ST)
 		ret = v->st_enable;
-	else if (module_id == MODULE_ID_VOICE_MODULE_FENS)
-		ret = v->fens_enable;
-
 	mutex_unlock(&v->lock);
 
 	return ret;
@@ -3960,6 +3932,49 @@
 	return ret;
 }
 
+int voc_set_lch(uint16_t session_id, enum voice_lch_mode lch_mode)
+{
+	struct voice_data *v = voice_get_session(session_id);
+	int ret = 0;
+
+	if (v == NULL) {
+		pr_err("%s: Invalid session_id 0x%x\n", __func__, session_id);
+
+		ret = -EINVAL;
+		goto done;
+	}
+
+	mutex_lock(&v->lock);
+	if (v->lch_mode == lch_mode) {
+		pr_debug("%s: Session %d already in LCH mode %d\n",
+				 __func__, session_id, lch_mode);
+
+		mutex_unlock(&v->lock);
+		goto done;
+	}
+
+	v->lch_mode = lch_mode;
+	mutex_unlock(&v->lock);
+
+	ret = voc_disable_cvp(session_id);
+	if (ret < 0) {
+		pr_err("%s: voc_disable_cvp failed ret=%d\n", __func__, ret);
+
+		goto done;
+	}
+
+	/* Mute and topology_none will be set as part of voc_enable_cvp() */
+	ret = voc_enable_cvp(session_id);
+	if (ret < 0) {
+		pr_err("%s: voc_enable_cvp failed ret=%d\n", __func__, ret);
+
+		goto done;
+	}
+
+done:
+	return ret;
+}
+
 int voc_resume_voice_call(uint16_t session_id)
 {
 	struct voice_data *v = voice_get_session(session_id);
@@ -4181,7 +4196,6 @@
 			case VSS_IMVM_CMD_DETACH_STREAM:
 			case VSS_ICOMMON_CMD_SET_NETWORK:
 			case VSS_ICOMMON_CMD_SET_VOICE_TIMING:
-			case VSS_IWIDEVOICE_CMD_SET_WIDEVOICE:
 			case VSS_IMVM_CMD_SET_POLICY_DUAL_CONTROL:
 			case VSS_IMVM_CMD_SET_CAL_NETWORK:
 			case VSS_IMVM_CMD_SET_CAL_MEDIA_TYPE:
@@ -4580,7 +4594,7 @@
 				v->cvp_state = CMD_STATUS_SUCCESS;
 				wake_up(&v->cvp_wait);
 				break;
-			case VSS_IVOCPROC_CMD_SET_DEVICE:
+			case VSS_IVOCPROC_CMD_SET_DEVICE_V2:
 			case VSS_IVOCPROC_CMD_SET_RX_VOLUME_INDEX:
 			case VSS_IVOCPROC_CMD_ENABLE:
 			case VSS_IVOCPROC_CMD_DISABLE:
@@ -4769,13 +4783,16 @@
 
 		/* initialize dev_rx and dev_tx */
 		common.voice[i].dev_rx.volume = common.default_vol_val;
-		common.voice[i].dev_rx.mute =  0;
-		common.voice[i].dev_tx.mute = common.default_mute_val;
+		common.voice[i].dev_rx.dev_mute =  0;
+		common.voice[i].dev_tx.dev_mute =  0;
+		common.voice[i].stream_rx.stream_mute = common.default_mute_val;
+		common.voice[i].stream_tx.stream_mute = common.default_mute_val;
 
 		common.voice[i].dev_tx.port_id = 0x100B;
 		common.voice[i].dev_rx.port_id = 0x100A;
 		common.voice[i].sidetone_gain = 0x512;
 		common.voice[i].dtmf_rx_detect_en = 0;
+		common.voice[i].lch_mode = 0;
 
 		common.voice[i].voc_state = VOC_INIT;
 
@@ -4803,4 +4820,4 @@
 	return rc;
 }
 
-device_initcall(voice_init);
+late_initcall(voice_init);
diff --git a/sound/soc/msm/qdsp6v2/q6voice.h b/sound/soc/msm/qdsp6v2/q6voice.h
index ef5c6e3..386634b 100644
--- a/sound/soc/msm/qdsp6v2/q6voice.h
+++ b/sound/soc/msm/qdsp6v2/q6voice.h
@@ -14,6 +14,7 @@
 
 #include <mach/qdsp6v2/apr.h>
 #include <linux/msm_ion.h>
+#include <sound/voice_params.h>
 
 #define MAX_VOC_PKT_SIZE 642
 #define SESSION_NAME_LEN 20
@@ -41,11 +42,15 @@
 	void *cb_handle;
 };
 
-/* Device information payload structure */
+/* Stream information payload structure */
+struct stream_data {
+	uint32_t stream_mute;
+};
 
+/* Device information payload structure */
 struct device_data {
 	uint32_t volume; /* in index */
-	uint32_t mute;
+	uint32_t dev_mute;
 	uint32_t sample;
 	uint32_t enabled;
 	uint32_t dev_id;
@@ -194,9 +199,6 @@
 #define VSS_ICOMMON_CMD_SET_VOICE_TIMING		0x000111E0
 /* Set the voice timing parameters. */
 
-#define VSS_IWIDEVOICE_CMD_SET_WIDEVOICE                0x00011243
-/* Enable/disable WideVoice */
-
 #define VSS_IMEMORY_CMD_MAP_PHYSICAL			0x00011334
 #define VSS_IMEMORY_RSP_MAP				0x00011336
 #define VSS_IMEMORY_CMD_UNMAP				0x00011337
@@ -291,14 +293,6 @@
 	/* Set to TRUE to enable modem state machine control */
 } __packed;
 
-struct vss_iwidevoice_cmd_set_widevoice_t {
-	uint32_t enable;
-	/* WideVoice enable/disable; possible values:
-	* - 0 -- WideVoice disabled
-	* - 1 -- WideVoice enabled
-	*/
-} __packed;
-
 struct mvm_attach_vocproc_cmd {
 	struct apr_hdr hdr;
 	struct vss_istream_cmd_attach_vocproc_t mvm_attach_cvp_handle;
@@ -344,11 +338,6 @@
 	struct vss_icommon_cmd_set_voice_timing_t timing;
 } __packed;
 
-struct mvm_set_widevoice_enable_cmd {
-	struct apr_hdr hdr;
-	struct vss_iwidevoice_cmd_set_widevoice_t vss_set_wv;
-} __packed;
-
 struct vss_imemory_table_descriptor_t {
 	uint64_t mem_address;
 	/*
@@ -484,7 +473,6 @@
 #define VSS_ISTREAM_CMD_SET_ENC_DTX_MODE		0x0001101D
 /* Set encoder DTX mode. */
 
-#define MODULE_ID_VOICE_MODULE_FENS			0x00010EEB
 #define MODULE_ID_VOICE_MODULE_ST			0x00010EE3
 #define VOICE_PARAM_MOD_ENABLE				0x00010E00
 #define MOD_ENABLE_PARAM_LEN				4
@@ -904,7 +892,7 @@
 
 #define APRV2_IBASIC_CMD_DESTROY_SESSION		0x0001003C
 
-#define VSS_IVOCPROC_CMD_SET_DEVICE			0x000100C4
+#define VSS_IVOCPROC_CMD_SET_DEVICE_V2			0x000112C6
 
 #define VSS_IVOCPROC_CMD_SET_VP3_DATA			0x000110EB
 
@@ -1042,8 +1030,8 @@
 	 */
 } __packed;
 
-struct vss_ivocproc_cmd_set_device_t {
-	uint32_t tx_port_id;
+struct vss_ivocproc_cmd_set_device_v2_t {
+	uint16_t tx_port_id;
 	/*
 	 * TX device port ID which vocproc will connect to.
 	 * VSS_IVOCPROC_PORT_ID_NONE means vocproc will not connect to any port.
@@ -1054,7 +1042,7 @@
 	 * VSS_IVOCPROC_TOPOLOGY_ID_NONE means vocproc does not contain any
 	 * pre/post-processing blocks and is pass-through.
 	 */
-	int32_t rx_port_id;
+	uint16_t rx_port_id;
 	/*
 	 * RX device port ID which vocproc will connect to.
 	 * VSS_IVOCPROC_PORT_ID_NONE means vocproc will not connect to any port.
@@ -1065,6 +1053,15 @@
 	 * VSS_IVOCPROC_TOPOLOGY_ID_NONE means vocproc does not contain any
 	 * pre/post-processing blocks and is pass-through.
 	 */
+	uint32_t vocproc_mode;
+	/* Vocproc mode. The supported values:
+	 * VSS_IVOCPROC_VOCPROC_MODE_EC_INT_MIXING - 0x00010F7C
+	 * VSS_IVOCPROC_VOCPROC_MODE_EC_EXT_MIXING - 0x00010F7D
+	 */
+	uint16_t ec_ref_port_id;
+	/* Port ID to which the vocproc connects for receiving
+	 * echo
+	 */
 } __packed;
 
 struct vss_ivocproc_cmd_register_device_config_t {
@@ -1128,7 +1125,7 @@
 
 struct cvp_set_device_cmd {
 	struct apr_hdr hdr;
-	struct vss_ivocproc_cmd_set_device_t cvp_set_device;
+	struct vss_ivocproc_cmd_set_device_v2_t cvp_set_device_v2;
 } __packed;
 
 struct cvp_set_vp3_data_cmd {
@@ -1230,10 +1227,14 @@
 	wait_queue_head_t cvs_wait;
 	wait_queue_head_t cvp_wait;
 
-	/* cache the values related to Rx and Tx */
+	/* Cache the values related to Rx and Tx devices */
 	struct device_data dev_rx;
 	struct device_data dev_tx;
 
+	/* Cache the values related to Rx and Tx streams */
+	struct stream_data stream_rx;
+	struct stream_data stream_tx;
+
 	u32 mvm_state;
 	u32 cvs_state;
 	u32 cvp_state;
@@ -1249,14 +1250,11 @@
 
 	uint16_t sidetone_gain;
 	uint8_t tty_mode;
-	/* widevoice enable value */
-	uint8_t wv_enable;
 	/* slowtalk enable value */
 	uint32_t st_enable;
-	/* FENC enable value */
-	uint32_t fens_enable;
-
 	uint32_t dtmf_rx_detect_en;
+	/* Local Call Hold mode */
+	uint8_t lch_mode;
 
 	struct voice_dev_route_state voc_route_state;
 
@@ -1345,14 +1343,13 @@
 int voc_set_pp_enable(uint16_t session_id, uint32_t module_id,
 		      uint32_t enable);
 int voc_get_pp_enable(uint16_t session_id, uint32_t module_id);
-int voc_set_widevoice_enable(uint16_t session_id, uint32_t wv_enable);
-uint32_t voc_get_widevoice_enable(uint16_t session_id);
 uint8_t voc_get_tty_mode(uint16_t session_id);
 int voc_set_tty_mode(uint16_t session_id, uint8_t tty_mode);
 int voc_start_voice_call(uint16_t session_id);
 int voc_end_voice_call(uint16_t session_id);
 int voc_standby_voice_call(uint16_t session_id);
 int voc_resume_voice_call(uint16_t session_id);
+int voc_set_lch(uint16_t session_id, enum voice_lch_mode lch_mode);
 int voc_set_rxtx_port(uint16_t session_id,
 		      uint32_t dev_port_id,
 		      uint32_t dev_type);