Merge "mm: panic on the first bad page table entry access"
diff --git a/Documentation/arm/msm/msm_smp2p.txt b/Documentation/arm/msm/msm_smp2p.txt
index 4f77614..77bfb50 100644
--- a/Documentation/arm/msm/msm_smp2p.txt
+++ b/Documentation/arm/msm/msm_smp2p.txt
@@ -128,8 +128,10 @@
   |                        section.                                           |
    ---------------------------------------------------------------------------
   | Feature      3 Bytes   Refer to Version                                   |
-  | flags                  and Feature Negotiation  Must be set to zero.      |
-  |                        section.                                           |
+  | flags                  and Feature Negotiation                            |
+  |                        section for details.                               |
+  |   bit 0                SSR_ACK Feature          Supported when set to 1   |
+  |   bits 1:31            Reserved                 Must be set to 0.         |
    ---------------------------------------------------------------------------
   | Entries      2 Bytes   Total number of          Must be 0 or greater.     |
   | Total                  entries.                                           |
@@ -137,7 +139,11 @@
   | Entries      2 Bytes   Number of valid          Must be between 0         |
   | Valid                  entries.                 and Entries Total.        |
    ---------------------------------------------------------------------------
-  | Reserved     4 Bytes   Reserved                 Must be set to 0.         |
+  | Flags        4 Bytes                                                      |
+  |   bit 0                RESTART_DONE             Toggle for every restart  |
+  |   bit 1                RESTART_ACK              Toggle to ACK remote      |
+  |                                                 RESTART_DONE              |
+  |   bits 2:31            Reserved                 Must be set to 0.         |
    ---------------------------------------------------------------------------
                            Table 1 - SMEM Item Header
 
@@ -299,6 +305,12 @@
        has changed.
     2) Compare Entries Valid to cached value.  If changed, initialize new entries.
 
+Security
+========
+Since the implementation resides in the kernel and does not expose interfaces
+to userspace, no security issues are anticipated.  The usage of separate SMEM
+items allows for future security enhancements in SMEM.
+
 Performance
 ===========
 No performance issues are anticipated as the signaling rate is expected to be
@@ -311,19 +323,18 @@
 
 To map an entry to the client, the client must add two nodes to the Device
 Tree:
-  1) A node that matches "qcom,smp2pgpio" to create the entry
-  2) A node that matches the client driver to provide the GPIO pin mapping
+    1) A node that matches "qcom,smp2pgpio" to create the entry
+    2) A node that matches the client driver to provide the GPIO pin mapping
 
-The details of the device tree entries are contained in the file
-Documentionat/devicetree/bindings/arm/msm/smp2p.txt.
-
+The details of the device tree entries for the GPIO interface are contained in
+the file Documentation/devicetree/bindings/gpio/gpio-smp2p.txt.
 
     /* SMP2P Test Driver for inbound entry. */
     smp2pgpio_smp2p_7_in: qcom,smp2pgpio-smp2p-7-in {
         compatible = "qcom,smp2pgpio";
         qcom,entry-name = "smp2p";
         qcom,remote-pid = <7>;
-        qcom,is_inbound;
+        qcom,is-inbound;
         gpio-controller;
         #gpio-cells = <2>;
         interrupt-controller;
@@ -374,6 +385,48 @@
 
 Please reference the unit test code for example usage.
 
+Subsystem Restart
+=================
+SMP2P is unaffected by SubSystem Restart (SSR) on the high-level OS side and is
+actually used as an underlying communication mechanism for SSR.  On the
+peripheral system that is being restarted, SMP2P will zero out all existing
+state entries upon reboot as part of the SMP2P initialization process and if the
+SSR_ACK feature is enabled, then it waits for an acknowledgement as outlined in
+the following subsections.
+
+SSR_ACK Feature - Reboot Use Case (Non-HLOS Only)
+-------------------------------------------------
+If a remote system boots up after an SSR and sees that the remote and local
+version numbers and feature flags are equal, then it zeros out entry values.  If
+the SSR_ACK feature is enabled, it will wait for an acknowledgement from the other
+processor that it has seen the zero entry before completing the negotiation
+sequence.
+
+    if remote and local version numbers and feature flags are equal
+        Zero out all entry values
+        if SSR_ACK feature is enabled
+            Set local RESTART_DONE flag to inverse of the remote RESTART_ACK
+            Send interrupt to remote system
+            Wait for interrupt and for remote RESTART_ACK to be equal to local
+            RESTART_DONE
+    Continue with normal negotiation sequence
+
+Interrupt Use Case
+------------------
+For every interrupt triggered by a remote change, SMP2P will notify the client
+of a change in state.  In addition, if the SSR_ACK feature is enabled, the SSR
+handshaking will also be handled.
+
+    if SSR_ACK feature is enabled
+        if remote RESTART_DONE != local RESTART_ACK
+            Notify client of entry change (will be * -> 0 transition)
+            Toggle local RESTART_ACK
+            Send interrupt to remote system
+        else
+            Notify client of entry change as usual
+    else
+        Notify client of entry change as usual
+
 Debug
 =====
 The state values and names for all entries accessible by the Apps are
@@ -395,12 +448,13 @@
 
 Config options
 ==============
-Configuration of interrupts will be done using Device Tree.  By default, the
-testing components will be enabled since it does not affect performance and has
-a minimal impact on kernel size.  However, customers can disable the testing
-components for size optimization.
+Configuration of interrupts will be done using Device Tree per the format in
+Documentation/devicetree/bindings/arm/msm/smp2p.txt.  By default, the testing
+components will be enabled since it does not affect performance and has a
+minimal impact on kernel size.  However, customers can disable the testing
+component for size optimization.
 
-    CONFIG_MSM_SMP2P - enables SMP2P core functionality
+    CONFIG_MSM_SMP2P - enables SMP2P
     CONFIG_MSM_SMP2P_TEST - enables unit test support
 
 Dependencies
diff --git a/Documentation/devicetree/bindings/arm/msm/cpr-regulator.txt b/Documentation/devicetree/bindings/arm/msm/cpr-regulator.txt
index 4e3abc2..a0b2f6d 100644
--- a/Documentation/devicetree/bindings/arm/msm/cpr-regulator.txt
+++ b/Documentation/devicetree/bindings/arm/msm/cpr-regulator.txt
@@ -22,16 +22,12 @@
 				should be 1 for SVS corner
 - regulator-max-microvolt:	Maximum corner value as max constraint, which
 				should be 4 for SUPER_TURBO or 3 for TURBO
-- qcom,pvs-bin-process:		A list of integers whose length is equal to 2 to
-				the power of qcom,pvs-fuse[num-of-bits]. The location or
-				0-based index of an element in the list corresponds
-				to the bin number. The value of each integer
-				corresponds to the PVS process speed of the APC
-				silicon for a chip with one of these cases:
-					1 = APC_PVS_SLOW
-					2 = APC_PVS_NOM
-					3 = APC_PVS_FAST
-					0 or other values = No PVS
+- qcom,pvs-init-voltage:  	A list of integers whose length is equal to 2
+				to the power of qcom,pvs-fuse[num-of-bits]. The
+				location or 0-based index of an element in the
+				list corresponds to the bin number. The value of
+				each integer corresponds to the initial voltage
+				of the PVS bin in turbo mode in microvolts.
 - qcom,pvs-corner-ceiling-slow:	Ceiling voltages of all corners for APC_PVS_SLOW
 - qcom,pvs-corner-ceiling-nom:	Ceiling voltages of all corners for APC_PVS_NOM
 - qcom,pvs-corner-ceiling-fast:	Ceiling voltages of all corners for APC_PVS_FAST
@@ -155,8 +151,14 @@
 		qcom,pvs-fuse-redun-sel = <22 24 3 2>;
 		qcom,pvs-fuse-redun = <22 27 5>;
 
-		qcom,pvs-bin-process = <0 0 0 0 0 1 1 1 1 1 2 2 2 2 2 2
-					2 2 2 2 3 3 3 3 3 3 3 3 0 0 0 0>;
+		qcom,pvs-init-voltage = <1330000 1330000 1330000 1320000
+						1310000 1300000 1290000 1280000
+						1270000 1260000 1250000 1240000
+						1230000 1220000 1210000 1200000
+						1190000 1180000 1170000 1160000
+						1150000 1140000 1140000 1140000
+						1140000 1140000 1140000 1140000
+						1140000 1140000 1140000 1140000>;
 		qcom,pvs-corner-ceiling-slow = <1050000 1160000 1275000>;
 		qcom,pvs-corner-ceiling-nom  =  <975000 1075000 1200000>;
 		qcom,pvs-corner-ceiling-fast =  <900000 1000000 1140000>;
diff --git a/Documentation/devicetree/bindings/fb/mdss-dsi-ctrl.txt b/Documentation/devicetree/bindings/fb/mdss-dsi-ctrl.txt
index 81dd825..7187908 100644
--- a/Documentation/devicetree/bindings/fb/mdss-dsi-ctrl.txt
+++ b/Documentation/devicetree/bindings/fb/mdss-dsi-ctrl.txt
@@ -44,6 +44,8 @@
 - qcom,platform-enable-gpio:		Specifies the panel lcd/display enable gpio.
 - qcom,platform-reset-gpio:		Specifies the panel reset gpio.
 - qcom,platform-te-gpio:		Specifies the gpio used for TE.
+- qcom,platform-mode-gpio:		Select video/command mode of panel through gpio when it supports
+					both modes.
 - qcom,platform-reset-sequence:		An array that lists the
 					sequence of reset gpio values and sleeps
 					Each command will have the format defined
@@ -74,6 +76,7 @@
 		qcom,platform-reset-gpio = <&msmgpio 25 1>;
 		qcom,platform-te-gpio = <&msmgpio 24 0>;
 		qcom,platform-enable-gpio = <&msmgpio 58 1>;
+		qcom,platform-mode-gpio = <&msmgpio 7 0>;
 		qcom,platform-reset-sequence = <1 25 0 20 1 10>;
 		qcom,platform-supply-entry1 {
 			qcom,supply-name = "vdd";
diff --git a/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt b/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
index fc162a4..9ad8abe 100644
--- a/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
+++ b/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
@@ -228,6 +228,10 @@
 					to the physical width in the framebuffer information.
 - qcom,mdss-pan-physical-height-dimension:	Specifies panel physical height in mm which corresponds
 					to the physical height in the framebuffer information.
+- qcom,mdss-dsi-panel-mode-gpio-state:	String that specifies the mode state for panel if it is defined
+					in dsi controller.
+					"high" = Set GPIO to HIGH
+					"low" = Set GPIO to LOW
 
 
 Note, if a given optional qcom,* binding is not present, then the driver will configure
@@ -316,5 +320,6 @@
 		qcom,mdss-dsi-pwm-gpio = <&pm8941_mpps 5 0>;
 		qcom,mdss-pan-physical-width-dimension = <60>;
 		qcom,mdss-pan-physical-height-dimension = <140>;
+		qcom,mdss-dsi-panel-mode-gpio-state = "low";
 	};
 };
diff --git a/Documentation/devicetree/bindings/input/touchscreen/synaptics_i2c_rmi4.txt b/Documentation/devicetree/bindings/input/touchscreen/synaptics_i2c_rmi4.txt
index 8fd813c..4f9307a 100644
--- a/Documentation/devicetree/bindings/input/touchscreen/synaptics_i2c_rmi4.txt
+++ b/Documentation/devicetree/bindings/input/touchscreen/synaptics_i2c_rmi4.txt
@@ -18,10 +18,14 @@
  - synaptics,button-map		: virtual key code mappings to be used
  - synaptics,x-flip		: modify orientation of the x axis
  - synaptics,y-flip		: modify orientation of the y axis
- - synaptics,panel-x		: panel x dimension
- - synaptics,panel-y		: panel y dimension
+ - synaptics,panel-coords	: touch panel min x, min y, max x and
+					max y resolution
+ - synaptics,display-coords	: display min x, min y, max x and
+					max y resolution
+ - synaptics,reset-delay	: reset delay for controller (ms), default 100
  - synaptics,fw-image-name	: name of firmware .img file in /etc/firmware
  - synaptics,power-down		: fully power down regulators in suspend
+ - synaptics,do-lockdown	: perform one time lockdown procedure
 
 Example:
 	i2c@f9927000 { /* BLSP1 QUP5 */
diff --git a/Documentation/devicetree/bindings/leds/leds-qpnp.txt b/Documentation/devicetree/bindings/leds/leds-qpnp.txt
index f7e50eb..af6a0b5 100644
--- a/Documentation/devicetree/bindings/leds/leds-qpnp.txt
+++ b/Documentation/devicetree/bindings/leds/leds-qpnp.txt
@@ -38,10 +38,10 @@
 Flash is used primarily as a camera or video flash.
 
 Optional properties for flash:
-- qcom,headroom: headroom to use, mV
-- qcom,duration: duration of the flash, ms
+- qcom,headroom: headroom to use. Values should be 0, 1, 2, 3 for 250mV, 300mV, 400mV and 500mV
+- qcom,duration: duration of the flash and torch, 10ms - 1280ms for flash and 2s - 33s for torch
 - qcom,clamp-curr: current to clamp at, mA
-- qcom,startup-dly: delay before flashing after flash executed, us
+- qcom,startup-dly: delay before flashing after flash executed. Values should 0, 1, 2, 3 for 10us, 32us, 64us, and 128us
 - qcom,saftey-timer: include for safety timer use, otherwise watchdog timer will be used
 - linux,default-trigger: trigger the led from external modules such as display
 - qcom,default-state:  default state of the led, should be "on" or "off"
diff --git a/Documentation/devicetree/bindings/media/video/ovti-image-sensor.txt b/Documentation/devicetree/bindings/media/video/ovti-image-sensor.txt
new file mode 100644
index 0000000..cef9cf5
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/video/ovti-image-sensor.txt
@@ -0,0 +1,9 @@
+OmniVision Image Sensor Device Tree Bindings.
+========================================
+
+Boards with the OmniVision Image Sensor shall have the following properties:
+
+Required root node properties:
+    - compatible:
+    - "ovti,ov8865" : OmniVision OV8865 8 megapixel Image Sensor.
+    - "ovti,ov5648" : OmniVision OV5648 5 megapixel Image Sensor.
diff --git a/Documentation/devicetree/bindings/power/qpnp-bms.txt b/Documentation/devicetree/bindings/power/qpnp-bms.txt
index 1162298..b076475 100644
--- a/Documentation/devicetree/bindings/power/qpnp-bms.txt
+++ b/Documentation/devicetree/bindings/power/qpnp-bms.txt
@@ -13,7 +13,15 @@
 		to determine whether the BMS is using an internal or external
 		rsense to accumulate the Coulomb Counter and read current.
 
-Additionally, an optional subnode may be included:
+Additionally, optional subnodes may be included:
+- qcom,batt-pres-status : A subnode with a register address for the SMBB
+		battery interface's BATT_PRES_STATUS register. If this node is
+		added, then the BMS will try to detect offmode battery removal
+		via the battery interface's offmode battery removal circuit.
+- qcom,soc-storage-reg : A subnode with a register address to a spare PMIC
+		register. If this node is included, then the BMS will store its
+		shutdown SOC in the specified register instead of the default
+		BMS data register.
 - qcom,battery-data : A phandle to a node containing the available batterydata
 		profiles. See the batterydata bindings documentation for more
 		details.
@@ -75,8 +83,8 @@
 - qcom,min-fcc-learning-soc: An interger value which defines the minimum SOC
 			to start FCC learning. This is applicable only if
 			FCC learning is enabled.
-- qcom,min-fcc-ocv-pc:	An interger value which defines the minimum PC-lookup(OCV)
-			to start FCC learning. This is applicable only if
+- qcom,min-fcc-ocv-pc:	An interger value which defines the minimum PC-lookup
+			(OCV) to start FCC learning. This is applicable only if
 			FCC learning is enabled.
 - qcom,min-fcc-learning-samples: An interger value which defines the minimum
 			number of the FCC measurement cycles required to
@@ -103,14 +111,23 @@
 - qcom,use-ocv-thresholds : A boolean that controls whether BMS will take
 			new OCVs only between the defined thresholds.
 - qcom,enable-fcc-learning: A boolean that defines if FCC learning is enabled.
-- qcom,bms-adc_tm: Corresponding ADC_TM device's phandle to set recurring measurements
-		and receive notifications for die_temperature, vbatt.
+- qcom,bms-adc_tm: Corresponding ADC_TM device's phandle to set recurring
+			measurements and receive notifications for
+			die_temperature and vbatt.
 
+qcom,batt-pres-status node required properties:
+- reg : offset and length of the PMIC SMBB battery interface BATT_PRES_STATUS
+		register.
 
-All sub node required properties:
+qcom,soc-storage-reg node required properties:
+- reg : address and length of the spare PMIC register that the BMS will store
+		shutdown SoC in.
+
+qcom,bms-iadc node required properties:
 - reg : offset and length of the PMIC peripheral register map.
 
 qcom,bms-bms node required properties:
+- reg : offset and length of the PMIC peripheral register map.
 - interrupts : the interrupt mappings.
 		The format should be
 		<slave-id peripheral-id interrupt-number>.
@@ -156,6 +173,10 @@
 	qcom,bms-iadc = <&pm8941_iadc>;
 	qcom,bms-adc_tm = <&pm8941_adc_tm>;
 
+	qcom,batt-pres-status@1208 {
+		reg = <0x1208 0x1>;
+	}
+
 	qcom,bms-iadc@3800 {
 		reg = <0x3800 0x100>;
 	};
diff --git a/Documentation/devicetree/bindings/pwm/qpnp-pwm.txt b/Documentation/devicetree/bindings/pwm/qpnp-pwm.txt
index 95be46c..3bb63de 100644
--- a/Documentation/devicetree/bindings/pwm/qpnp-pwm.txt
+++ b/Documentation/devicetree/bindings/pwm/qpnp-pwm.txt
@@ -18,6 +18,8 @@
 - qcom,channel-id:	channel Id for the PWM.
 
 Optional device bindings:
+- qcom,force-pwm-size:	For certain LPG channels, PWM size can be forced.
+			Possible values  6, 7, 8 and 9.
 - qcom,channel-owner:	A string value to supply owner information.
 - qcom,mode-select:	0 = PWM mode
 			1 = LPG mode
@@ -110,6 +112,7 @@
                                       <0xb040 0x80>;
 				reg-names = "qpnp-lpg-channel-base", "qpnp-lpg-lut-base";
                                 qcom,channel-id = <1>;
+                                qcom,force-pwm-size = <9>;
                                 qcom,period = <6000000>;
 				status = "okay";
 				qcom,pwm {
diff --git a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
index 6e4f7fc..5e686a4f 100644
--- a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
+++ b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
@@ -436,6 +436,8 @@
 - qcom,headset-jack-type-NO: Adjust GPIO level based on the headset jack type.
 - qcom,tapan-codec-9302: Indicates that this device node is for WCD9302 audio
 			    codec.
+- qcom,mbhc-bias-internal: Flag to indicate if internal micbias should be used
+			   for headset detection.
 
 * APQ8074 ASoC Machine driver
 
diff --git a/Documentation/devicetree/bindings/usb/msm-ehci-hsic.txt b/Documentation/devicetree/bindings/usb/msm-ehci-hsic.txt
index 7ca741c..24f21b4 100644
--- a/Documentation/devicetree/bindings/usb/msm-ehci-hsic.txt
+++ b/Documentation/devicetree/bindings/usb/msm-ehci-hsic.txt
@@ -7,7 +7,8 @@
 - interrupt-names : Required interrupt resource entries are:
 	"core_irq" : Interrupt for HSIC core
 - <supply-name>-supply: handle to the regulator device tree node
-  Required "supply-name" is "HSIC_VDDCX" and optionally - "HSIC_GDSC".
+  Required "supply-name" is either "hsic_vdd_dig" or "HSIC_VDDCX" and
+  optionally - "HSIC_GDSC".
 
 Optional properties :
 - interrupt-parent - This must provide reference to the current
@@ -81,6 +82,9 @@
   the reset and enumeration. Since some devices might take more than 100ms
   for initialization when receiving the bus reset, add delay to avoid the
   problem that enmueration is before device initialization done.
+- hsic,vdd-voltage-level: This property must be a list of three integer
+  values (no, min, max) where each value represents either a voltage in
+  microvolts or a value corresponding to voltage corner
 
 - Refer to "Documentation/devicetree/bindings/arm/msm/msm_bus.txt" for
   below optional properties:
@@ -104,7 +108,7 @@
 			1 &intc 0 148 0
 			2 &msmgpio 144 0x8>;
 		interrupt-names = "core_irq", "async_irq", "wakeup";
-		HSIC_VDDCX-supply = <&pm8019_l12>;
+		hsic_vdd_dig-supply = <&pm8841_s2_corner>;
 		HSIC_GDSC-supply = <&gdsc_usb_hsic>;
 		hsic,strobe-gpio = <&msmgpio 144 0x00>;
 		hsic,data-gpio = <&msmgpio 145 0x00>;
@@ -113,6 +117,7 @@
 		hsic,strobe-pad-offset = <0x2050>;
 		hsic,data-pad-offset = <0x2054>;
 		hsic,consider-ipa-handshake;
+		hsic,vdd-voltage-level = <1 5 7>;
 
 		qcom,msm-bus,name = "hsic";
 		qcom,msm-bus,num-cases = <2>;
diff --git a/Documentation/devicetree/bindings/usb/msm-hsusb.txt b/Documentation/devicetree/bindings/usb/msm-hsusb.txt
index ad1b5ad..e7eae76 100644
--- a/Documentation/devicetree/bindings/usb/msm-hsusb.txt
+++ b/Documentation/devicetree/bindings/usb/msm-hsusb.txt
@@ -130,7 +130,8 @@
 - interrupt-names : Required interrupt resource entries are:
             HSUSB EHCI expects "core_irq" and optionally "async_irq".
 - <supply-name>-supply: handle to the regulator device tree node
-  Required "supply-name" is "HSUSB_VDDCX" "HSUSB_1p8-supply" "HSUSB_3p3-supply".
+  Required "supply-name" is either "hsusb_vdd_dig" or "HSUSB_VDDCX"
+  "HSUSB_1p8-supply" "HSUSB_3p3-supply".
 - qcom,usb2-power-budget: maximum vbus power (in mA) that can be provided.
 
 Optional properties :
@@ -138,6 +139,15 @@
 - qcom,resume-gpio: if present then peripheral connected to usb controller
   cannot wakeup from XO shutdown using in-band usb bus resume. Use resume
   gpio to wakeup peripheral.
+- qcom,vdd-voltage-level: This property must be a list of five integer
+  values (no, 0.5vsuspend, 0.75suspend, min, max) where each value respresents
+  either a voltage in microvolts or a value corresponding to voltage corner.
+  First value represents value to vote when USB is not at all active, second
+  value represents value to vote when target is not connected to dock during low
+  power mode, third value represents vlaue to vote when target is connected to dock
+  and no peripheral connected over dock during low power mode, fourth value represents
+  minimum value to vote when USB is operational, fifth item represents maximum value
+  to vote for USB is operational.
 
 Example MSM HSUSB EHCI controller device node :
 	ehci: qcom,ehci-host@f9a55000 {
@@ -145,11 +155,12 @@
 		reg = <0xf9a55000 0x400>;
 		interrupts = <0 134 0>, <0 140 0>;
 		interrupt-names = "core_irq", "async_irq";
-		HSUSB_VDDCX-supply = <&pm8841_s2>;
+		hsusb_vdd_dig-supply = <&pm8841_s2_corner>;
 		HSUSB_1p8-supply = <&pm8941_l6>;
 		HSUSB_3p3-supply = <&pm8941_l24>;
 		qcom,usb2-enable-hsphy2;
 		qcom,usb2-power-budget = <500>;
+		qcom,vdd-voltage-level = <1 2 3 5 7>;
 	};
 
 ANDROID USB:
@@ -164,7 +175,8 @@
   for DMA latency in microsecs.
 - qcom,android-usb-cdrom : if this property is present then device creates
   a new LUN as CD-ROM
-
+- qcom,android-usb-internal-ums : if this property is present then device
+  creates a new LUN as internal usb mass storage
 Example Android USB device node :
 	android_usb@fc42b0c8 {
 		compatible = "qcom,android-usb";
diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
index 9fd3afe..1eec990 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.txt
+++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
@@ -36,6 +36,7 @@
 nintendo	Nintendo
 nvidia	NVIDIA
 nxp	NXP Semiconductors
+ovti	OmniVision Technologies, Inc.
 picochip	Picochip Ltd
 powervr	Imagination Technologies
 qcom	Qualcomm, Inc.
diff --git a/Documentation/devicetree/bindings/wcnss/wcnss-wlan.txt b/Documentation/devicetree/bindings/wcnss/wcnss-wlan.txt
index d0bbc47..5201827 100644
--- a/Documentation/devicetree/bindings/wcnss/wcnss-wlan.txt
+++ b/Documentation/devicetree/bindings/wcnss/wcnss-wlan.txt
@@ -20,6 +20,7 @@
 - gpios: gpio numbers to configure 5-wire interface of WLAN connectivity
 - qcom,has-48mhz-xo: boolean flag to determine the usage of 24MHz XO from RF
 - qcom,has-pronto-hw: boolean flag to determine the revId of the WLAN subsystem
+- qcom,wcnss-adc_tm: ADC handle for vbatt notification APIs.
 
 Optional properties:
 - qcom,has-autodetect-xo: boolean flag to determine whether Iris XO auto detect
@@ -49,4 +50,5 @@
                 <&msmgpio 39 0>, <&msmgpio 40 0>;
         qcom,has-48mhz-xo;
         qcom,has-pronto-hw;
+        qcom,wcnss-adc_tm = <&pm8226_adc_tm>;
     };
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 58fc698..aa37edc 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -1854,6 +1854,11 @@
 
 config DONT_MAP_HOLE_AFTER_MEMBANK0
 	def_bool n
+	depends on ENABLE_VMALLOC_SAVING=n
+
+config ENABLE_VMALLOC_SAVING
+	def_bool n
+	depends on DONT_MAP_HOLE_AFTER_MEMBANK0=n
 
 config HOLES_IN_ZONE
 	def_bool n
diff --git a/arch/arm/boot/dts/apq8026-v1-cdp.dts b/arch/arm/boot/dts/apq8026-v1-cdp.dts
index 7b40738..d7e283b 100644
--- a/arch/arm/boot/dts/apq8026-v1-cdp.dts
+++ b/arch/arm/boot/dts/apq8026-v1-cdp.dts
@@ -18,6 +18,5 @@
 / {
 	model = "Qualcomm APQ 8026 CDP";
 	compatible = "qcom,apq8026-cdp", "qcom,apq8026", "qcom,cdp";
-	qcom,msm-id = <199 1 0>,
-		      <219 1 0>;
+	qcom,board-id = <1 0>;
 };
diff --git a/arch/arm/boot/dts/apq8026-v1-mtp.dts b/arch/arm/boot/dts/apq8026-v1-mtp.dts
index ccf1741..d24875c 100644
--- a/arch/arm/boot/dts/apq8026-v1-mtp.dts
+++ b/arch/arm/boot/dts/apq8026-v1-mtp.dts
@@ -18,8 +18,7 @@
 / {
 	model = "Qualcomm APQ 8026 MTP";
 	compatible = "qcom,apq8026-mtp", "qcom,apq8026", "qcom,mtp";
-	qcom,msm-id = <199 8 0>,
-		      <219 8 0>;
+	qcom,board-id = <8 0>;
 };
 
 &cci {
diff --git a/arch/arm/boot/dts/apq8026-v1-xpm.dts b/arch/arm/boot/dts/apq8026-v1-xpm.dts
index 78ae609..f69511b 100644
--- a/arch/arm/boot/dts/apq8026-v1-xpm.dts
+++ b/arch/arm/boot/dts/apq8026-v1-xpm.dts
@@ -18,6 +18,5 @@
 / {
 	model = "Qualcomm APQ 8026 XPM";
 	compatible = "qcom,apq8026-xpm", "qcom,apq8026", "qcom,xpm";
-	qcom,msm-id = <199 14 0>,
-		      <219 14 0>;
+	qcom,board-id = <14 0>;
 };
diff --git a/arch/arm/boot/dts/apq8026-v1.dtsi b/arch/arm/boot/dts/apq8026-v1.dtsi
index 7fbfcb5..eaea002 100644
--- a/arch/arm/boot/dts/apq8026-v1.dtsi
+++ b/arch/arm/boot/dts/apq8026-v1.dtsi
@@ -21,6 +21,8 @@
 / {
 	model = "Qualcomm APQ 8026";
 	compatible = "qcom,apq8026";
+	qcom,msm-id = <199 0>,
+		      <219 0x20000>;
 };
 
 &tsens {
diff --git a/arch/arm/boot/dts/apq8026-v2-cdp.dts b/arch/arm/boot/dts/apq8026-v2-cdp.dts
index 3fb3c29..cb68779 100644
--- a/arch/arm/boot/dts/apq8026-v2-cdp.dts
+++ b/arch/arm/boot/dts/apq8026-v2-cdp.dts
@@ -18,6 +18,5 @@
 / {
 	model = "Qualcomm APQ 8026v2 CDP";
 	compatible = "qcom,apq8026-cdp", "qcom,apq8026", "qcom,cdp";
-	qcom,msm-id = <199 1 0x20000>,
-		      <219 1 0x20000>;
+	qcom,board-id = <1 0>;
 };
diff --git a/arch/arm/boot/dts/apq8026-v2-mtp.dts b/arch/arm/boot/dts/apq8026-v2-mtp.dts
index e620859..40856c8 100644
--- a/arch/arm/boot/dts/apq8026-v2-mtp.dts
+++ b/arch/arm/boot/dts/apq8026-v2-mtp.dts
@@ -18,6 +18,5 @@
 / {
 	model = "Qualcomm APQ 8026v2 MTP";
 	compatible = "qcom,apq8026-mtp", "qcom,apq8026", "qcom,mtp";
-	qcom,msm-id = <199 8 0x20000>,
-		      <219 8 0x20000>;
+	qcom,board-id = <8 0>;
 };
diff --git a/arch/arm/boot/dts/apq8026-v2-xpm.dts b/arch/arm/boot/dts/apq8026-v2-xpm.dts
index 2848b2e..324516d 100644
--- a/arch/arm/boot/dts/apq8026-v2-xpm.dts
+++ b/arch/arm/boot/dts/apq8026-v2-xpm.dts
@@ -18,6 +18,5 @@
 / {
 	model = "Qualcomm APQ 8026v2 XPM";
 	compatible = "qcom,apq8026-xpm", "qcom,apq8026", "qcom,xpm";
-	qcom,msm-id = <199 14 0x20000>,
-		      <219 14 0x20000>;
+	qcom,board-id = <14 0>;
 };
diff --git a/arch/arm/boot/dts/apq8026-v2.dtsi b/arch/arm/boot/dts/apq8026-v2.dtsi
index 4c0d3ce..3ee8d94 100644
--- a/arch/arm/boot/dts/apq8026-v2.dtsi
+++ b/arch/arm/boot/dts/apq8026-v2.dtsi
@@ -21,6 +21,8 @@
 / {
 	model = "Qualcomm APQ 8026";
 	compatible = "qcom,apq8026";
+	qcom,msm-id = <199 0x20000>,
+		      <219 0x20000>;
 };
 
 &tsens {
diff --git a/arch/arm/boot/dts/apq8074-dragonboard.dtsi b/arch/arm/boot/dts/apq8074-dragonboard.dtsi
index 46f5f22..60bb518 100644
--- a/arch/arm/boot/dts/apq8074-dragonboard.dtsi
+++ b/arch/arm/boot/dts/apq8074-dragonboard.dtsi
@@ -84,7 +84,7 @@
 				1 &intc 0 148 0
 				2 &msmgpio 144 0x8>;
 			interrupt-names = "core_irq", "async_irq", "wakeup";
-			HSIC_VDDCX-supply = <&pm8841_s2>;
+			hsic_vdd_dig-supply = <&pm8841_s2_corner>;
 			HSIC_GDSC-supply = <&gdsc_usb_hsic>;
 			hsic,strobe-gpio = <&msmgpio 144 0x00>;
 			hsic,data-gpio = <&msmgpio 145 0x00>;
@@ -92,6 +92,7 @@
 			hsic,strobe-pad-offset = <0x2050>;
 			hsic,data-pad-offset = <0x2054>;
 			qcom,phy-susp-sof-workaround;
+			hsic,vdd-voltage-level = <1 5 7>;
 
 			qcom,msm-bus,name = "hsic";
 			qcom,msm-bus,num-cases = <2>;
diff --git a/arch/arm/boot/dts/apq8074-v2.0-1.dtsi b/arch/arm/boot/dts/apq8074-v2.0-1.dtsi
index 8314fab..2b75fa2 100644
--- a/arch/arm/boot/dts/apq8074-v2.0-1.dtsi
+++ b/arch/arm/boot/dts/apq8074-v2.0-1.dtsi
@@ -55,3 +55,8 @@
 	status = "ok";
 };
 
+&ehci {
+	hsusb_vdd_dig-supply = <&pm8841_s2_corner>;
+	qcom,vdd-voltage-level = <1 2 3 5 7>;
+};
+
diff --git a/arch/arm/boot/dts/dsi-panel-hx8379a-wvga-video.dtsi b/arch/arm/boot/dts/dsi-panel-hx8379a-wvga-video.dtsi
new file mode 100644
index 0000000..4230018
--- /dev/null
+++ b/arch/arm/boot/dts/dsi-panel-hx8379a-wvga-video.dtsi
@@ -0,0 +1,123 @@
+/* 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.
+ */
+
+/*---------------------------------------------------------------------------
+ * This file is autogenerated file using gcdb parser. Please do not edit it.
+ * Update input XML file to add a new entry or update variable in this file
+ * VERSION = "1.0"
+ *---------------------------------------------------------------------------*/
+&mdss_mdp {
+	dsi_hx8379a_wvga_vid: qcom,mdss_dsi_hx8379a_wvga_video {
+		qcom,mdss-dsi-panel-name = "HX8379A wvga video mode dsi panel";
+		qcom,mdss-dsi-panel-controller = <&mdss_dsi0>;
+		qcom,mdss-dsi-panel-type = "dsi_video_mode";
+		qcom,mdss-dsi-panel-destination = "display_1";
+		qcom,mdss-dsi-panel-framerate = <60>;
+		qcom,mdss-dsi-virtual-channel-id = <0>;
+		qcom,mdss-dsi-stream = <0>;
+		qcom,mdss-dsi-panel-width = <480>;
+		qcom,mdss-dsi-panel-height = <800>;
+		qcom,mdss-dsi-h-front-porch = <100>;
+		qcom,mdss-dsi-h-back-porch = <94>;
+		qcom,mdss-dsi-h-pulse-width = <40>;
+		qcom,mdss-dsi-h-sync-skew = <0>;
+		qcom,mdss-dsi-v-back-porch = <4>;
+		qcom,mdss-dsi-v-front-porch = <6>;
+		qcom,mdss-dsi-v-pulse-width = <6>;
+		qcom,mdss-dsi-h-left-border = <0>;
+		qcom,mdss-dsi-h-right-border = <0>;
+		qcom,mdss-dsi-v-top-border = <0>;
+		qcom,mdss-dsi-v-bottom-border = <0>;
+		qcom,mdss-dsi-bpp = <24>;
+		qcom,mdss-dsi-color-order = <0>;
+		qcom,mdss-dsi-underflow-color = <0xff>;
+		qcom,mdss-dsi-border-color = <0>;
+		qcom,mdss-dsi-on-command = [
+			39 01 00 00 00 00 04
+				B9 FF 83 79
+			39 01 00 00 00 00 03
+				BA 51 93
+			39 01 00 00 00 00 14
+				B1 00 50 44
+				EA 8D 08 11
+				11 11 27 2F
+				9A 1A 42 0B
+				6E F1 00 E6
+			39 01 00 00 00 00 0E
+				B2 00 00 3C
+				08 04 19 22
+				00 FF 08 04
+				19 20
+			39 01 00 00 00 00 20
+				B4 80 08 00
+				32 10 03 32
+				13 70 32 10
+				08 37 01 28
+				07 37 08 35
+				08 3D 44 08
+				00 40 08 28
+				08 30 30 04
+			39 01 00 00 00 00 30
+				D5 00 00 0A
+				00 01 05 00
+				03 00 88 88
+				88 88 23 01
+				67 45 02 13
+				88 88 88 88
+				88 88 88 88
+				88 88 54 76
+				10 32 31 20
+				88 88 88 88
+				88 88 00 00
+				00 00 00 00
+			39 01 00 00 00 00 24
+				E0 79 05 0F
+				14 26 20 3F
+				2A 43 04 0C
+				11 15 17 15
+				15 10 13 05
+				0F 14 26 20
+				3F 2A 43 04
+				0C 11 15 17
+				15 15 10 13
+			23 01 00 00 00 00 02
+				cc 02
+			39 01 00 00 00 00 05
+				B6 00 9C 00
+				9C
+			05 01 00 00 96 00 02
+				11 00
+			05 01 00 00 78 00 02
+				29 00
+			];
+		qcom,mdss-dsi-off-command = [05 01 00 00 32 00 02 28 00
+					05 01 00 00 78 00 02 10 00];
+		qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
+		qcom,mdss-dsi-off-command-state = "dsi_lp_mode";
+		qcom,mdss-dsi-h-sync-pulse = <1>;
+		qcom,mdss-dsi-traffic-mode = <2>;
+		qcom,mdss-dsi-lane-map = <1>;
+		qcom,mdss-dsi-bllp-eof-power-mode;
+		qcom,mdss-dsi-bllp-power-mode;
+		qcom,mdss-dsi-lane-0-state;
+		qcom,mdss-dsi-lane-1-state;
+		qcom,mdss-dsi-panel-timings = [78 1B 11 00 3E 43 16 1E 1D 03 04 00];
+		qcom,mdss-dsi-t-clk-post = <0x04>;
+		qcom,mdss-dsi-t-clk-pre = <0x1b>;
+		qcom,mdss-dsi-bl-min-level = <1>;
+		qcom,mdss-dsi-bl-max-level = <255>;
+		qcom,mdss-dsi-dma-trigger = <4>;
+		qcom,mdss-dsi-mdp-trigger = <0>;
+		qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
+
+	};
+};
diff --git a/arch/arm/boot/dts/dsi-panel-nt35521-720p-video.dtsi b/arch/arm/boot/dts/dsi-panel-nt35521-720p-video.dtsi
index 357b024..829197a 100644
--- a/arch/arm/boot/dts/dsi-panel-nt35521-720p-video.dtsi
+++ b/arch/arm/boot/dts/dsi-panel-nt35521-720p-video.dtsi
@@ -242,13 +242,13 @@
 				29 01 00 00 00 00 03 E6 34 34
 				23 01 00 00 00 00 02 E7 05
 				29 01 00 00 00 00 06 F0 55 AA 52 00 00
-				05 01 00 00 32 00 02 11 00
-				05 01 00 00 96 00 02 29 00
+				05 01 00 00 00 00 02 11 00
+				05 01 00 00 14 00 02 29 00
 				29 01 00 00 00 00 06 F0 55 AA 52 08 01
 				29 01 00 00 00 00 06 F0 55 AA 52 00 00
 				29 01 00 00 00 00 02 53 2C];
-		qcom,mdss-dsi-off-command = [05 01 00 00 32 00 02 28 00
-					05 01 00 00 78 00 02 10 00];
+		qcom,mdss-dsi-off-command = [05 01 00 00 00 00 02 28 00
+					05 01 00 00 00 00 02 10 00];
 		qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
 		qcom,mdss-dsi-off-command-state = "dsi_hs_mode";
 		qcom,mdss-dsi-h-sync-pulse = <1>;
diff --git a/arch/arm/boot/dts/dsi-panel-otm8018b-fwvga-video.dtsi b/arch/arm/boot/dts/dsi-panel-otm8018b-fwvga-video.dtsi
new file mode 100644
index 0000000..89a5063
--- /dev/null
+++ b/arch/arm/boot/dts/dsi-panel-otm8018b-fwvga-video.dtsi
@@ -0,0 +1,266 @@
+/* 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.
+ */
+
+/*---------------------------------------------------------------------------
+ * This file is autogenerated file using gcdb parser. Please do not edit it.
+ * Update input XML file to add a new entry or update variable in this file
+ * VERSION = "1.0"
+ *---------------------------------------------------------------------------*/
+&mdss_mdp {
+	dsi_otm8018b_fwvga_vid: qcom,mdss_dsi_otm8018b_fwvga_video {
+		qcom,mdss-dsi-panel-name = "OTM8018b fwvga video mode dsi panel";
+		qcom,mdss-dsi-panel-controller = <&mdss_dsi0>;
+		qcom,mdss-dsi-panel-type = "dsi_video_mode";
+		qcom,mdss-dsi-panel-destination = "display_1";
+		qcom,mdss-dsi-panel-framerate = <60>;
+		qcom,mdss-dsi-virtual-channel-id = <0>;
+		qcom,mdss-dsi-stream = <0>;
+		qcom,mdss-dsi-panel-width = <480>;
+		qcom,mdss-dsi-panel-height = <854>;
+		qcom,mdss-dsi-h-front-porch = <80>;
+		qcom,mdss-dsi-h-back-porch = <54>;
+		qcom,mdss-dsi-h-pulse-width = <8>;
+		qcom,mdss-dsi-h-sync-skew = <0>;
+		qcom,mdss-dsi-v-back-porch = <16>;
+		qcom,mdss-dsi-v-front-porch = <12>;
+		qcom,mdss-dsi-v-pulse-width = <2>;
+		qcom,mdss-dsi-h-left-border = <0>;
+		qcom,mdss-dsi-h-right-border = <0>;
+		qcom,mdss-dsi-v-top-border = <0>;
+		qcom,mdss-dsi-v-bottom-border = <0>;
+		qcom,mdss-dsi-bpp = <24>;
+		qcom,mdss-dsi-color-order = <0>;
+		qcom,mdss-dsi-underflow-color = <0xff>;
+		qcom,mdss-dsi-border-color = <0>;
+		qcom,mdss-dsi-on-command = [
+					29 01 00 00 00 00 02
+						00 00
+					29 01 00 00 00 00 04
+						ff 80 09 01
+					29 01 00 00 00 00 02
+						00 80
+					29 01 00 00 00 00 03
+						ff 80 09
+					29 01 00 00 00 00 02
+						00 80
+					29 01 00 00 00 00 02
+						d6 48
+					29 01 00 00 00 00 02
+						00 03
+					29 01 00 00 00 00 02
+						ff 01
+					29 01 00 00 00 00 02
+						00 B4
+					29 01 00 00 00 00 02
+						C0 10
+					29 01 00 00 00 00 02
+						00 82
+					29 01 00 00 00 00 02
+						C5 A3
+					29 01 00 00 00 00 02
+						00 90
+					29 01 00 00 00 00 03
+						C5 96 87
+					29 01 00 00 00 00 02
+						00 00
+					29 01 00 00 00 00 03
+						D8 74 72
+					29 01 00 00 00 00 02
+						00 00
+					29 01 00 00 00 00 02
+						D9 56
+					29 01 00 00 00 00 02
+						00 00
+					29 01 00 00 00 00 11
+						E1 00 06 0A
+						07 03 16 08
+						0A 04 06 07
+						08 0F 23 22
+						05
+					29 01 00 00 00 00 02
+						00 00
+					29 01 00 00 00 00 11
+						E2 00 06 0A
+						07 03 16 08
+						0A 04 06 07
+						08 0F 23 22
+						05
+					29 01 00 00 00 00 02
+						00 81
+					29 01 00 00 00 00 02
+						C1 77
+					29 01 00 00 00 00 02
+						00 A0
+					29 01 00 00 00 00 02
+						C1 EA
+					29 01 00 00 00 00 02
+						00 A1
+					29 01 00 00 00 00 02
+						C1 08
+					29 01 00 00 00 00 02
+						00 89
+					29 01 00 00 00 00 02
+						C4 08
+					29 01 00 00 00 00 02
+						00 81
+					29 01 00 00 00 00 02
+						C4 83
+					29 01 00 00 00 00 02
+						00 92
+					29 01 00 00 00 00 02
+						C5 01
+					29 01 00 00 00 00 02
+						00 B1
+					29 01 00 00 00 00 02
+						C5 A9
+					29 01 00 00 00 00 02
+						00 92
+					29 01 00 00 00 00 02
+						B3 45
+					29 01 00 00 00 00 02
+						00 90
+					29 01 00 00 00 00 02
+						B3 02
+					29 01 00 00 00 00 02
+						00 80
+					29 01 00 00 00 00 06
+						C0 00 58 00
+						14 16
+					29 01 00 00 00 00 02
+						00 80
+					29 01 00 00 00 00 02
+						C4 30
+					29 01 00 00 00 00 02
+						00 90
+					29 01 00 00 00 00 07
+						C0 00 44 00
+						00 00 03
+					29 01 00 00 00 00 02
+						00 A6
+					29 01 00 00 00 00 04
+						C1 01 00 00
+					29 01 00 00 00 00 02
+						00 80
+					29 01 00 00 00 00 0D
+						CE 87 03 00
+						85 03 00 86
+						03 00 84 03
+						00
+					29 01 00 00 00 00 02
+						00 A0
+					29 01 00 00 00 00 0f
+						CE 38 03 03
+						58 00 00 00
+						38 02 03 59
+						00 00 00
+					29 01 00 00 00 00 02
+						00 B0
+					29 01 00 00 00 00 0f
+						CE 38 01 03
+						5A 00 00 00
+						38 00 03 5B
+						00 00 00
+					29 01 00 00 00 00 02
+						00 C0
+					29 01 00 00 00 00 0f
+						CE 30 00 03
+						5C 00 00 00
+						30 01 03 5D
+						00 00 00
+					29 01 00 00 00 00 02
+						00 D0
+					29 01 00 00 00 00 0f
+						CE 30 02 03
+						5E 00 00 00
+						30 03 03 5F
+						00 00 00
+					29 01 00 00 00 00 02
+						00 C7
+					29 01 00 00 00 00 02
+						CF 00
+					29 01 00 00 00 00 02
+						00 C9
+					29 01 00 00 00 00 02
+						CF 00
+					29 01 00 00 00 00 02
+						00 D0
+					29 01 00 00 00 00 02
+						CF 00
+					29 01 00 00 00 00 02
+						00 C4
+					29 01 00 00 00 00 07
+						CB 04 04 04
+						04 04 04
+					29 01 00 00 00 00 02
+						00 D9
+					29 01 00 00 00 00 07
+						CB 04 04 04
+						04 04 04
+					29 01 00 00 00 00 02
+						00 84
+					29 01 00 00 00 00 07
+						CC 0C 0A 10
+						0E 03 04
+					29 01 00 00 00 00 02
+						00 9E
+					29 01 00 00 00 00 02
+						CC 0B
+					29 01 00 00 00 00 02
+						00 A0
+					29 01 00 00 00 00 06
+						CC 09 0F 0D
+						01 02
+					29 01 00 00 00 00 02
+						00 B4
+					29 01 00 00 00 00 07
+						CC 0D 0F 09
+						0B 02 01
+					29 01 00 00 00 00 02
+						00 CE
+					29 01 00 00 00 00 02
+						CC 0E
+					29 01 00 00 00 00 02
+						00 D0
+					29 01 00 00 00 00 06
+						CC 10 0A 0C
+						04 03
+					29 01 00 00 00 00 02
+						00 00
+					29 01 00 00 00 00 04
+						ff ff ff ff
+					05 01 00 00 78 00 02
+						11 00
+					05 01 00 00 32 00 02
+						29 00
+					];
+		qcom,mdss-dsi-off-command = [05 01 00 00 32 00 02 28 00
+					05 01 00 00 78 00 02 10 00];
+		qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
+		qcom,mdss-dsi-off-command-state = "dsi_lp_mode";
+		qcom,mdss-dsi-h-sync-pulse = <0>;
+		qcom,mdss-dsi-traffic-mode = <1>;
+		qcom,mdss-dsi-lane-map = <1>;
+		qcom,mdss-dsi-bllp-eof-power-mode;
+		qcom,mdss-dsi-bllp-power-mode;
+		qcom,mdss-dsi-lane-0-state;
+		qcom,mdss-dsi-lane-1-state;
+		qcom,mdss-dsi-panel-timings = [8B 1F 14 00 45 4A 19 23 23 03 04 00];
+		qcom,mdss-dsi-t-clk-post = <0x04>;
+		qcom,mdss-dsi-t-clk-pre = <0x1b>;
+		qcom,mdss-dsi-bl-min-level = <1>;
+		qcom,mdss-dsi-bl-max-level = <255>;
+		qcom,mdss-dsi-dma-trigger = <4>;
+		qcom,mdss-dsi-mdp-trigger = <0>;
+		qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
+
+	};
+};
diff --git a/arch/arm/boot/dts/dsi-panel-ssd2080m-720p-video.dtsi b/arch/arm/boot/dts/dsi-panel-ssd2080m-720p-video.dtsi
new file mode 100644
index 0000000..7bb414a
--- /dev/null
+++ b/arch/arm/boot/dts/dsi-panel-ssd2080m-720p-video.dtsi
@@ -0,0 +1,119 @@
+/* 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.
+ */
+
+/*---------------------------------------------------------------------------
+ * This file is autogenerated file using gcdb parser. Please do not edit it.
+ * Update input XML file to add a new entry or update variable in this file
+ * VERSION = "1.0"
+ *---------------------------------------------------------------------------*/
+&mdss_mdp {
+	dsi_ssd2080m_720_vid: qcom,mdss_dsi_ssd2080m_720p_video {
+		qcom,mdss-dsi-panel-name = "ssd2080m 720p video mode dsi panel";
+		qcom,mdss-dsi-panel-controller = <&mdss_dsi0>;
+		qcom,mdss-dsi-panel-type = "dsi_video_mode";
+		qcom,mdss-dsi-panel-destination = "display_1";
+		qcom,mdss-dsi-panel-framerate = <60>;
+		qcom,mdss-dsi-virtual-channel-id = <0>;
+		qcom,mdss-dsi-stream = <0>;
+		qcom,mdss-dsi-panel-width = <720>;
+		qcom,mdss-dsi-panel-height = <1280>;
+		qcom,mdss-dsi-h-front-porch = <80>;
+		qcom,mdss-dsi-h-back-porch = <24>;
+		qcom,mdss-dsi-h-pulse-width = <14>;
+		qcom,mdss-dsi-h-sync-skew = <0>;
+		qcom,mdss-dsi-v-back-porch = <15>;
+		qcom,mdss-dsi-v-front-porch = <12>;
+		qcom,mdss-dsi-v-pulse-width = <10>;
+		qcom,mdss-dsi-h-left-border = <0>;
+		qcom,mdss-dsi-h-right-border = <0>;
+		qcom,mdss-dsi-v-top-border = <0>;
+		qcom,mdss-dsi-v-bottom-border = <0>;
+		qcom,mdss-dsi-bpp = <24>;
+		qcom,mdss-dsi-color-order = <0>;
+		qcom,mdss-dsi-underflow-color = <0xff>;
+		qcom,mdss-dsi-border-color = <0>;
+		qcom,mdss-dsi-on-command = [15 01 00 00 00 00 02 FF 01
+			29 01 00 00 00 00 05 C6 63 00 81 31
+			29 01 00 00 00 00 05 CB E7 80 73 33
+			29 01 00 00 00 00 02 EC D2
+			29 01 00 00 00 00 03 B3 04 9F
+			29 01 00 00 00 00 04 B2 16 1E 10
+			29 01 00 00 00 00 02 B4 00
+			29 01 00 00 00 00 02 C1 04
+			29 01 00 00 00 00 04 C2 BE 00 58
+			29 01 00 00 00 00 09 C3 01 22 11 21 0E 80 80 24
+			29 01 00 00 00 00 08 B6 09 16 42 01 13 00 00
+			29 01 00 00 00 00 04 B7 24 26 43
+			29 01 00 00 00 00 06 B8 16 08 25 44 08
+			29 01 00 00 00 00 09 B9 06 08 07 09 00 00 00 00
+			29 01 00 00 00 00 09 BA 0E 10 0A 0C 16 05 00 00
+			29 01 00 00 00 00 09 BB A1 A1 A1 A1 00 00 00 00
+			29 01 00 00 00 00 09 BC 0F 11 0B 0D 16 05 00 00
+			29 01 00 00 00 00 09 BD A1 A1 A1 A1 00 00 00 00
+			29 01 00 00 00 00 04 E6 FF FF 0F
+			29 01 00 00 00 00 02 C7 3F
+			29 01 00 00 00 00 07 B5 47 00 00 08 00 01
+			29 01 00 00 00 00 08 C4 DF 72 12 12 66 E3 99
+			29 01 00 00 00 00 07 D0 0A 00 0D 15 1F 2E
+			29 01 00 00 00 00 06 D1 28 27 14 02 01
+			29 01 00 00 00 00 07 D2 0A 00 0D 15 1F 2E
+			29 01 00 00 00 00 06 D3 28 27 14 02 01
+			29 01 00 00 00 00 07 D4 0A 00 0D 15 1F 2E
+			29 01 00 00 00 00 06 D5 28 27 14 02 01
+			29 01 00 00 00 00 07 D6 0A 00 0D 15 1F 2E
+			29 01 00 00 00 00 06 D7 28 27 14 02 01
+			29 01 00 00 00 00 07 D8 0A 00 0D 15 1F 2E
+			29 01 00 00 00 00 06 D9 28 27 14 02 01
+			29 01 00 00 00 00 07 DA 0A 00 0D 15 1F 2E
+			29 01 00 00 00 00 06 DB 28 27 14 02 01
+			29 01 00 00 00 00 03 CC 10 00
+			29 01 00 00 00 00 04 CE 4E 55 A5
+			29 01 00 00 00 00 04 E0 01 02 02
+			29 01 00 00 00 00 05 F6 00 00 00 00
+			29 01 00 00 00 00 05 F7 00 00 00 00
+			29 01 00 00 00 00 03 E1 90 00
+			29 01 00 00 00 00 03 DE 95 CF
+			29 01 00 00 00 00 02 CF 46
+			29 01 00 00 00 00 03 C5 77 47
+			29 01 00 00 00 00 03 ED 00 20
+			05 01 00 00 B4 00 02 11 00
+			05 01 00 00 82 00 02 29 00
+			15 01 00 00 00 00 02 53 2c];
+
+		qcom,mdss-dsi-off-command = [05 01 00 00 32 00 02 10 00
+			05 01 00 00 32 00 02 53 00
+			05 01 00 00 00 00 02 c2 00
+			39 01 00 00 00 00 02 cf 40
+			05 01 00 00 50 00 03 de 84 00
+			39 01 00 00 00 00 02 cb 22
+			05 01 00 00 00 00 02 c3 00];
+
+		qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
+		qcom,mdss-dsi-off-command-state = "dsi_hs_mode";
+		qcom,mdss-dsi-h-sync-pulse = <1>;
+		qcom,mdss-dsi-traffic-mode = <2>;
+		qcom,mdss-dsi-lane-map = <0>;
+		qcom,mdss-dsi-bllp-eof-power-mode;
+		qcom,mdss-dsi-lane-0-state;
+		qcom,mdss-dsi-lane-1-state;
+		qcom,mdss-dsi-lane-2-state;
+		qcom,mdss-dsi-lane-3-state;
+		qcom,mdss-dsi-panel-timings = [a8 1f 17 00 2f 2d 1c 21 29 03 04 00];
+		qcom,mdss-dsi-t-clk-post = <0x20>;
+		qcom,mdss-dsi-t-clk-pre = <0x2f>;
+		qcom,mdss-dsi-bl-min-level = <1>;
+		qcom,mdss-dsi-bl-max-level = <4095>;
+		qcom,mdss-dsi-dma-trigger = <4>;
+		qcom,mdss-dsi-mdp-trigger = <0>;
+		qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
+	};
+};
diff --git a/arch/arm/boot/dts/dsi-panel-truly-wvga-cmd.dtsi b/arch/arm/boot/dts/dsi-panel-truly-wvga-cmd.dtsi
new file mode 100644
index 0000000..f6e6df8
--- /dev/null
+++ b/arch/arm/boot/dts/dsi-panel-truly-wvga-cmd.dtsi
@@ -0,0 +1,170 @@
+/* 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.
+ */
+
+/*---------------------------------------------------------------------------
+ * This file is autogenerated file using gcdb parser. Please do not edit it.
+ * Update input XML file to add a new entry or update variable in this file
+ * VERSION = "1.0"
+ *---------------------------------------------------------------------------*/
+&mdss_mdp {
+	dsi_truly_wvga_cmd: qcom,mdss_dsi_truly_wvga_cmd {
+		qcom,mdss-dsi-panel-name = "Truly WVGA command mode dsi panel";
+		qcom,mdss-dsi-panel-controller = <&mdss_dsi0>;
+		qcom,mdss-dsi-panel-type = "dsi_cmd_mode";
+		qcom,mdss-dsi-panel-destination = "display_1";
+		qcom,mdss-dsi-panel-mode-gpio-state = "low";
+		qcom,mdss-dsi-panel-framerate = <60>;
+		qcom,mdss-dsi-virtual-channel-id = <0>;
+		qcom,mdss-dsi-stream = <0>;
+		qcom,mdss-dsi-panel-width = <480>;
+		qcom,mdss-dsi-panel-height = <800>;
+		qcom,mdss-dsi-h-front-porch = <160>;
+		qcom,mdss-dsi-h-back-porch = <40>;
+		qcom,mdss-dsi-h-pulse-width = <8>;
+		qcom,mdss-dsi-h-sync-skew = <0>;
+		qcom,mdss-dsi-v-back-porch = <10>;
+		qcom,mdss-dsi-v-front-porch = <12>;
+		qcom,mdss-dsi-v-pulse-width = <2>;
+		qcom,mdss-dsi-h-left-border = <0>;
+		qcom,mdss-dsi-h-right-border = <0>;
+		qcom,mdss-dsi-v-top-border = <0>;
+		qcom,mdss-dsi-v-bottom-border = <0>;
+		qcom,mdss-dsi-bpp = <24>;
+		qcom,mdss-dsi-color-order = <0>;
+		qcom,mdss-dsi-underflow-color = <0xff>;
+		qcom,mdss-dsi-border-color = <0>;
+		qcom,mdss-dsi-on-command = [
+					05 01 00 00 00 00 02
+						01 00
+					23 01 00 00 00 00 02
+						b0 04
+					29 01 00 00 00 00 03
+						b3 02 00
+					29 01 00 00 00 00 03
+						b6 51 83
+					29 01 00 00 00 00 05
+						b7 00 80 15 25
+					29 01 00 00 00 00 14
+						b8 00 07 07 ff c8 c8 01 18 10 10
+						37 5a 87 de ff 00 00 00 00
+					29 01 00 00 00 00 05
+						b9 00 00 00 00
+					23 01 00 00 00 00 02
+						bd 00
+					29 01 00 00 00 00 03
+						c0 02 43
+					29 01 00 00 00 00 10
+						c1 43 31 99 21 20 00 10 28 0c 0c
+						00 00 00 21 01
+					29 01 00 00 00 00 07
+						c2 28 06 06 01 03 00
+					29 01 00 00 00 00 04
+						c3 40 00 03
+					29 01 00 00 00 00 03
+						6f 03 00
+					29 01 00 00 00 00 03
+						c4 00 01
+					29 01 00 00 00 00 03
+						c6 00 00
+					29 01 00 00 00 00 06
+						c7 11 8d a0 f5 27
+					29 01 00 00 00 00 19
+						c8 01 0a 12 1c 2b 45 3f 29 17 13
+						0f 04 01 0a 12 1c 2b 45 3f 29 17 13 0f 04
+					29 01 00 00 00 00 19
+						c9 01 0a 12 1c 2b 45 3f 29 17 13
+						0f 04 01 0a 12 1c 2b 45 3f 29 17 13 0f 04
+					29 01 00 00 00 00 19
+						ca 01 0a 12 1c 2b 45 3f 29 17 13
+						0f 04 01 0a 12 1c 2b 45 3f 29 17 13 0f 04
+					29 01 00 00 00 00 11
+						d0 99 03 ce a6 00 43 20 10 01 00
+						01 01 00 03 01 00
+					29 01 00 00 00 00 08
+						d1 18 0C 23 03 75 02 50
+					23 01 00 00 00 00 02
+						d3 33
+					29 01 00 00 00 00 03
+						d5 2a 2a
+					29 01 00 00 00 00 02
+						d6 28
+					29 01 00 00 00 00 10
+						d7 01 00 aa c0 2a 2c 22	12 71 0a 12 00 a0
+						00 03
+					29 01 00 00 00 00 09
+						d8 44 44 22 44 21 46 42 40
+					29 01 00 00 00 00 04
+						d9 cf 2d 51
+					29 01 00 00 00 00 02
+						da 01
+					29 01 00 00 00 00 03
+						de 01 4f
+					29 01 00 00 00 00 07
+						e1 00 00 00 00 00 00
+					23 01 00 00 00 00 02
+						e6 4f
+					29 01 00 00 00 00 06
+						f3 06 00 00 24 00
+					29 01 00 00 00 00 02
+						f8 00
+					23 01 00 00 00 00 02
+						fa 03
+					29 01 00 00 00 00 04
+						fb 00 00 00
+					29 01 00 00 00 00 06
+						fc 00 00 00 00 00
+					29 01 00 00 00 00 05
+						fd 00 00 70 00
+					39 01 00 00 00 00 05
+						2a 00 00 01 df
+					39 01 00 00 00 00 05
+						2b 00 00 03 1f
+					15 01 00 00 00 00 02
+						35 00
+					39 01 00 00 00 00 03
+						44 00 50
+					15 01 00 00 00 00 02
+						36 41
+					15 01 00 00 00 00 02
+						3a 77
+					05 01 00 00 7D 00 02
+						11 00
+					05 01 00 00 3c 00 02
+						29 00
+					];
+		qcom,mdss-dsi-off-command = [05 01 00 00 32 00 02 28 00
+				05 01 00 00 78 00 02 10 00];
+		qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
+		qcom,mdss-dsi-off-command-state = "dsi_lp_mode";
+		qcom,mdss-dsi-h-sync-pulse = <0>;
+		qcom,mdss-dsi-traffic-mode = <1>;
+		qcom,mdss-dsi-lane-map = <0>;
+		qcom,mdss-dsi-bllp-eof-power-mode;
+		qcom,mdss-dsi-bllp-power-mode;
+		qcom,mdss-dsi-lane-0-state;
+		qcom,mdss-dsi-lane-1-state;
+		qcom,mdss-dsi-te-pin-select = <1>;
+		qcom,mdss-dsi-te-v-sync-rd-ptr-irq-line = <0x2c>;
+		qcom,mdss-dsi-te-v-sync-continues-lines = <0x3c>;
+		qcom,mdss-dsi-te-dcs-command = <1>;
+		qcom,mdss-dsi-te-check-enable;
+		qcom,mdss-dsi-te-using-te-pin;
+		qcom,mdss-dsi-panel-timings = [5D 12 0C 00 33 38 10 16 1E 03 04 00];
+		qcom,mdss-dsi-t-clk-post = <0x04>;
+		qcom,mdss-dsi-t-clk-pre = <0x1b>;
+		qcom,mdss-dsi-bl-min-level = <1>;
+		qcom,mdss-dsi-bl-max-level = <255>;
+		qcom,mdss-dsi-dma-trigger = <4>;
+		qcom,mdss-dsi-mdp-trigger = <2>;
+		qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
+	};
+};
diff --git a/arch/arm/boot/dts/dsi-panel-truly-wvga-video.dtsi b/arch/arm/boot/dts/dsi-panel-truly-wvga-video.dtsi
new file mode 100644
index 0000000..fae4834
--- /dev/null
+++ b/arch/arm/boot/dts/dsi-panel-truly-wvga-video.dtsi
@@ -0,0 +1,168 @@
+/* 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.
+ */
+
+/*---------------------------------------------------------------------------
+ * This file is autogenerated file using gcdb parser. Please do not edit it.
+ * Update input XML file to add a new entry or update variable in this file
+ * VERSION = "1.0"
+ *---------------------------------------------------------------------------*/
+&mdss_mdp {
+	dsi_truly_wvga_vid: qcom,mdss_dsi_truly_wvga_video {
+		qcom,mdss-dsi-panel-name = "Truly WVGA video mode dsi panel";
+		qcom,mdss-dsi-panel-controller = <&mdss_dsi0>;
+		qcom,mdss-dsi-panel-type = "dsi_video_mode";
+		qcom,mdss-dsi-panel-destination = "display_1";
+		qcom,mdss-dsi-panel-mode-gpio-state = "high";
+		qcom,mdss-dsi-panel-framerate = <60>;
+		qcom,mdss-dsi-virtual-channel-id = <0>;
+		qcom,mdss-dsi-stream = <0>;
+		qcom,mdss-dsi-panel-width = <480>;
+		qcom,mdss-dsi-panel-height = <800>;
+		qcom,mdss-dsi-h-front-porch = <160>;
+		qcom,mdss-dsi-h-back-porch = <40>;
+		qcom,mdss-dsi-h-pulse-width = <8>;
+		qcom,mdss-dsi-h-sync-skew = <0>;
+		qcom,mdss-dsi-v-back-porch = <10>;
+		qcom,mdss-dsi-v-front-porch = <12>;
+		qcom,mdss-dsi-v-pulse-width = <2>;
+		qcom,mdss-dsi-h-left-border = <0>;
+		qcom,mdss-dsi-h-right-border = <0>;
+		qcom,mdss-dsi-v-top-border = <0>;
+		qcom,mdss-dsi-v-bottom-border = <0>;
+		qcom,mdss-dsi-bpp = <24>;
+		qcom,mdss-dsi-color-order = <0>;
+		qcom,mdss-dsi-underflow-color = <0xff>;
+		qcom,mdss-dsi-border-color = <0>;
+		qcom,mdss-dsi-on-command = [
+					05 01 00 00 00 00 02
+						01 00
+					23 01 00 00 00 00 02
+						b0 04
+					29 01 00 00 00 00 03
+						b3 02 00
+					29 01 00 00 00 00 03
+						b6 51 83
+					29 01 00 00 00 00 05
+						b7 00 80 15 25
+					29 01 00 00 00 00 14
+						b8 00 07 07 ff c8 c8 01 18 10 10
+						37 5a 87 de ff 00 00 00 00
+					29 01 00 00 00 00 05
+						b9 00 00 00 00
+					23 01 00 00 00 00 02
+						bd 00
+					29 01 00 00 00 00 03
+						c0 02 43
+					29 01 00 00 00 00 10
+						c1 43 31 99 21 20 00 10 28 0c 0c
+						00 00 00 21 01
+					29 01 00 00 00 00 07
+						c2 28 06 06 01 03 00
+					29 01 00 00 00 00 04
+						c3 40 00 03
+					29 01 00 00 00 00 03
+						6f 03 00
+					29 01 00 00 00 00 03
+						c4 00 01
+					29 01 00 00 00 00 03
+						c6 00 00
+					29 01 00 00 00 00 06
+						c7 11 8d a0 f5 27
+					29 01 00 00 00 00 19
+						c8 01 0a 12 1c 2b 45 3f 29 17 13
+						0f 04 01 0a 12 1c 2b 45 3f 29 17 13 0f 04
+					29 01 00 00 00 00 19
+						c9 01 0a 12 1c 2b 45 3f 29 17 13
+						0f 04 01 0a 12 1c 2b 45 3f 29 17 13 0f 04
+					29 01 00 00 00 00 19
+						ca 01 0a 12 1c 2b 45 3f 29 17 13
+						0f 04 01 0a 12 1c 2b 45 3f 29 17 13 0f 04
+					29 01 00 00 00 00 11
+						d0 99 03 ce a6 00 43 20 10 01 00
+						01 01 00 03 01 00
+					29 01 00 00 00 00 08
+						d1 18 0C 23 03 75 02 50
+					23 01 00 00 00 00 02
+						d3 33
+					29 01 00 00 00 00 03
+						d5 2a 2a
+					29 01 00 00 00 00 02
+						d6 28
+					29 01 00 00 00 00 10
+						d7 01 00 aa c0 2a 2c 22	12 71 0a 12 00 a0
+						00 03
+					29 01 00 00 00 00 09
+						d8 44 44 22 44 21 46 42 40
+					29 01 00 00 00 00 04
+						d9 cf 2d 51
+					29 01 00 00 00 00 02
+						da 01
+					29 01 00 00 00 00 03
+						de 01 4f
+					29 01 00 00 00 00 07
+						e1 00 00 00 00 00 00
+					23 01 00 00 00 00 02
+						e6 4f
+					29 01 00 00 00 00 06
+						f3 06 00 00 24 00
+					29 01 00 00 00 00 02
+						f8 00
+					23 01 00 00 00 00 02
+						fa 03
+					29 01 00 00 00 00 04
+						fb 00 00 00
+					29 01 00 00 00 00 06
+						fc 00 00 00 00 00
+					29 01 00 00 00 00 05
+						fd 00 00 70 00
+					39 01 00 00 00 00 05
+						2a 00 00 01 df
+					39 01 00 00 00 00 05
+						2b 00 00 03 1f
+					15 01 00 00 00 00 02
+						35 00
+					39 01 00 00 00 00 03
+						44 00 50
+					15 01 00 00 00 00 02
+						36 c1
+					15 01 00 00 00 00 02
+						3a 77
+					05 01 00 00 7D 00 02
+						11 00
+					05 01 00 00 3c 00 02
+						29 00
+					];
+		qcom,mdss-dsi-off-command = [05 01 00 00 32 00 02 28 00
+					05 01 00 00 78 00 02 10 00
+					23 01 00 00 10 00 02
+						b0 04
+					23 01 00 00 20 00 02
+						b1 01];
+		qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
+		qcom,mdss-dsi-off-command-state = "dsi_lp_mode";
+		qcom,mdss-dsi-h-sync-pulse = <0>;
+		qcom,mdss-dsi-traffic-mode = <1>;
+		qcom,mdss-dsi-lane-map = <0>;
+		qcom,mdss-dsi-bllp-eof-power-mode;
+		qcom,mdss-dsi-bllp-power-mode;
+		qcom,mdss-dsi-lane-0-state;
+		qcom,mdss-dsi-lane-1-state;
+		qcom,mdss-dsi-panel-timings = [5D 12 0C 00 33 38 10 16 1E 03 04 00];
+		qcom,mdss-dsi-t-clk-post = <0x04>;
+		qcom,mdss-dsi-t-clk-pre = <0x1b>;
+		qcom,mdss-dsi-bl-min-level = <1>;
+		qcom,mdss-dsi-bl-max-level = <255>;
+		qcom,mdss-dsi-dma-trigger = <4>;
+		qcom,mdss-dsi-mdp-trigger = <0>;
+		qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
+	};
+};
diff --git a/arch/arm/boot/dts/msm-pm8110.dtsi b/arch/arm/boot/dts/msm-pm8110.dtsi
index 1820dc7..6969940 100644
--- a/arch/arm/boot/dts/msm-pm8110.dtsi
+++ b/arch/arm/boot/dts/msm-pm8110.dtsi
@@ -315,7 +315,7 @@
 			qcom,v-cutoff-uv = <3400000>;
 			qcom,max-voltage-uv = <4200000>;
 			qcom,r-conn-mohm = <0>;
-			qcom,shutdown-soc-valid-limit = <20>;
+			qcom,shutdown-soc-valid-limit = <100>;
 			qcom,adjust-soc-low-threshold = <15>;
 			qcom,ocv-voltage-high-threshold-uv = <3750000>;
 			qcom,ocv-voltage-low-threshold-uv = <3650000>;
diff --git a/arch/arm/boot/dts/msm-pm8226.dtsi b/arch/arm/boot/dts/msm-pm8226.dtsi
index 5642d4d..ba1bf08 100644
--- a/arch/arm/boot/dts/msm-pm8226.dtsi
+++ b/arch/arm/boot/dts/msm-pm8226.dtsi
@@ -189,7 +189,7 @@
 			qcom,v-cutoff-uv = <3400000>;
 			qcom,max-voltage-uv = <4200000>;
 			qcom,r-conn-mohm = <0>;
-			qcom,shutdown-soc-valid-limit = <20>;
+			qcom,shutdown-soc-valid-limit = <100>;
 			qcom,adjust-soc-low-threshold = <15>;
 			qcom,ocv-voltage-high-threshold-uv = <3750000>;
 			qcom,ocv-voltage-low-threshold-uv = <3650000>;
@@ -831,10 +831,10 @@
 			pm8226_flash0: qcom,flash_0 {
 				qcom,max-current = <1000>;
 				qcom,default-state = "off";
-				qcom,headroom = <0>;
+				qcom,headroom = <3>;
 				qcom,duration = <1280>;
 				qcom,clamp-curr = <200>;
-				qcom,startup-dly = <1>;
+				qcom,startup-dly = <3>;
 				qcom,safety-timer;
 				label = "flash";
 				linux,default-trigger =
@@ -847,10 +847,10 @@
 			pm8226_flash1: qcom,flash_1 {
 				qcom,max-current = <1000>;
 				qcom,default-state = "off";
-				qcom,headroom = <0>;
+				qcom,headroom = <3>;
 				qcom,duration = <1280>;
 				qcom,clamp-curr = <200>;
-				qcom,startup-dly = <1>;
+				qcom,startup-dly = <3>;
 				qcom,safety-timer;
 				linux,default-trigger =
 						"flash1_trigger";
diff --git a/arch/arm/boot/dts/msm-pm8941.dtsi b/arch/arm/boot/dts/msm-pm8941.dtsi
index 583cd3c..98d2f5e 100644
--- a/arch/arm/boot/dts/msm-pm8941.dtsi
+++ b/arch/arm/boot/dts/msm-pm8941.dtsi
@@ -120,7 +120,7 @@
 		qcom,v-cutoff-uv = <3400000>;
 		qcom,max-voltage-uv = <4200000>;
 		qcom,r-conn-mohm = <0>;
-		qcom,shutdown-soc-valid-limit = <20>;
+		qcom,shutdown-soc-valid-limit = <100>;
 		qcom,adjust-soc-low-threshold = <15>;
 		qcom,ocv-voltage-high-threshold-uv = <3750000>;
 		qcom,ocv-voltage-low-threshold-uv = <3650000>;
diff --git a/arch/arm/boot/dts/msm8226-camera-sensor-cdp.dtsi b/arch/arm/boot/dts/msm8226-camera-sensor-cdp.dtsi
index 5d7a7ec..fa5c739 100644
--- a/arch/arm/boot/dts/msm8226-camera-sensor-cdp.dtsi
+++ b/arch/arm/boot/dts/msm8226-camera-sensor-cdp.dtsi
@@ -31,6 +31,13 @@
 		qcom,cci-master = <0>;
 	};
 
+	actuator1: qcom,actuator@36 {
+		cell-index = <1>;
+		reg = <0x36>;
+		compatible = "qcom,actuator";
+		qcom,cci-master = <0>;
+	};
+
 	qcom,camera@6f {
 		compatible = "qcom,ov8825";
 		reg = <0x6f>;
@@ -75,6 +82,7 @@
 		qcom,slave-id = <0x20 0x0016 0x0135>;
 		qcom,csiphy-sd-index = <0>;
 		qcom,csid-sd-index = <0>;
+		qcom,actuator-src = <&actuator1>;
 		qcom,mount-angle = <90>;
 		qcom,sensor-name = "imx135";
 		cam_vdig-supply = <&pm8226_l5>;
diff --git a/arch/arm/boot/dts/msm8226-camera-sensor-qrd.dtsi b/arch/arm/boot/dts/msm8226-camera-sensor-qrd.dtsi
index 3eacef2..fd6d618 100644
--- a/arch/arm/boot/dts/msm8226-camera-sensor-qrd.dtsi
+++ b/arch/arm/boot/dts/msm8226-camera-sensor-qrd.dtsi
@@ -402,7 +402,7 @@
 	};
 
 	qcom,camera@6a {
-		compatible = "qcom,ov5648";
+		compatible = "ovti,ov5648";
 		reg = <0x6a>;
 		qcom,slave-id = <0x6c 0x300a 0x5648>;
 		qcom,csiphy-sd-index = <1>;
diff --git a/arch/arm/boot/dts/msm8226-cdp.dtsi b/arch/arm/boot/dts/msm8226-cdp.dtsi
index 066d6c2..d377bf0 100644
--- a/arch/arm/boot/dts/msm8226-cdp.dtsi
+++ b/arch/arm/boot/dts/msm8226-cdp.dtsi
@@ -29,6 +29,8 @@
 			synaptics,irq-gpio = <&msmgpio 17 0x2008>;
 			synaptics,button-map = <139 102 158>;
 			synaptics,i2c-pull-up;
+			synaptics,power-down;
+			synaptics,disable-gpios;
 		};
 	};
 
diff --git a/arch/arm/boot/dts/msm8226-mdss-panels.dtsi b/arch/arm/boot/dts/msm8226-mdss-panels.dtsi
index 8194bf6..eeec175 100644
--- a/arch/arm/boot/dts/msm8226-mdss-panels.dtsi
+++ b/arch/arm/boot/dts/msm8226-mdss-panels.dtsi
@@ -15,3 +15,4 @@
 /include/ "dsi-panel-nt35521-720p-video.dtsi"
 /include/ "dsi-panel-nt35596-1080p-video.dtsi"
 /include/ "dsi-panel-nt35590-720p-cmd.dtsi"
+/include/ "dsi-panel-ssd2080m-720p-video.dtsi"
diff --git a/arch/arm/boot/dts/msm8226-mtp.dtsi b/arch/arm/boot/dts/msm8226-mtp.dtsi
index f4f7442..318d4fc 100644
--- a/arch/arm/boot/dts/msm8226-mtp.dtsi
+++ b/arch/arm/boot/dts/msm8226-mtp.dtsi
@@ -29,6 +29,8 @@
 			synaptics,irq-gpio = <&msmgpio 17 0x2008>;
 			synaptics,button-map = <139 102 158>;
 			synaptics,i2c-pull-up;
+			synaptics,power-down;
+			synaptics,disable-gpios;
 		};
 	};
 
diff --git a/arch/arm/boot/dts/msm8226-qrd.dtsi b/arch/arm/boot/dts/msm8226-qrd.dtsi
index c178dbf..18a1aea 100644
--- a/arch/arm/boot/dts/msm8226-qrd.dtsi
+++ b/arch/arm/boot/dts/msm8226-qrd.dtsi
@@ -29,7 +29,10 @@
 			synaptics,irq-gpio = <&msmgpio 17 0x2008>;
 			synaptics,button-map = <139 102 158>;
 			synaptics,i2c-pull-up;
+			synaptics,power-down;
+			synaptics,disable-gpios;
 		};
+
 		focaltech@38 {
 			compatible = "focaltech,5x06";
 			reg = <0x38>;
@@ -114,10 +117,10 @@
 			"MIC BIAS1 External", "Handset Mic",
 			"AMIC2", "MIC BIAS2 External",
 			"MIC BIAS2 External", "Headset Mic",
-			"AMIC4", "MIC BIAS2 External",
-			"MIC BIAS2 External", "ANCRight Headset Mic",
-			"AMIC5", "MIC BIAS2 External",
-			"MIC BIAS2 External", "ANCLeft Headset Mic";
+			"AMIC3", "MIC BIAS1 External",
+			"MIC BIAS1 External", "Analog Mic3",
+			"AMIC4", "MIC BIAS3 External",
+			"MIC BIAS3 External", "Analog Mic4";
 
 		qcom,cdc-mclk-gpios = <&pm8226_gpios 1 0>;
 		qcom,cdc-vdd-spkr-gpios = <&pm8226_gpios 2 0>;
@@ -238,7 +241,7 @@
 	qcom,pad-drv-on = <0x4 0x4 0x4>; /* 10mA, 10mA, 10mA */
 	qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
 
-	qcom,clk-rates = <400000 25000000 50000000 100000000 200000000>;
+	qcom,clk-rates = <400000 25000000 50000000>;
 
 	#address-cells = <0>;
 	interrupt-parent = <&sdhc_2>;
@@ -454,6 +457,7 @@
 &slim_msm {
 	tapan_codec {
 		qcom,cdc-micbias1-ext-cap;
+		qcom,cdc-micbias3-ext-cap;
 	};
 };
 
@@ -472,6 +476,7 @@
 
 &android_usb {
 	qcom,android-usb-cdrom;
+	qcom,android-usb-internal-ums;
 };
 
 &mdss_mdp {
diff --git a/arch/arm/boot/dts/msm8226-regulator.dtsi b/arch/arm/boot/dts/msm8226-regulator.dtsi
index 5b3da9b..838592c 100644
--- a/arch/arm/boot/dts/msm8226-regulator.dtsi
+++ b/arch/arm/boot/dts/msm8226-regulator.dtsi
@@ -41,9 +41,14 @@
 		qcom,pvs-fuse = <22 6 5>;
 		qcom,pvs-fuse-redun = <22 27 5>;
 
-		qcom,pvs-bin-process = <0 0 0 0 0 1 1 1 1 1 2 2 2 2 2 2
-					2 2 2 2 3 3 3 3 3 3 3 3 0 0 0 0>;
-		qcom,pvs-corner-ceiling-slow = <1050000 1160000 1275000>;
+		qcom,pvs-init-voltage = <1275000 1275000 1275000 1275000 1275000
+					1275000 1260000 1245000 1230000 1215000
+					1200000 1185000 1170000 1155000 1140000
+					1140000 1140000 1140000 1140000 1140000
+					1150000 1140000 1140000 1140000 1140000
+					1140000 1140000 1140000 1275000 1275000
+					1275000 1275000>;
+		qcom,pvs-corner-ceiling-slow = <1050000 1150000 1275000>;
 		qcom,pvs-corner-ceiling-nom  = <1050000 1075000 1200000>;
 		qcom,pvs-corner-ceiling-fast = <1050000 1050000 1140000>;
 		vdd-apc-supply = <&pm8226_s2>;
diff --git a/arch/arm/boot/dts/msm8226-v1-cdp.dts b/arch/arm/boot/dts/msm8226-v1-cdp.dts
index c721df2..e426a97 100644
--- a/arch/arm/boot/dts/msm8226-v1-cdp.dts
+++ b/arch/arm/boot/dts/msm8226-v1-cdp.dts
@@ -17,13 +17,5 @@
 / {
 	model = "Qualcomm MSM 8226 CDP";
 	compatible = "qcom,msm8226-cdp", "qcom,msm8226", "qcom,cdp";
-	qcom,msm-id = <145 1 0>,
-		      <158 1 0>,
-		      <159 1 0>,
-		      <198 1 0>,
-		      <205 1 0>,
-		      <220 1 0>,
-		      <221 1 0>,
-		      <222 1 0>,
-		      <223 1 0>;
+	qcom,board-id = <1 0>;
 };
diff --git a/arch/arm/boot/dts/msm8226-v1-mtp.dts b/arch/arm/boot/dts/msm8226-v1-mtp.dts
index 95d88a7..08d7cec 100644
--- a/arch/arm/boot/dts/msm8226-v1-mtp.dts
+++ b/arch/arm/boot/dts/msm8226-v1-mtp.dts
@@ -17,15 +17,7 @@
 / {
 	model = "Qualcomm MSM 8226 MTP";
 	compatible = "qcom,msm8226-mtp", "qcom,msm8226", "qcom,mtp";
-	qcom,msm-id = <145 8 0>,
-		      <158 8 0>,
-		      <159 8 0>,
-		      <198 8 0>,
-		      <205 8 0>,
-		      <220 8 0>,
-		      <221 8 0>,
-		      <222 8 0>,
-		      <223 8 0>;
+	qcom,board-id = <8 0>;
 };
 
 &cci {
diff --git a/arch/arm/boot/dts/msm8226-v1-qrd-dvt.dts b/arch/arm/boot/dts/msm8226-v1-qrd-dvt.dts
index f8fd0c2..7e9f91b 100644
--- a/arch/arm/boot/dts/msm8226-v1-qrd-dvt.dts
+++ b/arch/arm/boot/dts/msm8226-v1-qrd-dvt.dts
@@ -17,15 +17,7 @@
 / {
 	model = "Qualcomm MSM 8226 QRD";
 	compatible = "qcom,msm8226-qrd", "qcom,msm8226", "qcom,qrd";
-	qcom,msm-id = <145 0x2000b 0>,
-		      <158 0x2000b 0>,
-		      <159 0x2000b 0>,
-		      <198 0x2000b 0>,
-		      <205 0x2000b 0>,
-		      <220 0x2000b 0>,
-		      <221 0x2000b 0>,
-		      <222 0x2000b 0>,
-		      <223 0x2000b 0>;
+	qcom,board-id = <0x2000b 0>;
 };
 
 &mdss_dsi0 {
diff --git a/arch/arm/boot/dts/msm8226-v1-qrd-evt.dts b/arch/arm/boot/dts/msm8226-v1-qrd-evt.dts
index bc5d8e7..c93d9db 100644
--- a/arch/arm/boot/dts/msm8226-v1-qrd-evt.dts
+++ b/arch/arm/boot/dts/msm8226-v1-qrd-evt.dts
@@ -17,15 +17,7 @@
 / {
 	model = "Qualcomm MSM 8226 QRD";
 	compatible = "qcom,msm8226-qrd", "qcom,msm8226", "qcom,qrd";
-	qcom,msm-id = <145 11 0>,
-		      <158 11 0>,
-		      <159 11 0>,
-		      <198 11 0>,
-		      <205 11 0>,
-		      <220 11 0>,
-		      <221 11 0>,
-		      <222 11 0>,
-		      <223 11 0>;
+	qcom,board-id = <11 0>;
 };
 
 &mdss_dsi0 {
diff --git a/arch/arm/boot/dts/msm8226-v2-cdp.dts b/arch/arm/boot/dts/msm8226-v2-cdp.dts
index 7c955dd..3d40180 100644
--- a/arch/arm/boot/dts/msm8226-v2-cdp.dts
+++ b/arch/arm/boot/dts/msm8226-v2-cdp.dts
@@ -18,13 +18,5 @@
 / {
 	model = "Qualcomm MSM 8226v2 CDP";
 	compatible = "qcom,msm8226-cdp", "qcom,msm8226", "qcom,cdp";
-	qcom,msm-id = <145 1 0x20000>,
-		      <158 1 0x20000>,
-		      <159 1 0x20000>,
-		      <198 1 0x20000>,
-		      <205 1 0x20000>,
-		      <220 1 0x20000>,
-		      <221 1 0x20000>,
-		      <222 1 0x20000>,
-		      <223 1 0x20000>;
+	qcom,board-id = <1 0>;
 };
diff --git a/arch/arm/boot/dts/msm8226-v2-mtp.dts b/arch/arm/boot/dts/msm8226-v2-mtp.dts
index dfdc5db..6034107 100644
--- a/arch/arm/boot/dts/msm8226-v2-mtp.dts
+++ b/arch/arm/boot/dts/msm8226-v2-mtp.dts
@@ -18,13 +18,5 @@
 / {
 	model = "Qualcomm MSM 8226v2 MTP";
 	compatible = "qcom,msm8226-mtp", "qcom,msm8226", "qcom,mtp";
-	qcom,msm-id = <145 8 0x20000>,
-		      <158 8 0x20000>,
-		      <159 8 0x20000>,
-		      <198 8 0x20000>,
-		      <205 8 0x20000>,
-		      <220 8 0x20000>,
-		      <221 8 0x20000>,
-		      <222 8 0x20000>,
-		      <223 8 0x20000>;
+	qcom,board-id = <8 0>;
 };
diff --git a/arch/arm/boot/dts/msm8226-v2-qrd-dvt.dts b/arch/arm/boot/dts/msm8226-v2-qrd-dvt.dts
index e492720..13402af 100644
--- a/arch/arm/boot/dts/msm8226-v2-qrd-dvt.dts
+++ b/arch/arm/boot/dts/msm8226-v2-qrd-dvt.dts
@@ -17,15 +17,7 @@
 / {
 	model = "Qualcomm MSM 8226v2 QRD";
 	compatible = "qcom,msm8226-qrd", "qcom,msm8226", "qcom,qrd";
-	qcom,msm-id = <145 0x2000b 0x20000>,
-		      <158 0x2000b 0x20000>,
-		      <159 0x2000b 0x20000>,
-		      <198 0x2000b 0x20000>,
-		      <205 0x2000b 0x20000>,
-		      <220 0x2000b 0x20000>,
-		      <221 0x2000b 0x20000>,
-		      <222 0x2000b 0x20000>,
-		      <223 0x2000b 0x20000>;
+	qcom,board-id = <0x2000b 0>;
 };
 
 &mdss_dsi0 {
diff --git a/arch/arm/boot/dts/msm8226-v2-qrd-evt.dts b/arch/arm/boot/dts/msm8226-v2-qrd-evt.dts
index 83c7034..b707d1c 100644
--- a/arch/arm/boot/dts/msm8226-v2-qrd-evt.dts
+++ b/arch/arm/boot/dts/msm8226-v2-qrd-evt.dts
@@ -17,15 +17,7 @@
 / {
 	model = "Qualcomm MSM 8226v2 QRD";
 	compatible = "qcom,msm8226-qrd", "qcom,msm8226", "qcom,qrd";
-	qcom,msm-id = <145 11 0x20000>,
-		      <158 11 0x20000>,
-		      <159 11 0x20000>,
-		      <198 11 0x20000>,
-		      <205 11 0x20000>,
-		      <220 11 0x20000>,
-		      <221 11 0x20000>,
-		      <222 11 0x20000>,
-		      <223 11 0x20000>;
+	qcom,board-id = <11 0>;
 };
 
 &mdss_dsi0 {
diff --git a/arch/arm/boot/dts/msm8226-v2.dtsi b/arch/arm/boot/dts/msm8226-v2.dtsi
index c2ce546..a57adcd 100644
--- a/arch/arm/boot/dts/msm8226-v2.dtsi
+++ b/arch/arm/boot/dts/msm8226-v2.dtsi
@@ -33,28 +33,33 @@
 
 &pm8226_l3 {
 	regulator-min-microvolt = <750000>;
-	regulator-max-microvolt = <1287500>;
+	regulator-max-microvolt = <1337500>;
 };
 
 &pm8226_l3_ao {
 	regulator-min-microvolt = <750000>;
-	regulator-max-microvolt = <1287500>;
+	regulator-max-microvolt = <1337500>;
 };
 
 &pm8226_l3_so {
 	regulator-min-microvolt = <750000>;
-	regulator-max-microvolt = <1287500>;
+	regulator-max-microvolt = <1337500>;
 };
 
 &pm8226_s2 {
 	regulator-min-microvolt = <900000>;
-	regulator-max-microvolt = <1280000>;
+	regulator-max-microvolt = <1330000>;
 };
 
 &apc_vreg_corner {
-	qcom,pvs-bin-process = <1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2
-				2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 3>;
-	qcom,pvs-corner-ceiling-slow = <1050000 1160000 1280000>;
+	qcom,pvs-init-voltage = <1330000 1330000 1330000 1320000 1310000
+					1300000 1290000 1280000 1270000 1260000
+					1250000 1240000 1230000 1220000 1210000
+					1200000 1190000 1180000 1170000 1160000
+					1150000 1140000 1140000 1140000 1140000
+					1140000 1140000 1140000 1140000 1140000
+					1140000 1140000>;
+	qcom,pvs-corner-ceiling-slow = <1050000 1150000 1280000>;
 	qcom,pvs-corner-ceiling-nom  = <1050000 1080000 1200000>;
 	qcom,pvs-corner-ceiling-fast = <1050000 1050000 1140000>;
 	qcom,cpr-step-quotient = <30>;
diff --git a/arch/arm/boot/dts/msm8226.dtsi b/arch/arm/boot/dts/msm8226.dtsi
index 7b944fc..cfb6bed 100644
--- a/arch/arm/boot/dts/msm8226.dtsi
+++ b/arch/arm/boot/dts/msm8226.dtsi
@@ -33,7 +33,7 @@
 
 		adsp_mem: adsp_region {
 			linux,contiguous-region;
-			reg = <0 0xc00000>;
+			reg = <0 0x2a00000>;
 			label = "adsp_mem";
 		};
 
@@ -201,6 +201,12 @@
 		};
 	};
 
+	qcom,vidc {
+		compatible = "qcom,msm-vidc";
+		qcom,hfi = "q6";
+		qcom,max-hw-load = <108000>; /* 720p @ 30 * 1  */
+	};
+
 	qcom,wfd {
 		compatible = "qcom,msm-wfd";
 	};
@@ -438,6 +444,10 @@
 		qcom,msm-dai-q6-dev-id = <8>;
 	};
 
+	qcom,msm-lsm-client {
+		compatible = "qcom,msm-lsm-client";
+	};
+
 	qcom,msm-dai-q6 {
 		compatible = "qcom,msm-dai-q6";
 		qcom,msm-dai-q6-sb-0-rx {
@@ -480,6 +490,11 @@
 			qcom,msm-dai-q6-dev-id = <16393>;
 		};
 
+		qcom,msm-dai-q6-sb-5-tx {
+                        compatible = "qcom,msm-dai-q6-dev";
+                        qcom,msm-dai-q6-dev-id = <16395>;
+                };
+
 		qcom,msm-dai-q6-bt-sco-rx {
 			compatible = "qcom,msm-dai-q6-dev";
 			qcom,msm-dai-q6-dev-id = <12288>;
@@ -576,6 +591,7 @@
 		gpios = <&msmgpio 40 0>, <&msmgpio 41 0>, <&msmgpio 42 0>, <&msmgpio 43 0>, <&msmgpio 44 0>;
 		qcom,has-pronto-hw;
 		qcom,has-autodetect-xo;
+		qcom,wcnss-adc_tm = <&pm8226_adc_tm>;
 	};
 
 	qcom,msm-adsp-sensors {
diff --git a/arch/arm/boot/dts/msm8610-camera-sensor-cdp-mtp.dtsi b/arch/arm/boot/dts/msm8610-camera-sensor-cdp-mtp.dtsi
index 1b4a594..e133117 100644
--- a/arch/arm/boot/dts/msm8610-camera-sensor-cdp-mtp.dtsi
+++ b/arch/arm/boot/dts/msm8610-camera-sensor-cdp-mtp.dtsi
@@ -38,6 +38,78 @@
 		qcom,cci-master = <0>;
 	};
 
+	eeprom0: qcom,eeprom@6a {
+		cell-index = <0>;
+		reg = <0x6a 0x0>;
+		qcom,eeprom-name = "truly_cm7700";
+		compatible = "qcom,msm_eeprom";
+		qcom,slave-addr = <0x6c>;
+		qcom,num-blocks = <9>;
+		qcom,page0 = <1 0x0100 2 0x01 1 1>;
+		qcom,poll0 = <0 0x0 2 0 1 1>;
+		qcom,mem0 = <0 0x0 2 0 1 0>;
+		qcom,page1 = <1 0x3d84 2 0x8 1 1>;
+		qcom,pageen1 = <1 0x3d81 2 0x01 1 10>;
+		qcom,poll1 = <0 0x0 2 0 1 1>;
+		qcom,mem1 = <32 0x3d00 2 0 1 0>;
+		qcom,page2 = <1 0x3d84 2 0x9 1 1>;
+		qcom,pageen2 = <1 0x3d81 2 0x01 1 10>;
+		qcom,poll2 = <0 0x0 2 0 1 1>;
+		qcom,mem2 = <32 0x3d00 2 0 1 0>;
+		qcom,page3 = <1 0x3d84 2 0xa 1 1>;
+		qcom,pageen3 = <1 0x3d81 2 0x01 1 10>;
+		qcom,poll3 = <0 0x0 2 0 1 1>;
+		qcom,mem3 = <32 0x3d00 2 0 1 0>;
+		qcom,page4 = <1 0x3d84 2 0xb 1 1>;
+		qcom,pageen4 = <1 0x3d81 2 0x01 1 10>;
+		qcom,poll4 = <0 0x0 2 0 1 1>;
+		qcom,mem4 = <32 0x3d00 2 0 1 0>;
+		qcom,page5 = <1 0x3d84 2 0xc 1 1>;
+		qcom,pageen5 = <1 0x3d81 2 0x01 1 10>;
+		qcom,poll5 = <0 0x0 2 0 1 1>;
+		qcom,mem5 = <32 0x3d00 2 0 1 0>;
+		qcom,page6 = <1 0x3d84 2 0xd 1 1>;
+		qcom,pageen6 = <1 0x3d81 2 0x01 1 10>;
+		qcom,poll6 = <0 0x0 2 0 1 1>;
+		qcom,mem6 = <32 0x3d00 2 0 1 0>;
+		qcom,page7 = <1 0x3d84 2 0xe 1 1>;
+		qcom,pageen7 = <1 0x3d81 2 0x01 1 10>;
+		qcom,poll7 = <0 0x0 2 0 1 1>;
+		qcom,mem7 = <32 0x3d00 2 0 1 0>;
+		qcom,page8 = <1 0x3d84 2 0xf 1 1>;
+		qcom,pageen8 = <1 0x3d81 2 0x01 1 10>;
+		qcom,poll8 = <0 0x0 2 0 1 1>;
+		qcom,mem8 = <32 0x3d00 2 0 1 0>;
+
+		cam_vdig-supply = <&pm8110_l2>;
+		cam_vio-supply = <&pm8110_l14>;
+		qcom,cam-vreg-name = "cam_vdig", "cam_vio";
+		qcom,cam-vreg-type = <0 0 0 0>;
+		qcom,cam-vreg-min-voltage = <1200000 1800000>;
+		qcom,cam-vreg-max-voltage = <1200000 1800000>;
+		qcom,cam-vreg-op-mode = <200000 8000>;
+		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,cam-power-seq-type = "sensor_vreg",
+			"sensor_vreg", "sensor_clk",
+			"sensor_gpio", "sensor_gpio";
+		qcom,cam-power-seq-val = "cam_vdig",
+			"cam_vio", "sensor_cam_mclk",
+			"sensor_gpio_reset",
+			"sensor_gpio_standby";
+		qcom,cam-power-seq-cfg-val = <1 1 24000000 1 1>;
+		qcom,cam-power-seq-delay = <1 1 5 5 10>;
+	};
+
 	qcom,camera@6f {
 		compatible = "qcom,ov8825";
 		reg = <0x6f>;
@@ -46,6 +118,7 @@
 		qcom,csid-sd-index = <0>;
 		qcom,actuator-src = <&actuator0>;
 		qcom,led-flash-src = <&led_flash0>;
+		qcom,eeprom-src = <&eeprom0>;
 		qcom,mount-angle = <90>;
 		qcom,sensor-name = "ov8825";
 		cam_vdig-supply = <&pm8110_l2>;
diff --git a/arch/arm/boot/dts/msm8610-cdp.dtsi b/arch/arm/boot/dts/msm8610-cdp.dtsi
index cc4d93b..4e0ee32 100644
--- a/arch/arm/boot/dts/msm8610-cdp.dtsi
+++ b/arch/arm/boot/dts/msm8610-cdp.dtsi
@@ -76,6 +76,21 @@
 				];
 			};
 		};
+
+		synaptics@20 {
+			compatible = "synaptics,rmi4";
+			reg = <0x20>;
+			interrupt-parent = <&msmgpio>;
+			interrupts = <1 0x2008>;
+			vdd-supply = <&pm8110_l19>;
+			vcc_i2c-supply = <&pm8110_l14>;
+			synaptics,reset-gpio = <&msmgpio 0 0x00>;
+			synaptics,irq-gpio = <&msmgpio 1 0x2008>;
+			synaptics,button-map = <139 102 158>;
+			synaptics,i2c-pull-up;
+			synaptics,power-down;
+			synaptics,disable-gpios;
+		};
 	};
 
 	gen-vkeys {
@@ -131,10 +146,6 @@
 			"AMIC2", "MIC BIAS Internal2";
 		qcom,headset-jack-type-NC;
     };
-
-	qcom,dsi_v2_truly_wvga_video {
-		qcom,cont-splash-enabled;
-	};
 };
 
 &i2c_cdc  {
@@ -176,6 +187,7 @@
 
 		qcom,cdc-on-demand-supplies = "cdc-vdda-cp",
 					      "cdc-vdd-mic-bias";
+		qcom,cdc-micbias1-ext-cap;
 	};
 
 	msm8x10_wcd_codec@77{
@@ -400,3 +412,19 @@
 	qcom,setb-gpios-pull = <0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0>;
 	qcom,setb-gpios-dir =  <2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2>;
 };
+
+&mdss_mdp {
+	qcom,mdss-pref-prim-intf = "dsi";
+};
+
+&mdss_dsi0 {
+	qcom,dsi-pref-prim-pan = <&dsi_truly_wvga_vid>;
+};
+
+&dsi_truly_wvga_vid {
+	qcom,cont-splash-enabled;
+};
+
+&dsi_truly_wvga_cmd {
+	qcom,cont-splash-enabled;
+};
diff --git a/arch/arm/boot/dts/msm8610-mdss-panels.dtsi b/arch/arm/boot/dts/msm8610-mdss-panels.dtsi
new file mode 100644
index 0000000..243d7e8
--- /dev/null
+++ b/arch/arm/boot/dts/msm8610-mdss-panels.dtsi
@@ -0,0 +1,17 @@
+/* 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-truly-wvga-video.dtsi"
+/include/ "dsi-panel-truly-wvga-cmd.dtsi"
+/include/ "dsi-panel-nt35590-720p-video.dtsi"
+/include/ "dsi-panel-otm8018b-fwvga-video.dtsi"
+/include/ "dsi-panel-hx8379a-wvga-video.dtsi"
diff --git a/arch/arm/boot/dts/msm8610-mdss.dtsi b/arch/arm/boot/dts/msm8610-mdss.dtsi
index d0fc1dc..f37a42b 100644
--- a/arch/arm/boot/dts/msm8610-mdss.dtsi
+++ b/arch/arm/boot/dts/msm8610-mdss.dtsi
@@ -11,7 +11,7 @@
  */
 
 &soc {
-	qcom,mdss_mdp@fd900000 {
+	mdss_mdp: qcom,mdss_mdp@fd900000 {
 		compatible = "qcom,mdss_mdp3";
 		reg = <0xfd900000 0x100000>;
 		reg-names = "mdp_phys";
@@ -29,7 +29,62 @@
 		cell-index = <0>;
 		reg = <0xfdd00000 0x100000>;
 		interrupts = <0 30 0>;
-		vdda-supply = <&pm8110_l4>;
+		vdd-supply = <&pm8110_l4>;
+		vdda-supply = <&pm8110_l19>;
+		vddio-supply = <&pm8110_l14>;
 		qcom,mdss-fb-map = <&mdss_fb0>;
+		qcom,mdss-mdp = <&mdss_mdp>;
+		qcom,platform-reset-gpio = <&msmgpio 41 0>;
+		qcom,platform-te-gpio = <&msmgpio 12 0>;
+		qcom,platform-mode-gpio = <&msmgpio 7 0>;
+
+		qcom,platform-reset-sequence = <1 20 0 2 1 20 2>;
+
+		qcom,platform-strength-ctrl = [ff 06];
+		qcom,platform-bist-ctrl = [03 03 00 00 0f 00];
+		qcom,platform-regulator-settings = [02 08 05 00 20 03];
+		qcom,platform-lane-config = [80 45 00 00 01 66
+		80 45 00 00 01 66
+		80 45 00 00 01 66
+		80 45 00 00 01 66
+		40 67 00 00 01 88];
+
+		qcom,platform-supply-entry1 {
+			qcom,supply-name = "vdd";
+			qcom,supply-min-voltage = <1200000>;
+			qcom,supply-max-voltage = <1200000>;
+			qcom,supply-enable-load = <100000>;
+			qcom,supply-disable-load = <100>;
+			qcom,supply-pre-on-sleep = <0>;
+			qcom,supply-post-on-sleep = <20>;
+			qcom,supply-pre-off-sleep = <0>;
+			qcom,supply-post-off-sleep = <20>;
+		};
+
+		qcom,platform-supply-entry2 {
+			qcom,supply-name = "vddio";
+			qcom,supply-min-voltage = <1800000>;
+			qcom,supply-max-voltage = <1800000>;
+			qcom,supply-enable-load = <100000>;
+			qcom,supply-disable-load = <100>;
+			qcom,supply-pre-on-sleep = <0>;
+			qcom,supply-post-on-sleep = <0>;
+			qcom,supply-pre-off-sleep = <0>;
+			qcom,supply-post-off-sleep = <0>;
+		};
+
+		qcom,platform-supply-entry3 {
+			qcom,supply-name = "vdda";
+			qcom,supply-min-voltage = <2850000>;
+			qcom,supply-max-voltage = <2850000>;
+			qcom,supply-enable-load = <100000>;
+			qcom,supply-disable-load = <100>;
+			qcom,supply-pre-on-sleep = <0>;
+			qcom,supply-post-on-sleep = <0>;
+			qcom,supply-pre-off-sleep = <0>;
+			qcom,supply-post-off-sleep = <0>;
+		};
 	};
 };
+
+/include/ "msm8610-mdss-panels.dtsi"
diff --git a/arch/arm/boot/dts/msm8610-mtp.dtsi b/arch/arm/boot/dts/msm8610-mtp.dtsi
index 798fab4..82f5aea 100644
--- a/arch/arm/boot/dts/msm8610-mtp.dtsi
+++ b/arch/arm/boot/dts/msm8610-mtp.dtsi
@@ -76,6 +76,21 @@
 				];
 			};
 		};
+
+		synaptics@20 {
+			compatible = "synaptics,rmi4";
+			reg = <0x20>;
+			interrupt-parent = <&msmgpio>;
+			interrupts = <1 0x2008>;
+			vdd-supply = <&pm8110_l19>;
+			vcc_i2c-supply = <&pm8110_l14>;
+			synaptics,reset-gpio = <&msmgpio 0 0x00>;
+			synaptics,irq-gpio = <&msmgpio 1 0x2008>;
+			synaptics,button-map = <139 102 158>;
+			synaptics,i2c-pull-up;
+			synaptics,power-down;
+			synaptics,disable-gpios;
+		};
 	};
 
 	i2c@f9925000 {
@@ -187,10 +202,6 @@
             "AMIC2", "MIC BIAS Internal2",
             "AMIC3", "MIC BIAS External";
     };
-
-	qcom,dsi_v2_truly_wvga_video {
-		qcom,cont-splash-enabled;
-	};
 };
 
 &i2c_cdc  {
@@ -232,6 +243,7 @@
 
 		qcom,cdc-on-demand-supplies = "cdc-vdda-cp",
 					      "cdc-vdd-mic-bias";
+		qcom,cdc-micbias1-ext-cap;
 	};
 
 	msm8x10_wcd_codec@77{
@@ -414,3 +426,19 @@
 &pm8110_bms {
 	status = "ok";
 };
+
+&mdss_mdp {
+	qcom,mdss-pref-prim-intf = "dsi";
+};
+
+&mdss_dsi0 {
+	qcom,dsi-pref-prim-pan = <&dsi_truly_wvga_vid>;
+};
+
+&dsi_truly_wvga_vid {
+	qcom,cont-splash-enabled;
+};
+
+&dsi_truly_wvga_cmd {
+	qcom,cont-splash-enabled;
+};
diff --git a/arch/arm/boot/dts/msm8610-qrd-skuaa.dtsi b/arch/arm/boot/dts/msm8610-qrd-skuaa.dtsi
index ae28e2c..86f1210 100644
--- a/arch/arm/boot/dts/msm8610-qrd-skuaa.dtsi
+++ b/arch/arm/boot/dts/msm8610-qrd-skuaa.dtsi
@@ -28,10 +28,6 @@
         qcom,ext-spk-amp-gpio = <&msmgpio 92 0x0>;
     };
 
-	qcom,dsi_v2_hx8379a_wvga_video {
-		qcom,cont-splash-enabled;
-	};
-
 	usb@f9a55000 {
 		qcom,hsusb-otg-phy-init-seq =
 		<0x44 0x80 0x6a 0x81 0x34 0x82 0x13 0x83 0xffffffff>;
@@ -62,3 +58,15 @@
 		qcom,scale-function = <7>;
 	};
 };
+
+&mdss_mdp {
+	qcom,mdss-pref-prim-intf = "dsi";
+};
+
+&mdss_dsi0 {
+	qcom,dsi-pref-prim-pan = <&dsi_hx8379a_wvga_vid>;
+};
+
+&dsi_hx8379a_wvga_vid {
+	qcom,cont-splash-enabled;
+};
diff --git a/arch/arm/boot/dts/msm8610-qrd-skuab.dtsi b/arch/arm/boot/dts/msm8610-qrd-skuab.dtsi
index ff70c25..17bf329 100644
--- a/arch/arm/boot/dts/msm8610-qrd-skuab.dtsi
+++ b/arch/arm/boot/dts/msm8610-qrd-skuab.dtsi
@@ -90,10 +90,6 @@
                qcom,hsusb-otg-phy-init-seq =
                        <0x44 0x80 0x6a 0x81 0x34 0x82 0x23 0x83 0xffffffff>;
 	};
-
-	qcom,dsi_v2_otm8018b_fwvga_video {
-		qcom,cont-splash-enabled;
-	};
 };
 
 / {
@@ -113,3 +109,15 @@
 &pm8110_chg {
 	qcom,battery-data = <&qrd_batterydata>;
 };
+
+&mdss_mdp {
+	qcom,mdss-pref-prim-intf = "dsi";
+};
+
+&mdss_dsi0 {
+	qcom,dsi-pref-prim-pan = <&dsi_otm8018b_fwvga_vid>;
+};
+
+&dsi_otm8018b_fwvga_vid {
+	qcom,cont-splash-enabled;
+};
diff --git a/arch/arm/boot/dts/msm8610-qrd.dtsi b/arch/arm/boot/dts/msm8610-qrd.dtsi
index df61ca6..83d84c0 100644
--- a/arch/arm/boot/dts/msm8610-qrd.dtsi
+++ b/arch/arm/boot/dts/msm8610-qrd.dtsi
@@ -135,13 +135,14 @@
 	};
 
     sound {
-        qcom,audio-routing =
-            "RX_BIAS", "MCLK",
-            "INT_LDO_H", "MCLK",
-            "MIC BIAS Internal1", "Handset Mic",
-            "MIC BIAS Internal2", "Headset Mic",
-            "AMIC1", "MIC BIAS Internal1",
-            "AMIC2", "MIC BIAS Internal2";
+	qcom,audio-routing =
+		"RX_BIAS", "MCLK",
+		"INT_LDO_H", "MCLK",
+		"MIC BIAS Internal1", "Handset Mic",
+		"MIC BIAS Internal2", "Headset Mic",
+		"AMIC1", "MIC BIAS Internal1",
+		"AMIC2", "MIC BIAS Internal2";
+	qcom,mbhc-bias-internal;
     };
 };
 
@@ -364,4 +365,5 @@
 
 &android_usb {
 	qcom,android-usb-cdrom;
+	qcom,android-usb-internal-ums;
 };
diff --git a/arch/arm/boot/dts/msm8610-regulator.dtsi b/arch/arm/boot/dts/msm8610-regulator.dtsi
index 1929b50..eb69678 100644
--- a/arch/arm/boot/dts/msm8610-regulator.dtsi
+++ b/arch/arm/boot/dts/msm8610-regulator.dtsi
@@ -42,10 +42,15 @@
 		qcom,pvs-fuse = <23 6 5>;
 		qcom,pvs-fuse-redun = <61 47 5>;
 
-		qcom,pvs-bin-process = <1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
-					1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1>;
-		qcom,pvs-corner-ceiling-slow = <1050000 1150000 1275000>;
-		qcom,pvs-corner-ceiling-nom  = <1050000 1075000 1200000>;
+		qcom,pvs-init-voltage = <1275000 1275000 1275000 1275000 1275000
+					1275000 1275000 1275000 1275000 1275000
+					1275000 1275000 1275000 1275000 1275000
+					1275000 1275000 1275000 1275000 1275000
+					1275000 1275000 1275000 1275000 1275000
+					1275000 1275000 1275000 1275000 1275000
+					1275000 1275000>;
+		qcom,pvs-corner-ceiling-slow = <1150000 1150000 1275000>;
+		qcom,pvs-corner-ceiling-nom  = <1075000 1075000 1200000>;
 		qcom,pvs-corner-ceiling-fast = <1050000 1050000 1140000>;
 		vdd-apc-supply = <&pm8110_s2>;
 
diff --git a/arch/arm/boot/dts/msm8610-v1-cdp.dts b/arch/arm/boot/dts/msm8610-v1-cdp.dts
index ba0851f..beb3976 100644
--- a/arch/arm/boot/dts/msm8610-v1-cdp.dts
+++ b/arch/arm/boot/dts/msm8610-v1-cdp.dts
@@ -14,7 +14,6 @@
 
 /include/ "msm8610-v1.dtsi"
 /include/ "msm8610-cdp.dtsi"
-/include/ "dsi-v2-panel-truly-wvga-video.dtsi"
 /include/ "msm8610-camera-sensor-cdp-mtp.dtsi"
 
 / {
diff --git a/arch/arm/boot/dts/msm8610-v1-mtp.dts b/arch/arm/boot/dts/msm8610-v1-mtp.dts
index 010903f..82992a3 100644
--- a/arch/arm/boot/dts/msm8610-v1-mtp.dts
+++ b/arch/arm/boot/dts/msm8610-v1-mtp.dts
@@ -14,7 +14,6 @@
 
 /include/ "msm8610-v1.dtsi"
 /include/ "msm8610-mtp.dtsi"
-/include/ "dsi-v2-panel-truly-wvga-video.dtsi"
 /include/ "msm8610-camera-sensor-cdp-mtp.dtsi"
 
 / {
diff --git a/arch/arm/boot/dts/msm8610-v1-pm.dtsi b/arch/arm/boot/dts/msm8610-v1-pm.dtsi
index 2a619db..4a2de1c 100644
--- a/arch/arm/boot/dts/msm8610-v1-pm.dtsi
+++ b/arch/arm/boot/dts/msm8610-v1-pm.dtsi
@@ -168,6 +168,7 @@
 			<53 104>, /* mdss_irq */
 			<62 222>, /* ee0_krait_hlos_spmi_periph_irq */
 			<2 216>, /* tsens_upper_lower_int */
+			<41 63>,  /* dino_gen_purpose_irq35 */
 			<0xff 18>,  /* APC_qgicQTmrSecPhysIrptReq */
 			<0xff 19>,  /* APC_qgicQTmrNonSecPhysIrptReq */
 			<0xff 35>,  /* WDT_barkInt */
diff --git a/arch/arm/boot/dts/msm8610-v1-qrd-skuaa.dts b/arch/arm/boot/dts/msm8610-v1-qrd-skuaa.dts
index ba53acc..ec8c4c6 100644
--- a/arch/arm/boot/dts/msm8610-v1-qrd-skuaa.dts
+++ b/arch/arm/boot/dts/msm8610-v1-qrd-skuaa.dts
@@ -14,7 +14,6 @@
 
 /include/ "msm8610-v1.dtsi"
 /include/ "msm8610-qrd-skuaa.dtsi"
-/include/ "dsi-v2-panel-hx8379a-wvga-video.dtsi"
 /include/ "msm8610-qrd-camera-sensor.dtsi"
 
 / {
diff --git a/arch/arm/boot/dts/msm8610-v1-qrd-skuab.dts b/arch/arm/boot/dts/msm8610-v1-qrd-skuab.dts
index 5e19997..b3350bb 100644
--- a/arch/arm/boot/dts/msm8610-v1-qrd-skuab.dts
+++ b/arch/arm/boot/dts/msm8610-v1-qrd-skuab.dts
@@ -14,7 +14,6 @@
 
 /include/ "msm8610-v1.dtsi"
 /include/ "msm8610-qrd-skuab.dtsi"
-/include/ "dsi-v2-panel-otm8018b-fwvga-video.dtsi"
 /include/ "msm8612-qrd-camera-sensor.dtsi"
 
 / {
diff --git a/arch/arm/boot/dts/msm8610-v2-cdp.dts b/arch/arm/boot/dts/msm8610-v2-cdp.dts
index 51ef7a2..a6d1d9c 100644
--- a/arch/arm/boot/dts/msm8610-v2-cdp.dts
+++ b/arch/arm/boot/dts/msm8610-v2-cdp.dts
@@ -14,7 +14,6 @@
 
 /include/ "msm8610-v2.dtsi"
 /include/ "msm8610-cdp.dtsi"
-/include/ "dsi-v2-panel-truly-wvga-video.dtsi"
 /include/ "msm8610-camera-sensor-cdp-mtp.dtsi"
 
 / {
diff --git a/arch/arm/boot/dts/msm8610-v2-mtp.dts b/arch/arm/boot/dts/msm8610-v2-mtp.dts
index e1c9bb8..405a775 100644
--- a/arch/arm/boot/dts/msm8610-v2-mtp.dts
+++ b/arch/arm/boot/dts/msm8610-v2-mtp.dts
@@ -14,7 +14,6 @@
 
 /include/ "msm8610-v2.dtsi"
 /include/ "msm8610-mtp.dtsi"
-/include/ "dsi-v2-panel-truly-wvga-video.dtsi"
 /include/ "msm8610-camera-sensor-cdp-mtp.dtsi"
 
 / {
diff --git a/arch/arm/boot/dts/msm8610-v2-pm.dtsi b/arch/arm/boot/dts/msm8610-v2-pm.dtsi
index 257d7a4..079f0b1 100644
--- a/arch/arm/boot/dts/msm8610-v2-pm.dtsi
+++ b/arch/arm/boot/dts/msm8610-v2-pm.dtsi
@@ -170,6 +170,7 @@
 			<53 104>, /* mdss_irq */
 			<62 222>, /* ee0_krait_hlos_spmi_periph_irq */
 			<2 216>, /* tsens_upper_lower_int */
+			<41 63>,  /* dino_gen_purpose_irq35 */
 			<0xff 56>,  /* q6_wdog_expired_irq */
 			<0xff 57>,  /* mss_to_apps_irq(0) */
 			<0xff 58>,  /* mss_to_apps_irq(1) */
diff --git a/arch/arm/boot/dts/msm8610-v2-qrd-skuaa.dts b/arch/arm/boot/dts/msm8610-v2-qrd-skuaa.dts
index 677365f..44df025 100644
--- a/arch/arm/boot/dts/msm8610-v2-qrd-skuaa.dts
+++ b/arch/arm/boot/dts/msm8610-v2-qrd-skuaa.dts
@@ -14,7 +14,6 @@
 
 /include/ "msm8610-v2.dtsi"
 /include/ "msm8610-qrd-skuaa.dtsi"
-/include/ "dsi-v2-panel-hx8379a-wvga-video.dtsi"
 /include/ "msm8610-qrd-camera-sensor.dtsi"
 
 / {
diff --git a/arch/arm/boot/dts/msm8610-v2-qrd-skuab.dts b/arch/arm/boot/dts/msm8610-v2-qrd-skuab.dts
index ccc38fc..92908fb 100644
--- a/arch/arm/boot/dts/msm8610-v2-qrd-skuab.dts
+++ b/arch/arm/boot/dts/msm8610-v2-qrd-skuab.dts
@@ -14,7 +14,6 @@
 
 /include/ "msm8610-v2.dtsi"
 /include/ "msm8610-qrd-skuab.dtsi"
-/include/ "dsi-v2-panel-otm8018b-fwvga-video.dtsi"
 /include/ "msm8612-qrd-camera-sensor.dtsi"
 
 / {
diff --git a/arch/arm/boot/dts/msm8926-camera-sensor-qrd.dtsi b/arch/arm/boot/dts/msm8926-camera-sensor-qrd.dtsi
new file mode 100644
index 0000000..a85e048
--- /dev/null
+++ b/arch/arm/boot/dts/msm8926-camera-sensor-qrd.dtsi
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+&soc {
+
+	led_flash0: qcom,camera-led-flash {
+		cell-index = <0>;
+		compatible = "qcom,camera-led-flash";
+		qcom,flash-type = <1>;
+		qcom,flash-source = <&pm8226_flash0 &pm8226_flash1>;
+		qcom,torch-source = <&pm8226_torch>;
+	};
+};
+
+&cci {
+
+	actuator0: qcom,actuator@6e {
+		cell-index = <5>;
+		reg = <0x18>;
+		compatible = "qcom,actuator";
+		qcom,cci-master = <0>;
+	};
+
+	qcom,camera@20 {
+		compatible = "ovti,ov8865";
+		reg = <0x20>;
+		qcom,slave-id = <0x20 0x300b 0x8865>;
+		qcom,csiphy-sd-index = <0>;
+		qcom,csid-sd-index = <0>;
+		qcom,actuator-src = <&actuator0>;
+		qcom,led-flash-src = <&led_flash0>;
+		qcom,mount-angle = <90>;
+		qcom,sensor-name = "ov8865_q8v18a";
+		cam_vdig-supply = <&pm8226_l5>;
+		cam_vana-supply = <&pm8226_l19>;
+		cam_vio-supply = <&pm8226_lvs1>;
+		cam_vaf-supply = <&pm8226_l15>;
+		qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana",
+		                                         "cam_vaf";
+		qcom,cam-vreg-type = <0 1 0 0>;
+		qcom,cam-vreg-min-voltage = <1200000 0 2850000 2800000>;
+		qcom,cam-vreg-max-voltage = <1200000 0 2850000 2800000>;
+		qcom,cam-vreg-op-mode = <200000 0 80000 100000>;
+		qcom,gpio-no-mux = <0>;
+		gpios = <&msmgpio 26 0>,
+		        <&msmgpio 37 0>,
+		        <&msmgpio 36 0>,
+		        <&msmgpio 15 0>;
+		qcom,gpio-reset = <1>;
+		qcom,gpio-standby = <2>;
+		qcom,gpio-af-pwdm = <3>;
+		qcom,gpio-req-tbl-num = <0 1 2 3>;
+		qcom,gpio-req-tbl-flags = <1 0 0 0>;
+		qcom,gpio-req-tbl-label = "CAMIF_MCLK",
+		        "CAM_RESET1",
+		        "CAM_STANDBY",
+		        "CAM_AF_PWDM";
+		qcom,csi-lane-assign = <0x4320>;
+		qcom,csi-lane-mask = <0x1F>;
+		qcom,sensor-position = <0>;
+		qcom,sensor-mode = <1>;
+		qcom,cci-master = <0>;
+	};
+
+	qcom,camera@6a {
+		compatible = "ovti,ov5648";
+		reg = <0x6a>;
+		qcom,slave-id = <0x6c 0x300a 0x5648>;
+		qcom,csiphy-sd-index = <1>;
+		qcom,csid-sd-index = <1>;
+		qcom,mount-angle = <270>;
+		qcom,sensor-name = "ov5648_oty5f03";
+		cam_vdig-supply = <&pm8226_l5>;
+		cam_vana-supply = <&pm8226_l19>;
+		cam_vio-supply = <&pm8226_lvs1>;
+		qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana";
+		qcom,cam-vreg-type = <0 1 0>;
+		qcom,cam-vreg-min-voltage = <1200000 0 2850000>;
+		qcom,cam-vreg-max-voltage = <1200000 0 2850000>;
+		qcom,cam-vreg-op-mode = <200000 0 80000>;
+		qcom,gpio-no-mux = <0>;
+		gpios = <&msmgpio 26 0>,
+				<&msmgpio 28 0>,
+				<&msmgpio 35 0>,
+				<&msmgpio 23 0>;
+		qcom,gpio-reset = <1>;
+		qcom,gpio-standby = <2>;
+		qcom,gpio-vdig = <3>;
+		qcom,gpio-req-tbl-num = <0 1 2 3>;
+		qcom,gpio-req-tbl-flags = <1 0 0 0>;
+		qcom,gpio-req-tbl-label = "CAMIF_MCLK",
+				"CAM_RESET",
+				"CAM_STANDBY",
+				"CAM_VDIG";
+		qcom,gpio-set-tbl-num = <1 1>;
+		qcom,gpio-set-tbl-flags = <0 2>;
+		qcom,gpio-set-tbl-delay = <1000 4000>;
+		qcom,csi-lane-assign = <0x4320>;
+		qcom,csi-lane-mask = <0x3>;
+		qcom,sensor-position = <1>;
+		qcom,sensor-mode = <1>;
+		qcom,cci-master = <0>;
+		status = "ok";
+	};
+};
diff --git a/arch/arm/boot/dts/msm8926-cdp.dts b/arch/arm/boot/dts/msm8926-cdp.dts
index 500c7d8..7d8d6cf 100644
--- a/arch/arm/boot/dts/msm8926-cdp.dts
+++ b/arch/arm/boot/dts/msm8926-cdp.dts
@@ -19,10 +19,7 @@
 / {
 	model = "Qualcomm MSM 8926 CDP";
 	compatible = "qcom,msm8926-cdp", "qcom,msm8926", "qcom,cdp";
-	qcom,msm-id = <200 1 0>,
-		      <224 1 0>,
-		      <200 1 0x10001>,
-		      <224 1 0x10001>;
+	qcom,board-id = <1 0>;
 };
 
 &pm8226_chg {
diff --git a/arch/arm/boot/dts/msm8926-mtp.dts b/arch/arm/boot/dts/msm8926-mtp.dts
index 73635bc..624781b 100644
--- a/arch/arm/boot/dts/msm8926-mtp.dts
+++ b/arch/arm/boot/dts/msm8926-mtp.dts
@@ -19,8 +19,5 @@
 / {
 	model = "Qualcomm MSM 8926 MTP";
 	compatible = "qcom,msm8926-mtp", "qcom,msm8926", "qcom,mtp";
-	qcom,msm-id = <200 8 0>,
-		      <224 8 0>,
-		      <200 8 0x10001>,
-		      <224 8 0x10001>;
+	qcom,board-id = <8 0>;
 };
diff --git a/arch/arm/boot/dts/msm8926-qrd-skug.dts b/arch/arm/boot/dts/msm8926-qrd-skug.dts
index 8fb0878..a366205 100644
--- a/arch/arm/boot/dts/msm8926-qrd-skug.dts
+++ b/arch/arm/boot/dts/msm8926-qrd-skug.dts
@@ -13,6 +13,7 @@
 /dts-v1/;
 /include/ "msm8926.dtsi"
 /include/ "msm8226-qrd.dtsi"
+/include/ "msm8926-camera-sensor-qrd.dtsi"
 
 / {
 	model = "Qualcomm MSM 8926 QRD SKUG";
@@ -34,3 +35,56 @@
 &pm8226_chg {
 	qcom,battery-data = <&qrd_batterydata>;
 };
+
+&soc {
+	i2c@f9927000 { /* BLSP1 QUP5 */
+		focaltech@38 {
+			compatible = "focaltech,5x06";
+			reg = <0x38>;
+			interrupt-parent = <&msmgpio>;
+			interrupts = <17 0x2>;
+			vdd-supply = <&pm8226_l19>;
+			vcc_i2c-supply = <&pm8226_lvs1>;
+			focaltech,name = "ft5336";
+			focaltech,family-id = <0x14>;
+			focaltech,reset-gpio = <&msmgpio 16 0x00>;
+			focaltech,irq-gpio = <&msmgpio 17 0x00>;
+			focaltech,display-coords = <0 0 720 1280>;
+			focaltech,panel-coords = <0 0 720 1400>;
+			focaltech,button-map= <139 102 158>;
+			focaltech,no-force-update;
+			focaltech,i2c-pull-up;
+			focaltech,group-id = <1>;
+			focaltech,hard-reset-delay-ms = <20>;
+			focaltech,soft-reset-delay-ms = <200>;
+			focaltech,num-max-touches = <5>;
+			focaltech,fw-name = "ft_8926_qrd_fw.bin";
+			focaltech,fw-delay-aa-ms = <30>;
+			focaltech,fw-delay-55-ms = <30>;
+			focaltech,fw-upgrade-id1 = <0x79>;
+			focaltech,fw-upgrade-id2 = <0x08>;
+			focaltech,fw-delay-readid-ms = <10>;
+			focaltech,fw-delay-era-flsh-ms = <2000>;
+			focaltech,fw-auto-cal;
+		};
+	};
+
+	gen-vkeys {
+		compatible = "qcom,gen-vkeys";
+		label = "ft5x06_ts";
+		qcom,disp-maxx = <720>;
+		qcom,disp-maxy = <1280>;
+		qcom,panel-maxx = <720>;
+		qcom,panel-maxy = <1404>;
+		qcom,key-codes = <139 172 158>;
+		qcom,y-offset = <0>;
+	};
+};
+
+&mdss_dsi0 {
+	qcom,dsi-pref-prim-pan = <&dsi_ssd2080m_720_vid>;
+};
+
+&dsi_ssd2080m_720_vid {
+	qcom,cont-splash-enabled;
+};
diff --git a/arch/arm/boot/dts/msm8926-qrd.dts b/arch/arm/boot/dts/msm8926-qrd.dts
index 5cae698..8ee8828 100644
--- a/arch/arm/boot/dts/msm8926-qrd.dts
+++ b/arch/arm/boot/dts/msm8926-qrd.dts
@@ -17,8 +17,5 @@
 / {
 	model = "Qualcomm MSM 8926 QRD";
 	compatible = "qcom,msm8926-qrd", "qcom,msm8926", "qcom,qrd";
-	qcom,msm-id = <200 11 0>,
-		      <224 11 0>,
-		      <200 11 0x10001>,
-		      <224 11 0x10001>;
+	qcom,board-id = <11 0>;
 };
diff --git a/arch/arm/boot/dts/msm8926.dtsi b/arch/arm/boot/dts/msm8926.dtsi
index 5893a9b..2ab272a 100644
--- a/arch/arm/boot/dts/msm8926.dtsi
+++ b/arch/arm/boot/dts/msm8926.dtsi
@@ -48,28 +48,33 @@
 
 &pm8226_l3 {
 	regulator-min-microvolt = <750000>;
-	regulator-max-microvolt = <1287500>;
+	regulator-max-microvolt = <1350000>;
 };
 
 &pm8226_l3_ao {
 	regulator-min-microvolt = <750000>;
-	regulator-max-microvolt = <1287500>;
+	regulator-max-microvolt = <1350000>;
 };
 
 &pm8226_l3_so {
 	regulator-min-microvolt = <750000>;
-	regulator-max-microvolt = <1287500>;
+	regulator-max-microvolt = <1350000>;
 };
 
 &pm8226_s2 {
 	regulator-min-microvolt = <900000>;
-	regulator-max-microvolt = <1280000>;
+	regulator-max-microvolt = <1350000>;
 };
 
 &apc_vreg_corner {
-	qcom,pvs-bin-process = <1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2
-				2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 3>;
-	qcom,pvs-corner-ceiling-slow = <1050000 1160000 1280000>;
+	qcom,pvs-init-voltage = <1350000 1340000 1330000 1320000 1310000
+					1300000 1290000 1280000 1270000 1260000
+					1250000 1240000 1230000 1220000 1210000
+					1200000 1190000 1180000 1170000 1160000
+					1150000 1140000 1140000 1140000 1140000
+					1140000 1140000 1140000 1140000 1140000
+					1140000 1140000>;
+	qcom,pvs-corner-ceiling-slow = <1050000 1150000 1280000>;
 	qcom,pvs-corner-ceiling-nom  = <1050000 1080000 1200000>;
 	qcom,pvs-corner-ceiling-fast = <1050000 1050000 1140000>;
 	qcom,cpr-step-quotient = <30>;
diff --git a/arch/arm/boot/dts/msm8974-camera-sensor-cdp.dtsi b/arch/arm/boot/dts/msm8974-camera-sensor-cdp.dtsi
index 26c5b8f..9948833 100644
--- a/arch/arm/boot/dts/msm8974-camera-sensor-cdp.dtsi
+++ b/arch/arm/boot/dts/msm8974-camera-sensor-cdp.dtsi
@@ -36,8 +36,6 @@
 		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>;
@@ -79,8 +77,6 @@
 		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>;
@@ -122,8 +118,6 @@
 		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>;
@@ -159,8 +153,6 @@
 		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-fluid.dtsi b/arch/arm/boot/dts/msm8974-camera-sensor-fluid.dtsi
index f61b83a..9cbd45c 100644
--- a/arch/arm/boot/dts/msm8974-camera-sensor-fluid.dtsi
+++ b/arch/arm/boot/dts/msm8974-camera-sensor-fluid.dtsi
@@ -37,8 +37,6 @@
 		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>;
@@ -80,8 +78,6 @@
 		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>;
@@ -123,8 +119,6 @@
 		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>;
@@ -160,8 +154,6 @@
 		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 cf968d2..bf7f492 100644
--- a/arch/arm/boot/dts/msm8974-camera-sensor-liquid.dtsi
+++ b/arch/arm/boot/dts/msm8974-camera-sensor-liquid.dtsi
@@ -37,8 +37,6 @@
 		qcom,mount-angle = <0>;
 		qcom,actuator-src = <&actuator0>;
 		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>;
@@ -79,8 +77,6 @@
 		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>;
@@ -123,8 +119,6 @@
 		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>;
@@ -159,8 +153,6 @@
 		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 6ad6213..68af4a6 100644
--- a/arch/arm/boot/dts/msm8974-camera-sensor-mtp.dtsi
+++ b/arch/arm/boot/dts/msm8974-camera-sensor-mtp.dtsi
@@ -37,8 +37,6 @@
 		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>;
@@ -79,8 +77,6 @@
 		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>;
@@ -124,8 +120,6 @@
 		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>;
@@ -161,8 +155,6 @@
 		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-cdp.dtsi b/arch/arm/boot/dts/msm8974-cdp.dtsi
index d200100..9e7b2e6 100644
--- a/arch/arm/boot/dts/msm8974-cdp.dtsi
+++ b/arch/arm/boot/dts/msm8974-cdp.dtsi
@@ -41,6 +41,22 @@
 	};
 
 	i2c@f9924000 {
+		synaptics@20 {
+			compatible = "synaptics,rmi4";
+			reg = <0x20>;
+			interrupt-parent = <&msmgpio>;
+			interrupts = <61 0x2008>;
+			vdd-supply = <&pm8941_l18>;
+			vcc_i2c-supply = <&pm8941_lvs1>;
+			synaptics,reset-gpio = <&msmgpio 60 0x00>;
+			synaptics,irq-gpio = <&msmgpio 61 0x2008>;
+			synaptics,display-coords = <0 0 1079 1919>;
+			synaptics,i2c-pull-up;
+			synaptics,power-down;
+			synaptics,disable-gpios;
+			synaptics,do-lockdown;
+		};
+
 		atmel_mxt_ts@4a {
 			compatible = "atmel,mxt-ts";
 			reg = <0x4a>;
@@ -227,7 +243,7 @@
 			1 &intc 0 148 0
 			2 &msmgpio 144 0x8>;
 		interrupt-names = "core_irq", "async_irq", "wakeup";
-		HSIC_VDDCX-supply = <&pm8841_s2>;
+		hsic_vdd_dig-supply = <&pm8841_s2_corner>;
 		HSIC_GDSC-supply = <&gdsc_usb_hsic>;
 		hsic,strobe-gpio = <&msmgpio 144 0x00>;
 		hsic,data-gpio = <&msmgpio 145 0x00>;
@@ -236,6 +252,7 @@
 		hsic,strobe-pad-offset = <0x2050>;
 		hsic,data-pad-offset = <0x2054>;
 		qcom,phy-susp-sof-workaround;
+		hsic,vdd-voltage-level = <1 5 7>;
 
 		qcom,msm-bus,name = "hsic";
 		qcom,msm-bus,num-cases = <2>;
diff --git a/arch/arm/boot/dts/msm8974-fluid.dtsi b/arch/arm/boot/dts/msm8974-fluid.dtsi
index d02021c..c112bea 100644
--- a/arch/arm/boot/dts/msm8974-fluid.dtsi
+++ b/arch/arm/boot/dts/msm8974-fluid.dtsi
@@ -37,6 +37,22 @@
 	};
 
 	i2c@f9924000 {
+		synaptics@20 {
+			compatible = "synaptics,rmi4";
+			reg = <0x20>;
+			interrupt-parent = <&msmgpio>;
+			interrupts = <61 0x2008>;
+			vdd-supply = <&pm8941_l18>;
+			vcc_i2c-supply = <&pm8941_lvs1>;
+			synaptics,reset-gpio = <&msmgpio 60 0x00>;
+			synaptics,irq-gpio = <&msmgpio 61 0x2008>;
+			synaptics,display-coords = <0 0 1079 1919>;
+			synaptics,i2c-pull-up;
+			synaptics,power-down;
+			synaptics,disable-gpios;
+			synaptics,do-lockdown;
+		};
+
 		atmel_mxt_ts@4a {
 			compatible = "atmel,mxt-ts";
 			reg = <0x4a>;
diff --git a/arch/arm/boot/dts/msm8974-liquid.dtsi b/arch/arm/boot/dts/msm8974-liquid.dtsi
index 73aba8f..67e1802 100644
--- a/arch/arm/boot/dts/msm8974-liquid.dtsi
+++ b/arch/arm/boot/dts/msm8974-liquid.dtsi
@@ -397,7 +397,7 @@
 		                1 &intc 0 148 0
 		                2 &msmgpio 144 0x8>;
 			interrupt-names = "core_irq", "async_irq", "wakeup";
-			HSIC_VDDCX-supply = <&pm8841_s2>;
+			hsic_vdd_dig-supply = <&pm8841_s2_corner>;
 			HSIC_GDSC-supply = <&gdsc_usb_hsic>;
 			hsic,strobe-gpio = <&msmgpio 144 0x00>;
 			hsic,data-gpio = <&msmgpio 145 0x00>;
@@ -405,6 +405,7 @@
 			hsic,strobe-pad-offset = <0x2050>;
 			hsic,data-pad-offset = <0x2054>;
 			qcom,phy-susp-sof-workaround;
+			hsic,vdd-voltage-level = <1 5 7>;
 
 			qcom,msm-bus,name = "hsic";
 			qcom,msm-bus,num-cases = <2>;
diff --git a/arch/arm/boot/dts/msm8974-mtp.dtsi b/arch/arm/boot/dts/msm8974-mtp.dtsi
index 22fff80..7a81e64 100644
--- a/arch/arm/boot/dts/msm8974-mtp.dtsi
+++ b/arch/arm/boot/dts/msm8974-mtp.dtsi
@@ -37,6 +37,22 @@
 	};
 
 	i2c@f9924000 {
+		synaptics@20 {
+			compatible = "synaptics,rmi4";
+			reg = <0x20>;
+			interrupt-parent = <&msmgpio>;
+			interrupts = <61 0x2008>;
+			vdd-supply = <&pm8941_l18>;
+			vcc_i2c-supply = <&pm8941_lvs1>;
+			synaptics,reset-gpio = <&msmgpio 60 0x00>;
+			synaptics,irq-gpio = <&msmgpio 61 0x2008>;
+			synaptics,display-coords = <0 0 1079 1919>;
+			synaptics,i2c-pull-up;
+			synaptics,power-down;
+			synaptics,disable-gpios;
+			synaptics,do-lockdown;
+		};
+
 		atmel_mxt_ts@4a {
 			compatible = "atmel,mxt-ts";
 			reg = <0x4a>;
diff --git a/arch/arm/boot/dts/msm8974-v1-cdp.dts b/arch/arm/boot/dts/msm8974-v1-cdp.dts
index c3fd98d..071c7c9 100644
--- a/arch/arm/boot/dts/msm8974-v1-cdp.dts
+++ b/arch/arm/boot/dts/msm8974-v1-cdp.dts
@@ -26,6 +26,8 @@
 &ehci {
 	status = "ok";
 	vbus-supply = <&usb2_otg_sw>;
+	hsusb_vdd_dig-supply = <&pm8841_s2_corner>;
+	qcom,vdd-voltage-level = <1 2 3 5 7>;
 };
 
 &hsic_host {
diff --git a/arch/arm/boot/dts/msm8974-v2.dtsi b/arch/arm/boot/dts/msm8974-v2.dtsi
index af4030f..f2f73e9 100644
--- a/arch/arm/boot/dts/msm8974-v2.dtsi
+++ b/arch/arm/boot/dts/msm8974-v2.dtsi
@@ -184,3 +184,26 @@
 		status = "ok";
 	};
 };
+
+&cci {
+
+	qcom,camera@6e {
+		qcom,vdd-cx-supply = <&pm8841_s2>;
+		qcom,vdd-cx-name = "qcom,vdd-cx";
+	};
+
+	qcom,camera@20 {
+		qcom,vdd-cx-supply = <&pm8841_s2>;
+		qcom,vdd-cx-name = "qcom,vdd-cx";
+	};
+
+	qcom,camera@6c {
+		qcom,vdd-cx-supply = <&pm8841_s2>;
+		qcom,vdd-cx-name = "qcom,vdd-cx";
+	};
+
+	qcom,camera@90 {
+		qcom,vdd-cx-supply = <&pm8841_s2>;
+		qcom,vdd-cx-name = "qcom,vdd-cx";
+	};
+};
diff --git a/arch/arm/boot/dts/msm8974.dtsi b/arch/arm/boot/dts/msm8974.dtsi
index 65307ae..652a8fc 100644
--- a/arch/arm/boot/dts/msm8974.dtsi
+++ b/arch/arm/boot/dts/msm8974.dtsi
@@ -835,9 +835,11 @@
 		reg-names = "qup_phys_addr";
 		interrupts = <0 96 0>;
 		interrupt-names = "qup_err_intr";
-		qcom,i2c-bus-freq = <100000>;
-		qcom,i2c-src-freq = <50000000>;
+		qcom,i2c-bus-freq = <384000>;
+		qcom,i2c-src-freq = <19200000>;
 		qcom,master-id = <86>;
+		qcom,scl-gpio = <&msmgpio 7 0>;
+		qcom,sda-gpio = <&msmgpio 6 0>;
 	};
 
 	spi_0: spi@f9923000 { /* BLSP1 QUP1 */
@@ -1559,7 +1561,8 @@
 
         memory_hole: qcom,msm-mem-hole {
                 compatible = "qcom,msm-mem-hole";
-                qcom,memblock-remove = <0x5d00000 0xa200000>; /* Address and Size of Hole */
+                qcom,memblock-remove = <0x5d00000 0x7d00000
+					0xfa00000 0x500000>; /* Address and Size of Hole */
         };
 
 	uart7: uart@f995d000 { /*BLSP #2, UART #7 */
diff --git a/arch/arm/boot/dts/msm8974pro-ac-mtp.dtsi b/arch/arm/boot/dts/msm8974pro-ac-mtp.dtsi
index debf7fb..cdb4ed0 100644
--- a/arch/arm/boot/dts/msm8974pro-ac-mtp.dtsi
+++ b/arch/arm/boot/dts/msm8974pro-ac-mtp.dtsi
@@ -46,6 +46,11 @@
 
 &soc {
 	i2c@f9924000 {
+		synaptics@20 {
+			vdd-supply = <&pma8084_l18>;
+			vcc_i2c-supply = <&pma8084_lvs1>;
+		};
+
 		atmel_mxt_ts@4a {
 			vdd_ana-supply = <&pma8084_l18>;
 			vcc_i2c-supply = <&pma8084_lvs1>;
diff --git a/arch/arm/configs/msm8226-perf_defconfig b/arch/arm/configs/msm8226-perf_defconfig
index 9535e05..d11634b 100644
--- a/arch/arm/configs/msm8226-perf_defconfig
+++ b/arch/arm/configs/msm8226-perf_defconfig
@@ -301,6 +301,7 @@
 CONFIG_OV8825=y
 CONFIG_OV12830=y
 CONFIG_IMX135=y
+CONFIG_OV8865=y
 CONFIG_MSM_CAMERA_SENSOR=y
 CONFIG_MSM_EEPROM=y
 CONFIG_MSM_CPP=y
diff --git a/arch/arm/configs/msm8226_defconfig b/arch/arm/configs/msm8226_defconfig
index 176a8a2..b03e4cd 100644
--- a/arch/arm/configs/msm8226_defconfig
+++ b/arch/arm/configs/msm8226_defconfig
@@ -305,6 +305,7 @@
 CONFIG_OV8825=y
 CONFIG_OV12830=y
 CONFIG_IMX135=y
+CONFIG_OV8865=y
 CONFIG_MSM_CAMERA_SENSOR=y
 CONFIG_MSM_EEPROM=y
 CONFIG_MSM_CPP=y
diff --git a/arch/arm/configs/msm8610-perf_defconfig b/arch/arm/configs/msm8610-perf_defconfig
index 970c03f..1a197a3 100644
--- a/arch/arm/configs/msm8610-perf_defconfig
+++ b/arch/arm/configs/msm8610-perf_defconfig
@@ -286,6 +286,7 @@
 CONFIG_OV5648=y
 CONFIG_MSM_CAMERA_SENSOR=y
 # CONFIG_MSM_CPP is not set
+CONFIG_MSM_EEPROM=y
 CONFIG_MSM_CCI=y
 CONFIG_MSM_CSI22_HEADER=y
 CONFIG_MSM_CSIPHY=y
diff --git a/arch/arm/configs/msm8610_defconfig b/arch/arm/configs/msm8610_defconfig
index 54b1c14..8238414 100644
--- a/arch/arm/configs/msm8610_defconfig
+++ b/arch/arm/configs/msm8610_defconfig
@@ -286,6 +286,7 @@
 CONFIG_HI256=y
 CONFIG_OV12830=y
 CONFIG_MSM_CAMERA_SENSOR=y
+CONFIG_MSM_EEPROM=y
 CONFIG_MSM_CCI=y
 CONFIG_MSM_CSIPHY=y
 CONFIG_MSM_CSID=y
diff --git a/arch/arm/configs/msm8960_defconfig b/arch/arm/configs/msm8960_defconfig
index 1d645e2..c668cb2 100644
--- a/arch/arm/configs/msm8960_defconfig
+++ b/arch/arm/configs/msm8960_defconfig
@@ -240,18 +240,18 @@
 CONFIG_NET_EMATCH_TEXT=y
 CONFIG_NET_CLS_ACT=y
 CONFIG_BT=y
-CONFIG_BT_RFCOMM=y
-CONFIG_BT_RFCOMM_TTY=y
-CONFIG_BT_BNEP=y
-CONFIG_BT_BNEP_MC_FILTER=y
-CONFIG_BT_BNEP_PROTO_FILTER=y
+# CONFIG_BT_RFCOMM is not set
+# CONFIG_BT_RFCOMM_TTY is not set
+# CONFIG_BT_BNEP is not set
+# CONFIG_BT_BNEP_MC_FILTER is not set
+# CONFIG_BT_BNEP_PROTO_FILTER is not set
 CONFIG_BT_HIDP=y
-CONFIG_BT_HCISMD=y
-CONFIG_BT_HCIUART=y
-CONFIG_BT_HCIUART_H4=y
-CONFIG_BT_HCIUART_ATH3K=y
-CONFIG_BT_HCIUART_IBS=y
-CONFIG_MSM_BT_POWER=y
+# CONFIG_BT_HCISMD is not set
+# CONFIG_BT_HCIUART is not set
+# CONFIG_BT_HCIUART_H4 is not set
+# CONFIG_BT_HCIUART_ATH3K is not set
+# CONFIG_BT_HCIUART_IBS is not set
+# CONFIG_MSM_BT_POWER is not set
 CONFIG_CFG80211=m
 CONFIG_CFG80211_INTERNAL_REGDB=y
 # CONFIG_CFG80211_WEXT is not set
diff --git a/arch/arm/configs/msm8974-perf_defconfig b/arch/arm/configs/msm8974-perf_defconfig
index a9e39ed..3224889 100644
--- a/arch/arm/configs/msm8974-perf_defconfig
+++ b/arch/arm/configs/msm8974-perf_defconfig
@@ -94,6 +94,7 @@
 CONFIG_AEABI=y
 CONFIG_HIGHMEM=y
 CONFIG_COMPACTION=y
+CONFIG_ENABLE_VMALLOC_SAVING=y
 CONFIG_CC_STACKPROTECTOR=y
 CONFIG_CP_ACCESS=y
 CONFIG_USE_OF=y
@@ -286,6 +287,8 @@
 CONFIG_INPUT_TOUCHSCREEN=y
 CONFIG_TOUCHSCREEN_ATMEL_MXT=y
 CONFIG_TOUCHSCREEN_GEN_VKEYS=y
+CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4=y
+CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE=y
 CONFIG_INPUT_MISC=y
 CONFIG_INPUT_UINPUT=y
 CONFIG_SERIAL_MSM_HS=y
diff --git a/arch/arm/configs/msm8974_defconfig b/arch/arm/configs/msm8974_defconfig
index ee38cc8..cd0e638 100644
--- a/arch/arm/configs/msm8974_defconfig
+++ b/arch/arm/configs/msm8974_defconfig
@@ -100,6 +100,7 @@
 CONFIG_AEABI=y
 CONFIG_HIGHMEM=y
 CONFIG_COMPACTION=y
+CONFIG_ENABLE_VMALLOC_SAVING=y
 CONFIG_CC_STACKPROTECTOR=y
 CONFIG_CP_ACCESS=y
 CONFIG_USE_OF=y
@@ -294,6 +295,8 @@
 CONFIG_INPUT_TOUCHSCREEN=y
 CONFIG_TOUCHSCREEN_ATMEL_MXT=y
 CONFIG_TOUCHSCREEN_GEN_VKEYS=y
+CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4=y
+CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE=y
 CONFIG_INPUT_MISC=y
 CONFIG_INPUT_UINPUT=y
 CONFIG_SERIAL_MSM_HS=y
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index 32b5b26..5bca467 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -555,7 +555,7 @@
 
 static DEFINE_RAW_SPINLOCK(stop_lock);
 
-static struct pt_regs __percpu regs_before_stop;
+DEFINE_PER_CPU(struct pt_regs, regs_before_stop);
 /*
  * ipi_cpu_stop - handle IPI from smp_send_stop()
  */
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index 87e3e5b..2fda467 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -280,11 +280,12 @@
 	select MEMORY_HOLE_CARVEOUT
 	select MSM_RPM_STATS_LOG
 	select QMI_ENCDEC
-	select DONT_MAP_HOLE_AFTER_MEMBANK0
 	select MSM_ULTRASOUND_B
 	select MSM_RPM_LOG
 	select ARCH_WANT_KMAP_ATOMIC_FLUSH
 	select KRAIT_REGULATOR
+	select USB_ARCH_HAS_XHCI
+	select ENABLE_VMALLOC_SAVING
 
 config ARCH_APQ8084
 	bool "APQ8084"
@@ -1761,6 +1762,16 @@
 	help
 	  SMD Transport Layer for IPC Router
 
+config MSM_IPC_ROUTER_HSIC_XPRT
+	depends on USB_QCOM_IPC_BRIDGE
+	depends on MSM_IPC_ROUTER
+	bool "MSM HSIC XPRT Layer"
+	help
+	  HSIC Transport Layer that enables off-chip communication of
+	  IPC Router. When the HSIC endpoint becomes available, this layer
+	  registers the transport with IPC Router and enable message
+	  exchange.
+
 config MSM_IPC_ROUTER_SECURITY
 	depends on MSM_IPC_ROUTER
 	bool "MSM IPC Router Security support"
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index 89eb589..dd533f4 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -130,6 +130,7 @@
 obj-$(CONFIG_MSM_SMD_NMEA) += smd_nmea.o
 obj-$(CONFIG_MSM_RESET_MODEM) += reset_modem.o
 obj-$(CONFIG_MSM_IPC_ROUTER_SMD_XPRT) += ipc_router_smd_xprt.o
+obj-$(CONFIG_MSM_IPC_ROUTER_HSIC_XPRT) += ipc_router_hsic_xprt.o
 obj-$(CONFIG_MSM_ONCRPCROUTER) += smd_rpcrouter.o
 obj-$(CONFIG_MSM_ONCRPCROUTER) += smd_rpcrouter_device.o
 obj-$(CONFIG_MSM_IPC_ROUTER) += ipc_router.o
diff --git a/arch/arm/mach-msm/acpuclock-8226.c b/arch/arm/mach-msm/acpuclock-8226.c
index 59c682f..65e22ae 100644
--- a/arch/arm/mach-msm/acpuclock-8226.c
+++ b/arch/arm/mach-msm/acpuclock-8226.c
@@ -95,7 +95,7 @@
 	{ 0 }
 };
 
-static struct clkctl_acpu_speed acpu_freq_tbl_8226_1p5[] = {
+static struct clkctl_acpu_speed acpu_freq_tbl_8226_1p6[] = {
 	{ 1,  300000, PLL0,    4, 2,   CPR_CORNER_SVS,    0, 4 },
 	{ 1,  384000, ACPUPLL, 5, 2,   CPR_CORNER_SVS,    0, 4 },
 	{ 1,  600000, PLL0,    4, 0,   CPR_CORNER_NORMAL, 0, 6 },
@@ -106,7 +106,8 @@
 	{ 1, 1305600, ACPUPLL, 5, 0,   CPR_CORNER_TURBO,  0, 7 },
 	{ 1, 1344000, ACPUPLL, 5, 0,   CPR_CORNER_TURBO,  0, 7 },
 	{ 1, 1401600, ACPUPLL, 5, 0,   CPR_CORNER_TURBO,  0, 7 },
-	/* No support for 1p5 GHz yet */
+	{ 1, 1497600, ACPUPLL, 5, 0,   CPR_CORNER_TURBO,  0, 7 },
+	{ 1, 1593600, ACPUPLL, 5, 0,   CPR_CORNER_TURBO,  0, 7 },
 	{ 0 }
 };
 
@@ -125,8 +126,9 @@
 	[6] = acpu_freq_tbl_8226_1p2,
 	[2] = acpu_freq_tbl_8226_1p4,
 	[5] = acpu_freq_tbl_8226_1p4,
-	[3] = acpu_freq_tbl_8226_1p5,
-	[4] = acpu_freq_tbl_8226_1p5,
+	[4] = acpu_freq_tbl_8226_1p4,
+	[7] = acpu_freq_tbl_8226_1p4,
+	[1] = acpu_freq_tbl_8226_1p6,
 };
 
 static struct acpuclk_drv_data drv_data = {
diff --git a/arch/arm/mach-msm/acpuclock-krait.c b/arch/arm/mach-msm/acpuclock-krait.c
index db66d27..0479844 100644
--- a/arch/arm/mach-msm/acpuclock-krait.c
+++ b/arch/arm/mach-msm/acpuclock-krait.c
@@ -55,8 +55,12 @@
 	return drv.scalable[cpu].cur_speed->khz;
 }
 
-/* Select a source on the primary MUX. */
-static void set_pri_clk_src(struct scalable *sc, u32 pri_src_sel)
+struct set_clk_src_args {
+	struct scalable *sc;
+	u32 src_sel;
+};
+
+static void __set_pri_clk_src(struct scalable *sc, u32 pri_src_sel)
 {
 	u32 regval;
 
@@ -73,6 +77,27 @@
 	udelay(1);
 }
 
+static void __set_cpu_pri_clk_src(void *data)
+{
+	struct set_clk_src_args *args = data;
+	__set_pri_clk_src(args->sc, args->src_sel);
+}
+
+/* Select a source on the primary MUX. */
+static void set_pri_clk_src(struct scalable *sc, u32 pri_src_sel)
+{
+	int cpu = sc - drv.scalable;
+	if (sc != &drv.scalable[L2] && cpu_online(cpu)) {
+		struct set_clk_src_args args = {
+			.sc = sc,
+			.src_sel = pri_src_sel,
+		};
+		smp_call_function_single(cpu, __set_cpu_pri_clk_src, &args, 1);
+	} else {
+		__set_pri_clk_src(sc, pri_src_sel);
+	}
+}
+
 /* Select a source on the secondary MUX. */
 static void __cpuinit set_sec_clk_src(struct scalable *sc, u32 sec_src_sel)
 {
diff --git a/arch/arm/mach-msm/bam_dmux.c b/arch/arm/mach-msm/bam_dmux.c
index 820bcf9..6281395 100644
--- a/arch/arm/mach-msm/bam_dmux.c
+++ b/arch/arm/mach-msm/bam_dmux.c
@@ -195,6 +195,7 @@
 static struct sps_register_event rx_register_event;
 static bool satellite_mode;
 static uint32_t num_buffers;
+static unsigned long long last_rx_pkt_timestamp;
 
 static struct bam_ch_info bam_ch[BAM_DMUX_NUM_CHANNELS];
 static int bam_mux_initialized;
@@ -1117,6 +1118,29 @@
 	queue_work_on(0, bam_mux_rx_workqueue, &rx_timer_work);
 }
 
+/**
+ * store_rx_timestamp() - store the current raw time as as a timestamp for when
+ *			the last rx packet was processed
+ */
+static void store_rx_timestamp(void)
+{
+	last_rx_pkt_timestamp = sched_clock();
+}
+
+/**
+ * log_rx_timestamp() - Log the stored rx pkt timestamp in a human readable
+ *			format
+ */
+static void log_rx_timestamp(void)
+{
+	unsigned long long t = last_rx_pkt_timestamp;
+	unsigned long nanosec_rem;
+
+	nanosec_rem = do_div(t, 1000000000U);
+	BAM_DMUX_LOG("Last rx pkt processed at [%6u.%09lu]\n", (unsigned)t,
+								nanosec_rem);
+}
+
 static void rx_timer_work_func(struct work_struct *work)
 {
 	struct sps_iovec iov;
@@ -1125,20 +1149,26 @@
 	int ret;
 	u32 buffs_unused, buffs_used;
 
+	BAM_DMUX_LOG("%s: polling start\n", __func__);
 	while (bam_connection_is_active) { /* timer loop */
 		++inactive_cycles;
 		while (bam_connection_is_active) { /* deplete queue loop */
-			if (in_global_reset)
+			if (in_global_reset) {
+				BAM_DMUX_LOG(
+						"%s: polling exit, global reset detected\n",
+						__func__);
 				return;
+			}
 
 			ret = sps_get_iovec(bam_rx_pipe, &iov);
 			if (ret) {
-				pr_err("%s: sps_get_iovec failed %d\n",
+				DMUX_LOG_KERR("%s: sps_get_iovec failed %d\n",
 						__func__, ret);
 				break;
 			}
 			if (iov.addr == 0)
 				break;
+			store_rx_timestamp();
 			inactive_cycles = 0;
 			mutex_lock(&bam_rx_pool_mutexlock);
 			if (unlikely(list_empty(&bam_rx_pool))) {
@@ -1171,6 +1201,7 @@
 		}
 
 		if (inactive_cycles >= POLLING_INACTIVITY) {
+			BAM_DMUX_LOG("%s: polling exit, no data\n", __func__);
 			rx_switch_to_interrupt_mode();
 			break;
 		}
@@ -1182,7 +1213,8 @@
 						&buffs_unused);
 
 			if (ret) {
-				pr_err("%s: error getting num buffers unused after sleep\n",
+				DMUX_LOG_KERR(
+					"%s: error getting num buffers unused after sleep\n",
 					__func__);
 
 				break;
@@ -1768,6 +1800,7 @@
 		if (time_remaining == 0) {
 			DMUX_LOG_KERR("%s: shutdown completion timed out\n",
 					__func__);
+			log_rx_timestamp();
 			ssrestart_check();
 		}
 	}
diff --git a/arch/arm/mach-msm/board-8226-gpiomux.c b/arch/arm/mach-msm/board-8226-gpiomux.c
index 300ac4f..5dd9bab 100644
--- a/arch/arm/mach-msm/board-8226-gpiomux.c
+++ b/arch/arm/mach-msm/board-8226-gpiomux.c
@@ -73,17 +73,22 @@
 	.pull = GPIOMUX_PULL_NONE,
 };
 
-static struct gpiomux_setting gpio_spi_config = {
+static struct gpiomux_setting gpio_spi_act_config = {
 	.func = GPIOMUX_FUNC_1,
 	.drv = GPIOMUX_DRV_8MA,
 	.pull = GPIOMUX_PULL_NONE,
 };
 
-static struct gpiomux_setting gpio_spi_cs_config = {
+static struct gpiomux_setting gpio_spi_cs_act_config = {
 	.func = GPIOMUX_FUNC_1,
 	.drv = GPIOMUX_DRV_6MA,
 	.pull = GPIOMUX_PULL_DOWN,
 };
+static struct gpiomux_setting gpio_spi_susp_config = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_DOWN,
+};
 
 static struct gpiomux_setting gpio_spi_cs_eth_config = {
 	.func = GPIOMUX_FUNC_4,
@@ -160,48 +165,56 @@
 	{
 		.gpio      = 0,		/* BLSP1 QUP1 SPI_DATA_MOSI */
 		.settings = {
-			[GPIOMUX_SUSPENDED] = &gpio_spi_config,
+			[GPIOMUX_ACTIVE] = &gpio_spi_act_config,
+			[GPIOMUX_SUSPENDED] = &gpio_spi_susp_config,
 		},
 	},
 	{
 		.gpio      = 1,		/* BLSP1 QUP1 SPI_DATA_MISO */
 		.settings = {
-			[GPIOMUX_SUSPENDED] = &gpio_spi_config,
+			[GPIOMUX_ACTIVE] = &gpio_spi_act_config,
+			[GPIOMUX_SUSPENDED] = &gpio_spi_susp_config,
 		},
 	},
 	{
 		.gpio      = 2,		/* BLSP1 QUP1 SPI_CS1 */
 		.settings = {
-			[GPIOMUX_SUSPENDED] = &gpio_spi_cs_config,
+			[GPIOMUX_ACTIVE] = &gpio_spi_cs_act_config,
+			[GPIOMUX_SUSPENDED] = &gpio_spi_susp_config,
 		},
 	},
 	{
 		.gpio      = 3,		/* BLSP1 QUP1 SPI_CLK */
 		.settings = {
-			[GPIOMUX_SUSPENDED] = &gpio_spi_config,
+			[GPIOMUX_ACTIVE] = &gpio_spi_act_config,
+			[GPIOMUX_SUSPENDED] = &gpio_spi_susp_config,
 		},
 	},
 	{
 		.gpio      = 14,	/* BLSP1 QUP4 I2C_SDA */
 		.settings = {
+			[GPIOMUX_ACTIVE] = &gpio_i2c_config,
 			[GPIOMUX_SUSPENDED] = &gpio_i2c_config,
 		},
 	},
 	{
 		.gpio      = 15,	/* BLSP1 QUP4 I2C_SCL */
 		.settings = {
+			[GPIOMUX_ACTIVE] = &gpio_i2c_config,
 			[GPIOMUX_SUSPENDED] = &gpio_i2c_config,
 		},
 	},
 	{
 		.gpio      = 18,		/* BLSP1 QUP5 I2C_SDA */
 		.settings = {
+			[GPIOMUX_ACTIVE] = &gpio_i2c_config,
 			[GPIOMUX_SUSPENDED] = &gpio_i2c_config,
 		},
 	},
 	{
 		.gpio      = 19,		/* BLSP1 QUP5 I2C_SCL */
 		.settings = {
+			[GPIOMUX_ACTIVE] = &gpio_i2c_config,
 			[GPIOMUX_SUSPENDED] = &gpio_i2c_config,
 		},
 	},
@@ -214,12 +227,14 @@
 	{					/*  NFC   */
 		.gpio      = 10,		/* BLSP1 QUP3 I2C_DAT */
 		.settings = {
+			[GPIOMUX_ACTIVE] = &gpio_i2c_config,
 			[GPIOMUX_SUSPENDED] = &gpio_i2c_config,
 		},
 	},
 	{					/*  NFC   */
 		.gpio      = 11,		/* BLSP1 QUP3 I2C_CLK */
 		.settings = {
+			[GPIOMUX_ACTIVE] = &gpio_i2c_config,
 			[GPIOMUX_SUSPENDED] = &gpio_i2c_config,
 		},
 	},
@@ -336,12 +351,14 @@
 	{
 		.gpio      = 18,		/* BLSP1 QUP5 I2C_SDA */
 		.settings = {
+			[GPIOMUX_ACTIVE] = &gpio_i2c_config,
 			[GPIOMUX_SUSPENDED] = &gpio_i2c_config,
 		},
 	},
 	{
 		.gpio      = 19,		/* BLSP1 QUP5 I2C_SCL */
 		.settings = {
+			[GPIOMUX_ACTIVE] = &gpio_i2c_config,
 			[GPIOMUX_SUSPENDED] = &gpio_i2c_config,
 		},
 	},
@@ -410,12 +427,14 @@
 	{					/*  NFC   */
 		.gpio      = 10,		/* BLSP1 QUP3 I2C_DAT */
 		.settings = {
+			[GPIOMUX_ACTIVE] = &gpio_i2c_config,
 			[GPIOMUX_SUSPENDED] = &gpio_i2c_config,
 		},
 	},
 	{					/*  NFC   */
 		.gpio      = 11,		/* BLSP1 QUP3 I2C_CLK */
 		.settings = {
+			[GPIOMUX_ACTIVE] = &gpio_i2c_config,
 			[GPIOMUX_SUSPENDED] = &gpio_i2c_config,
 		},
 	},
diff --git a/arch/arm/mach-msm/board-8610-gpiomux.c b/arch/arm/mach-msm/board-8610-gpiomux.c
index dc9c13d..87794c4 100644
--- a/arch/arm/mach-msm/board-8610-gpiomux.c
+++ b/arch/arm/mach-msm/board-8610-gpiomux.c
@@ -23,6 +23,11 @@
 	.drv = GPIOMUX_DRV_6MA,
 	.pull = GPIOMUX_PULL_NONE,
 };
+static struct gpiomux_setting gpio_spi_susp_config = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_DOWN,
+};
 
 static struct gpiomux_setting gpio_i2c_config = {
 	.func = GPIOMUX_FUNC_3,
@@ -188,36 +193,42 @@
 	{
 		.gpio      = 2,		/* BLSP1 QUP1 I2C_SDA */
 		.settings = {
+			[GPIOMUX_ACTIVE] = &gpio_i2c_config,
 			[GPIOMUX_SUSPENDED] = &gpio_i2c_config,
 		},
 	},
 	{
 		.gpio      = 3,		/* BLSP1 QUP1 I2C_SCL */
 		.settings = {
+			[GPIOMUX_ACTIVE] = &gpio_i2c_config,
 			[GPIOMUX_SUSPENDED] = &gpio_i2c_config,
 		},
 	},
 	{
 		.gpio      = 10,	/* BLSP1 QUP3 I2C_SDA */
 		.settings = {
+			[GPIOMUX_ACTIVE] = &gpio_i2c_config,
 			[GPIOMUX_SUSPENDED] = &gpio_i2c_config,
 		},
 	},
 	{
 		.gpio      = 11,	/* BLSP1 QUP3 I2C_SCL */
 		.settings = {
+			[GPIOMUX_ACTIVE] = &gpio_i2c_config,
 			[GPIOMUX_SUSPENDED] = &gpio_i2c_config,
 		},
 	},
 	{
 		.gpio      = 16,	/* BLSP1 QUP6 I2C_SDA */
 		.settings = {
+			[GPIOMUX_ACTIVE] = &gpio_cam_i2c_config,
 			[GPIOMUX_SUSPENDED] = &gpio_cam_i2c_config,
 		},
 	},
 	{
 		.gpio      = 17,	/* BLSP1 QUP6 I2C_SCL */
 		.settings = {
+			[GPIOMUX_ACTIVE] = &gpio_cam_i2c_config,
 			[GPIOMUX_SUSPENDED] = &gpio_cam_i2c_config,
 		},
 	},
@@ -241,25 +252,29 @@
 	{
 		.gpio      = 86,		/* BLSP1 QUP4 SPI_DATA_MOSI */
 		.settings = {
-			[GPIOMUX_SUSPENDED] = &gpio_spi_config,
+			[GPIOMUX_ACTIVE] = &gpio_spi_config,
+			[GPIOMUX_SUSPENDED] = &gpio_spi_susp_config,
 		},
 	},
 	{
 		.gpio      = 87,		/* BLSP1 QUP4 SPI_DATA_MISO */
 		.settings = {
-			[GPIOMUX_SUSPENDED] = &gpio_spi_config,
+			[GPIOMUX_ACTIVE] = &gpio_spi_config,
+			[GPIOMUX_SUSPENDED] = &gpio_spi_susp_config,
 		},
 	},
 	{
 		.gpio      = 89,		/* BLSP1 QUP4 SPI_CLK */
 		.settings = {
-			[GPIOMUX_SUSPENDED] = &gpio_spi_config,
+			[GPIOMUX_ACTIVE] = &gpio_spi_config,
+			[GPIOMUX_SUSPENDED] = &gpio_spi_susp_config,
 		},
 	},
 	{
 		.gpio      = 88,		/* BLSP1 QUP4 SPI_CS */
 		.settings = {
-			[GPIOMUX_SUSPENDED] = &gpio_spi_config,
+			[GPIOMUX_ACTIVE] = &gpio_spi_config,
+			[GPIOMUX_SUSPENDED] = &gpio_spi_susp_config,
 		},
 	},
 };
@@ -282,25 +297,29 @@
 	{
 		.gpio      = 86,		/* BLSP1 QUP4 SPI_DATA_MOSI */
 		.settings = {
-			[GPIOMUX_SUSPENDED] = &gpio_spi_config,
+			[GPIOMUX_ACTIVE] = &gpio_spi_config,
+			[GPIOMUX_SUSPENDED] = &gpio_spi_susp_config,
 		},
 	},
 	{
 		.gpio      = 87,		/* BLSP1 QUP4 SPI_DATA_MISO */
 		.settings = {
-			[GPIOMUX_SUSPENDED] = &gpio_spi_config,
+			[GPIOMUX_ACTIVE] = &gpio_spi_config,
+			[GPIOMUX_SUSPENDED] = &gpio_spi_susp_config,
 		},
 	},
 	{
 		.gpio      = 89,		/* BLSP1 QUP4 SPI_CLK */
 		.settings = {
-			[GPIOMUX_SUSPENDED] = &gpio_spi_config,
+			[GPIOMUX_ACTIVE] = &gpio_spi_config,
+			[GPIOMUX_SUSPENDED] = &gpio_spi_susp_config,
 		},
 	},
 	{
 		.gpio      = 88,		/* BLSP1 QUP4 SPI_CS */
 		.settings = {
-			[GPIOMUX_SUSPENDED] = &gpio_spi_config,
+			[GPIOMUX_ACTIVE] = &gpio_spi_config,
+			[GPIOMUX_SUSPENDED] = &gpio_spi_susp_config,
 		},
 	},
 };
diff --git a/arch/arm/mach-msm/board-8974-gpiomux.c b/arch/arm/mach-msm/board-8974-gpiomux.c
index f170b7b..c35a607 100644
--- a/arch/arm/mach-msm/board-8974-gpiomux.c
+++ b/arch/arm/mach-msm/board-8974-gpiomux.c
@@ -143,6 +143,11 @@
 	.drv = GPIOMUX_DRV_12MA,
 	.pull = GPIOMUX_PULL_NONE,
 };
+static struct gpiomux_setting gpio_spi_susp_config = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_DOWN,
+};
 
 static struct gpiomux_setting gpio_spi_cs1_config = {
 	.func = GPIOMUX_FUNC_GPIO,
@@ -223,6 +228,17 @@
 	.pull = GPIOMUX_PULL_NONE,
 };
 
+static struct gpiomux_setting gpio_i2c_act_config = {
+	.func = GPIOMUX_FUNC_3,
+	/*
+	 * Please keep I2C GPIOs drive-strength at minimum (2ma). It is a
+	 * workaround for HW issue of glitches caused by rapid GPIO current-
+	 * change.
+	 */
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_UP,
+};
+
 static struct gpiomux_setting lcd_en_act_cfg = {
 	.func = GPIOMUX_FUNC_GPIO,
 	.drv = GPIOMUX_DRV_8MA,
@@ -553,31 +569,36 @@
 	{
 		.gpio      = 0,		/* BLSP1 QUP SPI_DATA_MOSI */
 		.settings = {
-			[GPIOMUX_SUSPENDED] = &gpio_spi_config,
+			[GPIOMUX_ACTIVE] = &gpio_spi_config,
+			[GPIOMUX_SUSPENDED] = &gpio_spi_susp_config,
 		},
 	},
 	{
 		.gpio      = 1,		/* BLSP1 QUP SPI_DATA_MISO */
 		.settings = {
-			[GPIOMUX_SUSPENDED] = &gpio_spi_config,
+			[GPIOMUX_ACTIVE] = &gpio_spi_config,
+			[GPIOMUX_SUSPENDED] = &gpio_spi_susp_config,
 		},
 	},
 	{
 		.gpio      = 3,		/* BLSP1 QUP SPI_CLK */
 		.settings = {
-			[GPIOMUX_SUSPENDED] = &gpio_spi_config,
+			[GPIOMUX_ACTIVE] = &gpio_spi_config,
+			[GPIOMUX_SUSPENDED] = &gpio_spi_susp_config,
 		},
 	},
 	{
 		.gpio      = 9,		/* BLSP1 QUP SPI_CS2A_N */
 		.settings = {
-			[GPIOMUX_SUSPENDED] = &gpio_spi_cs2_config,
+			[GPIOMUX_ACTIVE] = &gpio_spi_cs2_config,
+			[GPIOMUX_SUSPENDED] = &gpio_spi_susp_config,
 		},
 	},
 	{
 		.gpio      = 8,		/* BLSP1 QUP SPI_CS1_N */
 		.settings = {
-			[GPIOMUX_SUSPENDED] = &gpio_spi_cs1_config,
+			[GPIOMUX_ACTIVE] = &gpio_spi_cs1_config,
+			[GPIOMUX_SUSPENDED] = &gpio_spi_susp_config,
 		},
 	},
 #endif
@@ -585,12 +606,14 @@
 		.gpio      = 6,		/* BLSP1 QUP2 I2C_DAT */
 		.settings = {
 			[GPIOMUX_SUSPENDED] = &gpio_i2c_config,
+			[GPIOMUX_ACTIVE] = &gpio_i2c_act_config,
 		},
 	},
 	{
 		.gpio      = 7,		/* BLSP1 QUP2 I2C_CLK */
 		.settings = {
 			[GPIOMUX_SUSPENDED] = &gpio_i2c_config,
+			[GPIOMUX_ACTIVE] = &gpio_i2c_act_config,
 		},
 	},
 	{
diff --git a/arch/arm/mach-msm/clock-8226.c b/arch/arm/mach-msm/clock-8226.c
index ba792ab..1999379 100644
--- a/arch/arm/mach-msm/clock-8226.c
+++ b/arch/arm/mach-msm/clock-8226.c
@@ -2829,6 +2829,8 @@
 	F_APCS_PLL(1305600000, 68, 0x0, 0x1, 0x0, 0x0, 0x0),
 	F_APCS_PLL(1344000000, 70, 0x0, 0x1, 0x0, 0x0, 0x0),
 	F_APCS_PLL(1401600000, 73, 0x0, 0x1, 0x0, 0x0, 0x0),
+	F_APCS_PLL(1497600000, 78, 0x0, 0x1, 0x0, 0x0, 0x0),
+	F_APCS_PLL(1593600000, 83, 0x0, 0x1, 0x0, 0x0, 0x0),
 	PLL_F_END
 };
 
diff --git a/arch/arm/mach-msm/clock-8610.c b/arch/arm/mach-msm/clock-8610.c
index 92dab97..33dcd9f 100644
--- a/arch/arm/mach-msm/clock-8610.c
+++ b/arch/arm/mach-msm/clock-8610.c
@@ -3026,11 +3026,13 @@
 	CLK_LOOKUP("cam_src_clk", mclk0_clk_src.c, "6-006d"),
 	CLK_LOOKUP("cam_src_clk", mclk1_clk_src.c, "6-0078"),
 	CLK_LOOKUP("cam_src_clk", mclk0_clk_src.c, "6-0020"),
+	CLK_LOOKUP("cam_src_clk", mclk0_clk_src.c, "6-006a"),
 	CLK_LOOKUP("cam_clk", mclk0_clk.c, "6-006f"),
 	CLK_LOOKUP("cam_clk", mclk0_clk.c, "6-007d"),
 	CLK_LOOKUP("cam_clk", mclk0_clk.c, "6-006d"),
 	CLK_LOOKUP("cam_clk", mclk1_clk.c, "6-0078"),
 	CLK_LOOKUP("cam_clk", mclk0_clk.c, "6-0020"),
+	CLK_LOOKUP("cam_clk", mclk0_clk.c, "6-006a"),
 
 
 	/* CSIPHY clocks */
diff --git a/arch/arm/mach-msm/clock-8974.c b/arch/arm/mach-msm/clock-8974.c
index 3b80374..654dbd3 100644
--- a/arch/arm/mach-msm/clock-8974.c
+++ b/arch/arm/mach-msm/clock-8974.c
@@ -4897,10 +4897,29 @@
 	CLK_DUMMY("core_clk", NULL, "fdc84000.qcom,iommu", oFF),
 };
 
-static struct clk_lookup msm_clocks_8974ac_only[] __initdata = {
+static struct clk_lookup msm_clocks_8974pro_only[] __initdata = {
 	CLK_LOOKUP("gpll4", gpll4_clk_src.c, ""),
 	CLK_LOOKUP("sleep_clk", gcc_sdcc1_cdccal_sleep_clk.c, "msm_sdcc.1"),
 	CLK_LOOKUP("cal_clk", gcc_sdcc1_cdccal_ff_clk.c, "msm_sdcc.1"),
+	CLK_LOOKUP("cam_src_clk", mclk0_clk_src.c, "6e.qcom,camera"),
+	CLK_LOOKUP("cam_src_clk", mclk0_clk_src.c, "20.qcom,camera"),
+	CLK_LOOKUP("cam_src_clk", mclk2_clk_src.c, "6c.qcom,camera"),
+	CLK_LOOKUP("cam_src_clk", mclk1_clk_src.c, "90.qcom,camera"),
+	CLK_LOOKUP("cam_clk", camss_mclk0_clk.c, "6e.qcom,camera"),
+	CLK_LOOKUP("cam_clk", camss_mclk0_clk.c, "20.qcom,camera"),
+	CLK_LOOKUP("cam_clk", camss_mclk2_clk.c, "6c.qcom,camera"),
+	CLK_LOOKUP("cam_clk", camss_mclk1_clk.c, "90.qcom,camera"),
+};
+
+static struct clk_lookup msm_clocks_8974_only[] __initdata = {
+	CLK_LOOKUP("cam_src_clk", mmss_gp0_clk_src.c, "6e.qcom,camera"),
+	CLK_LOOKUP("cam_src_clk", mmss_gp0_clk_src.c, "20.qcom,camera"),
+	CLK_LOOKUP("cam_src_clk", gp1_clk_src.c, "6c.qcom,camera"),
+	CLK_LOOKUP("cam_src_clk", mmss_gp1_clk_src.c, "90.qcom,camera"),
+	CLK_LOOKUP("cam_clk", camss_gp0_clk.c, "6e.qcom,camera"),
+	CLK_LOOKUP("cam_clk", camss_gp0_clk.c, "20.qcom,camera"),
+	CLK_LOOKUP("cam_clk", gcc_gp1_clk.c, "6c.qcom,camera"),
+	CLK_LOOKUP("cam_clk", camss_gp1_clk.c, "90.qcom,camera"),
 };
 
 static struct clk_lookup msm_clocks_8974_common[] __initdata = {
@@ -5076,22 +5095,16 @@
 	CLK_LOOKUP("core_clk_src", mdp_clk_src.c, "mdp.0"),
 	CLK_LOOKUP("vsync_clk", mdss_vsync_clk.c, "mdp.0"),
 
-	/* MM sensor clocks */
-	CLK_LOOKUP("cam_src_clk", mmss_gp0_clk_src.c, "6e.qcom,camera"),
-	CLK_LOOKUP("cam_src_clk", mmss_gp0_clk_src.c, "20.qcom,camera"),
-	CLK_LOOKUP("cam_src_clk", gp1_clk_src.c, "6c.qcom,camera"),
-	CLK_LOOKUP("cam_src_clk", mmss_gp1_clk_src.c, "90.qcom,camera"),
-	CLK_LOOKUP("cam_clk", camss_gp0_clk.c, "6e.qcom,camera"),
-	CLK_LOOKUP("cam_clk", camss_gp0_clk.c, "20.qcom,camera"),
-	CLK_LOOKUP("cam_clk", gcc_gp1_clk.c, "6c.qcom,camera"),
-	CLK_LOOKUP("cam_clk", camss_gp1_clk.c, "90.qcom,camera"),
-	CLK_LOOKUP("cam_clk", camss_mclk1_clk.c, ""),
-	CLK_LOOKUP("cam_clk", camss_mclk2_clk.c, ""),
-	CLK_LOOKUP("cam_clk", camss_mclk3_clk.c, ""),
-	CLK_LOOKUP("cam_gp0_src_clk", mmss_gp0_clk_src.c, ""),
-	CLK_LOOKUP("cam_gp1_src_clk", mmss_gp1_clk_src.c, ""),
-	CLK_LOOKUP("cam_gp0_clk", camss_gp0_clk.c, ""),
-	CLK_LOOKUP("cam_gp1_clk", camss_gp1_clk.c, ""),
+	/* MM sensor clocks placeholder */
+	CLK_LOOKUP("", camss_mclk0_clk.c, ""),
+	CLK_LOOKUP("", camss_mclk1_clk.c, ""),
+	CLK_LOOKUP("", camss_mclk2_clk.c, ""),
+	CLK_LOOKUP("", camss_mclk3_clk.c, ""),
+	CLK_LOOKUP("", mmss_gp0_clk_src.c, ""),
+	CLK_LOOKUP("", mmss_gp1_clk_src.c, ""),
+	CLK_LOOKUP("", camss_gp0_clk.c, ""),
+	CLK_LOOKUP("", camss_gp1_clk.c, ""),
+
 	/* CCI clocks */
 	CLK_LOOKUP("camss_top_ahb_clk", camss_top_ahb_clk.c,
 		"fda0c000.qcom,cci"),
@@ -5450,7 +5463,8 @@
 };
 
 static struct clk_lookup msm_clocks_8974[ARRAY_SIZE(msm_clocks_8974_common)
-	+ ARRAY_SIZE(msm_clocks_8974ac_only)];
+	+ ARRAY_SIZE(msm_clocks_8974_only)
+	+ ARRAY_SIZE(msm_clocks_8974pro_only)];
 
 static struct pll_config_regs mmpll0_regs __initdata = {
 	.l_reg = (void __iomem *)MMPLL0_L_REG,
@@ -5797,18 +5811,26 @@
 
 	memcpy(msm_clocks_8974, msm_clocks_8974_common,
 	       sizeof(msm_clocks_8974_common));
-	msm8974_clock_init_data.size -= ARRAY_SIZE(msm_clocks_8974ac_only);
 
-	/* version specific changes */
+	/* version specific clock changes */
 	if (SOCINFO_VERSION_MAJOR(socinfo_get_version()) >= 2
 	    || cpu_is_msm8974pro())
 		msm8974_v2_clock_override();
-	if (cpu_is_msm8974pro()) {
+	if (cpu_is_msm8974pro())
 		msm8974_pro_clock_override();
+
+	/* version specific lookup table changes */
+	if (cpu_is_msm8974()) {
 		memcpy(msm_clocks_8974 + ARRAY_SIZE(msm_clocks_8974_common),
-		       msm_clocks_8974ac_only, sizeof(msm_clocks_8974ac_only));
+		       msm_clocks_8974_only, sizeof(msm_clocks_8974_only));
 		msm8974_clock_init_data.size +=
-			ARRAY_SIZE(msm_clocks_8974ac_only);
+			ARRAY_SIZE(msm_clocks_8974_only);
+	} else if (cpu_is_msm8974pro()) {
+		memcpy(msm_clocks_8974 + ARRAY_SIZE(msm_clocks_8974_common),
+		       msm_clocks_8974pro_only,
+		       sizeof(msm_clocks_8974pro_only));
+		msm8974_clock_init_data.size +=
+			ARRAY_SIZE(msm_clocks_8974pro_only);
 	}
 
 	clk_ops_pixel_clock = clk_ops_pixel;
@@ -5841,7 +5863,7 @@
 
 struct clock_init_data msm8974_clock_init_data __initdata = {
 	.table = msm_clocks_8974,
-	.size = ARRAY_SIZE(msm_clocks_8974),
+	.size = ARRAY_SIZE(msm_clocks_8974_common),
 	.pre_init = msm8974_clock_pre_init,
 	.post_init = msm8974_clock_post_init,
 };
diff --git a/arch/arm/mach-msm/cpr-regulator.c b/arch/arm/mach-msm/cpr-regulator.c
index b69b155..59e0e2a 100644
--- a/arch/arm/mach-msm/cpr-regulator.c
+++ b/arch/arm/mach-msm/cpr-regulator.c
@@ -148,7 +148,7 @@
 	void __iomem	*efuse_base;
 
 	/* Process voltage parameters */
-	u32		pvs_bin_process[CPR_PVS_EFUSE_BINS_MAX];
+	u32		pvs_init_v[CPR_PVS_EFUSE_BINS_MAX];
 	u32		pvs_corner_v[NUM_APC_PVS][CPR_CORNER_MAX];
 	/* Process voltage variables */
 	u32		pvs_bin;
@@ -999,6 +999,7 @@
 	u64 efuse_bits;
 	int rc, process;
 	u32 pvs_fuse[3], pvs_fuse_redun_sel[4];
+	u32 init_v;
 	bool redundant;
 	size_t pvs_bins;
 
@@ -1034,25 +1035,35 @@
 				   ((1 << pvs_fuse[2]) - 1);
 
 	pvs_bins = 1 << pvs_fuse[2];
-	rc = of_property_read_u32_array(of_node, "qcom,pvs-bin-process",
-					cpr_vreg->pvs_bin_process,
-					pvs_bins);
+
+	rc = of_property_read_u32_array(of_node, "qcom,pvs-init-voltage",
+					cpr_vreg->pvs_init_v, pvs_bins);
 	if (rc < 0) {
-		pr_err("pvs-bin-process missing: rc=%d\n", rc);
+		pr_err("pvs-init-voltage missing: rc=%d\n", rc);
 		return rc;
 	}
 
-	process = cpr_vreg->pvs_bin_process[cpr_vreg->pvs_bin];
-	pr_info("[row:%d] = 0x%llX, n_bits=%d, bin=%d (%d)\n",
-		pvs_fuse[0], efuse_bits, pvs_fuse[2],
-		cpr_vreg->pvs_bin, process);
+	init_v = cpr_vreg->pvs_init_v[cpr_vreg->pvs_bin];
+	for (process = NUM_APC_PVS - 1; process > APC_PVS_NO; process--) {
+		if (init_v <= cpr_vreg->pvs_corner_v[process][CPR_CORNER_TURBO])
+			break;
+	}
 
-	if (process == APC_PVS_NO || process >= NUM_APC_PVS) {
-		pr_err("Bin=%d (%d) is out of spec. Assume SLOW.\n",
-		       cpr_vreg->pvs_bin, process);
+	if (process == APC_PVS_NO) {
+		process = APC_PVS_SLOW;
+		cpr_vreg->pvs_corner_v[process][CPR_CORNER_TURBO] = init_v;
+		cpr_vreg->ceiling_max = init_v;
+	} else if (process == APC_PVS_FAST &&
+		init_v < cpr_vreg->pvs_corner_v[APC_PVS_FAST][CPR_CORNER_SVS]) {
 		process = APC_PVS_SLOW;
 	}
 
+	pr_info("[row:%d] = 0x%llX, n_bits=%d, bin=%d (%d)",
+		pvs_fuse[0], efuse_bits, pvs_fuse[2],
+		cpr_vreg->pvs_bin, process);
+	pr_info("pvs initial turbo voltage_= from %u to %u\n",
+		init_v, cpr_vreg->pvs_corner_v[process][CPR_CORNER_TURBO]);
+
 	cpr_vreg->process = process;
 
 	return 0;
diff --git a/arch/arm/mach-msm/ipc_router.c b/arch/arm/mach-msm/ipc_router.c
index 6fe945c..ce66531 100644
--- a/arch/arm/mach-msm/ipc_router.c
+++ b/arch/arm/mach-msm/ipc_router.c
@@ -298,6 +298,8 @@
 		pr_err("%s: failure\n", __func__);
 		return NULL;
 	}
+	memcpy(&(cloned_pkt->hdr), &(pkt->hdr), sizeof(struct rr_header_v1));
+	/* TODO: Copy optional headers, if available */
 
 	pkt_fragment_q = kmalloc(sizeof(struct sk_buff_head), GFP_KERNEL);
 	if (!pkt_fragment_q) {
@@ -323,6 +325,7 @@
 		kfree_skb(temp_skb);
 	}
 	kfree(pkt_fragment_q);
+	/* TODO: Free optional headers, if present */
 	kfree(cloned_pkt);
 	return NULL;
 }
@@ -361,6 +364,7 @@
 		kfree_skb(temp_skb);
 	}
 	kfree(pkt->pkt_fragment_q);
+	/* TODO: Free Optional headers, if present */
 	kfree(pkt);
 	return;
 }
@@ -373,6 +377,8 @@
 	int first = 1, offset = 0;
 	int skb_size, data_size;
 	void *data;
+	int last = 1;
+	int align_size;
 
 	skb_head = kmalloc(sizeof(struct sk_buff_head), GFP_KERNEL);
 	if (!skb_head) {
@@ -382,10 +388,13 @@
 	skb_queue_head_init(skb_head);
 
 	data_size = buf_len;
+	align_size = ALIGN_SIZE(data_size);
 	while (offset != buf_len) {
 		skb_size = data_size;
 		if (first)
 			skb_size += IPC_ROUTER_HDR_SIZE;
+		if (last)
+			skb_size += align_size;
 
 		skb = alloc_skb(skb_size, GFP_KERNEL);
 		if (!skb) {
@@ -394,6 +403,7 @@
 				goto buf_to_skb_error;
 			}
 			data_size = data_size / 2;
+			last = 0;
 			continue;
 		}
 
@@ -407,6 +417,7 @@
 		skb_queue_tail(skb_head, skb);
 		offset += data_size;
 		data_size = buf_len - offset;
+		last = 1;
 	}
 	return skb_head;
 
@@ -447,7 +458,7 @@
 	return buf;
 }
 
-static void msm_ipc_router_free_skb(struct sk_buff_head *skb_head)
+void msm_ipc_router_free_skb(struct sk_buff_head *skb_head)
 {
 	struct sk_buff *temp_skb;
 
@@ -461,6 +472,328 @@
 	kfree(skb_head);
 }
 
+/**
+ * extract_header_v1() - Extract IPC Router header of version 1
+ * @pkt: Packet structure into which the header has to be extraced.
+ * @skb: SKB from which the header has to be extracted.
+ *
+ * @return: 0 on success, standard Linux error codes on failure.
+ */
+static int extract_header_v1(struct rr_packet *pkt, struct sk_buff *skb)
+{
+	if (!pkt || !skb) {
+		pr_err("%s: Invalid pkt or skb\n", __func__);
+		return -EINVAL;
+	}
+
+	memcpy(&pkt->hdr, skb->data, sizeof(struct rr_header_v1));
+	skb_pull(skb, sizeof(struct rr_header_v1));
+	pkt->length -= sizeof(struct rr_header_v1);
+	return 0;
+}
+
+/**
+ * extract_header_v2() - Extract IPC Router header of version 2
+ * @pkt: Packet structure into which the header has to be extraced.
+ * @skb: SKB from which the header has to be extracted.
+ *
+ * @return: 0 on success, standard Linux error codes on failure.
+ */
+static int extract_header_v2(struct rr_packet *pkt, struct sk_buff *skb)
+{
+	struct rr_header_v2 *hdr;
+
+	if (!pkt || !skb) {
+		pr_err("%s: Invalid pkt or skb\n", __func__);
+		return -EINVAL;
+	}
+
+	hdr = (struct rr_header_v2 *)skb->data;
+	pkt->hdr.version = (uint32_t)hdr->version;
+	pkt->hdr.type = (uint32_t)hdr->type;
+	pkt->hdr.src_node_id = (uint32_t)hdr->src_node_id;
+	pkt->hdr.src_port_id = (uint32_t)hdr->src_port_id;
+	pkt->hdr.size = (uint32_t)hdr->size;
+	pkt->hdr.control_flag = (uint32_t)hdr->control_flag;
+	pkt->hdr.dst_node_id = (uint32_t)hdr->dst_node_id;
+	pkt->hdr.dst_port_id = (uint32_t)hdr->dst_port_id;
+	skb_pull(skb, sizeof(struct rr_header_v2));
+	pkt->length -= sizeof(struct rr_header_v2);
+	return 0;
+}
+
+/**
+ * extract_header() - Extract IPC Router header
+ * @pkt: Packet from which the header has to be extraced.
+ *
+ * @return: 0 on success, standard Linux error codes on failure.
+ *
+ * This function will check if the header version is v1 or v2 and invoke
+ * the corresponding helper function to extract the IPC Router header.
+ */
+static int extract_header(struct rr_packet *pkt)
+{
+	struct sk_buff *temp_skb;
+	int ret;
+
+	if (!pkt) {
+		pr_err("%s: NULL PKT\n", __func__);
+		return -EINVAL;
+	}
+
+	temp_skb = skb_peek(pkt->pkt_fragment_q);
+	if (!temp_skb || !temp_skb->data) {
+		pr_err("%s: No SKBs in skb_queue\n", __func__);
+		return -EINVAL;
+	}
+
+	if (temp_skb->data[0] == IPC_ROUTER_V1) {
+		ret = extract_header_v1(pkt, temp_skb);
+	} else if (temp_skb->data[0] == IPC_ROUTER_V2) {
+		ret = extract_header_v2(pkt, temp_skb);
+		/* TODO: Extract optional headers if present */
+	} else {
+		pr_err("%s: Invalid Header version %02x\n",
+			__func__, temp_skb->data[0]);
+		print_hex_dump(KERN_ERR, "Header: ", DUMP_PREFIX_ADDRESS,
+			       16, 1, temp_skb->data, pkt->length, true);
+		return -EINVAL;
+	}
+	return ret;
+}
+
+/**
+ * calc_tx_header_size() - Calculate header size to be reserved in SKB
+ * @pkt: Packet in which the space for header has to be reserved.
+ * @dst_xprt_info: XPRT through which the destination is reachable.
+ *
+ * @return: required header size on success,
+ *          starndard Linux error codes on failure.
+ *
+ * This function is used to calculate the header size that has to be reserved
+ * in a transmit SKB. The header size is calculated based on the XPRT through
+ * which the destination node is reachable.
+ */
+static int calc_tx_header_size(struct rr_packet *pkt,
+			       struct msm_ipc_router_xprt_info *dst_xprt_info)
+{
+	int hdr_size = 0;
+	int xprt_version = 0;
+	struct msm_ipc_routing_table_entry *rt_entry;
+	struct msm_ipc_router_xprt_info *xprt_info = dst_xprt_info;
+
+	if (!pkt) {
+		pr_err("%s: NULL PKT\n", __func__);
+		return -EINVAL;
+	}
+
+	if (!xprt_info) {
+		rt_entry = lookup_routing_table(pkt->hdr.dst_node_id);
+		if (!rt_entry || !(rt_entry->xprt_info)) {
+			pr_err("%s: Node %d is not up\n",
+				__func__, pkt->hdr.dst_node_id);
+			return -ENODEV;
+		}
+
+		xprt_info = rt_entry->xprt_info;
+	}
+	if (xprt_info)
+		xprt_version = xprt_info->xprt->get_version(xprt_info->xprt);
+
+	if (xprt_version == IPC_ROUTER_V1) {
+		pkt->hdr.version = IPC_ROUTER_V1;
+		hdr_size = sizeof(struct rr_header_v1);
+	} else if (xprt_version == IPC_ROUTER_V2) {
+		pkt->hdr.version = IPC_ROUTER_V2;
+		hdr_size = sizeof(struct rr_header_v2);
+		/* TODO: Calculate optional header length, if present */
+	} else {
+		pr_err("%s: Invalid xprt_version %d\n",
+			__func__, xprt_version);
+		hdr_size = -EINVAL;
+	}
+
+	return hdr_size;
+}
+
+/**
+ * prepend_header_v1() - Prepend IPC Router header of version 1
+ * @pkt: Packet structure which contains the header info to be prepended.
+ * @hdr_size: Size of the header
+ *
+ * @return: 0 on success, standard Linux error codes on failure.
+ */
+static int prepend_header_v1(struct rr_packet *pkt, int hdr_size)
+{
+	struct sk_buff *temp_skb;
+	struct rr_header_v1 *hdr;
+
+	if (!pkt || hdr_size <= 0) {
+		pr_err("%s: Invalid input parameters\n", __func__);
+		return -EINVAL;
+	}
+
+	temp_skb = skb_peek(pkt->pkt_fragment_q);
+	if (!temp_skb || !temp_skb->data) {
+		pr_err("%s: No SKBs in skb_queue\n", __func__);
+		return -EINVAL;
+	}
+
+	if (skb_headroom(temp_skb) < hdr_size) {
+		temp_skb = alloc_skb(hdr_size, GFP_KERNEL);
+		if (!temp_skb) {
+			pr_err("%s: Could not allocate SKB of size %d\n",
+				__func__, hdr_size);
+			return -ENOMEM;
+		}
+	}
+
+	hdr = (struct rr_header_v1 *)skb_push(temp_skb, hdr_size);
+	memcpy(hdr, &pkt->hdr, hdr_size);
+	if (temp_skb != skb_peek(pkt->pkt_fragment_q))
+		skb_queue_head(pkt->pkt_fragment_q, temp_skb);
+	pkt->length += hdr_size;
+	return 0;
+}
+
+/**
+ * prepend_header_v2() - Prepend IPC Router header of version 2
+ * @pkt: Packet structure which contains the header info to be prepended.
+ * @hdr_size: Size of the header
+ *
+ * @return: 0 on success, standard Linux error codes on failure.
+ */
+static int prepend_header_v2(struct rr_packet *pkt, int hdr_size)
+{
+	struct sk_buff *temp_skb;
+	struct rr_header_v2 *hdr;
+
+	if (!pkt || hdr_size <= 0) {
+		pr_err("%s: Invalid input parameters\n", __func__);
+		return -EINVAL;
+	}
+
+	temp_skb = skb_peek(pkt->pkt_fragment_q);
+	if (!temp_skb || !temp_skb->data) {
+		pr_err("%s: No SKBs in skb_queue\n", __func__);
+		return -EINVAL;
+	}
+
+	if (skb_headroom(temp_skb) < hdr_size) {
+		temp_skb = alloc_skb(hdr_size, GFP_KERNEL);
+		if (!temp_skb) {
+			pr_err("%s: Could not allocate SKB of size %d\n",
+				__func__, hdr_size);
+			return -ENOMEM;
+		}
+	}
+
+	hdr = (struct rr_header_v2 *)skb_push(temp_skb, hdr_size);
+	hdr->version = (uint8_t)pkt->hdr.version;
+	hdr->type = (uint8_t)pkt->hdr.type;
+	hdr->control_flag = (uint16_t)pkt->hdr.control_flag;
+	hdr->size = (uint32_t)pkt->hdr.size;
+	hdr->src_node_id = (uint16_t)pkt->hdr.src_node_id;
+	hdr->src_port_id = (uint16_t)pkt->hdr.src_port_id;
+	hdr->dst_node_id = (uint16_t)pkt->hdr.dst_node_id;
+	hdr->dst_port_id = (uint16_t)pkt->hdr.dst_port_id;
+	/* TODO: Add optional headers, if present */
+	if (temp_skb != skb_peek(pkt->pkt_fragment_q))
+		skb_queue_head(pkt->pkt_fragment_q, temp_skb);
+	pkt->length += hdr_size;
+	return 0;
+}
+
+/**
+ * prepend_header() - Prepend IPC Router header
+ * @pkt: Packet structure which contains the header info to be prepended.
+ * @xprt_info: XPRT through which the packet is transmitted.
+ *
+ * @return: 0 on success, standard Linux error codes on failure.
+ *
+ * This function prepends the header to the packet to be transmitted. The
+ * IPC Router header version to be prepended depends on the XPRT through
+ * which the destination is reachable.
+ */
+static int prepend_header(struct rr_packet *pkt,
+			  struct msm_ipc_router_xprt_info *xprt_info)
+{
+	int hdr_size;
+	struct sk_buff *temp_skb;
+
+	if (!pkt) {
+		pr_err("%s: NULL PKT\n", __func__);
+		return -EINVAL;
+	}
+
+	temp_skb = skb_peek(pkt->pkt_fragment_q);
+	if (!temp_skb || !temp_skb->data) {
+		pr_err("%s: No SKBs in skb_queue\n", __func__);
+		return -EINVAL;
+	}
+
+	hdr_size = calc_tx_header_size(pkt, xprt_info);
+	if (hdr_size <= 0)
+		return hdr_size;
+
+	if (pkt->hdr.version == IPC_ROUTER_V1)
+		return prepend_header_v1(pkt, hdr_size);
+	else if (pkt->hdr.version == IPC_ROUTER_V2)
+		return prepend_header_v2(pkt, hdr_size);
+	else
+		return -EINVAL;
+}
+
+/**
+ * defragment_pkt() - Defragment and linearize the packet
+ * @pkt: Packet to be linearized.
+ *
+ * @return: 0 on success, standard Linux error codes on failure.
+ *
+ * Some packets contain fragments of data over multiple SKBs. If an XPRT
+ * does not supported fragmented writes, linearize multiple SKBs into one
+ * single SKB.
+ */
+static int defragment_pkt(struct rr_packet *pkt)
+{
+	struct sk_buff *dst_skb, *src_skb, *temp_skb;
+	int offset = 0, buf_len = 0, copy_len;
+	void *buf;
+	int align_size;
+
+	if (!pkt || pkt->length <= 0) {
+		pr_err("%s: Invalid PKT\n", __func__);
+		return -EINVAL;
+	}
+
+	if (skb_queue_len(pkt->pkt_fragment_q) == 1)
+		return 0;
+
+	align_size = ALIGN_SIZE(pkt->length);
+	dst_skb = alloc_skb(pkt->length + align_size, GFP_KERNEL);
+	if (!dst_skb) {
+		pr_err("%s: could not allocate one skb of size %d\n",
+			__func__, pkt->length);
+		return -ENOMEM;
+	}
+	buf = skb_put(dst_skb, pkt->length);
+	buf_len = pkt->length;
+
+	skb_queue_walk(pkt->pkt_fragment_q, src_skb) {
+		copy_len =  buf_len < src_skb->len ? buf_len : src_skb->len;
+		memcpy(buf + offset, src_skb->data, copy_len);
+		offset += copy_len;
+		buf_len -= copy_len;
+	}
+
+	while (!skb_queue_empty(pkt->pkt_fragment_q)) {
+		temp_skb = skb_dequeue(pkt->pkt_fragment_q);
+		kfree_skb(temp_skb);
+	}
+	skb_queue_tail(pkt->pkt_fragment_q, dst_skb);
+	return 0;
+}
+
 static int post_pkt_to_port(struct msm_ipc_port *port_ptr,
 			    struct rr_packet *pkt, int clone)
 {
@@ -515,7 +848,7 @@
 	down_read(&local_ports_lock_lha2);
 	do {
 		next_port_id++;
-		if ((next_port_id & 0xFFFFFFFE) == 0xFFFFFFFE)
+		if ((next_port_id & IPC_ROUTER_ADDRESS) == IPC_ROUTER_ADDRESS)
 			next_port_id = 1;
 
 		key = (next_port_id & (LP_HASH_SIZE - 1));
@@ -932,7 +1265,7 @@
 {
 	struct rr_packet *pkt;
 	struct sk_buff *ipc_rtr_pkt;
-	struct rr_header *hdr;
+	struct rr_header_v1 *hdr;
 	int pkt_size;
 	void *data;
 	struct sk_buff_head *pkt_fragment_q;
@@ -973,32 +1306,33 @@
 	skb_reserve(ipc_rtr_pkt, IPC_ROUTER_HDR_SIZE);
 	data = skb_put(ipc_rtr_pkt, sizeof(*msg));
 	memcpy(data, msg, sizeof(*msg));
-	hdr = (struct rr_header *)skb_push(ipc_rtr_pkt, IPC_ROUTER_HDR_SIZE);
-	if (!hdr) {
-		pr_err("%s: skb_push failed\n", __func__);
-		kfree_skb(ipc_rtr_pkt);
-		kfree(pkt_fragment_q);
-		kfree(pkt);
-		return -ENOMEM;
-	}
+	skb_queue_tail(pkt_fragment_q, ipc_rtr_pkt);
+	pkt->pkt_fragment_q = pkt_fragment_q;
+	pkt->length = sizeof(*msg);
 
-	hdr->version = IPC_ROUTER_VERSION;
+	hdr = &(pkt->hdr);
+	hdr->version = IPC_ROUTER_V1;
 	hdr->type = msg->cmd;
 	hdr->src_node_id = IPC_ROUTER_NID_LOCAL;
 	hdr->src_port_id = IPC_ROUTER_ADDRESS;
-	hdr->confirm_rx = 0;
+	hdr->control_flag = 0;
 	hdr->size = sizeof(*msg);
 	if (hdr->type == IPC_ROUTER_CTRL_CMD_RESUME_TX)
 		hdr->dst_node_id = dst_node_id;
 	else
 		hdr->dst_node_id = xprt_info->remote_node_id;
 	hdr->dst_port_id = IPC_ROUTER_ADDRESS;
-	skb_queue_tail(pkt_fragment_q, ipc_rtr_pkt);
-	pkt->pkt_fragment_q = pkt_fragment_q;
-	pkt->length = pkt_size;
 
 	mutex_lock(&xprt_info->tx_lock_lhb2);
-	ret = xprt_info->xprt->write(pkt, pkt_size, xprt_info->xprt);
+	ret = prepend_header(pkt, xprt_info);
+	if (ret < 0) {
+		mutex_unlock(&xprt_info->tx_lock_lhb2);
+		pr_err("%s: Prepend Header failed\n", __func__);
+		release_pkt(pkt);
+		return ret;
+	}
+
+	ret = xprt_info->xprt->write(pkt, pkt->length, xprt_info->xprt);
 	mutex_unlock(&xprt_info->tx_lock_lhb2);
 
 	release_pkt(pkt);
@@ -1074,7 +1408,7 @@
 {
 	struct rr_packet *pkt;
 	struct sk_buff *ipc_rtr_pkt;
-	struct rr_header *hdr;
+	struct rr_header_v1 *hdr;
 	int pkt_size;
 	void *data;
 	struct sk_buff_head *pkt_fragment_q;
@@ -1094,7 +1428,7 @@
 	}
 	skb_queue_head_init(pkt_fragment_q);
 
-	pkt_size = IPC_ROUTER_HDR_SIZE + sizeof(*msg);
+	pkt_size = sizeof(*msg);
 	ipc_rtr_pkt = alloc_skb(pkt_size, GFP_KERNEL);
 	if (!ipc_rtr_pkt) {
 		pr_err("%s: ipc_rtr_pkt alloc failed\n", __func__);
@@ -1103,22 +1437,14 @@
 		return -ENOMEM;
 	}
 
-	skb_reserve(ipc_rtr_pkt, IPC_ROUTER_HDR_SIZE);
 	data = skb_put(ipc_rtr_pkt, sizeof(*msg));
 	memcpy(data, msg, sizeof(*msg));
-	hdr = (struct rr_header *)skb_push(ipc_rtr_pkt, IPC_ROUTER_HDR_SIZE);
-	if (!hdr) {
-		pr_err("%s: skb_push failed\n", __func__);
-		kfree_skb(ipc_rtr_pkt);
-		kfree(pkt_fragment_q);
-		kfree(pkt);
-		return -ENOMEM;
-	}
-	hdr->version = IPC_ROUTER_VERSION;
+	hdr = &(pkt->hdr);
+	hdr->version = IPC_ROUTER_V1;
 	hdr->type = msg->cmd;
 	hdr->src_node_id = IPC_ROUTER_NID_LOCAL;
 	hdr->src_port_id = IPC_ROUTER_ADDRESS;
-	hdr->confirm_rx = 0;
+	hdr->control_flag = 0;
 	hdr->size = sizeof(*msg);
 	hdr->dst_node_id = IPC_ROUTER_NID_LOCAL;
 	hdr->dst_port_id = IPC_ROUTER_ADDRESS;
@@ -1164,70 +1490,60 @@
 	return 0;
 }
 
-static int relay_msg(struct msm_ipc_router_xprt_info *xprt_info,
-		     struct rr_packet *pkt)
-{
-	struct msm_ipc_router_xprt_info *fwd_xprt_info;
-
-	if (!xprt_info || !pkt)
-		return -EINVAL;
-
-	down_read(&xprt_info_list_lock_lha5);
-	list_for_each_entry(fwd_xprt_info, &xprt_info_list, list) {
-		mutex_lock(&fwd_xprt_info->tx_lock_lhb2);
-		if (xprt_info->xprt->link_id != fwd_xprt_info->xprt->link_id)
-			fwd_xprt_info->xprt->write(pkt, pkt->length,
-						   fwd_xprt_info->xprt);
-		mutex_unlock(&fwd_xprt_info->tx_lock_lhb2);
-	}
-	up_read(&xprt_info_list_lock_lha5);
-	return 0;
-}
-
 static int forward_msg(struct msm_ipc_router_xprt_info *xprt_info,
 		       struct rr_packet *pkt)
 {
-	uint32_t dst_node_id;
-	struct sk_buff *head_pkt;
-	struct rr_header *hdr;
+	struct rr_header_v1 *hdr;
 	struct msm_ipc_router_xprt_info *fwd_xprt_info;
 	struct msm_ipc_routing_table_entry *rt_entry;
 	int ret = 0;
+	int fwd_xprt_option;
 
 	if (!xprt_info || !pkt)
 		return -EINVAL;
 
-	head_pkt = skb_peek(pkt->pkt_fragment_q);
-	if (!head_pkt)
-		return -EINVAL;
-
-	hdr = (struct rr_header *)head_pkt->data;
-	dst_node_id = hdr->dst_node_id;
+	hdr = &(pkt->hdr);
 	down_read(&routing_table_lock_lha3);
-	rt_entry = lookup_routing_table(dst_node_id);
+	rt_entry = lookup_routing_table(hdr->dst_node_id);
 	if (!(rt_entry) || !(rt_entry->xprt_info)) {
-		up_read(&routing_table_lock_lha3);
 		pr_err("%s: Routing table not initialized\n", __func__);
-		return -ENODEV;
+		ret = -ENODEV;
+		goto fm_error1;
 	}
 
 	down_read(&rt_entry->lock_lha4);
 	fwd_xprt_info = rt_entry->xprt_info;
+	ret = prepend_header(pkt, fwd_xprt_info);
+	if (ret < 0) {
+		pr_err("%s: Prepend Header failed\n", __func__);
+		goto fm_error2;
+	}
+	fwd_xprt_option = fwd_xprt_info->xprt->get_option(fwd_xprt_info->xprt);
+	if (!(fwd_xprt_option & FRAG_PKT_WRITE_ENABLE)) {
+		ret = defragment_pkt(pkt);
+		if (ret < 0)
+			goto fm_error2;
+	}
+
+	mutex_lock(&fwd_xprt_info->tx_lock_lhb2);
 	if (xprt_info->remote_node_id == fwd_xprt_info->remote_node_id) {
 		pr_err("%s: Discarding Command to route back\n", __func__);
 		ret = -EINVAL;
-		goto fwd_msg_out;
+		goto fm_error3;
 	}
 
 	if (xprt_info->xprt->link_id == fwd_xprt_info->xprt->link_id) {
 		pr_err("%s: DST in the same cluster\n", __func__);
-		goto fwd_msg_out;
+		ret = 0;
+		goto fm_error3;
 	}
-	mutex_lock(&fwd_xprt_info->tx_lock_lhb2);
 	fwd_xprt_info->xprt->write(pkt, pkt->length, fwd_xprt_info->xprt);
+
+fm_error3:
 	mutex_unlock(&fwd_xprt_info->tx_lock_lhb2);
-fwd_msg_out:
+fm_error2:
 	up_read(&rt_entry->lock_lha4);
+fm_error1:
 	up_read(&routing_table_lock_lha3);
 
 	return ret;
@@ -1470,7 +1786,7 @@
 }
 
 static int process_hello_msg(struct msm_ipc_router_xprt_info *xprt_info,
-			     struct rr_header *hdr)
+			     struct rr_header_v1 *hdr)
 {
 	int i, rc = 0;
 	union rr_control_msg ctl;
@@ -1508,7 +1824,7 @@
 
 	/* Send a reply HELLO message */
 	memset(&ctl, 0, sizeof(ctl));
-	ctl.cmd = IPC_ROUTER_CTRL_CMD_HELLO;
+	ctl.hello.cmd = IPC_ROUTER_CTRL_CMD_HELLO;
 	rc = msm_ipc_router_send_control_msg(xprt_info, &ctl,
 						IPC_ROUTER_DUMMY_DEST_NODE);
 	if (rc < 0) {
@@ -1654,7 +1970,7 @@
 	 * to the cluster from which this message is received. Notify the
 	 * local clients waiting for this service.
 	 */
-	relay_msg(xprt_info, pkt);
+	relay_ctl_msg(xprt_info, msg);
 	post_control_ports(pkt);
 	return 0;
 }
@@ -1677,7 +1993,7 @@
 		 * belong to the cluster from which this message is received.
 		 * Notify the local clients communicating with the service.
 		 */
-		relay_msg(xprt_info, pkt);
+		relay_ctl_msg(xprt_info, msg);
 		post_control_ports(pkt);
 	}
 	up_write(&server_list_lock_lha2);
@@ -1697,7 +2013,7 @@
 		msm_ipc_router_destroy_remote_port(rport_ptr);
 	up_write(&routing_table_lock_lha3);
 
-	relay_msg(xprt_info, pkt);
+	relay_ctl_msg(xprt_info, msg);
 	post_control_ports(pkt);
 	return 0;
 }
@@ -1707,26 +2023,20 @@
 {
 	union rr_control_msg *msg;
 	int rc = 0;
-	struct sk_buff *temp_ptr;
-	struct rr_header *hdr;
+	struct rr_header_v1 *hdr;
 
-	if (pkt->length != (IPC_ROUTER_HDR_SIZE + sizeof(*msg))) {
+	if (pkt->length != sizeof(*msg)) {
 		pr_err("%s: r2r msg size %d != %d\n", __func__, pkt->length,
-			(IPC_ROUTER_HDR_SIZE + sizeof(*msg)));
+			sizeof(*msg));
 		return -EINVAL;
 	}
 
-	temp_ptr = skb_peek(pkt->pkt_fragment_q);
-	if (!temp_ptr) {
-		pr_err("%s: pkt_fragment_q is empty\n", __func__);
-		return -EINVAL;
+	hdr = &(pkt->hdr);
+	msg = msm_ipc_router_skb_to_buf(pkt->pkt_fragment_q, sizeof(*msg));
+	if (!msg) {
+		pr_err("%s: Error extracting control msg\n", __func__);
+		return -ENOMEM;
 	}
-	hdr = (struct rr_header *)temp_ptr->data;
-	if (!hdr) {
-		pr_err("%s: No data inside the skb\n", __func__);
-		return -EINVAL;
-	}
-	msg = (union rr_control_msg *)((char *)hdr + IPC_ROUTER_HDR_SIZE);
 
 	switch (msg->cmd) {
 	case IPC_ROUTER_CTRL_CMD_HELLO:
@@ -1752,17 +2062,17 @@
 		RR("o UNKNOWN(%08x)\n", msg->cmd);
 		rc = -ENOSYS;
 	}
-
+	kfree(msg);
 	return rc;
 }
 
 static void do_read_data(struct work_struct *work)
 {
-	struct rr_header *hdr;
+	struct rr_header_v1 *hdr;
 	struct rr_packet *pkt = NULL;
 	struct msm_ipc_port *port_ptr;
-	struct sk_buff *head_skb;
 	struct msm_ipc_router_remote_port *rport_ptr;
+	int ret;
 
 	struct msm_ipc_router_xprt_info *xprt_info =
 		container_of(work,
@@ -1777,24 +2087,15 @@
 			goto fail_data;
 		}
 
-		head_skb = skb_peek(pkt->pkt_fragment_q);
-		if (!head_skb) {
-			pr_err("%s: head_skb is invalid\n", __func__);
+		ret = extract_header(pkt);
+		if (ret < 0)
 			goto fail_data;
-		}
-
-		hdr = (struct rr_header *)(head_skb->data);
+		hdr = &(pkt->hdr);
 		RAW("ver=%d type=%d src=%d:%08x crx=%d siz=%d dst=%d:%08x\n",
 		     hdr->version, hdr->type, hdr->src_node_id,
-		     hdr->src_port_id, hdr->confirm_rx, hdr->size,
+		     hdr->src_port_id, hdr->control_flag, hdr->size,
 		     hdr->dst_node_id, hdr->dst_port_id);
 
-		if (hdr->version != IPC_ROUTER_VERSION) {
-			pr_err("version %d != %d\n",
-				hdr->version, IPC_ROUTER_VERSION);
-			goto fail_data;
-		}
-
 		if ((hdr->dst_node_id != IPC_ROUTER_NID_LOCAL) &&
 		    ((hdr->type == IPC_ROUTER_CTRL_CMD_RESUME_TX) ||
 		     (hdr->type == IPC_ROUTER_CTRL_CMD_DATA))) {
@@ -1803,8 +2104,7 @@
 			continue;
 		}
 
-		if ((hdr->dst_port_id == IPC_ROUTER_ADDRESS) ||
-		    (hdr->type == IPC_ROUTER_CTRL_CMD_HELLO)) {
+		if (hdr->type != IPC_ROUTER_CTRL_CMD_DATA) {
 			process_control_msg(xprt_info, pkt);
 			release_pkt(pkt);
 			continue;
@@ -1819,7 +2119,7 @@
 				(hdr->src_port_id & 0xffffff),
 				(hdr->dst_node_id << 24) |
 				(hdr->dst_port_id & 0xffffff),
-				(hdr->type << 24) | (hdr->confirm_rx << 16) |
+				(hdr->type << 24) | (hdr->control_flag << 16) |
 				(hdr->size & 0xffff));
 		}
 #endif
@@ -1906,6 +2206,7 @@
 	ctl.srv.port_id = port_ptr->this_port.port_id;
 	up_write(&server_list_lock_lha2);
 	broadcast_ctl_msg(&ctl);
+	broadcast_ctl_msg_locally(&ctl);
 	spin_lock_irqsave(&port_ptr->port_lock, flags);
 	port_ptr->type = SERVER_PORT;
 	port_ptr->mode_info.mode = MULTI_LINK_MODE;
@@ -1957,6 +2258,7 @@
 				      port_ptr->this_port.port_id);
 	up_write(&server_list_lock_lha2);
 	broadcast_ctl_msg(&ctl);
+	broadcast_ctl_msg_locally(&ctl);
 	spin_lock_irqsave(&port_ptr->port_lock, flags);
 	port_ptr->type = CLIENT_PORT;
 	spin_unlock_irqrestore(&port_ptr->port_lock, flags);
@@ -1967,8 +2269,7 @@
 			uint32_t port_id,
 			struct sk_buff_head *data)
 {
-	struct sk_buff *head_skb;
-	struct rr_header *hdr;
+	struct rr_header_v1 *hdr;
 	struct msm_ipc_port *port_ptr;
 	struct rr_packet *pkt;
 	int ret_len;
@@ -1983,34 +2284,22 @@
 		pr_err("%s: New pkt create failed\n", __func__);
 		return -ENOMEM;
 	}
-
-	head_skb = skb_peek(pkt->pkt_fragment_q);
-	if (!head_skb) {
-		pr_err("%s: pkt_fragment_q is empty\n", __func__);
-		release_pkt(pkt);
-		return -EINVAL;
-	}
-	hdr = (struct rr_header *)skb_push(head_skb, IPC_ROUTER_HDR_SIZE);
-	if (!hdr) {
-		pr_err("%s: Prepend Header failed\n", __func__);
-		release_pkt(pkt);
-		return -ENOMEM;
-	}
-	hdr->version = IPC_ROUTER_VERSION;
+	hdr = &(pkt->hdr);
+	hdr->version = IPC_ROUTER_V1;
 	hdr->type = IPC_ROUTER_CTRL_CMD_DATA;
 	hdr->src_node_id = src->this_port.node_id;
 	hdr->src_port_id = src->this_port.port_id;
 	hdr->size = pkt->length;
-	hdr->confirm_rx = 0;
+	hdr->control_flag = 0;
 	hdr->dst_node_id = IPC_ROUTER_NID_LOCAL;
 	hdr->dst_port_id = port_id;
-	pkt->length += IPC_ROUTER_HDR_SIZE;
 
 	down_read(&local_ports_lock_lha2);
 	port_ptr = msm_ipc_router_lookup_local_port(port_id);
 	if (!port_ptr) {
 		pr_err("%s: Local port %d not present\n", __func__, port_id);
 		up_read(&local_ports_lock_lha2);
+		pkt->pkt_fragment_q = NULL;
 		release_pkt(pkt);
 		return -ENODEV;
 	}
@@ -2027,35 +2316,26 @@
 				struct msm_ipc_router_remote_port *rport_ptr,
 				struct rr_packet *pkt)
 {
-	struct sk_buff *head_skb;
-	struct rr_header *hdr;
+	struct rr_header_v1 *hdr;
 	struct msm_ipc_router_xprt_info *xprt_info;
 	struct msm_ipc_routing_table_entry *rt_entry;
 	struct msm_ipc_resume_tx_port  *resume_tx_port;
+	struct sk_buff *temp_skb;
+	int xprt_option;
 	int ret;
+	int align_size;
 
 	if (!rport_ptr || !src || !pkt)
 		return -EINVAL;
 
-	head_skb = skb_peek(pkt->pkt_fragment_q);
-	if (!head_skb) {
-		pr_err("%s: pkt_fragment_q is empty\n", __func__);
-		return -EINVAL;
-	}
-	hdr = (struct rr_header *)skb_push(head_skb, IPC_ROUTER_HDR_SIZE);
-	if (!hdr) {
-		pr_err("%s: Prepend Header failed\n", __func__);
-		return -ENOMEM;
-	}
-	hdr->version = IPC_ROUTER_VERSION;
+	hdr = &(pkt->hdr);
 	hdr->type = IPC_ROUTER_CTRL_CMD_DATA;
 	hdr->src_node_id = src->this_port.node_id;
 	hdr->src_port_id = src->this_port.port_id;
 	hdr->size = pkt->length;
-	hdr->confirm_rx = 0;
+	hdr->control_flag = 0;
 	hdr->dst_node_id = rport_ptr->node_id;
 	hdr->dst_port_id = rport_ptr->port_id;
-	pkt->length += IPC_ROUTER_HDR_SIZE;
 
 	mutex_lock(&rport_ptr->quota_lock_lhb2);
 	if (rport_ptr->tx_quota_cnt == IPC_ROUTER_DEFAULT_RX_QUOTA) {
@@ -2083,7 +2363,7 @@
 	}
 	rport_ptr->tx_quota_cnt++;
 	if (rport_ptr->tx_quota_cnt == IPC_ROUTER_DEFAULT_RX_QUOTA)
-		hdr->confirm_rx = 1;
+		hdr->control_flag |= CONTROL_FLAG_CONFIRM_RX;
 	mutex_unlock(&rport_ptr->quota_lock_lhb2);
 
 	rt_entry = lookup_routing_table(hdr->dst_node_id);
@@ -2094,6 +2374,25 @@
 	}
 	down_read(&rt_entry->lock_lha4);
 	xprt_info = rt_entry->xprt_info;
+	ret = prepend_header(pkt, xprt_info);
+	if (ret < 0) {
+		up_read(&rt_entry->lock_lha4);
+		pr_err("%s: Prepend Header failed\n", __func__);
+		return ret;
+	}
+	xprt_option = xprt_info->xprt->get_option(xprt_info->xprt);
+	if (!(xprt_option & FRAG_PKT_WRITE_ENABLE)) {
+		ret = defragment_pkt(pkt);
+		if (ret < 0) {
+			up_read(&rt_entry->lock_lha4);
+			return ret;
+		}
+	}
+
+	temp_skb = skb_peek_tail(pkt->pkt_fragment_q);
+	align_size = ALIGN_SIZE(pkt->length);
+	skb_put(temp_skb, align_size);
+	pkt->length += align_size;
 	mutex_lock(&xprt_info->tx_lock_lhb2);
 	ret = xprt_info->xprt->write(pkt, pkt->length, xprt_info->xprt);
 	mutex_unlock(&xprt_info->tx_lock_lhb2);
@@ -2107,10 +2406,10 @@
 
 	RAW_HDR("[w rr_h] "
 		"ver=%i,type=%s,src_nid=%08x,src_port_id=%08x,"
-		"confirm_rx=%i,size=%3i,dst_pid=%08x,dst_cid=%08x\n",
+		"control_flag=%i,size=%3i,dst_pid=%08x,dst_cid=%08x\n",
 		hdr->version, type_to_str(hdr->type),
 		hdr->src_node_id, hdr->src_port_id,
-		hdr->confirm_rx, hdr->size,
+		hdr->control_flag, hdr->size,
 		hdr->dst_node_id, hdr->dst_port_id);
 
 #if defined(CONFIG_MSM_SMD_LOGGING)
@@ -2123,13 +2422,13 @@
 			(hdr->src_port_id & 0xffffff),
 			(hdr->dst_node_id << 24) |
 			(hdr->dst_port_id & 0xffffff),
-			(hdr->type << 24) | (hdr->confirm_rx << 16) |
+			(hdr->type << 24) | (hdr->control_flag << 16) |
 			(hdr->size & 0xffff));
 	}
 #endif
 #endif
 
-	return pkt->length;
+	return hdr->size;
 }
 
 int msm_ipc_router_send_to(struct msm_ipc_port *src,
@@ -2203,6 +2502,8 @@
 
 	ret = msm_ipc_router_write_pkt(src, rport_ptr, pkt);
 	up_read(&routing_table_lock_lha3);
+	if (ret < 0)
+		pkt->pkt_fragment_q = NULL;
 	release_pkt(pkt);
 
 	return ret;
@@ -2222,11 +2523,10 @@
 	}
 
 	ret = msm_ipc_router_send_to(src, out_skb_head, dest);
-	if (ret == -EAGAIN)
-		return ret;
 	if (ret < 0) {
-		pr_err("%s: msm_ipc_router_send_to failed - ret: %d\n",
-			__func__, ret);
+		if (ret != -EAGAIN)
+			pr_err("%s: msm_ipc_router_send_to failed - ret: %d\n",
+				__func__, ret);
 		msm_ipc_router_free_skb(out_skb_head);
 		return ret;
 	}
@@ -2248,7 +2548,7 @@
 static int msm_ipc_router_send_resume_tx(void *data)
 {
 	union rr_control_msg msg;
-	struct rr_header *hdr = (struct rr_header *)data;
+	struct rr_header_v1 *hdr = (struct rr_header_v1 *)data;
 	struct msm_ipc_routing_table_entry *rt_entry;
 	int ret;
 
@@ -2278,14 +2578,12 @@
 }
 
 int msm_ipc_router_read(struct msm_ipc_port *port_ptr,
-			struct sk_buff_head **data,
+			struct rr_packet **read_pkt,
 			size_t buf_len)
 {
 	struct rr_packet *pkt;
-	struct sk_buff *head_skb;
-	int ret;
 
-	if (!port_ptr || !data)
+	if (!port_ptr || !read_pkt)
 		return -EINVAL;
 
 	mutex_lock(&port_ptr->port_rx_q_lock_lhb3);
@@ -2295,26 +2593,19 @@
 	}
 
 	pkt = list_first_entry(&port_ptr->port_rx_q, struct rr_packet, list);
-	if ((buf_len) && ((pkt->length - IPC_ROUTER_HDR_SIZE) > buf_len)) {
+	if ((buf_len) && (pkt->hdr.size > buf_len)) {
 		mutex_unlock(&port_ptr->port_rx_q_lock_lhb3);
 		return -ETOOSMALL;
 	}
 	list_del(&pkt->list);
 	if (list_empty(&port_ptr->port_rx_q))
 		wake_unlock(&port_ptr->port_rx_wake_lock);
-	*data = pkt->pkt_fragment_q;
-	ret = pkt->length;
+	*read_pkt = pkt;
 	mutex_unlock(&port_ptr->port_rx_q_lock_lhb3);
-	kfree(pkt);
-	head_skb = skb_peek(*data);
-	if (!head_skb) {
-		pr_err("%s: Socket Buffer not found", __func__);
-		return -EFAULT;
-	}
-	if (((struct rr_header *)(head_skb->data))->confirm_rx)
-		msm_ipc_router_send_resume_tx((void *)(head_skb->data));
+	if (pkt->hdr.control_flag & CONTROL_FLAG_CONFIRM_RX)
+		msm_ipc_router_send_resume_tx(&pkt->hdr);
 
-	return ret;
+	return pkt->length;
 }
 
 /**
@@ -2362,7 +2653,7 @@
 /**
  * msm_ipc_router_recv_from() - Recieve messages destined to a local port.
  * @port_ptr: Pointer to the local port
- * @data : Pointer to the socket buffer head
+ * @pkt : Pointer to the router-to-router packet
  * @src: Pointer to local port address
  * @timeout: < 0 timeout indicates infinite wait till a message arrives.
  *	     > 0 timeout indicates the wait time.
@@ -2383,31 +2674,30 @@
  * of bytes that are read.
  */
 int msm_ipc_router_recv_from(struct msm_ipc_port *port_ptr,
-			     struct sk_buff_head **data,
+			     struct rr_packet **pkt,
 			     struct msm_ipc_addr *src,
 			     long timeout)
 {
 	int ret, data_len, align_size;
 	struct sk_buff *temp_skb;
-	struct rr_header *hdr = NULL;
+	struct rr_header_v1 *hdr = NULL;
 
-	if (!port_ptr || !data) {
+	if (!port_ptr || !pkt) {
 		pr_err("%s: Invalid pointers being passed\n", __func__);
 		return -EINVAL;
 	}
 
-	*data = NULL;
+	*pkt = NULL;
 
 	ret = msm_ipc_router_rx_data_wait(port_ptr, timeout);
 	if (ret)
 		return ret;
 
-	ret = msm_ipc_router_read(port_ptr, data, 0);
-	if (ret <= 0 || !(*data))
+	ret = msm_ipc_router_read(port_ptr, pkt, 0);
+	if (ret <= 0 || !(*pkt))
 		return ret;
 
-	temp_skb = skb_peek(*data);
-	hdr = (struct rr_header *)(temp_skb->data);
+	hdr = &((*pkt)->hdr);
 	if (src) {
 		src->addrtype = MSM_IPC_ADDR_ID;
 		src->addr.port_addr.node_id = hdr->src_node_id;
@@ -2415,10 +2705,9 @@
 	}
 
 	data_len = hdr->size;
-	skb_pull(temp_skb, IPC_ROUTER_HDR_SIZE);
 	align_size = ALIGN_SIZE(data_len);
 	if (align_size) {
-		temp_skb = skb_peek_tail(*data);
+		temp_skb = skb_peek_tail((*pkt)->pkt_fragment_q);
 		skb_trim(temp_skb, (temp_skb->len - align_size));
 	}
 	return data_len;
@@ -2429,11 +2718,10 @@
 			    unsigned char **data,
 			    unsigned int *len)
 {
-	struct sk_buff_head *in_skb_head;
+	struct rr_packet *pkt;
 	int ret;
 
-	ret = msm_ipc_router_recv_from(port_ptr, &in_skb_head, src, 0);
-
+	ret = msm_ipc_router_recv_from(port_ptr, &pkt, src, 0);
 	if (ret < 0) {
 		if (ret != -ENOMSG)
 			pr_err("%s: msm_ipc_router_recv_from failed - ret: %d\n",
@@ -2441,12 +2729,12 @@
 		return ret;
 	}
 
-	*data = msm_ipc_router_skb_to_buf(in_skb_head, ret);
+	*data = msm_ipc_router_skb_to_buf(pkt->pkt_fragment_q, ret);
 	if (!(*data))
 		pr_err("%s: Buf conversion failed\n", __func__);
 
 	*len = ret;
-	msm_ipc_router_free_skb(in_skb_head);
+	release_pkt(pkt);
 	return 0;
 }
 
diff --git a/arch/arm/mach-msm/ipc_router.h b/arch/arm/mach-msm/ipc_router.h
index 7bfc52b..8ffd661 100644
--- a/arch/arm/mach-msm/ipc_router.h
+++ b/arch/arm/mach-msm/ipc_router.h
@@ -24,12 +24,17 @@
 #include <net/sock.h>
 
 /* definitions for the R2R wire protcol */
-#define IPC_ROUTER_VERSION			1
+#define IPC_ROUTER_V1		1
+/*
+ * Ambiguous definition but will enable multiplexing IPC_ROUTER_V2 packets
+ * with an existing alternate transport in user-space, if needed.
+ */
+#define IPC_ROUTER_V2		3
 
-#define IPC_ROUTER_CLIENT_BCAST_ID		0xffffffff
-#define IPC_ROUTER_ADDRESS			0xfffffffe
+#define IPC_ROUTER_ADDRESS			0x0000FFFF
 
 #define IPC_ROUTER_NID_LOCAL			1
+#define MAX_IPC_PKT_SIZE 66000
 
 #define IPC_ROUTER_CTRL_CMD_DATA		1
 #define IPC_ROUTER_CTRL_CMD_HELLO		2
@@ -55,6 +60,11 @@
 #define ALL_SERVICE 0xFFFFFFFF
 #define ALL_INSTANCE 0xFFFFFFFF
 
+#define CONTROL_FLAG_CONFIRM_RX 0x1
+#define CONTROL_FLAG_OPT_HDR 0x2
+
+#define FRAG_PKT_WRITE_ENABLE 0x1
+
 enum {
 	CLIENT_PORT,
 	SERVER_PORT,
@@ -68,10 +78,22 @@
 	MULTI_LINK_MODE,
 };
 
+/**
+ * rr_control_msg - Control message structure
+ * @cmd: Command identifier for HELLO message in Version 1.
+ * @hello: Message structure for HELLO message in Version 2.
+ * @srv: Message structure for NEW_SERVER/REMOVE_SERVER events.
+ * @cli: Message structure for REMOVE_CLIENT event.
+ */
 union rr_control_msg {
 	uint32_t cmd;
 	struct {
 		uint32_t cmd;
+		uint32_t magic;
+		uint32_t capability;
+	} hello;
+	struct {
+		uint32_t cmd;
 		uint32_t service;
 		uint32_t instance;
 		uint32_t node_id;
@@ -84,22 +106,67 @@
 	} cli;
 };
 
-struct rr_header {
+/**
+ * rr_header_v1 - IPC Router header version 1
+ * @version: Version information.
+ * @type: IPC Router Message Type.
+ * @src_node_id: Source Node ID of the message.
+ * @src_port_id: Source Port ID of the message.
+ * @control_flag: Flag to indicate flow control.
+ * @size: Size of the IPC Router payload.
+ * @dst_node_id: Destination Node ID of the message.
+ * @dst_port_id: Destination Port ID of the message.
+ */
+struct rr_header_v1 {
 	uint32_t version;
 	uint32_t type;
 	uint32_t src_node_id;
 	uint32_t src_port_id;
-	uint32_t confirm_rx;
+	uint32_t control_flag;
 	uint32_t size;
 	uint32_t dst_node_id;
 	uint32_t dst_port_id;
 };
 
-#define IPC_ROUTER_HDR_SIZE sizeof(struct rr_header)
-#define MAX_IPC_PKT_SIZE 66000
+/**
+ * rr_header_v2 - IPC Router header version 2
+ * @version: Version information.
+ * @type: IPC Router Message Type.
+ * @control_flag: Flags to indicate flow control, optional header etc.
+ * @size: Size of the IPC Router payload.
+ * @src_node_id: Source Node ID of the message.
+ * @src_port_id: Source Port ID of the message.
+ * @dst_node_id: Destination Node ID of the message.
+ * @dst_port_id: Destination Port ID of the message.
+ */
+struct rr_header_v2 {
+	uint8_t version;
+	uint8_t type;
+	uint16_t control_flag;
+	uint32_t size;
+	uint16_t src_node_id;
+	uint16_t src_port_id;
+	uint16_t dst_node_id;
+	uint16_t dst_port_id;
+} __attribute__((__packed__));
 
+union rr_header {
+	struct rr_header_v1 hdr_v1;
+	struct rr_header_v2 hdr_v2;
+};
+
+#define IPC_ROUTER_HDR_SIZE sizeof(union rr_header)
+
+/**
+ * rr_packet - Router to Router packet structure
+ * @list: Pointer to prev & next packets in a port's rx list.
+ * @hdr: Header information extracted from or prepended to a packet.
+ * @pkt_fragment_q: Queue of SKBs containing payload.
+ * @length: Length of data in the chain of SKBs
+ */
 struct rr_packet {
 	struct list_head list;
+	struct rr_header_v1 hdr;
 	struct sk_buff_head *pkt_fragment_q;
 	uint32_t length;
 };
@@ -110,11 +177,28 @@
 	void *default_pil;
 };
 
+/**
+ * msm_ipc_router_xprt - Structure to hold XPRT specific information
+ * @name: Name of the XPRT.
+ * @link_id: Network cluster ID to which the XPRT belongs to.
+ * @priv: XPRT's private data.
+ * @get_version: Method to get header version supported by the XPRT.
+ * @get_option: Method to get XPRT specific options.
+ * @read_avail: Method to get data size available to be read from the XPRT.
+ * @read: Method to read data from the XPRT.
+ * @write_avail: Method to get write space available in the XPRT.
+ * @write: Method to write data to the XPRT.
+ * @close: Method to close the XPRT.
+ * @sft_close_done: Method to indicate to the XPRT that handling of reset
+ *                  event is complete.
+ */
 struct msm_ipc_router_xprt {
 	char *name;
 	uint32_t link_id;
 	void *priv;
 
+	int (*get_version)(struct msm_ipc_router_xprt *xprt);
+	int (*get_option)(struct msm_ipc_router_xprt *xprt);
 	int (*read_avail)(struct msm_ipc_router_xprt *xprt);
 	int (*read)(void *data, uint32_t len,
 		    struct msm_ipc_router_xprt *xprt);
@@ -141,12 +225,12 @@
 			   struct sk_buff_head *data,
 			   struct msm_ipc_addr *dest);
 int msm_ipc_router_read(struct msm_ipc_port *port_ptr,
-			struct sk_buff_head **data,
+			struct rr_packet **pkt,
 			size_t buf_len);
 int msm_ipc_router_bind_control_port(struct msm_ipc_port *port_ptr);
 
 int msm_ipc_router_recv_from(struct msm_ipc_port *port_ptr,
-		      struct sk_buff_head **data,
+		      struct rr_packet **pkt,
 		      struct msm_ipc_addr *src_addr,
 		      long timeout);
 int msm_ipc_router_register_server(struct msm_ipc_port *server_port,
@@ -173,4 +257,5 @@
 static inline void msm_ipc_unload_default_node(void *pil) { }
 #endif
 
+void msm_ipc_router_free_skb(struct sk_buff_head *skb_head);
 #endif
diff --git a/arch/arm/mach-msm/ipc_router_hsic_xprt.c b/arch/arm/mach-msm/ipc_router_hsic_xprt.c
new file mode 100644
index 0000000..0427c1c
--- /dev/null
+++ b/arch/arm/mach-msm/ipc_router_hsic_xprt.c
@@ -0,0 +1,503 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/*
+ * IPC ROUTER HSIC XPRT module.
+ */
+#define DEBUG
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/types.h>
+
+#include <mach/ipc_bridge.h>
+#include <mach/subsystem_restart.h>
+
+#include "ipc_router.h"
+
+static int msm_ipc_router_hsic_xprt_debug_mask;
+module_param_named(debug_mask, msm_ipc_router_hsic_xprt_debug_mask,
+		   int, S_IRUGO | S_IWUSR | S_IWGRP);
+
+#if defined(DEBUG)
+#define D(x...) do { \
+if (msm_ipc_router_hsic_xprt_debug_mask) \
+	pr_info(x); \
+} while (0)
+#else
+#define D(x...) do { } while (0)
+#endif
+
+#define NUM_HSIC_XPRTS 1
+#define XPRT_NAME_LEN 32
+
+/**
+ * msm_ipc_router_hsic_xprt - IPC Router's HSIC XPRT strucutre
+ * @xprt: IPC Router XPRT structure to contain HSIC XPRT specific info.
+ * @pdev: Platform device registered by IPC Bridge function driver.
+ * @hsic_xprt_wq: Workqueue to queue read & other XPRT related works.
+ * @read_work: Read Work to perform read operation from HSIC's ipc_bridge.
+ * @in_pkt: Pointer to any partially read packet.
+ * @ss_reset_lock: Lock to protect access to the ss_reset flag.
+ * @sft_close_complete: Variable to indicate completion of SSR handling
+ *                      by IPC Router.
+ * @xprt_version: IPC Router header version supported by this XPRT.
+ * @xprt_option: XPRT specific options to be handled by IPC Router.
+ */
+struct msm_ipc_router_hsic_xprt {
+	struct msm_ipc_router_xprt xprt;
+	struct platform_device *pdev;
+	struct workqueue_struct *hsic_xprt_wq;
+	struct delayed_work read_work;
+	struct rr_packet *in_pkt;
+	struct mutex ss_reset_lock;
+	int ss_reset;
+	struct completion sft_close_complete;
+	unsigned xprt_version;
+	unsigned xprt_option;
+};
+
+struct msm_ipc_router_hsic_xprt_work {
+	struct msm_ipc_router_xprt *xprt;
+	struct work_struct work;
+};
+
+static void hsic_xprt_read_data(struct work_struct *work);
+
+/**
+ * msm_ipc_router_hsic_xprt_config - Config. Info. of each HSIC XPRT
+ * @ch_name: Name of the HSIC endpoint exported by ipc_bridge driver.
+ * @xprt_name: Name of the XPRT to be registered with IPC Router.
+ * @hsic_pdev_id: ID to differentiate among multiple ipc_bridge endpoints.
+ * @link_id: Network Cluster ID to which this XPRT belongs to.
+ * @xprt_version: IPC Router header version supported by this XPRT.
+ */
+struct msm_ipc_router_hsic_xprt_config {
+	char ch_name[XPRT_NAME_LEN];
+	char xprt_name[XPRT_NAME_LEN];
+	int hsic_pdev_id;
+	uint32_t link_id;
+	unsigned xprt_version;
+};
+
+struct msm_ipc_router_hsic_xprt_config hsic_xprt_cfg[] = {
+	{"ipc_bridge", "ipc_rtr_ipc_bridge1", 1, 1, 3},
+};
+
+static struct msm_ipc_router_hsic_xprt hsic_remote_xprt[NUM_HSIC_XPRTS];
+
+/**
+ * find_hsic_xprt_cfg() - Find the config info specific to an HSIC endpoint
+ * @pdev: Platform device registered by HSIC's ipc_bridge driver
+ *
+ * @return: Index to the entry in the hsic_remote_xprt table if matching
+ *          endpoint is found, < 0 on error.
+ *
+ * This function is used to find the configuration information specific to
+ * an HSIC endpoint from the hsic_remote_xprt table.
+ */
+static int find_hsic_xprt_cfg(struct platform_device *pdev)
+{
+	int i;
+
+	for (i = 0; i < NUM_HSIC_XPRTS; i++) {
+		/* TODO: Update the condition for multiple hsic links */
+		if (!strncmp(pdev->name, hsic_xprt_cfg[i].ch_name, 32))
+			return i;
+	}
+
+	return -ENODEV;
+}
+
+/**
+ * msm_ipc_router_hsic_get_xprt_version() - Get IPC Router header version
+ *                                          supported by the XPRT
+ * @xprt: XPRT for which the version information is required.
+ *
+ * @return: IPC Router header version supported by the XPRT.
+ */
+static int msm_ipc_router_hsic_get_xprt_version(
+	struct msm_ipc_router_xprt *xprt)
+{
+	struct msm_ipc_router_hsic_xprt *hsic_xprtp;
+	if (!xprt)
+		return -EINVAL;
+	hsic_xprtp = container_of(xprt, struct msm_ipc_router_hsic_xprt, xprt);
+
+	return (int)hsic_xprtp->xprt_version;
+}
+
+/**
+ * msm_ipc_router_hsic_get_xprt_option() - Get XPRT options
+ * @xprt: XPRT for which the option information is required.
+ *
+ * @return: Options supported by the XPRT.
+ */
+static int msm_ipc_router_hsic_get_xprt_option(
+	struct msm_ipc_router_xprt *xprt)
+{
+	struct msm_ipc_router_hsic_xprt *hsic_xprtp;
+	if (!xprt)
+		return -EINVAL;
+	hsic_xprtp = container_of(xprt, struct msm_ipc_router_hsic_xprt, xprt);
+
+	return (int)hsic_xprtp->xprt_option;
+}
+
+/**
+ * msm_ipc_router_hsic_remote_write_avail() - Get available write space
+ * @xprt: XPRT for which the available write space info. is required.
+ *
+ * @return: Write space in bytes on success, 0 on SSR.
+ */
+static int msm_ipc_router_hsic_remote_write_avail(
+	struct msm_ipc_router_xprt *xprt)
+{
+	struct ipc_bridge_platform_data *pdata;
+	int write_avail;
+	struct msm_ipc_router_hsic_xprt *hsic_xprtp =
+		container_of(xprt, struct msm_ipc_router_hsic_xprt, xprt);
+
+	mutex_lock(&hsic_xprtp->ss_reset_lock);
+	if (hsic_xprtp->ss_reset || !hsic_xprtp->pdev) {
+		write_avail = 0;
+	} else {
+		pdata = hsic_xprtp->pdev->dev.platform_data;
+		write_avail = pdata->max_write_size;
+	}
+	mutex_unlock(&hsic_xprtp->ss_reset_lock);
+	return write_avail;
+}
+
+/**
+ * msm_ipc_router_hsic_remote_write() - Write to XPRT
+ * @data: Data to be written to the XPRT.
+ * @len: Length of the data to be written.
+ * @xprt: XPRT to which the data has to be written.
+ *
+ * @return: Data Length on success, standard Linux error codes on failure.
+ */
+static int msm_ipc_router_hsic_remote_write(void *data,
+		uint32_t len, struct msm_ipc_router_xprt *xprt)
+{
+	struct rr_packet *pkt = (struct rr_packet *)data;
+	struct sk_buff *skb;
+	struct ipc_bridge_platform_data *pdata;
+	struct msm_ipc_router_hsic_xprt *hsic_xprtp;
+	int ret;
+
+	if (!pkt || pkt->length != len || !xprt) {
+		pr_err("%s: Invalid input parameters\n", __func__);
+		return -EINVAL;
+	}
+
+	hsic_xprtp = container_of(xprt, struct msm_ipc_router_hsic_xprt, xprt);
+	mutex_lock(&hsic_xprtp->ss_reset_lock);
+	if (hsic_xprtp->ss_reset) {
+		pr_err("%s: Trying to write on a reset link\n", __func__);
+		mutex_unlock(&hsic_xprtp->ss_reset_lock);
+		return -ENETRESET;
+	}
+
+	if (!hsic_xprtp->pdev) {
+		pr_err("%s: Trying to write on a closed link\n", __func__);
+		mutex_unlock(&hsic_xprtp->ss_reset_lock);
+		return -ENODEV;
+	}
+
+	pdata = hsic_xprtp->pdev->dev.platform_data;
+	if (!pdata || !pdata->write) {
+		pr_err("%s on a uninitialized link\n", __func__);
+		mutex_unlock(&hsic_xprtp->ss_reset_lock);
+		return -EFAULT;
+	}
+
+	skb = skb_peek(pkt->pkt_fragment_q);
+	if (!skb) {
+		pr_err("%s SKB is NULL\n", __func__);
+		mutex_unlock(&hsic_xprtp->ss_reset_lock);
+		return -EINVAL;
+	}
+	D("%s: About to write %d bytes\n", __func__, len);
+	ret = pdata->write(hsic_xprtp->pdev, skb->data, skb->len);
+	if (ret == skb->len)
+		ret = len;
+	D("%s: Finished writing %d bytes\n", __func__, len);
+	mutex_unlock(&hsic_xprtp->ss_reset_lock);
+	return ret;
+}
+
+/**
+ * msm_ipc_router_hsic_remote_close() - Close the XPRT
+ * @xprt: XPRT which needs to be closed.
+ *
+ * @return: 0 on success, standard Linux error codes on failure.
+ */
+static int msm_ipc_router_hsic_remote_close(
+	struct msm_ipc_router_xprt *xprt)
+{
+	struct msm_ipc_router_hsic_xprt *hsic_xprtp;
+	struct ipc_bridge_platform_data *pdata;
+
+	if (!xprt)
+		return -EINVAL;
+	hsic_xprtp = container_of(xprt, struct msm_ipc_router_hsic_xprt, xprt);
+
+	mutex_lock(&hsic_xprtp->ss_reset_lock);
+	hsic_xprtp->ss_reset = 1;
+	mutex_unlock(&hsic_xprtp->ss_reset_lock);
+	flush_workqueue(hsic_xprtp->hsic_xprt_wq);
+	destroy_workqueue(hsic_xprtp->hsic_xprt_wq);
+	pdata = hsic_xprtp->pdev->dev.platform_data;
+	if (pdata && pdata->close)
+		pdata->close(hsic_xprtp->pdev);
+	hsic_xprtp->pdev = NULL;
+	return 0;
+}
+
+/**
+ * hsic_xprt_read_data() - Read work to read from the XPRT
+ * @work: Read work to be executed.
+ *
+ * This function is a read work item queued on a XPRT specific workqueue.
+ * The work parameter contains information regarding the XPRT on which this
+ * read work has to be performed. The work item keeps reading from the HSIC
+ * endpoint, until the endpoint returns an error.
+ */
+static void hsic_xprt_read_data(struct work_struct *work)
+{
+	int pkt_size;
+	struct sk_buff *skb = NULL;
+	void *data;
+	struct ipc_bridge_platform_data *pdata;
+	struct delayed_work *rwork = to_delayed_work(work);
+	struct msm_ipc_router_hsic_xprt *hsic_xprtp =
+		container_of(rwork, struct msm_ipc_router_hsic_xprt, read_work);
+
+	while (1) {
+		mutex_lock(&hsic_xprtp->ss_reset_lock);
+		if (hsic_xprtp->ss_reset) {
+			mutex_unlock(&hsic_xprtp->ss_reset_lock);
+			break;
+		}
+		pdata = hsic_xprtp->pdev->dev.platform_data;
+		mutex_unlock(&hsic_xprtp->ss_reset_lock);
+		while (!hsic_xprtp->in_pkt) {
+			hsic_xprtp->in_pkt = kzalloc(sizeof(struct rr_packet),
+						     GFP_KERNEL);
+			if (hsic_xprtp->in_pkt)
+				break;
+			pr_err("%s: packet allocation failure\n", __func__);
+			msleep(100);
+		}
+		while (!hsic_xprtp->in_pkt->pkt_fragment_q) {
+			hsic_xprtp->in_pkt->pkt_fragment_q =
+				kmalloc(sizeof(struct sk_buff_head),
+					GFP_KERNEL);
+			if (hsic_xprtp->in_pkt->pkt_fragment_q)
+				break;
+			pr_err("%s: Couldn't alloc pkt_fragment_q\n",
+				__func__);
+			msleep(100);
+		}
+		skb_queue_head_init(hsic_xprtp->in_pkt->pkt_fragment_q);
+		D("%s: Allocated rr_packet\n", __func__);
+
+		while (!skb) {
+			skb = alloc_skb(pdata->max_read_size, GFP_KERNEL);
+			if (skb)
+				break;
+			pr_err("%s: Couldn't alloc SKB\n", __func__);
+			msleep(100);
+		}
+		data = skb_put(skb, pdata->max_read_size);
+		pkt_size = pdata->read(hsic_xprtp->pdev, data,
+					pdata->max_read_size);
+		if (pkt_size < 0) {
+			pr_err("%s: Error %d @ read operation\n",
+				__func__, pkt_size);
+			kfree_skb(skb);
+			kfree(hsic_xprtp->in_pkt->pkt_fragment_q);
+			kfree(hsic_xprtp->in_pkt);
+			break;
+		}
+		skb_queue_tail(hsic_xprtp->in_pkt->pkt_fragment_q, skb);
+		hsic_xprtp->in_pkt->length = pkt_size;
+		D("%s: Packet size read %d\n", __func__, pkt_size);
+		msm_ipc_router_xprt_notify(&hsic_xprtp->xprt,
+			IPC_ROUTER_XPRT_EVENT_DATA, (void *)hsic_xprtp->in_pkt);
+		release_pkt(hsic_xprtp->in_pkt);
+		hsic_xprtp->in_pkt = NULL;
+		skb = NULL;
+	}
+}
+
+/**
+ * hsic_xprt_sft_close_done() - Completion of XPRT reset
+ * @xprt: XPRT on which the reset operation is complete.
+ *
+ * This function is used by IPC Router to signal this HSIC XPRT Abstraction
+ * Layer(XAL) that the reset of XPRT is completely handled by IPC Router.
+ */
+static void hsic_xprt_sft_close_done(struct msm_ipc_router_xprt *xprt)
+{
+	struct msm_ipc_router_hsic_xprt *hsic_xprtp =
+		container_of(xprt, struct msm_ipc_router_hsic_xprt, xprt);
+
+	complete_all(&hsic_xprtp->sft_close_complete);
+}
+
+/**
+ * msm_ipc_router_hsic_remote_remove() - Remove an HSIC endpoint
+ * @pdev: Platform device corresponding to HSIC endpoint.
+ *
+ * @return: 0 on success, standard Linux error codes on error.
+ *
+ * This function is called when the underlying ipc_bridge driver unregisters
+ * a platform device, mapped to an HSIC endpoint, during SSR.
+ */
+static int msm_ipc_router_hsic_remote_remove(struct platform_device *pdev)
+{
+	int id;
+	struct ipc_bridge_platform_data *pdata;
+
+	id = find_hsic_xprt_cfg(pdev);
+	if (id < 0) {
+		pr_err("%s: called for unknown ch %s\n",
+			__func__, pdev->name);
+		return id;
+	}
+
+	mutex_lock(&hsic_remote_xprt[id].ss_reset_lock);
+	hsic_remote_xprt[id].ss_reset = 1;
+	mutex_unlock(&hsic_remote_xprt[id].ss_reset_lock);
+	flush_workqueue(hsic_remote_xprt[id].hsic_xprt_wq);
+	destroy_workqueue(hsic_remote_xprt[id].hsic_xprt_wq);
+	init_completion(&hsic_remote_xprt[id].sft_close_complete);
+	msm_ipc_router_xprt_notify(&hsic_remote_xprt[id].xprt,
+				   IPC_ROUTER_XPRT_EVENT_CLOSE, NULL);
+	D("%s: Notified IPC Router of %s CLOSE\n",
+	  __func__, hsic_remote_xprt[id].xprt.name);
+	wait_for_completion(&hsic_remote_xprt[id].sft_close_complete);
+	hsic_remote_xprt[id].pdev = NULL;
+	pdata = pdev->dev.platform_data;
+	if (pdata && pdata->close)
+		pdata->close(pdev);
+	return 0;
+}
+
+/**
+ * msm_ipc_router_hsic_remote_probe() - Probe an HSIC endpoint
+ * @pdev: Platform device corresponding to HSIC endpoint.
+ *
+ * @return: 0 on success, standard Linux error codes on error.
+ *
+ * This function is called when the underlying ipc_bridge driver registers
+ * a platform device, mapped to an HSIC endpoint.
+ */
+static int msm_ipc_router_hsic_remote_probe(struct platform_device *pdev)
+{
+	int rc;
+	int id;		/*Index into the hsic_xprt_cfg table*/
+	struct ipc_bridge_platform_data *pdata;
+
+	pdata = pdev->dev.platform_data;
+	if (!pdata || !pdata->open || !pdata->read ||
+	    !pdata->write || !pdata->close) {
+		pr_err("%s: pdata or pdata->operations is NULL\n", __func__);
+		return -EINVAL;
+	}
+
+	id = find_hsic_xprt_cfg(pdev);
+	if (id < 0) {
+		pr_err("%s: called for unknown ch %s\n",
+			__func__, pdev->name);
+		return id;
+	}
+
+	hsic_remote_xprt[id].hsic_xprt_wq =
+		create_singlethread_workqueue(pdev->name);
+	if (!hsic_remote_xprt[id].hsic_xprt_wq) {
+		pr_err("%s: WQ creation failed for %s\n",
+			__func__, pdev->name);
+		return -EFAULT;
+	}
+
+	hsic_remote_xprt[id].xprt.name = hsic_xprt_cfg[id].xprt_name;
+	hsic_remote_xprt[id].xprt.link_id = hsic_xprt_cfg[id].link_id;
+	hsic_remote_xprt[id].xprt.get_version =
+		msm_ipc_router_hsic_get_xprt_version;
+	hsic_remote_xprt[id].xprt.get_option =
+		 msm_ipc_router_hsic_get_xprt_option;
+	hsic_remote_xprt[id].xprt.read_avail = NULL;
+	hsic_remote_xprt[id].xprt.read = NULL;
+	hsic_remote_xprt[id].xprt.write_avail =
+		msm_ipc_router_hsic_remote_write_avail;
+	hsic_remote_xprt[id].xprt.write = msm_ipc_router_hsic_remote_write;
+	hsic_remote_xprt[id].xprt.close = msm_ipc_router_hsic_remote_close;
+	hsic_remote_xprt[id].xprt.sft_close_done = hsic_xprt_sft_close_done;
+	hsic_remote_xprt[id].xprt.priv = NULL;
+
+	hsic_remote_xprt[id].in_pkt = NULL;
+	INIT_DELAYED_WORK(&hsic_remote_xprt[id].read_work, hsic_xprt_read_data);
+	mutex_init(&hsic_remote_xprt[id].ss_reset_lock);
+	hsic_remote_xprt[id].ss_reset = 0;
+	hsic_remote_xprt[id].xprt_version = hsic_xprt_cfg[id].xprt_version;
+	hsic_remote_xprt[id].xprt_option = 0;
+
+	rc = pdata->open(pdev);
+	if (rc < 0) {
+		pr_err("%s: Channel open failed for %s.%d\n",
+			__func__, pdev->name, pdev->id);
+		destroy_workqueue(hsic_remote_xprt[id].hsic_xprt_wq);
+		return rc;
+	}
+	hsic_remote_xprt[id].pdev = pdev;
+	msm_ipc_router_xprt_notify(&hsic_remote_xprt[id].xprt,
+				   IPC_ROUTER_XPRT_EVENT_OPEN, NULL);
+	D("%s: Notified IPC Router of %s OPEN\n",
+	  __func__, hsic_remote_xprt[id].xprt.name);
+	queue_delayed_work(hsic_remote_xprt[id].hsic_xprt_wq,
+			   &hsic_remote_xprt[id].read_work, 0);
+	return 0;
+}
+
+static struct platform_driver msm_ipc_router_hsic_remote_driver[] = {
+	{
+		.probe		= msm_ipc_router_hsic_remote_probe,
+		.remove		= msm_ipc_router_hsic_remote_remove,
+		.driver		= {
+				.name	= "ipc_bridge",
+				.owner	= THIS_MODULE,
+		},
+	},
+};
+
+static int __init msm_ipc_router_hsic_init(void)
+{
+	int i, ret, rc = 0;
+	BUG_ON(ARRAY_SIZE(hsic_xprt_cfg) != NUM_HSIC_XPRTS);
+	for (i = 0; i < ARRAY_SIZE(msm_ipc_router_hsic_remote_driver); i++) {
+		ret = platform_driver_register(
+				&msm_ipc_router_hsic_remote_driver[i]);
+		if (ret) {
+			pr_err("%s: Failed to register platform driver for xprt%d. Continuing...\n",
+				__func__, i);
+			rc = ret;
+		}
+	}
+	return rc;
+}
+
+module_init(msm_ipc_router_hsic_init);
+MODULE_DESCRIPTION("IPC Router HSIC XPRT");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/ipc_router_smd_xprt.c b/arch/arm/mach-msm/ipc_router_smd_xprt.c
index d6a3e03..87880c2 100644
--- a/arch/arm/mach-msm/ipc_router_smd_xprt.c
+++ b/arch/arm/mach-msm/ipc_router_smd_xprt.c
@@ -55,6 +55,8 @@
 	int ss_reset;
 	void *pil;
 	struct completion sft_close_complete;
+	unsigned xprt_version;
+	unsigned xprt_option;
 };
 
 struct msm_ipc_router_smd_xprt_work {
@@ -71,13 +73,14 @@
 	char xprt_name[XPRT_NAME_LEN];
 	uint32_t edge;
 	uint32_t link_id;
+	unsigned xprt_version;
 };
 
 struct msm_ipc_router_smd_xprt_config smd_xprt_cfg[] = {
-	{"RPCRPY_CNTL", "ipc_rtr_smd_rpcrpy_cntl", SMD_APPS_MODEM, 1},
-	{"IPCRTR", "ipc_rtr_smd_ipcrtr", SMD_APPS_MODEM, 1},
-	{"IPCRTR", "ipc_rtr_q6_ipcrtr", SMD_APPS_QDSP, 1},
-	{"IPCRTR", "ipc_rtr_wcnss_ipcrtr", SMD_APPS_WCNSS, 1},
+	{"RPCRPY_CNTL", "ipc_rtr_smd_rpcrpy_cntl", SMD_APPS_MODEM, 1, 1},
+	{"IPCRTR", "ipc_rtr_smd_ipcrtr", SMD_APPS_MODEM, 1, 1},
+	{"IPCRTR", "ipc_rtr_q6_ipcrtr", SMD_APPS_QDSP, 1, 1},
+	{"IPCRTR", "ipc_rtr_wcnss_ipcrtr", SMD_APPS_WCNSS, 1, 1},
 };
 
 static struct msm_ipc_router_smd_xprt smd_remote_xprt[NUM_SMD_XPRTS];
@@ -95,6 +98,28 @@
 	return -ENODEV;
 }
 
+static int msm_ipc_router_smd_get_xprt_version(
+	struct msm_ipc_router_xprt *xprt)
+{
+	struct msm_ipc_router_smd_xprt *smd_xprtp;
+	if (!xprt)
+		return -EINVAL;
+	smd_xprtp = container_of(xprt, struct msm_ipc_router_smd_xprt, xprt);
+
+	return (int)smd_xprtp->xprt_version;
+}
+
+static int msm_ipc_router_smd_get_xprt_option(
+	struct msm_ipc_router_xprt *xprt)
+{
+	struct msm_ipc_router_smd_xprt *smd_xprtp;
+	if (!xprt)
+		return -EINVAL;
+	smd_xprtp = container_of(xprt, struct msm_ipc_router_smd_xprt, xprt);
+
+	return (int)smd_xprtp->xprt_option;
+}
+
 static int msm_ipc_router_smd_remote_write_avail(
 	struct msm_ipc_router_xprt *xprt)
 {
@@ -110,7 +135,6 @@
 {
 	struct rr_packet *pkt = (struct rr_packet *)data;
 	struct sk_buff *ipc_rtr_pkt;
-	int align_sz, align_data = 0;
 	int offset, sz_written = 0;
 	int ret, num_retries = 0;
 	unsigned long flags;
@@ -123,9 +147,7 @@
 	if (!len || pkt->length != len)
 		return -EINVAL;
 
-	align_sz = ALIGN_SIZE(pkt->length);
-	while ((ret = smd_write_start(smd_xprtp->channel,
-				      (len + align_sz))) < 0) {
+	while ((ret = smd_write_start(smd_xprtp->channel, len)) < 0) {
 		spin_lock_irqsave(&smd_xprtp->ss_reset_lock, flags);
 		if (smd_xprtp->ss_reset) {
 			spin_unlock_irqrestore(&smd_xprtp->ss_reset_lock,
@@ -143,7 +165,7 @@
 		num_retries++;
 	}
 
-	D("%s: Ready to write\n", __func__);
+	D("%s: Ready to write %d bytes\n", __func__, len);
 	skb_queue_walk(pkt->pkt_fragment_q, ipc_rtr_pkt) {
 		offset = 0;
 		while (offset < ipc_rtr_pkt->len) {
@@ -175,30 +197,6 @@
 		  __func__, offset, xprt->name);
 	}
 
-	if (align_sz) {
-		if (smd_write_segment_avail(smd_xprtp->channel) < align_sz)
-			smd_enable_read_intr(smd_xprtp->channel);
-
-		wait_event(smd_xprtp->write_avail_wait_q,
-			((smd_write_segment_avail(smd_xprtp->channel) >=
-			 align_sz) || smd_xprtp->ss_reset));
-		smd_disable_read_intr(smd_xprtp->channel);
-		spin_lock_irqsave(&smd_xprtp->ss_reset_lock, flags);
-		if (smd_xprtp->ss_reset) {
-			spin_unlock_irqrestore(
-				&smd_xprtp->ss_reset_lock, flags);
-			pr_err("%s: %s chnl reset\n",
-				__func__, xprt->name);
-			return -ENETRESET;
-		}
-		spin_unlock_irqrestore(&smd_xprtp->ss_reset_lock,
-					flags);
-
-		smd_write_segment(smd_xprtp->channel,
-				  &align_data, align_sz, 0);
-		D("%s: Wrote %d align bytes over %s\n",
-		  __func__, align_sz, xprt->name);
-	}
 	if (!smd_write_end(smd_xprtp->channel))
 		D("%s: Finished writing\n", __func__);
 	return len;
@@ -453,6 +451,10 @@
 
 	smd_remote_xprt[id].xprt.name = smd_xprt_cfg[id].xprt_name;
 	smd_remote_xprt[id].xprt.link_id = smd_xprt_cfg[id].link_id;
+	smd_remote_xprt[id].xprt.get_version =
+		msm_ipc_router_smd_get_xprt_version;
+	smd_remote_xprt[id].xprt.get_option =
+		msm_ipc_router_smd_get_xprt_option;
 	smd_remote_xprt[id].xprt.read_avail = NULL;
 	smd_remote_xprt[id].xprt.read = NULL;
 	smd_remote_xprt[id].xprt.write_avail =
@@ -468,6 +470,8 @@
 	INIT_DELAYED_WORK(&smd_remote_xprt[id].read_work, smd_xprt_read_data);
 	spin_lock_init(&smd_remote_xprt[id].ss_reset_lock);
 	smd_remote_xprt[id].ss_reset = 0;
+	smd_remote_xprt[id].xprt_version = smd_xprt_cfg[id].xprt_version;
+	smd_remote_xprt[id].xprt_option = FRAG_PKT_WRITE_ENABLE;
 
 	smd_remote_xprt[id].pil = msm_ipc_load_subsystem(
 					smd_xprt_cfg[id].edge);
diff --git a/arch/arm/mach-msm/ipc_socket.c b/arch/arm/mach-msm/ipc_socket.c
index ea27c71..bdda546 100644
--- a/arch/arm/mach-msm/ipc_socket.c
+++ b/arch/arm/mach-msm/ipc_socket.c
@@ -131,12 +131,15 @@
 	int i, copied, first = 1;
 	int data_size = 0, request_size, offset;
 	void *data;
+	int last = 0;
+	int align_size;
 
 	for (i = 0; i < num_sect; i++)
 		data_size += msg_sect[i].iov_len;
 
 	if (!data_size)
 		return NULL;
+	align_size = ALIGN_SIZE(data_size);
 
 	msg_head = kmalloc(sizeof(struct sk_buff_head), GFP_KERNEL);
 	if (!msg_head) {
@@ -148,10 +151,14 @@
 	for (copied = 1, i = 0; copied && (i < num_sect); i++) {
 		data_size = msg_sect[i].iov_len;
 		offset = 0;
+		if (i == (num_sect - 1))
+			last = 1;
 		while (offset != msg_sect[i].iov_len) {
 			request_size = data_size;
 			if (first)
 				request_size += IPC_ROUTER_HDR_SIZE;
+			if (last)
+				request_size += align_size;
 
 			msg = alloc_skb(request_size, GFP_KERNEL);
 			if (!msg) {
@@ -161,6 +168,7 @@
 					goto msg_build_failure;
 				}
 				data_size = data_size / 2;
+				last = 0;
 				continue;
 			}
 
@@ -182,6 +190,8 @@
 			skb_queue_tail(msg_head, msg);
 			offset += data_size;
 			data_size = msg_sect[i].iov_len - offset;
+			if (i == (num_sect - 1))
+				last = 1;
 		}
 	}
 	return msg_head;
@@ -196,24 +206,23 @@
 }
 
 static int msm_ipc_router_extract_msg(struct msghdr *m,
-				      struct sk_buff_head *msg_head)
+				      struct rr_packet *pkt)
 {
 	struct sockaddr_msm_ipc *addr;
-	struct rr_header *hdr;
+	struct rr_header_v1 *hdr;
 	struct sk_buff *temp;
 	union rr_control_msg *ctl_msg;
 	int offset = 0, data_len = 0, copy_len;
 
-	if (!m || !msg_head) {
+	if (!m || !pkt) {
 		pr_err("%s: Invalid pointers passed\n", __func__);
 		return -EINVAL;
 	}
 	addr = (struct sockaddr_msm_ipc *)m->msg_name;
 
-	temp = skb_peek(msg_head);
-	hdr = (struct rr_header *)(temp->data);
+	hdr = &(pkt->hdr);
 	if (addr && (hdr->type == IPC_ROUTER_CTRL_CMD_RESUME_TX)) {
-		skb_pull(temp, IPC_ROUTER_HDR_SIZE);
+		temp = skb_peek(pkt->pkt_fragment_q);
 		ctl_msg = (union rr_control_msg *)(temp->data);
 		addr->family = AF_MSM_IPC;
 		addr->address.addrtype = MSM_IPC_ADDR_ID;
@@ -222,7 +231,7 @@
 		m->msg_namelen = sizeof(struct sockaddr_msm_ipc);
 		return offset;
 	}
-	if (addr && (hdr->src_port_id != IPC_ROUTER_ADDRESS)) {
+	if (addr && (hdr->type == IPC_ROUTER_CTRL_CMD_DATA)) {
 		addr->family = AF_MSM_IPC;
 		addr->address.addrtype = MSM_IPC_ADDR_ID;
 		addr->address.addr.port_addr.node_id = hdr->src_node_id;
@@ -231,8 +240,7 @@
 	}
 
 	data_len = hdr->size;
-	skb_pull(temp, IPC_ROUTER_HDR_SIZE);
-	skb_queue_walk(msg_head, temp) {
+	skb_queue_walk(pkt->pkt_fragment_q, temp) {
 		copy_len = data_len < temp->len ? data_len : temp->len;
 		if (copy_to_user(m->msg_iov->iov_base + offset, temp->data,
 				 copy_len)) {
@@ -245,22 +253,6 @@
 	return offset;
 }
 
-static void msm_ipc_router_release_msg(struct sk_buff_head *msg_head)
-{
-	struct sk_buff *temp;
-
-	if (!msg_head) {
-		pr_err("%s: Invalid msg pointer\n", __func__);
-		return;
-	}
-
-	while (!skb_queue_empty(msg_head)) {
-		temp = skb_dequeue(msg_head);
-		kfree_skb(temp);
-	}
-	kfree(msg_head);
-}
-
 static int msm_ipc_router_create(struct net *net,
 				 struct socket *sock,
 				 int protocol,
@@ -385,8 +377,16 @@
 	if (ipc_buf)
 		msm_ipc_router_ipc_log(IPC_SEND, ipc_buf, port_ptr);
 	ret = msm_ipc_router_send_to(port_ptr, msg, &dest->address);
-	if (ret == (IPC_ROUTER_HDR_SIZE + total_len))
-		ret = total_len;
+	if (ret != total_len) {
+		if (ret < 0) {
+			if (ret != -EAGAIN)
+				pr_err("%s: Send_to failure %d\n",
+							__func__, ret);
+			msm_ipc_router_free_skb(msg);
+		} else if (ret >= 0) {
+			ret = -EFAULT;
+		}
+	}
 
 out_sendmsg:
 	release_sock(sk);
@@ -398,7 +398,7 @@
 {
 	struct sock *sk = sock->sk;
 	struct msm_ipc_port *port_ptr = msm_ipc_sk_port(sk);
-	struct sk_buff_head *msg;
+	struct rr_packet *pkt;
 	struct sk_buff *ipc_buf;
 	long timeout;
 	int ret;
@@ -420,18 +420,17 @@
 		return ret;
 	}
 
-	ret = msm_ipc_router_read(port_ptr, &msg, buf_len);
-	if (ret <= 0 || !msg) {
+	ret = msm_ipc_router_read(port_ptr, &pkt, buf_len);
+	if (ret <= 0 || !pkt) {
 		release_sock(sk);
 		return ret;
 	}
 
-	ret = msm_ipc_router_extract_msg(m, msg);
-	ipc_buf = skb_peek(msg);
+	ret = msm_ipc_router_extract_msg(m, pkt);
+	ipc_buf = skb_peek(pkt->pkt_fragment_q);
 	if (ipc_buf)
 		msm_ipc_router_ipc_log(IPC_RECV, ipc_buf, port_ptr);
-	msm_ipc_router_release_msg(msg);
-	msg = NULL;
+	release_pkt(pkt);
 	release_sock(sk);
 	return ret;
 }
@@ -460,7 +459,7 @@
 
 	switch (cmd) {
 	case IPC_ROUTER_IOCTL_GET_VERSION:
-		n = IPC_ROUTER_VERSION;
+		n = IPC_ROUTER_V1;
 		ret = put_user(n, (unsigned int *)arg);
 		break;
 
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_bimc.c b/arch/arm/mach-msm/msm_bus/msm_bus_bimc.c
index bc15fe8..8b64653 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_bimc.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_bimc.c
@@ -1876,7 +1876,7 @@
 	struct msm_bus_bimc_info *binfo;
 	struct msm_bus_bimc_qos_bw qbw;
 	int i;
-	long int bw;
+	int64_t bw;
 	int ports = info->node_info->num_mports;
 	struct msm_bus_bimc_commit *sel_cd =
 		(struct msm_bus_bimc_commit *)sel_cdata;
@@ -1912,11 +1912,11 @@
 			qbw.bw = sel_cd->mas[info->node_info->masterp[i]].bw;
 			qbw.ws = info->node_info->ws;
 			/* Threshold low = 90% of bw */
-			qbw.thl = (90 * bw) / 100;
+			qbw.thl = div_s64((90 * bw), 100);
 			/* Threshold medium = bw */
 			qbw.thm = bw;
 			/* Threshold high = 10% more than bw */
-			qbw.thh = (110 * bw) / 100;
+			qbw.thh = div_s64((110 * bw), 100);
 			/* Check if info is a shared master.
 			 * If it is, mark it dirty
 			 * If it isn't, then set QOS Bandwidth
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_core.h b/arch/arm/mach-msm/msm_bus/msm_bus_core.h
index 87719e3..7e4a513 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_core.h
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_core.h
@@ -36,7 +36,8 @@
 	(((slv >= MSM_BUS_SLAVE_FIRST) && (slv <= MSM_BUS_SLAVE_LAST)) ? 1 : 0)
 
 #define INTERLEAVED_BW(fab_pdata, bw, ports) \
-	((fab_pdata->il_flag) ? msm_bus_div64((ports), (bw)) : (bw))
+	((fab_pdata->il_flag) ? ((bw < 0) \
+	? -msm_bus_div64((ports), (-bw)) : msm_bus_div64((ports), (bw))) : (bw))
 #define INTERLEAVED_VAL(fab_pdata, n) \
 	((fab_pdata->il_flag) ? (n) : 1)
 
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_noc.c b/arch/arm/mach-msm/msm_bus/msm_bus_noc.c
index d33c340..8f7b7f2 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_noc.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_noc.c
@@ -511,7 +511,7 @@
 	struct msm_bus_noc_info *ninfo;
 	struct msm_bus_noc_qos_bw qos_bw;
 	int i, ports;
-	long int bw;
+	int64_t bw;
 	struct msm_bus_noc_commit *sel_cd =
 		(struct msm_bus_noc_commit *)sel_cdata;
 
diff --git a/arch/arm/mach-msm/pil-q6v5-lpass.c b/arch/arm/mach-msm/pil-q6v5-lpass.c
index a9a6942..de15be5 100644
--- a/arch/arm/mach-msm/pil-q6v5-lpass.c
+++ b/arch/arm/mach-msm/pil-q6v5-lpass.c
@@ -378,9 +378,7 @@
 {
 	struct lpass_data *drv = subsys_to_drv(dev_id);
 
-	disable_irq_nosync(drv->subsys_desc.wdog_bite_irq);
 	schedule_work(&drv->work);
-
 	return IRQ_HANDLED;
 }
 
diff --git a/arch/arm/mach-msm/qdsp6v2/msm_audio_ion.c b/arch/arm/mach-msm/qdsp6v2/msm_audio_ion.c
index 0c71659..0a50bcc 100644
--- a/arch/arm/mach-msm/qdsp6v2/msm_audio_ion.c
+++ b/arch/arm/mach-msm/qdsp6v2/msm_audio_ion.c
@@ -53,7 +53,11 @@
 		pr_debug("%s:probe is not done, deferred\n", __func__);
 		return -EPROBE_DEFER;
 	}
-
+	if (!name || !client || !handle || !paddr || !vaddr
+		|| !bufsz || !pa_len) {
+		pr_err("%s: Invalid params\n", __func__);
+		return -EINVAL;
+	}
 	*client = msm_audio_ion_client_create(UINT_MAX, name);
 	if (IS_ERR_OR_NULL((void *)(*client))) {
 		pr_err("%s: ION create client for AUDIO failed\n", __func__);
@@ -102,9 +106,9 @@
 
 err_ion_handle:
 	ion_free(*client, *handle);
-	*handle = NULL;
 err_ion_client:
 	msm_audio_ion_client_destroy(*client);
+	*handle = NULL;
 	*client = NULL;
 err:
 	return -EINVAL;
@@ -116,10 +120,16 @@
 			ion_phys_addr_t *paddr, size_t *pa_len, void **vaddr)
 {
 	int rc = 0;
+	if (!name || !client || !handle || !paddr || !vaddr || !pa_len) {
+		pr_err("%s: Invalid params\n", __func__);
+		rc = -EINVAL;
+		goto err;
+	}
 
 	*client = msm_audio_ion_client_create(UINT_MAX, name);
 	if (IS_ERR_OR_NULL((void *)(*client))) {
 		pr_err("%s: ION create client for AUDIO failed\n", __func__);
+		rc = -EINVAL;
 		goto err;
 	}
 
@@ -132,8 +142,9 @@
 	if (IS_ERR_OR_NULL((void *) (*handle))) {
 		pr_err("%s: ion import dma buffer failed\n",
 				__func__);
-		goto err_ion_handle;
-		}
+		rc = -EINVAL;
+		goto err_destroy_client;
+	}
 
 	if (ionflag != NULL) {
 		rc = ion_handle_get_flags(*client, *handle, ionflag);
@@ -154,6 +165,7 @@
 	*vaddr = ion_map_kernel(*client, *handle);
 	if (IS_ERR_OR_NULL((void *)*vaddr)) {
 		pr_err("%s: ION memory mapping for AUDIO failed\n", __func__);
+		rc = -ENOMEM;
 		goto err_ion_handle;
 	}
 	pr_debug("%s: mapped address = %p, size=%d\n", __func__, *vaddr, bufsz);
@@ -162,13 +174,20 @@
 
 err_ion_handle:
 	ion_free(*client, *handle);
+err_destroy_client:
 	msm_audio_ion_client_destroy(*client);
+	*client = NULL;
+	*handle = NULL;
 err:
-	return -EINVAL;
+	return rc;
 }
 
 int msm_audio_ion_free(struct ion_client *client, struct ion_handle *handle)
 {
+	if (!client || !handle) {
+		pr_err("%s Invalid params\n", __func__);
+		return -EINVAL;
+	}
 	if (msm_audio_ion_data.smmu_enabled) {
 		/* Need to populate book kept infomation */
 		pr_debug("client=%p, domain=%p, domain_id=%d, group=%p",
diff --git a/arch/arm/mach-msm/rpm-smd.c b/arch/arm/mach-msm/rpm-smd.c
index 2bae37a..ccab6e2 100644
--- a/arch/arm/mach-msm/rpm-smd.c
+++ b/arch/arm/mach-msm/rpm-smd.c
@@ -284,8 +284,10 @@
 	struct kvp *e, *n;
 
 	for_each_kvp(buf, n) {
+		bool found = false;
 		for_each_kvp(s->buf, e) {
 			if (n->k == e->k) {
+				found = true;
 				if (n->s == e->s) {
 					void *e_data = get_data(e);
 					void *n_data = get_data(n);
@@ -300,6 +302,11 @@
 				}
 				break;
 			}
+
+		}
+		if (!found) {
+			add_kvp(s->buf, n);
+			s->valid = true;
 		}
 	}
 }
diff --git a/arch/arm/mach-msm/smd.c b/arch/arm/mach-msm/smd.c
index deb1cc7..d34bdf2 100644
--- a/arch/arm/mach-msm/smd.c
+++ b/arch/arm/mach-msm/smd.c
@@ -144,7 +144,7 @@
 	SMSM_APPS_DEM_I = 3,
 };
 
-int msm_smd_debug_mask = MSM_SMx_POWER_INFO;
+int msm_smd_debug_mask = MSM_SMx_POWER_INFO | MSM_SMD_INFO;
 module_param_named(debug_mask, msm_smd_debug_mask,
 		   int, S_IRUGO | S_IWUSR | S_IWGRP);
 void *smd_log_ctx;
@@ -825,7 +825,7 @@
 	}
 }
 
-static void smd_channel_reset_state(struct smd_alloc_elm *shared,
+static void smd_channel_reset_state(struct smd_alloc_elm *shared, int table_id,
 		unsigned new_state, unsigned pid)
 {
 	unsigned n;
@@ -834,6 +834,19 @@
 	void *local_ch;
 	void *remote_ch;
 	int is_word_access;
+	unsigned base_id;
+
+	switch (table_id) {
+	case PRI_ALLOC_TBL:
+		base_id = SMEM_SMD_BASE_ID;
+		break;
+	case SEC_ALLOC_TBL:
+		base_id = SMEM_SMD_BASE_ID_2;
+		break;
+	default:
+		SMD_INFO("%s: invalid table_id:%d\n", __func__, table_id);
+		return;
+	}
 
 	for (n = 0; n < SMD_CHANNELS; n++) {
 		if (!shared[n].ref_count)
@@ -844,10 +857,10 @@
 		type = SMD_CHANNEL_TYPE(shared[n].type);
 		is_word_access = is_word_access_ch(type);
 		if (is_word_access)
-			shared2 = smem_alloc(SMEM_SMD_BASE_ID + n,
+			shared2 = smem_alloc(base_id + n,
 				sizeof(struct smd_shared_v2_word_access));
 		else
-			shared2 = smem_alloc(SMEM_SMD_BASE_ID + n,
+			shared2 = smem_alloc(base_id + n,
 				sizeof(struct smd_shared_v2));
 		if (!shared2)
 			continue;
@@ -870,16 +883,19 @@
 
 void smd_channel_reset(uint32_t restart_pid)
 {
-	struct smd_alloc_elm *shared;
+	struct smd_alloc_elm *shared_pri;
+	struct smd_alloc_elm *shared_sec;
 	unsigned long flags;
 
 	SMx_POWER_INFO("%s: starting reset\n", __func__);
 
-	shared = smem_find(ID_CH_ALLOC_TBL, sizeof(*shared) * 64);
-	if (!shared) {
+	shared_pri = smem_find(ID_CH_ALLOC_TBL, sizeof(*shared_pri) * 64);
+	if (!shared_pri) {
 		pr_err("%s: allocation table not initialized\n", __func__);
 		return;
 	}
+	shared_sec = smem_find(SMEM_CHANNEL_ALLOC_TBL_2,
+						sizeof(*shared_sec) * 64);
 
 	/* reset SMSM entry */
 	if (smsm_info.state) {
@@ -903,7 +919,11 @@
 	/* change all remote states to CLOSING */
 	mutex_lock(&smd_probe_lock);
 	spin_lock_irqsave(&smd_lock, flags);
-	smd_channel_reset_state(shared, SMD_SS_CLOSING, restart_pid);
+	smd_channel_reset_state(shared_pri, PRI_ALLOC_TBL, SMD_SS_CLOSING,
+								restart_pid);
+	if (shared_sec)
+		smd_channel_reset_state(shared_sec, SEC_ALLOC_TBL,
+						SMD_SS_CLOSING, restart_pid);
 	spin_unlock_irqrestore(&smd_lock, flags);
 	mutex_unlock(&smd_probe_lock);
 
@@ -919,7 +939,11 @@
 	/* change all remote states to CLOSED */
 	mutex_lock(&smd_probe_lock);
 	spin_lock_irqsave(&smd_lock, flags);
-	smd_channel_reset_state(shared, SMD_SS_CLOSED, restart_pid);
+	smd_channel_reset_state(shared_pri, PRI_ALLOC_TBL, SMD_SS_CLOSED,
+								restart_pid);
+	if (shared_sec)
+		smd_channel_reset_state(shared_sec, SEC_ALLOC_TBL,
+						SMD_SS_CLOSED, restart_pid);
 	spin_unlock_irqrestore(&smd_lock, flags);
 	mutex_unlock(&smd_probe_lock);
 
diff --git a/arch/arm/mach-msm/smd_tty.c b/arch/arm/mach-msm/smd_tty.c
index 6df1da4..428d5b0 100644
--- a/arch/arm/mach-msm/smd_tty.c
+++ b/arch/arm/mach-msm/smd_tty.c
@@ -21,7 +21,7 @@
 #include <linux/device.h>
 #include <linux/interrupt.h>
 #include <linux/delay.h>
-#include <linux/wakelock.h>
+#include <linux/pm.h>
 #include <linux/platform_device.h>
 #include <linux/sched.h>
 
@@ -39,6 +39,7 @@
 #define MODULE_NAME "msm_smdtty"
 #define MAX_SMD_TTYS 37
 #define MAX_TTY_BUF_SIZE 2048
+#define TTY_PUSH_WS_DELAY 500
 #define MAX_RA_WAKE_LOCK_NAME_LEN 32
 #define SMD_TTY_PROBE_WAIT_TIMEOUT 3000
 #define SMD_TTY_LOG_PAGES 2
@@ -58,34 +59,65 @@
 } while (0)
 
 static void *smd_tty_log_ctx;
-static DEFINE_MUTEX(smd_tty_lock);
 
 static struct delayed_work smd_tty_probe_work;
 static int smd_tty_probe_done;
 
+/**
+ * struct smd_tty_info - context for an individual SMD TTY device
+ *
+ * @ch:  SMD channel handle
+ * @port:  TTY port context structure
+ * @device_ptr:  TTY device pointer
+ * @pending_ws:  pending-data wakeup source
+ * @tty_tsklt:  read tasklet
+ * @buf_req_timer:  RX buffer retry timer
+ * @ch_allocated:  completion set when SMD channel is allocated
+ * @driver:  SMD channel platform driver context structure
+ * @pil:  Peripheral Image Loader handle
+ * @edge:  SMD edge associated with port
+ * @ch_name:  SMD channel name associated with port
+ * @dev_name:  SMD platform device name associated with port
+ *
+ * @open_lock_lha1: open/close lock - used to serialize open/close operations
+ * @open_wait:  Timeout in seconds to wait for SMD port to be created / opened
+ *
+ * @reset_lock_lha2: lock for reset and open state
+ * @in_reset:  True if SMD channel is closed / in SSR
+ * @in_reset_updated:  reset state changed
+ * @is_open:  True if SMD port is open
+ * @ch_opened_wait_queue:  SMD port open/close wait queue
+ *
+ * @ra_lock_lha3:  Read-available lock - used to synchronize reads from SMD
+ * @ra_wakeup_source_name: Name of the read-available wakeup source
+ * @ra_wakeup_source:  Read-available wakeup source
+ */
 struct smd_tty_info {
 	smd_channel_t *ch;
 	struct tty_port port;
 	struct device *device_ptr;
-	struct wake_lock wake_lock;
+	struct wakeup_source pending_ws;
 	struct tasklet_struct tty_tsklt;
 	struct timer_list buf_req_timer;
 	struct completion ch_allocated;
 	struct platform_driver driver;
 	void *pil;
-	int in_reset;
-	int in_reset_updated;
-	int is_open;
-	unsigned int open_wait;
-	wait_queue_head_t ch_opened_wait_queue;
-	spinlock_t reset_lock;
-	spinlock_t ra_lock;		/* Read Available Lock*/
-	char ra_wake_lock_name[MAX_RA_WAKE_LOCK_NAME_LEN];
-	struct wake_lock ra_wake_lock;	/* Read Available Wakelock */
-
 	uint32_t edge;
 	char ch_name[SMD_MAX_CH_NAME_LEN];
 	char dev_name[SMD_MAX_CH_NAME_LEN];
+
+	struct mutex open_lock_lha1;
+	unsigned int open_wait;
+
+	spinlock_t reset_lock_lha2;
+	int in_reset;
+	int in_reset_updated;
+	int is_open;
+	wait_queue_head_t ch_opened_wait_queue;
+
+	spinlock_t ra_lock_lha3;
+	char ra_wakeup_source_name[MAX_RA_WAKE_LOCK_NAME_LEN];
+	struct wakeup_source ra_wakeup_source;
 };
 
 /**
@@ -140,13 +172,13 @@
 	struct smd_tty_info *info = (struct smd_tty_info *)param;
 	unsigned long flags;
 
-	spin_lock_irqsave(&info->reset_lock, flags);
+	spin_lock_irqsave(&info->reset_lock_lha2, flags);
 	if (info->is_open) {
-		spin_unlock_irqrestore(&info->reset_lock, flags);
+		spin_unlock_irqrestore(&info->reset_lock_lha2, flags);
 		tasklet_hi_schedule(&info->tty_tsklt);
 		return;
 	}
-	spin_unlock_irqrestore(&info->reset_lock, flags);
+	spin_unlock_irqrestore(&info->reset_lock_lha2, flags);
 }
 
 static ssize_t open_timeout_store(struct device *dev,
@@ -168,7 +200,9 @@
 		return -EINVAL;
 	}
 	if (!kstrtoul(buf, 10, &wait)) {
+		mutex_lock(&smd_tty[num_dev].open_lock_lha1);
 		smd_tty[num_dev].open_wait = wait;
+		mutex_unlock(&smd_tty[num_dev].open_lock_lha1);
 		return n;
 	} else {
 		SMD_TTY_INFO("[%s]: Unable to convert %s to an int",
@@ -181,6 +215,7 @@
 			struct device_attribute *attr, char *buf)
 {
 	unsigned int num_dev;
+	unsigned int open_wait;
 
 	if (dev == NULL) {
 		SMD_TTY_INFO("%s: Invalid Device passed", __func__);
@@ -195,8 +230,11 @@
 		return -EINVAL;
 	}
 
-	return snprintf(buf, PAGE_SIZE, "%d\n",
-			smd_tty[num_dev].open_wait);
+	mutex_lock(&smd_tty[num_dev].open_lock_lha1);
+	open_wait = smd_tty[num_dev].open_wait;
+	mutex_unlock(&smd_tty[num_dev].open_lock_lha1);
+
+	return snprintf(buf, PAGE_SIZE, "%d\n", open_wait);
 }
 
 static DEVICE_ATTR
@@ -222,14 +260,14 @@
 		}
 
 		if (test_bit(TTY_THROTTLED, &tty->flags)) break;
-		spin_lock_irqsave(&info->ra_lock, flags);
+		spin_lock_irqsave(&info->ra_lock_lha3, flags);
 		avail = smd_read_avail(info->ch);
 		if (avail == 0) {
-			wake_unlock(&info->ra_wake_lock);
-			spin_unlock_irqrestore(&info->ra_lock, flags);
+			__pm_relax(&info->ra_wakeup_source);
+			spin_unlock_irqrestore(&info->ra_lock_lha3, flags);
 			break;
 		}
-		spin_unlock_irqrestore(&info->ra_lock, flags);
+		spin_unlock_irqrestore(&info->ra_lock_lha3, flags);
 
 		if (avail > MAX_TTY_BUF_SIZE)
 			avail = MAX_TTY_BUF_SIZE;
@@ -252,7 +290,13 @@
 				__func__, info->ch->name);
 		}
 
-		wake_lock_timeout(&info->wake_lock, HZ / 2);
+		/*
+		 * Keep system awake long enough to allow the TTY
+		 * framework to pass the flip buffer to any waiting
+		 * userspace clients.
+		 */
+		__pm_wakeup_event(&info->pending_ws, TTY_PUSH_WS_DELAY);
+
 		tty_flip_buffer_push(tty);
 	}
 
@@ -269,12 +313,12 @@
 
 	switch (event) {
 	case SMD_EVENT_DATA:
-		spin_lock_irqsave(&info->reset_lock, flags);
+		spin_lock_irqsave(&info->reset_lock_lha2, flags);
 		if (!info->is_open) {
-			spin_unlock_irqrestore(&info->reset_lock, flags);
+			spin_unlock_irqrestore(&info->reset_lock_lha2, flags);
 			break;
 		}
-		spin_unlock_irqrestore(&info->reset_lock, flags);
+		spin_unlock_irqrestore(&info->reset_lock_lha2, flags);
 		/* There may be clients (tty framework) that are blocked
 		 * waiting for space to write data, so if a possible read
 		 * interrupt came in wake anyone waiting and disable the
@@ -287,37 +331,45 @@
 				wake_up_interruptible(&tty->write_wait);
 			tty_kref_put(tty);
 		}
-		spin_lock_irqsave(&info->ra_lock, flags);
+		spin_lock_irqsave(&info->ra_lock_lha3, flags);
 		if (smd_read_avail(info->ch)) {
-			wake_lock(&info->ra_wake_lock);
+			__pm_stay_awake(&info->ra_wakeup_source);
 			tasklet_hi_schedule(&info->tty_tsklt);
 		}
-		spin_unlock_irqrestore(&info->ra_lock, flags);
+		spin_unlock_irqrestore(&info->ra_lock_lha3, flags);
 		break;
 
 	case SMD_EVENT_OPEN:
-		spin_lock_irqsave(&info->reset_lock, flags);
+		tty = tty_port_tty_get(&info->port);
+		spin_lock_irqsave(&info->reset_lock_lha2, flags);
+		if (tty)
+			clear_bit(TTY_OTHER_CLOSED, &tty->flags);
 		info->in_reset = 0;
 		info->in_reset_updated = 1;
 		info->is_open = 1;
 		wake_up_interruptible(&info->ch_opened_wait_queue);
-		spin_unlock_irqrestore(&info->reset_lock, flags);
+		spin_unlock_irqrestore(&info->reset_lock_lha2, flags);
+		tty_kref_put(tty);
 		break;
 
 	case SMD_EVENT_CLOSE:
-		spin_lock_irqsave(&info->reset_lock, flags);
+		spin_lock_irqsave(&info->reset_lock_lha2, flags);
 		info->in_reset = 1;
 		info->in_reset_updated = 1;
 		info->is_open = 0;
 		wake_up_interruptible(&info->ch_opened_wait_queue);
-		spin_unlock_irqrestore(&info->reset_lock, flags);
-		/* schedule task to send TTY_BREAK */
-		tasklet_hi_schedule(&info->tty_tsklt);
+		spin_unlock_irqrestore(&info->reset_lock_lha2, flags);
 
 		tty = tty_port_tty_get(&info->port);
-		if (tty->index == LOOPBACK_IDX)
-			schedule_delayed_work(&loopback_work,
-					msecs_to_jiffies(1000));
+		if (tty) {
+			/* send TTY_BREAK through read tasklet */
+			set_bit(TTY_OTHER_CLOSED, &tty->flags);
+			tasklet_hi_schedule(&info->tty_tsklt);
+
+			if (tty->index == LOOPBACK_IDX)
+				schedule_delayed_work(&loopback_work,
+						msecs_to_jiffies(1000));
+		}
 		tty_kref_put(tty);
 		break;
 	}
@@ -346,7 +398,7 @@
 
 	info = smd_tty + n;
 
-	mutex_lock(&smd_tty_lock);
+	mutex_lock(&info->open_lock_lha1);
 	tty->driver_data = info;
 
 	peripheral = smd_edge_to_subsystem(smd_tty[n].edge);
@@ -407,12 +459,11 @@
 	}
 
 	tasklet_init(&info->tty_tsklt, smd_tty_read, (unsigned long)info);
-	wake_lock_init(&info->wake_lock, WAKE_LOCK_SUSPEND,
-			info->ch_name);
-	scnprintf(info->ra_wake_lock_name, MAX_RA_WAKE_LOCK_NAME_LEN,
+	wakeup_source_init(&info->pending_ws, info->ch_name);
+	scnprintf(info->ra_wakeup_source_name, MAX_RA_WAKE_LOCK_NAME_LEN,
 		  "SMD_TTY_%s_RA", info->ch_name);
-	wake_lock_init(&info->ra_wake_lock, WAKE_LOCK_SUSPEND,
-			info->ra_wake_lock_name);
+	wakeup_source_init(&info->ra_wakeup_source,
+			info->ra_wakeup_source_name);
 
 	res = smd_named_open_on_edge(info->ch_name,
 				     smd_tty[n].edge, &info->ch, info,
@@ -435,7 +486,7 @@
 	SMD_TTY_INFO("%s with PID %u opened port %s",
 		      current->comm, current->pid, info->ch_name);
 	smd_disable_read_intr(info->ch);
-	mutex_unlock(&smd_tty_lock);
+	mutex_unlock(&info->open_lock_lha1);
 	return 0;
 
 close_ch:
@@ -444,13 +495,13 @@
 
 release_wl_tl:
 	tasklet_kill(&info->tty_tsklt);
-	wake_lock_destroy(&info->wake_lock);
-	wake_lock_destroy(&info->ra_wake_lock);
+	wakeup_source_trash(&info->pending_ws);
+	wakeup_source_trash(&info->ra_wakeup_source);
 
 release_pil:
 	subsystem_put(info->pil);
 out:
-	mutex_unlock(&smd_tty_lock);
+	mutex_unlock(&info->open_lock_lha1);
 
 	return res;
 }
@@ -467,15 +518,15 @@
 		return;
 	}
 
-	mutex_lock(&smd_tty_lock);
+	mutex_lock(&info->open_lock_lha1);
 
-	spin_lock_irqsave(&info->reset_lock, flags);
+	spin_lock_irqsave(&info->reset_lock_lha2, flags);
 	info->is_open = 0;
-	spin_unlock_irqrestore(&info->reset_lock, flags);
+	spin_unlock_irqrestore(&info->reset_lock_lha2, flags);
 
 	tasklet_kill(&info->tty_tsklt);
-	wake_lock_destroy(&info->wake_lock);
-	wake_lock_destroy(&info->ra_wake_lock);
+	wakeup_source_trash(&info->pending_ws);
+	wakeup_source_trash(&info->ra_wakeup_source);
 
 	SMD_TTY_INFO("%s with PID %u closed port %s",
 			current->comm, current->pid,
@@ -487,7 +538,7 @@
 	info->ch = NULL;
 	subsystem_put(info->pil);
 
-	mutex_unlock(&smd_tty_lock);
+	mutex_unlock(&info->open_lock_lha1);
 	tty_kref_put(tty);
 }
 
@@ -550,13 +601,13 @@
 	struct smd_tty_info *info = tty->driver_data;
 	unsigned long flags;
 
-	spin_lock_irqsave(&info->reset_lock, flags);
+	spin_lock_irqsave(&info->reset_lock_lha2, flags);
 	if (info->is_open) {
-		spin_unlock_irqrestore(&info->reset_lock, flags);
+		spin_unlock_irqrestore(&info->reset_lock_lha2, flags);
 		tasklet_hi_schedule(&info->tty_tsklt);
 		return;
 	}
-	spin_unlock_irqrestore(&info->reset_lock, flags);
+	spin_unlock_irqrestore(&info->reset_lock_lha2, flags);
 }
 
 /*
@@ -573,7 +624,7 @@
 
 	tiocm = smd_tiocmget(info->ch);
 
-	spin_lock_irqsave(&info->reset_lock, flags);
+	spin_lock_irqsave(&info->reset_lock_lha2, flags);
 	tiocm |= (info->in_reset ? TIOCM_OUT1 : 0);
 	if (info->in_reset_updated) {
 		tiocm |= TIOCM_OUT2;
@@ -581,7 +632,7 @@
 	}
 	SMD_TTY_INFO("PID %u --> %s TIOCM is %x ",
 			current->pid, __func__, tiocm);
-	spin_unlock_irqrestore(&info->reset_lock, flags);
+	spin_unlock_irqrestore(&info->reset_lock_lha2, flags);
 
 	return tiocm;
 }
@@ -707,23 +758,29 @@
 	/* TODO: For kernel >= 3.7 use tty_port_register_device */
 	smd_tty[idx].device_ptr = tty_register_device(smd_tty_driver, idx, 0);
 	init_completion(&smd_tty[idx].ch_allocated);
+	mutex_init(&smd_tty[idx].open_lock_lha1);
 
 	/* register platform device */
 	smd_tty[idx].driver.probe = smd_tty_dummy_probe;
 	smd_tty[idx].driver.driver.name = smd_tty[idx].dev_name;
 	smd_tty[idx].driver.driver.owner = THIS_MODULE;
-	spin_lock_init(&smd_tty[idx].reset_lock);
-	spin_lock_init(&smd_tty[idx].ra_lock);
+	spin_lock_init(&smd_tty[idx].reset_lock_lha2);
+	spin_lock_init(&smd_tty[idx].ra_lock_lha3);
 	smd_tty[idx].is_open = 0;
 	setup_timer(&smd_tty[idx].buf_req_timer, buf_req_retry,
 			(unsigned long)&smd_tty[idx]);
 	init_waitqueue_head(&smd_tty[idx].ch_opened_wait_queue);
 	ret = platform_driver_register(&smd_tty[idx].driver);
+	if (ret)
+		return ret;
 
+	if (device_create_file(smd_tty[idx].device_ptr, &dev_attr_open_timeout))
+		SMD_TTY_ERR("%s: Unable to create device attributes for %s",
+			__func__, smd_configs[idx].port_name);
 	return ret;
 }
 
-static int __init smd_tty_core_init(void)
+static int smd_tty_core_init(void)
 {
 	int ret;
 	int n;
@@ -771,12 +828,6 @@
 		}
 
 		ret = smd_tty_device_init(idx);
-		if (device_create_file(smd_tty[idx].device_ptr,
-					&dev_attr_open_timeout))
-			SMD_TTY_ERR(
-				"%s: Unable to create device attributes for %s",
-				__func__, smd_configs[n].port_name);
-
 		if (ret) {
 			SMD_TTY_ERR(
 				"%s: init failed %d (%d)", __func__, idx, ret);
@@ -803,7 +854,7 @@
 	return ret;
 }
 
-static int __init smd_tty_devicetree_init(struct platform_device *pdev)
+static int smd_tty_devicetree_init(struct platform_device *pdev)
 {
 	int ret;
 	int idx;
diff --git a/arch/arm/mach-msm/smp2p.c b/arch/arm/mach-msm/smp2p.c
index 4b69cf0..df241f8 100644
--- a/arch/arm/mach-msm/smp2p.c
+++ b/arch/arm/mach-msm/smp2p.c
@@ -53,6 +53,9 @@
  * @smem_edge_out: Pointer to outbound smem item.
  * @smem_edge_state: State of the outbound edge.
  * @ops_ptr: Pointer to internal version-specific SMEM item access functions.
+ *
+ * @feature_ssr_ack_enabled: SSR ACK Support Enabled
+ * @restart_ack: Current cached state of the local ack bit
  */
 struct smp2p_out_list_item {
 	spinlock_t out_item_lock_lha1;
@@ -61,11 +64,14 @@
 	struct smp2p_smem __iomem *smem_edge_out;
 	enum msm_smp2p_edge_state smem_edge_state;
 	struct smp2p_version_if *ops_ptr;
+
+	bool feature_ssr_ack_enabled;
+	bool restart_ack;
 };
 static struct smp2p_out_list_item out_list[SMP2P_NUM_PROCS];
 
 static void *log_ctx;
-static int smp2p_debug_mask = MSM_SMP2P_INFO;
+static int smp2p_debug_mask = MSM_SMP2P_INFO | MSM_SMP2P_DEBUG;
 module_param_named(debug_mask, smp2p_debug_mask,
 		   int, S_IRUGO | S_IWUSR | S_IWGRP);
 
@@ -115,6 +121,7 @@
  *
  * @is_supported: True if this version is supported by SMP2P
  * @negotiate_features: Returns (sub)set of supported features
+ * @negotiation_complete:  Called when negotiation has been completed
  * @find_entry: Finds existing / next empty entry
  * @create_entry: Creates a new entry
  * @read_entry: Reads the value of an entry
@@ -128,6 +135,7 @@
 	/* common functions */
 	bool is_supported;
 	uint32_t (*negotiate_features)(uint32_t features);
+	void (*negotiation_complete)(struct smp2p_out_list_item *);
 	void (*find_entry)(struct smp2p_smem __iomem *item,
 			uint32_t entries_total,	char *name,
 			uint32_t **entry_ptr, int *empty_spot);
@@ -148,6 +156,7 @@
 
 /* v0 (uninitialized SMEM item) interface functions */
 static uint32_t smp2p_negotiate_features_v0(uint32_t features);
+static void smp2p_negotiation_complete_v0(struct smp2p_out_list_item *out_item);
 static void smp2p_find_entry_v0(struct smp2p_smem __iomem *item,
 		uint32_t entries_total, char *name, uint32_t **entry_ptr,
 		int *empty_spot);
@@ -160,6 +169,7 @@
 
 /* v1 interface functions */
 static uint32_t smp2p_negotiate_features_v1(uint32_t features);
+static void smp2p_negotiation_complete_v1(struct smp2p_out_list_item *out_item);
 static void smp2p_find_entry_v1(struct smp2p_smem __iomem *item,
 		uint32_t entries_total, char *name, uint32_t **entry_ptr,
 		int *empty_spot);
@@ -174,6 +184,7 @@
 static struct smp2p_version_if version_if[] = {
 	[0] = {
 		.negotiate_features = smp2p_negotiate_features_v0,
+		.negotiation_complete = smp2p_negotiation_complete_v0,
 		.find_entry = smp2p_find_entry_v0,
 		.create_entry = smp2p_out_create_v0,
 		.read_entry = smp2p_out_read_v0,
@@ -184,6 +195,7 @@
 	[1] = {
 		.is_supported = true,
 		.negotiate_features = smp2p_negotiate_features_v1,
+		.negotiation_complete = smp2p_negotiation_complete_v1,
 		.find_entry = smp2p_find_entry_v1,
 		.create_entry = smp2p_out_create_v1,
 		.read_entry = smp2p_out_read_v1,
@@ -399,15 +411,76 @@
 }
 
 /**
- * smp2p_negotiate_features_v0 - Initial feature negotiation.
+ * smp2p_ssr_ack_needed - Returns true if SSR ACK required
+ *
+ * @rpid: Remote processor ID
+ *
+ * Must be called with out_item_lock_lha1 and in_item_lock_lhb1 locked.
+ */
+static bool smp2p_ssr_ack_needed(uint32_t rpid)
+{
+	bool ssr_done;
+
+	if (!out_list[rpid].feature_ssr_ack_enabled)
+		return false;
+
+	ssr_done = SMP2P_GET_RESTART_DONE(in_list[rpid].smem_edge_in->flags);
+	if (ssr_done != out_list[rpid].restart_ack)
+		return true;
+
+	return false;
+}
+
+/**
+ * smp2p_do_ssr_ack - Handles SSR ACK
+ *
+ * @rpid: Remote processor ID
+ *
+ * Must be called with out_item_lock_lha1 and in_item_lock_lhb1 locked.
+ */
+static void smp2p_do_ssr_ack(uint32_t rpid)
+{
+	bool ack;
+
+	if (!smp2p_ssr_ack_needed(rpid))
+		return;
+
+	ack = !out_list[rpid].restart_ack;
+	SMP2P_INFO("%s: ssr ack pid %d: %d -> %d\n", __func__, rpid,
+			out_list[rpid].restart_ack, ack);
+	out_list[rpid].restart_ack = ack;
+	SMP2P_SET_RESTART_ACK(out_list[rpid].smem_edge_out->flags, ack);
+	smp2p_send_interrupt(rpid);
+}
+
+/**
+ * smp2p_negotiate_features_v1 - Initial feature negotiation.
  *
  * @features: Inbound feature set.
  * @returns: Supported features (will be a same/subset of @features).
  */
 static uint32_t smp2p_negotiate_features_v1(uint32_t features)
 {
-	/* no supported features */
-	return 0;
+	return SMP2P_FEATURE_SSR_ACK;
+}
+
+/**
+ * smp2p_negotiation_complete_v1 - Negotiation completed
+ *
+ * @out_item:   Pointer to the output item structure
+ *
+ * Can be used to do final configuration based upon the negotiated feature set.
+ *
+ * Must be called with out_item_lock_lha1 locked.
+ */
+static void smp2p_negotiation_complete_v1(struct smp2p_out_list_item *out_item)
+{
+	uint32_t features;
+
+	features = SMP2P_GET_FEATURES(out_item->smem_edge_out->feature_version);
+
+	if (features & SMP2P_FEATURE_SSR_ACK)
+		out_item->feature_ssr_ack_enabled = true;
 }
 
 /**
@@ -707,6 +780,20 @@
 }
 
 /**
+ * smp2p_negotiation_complete_v0 - Negotiation completed
+ *
+ * @out_item:   Pointer to the output item structure
+ *
+ * Can be used to do final configuration based upon the negotiated feature set.
+ */
+static void smp2p_negotiation_complete_v0(struct smp2p_out_list_item *out_item)
+{
+	SMP2P_ERR("%s: invalid negotiation complete for v0 pid %d\n",
+		__func__,
+		SMP2P_GET_REMOTE_PID(out_item->smem_edge_out->rem_loc_proc_id));
+}
+
+/**
  * smp2p_find_entry_v0 - Stub function.
  *
  * @item: Pointer to the smem item.
@@ -885,7 +972,7 @@
 	SMP2P_SET_FEATURES(header_ptr->feature_version, features);
 	SMP2P_SET_ENT_TOTAL(header_ptr->valid_total_ent, SMP2P_MAX_ENTRY);
 	SMP2P_SET_ENT_VALID(header_ptr->valid_total_ent, 0);
-	header_ptr->reserved = 0;
+	header_ptr->flags = 0;
 
 	/* ensure that all fields are valid before version is written */
 	wmb();
@@ -992,8 +1079,9 @@
 		struct msm_smp2p_out *pos;
 
 		/* negotiation complete */
-		out_item->smem_edge_state = SMP2P_EDGE_STATE_OPENED;
 		out_item->ops_ptr = &version_if[l_version];
+		out_item->ops_ptr->negotiation_complete(out_item);
+		out_item->smem_edge_state = SMP2P_EDGE_STATE_OPENED;
 		SMP2P_INFO(
 			"%s: negotiation complete pid %d: State %d->%d F0x%08x\n",
 			__func__, remote_pid, prev_state,
@@ -1528,9 +1616,41 @@
 		smp2p_do_negotiation(remote_pid, &out_list[remote_pid]);
 
 	if (out_list[remote_pid].smem_edge_state == SMP2P_EDGE_STATE_OPENED) {
+		bool do_restart_ack;
+
+		/*
+		 * Follow double-check pattern for restart ack since:
+		 * 1) we must notify clients of the X->0 transition
+		 *    that is part of the restart
+		 * 2) lock cannot be held during the
+		 *    smp2p_in_edge_notify() call because clients may do
+		 *    re-entrant calls into our APIs.
+		 *
+		 * smp2p_do_ssr_ack() will only do the ack if it is
+		 * necessary to handle the race condition exposed by
+		 * unlocking the spinlocks.
+		 */
+		spin_lock(&in_list[remote_pid].in_item_lock_lhb1);
+		do_restart_ack = smp2p_ssr_ack_needed(remote_pid);
+		spin_unlock(&in_list[remote_pid].in_item_lock_lhb1);
 		spin_unlock_irqrestore(&out_list[remote_pid].out_item_lock_lha1,
 			flags);
+
 		smp2p_in_edge_notify(remote_pid);
+
+		if (do_restart_ack) {
+			spin_lock_irqsave(
+				&out_list[remote_pid].out_item_lock_lha1,
+				flags);
+			spin_lock(&in_list[remote_pid].in_item_lock_lhb1);
+
+			smp2p_do_ssr_ack(remote_pid);
+
+			spin_unlock(&in_list[remote_pid].in_item_lock_lhb1);
+			spin_unlock_irqrestore(
+				&out_list[remote_pid].out_item_lock_lha1,
+				flags);
+		}
 	} else {
 		spin_unlock_irqrestore(&out_list[remote_pid].out_item_lock_lha1,
 			flags);
@@ -1565,6 +1685,8 @@
 	out_list[rpid].smem_edge_out = NULL;
 	out_list[rpid].ops_ptr = &version_if[0];
 	out_list[rpid].smem_edge_state = SMP2P_EDGE_STATE_CLOSED;
+	out_list[rpid].feature_ssr_ack_enabled = false;
+	out_list[rpid].restart_ack = false;
 
 	in_list[rpid].smem_edge_in = NULL;
 	in_list[rpid].item_size = 0;
@@ -1699,6 +1821,8 @@
 		out_list[i].smem_edge_out = NULL;
 		out_list[i].smem_edge_state = SMP2P_EDGE_STATE_CLOSED;
 		out_list[i].ops_ptr = &version_if[0];
+		out_list[i].feature_ssr_ack_enabled = false;
+		out_list[i].restart_ack = false;
 
 		spin_lock_init(&in_list[i].in_item_lock_lhb1);
 		INIT_LIST_HEAD(&in_list[i].list);
diff --git a/arch/arm/mach-msm/smp2p_debug.c b/arch/arm/mach-msm/smp2p_debug.c
index a493cbe..f4ff42d 100644
--- a/arch/arm/mach-msm/smp2p_debug.c
+++ b/arch/arm/mach-msm/smp2p_debug.c
@@ -141,9 +141,11 @@
 	}
 
 	i += scnprintf(buf + i, max - i,
-		"Entries Valid/Max: %d/%d",
+		"Entries #/Max: %d/%d Flags: %c%c",
 		SMP2P_GET_ENT_VALID(item_ptr->valid_total_ent),
-		SMP2P_GET_ENT_TOTAL(item_ptr->valid_total_ent)
+		SMP2P_GET_ENT_TOTAL(item_ptr->valid_total_ent),
+		item_ptr->flags & SMP2P_FLAGS_RESTART_ACK_MASK ? 'A' : 'a',
+		item_ptr->flags & SMP2P_FLAGS_RESTART_DONE_MASK ? 'D' : 'd'
 		);
 
 	return i;
diff --git a/arch/arm/mach-msm/smp2p_gpio.c b/arch/arm/mach-msm/smp2p_gpio.c
index 2a85e5f..5f70e0c 100644
--- a/arch/arm/mach-msm/smp2p_gpio.c
+++ b/arch/arm/mach-msm/smp2p_gpio.c
@@ -420,7 +420,7 @@
 		spin_unlock_irqrestore(&chip->irq_lock, flags);
 
 		if (trigger_interrrupt) {
-			SMP2P_GPIO(
+			SMP2P_INFO(
 				"'%s':%d GPIO bit %d virq %d (%s,%s) - edge %s triggering\n",
 				chip->name, chip->remote_pid, i,
 				chip->irq_base + i,
diff --git a/arch/arm/mach-msm/smp2p_private.h b/arch/arm/mach-msm/smp2p_private.h
index b9a5cfe..8e0d7a3 100644
--- a/arch/arm/mach-msm/smp2p_private.h
+++ b/arch/arm/mach-msm/smp2p_private.h
@@ -20,8 +20,7 @@
 #include "smp2p_private_api.h"
 
 #define SMP2P_MAX_ENTRY 16
-#define SMP2P_LOCAL_VERSION 1
-#define SMP2P_LOCAL_FEATURE  0x0
+#define SMP2P_FEATURE_SSR_ACK 0x1
 
 /* SMEM Item Header Macros */
 #define SMP2P_MAGIC 0x504D5324
@@ -37,6 +36,10 @@
 #define SMP2P_ENT_TOTAL_BIT 0
 #define SMP2P_ENT_VALID_MASK 0xffff0000
 #define SMP2P_ENT_VALID_BIT 16
+#define SMP2P_FLAGS_RESTART_DONE_BIT 0
+#define SMP2P_FLAGS_RESTART_DONE_MASK 0x1
+#define SMP2P_FLAGS_RESTART_ACK_BIT 1
+#define SMP2P_FLAGS_RESTART_ACK_MASK 0x2
 
 #define SMP2P_GET_BITS(hdr_val, mask, bit) \
 	(((hdr_val) & (mask)) >> (bit))
@@ -77,6 +80,20 @@
 	SMP2P_SET_BITS(hdr,  SMP2P_ENT_VALID_MASK, SMP2P_ENT_VALID_BIT,\
 		entries)
 
+#define SMP2P_GET_RESTART_DONE(hdr) \
+	SMP2P_GET_BITS(hdr, SMP2P_FLAGS_RESTART_DONE_MASK, \
+			SMP2P_FLAGS_RESTART_DONE_BIT)
+#define SMP2P_SET_RESTART_DONE(hdr, value) \
+	SMP2P_SET_BITS(hdr, SMP2P_FLAGS_RESTART_DONE_MASK, \
+			SMP2P_FLAGS_RESTART_DONE_BIT, value)
+
+#define SMP2P_GET_RESTART_ACK(hdr) \
+	SMP2P_GET_BITS(hdr, SMP2P_FLAGS_RESTART_ACK_MASK, \
+			SMP2P_FLAGS_RESTART_ACK_BIT)
+#define SMP2P_SET_RESTART_ACK(hdr, value) \
+	SMP2P_SET_BITS(hdr, SMP2P_FLAGS_RESTART_ACK_MASK, \
+			SMP2P_FLAGS_RESTART_ACK_BIT, value)
+
 /* Loopback Command Macros */
 #define SMP2P_RMT_CMD_TYPE_MASK 0x80000000
 #define SMP2P_RMT_CMD_TYPE_BIT 31
@@ -162,12 +179,21 @@
 	SMP2P_EDGE_STATE_FAILED = 0xff,
 };
 
+/**
+ * struct smp2p_smem - SMP2P SMEM Item Header
+ *
+ * @magic:  Set to "$SMP" -- used for identification / debug purposes
+ * @feature_version:  Feature and version fields
+ * @rem_loc_proc_id:  Remote (31:16) and Local (15:0) processor IDs
+ * @valid_total_ent:  Valid (31:16) and total (15:0) entries
+ * @flags:  Flags (bits 31:2 reserved)
+ */
 struct smp2p_smem {
 	uint32_t magic;
 	uint32_t feature_version;
 	uint32_t rem_loc_proc_id;
 	uint32_t valid_total_ent;
-	uint32_t reserved;
+	uint32_t flags;
 };
 
 struct smp2p_entry_v1 {
diff --git a/arch/arm/mach-msm/smp2p_test.c b/arch/arm/mach-msm/smp2p_test.c
index 18c9bfd..2f86df4 100644
--- a/arch/arm/mach-msm/smp2p_test.c
+++ b/arch/arm/mach-msm/smp2p_test.c
@@ -16,6 +16,7 @@
 #include <linux/jiffies.h>
 #include <linux/delay.h>
 #include <linux/completion.h>
+#include <mach/subsystem_restart.h>
 #include "smp2p_private.h"
 #include "smp2p_test_common.h"
 
@@ -77,7 +78,7 @@
 		rmp->remote_item.header.valid_total_ent, SMP2P_MAX_ENTRY);
 		SMP2P_SET_ENT_VALID(
 		rmp->remote_item.header.valid_total_ent, 0);
-		rmp->remote_item.header.reserved = 0x0;
+		rmp->remote_item.header.flags = 0x0;
 		msm_smp2p_set_remote_mock_exists(true);
 		rmp->tx_interrupt();
 
@@ -161,7 +162,7 @@
 			SMP2P_MAX_ENTRY);
 		SMP2P_SET_ENT_VALID(
 		rmp->remote_item.header.valid_total_ent, 0);
-		rmp->remote_item.header.reserved = 0x0;
+		rmp->remote_item.header.flags = 0x0;
 
 		msm_smp2p_set_remote_mock_exists(true);
 
@@ -251,7 +252,7 @@
 		rmp->remote_item.header.valid_total_ent, SMP2P_MAX_ENTRY);
 		SMP2P_SET_ENT_VALID(
 		rmp->remote_item.header.valid_total_ent, 0);
-		rmp->remote_item.header.reserved = 0x0;
+		rmp->remote_item.header.flags = 0x0;
 
 		msm_smp2p_set_remote_mock_exists(false);
 		UT_ASSERT_PTR(NULL, ==,
@@ -369,7 +370,7 @@
 		rmp->remote_item.header.valid_total_ent, SMP2P_MAX_ENTRY);
 		SMP2P_SET_ENT_VALID(
 		rmp->remote_item.header.valid_total_ent, 1);
-		rmp->remote_item.header.reserved = 0x0;
+		rmp->remote_item.header.flags = 0x0;
 		msm_smp2p_set_remote_mock_exists(true);
 
 		/* Create test entry and attach loopback server */
@@ -794,7 +795,7 @@
 		rmp->remote_item.header.valid_total_ent, SMP2P_MAX_ENTRY);
 		SMP2P_SET_ENT_VALID(
 		rmp->remote_item.header.valid_total_ent, 0);
-		rmp->remote_item.header.reserved = 0x0;
+		rmp->remote_item.header.flags = 0x0;
 		msm_smp2p_set_remote_mock_exists(true);
 
 		/* Create Max Entries in the remote mock object */
@@ -892,7 +893,7 @@
 		rmp->remote_item.header.valid_total_ent, 1);
 		SMP2P_SET_ENT_VALID(
 		rmp->remote_item.header.valid_total_ent, 0);
-		rmp->remote_item.header.reserved = 0x0;
+		rmp->remote_item.header.flags = 0x0;
 		msm_smp2p_set_remote_mock_exists(true);
 
 		/* Create an Entry in the remote mock object */
@@ -953,6 +954,217 @@
 	}
 }
 
+/**
+ * smp2p_ut_local_ssr_ack - Verify SSR Done/ACK Feature
+ *
+ * @s: pointer to output file
+ */
+static void smp2p_ut_local_ssr_ack(struct seq_file *s)
+{
+	int failed = 0;
+	struct msm_smp2p_remote_mock *rmp = NULL;
+	int ret;
+
+	seq_printf(s, "Running %s\n", __func__);
+	do {
+		struct smp2p_smem *rhdr;
+		struct smp2p_smem *lhdr;
+		int negotiation_state;
+
+		/* initialize v1 without SMP2P_FEATURE_SSR_ACK enabled */
+		ret = smp2p_reset_mock_edge();
+		UT_ASSERT_INT(ret, ==, 0);
+		rmp = msm_smp2p_get_remote_mock();
+		UT_ASSERT_PTR(rmp, !=, NULL);
+		rhdr = &rmp->remote_item.header;
+
+		rmp->rx_interrupt_count = 0;
+		memset(&rmp->remote_item, 0, sizeof(struct smp2p_smem_item));
+		rhdr->magic = SMP2P_MAGIC;
+		SMP2P_SET_LOCAL_PID(rhdr->rem_loc_proc_id,
+				SMP2P_REMOTE_MOCK_PROC);
+		SMP2P_SET_REMOTE_PID(rhdr->rem_loc_proc_id, SMP2P_APPS_PROC);
+		SMP2P_SET_VERSION(rhdr->feature_version, 1);
+		SMP2P_SET_FEATURES(rhdr->feature_version, 0);
+		SMP2P_SET_ENT_TOTAL(rhdr->valid_total_ent, SMP2P_MAX_ENTRY);
+		SMP2P_SET_ENT_VALID(rhdr->valid_total_ent, 0);
+		rhdr->flags = 0x0;
+		msm_smp2p_set_remote_mock_exists(true);
+		rmp->tx_interrupt();
+
+		/* verify edge is open */
+		lhdr = smp2p_get_out_item(SMP2P_REMOTE_MOCK_PROC,
+					&negotiation_state);
+		UT_ASSERT_PTR(NULL, !=, lhdr);
+		UT_ASSERT_INT(negotiation_state, ==, SMP2P_EDGE_STATE_OPENED);
+		UT_ASSERT_INT(rmp->rx_interrupt_count, ==, 1);
+
+		/* verify no response to ack feature */
+		rmp->rx_interrupt_count = 0;
+		SMP2P_SET_RESTART_DONE(rhdr->flags, 1);
+		rmp->tx_interrupt();
+		UT_ASSERT_INT(0, ==, SMP2P_GET_RESTART_DONE(lhdr->flags));
+		UT_ASSERT_INT(0, ==, SMP2P_GET_RESTART_ACK(lhdr->flags));
+		UT_ASSERT_INT(rmp->rx_interrupt_count, ==, 0);
+
+		/* initialize v1 with SMP2P_FEATURE_SSR_ACK enabled */
+		ret = smp2p_reset_mock_edge();
+		UT_ASSERT_INT(ret, ==, 0);
+		rmp = msm_smp2p_get_remote_mock();
+		UT_ASSERT_PTR(rmp, !=, NULL);
+		rhdr = &rmp->remote_item.header;
+
+		rmp->rx_interrupt_count = 0;
+		memset(&rmp->remote_item, 0, sizeof(struct smp2p_smem_item));
+		rhdr->magic = SMP2P_MAGIC;
+		SMP2P_SET_LOCAL_PID(rhdr->rem_loc_proc_id,
+				SMP2P_REMOTE_MOCK_PROC);
+		SMP2P_SET_REMOTE_PID(rhdr->rem_loc_proc_id, SMP2P_APPS_PROC);
+		SMP2P_SET_VERSION(rhdr->feature_version, 1);
+		SMP2P_SET_FEATURES(rhdr->feature_version,
+				SMP2P_FEATURE_SSR_ACK);
+		SMP2P_SET_ENT_TOTAL(rhdr->valid_total_ent, SMP2P_MAX_ENTRY);
+		SMP2P_SET_ENT_VALID(rhdr->valid_total_ent, 0);
+		rmp->rx_interrupt_count = 0;
+		rhdr->flags = 0x0;
+		msm_smp2p_set_remote_mock_exists(true);
+		rmp->tx_interrupt();
+
+		/* verify edge is open */
+		lhdr = smp2p_get_out_item(SMP2P_REMOTE_MOCK_PROC,
+					&negotiation_state);
+		UT_ASSERT_PTR(NULL, !=, lhdr);
+		UT_ASSERT_INT(negotiation_state, ==, SMP2P_EDGE_STATE_OPENED);
+		UT_ASSERT_INT(rmp->rx_interrupt_count, ==, 1);
+
+		/* verify response to ack feature */
+		rmp->rx_interrupt_count = 0;
+		SMP2P_SET_RESTART_DONE(rhdr->flags, 1);
+		rmp->tx_interrupt();
+		UT_ASSERT_INT(0, ==, SMP2P_GET_RESTART_DONE(lhdr->flags));
+		UT_ASSERT_INT(1, ==, SMP2P_GET_RESTART_ACK(lhdr->flags));
+		UT_ASSERT_INT(rmp->rx_interrupt_count, ==, 1);
+
+		rmp->rx_interrupt_count = 0;
+		SMP2P_SET_RESTART_DONE(rhdr->flags, 0);
+		rmp->tx_interrupt();
+		UT_ASSERT_INT(0, ==, SMP2P_GET_RESTART_DONE(lhdr->flags));
+		UT_ASSERT_INT(0, ==, SMP2P_GET_RESTART_ACK(lhdr->flags));
+		UT_ASSERT_INT(rmp->rx_interrupt_count, ==, 1);
+
+		seq_puts(s, "\tOK\n");
+	} while (0);
+
+	if (failed) {
+		pr_err("%s: Failed\n", __func__);
+		seq_puts(s, "\tFailed\n");
+	}
+}
+
+/**
+ * smp2p_ut_local_ssr_ack - Verify SSR Done/ACK Feature
+ *
+ * @s: pointer to output file
+ * @rpid: Remote processor ID
+ * @int_cfg: Interrupt config
+ */
+static void smp2p_ut_remotesubsys_ssr_ack(struct seq_file *s, uint32_t rpid,
+		struct smp2p_interrupt_config *int_cfg)
+{
+	int failed = 0;
+
+	seq_printf(s, "Running %s\n", __func__);
+	do {
+		struct smp2p_smem *rhdr;
+		struct smp2p_smem *lhdr;
+		int negotiation_state;
+		bool ssr_ack_enabled;
+		uint32_t ssr_done_start;
+
+		lhdr = smp2p_get_out_item(rpid, &negotiation_state);
+		UT_ASSERT_PTR(NULL, !=, lhdr);
+		UT_ASSERT_INT(SMP2P_EDGE_STATE_OPENED, ==, negotiation_state);
+
+		rhdr = smp2p_get_in_item(rpid);
+		UT_ASSERT_PTR(NULL, !=, rhdr);
+
+		/* get initial state of SSR flags */
+		if (SMP2P_GET_FEATURES(rhdr->feature_version)
+				& SMP2P_FEATURE_SSR_ACK)
+			ssr_ack_enabled = true;
+		else
+			ssr_ack_enabled = false;
+
+		ssr_done_start = SMP2P_GET_RESTART_DONE(rhdr->flags);
+		UT_ASSERT_INT(ssr_done_start, ==,
+				SMP2P_GET_RESTART_ACK(lhdr->flags));
+
+		/* trigger restart */
+		seq_printf(s, "Restarting '%s'\n", int_cfg->name);
+		subsystem_restart(int_cfg->name);
+		msleep(10*1000);
+
+		/* verify ack signaling */
+		if (ssr_ack_enabled) {
+			ssr_done_start ^= 1;
+			UT_ASSERT_INT(ssr_done_start, ==,
+					SMP2P_GET_RESTART_ACK(lhdr->flags));
+			UT_ASSERT_INT(ssr_done_start, ==,
+					SMP2P_GET_RESTART_DONE(rhdr->flags));
+			UT_ASSERT_INT(0, ==,
+					SMP2P_GET_RESTART_DONE(lhdr->flags));
+			seq_puts(s, "\tSSR ACK Enabled and Toggled\n");
+		} else {
+			UT_ASSERT_INT(0, ==,
+					SMP2P_GET_RESTART_DONE(lhdr->flags));
+			UT_ASSERT_INT(0, ==,
+					SMP2P_GET_RESTART_ACK(lhdr->flags));
+
+			UT_ASSERT_INT(0, ==,
+					SMP2P_GET_RESTART_DONE(rhdr->flags));
+			UT_ASSERT_INT(0, ==,
+					SMP2P_GET_RESTART_ACK(rhdr->flags));
+			seq_puts(s, "\tSSR ACK Disabled\n");
+		}
+
+		seq_puts(s, "\tOK\n");
+	} while (0);
+
+	if (failed) {
+		pr_err("%s: Failed\n", __func__);
+		seq_puts(s, "\tFailed\n");
+	}
+}
+
+/**
+ * smp2p_ut_remote_ssr_ack - Verify SSR Done/ACK Feature
+ *
+ * @s: pointer to output file
+ *
+ * Triggers SSR for each subsystem.
+ */
+static void smp2p_ut_remote_ssr_ack(struct seq_file *s)
+{
+	struct smp2p_interrupt_config *int_cfg;
+	int pid;
+
+	int_cfg = smp2p_get_interrupt_config();
+	if (!int_cfg) {
+		seq_puts(s,
+			"Remote processor config unavailable\n");
+		return;
+	}
+
+	for (pid = 0; pid < SMP2P_NUM_PROCS; ++pid) {
+		if (!int_cfg[pid].is_configured)
+			continue;
+
+		msm_smp2p_deinit_rmt_lpb_proc(pid);
+		smp2p_ut_remotesubsys_ssr_ack(s, pid, &int_cfg[pid]);
+		msm_smp2p_init_rmt_lpb_proc(pid);
+	}
+}
+
 static struct dentry *dent;
 
 static int debugfs_show(struct seq_file *s, void *data)
@@ -1019,6 +1231,10 @@
 			smp2p_ut_remote_out_max_entries);
 	smp2p_debug_create("ut_local_in_multiple",
 			smp2p_ut_local_in_multiple);
+	smp2p_debug_create("ut_local_ssr_ack",
+			smp2p_ut_local_ssr_ack);
+	smp2p_debug_create("ut_remote_ssr_ack",
+			smp2p_ut_remote_ssr_ack);
 
 	return 0;
 }
diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c
index e82ea2b..34ae4e6 100644
--- a/arch/arm/mm/init.c
+++ b/arch/arm/mm/init.c
@@ -734,6 +734,46 @@
 #endif
 }
 
+#define MLK(b, t) b, t, ((t) - (b)) >> 10
+#define MLM(b, t) b, t, ((t) - (b)) >> 20
+#define MLK_ROUNDUP(b, t) b, t, DIV_ROUND_UP(((t) - (b)), SZ_1K)
+
+#ifdef CONFIG_ENABLE_VMALLOC_SAVING
+void print_vmalloc_lowmem_info(void)
+{
+	int i;
+	void *va_start, *va_end;
+
+	printk(KERN_NOTICE
+		"	   vmalloc : 0x%08lx - 0x%08lx   (%4ld MB)\n",
+		MLM(VMALLOC_START, VMALLOC_END));
+
+	for (i = meminfo.nr_banks - 1; i >= 0; i--) {
+		if (!meminfo.bank[i].highmem) {
+			va_start = __va(meminfo.bank[i].start);
+			va_end = __va(meminfo.bank[i].start +
+						meminfo.bank[i].size);
+			printk(KERN_NOTICE
+			 "	    lowmem : 0x%08lx - 0x%08lx   (%4ld MB)\n",
+			MLM((unsigned long)va_start, (unsigned long)va_end));
+		}
+		if (i && ((meminfo.bank[i-1].start + meminfo.bank[i-1].size) !=
+			   meminfo.bank[i].start)) {
+			if (meminfo.bank[i-1].start + meminfo.bank[i-1].size
+				   <= MAX_HOLE_ADDRESS) {
+				va_start = __va(meminfo.bank[i-1].start
+						+ meminfo.bank[i-1].size);
+				va_end = __va(meminfo.bank[i].start);
+				printk(KERN_NOTICE
+				"	   vmalloc : 0x%08lx - 0x%08lx   (%4ld MB)\n",
+					   MLM((unsigned long)va_start,
+						   (unsigned long)va_end));
+			}
+		}
+	}
+}
+#endif
+
 /*
  * mem_init() marks the free areas in the mem_map and tells us how much
  * memory is free.  This is done after various parts of the system have
@@ -814,10 +854,6 @@
 		reserved_pages << (PAGE_SHIFT-10),
 		totalhigh_pages << (PAGE_SHIFT-10));
 
-#define MLK(b, t) b, t, ((t) - (b)) >> 10
-#define MLM(b, t) b, t, ((t) - (b)) >> 20
-#define MLK_ROUNDUP(b, t) b, t, DIV_ROUND_UP(((t) - (b)), SZ_1K)
-
 	printk(KERN_NOTICE "Virtual kernel memory layout:\n"
 			"    vector  : 0x%08lx - 0x%08lx   (%4ld kB)\n"
 #ifdef CONFIG_ARM_USE_USER_ACCESSIBLE_TIMERS
@@ -827,20 +863,7 @@
 			"    DTCM    : 0x%08lx - 0x%08lx   (%4ld kB)\n"
 			"    ITCM    : 0x%08lx - 0x%08lx   (%4ld kB)\n"
 #endif
-			"    fixmap  : 0x%08lx - 0x%08lx   (%4ld kB)\n"
-			"    vmalloc : 0x%08lx - 0x%08lx   (%4ld MB)\n"
-			"    lowmem  : 0x%08lx - 0x%08lx   (%4ld MB)\n"
-#ifdef CONFIG_HIGHMEM
-			"    pkmap   : 0x%08lx - 0x%08lx   (%4ld MB)\n"
-#endif
-#ifdef CONFIG_MODULES
-			"    modules : 0x%08lx - 0x%08lx   (%4ld MB)\n"
-#endif
-			"      .text : 0x%p" " - 0x%p" "   (%4d kB)\n"
-			"      .init : 0x%p" " - 0x%p" "   (%4d kB)\n"
-			"      .data : 0x%p" " - 0x%p" "   (%4d kB)\n"
-			"       .bss : 0x%p" " - 0x%p" "   (%4d kB)\n",
-
+			"    fixmap  : 0x%08lx - 0x%08lx   (%4ld kB)\n",
 			MLK(UL(CONFIG_VECTORS_BASE), UL(CONFIG_VECTORS_BASE) +
 				(PAGE_SIZE)),
 #ifdef CONFIG_ARM_USE_USER_ACCESSIBLE_TIMERS
@@ -852,25 +875,39 @@
 			MLK(DTCM_OFFSET, (unsigned long) dtcm_end),
 			MLK(ITCM_OFFSET, (unsigned long) itcm_end),
 #endif
-			MLK(FIXADDR_START, FIXADDR_TOP),
-			MLM(VMALLOC_START, VMALLOC_END),
-			MLM(PAGE_OFFSET, (unsigned long)high_memory),
+			MLK(FIXADDR_START, FIXADDR_TOP));
+#ifdef CONFIG_ENABLE_VMALLOC_SAVING
+	print_vmalloc_lowmem_info();
+#else
+	printk(KERN_NOTICE
+		   "    vmalloc : 0x%08lx - 0x%08lx   (%4ld MB)\n"
+		   "    lowmem  : 0x%08lx - 0x%08lx   (%4ld MB)\n",
+		   MLM(VMALLOC_START, VMALLOC_END),
+		   MLM(PAGE_OFFSET, (unsigned long)high_memory));
+#endif
 #ifdef CONFIG_HIGHMEM
-			MLM(PKMAP_BASE, (PKMAP_BASE) + (LAST_PKMAP) *
+	printk(KERN_NOTICE
+		   "    pkmap   : 0x%08lx - 0x%08lx   (%4ld MB)\n"
+#endif
+#ifdef CONFIG_MODULES
+		   "    modules : 0x%08lx - 0x%08lx   (%4ld MB)\n"
+#endif
+		   "      .text : 0x%p" " - 0x%p" "   (%4d kB)\n"
+		   "      .init : 0x%p" " - 0x%p" "   (%4d kB)\n"
+		   "      .data : 0x%p" " - 0x%p" "   (%4d kB)\n"
+		   "       .bss : 0x%p" " - 0x%p" "   (%4d kB)\n",
+#ifdef CONFIG_HIGHMEM
+		   MLM(PKMAP_BASE, (PKMAP_BASE) + (LAST_PKMAP) *
 				(PAGE_SIZE)),
 #endif
 #ifdef CONFIG_MODULES
-			MLM(MODULES_VADDR, MODULES_END),
+		   MLM(MODULES_VADDR, MODULES_END),
 #endif
 
-			MLK_ROUNDUP(_text, _etext),
-			MLK_ROUNDUP(__init_begin, __init_end),
-			MLK_ROUNDUP(_sdata, _edata),
-			MLK_ROUNDUP(__bss_start, __bss_stop));
-
-#undef MLK
-#undef MLM
-#undef MLK_ROUNDUP
+		   MLK_ROUNDUP(_text, _etext),
+		   MLK_ROUNDUP(__init_begin, __init_end),
+		   MLK_ROUNDUP(_sdata, _edata),
+		   MLK_ROUNDUP(__bss_start, __bss_stop));
 
 	/*
 	 * Check boundaries twice: Some fundamental inconsistencies can
@@ -878,7 +915,7 @@
 	 */
 #ifdef CONFIG_MMU
 	BUILD_BUG_ON(TASK_SIZE				> MODULES_VADDR);
-	BUG_ON(TASK_SIZE 				> MODULES_VADDR);
+	BUG_ON(TASK_SIZE				> MODULES_VADDR);
 #endif
 
 #ifdef CONFIG_HIGHMEM
@@ -897,6 +934,9 @@
 	}
 }
 
+#undef MLK
+#undef MLM
+#undef MLK_ROUNDUP
 void free_initmem(void)
 {
 	unsigned long reclaimed_initmem;
diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c
index e5a60a9..509f59d 100644
--- a/arch/arm/mm/mmu.c
+++ b/arch/arm/mm/mmu.c
@@ -871,6 +871,7 @@
 {
 	struct map_desc *md;
 	struct vm_struct *vm;
+	int rc = 0;
 
 	if (!nr)
 		return;
@@ -881,11 +882,13 @@
 		create_mapping(md);
 		vm->addr = (void *)(md->virtual & PAGE_MASK);
 		vm->size = PAGE_ALIGN(md->length + (md->virtual & ~PAGE_MASK));
-		vm->phys_addr = __pfn_to_phys(md->pfn); 
-		vm->flags = VM_IOREMAP | VM_ARM_STATIC_MAPPING; 
+		vm->phys_addr = __pfn_to_phys(md->pfn);
+		vm->flags = VM_IOREMAP | VM_ARM_STATIC_MAPPING;
 		vm->flags |= VM_ARM_MTYPE(md->type);
 		vm->caller = iotable_init;
-		vm_area_add_early(vm++);
+		rc = vm_area_check_early(vm);
+		if (!rc)
+			vm_area_add_early(vm++);
 	}
 }
 
@@ -999,6 +1002,18 @@
 {
 	int i, j, highmem = 0;
 
+#ifdef CONFIG_ENABLE_VMALLOC_SAVING
+	unsigned long hole_start;
+	for (i = 0; i < (meminfo.nr_banks - 1); i++) {
+		hole_start = meminfo.bank[i].start + meminfo.bank[i].size;
+		if (hole_start != meminfo.bank[i+1].start) {
+			if (hole_start <= MAX_HOLE_ADDRESS) {
+				vmalloc_min = (void *) (vmalloc_min +
+				(meminfo.bank[i+1].start - hole_start));
+			}
+		}
+	}
+#endif
 #ifdef CONFIG_DONT_MAP_HOLE_AFTER_MEMBANK0
 	find_memory_hole();
 #endif
@@ -1382,12 +1397,21 @@
 static void __init map_lowmem(void)
 {
 	struct memblock_region *reg;
+	struct vm_struct *vm;
+	phys_addr_t start;
+	phys_addr_t end;
+	unsigned long vaddr;
+	unsigned long pfn;
+	unsigned long length;
+	unsigned int type;
+	int nr = 0;
 
 	/* Map all the lowmem memory banks. */
 	for_each_memblock(memory, reg) {
-		phys_addr_t start = reg->base;
-		phys_addr_t end = start + reg->size;
 		struct map_desc map;
+		nr++;
+		start = reg->base;
+		end = start + reg->size;
 
 		if (end > arm_lowmem_limit)
 			end = arm_lowmem_limit;
@@ -1440,6 +1464,32 @@
 
 		create_mapping(&map);
 	}
+
+	vm = early_alloc_aligned(sizeof(*vm) * nr, __alignof__(*vm));
+
+	for_each_memblock(memory, reg) {
+
+		start = reg->base;
+		end = start + reg->size;
+
+		if (end > arm_lowmem_limit)
+			end = arm_lowmem_limit;
+		if (start >= end)
+			break;
+
+		pfn = __phys_to_pfn(start);
+		vaddr = __phys_to_virt(start);
+		length = end - start;
+		type = MT_MEMORY;
+
+		vm->addr = (void *)(vaddr & PAGE_MASK);
+		vm->size = PAGE_ALIGN(length + (vaddr & ~PAGE_MASK));
+		vm->phys_addr = __pfn_to_phys(pfn);
+		vm->flags = VM_IOREMAP | VM_ARM_STATIC_MAPPING;
+		vm->flags |= VM_ARM_MTYPE(type);
+		vm->caller = map_lowmem;
+		vm_area_add_early(vm++);
+	}
 }
 
 /*
diff --git a/drivers/bif/bif-core.c b/drivers/bif/bif-core.c
index e11e6ba4..7bc9af2 100644
--- a/drivers/bif/bif-core.c
+++ b/drivers/bif/bif-core.c
@@ -2827,6 +2827,7 @@
 	struct bif_ctrl_dev *bdev = ERR_PTR(-EINVAL);
 	struct bif_slave_dev *sdev;
 	bool battery_present = false;
+	bool slaves_present = false;
 	int rc, rid_ohm;
 
 	if (!bif_desc) {
@@ -2901,12 +2902,21 @@
 	list_for_each_entry(sdev, &bif_sdev_list, list) {
 		if (sdev->present) {
 			battery_present = true;
+			slaves_present = true;
 			break;
 		}
 	}
 
 	BLOCKING_INIT_NOTIFIER_HEAD(&bdev->bus_change_notifier);
 
+	/* Disable the BIF bus master if no slaves are found. */
+	if (!slaves_present) {
+		rc = bdev->desc->ops->set_bus_state(bdev,
+			BIF_BUS_STATE_MASTER_DISABLED);
+		if (rc < 0)
+			pr_err("Could not disble BIF master, rc=%d\n", rc);
+	}
+
 	if (battery_present) {
 		bdev->battery_present = true;
 		rc = blocking_notifier_call_chain(&bdev->bus_change_notifier,
diff --git a/drivers/bif/qpnp-bsi.c b/drivers/bif/qpnp-bsi.c
index 9d0abd2..19a560a 100644
--- a/drivers/bif/qpnp-bsi.c
+++ b/drivers/bif/qpnp-bsi.c
@@ -1162,6 +1162,7 @@
 			+ QPNP_BSI_POWER_UP_LOW_DELAY_US);
 		break;
 	case BIF_BUS_STATE_POWER_DOWN:
+	case BIF_BUS_STATE_MASTER_DISABLED:
 		msleep(QPNP_BSI_MAX_SLAVE_POWER_UP_DELAY_MS);
 		break;
 	}
@@ -1180,13 +1181,34 @@
 {
 	struct qpnp_bsi_chip *chip = bdev_get_drvdata(bdev);
 	int rc = 0;
+	u8 reg;
 
 	if (state == chip->state)
 		return 0;
 
+	if (chip->state == BIF_BUS_STATE_MASTER_DISABLED) {
+		/*
+		 * Enable the BSI peripheral when transitioning from a disabled
+		 * bus state to any of the active bus states so that BIF
+		 * transactions can take place.
+		 */
+		reg = QPNP_BSI_ENABLE;
+		rc = qpnp_bsi_write(chip, QPNP_BSI_REG_ENABLE, &reg, 1);
+		if (rc) {
+			dev_err(&chip->spmi_dev->dev, "%s: qpnp_bsi_write() failed, rc=%d\n",
+				__func__, rc);
+			return rc;
+		}
+	}
+
 	switch (state) {
 	case BIF_BUS_STATE_MASTER_DISABLED:
-		pr_info("master disable not yet supported.\n");
+		/* Disable the BSI peripheral. */
+		reg = QPNP_BSI_DISABLE;
+		rc = qpnp_bsi_write(chip, QPNP_BSI_REG_ENABLE, &reg, 1);
+		if (rc)
+			dev_err(&chip->spmi_dev->dev, "%s: qpnp_bsi_write() failed, rc=%d\n",
+				__func__, rc);
 		break;
 	case BIF_BUS_STATE_POWER_DOWN:
 		rc = qpnp_bsi_bus_transaction(bdev, BIF_TRANS_BC, BIF_CMD_PDWN);
@@ -1624,7 +1646,7 @@
 	struct device *dev = &spmi->dev;
 	struct qpnp_bsi_chip *chip;
 	int rc;
-	u8 type[2], reg;
+	u8 type[2];
 
 	if (!spmi->dev.of_node) {
 		dev_err(dev, "%s: device node missing\n", __func__);
@@ -1655,7 +1677,7 @@
 
 	chip->spmi_dev		= spmi;
 	chip->bdesc.ops		= &qpnp_bsi_ops;
-	chip->state		= BIF_BUS_STATE_POWER_DOWN;
+	chip->state		= BIF_BUS_STATE_MASTER_DISABLED;
 	chip->com_mode		= QPNP_BSI_COM_MODE_IRQ;
 
 	rc = qpnp_bsi_read(chip, QPNP_BSI_REG_TYPE, type, 2);
@@ -1691,15 +1713,6 @@
 		goto cleanup_irqs;
 	}
 
-	/* Enable the BSI module. */
-	reg = QPNP_BSI_ENABLE;
-	rc = qpnp_bsi_write(chip, QPNP_BSI_REG_ENABLE, &reg, 1);
-	if (rc) {
-		dev_err(dev, "%s: qpnp_bsi_write() failed, rc=%d\n",
-			__func__, rc);
-		goto cleanup_irqs;
-	}
-
 	chip->bdev = bif_ctrl_register(&chip->bdesc, dev, chip,
 					spmi->dev.of_node);
 	if (IS_ERR(chip->bdev)) {
diff --git a/drivers/char/diag/diag_masks.c b/drivers/char/diag/diag_masks.c
index 9c27180..69e6250 100644
--- a/drivers/char/diag/diag_masks.c
+++ b/drivers/char/diag/diag_masks.c
@@ -368,7 +368,7 @@
 			driver->log_mask->status = DIAG_CTRL_MASK_INVALID;
 		}
 
-		if (driver->msg_mask->status == DIAG_CTRL_MASK_INVALID) {
+		if (driver->log_mask->status == DIAG_CTRL_MASK_INVALID) {
 			mutex_unlock(&driver->diag_cntl_mutex);
 			return;
 		}
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index dcaa4e1..cdf711c 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -805,6 +805,8 @@
 	int i;
 	unsigned int ttbr0, tlbiall, tlbstatus, tlbsync, mmu_ctrl;
 
+	cmds += adreno_add_idle_cmds(adreno_dev, cmds);
+
 	for (i = 0; i < num_iommu_units; i++) {
 		ttbr0_val = kgsl_mmu_get_default_ttbr0(&device->mmu,
 				i, KGSL_IOMMU_CONTEXT_USER);
@@ -892,8 +894,14 @@
 					KGSL_IOMMU_CTX_TLBSTATUS) >> 2;
 			cmds += adreno_wait_reg_eq(cmds, tlbstatus, 0,
 					KGSL_IOMMU_CTX_TLBSTATUS_SACTIVE, 0xF);
+			/* release all commands with wait_for_me */
+			*cmds++ = cp_type3_packet(CP_WAIT_FOR_ME, 1);
+			*cmds++ = 0;
 		}
 	}
+
+	cmds += adreno_add_idle_cmds(adreno_dev, cmds);
+
 	return cmds - cmds_orig;
 }
 
@@ -3107,6 +3115,7 @@
 				adreno_dev->fast_hang_detect = 1;
 				kgsl_pwrscale_enable(device);
 			} else {
+				kgsl_pwrctrl_wake(device);
 				device->pwrctrl.ctrl_flags = KGSL_PWR_ON;
 				adreno_dev->fast_hang_detect = 0;
 				kgsl_pwrscale_disable(device);
diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h
index 9a070a6..6507852 100644
--- a/drivers/gpu/msm/adreno.h
+++ b/drivers/gpu/msm/adreno.h
@@ -658,9 +658,7 @@
 	*cmds++ = cp_type3_packet(CP_WAIT_FOR_IDLE, 1);
 	*cmds++ = 0;
 
-	if ((adreno_dev->gpurev == ADRENO_REV_A305) ||
-		(adreno_dev->gpurev == ADRENO_REV_A305C) ||
-		(adreno_dev->gpurev == ADRENO_REV_A320)) {
+	if (adreno_is_a3xx(adreno_dev)) {
 		*cmds++ = cp_type3_packet(CP_WAIT_FOR_ME, 1);
 		*cmds++ = 0;
 	}
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index 2781a34..7da0811 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -911,11 +911,7 @@
 
 	mutex_lock(&private->process_private_mutex);
 
-	/*
-	 * If debug root initialized then it means the rest of the fields
-	 * are also initialized
-	 */
-	if (private->debug_root)
+	if (test_bit(KGSL_PROCESS_INIT, &private->priv))
 		goto done;
 
 	private->mem_rb = RB_ROOT;
@@ -936,6 +932,8 @@
 	if (kgsl_process_init_debugfs(private))
 		goto error;
 
+	set_bit(KGSL_PROCESS_INIT, &private->priv);
+
 done:
 	mutex_unlock(&private->process_private_mutex);
 	return private;
diff --git a/drivers/gpu/msm/kgsl_debugfs.h b/drivers/gpu/msm/kgsl_debugfs.h
index b2f137c..fe9bc76 100644
--- a/drivers/gpu/msm/kgsl_debugfs.h
+++ b/drivers/gpu/msm/kgsl_debugfs.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2002,2008-2011, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2002,2008-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
@@ -35,7 +35,7 @@
 static inline void kgsl_device_debugfs_init(struct kgsl_device *device) { }
 static inline void kgsl_core_debugfs_close(void) { }
 static inline struct dentry *kgsl_get_debugfs_dir(void) { return NULL; }
-static inline int kgsl_process_init_debugfs(struct kgsl_process_private *)
+static inline int kgsl_process_init_debugfs(struct kgsl_process_private *priv)
 {
 	return 0;
 }
diff --git a/drivers/gpu/msm/kgsl_device.h b/drivers/gpu/msm/kgsl_device.h
index 09a31c9..0b5fe52 100644
--- a/drivers/gpu/msm/kgsl_device.h
+++ b/drivers/gpu/msm/kgsl_device.h
@@ -315,8 +315,23 @@
 	unsigned int pagefault_ts;
 };
 
+/**
+ * struct kgsl_process_private -  Private structure for a KGSL process (across
+ * all devices)
+ * @priv: Internal flags, use KGSL_PROCESS_* values
+ * @pid: ID for the task owner of the process
+ * @mem_lock: Spinlock to protect the process memory lists
+ * @refcount: kref object for reference counting the process
+ * @process_private_mutex: Mutex to synchronize access to the process struct
+ * @mem_rb: RB tree node for the memory owned by this process
+ * @idr: Iterator for assigning IDs to memory allocations
+ * @pagetable: Pointer to the pagetable owned by this process
+ * @kobj: Pointer to a kobj for the sysfs directory for this process
+ * @debug_root: Pointer to the debugfs root for this process
+ * @stats: Memory allocation statistics for this process
+ */
 struct kgsl_process_private {
-	unsigned int refcnt;
+	unsigned long priv;
 	pid_t pid;
 	spinlock_t mem_lock;
 
@@ -338,6 +353,14 @@
 	} stats[KGSL_MEM_ENTRY_MAX];
 };
 
+/**
+ * enum kgsl_process_priv_flags - Private flags for kgsl_process_private
+ * @KGSL_PROCESS_INIT: Set if the process structure has been set up
+ */
+enum kgsl_process_priv_flags {
+	KGSL_PROCESS_INIT = 0,
+};
+
 struct kgsl_device_private {
 	struct kgsl_device *device;
 	struct kgsl_process_private *process_priv;
diff --git a/drivers/gpu/msm/kgsl_pwrscale_trustzone.c b/drivers/gpu/msm/kgsl_pwrscale_trustzone.c
index 8fc1753..7f8a6b1 100644
--- a/drivers/gpu/msm/kgsl_pwrscale_trustzone.c
+++ b/drivers/gpu/msm/kgsl_pwrscale_trustzone.c
@@ -159,11 +159,13 @@
 		(priv->bin.total_time < FLOOR))
 		return;
 
-	/* If there is an extended block of busy processing,
-	 * increase frequency.  Otherwise run the normal algorithm.
+	/* If there is an extended block of busy processing, set
+	 * frequency to turbo.  Otherwise run the normal algorithm.
 	 */
 	if (priv->bin.busy_time > CEILING) {
-		val = -1;
+		val = 0;
+		kgsl_pwrctrl_pwrlevel_change(device,
+				KGSL_PWRLEVEL_TURBO);
 	} else if (priv->idle_dcvs) {
 		idle = priv->bin.total_time - priv->bin.busy_time;
 		idle = (idle > 0) ? idle : 0;
diff --git a/drivers/input/misc/mpu3050.c b/drivers/input/misc/mpu3050.c
index 1537866..642975d 100644
--- a/drivers/input/misc/mpu3050.c
+++ b/drivers/input/misc/mpu3050.c
@@ -734,7 +734,6 @@
 
 	idev->name = "MPU3050";
 	idev->id.bustype = BUS_I2C;
-	idev->dev.parent = &client->dev;
 
 	idev->open = mpu3050_input_open;
 	idev->close = mpu3050_input_close;
diff --git a/drivers/input/touchscreen/synaptics_fw_update.c b/drivers/input/touchscreen/synaptics_fw_update.c
index 9f326f1..0a92d51 100644
--- a/drivers/input/touchscreen/synaptics_fw_update.c
+++ b/drivers/input/touchscreen/synaptics_fw_update.c
@@ -32,7 +32,6 @@
 #define SHOW_PROGRESS
 #define MAX_FIRMWARE_ID_LEN 10
 #define FORCE_UPDATE false
-#define DO_LOCKDOWN false
 #define INSIDE_FIRMWARE_UPDATE
 
 #define FW_IMAGE_OFFSET 0x100
@@ -1115,7 +1114,11 @@
 	if (retval < 0)
 		return retval;
 
-	if (f01_device_status.flash_prog) {
+	if (force) {
+		dev_info(&fwu->rmi4_data->i2c_client->dev,
+			"%s: Force to enter flash prog mode\n",
+			__func__);
+	} else if (f01_device_status.flash_prog) {
 		dev_info(&fwu->rmi4_data->i2c_client->dev,
 				"%s: Already in flash prog mode\n",
 				__func__);
@@ -1475,6 +1478,9 @@
 			"%s: Erase all command written\n",
 			__func__);
 
+	if (fwu->polling_mode)
+		msleep(100);
+
 	retval = fwu_wait_for_idle(ERASE_WAIT_MS);
 	if (retval < 0)
 		return retval;
@@ -1757,7 +1763,7 @@
 	kfree(fwu->ext_data_source);
 	fwu->ext_data_source = NULL;
 	fwu->force_update = FORCE_UPDATE;
-	fwu->do_lockdown = DO_LOCKDOWN;
+	fwu->do_lockdown = rmi4_data->board->do_lockdown;
 	return retval;
 }
 
@@ -1800,7 +1806,7 @@
 	kfree(fwu->ext_data_source);
 	fwu->ext_data_source = NULL;
 	fwu->force_update = FORCE_UPDATE;
-	fwu->do_lockdown = DO_LOCKDOWN;
+	fwu->do_lockdown = rmi4_data->board->do_lockdown;
 	return retval;
 }
 
@@ -1835,7 +1841,7 @@
 	kfree(fwu->ext_data_source);
 	fwu->ext_data_source = NULL;
 	fwu->force_update = FORCE_UPDATE;
-	fwu->do_lockdown = DO_LOCKDOWN;
+	fwu->do_lockdown = rmi4_data->board->do_lockdown;
 	return retval;
 }
 
@@ -2166,7 +2172,7 @@
 
 	fwu->initialized = true;
 	fwu->force_update = FORCE_UPDATE;
-	fwu->do_lockdown = DO_LOCKDOWN;
+	fwu->do_lockdown = rmi4_data->board->do_lockdown;
 	fwu->initialized = true;
 	fwu->polling_mode = false;
 
diff --git a/drivers/input/touchscreen/synaptics_i2c_rmi4.c b/drivers/input/touchscreen/synaptics_i2c_rmi4.c
index f8ab5f4..aec655c 100644
--- a/drivers/input/touchscreen/synaptics_i2c_rmi4.c
+++ b/drivers/input/touchscreen/synaptics_i2c_rmi4.c
@@ -96,6 +96,8 @@
 #define F12_FINGERS_TO_SUPPORT 10
 #define MAX_F11_TOUCH_WIDTH 15
 
+#define RMI4_COORDS_ARR_SIZE 4
+
 static int synaptics_rmi4_i2c_read(struct synaptics_rmi4_data *rmi4_data,
 		unsigned short addr, unsigned char *data,
 		unsigned short length);
@@ -820,6 +822,32 @@
 	return retval;
 }
 
+/**
+ * synaptics_rmi4_release_all()
+ *
+ * Called by synaptics_rmi4_suspend()
+ *
+ * Release all touch data during the touch device switch to suspend state.
+ */
+
+static void synaptics_rmi4_release_all(struct synaptics_rmi4_data *rmi4_data)
+{
+	int finger;
+	int max_num_fingers = rmi4_data->num_of_fingers;
+
+	for (finger = 0; finger < max_num_fingers; finger++) {
+		input_mt_slot(rmi4_data->input_dev, finger);
+		input_mt_report_slot_state(rmi4_data->input_dev,
+				MT_TOOL_FINGER, 0);
+	}
+
+	input_report_key(rmi4_data->input_dev, BTN_TOUCH, 0);
+	input_report_key(rmi4_data->input_dev,
+			BTN_TOOL_FINGER, 0);
+
+	input_sync(rmi4_data->input_dev);
+}
+
  /**
  * synaptics_rmi4_f11_abs_report()
  *
@@ -1027,9 +1055,9 @@
 			wy = finger_data->wy;
 #endif
 
-			if (rmi4_data->board->x_flip)
+			if (rmi4_data->flip_x)
 				x = rmi4_data->sensor_max_x - x;
-			if (rmi4_data->board->y_flip)
+			if (rmi4_data->flip_y)
 				y = rmi4_data->sensor_max_y - y;
 
 			dev_dbg(&rmi4_data->i2c_client->dev,
@@ -1306,6 +1334,50 @@
 }
 
 #ifdef CONFIG_OF
+static int synaptics_rmi4_get_dt_coords(struct device *dev, char *name,
+				struct synaptics_rmi4_platform_data *pdata)
+{
+	u32 coords[RMI4_COORDS_ARR_SIZE];
+	struct property *prop;
+	struct device_node *np = dev->of_node;
+	int coords_size, rc;
+
+	prop = of_find_property(np, name, NULL);
+	if (!prop)
+		return -EINVAL;
+	if (!prop->value)
+		return -ENODATA;
+
+	coords_size = prop->length / sizeof(u32);
+	if (coords_size != RMI4_COORDS_ARR_SIZE) {
+		dev_err(dev, "invalid %s\n", name);
+		return -EINVAL;
+	}
+
+	rc = of_property_read_u32_array(np, name, coords, coords_size);
+	if (rc && (rc != -EINVAL)) {
+		dev_err(dev, "Unable to read %s\n", name);
+		return rc;
+	}
+
+	if (strcmp(name, "synaptics,panel-coords") == 0) {
+		pdata->panel_minx = coords[0];
+		pdata->panel_miny = coords[1];
+		pdata->panel_maxx = coords[2];
+		pdata->panel_maxy = coords[3];
+	} else if (strcmp(name, "synaptics,display-coords") == 0) {
+		pdata->disp_minx = coords[0];
+		pdata->disp_miny = coords[1];
+		pdata->disp_maxx = coords[2];
+		pdata->disp_maxy = coords[3];
+	} else {
+		dev_err(dev, "unsupported property %s\n", name);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
 static int synaptics_rmi4_parse_dt(struct device *dev,
 				struct synaptics_rmi4_platform_data *rmi4_pdata)
 {
@@ -1323,21 +1395,26 @@
 			"synaptics,disable-gpios");
 	rmi4_pdata->x_flip = of_property_read_bool(np, "synaptics,x-flip");
 	rmi4_pdata->y_flip = of_property_read_bool(np, "synaptics,y-flip");
+	rmi4_pdata->do_lockdown = of_property_read_bool(np,
+			"synaptics,do-lockdown");
 
-	rc = of_property_read_u32(np, "synaptics,panel-x", &temp_val);
-	if (rc && (rc != -EINVAL)) {
-		dev_err(dev, "Unable to read panel X dimension\n");
+	rc = synaptics_rmi4_get_dt_coords(dev, "synaptics,display-coords",
+				rmi4_pdata);
+	if (rc && (rc != -EINVAL))
 		return rc;
-	} else {
-		rmi4_pdata->panel_x = temp_val;
-	}
 
-	rc = of_property_read_u32(np, "synaptics,panel-y", &temp_val);
-	if (rc && (rc != -EINVAL)) {
-		dev_err(dev, "Unable to read panel Y dimension\n");
+	rc = synaptics_rmi4_get_dt_coords(dev, "synaptics,panel-coords",
+				rmi4_pdata);
+	if (rc && (rc != -EINVAL))
 		return rc;
-	} else {
-		rmi4_pdata->panel_y = temp_val;
+
+	rmi4_pdata->reset_delay = RESET_DELAY;
+	rc = of_property_read_u32(np, "synaptics,reset-delay", &temp_val);
+	if (!rc)
+		rmi4_pdata->reset_delay = temp_val;
+	else if (rc != -EINVAL) {
+		dev_err(dev, "Unable to read reset delay\n");
+		return rc;
 	}
 
 	rc = of_property_read_string(np, "synaptics,fw-image-name",
@@ -1793,11 +1870,10 @@
 	const struct synaptics_rmi4_platform_data *pdata = rmi4_data->board;
 
 	if (!pdata->capacitance_button_map) {
-		dev_err(&rmi4_data->i2c_client->dev,
-				"%s: capacitance_button_map is" \
-				"NULL in board file\n",
+		dev_info(&rmi4_data->i2c_client->dev,
+				"%s: capacitance_button_map not in use\n",
 				__func__);
-		return -ENODEV;
+		return 0;
 	} else if (!pdata->capacitance_button_map->map) {
 		dev_err(&rmi4_data->i2c_client->dev,
 				"%s: Button map is missing in board file\n",
@@ -2232,7 +2308,7 @@
 		return retval;
 	}
 
-	msleep(RESET_DELAY);
+	msleep(rmi4_data->board->reset_delay);
 	return retval;
 };
 
@@ -2577,7 +2653,7 @@
 			gpio_set_value(rmi4_data->board->reset_gpio, 0);
 			usleep(RMI4_GPIO_SLEEP_LOW_US);
 			gpio_set_value(rmi4_data->board->reset_gpio, 1);
-			msleep(RESET_DELAY);
+			msleep(rmi4_data->board->reset_delay);
 		} else
 			synaptics_rmi4_reset_command(rmi4_data);
 
@@ -2750,12 +2826,32 @@
 		goto err_free_gpios;
 	}
 
+	if (rmi4_data->board->disp_maxx)
+		rmi4_data->disp_maxx = rmi4_data->board->disp_maxx;
+	else
+		rmi4_data->disp_maxx = rmi4_data->sensor_max_x;
+
+	if (rmi4_data->board->disp_maxy)
+		rmi4_data->disp_maxy = rmi4_data->board->disp_maxy;
+	else
+		rmi4_data->disp_maxy = rmi4_data->sensor_max_y;
+
+	if (rmi4_data->board->disp_minx)
+		rmi4_data->disp_minx = rmi4_data->board->disp_minx;
+	else
+		rmi4_data->disp_minx = 0;
+
+	if (rmi4_data->board->disp_miny)
+		rmi4_data->disp_miny = rmi4_data->board->disp_miny;
+	else
+		rmi4_data->disp_miny = 0;
+
 	input_set_abs_params(rmi4_data->input_dev,
-			ABS_MT_POSITION_X, 0,
-			rmi4_data->sensor_max_x, 0, 0);
+			ABS_MT_POSITION_X, rmi4_data->disp_minx,
+			rmi4_data->disp_maxx, 0, 0);
 	input_set_abs_params(rmi4_data->input_dev,
-			ABS_MT_POSITION_Y, 0,
-			rmi4_data->sensor_max_y, 0, 0);
+			ABS_MT_POSITION_Y, rmi4_data->disp_miny,
+			rmi4_data->disp_maxy, 0, 0);
 	input_set_abs_params(rmi4_data->input_dev,
 			ABS_PRESSURE, 0, 255, 0, 0);
 #ifdef REPORT_2D_W
@@ -3299,6 +3395,8 @@
 			synaptics_rmi4_sensor_sleep(rmi4_data);
 		}
 
+		synaptics_rmi4_release_all(rmi4_data);
+
 		retval = synaptics_rmi4_regulator_lpm(rmi4_data, true);
 		if (retval < 0) {
 			dev_err(dev, "failed to enter low power mode\n");
@@ -3363,17 +3461,6 @@
 	rmi4_data->touch_stopped = false;
 	synaptics_rmi4_irq_enable(rmi4_data, true);
 
-	if (rmi4_data->board->power_down_enable ||
-			rmi4_data->board->disable_gpios) {
-		retval = synaptics_rmi4_reset_device(rmi4_data);
-		if (retval < 0) {
-			dev_err(&rmi4_data->i2c_client->dev,
-				"%s: Failed to issue reset command, " \
-				"rc = %d\n", __func__, retval);
-			return retval;
-		}
-	}
-
 	rmi4_data->suspended = false;
 
 	return 0;
diff --git a/drivers/input/touchscreen/synaptics_i2c_rmi4.h b/drivers/input/touchscreen/synaptics_i2c_rmi4.h
index 677a2fe..ef39bb7 100644
--- a/drivers/input/touchscreen/synaptics_i2c_rmi4.h
+++ b/drivers/input/touchscreen/synaptics_i2c_rmi4.h
@@ -186,6 +186,10 @@
  * @irq: attention interrupt
  * @sensor_max_x: sensor maximum x value
  * @sensor_max_y: sensor maximum y value
+ * @disp_maxx: max x value of display
+ * @disp_maxy: max y value of display
+ * @disp_minx: min x value of display
+ * @disp_miny: min y value of display
  * @irq_enabled: flag for indicating interrupt enable status
  * @touch_stopped: flag to stop interrupt thread processing
  * @fingers_on_2d: flag to indicate presence of fingers in 2d area
@@ -230,6 +234,10 @@
 	int irq;
 	int sensor_max_x;
 	int sensor_max_y;
+	int disp_maxx;
+	int disp_maxy;
+	int disp_minx;
+	int disp_miny;
 	bool irq_enabled;
 	bool touch_stopped;
 	bool fingers_on_2d;
diff --git a/drivers/leds/leds-qpnp.c b/drivers/leds/leds-qpnp.c
index 5a405be..bf59d03 100644
--- a/drivers/leds/leds-qpnp.c
+++ b/drivers/leds/leds-qpnp.c
@@ -23,6 +23,7 @@
 #include <linux/spmi.h>
 #include <linux/qpnp/pwm.h>
 #include <linux/workqueue.h>
+#include <linux/delay.h>
 #include <linux/regulator/consumer.h>
 
 #define WLED_MOD_EN_REG(base, n)	(base + 0x60 + n*0x10)
@@ -43,6 +44,7 @@
 #define WLED_HIGH_POLE_CAP_REG(base)		(base + 0x58)
 #define WLED_CURR_SINK_MASK		0xE0
 #define WLED_CURR_SINK_SHFT		0x05
+#define WLED_DISABLE_ALL_SINKS		0x00
 #define WLED_SWITCH_FREQ_MASK		0x0F
 #define WLED_OVP_VAL_MASK		0x03
 #define WLED_OVP_VAL_BIT_SHFT		0x00
@@ -58,8 +60,10 @@
 #define WLED_CTL_DLY_STEP		200
 #define WLED_CTL_DLY_MAX		1400
 #define WLED_MAX_CURR			25
+#define WLED_NO_CURRENT			0x00
+#define WLED_OVP_DELAY			1000
 #define WLED_MSB_MASK			0x0F
-#define WLED_MAX_CURR_MASK		0x19
+#define WLED_MAX_CURR_MASK		0x1F
 #define WLED_OP_FDBCK_MASK		0x07
 #define WLED_OP_FDBCK_BIT_SHFT		0x00
 #define WLED_OP_FDBCK_DEFAULT		0x00
@@ -73,6 +77,9 @@
 #define WLED_SYNC_VAL			0x07
 #define WLED_SYNC_RESET_VAL		0x00
 
+#define PMIC_VER_8026			0x04
+#define PMIC_VERSION_REG		0x0105
+
 #define WLED_DEFAULT_STRINGS		0x01
 #define WLED_DEFAULT_OVP_VAL		0x02
 #define WLED_BOOST_LIM_DEFAULT		0x03
@@ -173,7 +180,8 @@
 #define LED_MPP_EN_CTRL(base)		(base + 0x46)
 #define LED_MPP_SINK_CTRL(base)		(base + 0x4C)
 
-#define LED_MPP_CURRENT_DEFAULT		5
+#define LED_MPP_CURRENT_MIN		5
+#define LED_MPP_CURRENT_MAX		40
 #define LED_MPP_VIN_CTRL_DEFAULT	0
 #define LED_MPP_CURRENT_PER_SETTING	5
 #define LED_MPP_SOURCE_SEL_DEFAULT	LED_MPP_MODE_ENABLE
@@ -336,6 +344,7 @@
 	u8	ctrl_delay_us;
 	u8	switch_freq;
 	u8	op_fdbck;
+	u8	pmic_version;
 	bool	dig_mod_gen_en;
 	bool	cs_out_en;
 };
@@ -510,16 +519,86 @@
 	pr_debug("===== %s LED register dump end =====\n", led->cdev.name);
 }
 
+static int qpnp_wled_sync(struct qpnp_led_data *led)
+{
+	int rc;
+	u8 val;
+
+	/* sync */
+	val = WLED_SYNC_VAL;
+	rc = spmi_ext_register_writel(led->spmi_dev->ctrl, led->spmi_dev->sid,
+		WLED_SYNC_REG(led->base), &val, 1);
+	if (rc) {
+		dev_err(&led->spmi_dev->dev,
+				"WLED set sync reg failed(%d)\n", rc);
+		return rc;
+	}
+
+	val = WLED_SYNC_RESET_VAL;
+	rc = spmi_ext_register_writel(led->spmi_dev->ctrl, led->spmi_dev->sid,
+		WLED_SYNC_REG(led->base), &val, 1);
+	if (rc) {
+		dev_err(&led->spmi_dev->dev,
+				"WLED reset sync reg failed(%d)\n", rc);
+		return rc;
+	}
+	return 0;
+}
+
 static int qpnp_wled_set(struct qpnp_led_data *led)
 {
 	int rc, duty, level;
-	u8 val, i, num_wled_strings;
+	u8 val, i, num_wled_strings, sink_val;
+
+	num_wled_strings = led->wled_cfg->num_strings;
 
 	level = led->cdev.brightness;
 
 	if (level > WLED_MAX_LEVEL)
 		level = WLED_MAX_LEVEL;
 	if (level == 0) {
+		for (i = 0; i < num_wled_strings; i++) {
+			rc = qpnp_led_masked_write(led,
+				WLED_FULL_SCALE_REG(led->base, i),
+				WLED_MAX_CURR_MASK, WLED_NO_CURRENT);
+			if (rc) {
+				dev_err(&led->spmi_dev->dev,
+					"Write max current failure (%d)\n",
+					rc);
+				return rc;
+			}
+		}
+
+		rc = qpnp_wled_sync(led);
+		if (rc) {
+			dev_err(&led->spmi_dev->dev,
+				"WLED sync failed(%d)\n", rc);
+			return rc;
+		}
+
+		rc = spmi_ext_register_readl(led->spmi_dev->ctrl,
+			led->spmi_dev->sid, WLED_CURR_SINK_REG(led->base),
+			&sink_val, 1);
+		if (rc) {
+			dev_err(&led->spmi_dev->dev,
+				"WLED read sink reg failed(%d)\n", rc);
+			return rc;
+		}
+
+		if (led->wled_cfg->pmic_version == PMIC_VER_8026) {
+			val = WLED_DISABLE_ALL_SINKS;
+			rc = spmi_ext_register_writel(led->spmi_dev->ctrl,
+				led->spmi_dev->sid,
+				WLED_CURR_SINK_REG(led->base), &val, 1);
+			if (rc) {
+				dev_err(&led->spmi_dev->dev,
+					"WLED write sink reg failed(%d)\n", rc);
+				return rc;
+			}
+
+			usleep(WLED_OVP_DELAY);
+		}
+
 		val = WLED_BOOST_OFF;
 		rc = spmi_ext_register_writel(led->spmi_dev->ctrl,
 			led->spmi_dev->sid, WLED_MOD_CTRL_REG(led->base),
@@ -529,6 +608,35 @@
 				"WLED write ctrl reg failed(%d)\n", rc);
 			return rc;
 		}
+
+		for (i = 0; i < num_wled_strings; i++) {
+			rc = qpnp_led_masked_write(led,
+				WLED_FULL_SCALE_REG(led->base, i),
+				WLED_MAX_CURR_MASK, led->max_current);
+			if (rc) {
+				dev_err(&led->spmi_dev->dev,
+					"Write max current failure (%d)\n",
+					rc);
+				return rc;
+			}
+		}
+
+		rc = qpnp_wled_sync(led);
+		if (rc) {
+			dev_err(&led->spmi_dev->dev,
+				"WLED sync failed(%d)\n", rc);
+			return rc;
+		}
+
+		rc = spmi_ext_register_writel(led->spmi_dev->ctrl,
+			led->spmi_dev->sid, WLED_CURR_SINK_REG(led->base),
+			&sink_val, 1);
+		if (rc) {
+			dev_err(&led->spmi_dev->dev,
+				"WLED write sink reg failed(%d)\n", rc);
+			return rc;
+		}
+
 	} else {
 		val = WLED_BOOST_ON;
 		rc = spmi_ext_register_writel(led->spmi_dev->ctrl,
@@ -543,8 +651,6 @@
 
 	duty = (WLED_MAX_DUTY_CYCLE * level) / WLED_MAX_LEVEL;
 
-	num_wled_strings = led->wled_cfg->num_strings;
-
 	/* program brightness control registers */
 	for (i = 0; i < num_wled_strings; i++) {
 		rc = qpnp_led_masked_write(led,
@@ -566,22 +672,9 @@
 		}
 	}
 
-	/* sync */
-	val = WLED_SYNC_VAL;
-	rc = spmi_ext_register_writel(led->spmi_dev->ctrl, led->spmi_dev->sid,
-		WLED_SYNC_REG(led->base), &val, 1);
+	rc = qpnp_wled_sync(led);
 	if (rc) {
-		dev_err(&led->spmi_dev->dev,
-				"WLED set sync reg failed(%d)\n", rc);
-		return rc;
-	}
-
-	val = WLED_SYNC_RESET_VAL;
-	rc = spmi_ext_register_writel(led->spmi_dev->ctrl, led->spmi_dev->sid,
-		WLED_SYNC_REG(led->base), &val, 1);
-	if (rc) {
-		dev_err(&led->spmi_dev->dev,
-				"WLED reset sync reg failed(%d)\n", rc);
+		dev_err(&led->spmi_dev->dev, "WLED sync failed(%d)\n", rc);
 		return rc;
 	}
 	return 0;
@@ -625,6 +718,21 @@
 
 		if (led->mpp_cfg->pwm_mode != MANUAL_MODE)
 			pwm_enable(led->mpp_cfg->pwm_cfg->pwm_dev);
+		else {
+			if (led->cdev.brightness < LED_MPP_CURRENT_MIN)
+				led->cdev.brightness = LED_MPP_CURRENT_MIN;
+
+			val = (led->cdev.brightness / LED_MPP_CURRENT_MIN) - 1;
+
+			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 sink control reg\n");
+				return rc;
+			}
+		}
 
 		val = (led->mpp_cfg->source_sel & LED_MPP_SRC_MASK) |
 			(led->mpp_cfg->mode_ctrl & LED_MPP_MODE_CTRL_MASK);
@@ -1351,7 +1459,10 @@
 		led->cdev.max_brightness = RGB_MAX_LEVEL;
 		break;
 	case QPNP_ID_LED_MPP:
-		led->cdev.max_brightness = MPP_MAX_LEVEL;
+		if (led->mpp_cfg->pwm_mode == MANUAL_MODE)
+			led->cdev.max_brightness = led->max_current;
+		else
+			led->cdev.max_brightness = MPP_MAX_LEVEL;
 		break;
 	case QPNP_ID_KPDBL:
 		led->cdev.max_brightness = KPDBL_MAX_LEVEL;
@@ -2332,6 +2443,14 @@
 {
 	int rc, val;
 
+
+	if (led->max_current < LED_MPP_CURRENT_MIN ||
+		led->max_current > LED_MPP_CURRENT_MAX) {
+		dev_err(&led->spmi_dev->dev,
+			"max current for mpp is not valid\n");
+		return -EINVAL;
+	}
+
 	val = (led->mpp_cfg->current_setting / LED_MPP_CURRENT_PER_SETTING) - 1;
 
 	if (val < 0)
@@ -2349,7 +2468,7 @@
 		LED_MPP_SINK_MASK, val);
 	if (rc) {
 		dev_err(&led->spmi_dev->dev,
-			"Failed to write led enable reg\n");
+			"Failed to write sink control reg\n");
 		return rc;
 	}
 
@@ -2462,6 +2581,13 @@
 		return -ENOMEM;
 	}
 
+	rc = spmi_ext_register_readl(led->spmi_dev->ctrl, led->spmi_dev->sid,
+		PMIC_VERSION_REG, &led->wled_cfg->pmic_version, 1);
+	if (rc) {
+		dev_err(&led->spmi_dev->dev,
+			"Unable to read pmic ver, rc(%d)\n", rc);
+	}
+
 	led->wled_cfg->num_strings = WLED_DEFAULT_STRINGS;
 	rc = of_property_read_u32(node, "qcom,num-strings", &val);
 	if (!rc)
@@ -2954,11 +3080,16 @@
 		return -ENOMEM;
 	}
 
-	led->mpp_cfg->current_setting = LED_MPP_CURRENT_DEFAULT;
+	led->mpp_cfg->current_setting = LED_MPP_CURRENT_MIN;
 	rc = of_property_read_u32(node, "qcom,current-setting", &val);
-	if (!rc)
-		led->mpp_cfg->current_setting = (u8) val;
-	else if (rc != -EINVAL)
+	if (!rc) {
+		if (led->mpp_cfg->current_setting < LED_MPP_CURRENT_MIN)
+			led->mpp_cfg->current_setting = LED_MPP_CURRENT_MIN;
+		else if (led->mpp_cfg->current_setting > LED_MPP_CURRENT_MAX)
+			led->mpp_cfg->current_setting = LED_MPP_CURRENT_MAX;
+		else
+			led->mpp_cfg->current_setting = (u8) val;
+	} else if (rc != -EINVAL)
 		return rc;
 
 	led->mpp_cfg->source_sel = LED_MPP_SOURCE_SEL_DEFAULT;
diff --git a/drivers/media/platform/msm/camera_v1/server/msm_cam_server.c b/drivers/media/platform/msm/camera_v1/server/msm_cam_server.c
index 78d15d9..d9fba33 100644
--- a/drivers/media/platform/msm/camera_v1/server/msm_cam_server.c
+++ b/drivers/media/platform/msm/camera_v1/server/msm_cam_server.c
@@ -2777,40 +2777,6 @@
 	return rc;
 }
 
-static int msm_mmap_config(struct file *fp, struct vm_area_struct *vma)
-{
-	struct msm_cam_config_dev *config_cam = fp->private_data;
-	int rc = 0;
-	int phyaddr;
-	int retval;
-	unsigned long size;
-
-	D("%s: phy_addr=0x%x", __func__, config_cam->mem_map.cookie);
-	phyaddr = (int)config_cam->mem_map.cookie;
-	if (!phyaddr) {
-		pr_err("%s: no physical memory to map", __func__);
-		return -EFAULT;
-	}
-	memset(&config_cam->mem_map, 0,
-		sizeof(struct msm_mem_map_info));
-	size = vma->vm_end - vma->vm_start;
-	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
-	retval = remap_pfn_range(vma, vma->vm_start,
-					phyaddr >> PAGE_SHIFT,
-					size, vma->vm_page_prot);
-	if (retval) {
-		pr_err("%s: remap failed, rc = %d",
-					__func__, retval);
-		rc = -ENOMEM;
-		goto end;
-	}
-	D("%s: phy_addr=0x%x: %08lx-%08lx, pgoff %08lx\n",
-			__func__, (uint32_t)phyaddr,
-			vma->vm_start, vma->vm_end, vma->vm_pgoff);
-end:
-	return rc;
-}
-
 static int msm_open_config(struct inode *inode, struct file *fp)
 {
 	int rc;
@@ -3081,12 +3047,6 @@
 		rc = msm_v4l2_evt_notify(config_cam->p_mctl, cmd, arg);
 		break;
 
-	case MSM_CAM_IOCTL_SET_MEM_MAP_INFO:
-		if (copy_from_user(&config_cam->mem_map, (void __user *)arg,
-				sizeof(struct msm_mem_map_info)))
-			rc = -EINVAL;
-		break;
-
 	case MSM_CAM_IOCTL_SET_MCTL_SDEV:{
 		struct msm_mctl_set_sdev_data set_data;
 		if (copy_from_user(&set_data, (void __user *)arg,
@@ -3148,7 +3108,6 @@
 	.open  = msm_open_config,
 	.poll  = msm_poll_config,
 	.unlocked_ioctl = msm_ioctl_config,
-	.mmap	= msm_mmap_config,
 	.release = msm_close_config,
 };
 
diff --git a/drivers/media/platform/msm/camera_v2/Kconfig b/drivers/media/platform/msm/camera_v2/Kconfig
index 4668d02..bc7d135 100644
--- a/drivers/media/platform/msm/camera_v2/Kconfig
+++ b/drivers/media/platform/msm/camera_v2/Kconfig
@@ -191,6 +191,15 @@
 		snapshot config = 3264 * 2448 at 18 fps.
 		2 lanes max fps is 18, 4 lanes max fps is 24.
 
+config OV8865
+	bool "OmniVision OV8865 (BAYER 8MP)"
+	depends on MSMB_CAMERA
+	---help---
+		OmniVision 8 MP Bayer Sensor with auto focus.uses
+		4 mipi lanes, preview config = 1632*1224 30 fps,
+		snapshot config = 3264 * 2448 at 30 fps.
+		Max fps is 30fps at 3264 * 2448, 60fps at 1632 * 1224
+
 config s5k4e1
 	bool "Sensor s5k4e1 (BAYER 5MP)"
 	depends on MSMB_CAMERA
diff --git a/drivers/media/platform/msm/camera_v2/sensor/Makefile b/drivers/media/platform/msm/camera_v2/sensor/Makefile
index bd1b10b..bbfbbdf 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/Makefile
+++ b/drivers/media/platform/msm/camera_v2/sensor/Makefile
@@ -17,3 +17,4 @@
 obj-$(CONFIG_MT9M114) += mt9m114.o
 obj-$(CONFIG_SP1628) += sp1628.o
 obj-$(CONFIG_GC0339) += gc0339.o
+obj-$(CONFIG_OV8865) += ov8865.o
diff --git a/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c b/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c
index c188105..32d74ba 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
@@ -816,6 +816,7 @@
 
 	cci_client = msm_actuator_t->i2c_client.cci_client;
 	cci_client->cci_subdev = msm_cci_get_subdev();
+	cci_client->cci_i2c_master = MASTER_MAX;
 	v4l2_subdev_init(&msm_actuator_t->msm_sd.sd,
 		msm_actuator_t->act_v4l2_subdev_ops);
 	v4l2_set_subdevdata(&msm_actuator_t->msm_sd.sd, msm_actuator_t);
diff --git a/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cam_cci_hwreg.h b/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cam_cci_hwreg.h
index 591c464..059633b 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cam_cci_hwreg.h
+++ b/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cam_cci_hwreg.h
@@ -15,7 +15,7 @@
 
 #define CCI_HW_VERSION_ADDR                                         0x00000000
 #define CCI_RESET_CMD_ADDR                                          0x00000004
-#define CCI_RESET_CMD_RMSK                                          0xcf73f3f7
+#define CCI_RESET_CMD_RMSK                                          0x0f73f3f7
 #define CCI_M0_RESET_RMSK                                                0x3F1
 #define CCI_M1_RESET_RMSK                                              0x3F001
 #define CCI_QUEUE_START_ADDR                                        0x00000008
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 17c5a14..d11798e 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
@@ -628,21 +628,46 @@
 	{"cci_clk", -1},
 };
 
-static int32_t msm_cci_init(struct v4l2_subdev *sd)
+static int32_t msm_cci_init(struct v4l2_subdev *sd,
+	struct msm_camera_cci_ctrl *c_ctrl)
 {
 	int rc = 0;
 	struct cci_device *cci_dev;
+	enum cci_i2c_master_t master;
 	cci_dev = v4l2_get_subdevdata(sd);
-	CDBG("%s line %d\n", __func__, __LINE__);
 
-	if (!cci_dev) {
-		pr_err("%s cci device NULL\n", __func__);
+	if (!cci_dev || !c_ctrl) {
+		pr_err("%s:%d failed: invalid params %p %p\n", __func__,
+			__LINE__, cci_dev, c_ctrl);
 		rc = -ENOMEM;
 		return rc;
 	}
 
 	if (cci_dev->ref_count++) {
 		CDBG("%s ref_count %d\n", __func__, cci_dev->ref_count);
+		master = c_ctrl->cci_info->cci_i2c_master;
+		CDBG("%s:%d master %d\n", __func__, __LINE__, master);
+		if (master < MASTER_MAX) {
+			mutex_lock(&cci_dev->cci_master_info[master].mutex);
+			/* Set reset pending flag to TRUE */
+			cci_dev->cci_master_info[master].reset_pending = TRUE;
+			/* Set proper mask to RESET CMD address */
+			if (master == MASTER_0)
+				msm_camera_io_w(CCI_M0_RESET_RMSK,
+					cci_dev->base + CCI_RESET_CMD_ADDR);
+			else
+				msm_camera_io_w(CCI_M1_RESET_RMSK,
+					cci_dev->base + CCI_RESET_CMD_ADDR);
+			/* wait for reset done irq */
+			rc = wait_for_completion_interruptible_timeout(
+				&cci_dev->cci_master_info[master].
+				reset_complete,
+				CCI_TIMEOUT);
+			if (rc <= 0)
+				pr_err("%s:%d wait failed %d\n", __func__,
+					__LINE__, rc);
+			mutex_unlock(&cci_dev->cci_master_info[master].mutex);
+		}
 		return 0;
 	}
 
@@ -685,6 +710,7 @@
 		cci_dev->base + CCI_IRQ_CLEAR_0_ADDR);
 	msm_camera_io_w(0x1, cci_dev->base + CCI_IRQ_GLOBAL_CLEAR_CMD_ADDR);
 	cci_dev->cci_state = CCI_STATE_ENABLED;
+
 	return 0;
 
 reset_complete_failed:
@@ -695,6 +721,7 @@
 	msm_camera_request_gpio_table(cci_dev->cci_gpio_tbl,
 		cci_dev->cci_gpio_tbl_size, 0);
 request_gpio_failed:
+	cci_dev->ref_count--;
 	return rc;
 }
 
@@ -710,7 +737,7 @@
 	}
 
 	if (--cci_dev->ref_count) {
-		CDBG("%s ref_count %d\n", __func__, cci_dev->ref_count);
+		CDBG("%s ref_count Exit %d\n", __func__, cci_dev->ref_count);
 		return 0;
 	}
 
@@ -723,6 +750,7 @@
 		cci_dev->cci_gpio_tbl_size, 0);
 
 	cci_dev->cci_state = CCI_STATE_DISABLED;
+
 	return 0;
 }
 
@@ -734,7 +762,7 @@
 		cci_ctrl->cmd);
 	switch (cci_ctrl->cmd) {
 	case MSM_CCI_INIT:
-		rc = msm_cci_init(sd);
+		rc = msm_cci_init(sd, cci_ctrl);
 		break;
 	case MSM_CCI_RELEASE:
 		rc = msm_cci_release(sd);
@@ -837,10 +865,7 @@
 		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;
+		return rc;
 	}
 	default:
 		rc = -ENOIOCTLCMD;
diff --git a/drivers/media/platform/msm/camera_v2/sensor/eeprom/msm_eeprom.c b/drivers/media/platform/msm/camera_v2/sensor/eeprom/msm_eeprom.c
index 1407f12..7f13568 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/eeprom/msm_eeprom.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/eeprom/msm_eeprom.c
@@ -229,6 +229,88 @@
 	return rc;
 }
 
+static int msm_eeprom_get_dt_data(struct msm_eeprom_ctrl_t *e_ctrl)
+{
+	int rc = 0, i = 0;
+	struct msm_eeprom_board_info *eb_info;
+	struct msm_camera_power_ctrl_t *power_info =
+		&e_ctrl->eboard_info->power_info;
+	struct device_node *of_node = NULL;
+	struct msm_camera_gpio_conf *gconf = NULL;
+	uint16_t gpio_array_size = 0;
+	uint16_t *gpio_array = NULL;
+
+	eb_info = e_ctrl->eboard_info;
+	if (e_ctrl->eeprom_device_type == MSM_CAMERA_SPI_DEVICE)
+		of_node = e_ctrl->i2c_client.
+			spi_client->spi_master->dev.of_node;
+	else if (e_ctrl->eeprom_device_type == MSM_CAMERA_PLATFORM_DEVICE)
+		of_node = e_ctrl->pdev->dev.of_node;
+	else if (e_ctrl->eeprom_device_type == MSM_CAMERA_I2C_DEVICE)
+		of_node = e_ctrl->i2c_client.client->dev.of_node;
+
+	rc = msm_camera_get_dt_vreg_data(of_node, &power_info->cam_vreg,
+					     &power_info->num_vreg);
+	if (rc < 0)
+		return rc;
+
+	rc = msm_camera_get_dt_power_setting_data(of_node,
+		power_info->cam_vreg, power_info->num_vreg,
+		&power_info->power_setting, &power_info->power_setting_size);
+	if (rc < 0)
+		goto error1;
+
+	power_info->gpio_conf = kzalloc(sizeof(struct msm_camera_gpio_conf),
+					GFP_KERNEL);
+	if (!power_info->gpio_conf) {
+		rc = -ENOMEM;
+		goto error2;
+	}
+	gconf = power_info->gpio_conf;
+	gpio_array_size = of_gpio_count(of_node);
+	CDBG("%s gpio count %d\n", __func__, gpio_array_size);
+
+	if (gpio_array_size) {
+		gpio_array = kzalloc(sizeof(uint16_t) * gpio_array_size,
+			GFP_KERNEL);
+		if (!gpio_array) {
+			pr_err("%s failed %d\n", __func__, __LINE__);
+			goto error3;
+		}
+		for (i = 0; i < gpio_array_size; i++) {
+			gpio_array[i] = of_get_gpio(of_node, i);
+			CDBG("%s gpio_array[%d] = %d\n", __func__, i,
+				gpio_array[i]);
+		}
+
+		rc = msm_camera_get_dt_gpio_req_tbl(of_node, gconf,
+			gpio_array, gpio_array_size);
+		if (rc < 0) {
+			pr_err("%s failed %d\n", __func__, __LINE__);
+			goto error4;
+		}
+
+		rc = msm_camera_init_gpio_pin_tbl(of_node, gconf,
+			gpio_array, gpio_array_size);
+		if (rc < 0) {
+			pr_err("%s failed %d\n", __func__, __LINE__);
+			goto error4;
+		}
+		kfree(gpio_array);
+	}
+
+	return rc;
+error4:
+	kfree(gpio_array);
+error3:
+	kfree(power_info->gpio_conf);
+error2:
+	kfree(power_info->cam_vreg);
+error1:
+	kfree(power_info->power_setting);
+	return rc;
+}
+
 static int msm_eeprom_alloc_memory_map(struct msm_eeprom_ctrl_t *e_ctrl,
 				       struct device_node *of)
 {
@@ -320,10 +402,19 @@
 int32_t msm_eeprom_i2c_probe(struct i2c_client *client,
 	const struct i2c_device_id *id) {
 	int rc = 0;
+	int32_t j = 0;
+	uint32_t temp = 0;
 	struct msm_eeprom_ctrl_t *e_ctrl = NULL;
 	struct msm_camera_power_ctrl_t *power_info = NULL;
+	struct device_node *of_node = client->dev.of_node;
 	CDBG("%s E\n", __func__);
 
+
+	if (!of_node) {
+		pr_err("%s of_node NULL\n", __func__);
+		return -EINVAL;
+	}
+
 	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
 		pr_err("%s i2c_check_functionality failed\n", __func__);
 		goto probe_failure;
@@ -337,13 +428,23 @@
 	e_ctrl->eeprom_v4l2_subdev_ops = &msm_eeprom_subdev_ops;
 	e_ctrl->eeprom_mutex = &msm_eeprom_mutex;
 	CDBG("%s client = %x\n", __func__, (unsigned int)client);
-	e_ctrl->eboard_info = (struct msm_eeprom_board_info *)(id->driver_data);
+	e_ctrl->eboard_info = kzalloc(sizeof(
+		struct msm_eeprom_board_info), GFP_KERNEL);
 	if (!e_ctrl->eboard_info) {
 		pr_err("%s:%d board info NULL\n", __func__, __LINE__);
 		return -EINVAL;
 	}
+
+	rc = of_property_read_u32(of_node, "qcom,slave-addr", &temp);
+	if (rc < 0) {
+		pr_err("%s failed rc %d\n", __func__, rc);
+		return rc;
+	}
+
 	power_info = &e_ctrl->eboard_info->power_info;
+	e_ctrl->eboard_info->i2c_slaveaddr = temp;
 	e_ctrl->i2c_client.client = client;
+	e_ctrl->is_supported = 0;
 
 	/* Set device type as I2C */
 	e_ctrl->eeprom_device_type = MSM_CAMERA_I2C_DEVICE;
@@ -356,6 +457,45 @@
 	power_info->clk_info_size = ARRAY_SIZE(cam_8960_clk_info);
 	power_info->dev = &client->dev;
 
+	rc = of_property_read_string(of_node, "qcom,eeprom-name",
+		&e_ctrl->eboard_info->eeprom_name);
+	CDBG("%s qcom,eeprom-name %s, rc %d\n", __func__,
+		e_ctrl->eboard_info->eeprom_name, rc);
+	if (rc < 0) {
+		pr_err("%s failed %d\n", __func__, __LINE__);
+		goto board_free;
+	}
+
+	rc = msm_eeprom_get_dt_data(e_ctrl);
+	if (rc)
+		goto board_free;
+
+	rc = msm_eeprom_alloc_memory_map(e_ctrl, of_node);
+	if (rc)
+		goto board_free;
+
+	rc = msm_camera_power_up(power_info, e_ctrl->eeprom_device_type,
+		&e_ctrl->i2c_client);
+	if (rc) {
+		pr_err("%s failed power up %d\n", __func__, __LINE__);
+		goto memdata_free;
+	}
+	rc = read_eeprom_memory(e_ctrl);
+	if (rc < 0) {
+		pr_err("%s read_eeprom_memory failed\n", __func__);
+		goto power_down;
+	}
+
+	for (j = 0; j < e_ctrl->num_bytes; j++)
+		CDBG("memory_data[%d] = 0x%X\n", j, e_ctrl->memory_data[j]);
+
+	rc = msm_camera_power_down(power_info, e_ctrl->eeprom_device_type,
+		&e_ctrl->i2c_client);
+	if (rc) {
+		pr_err("failed rc %d\n", rc);
+		goto power_down;
+	}
+
 	/*IMPLEMENT READING PART*/
 	/* Initialize sub device */
 	v4l2_i2c_subdev_init(&e_ctrl->msm_sd.sd,
@@ -368,9 +508,18 @@
 	e_ctrl->msm_sd.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV;
 	e_ctrl->msm_sd.sd.entity.group_id = MSM_CAMERA_SUBDEV_EEPROM;
 	msm_sd_register(&e_ctrl->msm_sd);
+	e_ctrl->is_supported = 1;
 	CDBG("%s success result=%d X\n", __func__, rc);
 	return rc;
 
+power_down:
+	msm_camera_power_down(power_info, e_ctrl->eeprom_device_type,
+		&e_ctrl->i2c_client);
+memdata_free:
+	kfree(e_ctrl->memory_data);
+	kfree(e_ctrl->eboard_info->eeprom_map);
+board_free:
+	kfree(e_ctrl->eboard_info);
 probe_failure:
 	pr_err("%s failed! rc = %d\n", __func__, rc);
 	return rc;
@@ -454,86 +603,6 @@
 	return 0;
 }
 
-static int msm_eeprom_get_dt_data(struct msm_eeprom_ctrl_t *e_ctrl)
-{
-	int rc = 0, i = 0;
-	struct msm_eeprom_board_info *eb_info;
-	struct msm_camera_power_ctrl_t *power_info =
-		&e_ctrl->eboard_info->power_info;
-	struct device_node *of_node = NULL;
-	struct msm_camera_gpio_conf *gconf = NULL;
-	uint16_t gpio_array_size = 0;
-	uint16_t *gpio_array = NULL;
-
-	eb_info = e_ctrl->eboard_info;
-	if (e_ctrl->eeprom_device_type == MSM_CAMERA_SPI_DEVICE)
-		of_node = e_ctrl->i2c_client.
-			spi_client->spi_master->dev.of_node;
-	else if (e_ctrl->eeprom_device_type == MSM_CAMERA_PLATFORM_DEVICE)
-		of_node = e_ctrl->pdev->dev.of_node;
-
-	rc = msm_camera_get_dt_vreg_data(of_node, &power_info->cam_vreg,
-					     &power_info->num_vreg);
-	if (rc < 0)
-		return rc;
-
-	rc = msm_camera_get_dt_power_setting_data(of_node,
-		power_info->cam_vreg, power_info->num_vreg,
-		&power_info->power_setting, &power_info->power_setting_size);
-	if (rc < 0)
-		goto ERROR1;
-
-	power_info->gpio_conf = kzalloc(sizeof(struct msm_camera_gpio_conf),
-					GFP_KERNEL);
-	if (!power_info->gpio_conf) {
-		rc = -ENOMEM;
-		goto ERROR2;
-	}
-	gconf = power_info->gpio_conf;
-	gpio_array_size = of_gpio_count(of_node);
-	CDBG("%s gpio count %d\n", __func__, gpio_array_size);
-
-	if (gpio_array_size) {
-		gpio_array = kzalloc(sizeof(uint16_t) * gpio_array_size,
-			GFP_KERNEL);
-		if (!gpio_array) {
-			pr_err("%s failed %d\n", __func__, __LINE__);
-			goto ERROR3;
-		}
-		for (i = 0; i < gpio_array_size; i++) {
-			gpio_array[i] = of_get_gpio(of_node, i);
-			CDBG("%s gpio_array[%d] = %d\n", __func__, i,
-				gpio_array[i]);
-		}
-
-		rc = msm_camera_get_dt_gpio_req_tbl(of_node, gconf,
-			gpio_array, gpio_array_size);
-		if (rc < 0) {
-			pr_err("%s failed %d\n", __func__, __LINE__);
-			goto ERROR4;
-		}
-
-		rc = msm_camera_init_gpio_pin_tbl(of_node, gconf,
-			gpio_array, gpio_array_size);
-		if (rc < 0) {
-			pr_err("%s failed %d\n", __func__, __LINE__);
-			goto ERROR4;
-		}
-		kfree(gpio_array);
-	}
-
-	return rc;
-ERROR4:
-	kfree(gpio_array);
-ERROR3:
-	kfree(power_info->gpio_conf);
-ERROR2:
-	kfree(power_info->cam_vreg);
-ERROR1:
-	kfree(power_info->power_setting);
-	return rc;
-}
-
 static int msm_eeprom_spi_setup(struct spi_device *spi)
 {
 	struct msm_eeprom_ctrl_t *e_ctrl = NULL;
diff --git a/drivers/media/platform/msm/camera_v2/sensor/flash/Makefile b/drivers/media/platform/msm/camera_v2/sensor/flash/Makefile
index 62102cb..9fc3817 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/flash/Makefile
+++ b/drivers/media/platform/msm/camera_v2/sensor/flash/Makefile
@@ -4,3 +4,4 @@
 obj-$(CONFIG_MSMB_CAMERA) += msm_led_trigger.o
 obj-$(CONFIG_MSMB_CAMERA) += msm_led_i2c_trigger.o
 obj-$(CONFIG_MSMB_CAMERA) += adp1660.o
+obj-$(CONFIG_MSMB_CAMERA) += msm_led_torch.o
diff --git a/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_i2c_trigger.c b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_i2c_trigger.c
index b5afa86..9caa270 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_i2c_trigger.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_i2c_trigger.c
@@ -19,6 +19,7 @@
 #include "msm_camera_io_util.h"
 #include "../msm_sensor.h"
 #include "msm_led_flash.h"
+#include <linux/debugfs.h>
 
 #define FLASH_NAME "camera-led-flash"
 
@@ -485,12 +486,44 @@
 		msm_camera_qup_i2c_write_table_w_microdelay,
 };
 
+#ifdef CONFIG_DEBUG_FS
+static int set_led_status(void *data, u64 val)
+{
+	struct msm_led_flash_ctrl_t *fctrl =
+		 (struct msm_led_flash_ctrl_t *)data;
+	int rc = -1;
+	pr_debug("set_led_status: Enter val: %llu", val);
+	if (!fctrl) {
+		pr_err("set_led_status: fctrl is NULL");
+		return rc;
+	}
+	if (!fctrl->func_tbl) {
+		pr_err("set_led_status: fctrl->func_tbl is NULL");
+		return rc;
+	}
+	if (val == 0) {
+		pr_debug("set_led_status: val is disable");
+		rc = msm_flash_led_off(fctrl);
+	} else {
+		pr_debug("set_led_status: val is enable");
+		rc = msm_flash_led_low(fctrl);
+	}
+
+	return rc;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(ledflashdbg_fops,
+	NULL, set_led_status, "%llu\n");
+#endif
+
 int msm_flash_i2c_probe(struct i2c_client *client,
 		const struct i2c_device_id *id)
 {
 	int rc = 0;
 	struct msm_led_flash_ctrl_t *fctrl = NULL;
-
+#ifdef CONFIG_DEBUG_FS
+	struct dentry *dentry;
+#endif
 	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
 		pr_err("i2c_check_functionality failed\n");
 		goto probe_failure;
@@ -529,6 +562,12 @@
 			&msm_sensor_qup_func_tbl;
 
 	rc = msm_led_i2c_flash_create_v4lsubdev(fctrl);
+#ifdef CONFIG_DEBUG_FS
+	dentry = debugfs_create_file("ledflash", S_IRUGO, NULL, (void *)fctrl,
+		&ledflashdbg_fops);
+	if (!dentry)
+		pr_err("Failed to create the debugfs ledflash file");
+#endif
 	CDBG("%s:%d probe success\n", __func__, __LINE__);
 	return 0;
 
diff --git a/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_torch.c b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_torch.c
new file mode 100644
index 0000000..ff63696
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_torch.c
@@ -0,0 +1,60 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#define pr_fmt(fmt) "%s:%d " fmt, __func__, __LINE__
+
+#include <linux/module.h>
+#include "msm_led_flash.h"
+
+static struct led_trigger *torch_trigger;
+
+static void msm_led_torch_brightness_set(struct led_classdev *led_cdev,
+				enum led_brightness value)
+{
+	if (!torch_trigger) {
+		pr_err("No torch trigger found, can't set brightness\n");
+		return;
+	}
+
+	led_trigger_event(torch_trigger, value);
+};
+
+static struct led_classdev msm_torch_led = {
+	.name			= "torch-light",
+	.brightness_set	= msm_led_torch_brightness_set,
+	.brightness		= LED_OFF,
+};
+
+int32_t msm_led_torch_create_classdev(struct platform_device *pdev,
+				void *data)
+{
+	int rc;
+	struct msm_led_flash_ctrl_t *fctrl =
+		(struct msm_led_flash_ctrl_t *)data;
+
+	if (!fctrl || !fctrl->torch_trigger) {
+		pr_err("Invalid fctrl or torch trigger\n");
+		return -EINVAL;
+	}
+
+	torch_trigger = fctrl->torch_trigger;
+	msm_led_torch_brightness_set(&msm_torch_led, LED_OFF);
+
+	rc = led_classdev_register(&pdev->dev, &msm_torch_led);
+	if (rc) {
+		pr_err("Failed to register led dev. rc = %d\n", rc);
+		return rc;
+	}
+
+	return 0;
+};
diff --git a/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_trigger.c b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_trigger.c
index 1b0ec44..20905c9 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_trigger.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_trigger.c
@@ -26,6 +26,9 @@
 #define CDBG(fmt, args...) do { } while (0)
 #endif
 
+extern int32_t msm_led_torch_create_classdev(
+				struct platform_device *pdev, void *data);
+
 static struct msm_led_flash_ctrl_t fctrl;
 
 static int32_t msm_led_trigger_get_subdev_id(struct msm_led_flash_ctrl_t *fctrl,
@@ -209,7 +212,11 @@
 			of_node_put(flash_src_node);
 		}
 	}
+
 	rc = msm_led_flash_create_v4lsubdev(pdev, &fctrl);
+	if (!rc)
+		msm_led_torch_create_classdev(pdev, &fctrl);
+
 	return rc;
 }
 
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 ddc168a..0083378 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.c
@@ -1272,9 +1272,10 @@
 	case VIDIOC_MSM_SENSOR_GET_AF_STATUS:
 		return msm_sensor_get_af_status(s_ctrl, argp);
 	case VIDIOC_MSM_SENSOR_RELEASE:
-	case MSM_SD_SHUTDOWN:
 		msm_sensor_stop_stream(s_ctrl);
 		return 0;
+	case MSM_SD_SHUTDOWN:
+		return 0;
 	default:
 		return -ENOIOCTLCMD;
 	}
diff --git a/drivers/media/platform/msm/camera_v2/sensor/ov5648.c b/drivers/media/platform/msm/camera_v2/sensor/ov5648.c
index 417c7ab..9922468 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/ov5648.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/ov5648.c
@@ -126,7 +126,7 @@
 
 static const struct of_device_id ov5648_dt_match[] = {
 	{
-		.compatible = "qcom,ov5648",
+		.compatible = "ovti,ov5648",
 		.data = &ov5648_s_ctrl
 	},
 	{}
@@ -136,7 +136,7 @@
 
 static struct platform_driver ov5648_platform_driver = {
 	.driver = {
-		.name = "qcom,ov5648",
+		.name = "ovti,ov5648",
 		.owner = THIS_MODULE,
 		.of_match_table = ov5648_dt_match,
 	},
diff --git a/drivers/media/platform/msm/camera_v2/sensor/ov8865.c b/drivers/media/platform/msm/camera_v2/sensor/ov8865.c
new file mode 100644
index 0000000..6d788f5
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/sensor/ov8865.c
@@ -0,0 +1,185 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#include "msm_sensor.h"
+#define OV8865_SENSOR_NAME "ov8865"
+DEFINE_MSM_MUTEX(ov8865_mut);
+
+static struct msm_sensor_ctrl_t ov8865_s_ctrl;
+
+static struct msm_sensor_power_setting ov8865_power_setting[] = {
+	{
+		.seq_type = SENSOR_VREG,
+		.seq_val = CAM_VIO,
+		.config_val = 0,
+		.delay = 1,
+	},
+	{
+		.seq_type = SENSOR_VREG,
+		.seq_val = CAM_VANA,
+		.config_val = 0,
+		.delay = 1,
+	},
+	{
+		.seq_type = SENSOR_VREG,
+		.seq_val = CAM_VDIG,
+		.config_val = 0,
+		.delay = 1,
+	},
+	{
+		.seq_type = SENSOR_VREG,
+		.seq_val = CAM_VAF,
+		.config_val = 0,
+		.delay = 5,
+	},
+	{
+		.seq_type = SENSOR_GPIO,
+		.seq_val = SENSOR_GPIO_STANDBY,
+		.config_val = GPIO_OUT_LOW,
+		.delay = 1,
+	},
+	{
+		.seq_type = SENSOR_GPIO,
+		.seq_val = SENSOR_GPIO_RESET,
+		.config_val = GPIO_OUT_LOW,
+		.delay = 5,
+	},
+	{
+		.seq_type = SENSOR_GPIO,
+		.seq_val = SENSOR_GPIO_AF_PWDM,
+		.config_val = GPIO_OUT_LOW,
+		.delay = 5,
+	},
+	{
+		.seq_type = SENSOR_GPIO,
+		.seq_val = SENSOR_GPIO_STANDBY,
+		.config_val = GPIO_OUT_HIGH,
+		.delay = 5,
+	},
+	{
+		.seq_type = SENSOR_GPIO,
+		.seq_val = SENSOR_GPIO_RESET,
+		.config_val = GPIO_OUT_HIGH,
+		.delay = 10,
+	},
+	{
+		.seq_type = SENSOR_GPIO,
+		.seq_val = SENSOR_GPIO_AF_PWDM,
+		.config_val = GPIO_OUT_HIGH,
+		.delay = 5,
+	},
+	{
+		.seq_type = SENSOR_CLK,
+		.seq_val = SENSOR_CAM_MCLK,
+		.config_val = 24000000,
+		.delay = 10,
+	},
+	{
+		.seq_type = SENSOR_I2C_MUX,
+		.seq_val = 0,
+		.config_val = 0,
+		.delay = 0,
+	},
+};
+
+static struct v4l2_subdev_info ov8865_subdev_info[] = {
+	{
+		.code   = V4L2_MBUS_FMT_SBGGR10_1X10,
+		.colorspace = V4L2_COLORSPACE_JPEG,
+		.fmt    = 1,
+		.order    = 0,
+	},
+};
+
+static const struct i2c_device_id ov8865_i2c_id[] = {
+	{OV8865_SENSOR_NAME, (kernel_ulong_t)&ov8865_s_ctrl},
+	{ }
+};
+
+static int32_t msm_ov8865_i2c_probe(struct i2c_client *client,
+	const struct i2c_device_id *id)
+{
+	return msm_sensor_i2c_probe(client, id, &ov8865_s_ctrl);
+}
+
+static struct i2c_driver ov8865_i2c_driver = {
+	.id_table = ov8865_i2c_id,
+	.probe  = msm_ov8865_i2c_probe,
+	.driver = {
+		.name = OV8865_SENSOR_NAME,
+	},
+};
+
+static struct msm_camera_i2c_client ov8865_sensor_i2c_client = {
+	.addr_type = MSM_CAMERA_I2C_WORD_ADDR,
+};
+
+static const struct of_device_id ov8865_dt_match[] = {
+	{.compatible = "ovti,ov8865", .data = &ov8865_s_ctrl},
+	{}
+};
+
+MODULE_DEVICE_TABLE(of, ov8865_dt_match);
+
+static struct platform_driver ov8865_platform_driver = {
+	.driver = {
+		.name = "ovti,ov8865",
+		.owner = THIS_MODULE,
+		.of_match_table = ov8865_dt_match,
+	},
+};
+
+static int32_t ov8865_platform_probe(struct platform_device *pdev)
+{
+	int32_t rc = 0;
+	const struct of_device_id *match;
+	match = of_match_device(ov8865_dt_match, &pdev->dev);
+	rc = msm_sensor_platform_probe(pdev, match->data);
+	return rc;
+}
+
+static int __init ov8865_init_module(void)
+{
+	int32_t rc = 0;
+	pr_info("%s:%d\n", __func__, __LINE__);
+	rc = platform_driver_probe(&ov8865_platform_driver,
+		ov8865_platform_probe);
+	if (!rc)
+		return rc;
+	pr_err("%s:%d rc %d\n", __func__, __LINE__, rc);
+	return i2c_add_driver(&ov8865_i2c_driver);
+}
+
+static void __exit ov8865_exit_module(void)
+{
+	pr_info("%s:%d\n", __func__, __LINE__);
+	if (ov8865_s_ctrl.pdev) {
+		msm_sensor_free_sensor_data(&ov8865_s_ctrl);
+		platform_driver_unregister(&ov8865_platform_driver);
+	} else
+		i2c_del_driver(&ov8865_i2c_driver);
+	return;
+}
+
+static struct msm_sensor_ctrl_t ov8865_s_ctrl = {
+	.sensor_i2c_client = &ov8865_sensor_i2c_client,
+	.power_setting_array.power_setting = ov8865_power_setting,
+	.power_setting_array.size = ARRAY_SIZE(ov8865_power_setting),
+	.msm_sensor_mutex = &ov8865_mut,
+	.sensor_v4l2_subdev_info = ov8865_subdev_info,
+	.sensor_v4l2_subdev_info_size = ARRAY_SIZE(ov8865_subdev_info),
+};
+
+module_init(ov8865_init_module);
+module_exit(ov8865_exit_module);
+MODULE_DESCRIPTION("ov8865");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c b/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c
index e335ff0..afd7200 100644
--- a/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c
+++ b/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c
@@ -514,6 +514,19 @@
 		b->m.planes[i].m.userptr = binfo->device_addr[i];
 		dprintk(VIDC_DBG, "Queueing device address = 0x%x\n",
 				binfo->device_addr[i]);
+
+		if ((vidc_inst->fmts[OUTPUT_PORT]->fourcc ==
+			V4L2_PIX_FMT_HEVC_HYBRID) &&  binfo->handle[i] &&
+			(b->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)) {
+			rc = msm_smem_cache_operations(v4l2_inst->mem_client,
+				binfo->handle[i], SMEM_CACHE_INVALIDATE);
+			if (rc) {
+				dprintk(VIDC_ERR,
+					"Failed to INV caches: %d\n", rc);
+					goto err_invalid_buff;
+			}
+		}
+
 		if (binfo->handle[i] &&
 			(b->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)) {
 			rc = msm_smem_cache_operations(v4l2_inst->mem_client,
diff --git a/drivers/media/platform/msm/vidc/msm_vdec.c b/drivers/media/platform/msm/vidc/msm_vdec.c
index 73ff9fa..a3d88c5 100644
--- a/drivers/media/platform/msm/vidc/msm_vdec.c
+++ b/drivers/media/platform/msm/vidc/msm_vdec.c
@@ -363,6 +363,14 @@
 		.type = OUTPUT_PORT,
 	},
 	{
+		.name = "HEVC_HYBRID",
+		.description = "HEVC compressed format",
+		.fourcc = V4L2_PIX_FMT_HEVC_HYBRID,
+		.num_planes = 1,
+		.get_frame_size = get_frame_size_compressed,
+		.type = OUTPUT_PORT,
+	},
+	{
 		.name = "VP8",
 		.description = "VP8 compressed format",
 		.fourcc = V4L2_PIX_FMT_VP8,
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c
index 122f0e9..fdc851c 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c
@@ -1337,7 +1337,9 @@
 	case V4L2_PIX_FMT_HEVC:
 		codec = HAL_VIDEO_CODEC_HEVC;
 		break;
-
+	case V4L2_PIX_FMT_HEVC_HYBRID:
+		codec = HAL_VIDEO_CODEC_HEVC_HYBRID;
+		break;
 	default:
 		dprintk(VIDC_ERR, "Wrong codec: %d\n", fourcc);
 		codec = HAL_UNUSED_CODEC;
diff --git a/drivers/media/platform/msm/vidc/venus_hfi.c b/drivers/media/platform/msm/vidc/venus_hfi.c
index aaf1f50..a5aebd5 100644
--- a/drivers/media/platform/msm/vidc/venus_hfi.c
+++ b/drivers/media/platform/msm/vidc/venus_hfi.c
@@ -2691,6 +2691,7 @@
 		dprintk(VIDC_ERR, "Invalid params: %p\n", device);
 		return;
 	}
+	mutex_lock(&device->clk_pwr_lock);
 	if (device->clocks_enabled) {
 		for (i = VCODEC_CLK; i < VCODEC_MAX_CLKS; i++) {
 			cl = &device->resources.clock[i];
@@ -2710,6 +2711,7 @@
 		clk_unprepare(cl->clk);
 	}
 	device->clocks_enabled = 0;
+	mutex_unlock(&device->clk_pwr_lock);
 }
 static inline int venus_hfi_enable_clks(struct venus_hfi_device *device)
 {
@@ -2720,7 +2722,7 @@
 		dprintk(VIDC_ERR, "Invalid params: %p\n", device);
 		return -EINVAL;
 	}
-
+	mutex_lock(&device->clk_pwr_lock);
 	for (i = VCODEC_CLK; i < VCODEC_MAX_CLKS; i++) {
 		if (i == VCODEC_OCMEM_CLK && !device->res->has_ocmem)
 			continue;
@@ -2734,12 +2736,14 @@
 		}
 	}
 	device->clocks_enabled = 1;
+	mutex_unlock(&device->clk_pwr_lock);
 	return rc;
 fail_clk_enable:
 	for (; i >= 0; i--) {
 		cl = &device->resources.clock[i];
 		clk_disable_unprepare(cl->clk);
 	}
+	mutex_unlock(&device->clk_pwr_lock);
 	return rc;
 }
 static int venus_hfi_register_iommu_domains(struct venus_hfi_device *device,
@@ -3184,10 +3188,12 @@
 		goto fail_iommu_attach;
 	}
 
+	mutex_lock(&device->clk_pwr_lock);
 	if (!device->resources.fw.cookie) {
 		rc = regulator_enable(device->gdsc);
 		if (rc) {
 			dprintk(VIDC_ERR, "Failed to enable GDSC %d", rc);
+			mutex_unlock(&device->clk_pwr_lock);
 			goto fail_enable_gdsc;
 		}
 		device->resources.fw.cookie = subsystem_get("venus");
@@ -3196,9 +3202,11 @@
 	if (IS_ERR_OR_NULL(device->resources.fw.cookie)) {
 		dprintk(VIDC_ERR, "Failed to download firmware\n");
 		rc = -ENOMEM;
+		mutex_unlock(&device->clk_pwr_lock);
 		goto fail_load_fw;
 	}
 	device->power_enabled = 1;
+	mutex_unlock(&device->clk_pwr_lock);
 	/*Clocks can be enabled only after pil_get since
 	 * gdsc is turned-on in pil_get*/
 	rc = venus_hfi_enable_clks(device);
@@ -3219,8 +3227,11 @@
 fail_enable_clks:
 	subsystem_put(device->resources.fw.cookie);
 fail_load_fw:
+	mutex_lock(&device->clk_pwr_lock);
 	device->resources.fw.cookie = NULL;
 	regulator_disable(device->gdsc);
+	device->power_enabled = 0;
+	mutex_unlock(&device->clk_pwr_lock);
 fail_enable_gdsc:
 	venus_hfi_iommu_detach(device);
 fail_iommu_attach:
@@ -3239,8 +3250,11 @@
 		flush_workqueue(device->vidc_workq);
 		flush_workqueue(device->venus_pm_workq);
 		venus_hfi_disable_clks(device);
+		mutex_lock(&device->clk_pwr_lock);
 		subsystem_put(device->resources.fw.cookie);
 		regulator_disable(device->gdsc);
+		device->power_enabled = 0;
+		mutex_unlock(&device->clk_pwr_lock);
 		venus_hfi_interface_queues_release(dev);
 		venus_hfi_iommu_detach(device);
 		device->resources.fw.cookie = NULL;
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_api.h b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
index 890a5be..b600d64 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi_api.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
@@ -202,6 +202,7 @@
 	HAL_VIDEO_CODEC_VP7      = 0x00000800,
 	HAL_VIDEO_CODEC_VP8      = 0x00001000,
 	HAL_VIDEO_CODEC_HEVC     = 0x00002000,
+	HAL_VIDEO_CODEC_HEVC_HYBRID     = 0x00004000,
 	HAL_UNUSED_CODEC = 0x10000000,
 };
 
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_helper.h b/drivers/media/platform/msm/vidc/vidc_hfi_helper.h
index de312f4..b5c431e 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi_helper.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi_helper.h
@@ -80,6 +80,7 @@
 #define HFI_VIDEO_CODEC_SPARK				0x00000200
 #define HFI_VIDEO_CODEC_VP8				0x00001000
 #define HFI_VIDEO_CODEC_HEVC				0x00002000
+#define HFI_VIDEO_CODEC_HEVC_HYBRID			0x00004000
 
 #define HFI_H264_PROFILE_BASELINE			0x00000001
 #define HFI_H264_PROFILE_MAIN				0x00000002
diff --git a/drivers/media/radio/radio-iris.c b/drivers/media/radio/radio-iris.c
index a4cf18e..5e056be 100644
--- a/drivers/media/radio/radio-iris.c
+++ b/drivers/media/radio/radio-iris.c
@@ -4122,6 +4122,7 @@
 	radio = video_get_drvdata(video_devdata(file));
 	strlcpy(capability->driver, DRIVER_NAME, sizeof(capability->driver));
 	strlcpy(capability->card, DRIVER_CARD, sizeof(capability->card));
+	capability->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
 	radio->g_cap = capability;
 	return 0;
 }
diff --git a/drivers/misc/isa1200.c b/drivers/misc/isa1200.c
index c6d08d1..8090b95 100644
--- a/drivers/misc/isa1200.c
+++ b/drivers/misc/isa1200.c
@@ -44,6 +44,7 @@
 	struct timed_output_dev dev;
 	struct work_struct work;
 	struct mutex lock;
+	struct mutex lock_clk;
 	unsigned int enable;
 	unsigned int period_ns;
 	bool is_len_gpio_valid;
@@ -120,16 +121,19 @@
 				}
 			}
 
+			mutex_lock(&haptic->lock_clk);
 			/* vote for clock */
 			if (haptic->pdata->need_pwm_clk && !haptic->clk_on) {
 				rc = clk_prepare_enable(haptic->pwm_clk);
 				if (rc < 0) {
 					pr_err("%s: clk enable failed\n",
 								__func__);
+					mutex_unlock(&haptic->lock_clk);
 					goto dis_clk_cb;
 				}
 				haptic->clk_on = true;
 			}
+			mutex_unlock(&haptic->lock_clk);
 
 			rc = isa1200_write_reg(haptic->client,
 						ISA1200_HCTRL5,
@@ -162,11 +166,13 @@
 			if (rc < 0)
 				pr_err("%s: stop vibartion fail\n", __func__);
 
+			mutex_lock(&haptic->lock_clk);
 			/* de-vote clock */
 			if (haptic->pdata->need_pwm_clk && haptic->clk_on) {
 				clk_disable_unprepare(haptic->pwm_clk);
 				haptic->clk_on = false;
 			}
+			mutex_unlock(&haptic->lock_clk);
 			/* check for board specific clk callback */
 			if (haptic->pdata->clk_enable) {
 				rc = haptic->pdata->clk_enable(false);
@@ -180,10 +186,12 @@
 	return;
 
 dis_clk:
+	mutex_lock(&haptic->lock_clk);
 	if (haptic->pdata->need_pwm_clk && haptic->clk_on) {
 		clk_disable_unprepare(haptic->pwm_clk);
 		haptic->clk_on = false;
 	}
+	mutex_unlock(&haptic->lock_clk);
 
 dis_clk_cb:
 	if (haptic->pdata->clk_enable) {
@@ -649,6 +657,7 @@
 	}
 
 	mutex_init(&haptic->lock);
+	mutex_init(&haptic->lock_clk);
 	INIT_WORK(&haptic->work, isa1200_chip_work);
 	haptic->clk_on = false;
 
@@ -787,6 +796,7 @@
 
 	/* destroy mutex */
 	mutex_destroy(&haptic->lock);
+	mutex_destroy(&haptic->lock_clk);
 
 	/* power-off the chip */
 	if (haptic->pdata->regulator_info) {
diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
index a4498d2..3648d88 100644
--- a/drivers/mmc/core/sd.c
+++ b/drivers/mmc/core/sd.c
@@ -26,6 +26,12 @@
 #include "sd.h"
 #include "sd_ops.h"
 
+#define UHS_SDR104_MIN_DTR	(100 * 1000 * 1000)
+#define UHS_DDR50_MIN_DTR	(50 * 1000 * 1000)
+#define UHS_SDR50_MIN_DTR	(50 * 1000 * 1000)
+#define UHS_SDR25_MIN_DTR	(25 * 1000 * 1000)
+#define UHS_SDR12_MIN_DTR	(12.5 * 1000 * 1000)
+
 static const unsigned int tran_exp[] = {
 	10000,		100000,		1000000,	10000000,
 	0,		0,		0,		0
@@ -486,18 +492,22 @@
 	}
 
 	if ((card->host->caps & MMC_CAP_UHS_SDR104) &&
-	    (card->sw_caps.sd3_bus_mode & SD_MODE_UHS_SDR104)) {
+	    (card->sw_caps.sd3_bus_mode & SD_MODE_UHS_SDR104) &&
+	    (card->host->f_max > UHS_SDR104_MIN_DTR)) {
 			card->sd_bus_speed = UHS_SDR104_BUS_SPEED;
 	} else if ((card->host->caps & MMC_CAP_UHS_DDR50) &&
-		   (card->sw_caps.sd3_bus_mode & SD_MODE_UHS_DDR50)) {
+		   (card->sw_caps.sd3_bus_mode & SD_MODE_UHS_DDR50) &&
+		    (card->host->f_max > UHS_DDR50_MIN_DTR)) {
 			card->sd_bus_speed = UHS_DDR50_BUS_SPEED;
 	} else if ((card->host->caps & (MMC_CAP_UHS_SDR104 |
 		    MMC_CAP_UHS_SDR50)) && (card->sw_caps.sd3_bus_mode &
-		    SD_MODE_UHS_SDR50)) {
+		    SD_MODE_UHS_SDR50) &&
+		    (card->host->f_max > UHS_SDR50_MIN_DTR)) {
 			card->sd_bus_speed = UHS_SDR50_BUS_SPEED;
 	} else if ((card->host->caps & (MMC_CAP_UHS_SDR104 |
 		    MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR25)) &&
-		   (card->sw_caps.sd3_bus_mode & SD_MODE_UHS_SDR25)) {
+		   (card->sw_caps.sd3_bus_mode & SD_MODE_UHS_SDR25) &&
+		 (card->host->f_max > UHS_SDR25_MIN_DTR)) {
 			card->sd_bus_speed = UHS_SDR25_BUS_SPEED;
 	} else if ((card->host->caps & (MMC_CAP_UHS_SDR104 |
 		    MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR25 |
diff --git a/drivers/net/ethernet/msm/msm_rmnet_bam.c b/drivers/net/ethernet/msm/msm_rmnet_bam.c
index 44f86dd..9f06258 100644
--- a/drivers/net/ethernet/msm/msm_rmnet_bam.c
+++ b/drivers/net/ethernet/msm/msm_rmnet_bam.c
@@ -42,6 +42,11 @@
 module_param_named(debug_enable, msm_rmnet_bam_debug_mask,
 			int, S_IRUGO | S_IWUSR | S_IWGRP);
 
+static unsigned long int msm_rmnet_bam_headroom_check_failure;
+module_param(msm_rmnet_bam_headroom_check_failure, ulong, S_IRUGO);
+MODULE_PARM_DESC(msm_rmnet_bam_headroom_check_failure,
+		 "Number of packets with insufficient headroom");
+
 #define DEBUG_MASK_LVL0 (1U << 0)
 #define DEBUG_MASK_LVL1 (1U << 1)
 #define DEBUG_MASK_LVL2 (1U << 2)
@@ -287,6 +292,23 @@
 			((struct net_device *)dev)->name, __func__);
 }
 
+static struct sk_buff *_rmnet_add_headroom(struct sk_buff **skb,
+					   struct net_device *dev)
+{
+	struct sk_buff *skbn;
+
+	if (skb_headroom(*skb) < dev->needed_headroom) {
+		msm_rmnet_bam_headroom_check_failure++;
+		skbn = skb_realloc_headroom(*skb, dev->needed_headroom);
+		kfree_skb(*skb);
+		*skb = skbn;
+	} else {
+		skbn = *skb;
+	}
+
+	return skbn;
+}
+
 static int _rmnet_xmit(struct sk_buff *skb, struct net_device *dev)
 {
 	struct rmnet_private *p = netdev_priv(dev);
@@ -295,6 +317,10 @@
 	u32 opmode;
 	unsigned long flags;
 
+	if (unlikely(!_rmnet_add_headroom(&skb, dev))) {
+		dev->stats.tx_dropped++;
+		return NETDEV_TX_OK;
+	}
 	/* For QoS mode, prepend QMI header and assign flow ID from skb->mark */
 	spin_lock_irqsave(&p->lock, flags);
 	opmode = p->operation_mode;
diff --git a/drivers/net/wireless/wcnss/wcnss_wlan.c b/drivers/net/wireless/wcnss/wcnss_wlan.c
index aa29748..d35bdaa 100644
--- a/drivers/net/wireless/wcnss/wcnss_wlan.c
+++ b/drivers/net/wireless/wcnss/wcnss_wlan.c
@@ -34,6 +34,7 @@
 #include <linux/suspend.h>
 #include <linux/rwsem.h>
 #include <linux/mfd/pm8xxx/misc.h>
+#include <linux/qpnp/qpnp-adc.h>
 
 #include <mach/msm_smd.h>
 #include <mach/msm_iomap.h>
@@ -131,6 +132,10 @@
 #define MSM_PRONTO_BRDG_ERR_SRC         0xfb080fb0
 
 #define WCNSS_DEF_WLAN_RX_BUFF_COUNT		1024
+#define WCNSS_VBATT_THRESHOLD		3500000
+#define WCNSS_VBATT_GUARD		200
+#define WCNSS_VBATT_HIGH		3700000
+#define WCNSS_VBATT_LOW			3300000
 
 #define WCNSS_CTRL_CHANNEL			"WCNSS_CTRL"
 #define WCNSS_MAX_FRAME_SIZE		(4*1024)
@@ -146,6 +151,7 @@
 #define	WCNSS_CALDATA_UPLD_RSP        (WCNSS_CTRL_MSG_START + 5)
 #define	WCNSS_CALDATA_DNLD_REQ        (WCNSS_CTRL_MSG_START + 6)
 #define	WCNSS_CALDATA_DNLD_RSP        (WCNSS_CTRL_MSG_START + 7)
+#define	WCNSS_VBATT_LEVEL_IND         (WCNSS_CTRL_MSG_START + 8)
 
 
 #define VALID_VERSION(version) \
@@ -277,6 +283,16 @@
 	struct cal_data_params cal_params;
 };
 
+struct vbatt_level {
+	u32 curr_volt;
+	u32 threshold;
+};
+
+struct vbatt_message {
+	struct smd_msg_hdr hdr;
+	struct vbatt_level vbatt;
+};
+
 static struct {
 	struct platform_device *pdev;
 	void		*pil;
@@ -298,6 +314,7 @@
 	void		(*tm_notify)(struct device *, int);
 	struct wcnss_wlan_config wlan_config;
 	struct delayed_work wcnss_work;
+	struct delayed_work vbatt_work;
 	struct work_struct wcnssctrl_version_work;
 	struct work_struct wcnssctrl_nvbin_dnld_work;
 	struct work_struct wcnssctrl_rx_work;
@@ -324,8 +341,12 @@
 	int	user_cal_exp_size;
 	int	device_opened;
 	int	iris_xo_mode_set;
+	int	fw_vbatt_state;
 	struct mutex dev_lock;
 	wait_queue_head_t read_wait;
+	struct qpnp_adc_tm_btm_param vbat_monitor_params;
+	struct qpnp_adc_tm_chip *adc_tm_dev;
+	struct mutex vbat_monitor_mutex;
 } *penv = NULL;
 
 static ssize_t wcnss_serial_number_show(struct device *dev,
@@ -1081,7 +1102,6 @@
 }
 EXPORT_SYMBOL(wcnss_get_wlan_rx_buff_count);
 
-
 static int wcnss_smd_tx(void *data, int len)
 {
 	int ret = 0;
@@ -1099,6 +1119,102 @@
 	return ret;
 }
 
+static void wcnss_notify_vbat(enum qpnp_tm_state state, void *ctx)
+{
+	mutex_lock(&penv->vbat_monitor_mutex);
+	cancel_delayed_work_sync(&penv->vbatt_work);
+
+	if (state == ADC_TM_LOW_STATE) {
+		pr_debug("wcnss: low voltage notification triggered\n");
+		penv->vbat_monitor_params.state_request =
+			ADC_TM_HIGH_THR_ENABLE;
+		penv->vbat_monitor_params.high_thr = WCNSS_VBATT_THRESHOLD +
+		WCNSS_VBATT_GUARD;
+		penv->vbat_monitor_params.low_thr = 0;
+	} else if (state == ADC_TM_HIGH_STATE) {
+		penv->vbat_monitor_params.state_request =
+			ADC_TM_LOW_THR_ENABLE;
+		penv->vbat_monitor_params.low_thr = WCNSS_VBATT_THRESHOLD -
+		WCNSS_VBATT_GUARD;
+		penv->vbat_monitor_params.high_thr = 0;
+		pr_debug("wcnss: high voltage notification triggered\n");
+	} else {
+		pr_debug("wcnss: unknown voltage notification state: %d\n",
+				state);
+		mutex_unlock(&penv->vbat_monitor_mutex);
+		return;
+	}
+	pr_debug("wcnss: set low thr to %d and high to %d\n",
+			penv->vbat_monitor_params.low_thr,
+			penv->vbat_monitor_params.high_thr);
+
+	qpnp_adc_tm_channel_measure(penv->adc_tm_dev,
+			&penv->vbat_monitor_params);
+	schedule_delayed_work(&penv->vbatt_work, msecs_to_jiffies(2000));
+	mutex_unlock(&penv->vbat_monitor_mutex);
+}
+
+static int wcnss_setup_vbat_monitoring(void)
+{
+	int rc = -1;
+
+	if (!penv->adc_tm_dev) {
+		pr_err("wcnss: not setting up vbatt\n");
+		return rc;
+	}
+	penv->vbat_monitor_params.low_thr = WCNSS_VBATT_THRESHOLD;
+	penv->vbat_monitor_params.high_thr = WCNSS_VBATT_THRESHOLD;
+	penv->vbat_monitor_params.state_request = ADC_TM_HIGH_LOW_THR_ENABLE;
+	penv->vbat_monitor_params.channel = VBAT_SNS;
+	penv->vbat_monitor_params.btm_ctx = (void *)penv;
+	penv->vbat_monitor_params.timer_interval = ADC_MEAS1_INTERVAL_1S;
+	penv->vbat_monitor_params.threshold_notification = &wcnss_notify_vbat;
+	pr_debug("wcnss: set low thr to %d and high to %d\n",
+			penv->vbat_monitor_params.low_thr,
+			penv->vbat_monitor_params.high_thr);
+
+	rc = qpnp_adc_tm_channel_measure(penv->adc_tm_dev,
+					&penv->vbat_monitor_params);
+	if (rc)
+		pr_err("wcnss: tm setup failed: %d\n", rc);
+
+	return rc;
+}
+
+static void wcnss_update_vbatt(struct work_struct *work)
+{
+	struct vbatt_message vbatt_msg;
+	int ret = 0;
+
+	vbatt_msg.hdr.msg_type = WCNSS_VBATT_LEVEL_IND;
+	vbatt_msg.hdr.msg_len = sizeof(struct vbatt_message);
+	vbatt_msg.vbatt.threshold = WCNSS_VBATT_THRESHOLD;
+
+	mutex_lock(&penv->vbat_monitor_mutex);
+	if (penv->vbat_monitor_params.low_thr &&
+		(penv->fw_vbatt_state == WCNSS_VBATT_LOW ||
+			penv->fw_vbatt_state == WCNSS_CONFIG_UNSPECIFIED)) {
+		vbatt_msg.vbatt.curr_volt = WCNSS_VBATT_HIGH;
+		penv->fw_vbatt_state = WCNSS_VBATT_HIGH;
+		pr_debug("wcnss: send HIGH BATT to FW\n");
+	} else if (!penv->vbat_monitor_params.low_thr &&
+		(penv->fw_vbatt_state == WCNSS_VBATT_HIGH ||
+			penv->fw_vbatt_state == WCNSS_CONFIG_UNSPECIFIED)){
+		vbatt_msg.vbatt.curr_volt = WCNSS_VBATT_LOW;
+		penv->fw_vbatt_state = WCNSS_VBATT_LOW;
+		pr_debug("wcnss: send LOW BATT to FW\n");
+	} else {
+		mutex_unlock(&penv->vbat_monitor_mutex);
+		return;
+	}
+	mutex_unlock(&penv->vbat_monitor_mutex);
+	ret = wcnss_smd_tx(&vbatt_msg, vbatt_msg.hdr.msg_len);
+	if (ret < 0)
+		pr_err("wcnss: smd tx failed\n");
+	return;
+}
+
+
 static unsigned char wcnss_fw_status(void)
 {
 	int len = 0;
@@ -1312,6 +1428,7 @@
 		fw_status = wcnss_fw_status();
 		pr_debug("wcnss: received WCNSS_NVBIN_DNLD_RSP from ccpu %u\n",
 			fw_status);
+		wcnss_setup_vbat_monitoring();
 		break;
 
 	case WCNSS_CALDATA_DNLD_RSP:
@@ -1791,12 +1908,21 @@
 		}
 
 	}
+	penv->adc_tm_dev = qpnp_get_adc_tm(&penv->pdev->dev, "wcnss");
+	if (IS_ERR(penv->adc_tm_dev)) {
+		pr_err("%s:  adc get failed\n", __func__);
+		penv->adc_tm_dev = NULL;
+	} else {
+		INIT_DELAYED_WORK(&penv->vbatt_work, wcnss_update_vbatt);
+		penv->fw_vbatt_state = WCNSS_CONFIG_UNSPECIFIED;
+	}
 
 	/* trigger initialization of the WCNSS */
 	penv->pil = subsystem_get(WCNSS_PIL_DEVICE);
 	if (IS_ERR(penv->pil)) {
 		dev_err(&pdev->dev, "Peripheral Loader failed on WCNSS.\n");
 		ret = PTR_ERR(penv->pil);
+		wcnss_pronto_log_debug_regs();
 		penv->pil = NULL;
 		goto fail_pil;
 	}
@@ -2004,6 +2130,7 @@
 	}
 
 	mutex_init(&penv->dev_lock);
+	mutex_init(&penv->vbat_monitor_mutex);
 	init_waitqueue_head(&penv->read_wait);
 
 	/* Since we were built into the kernel we'll be called as part
diff --git a/drivers/platform/msm/qpnp-pwm.c b/drivers/platform/msm/qpnp-pwm.c
index b77c826..7d26bef 100644
--- a/drivers/platform/msm/qpnp-pwm.c
+++ b/drivers/platform/msm/qpnp-pwm.c
@@ -199,8 +199,15 @@
 #define qpnp_check_gpled_lpg_channel(id) \
 	(id >= QPNP_GPLED_LPG_CHANNEL_RANGE_START && \
 	id <= QPNP_GPLED_LPG_CHANNEL_RANGE_END)
+
 #define QPNP_PWM_LUT_NOT_SUPPORTED	0x1
 
+/* Supported PWM sizes */
+#define QPNP_PWM_SIZE_6_BIT		6
+#define QPNP_PWM_SIZE_7_BIT		7
+#define QPNP_PWM_SIZE_8_BIT		8
+#define QPNP_PWM_SIZE_9_BIT		9
+
 /* LPG revisions */
 enum qpnp_lpg_revision {
 	QPNP_LPG_REVISION_0 = 0x0,
@@ -301,6 +308,7 @@
 	int				pwm_period;
 	int				pwm_duty;
 	struct pwm_period_config	period;
+	int				force_pwm_size;
 };
 
 /* Public facing structure */
@@ -418,14 +426,16 @@
  * (PWM Period / N) = (Pre-divide * Clock Period) * 2^m
  */
 static void qpnp_lpg_calc_period(unsigned int period_us,
-				   struct qpnp_pwm_config *pwm_conf)
+				   struct pwm_device *pwm)
 {
 	int		n, m, clk, div;
 	int		best_m, best_div, best_clk;
 	unsigned int	last_err, cur_err, min_err;
 	unsigned int	tmp_p, period_n;
-	int		id = pwm_conf->channel_id;
-	struct pwm_period_config *period = &pwm_conf->period;
+	int		id = pwm->pwm_config.channel_id;
+	int		force_pwm_size = pwm->pwm_config.force_pwm_size;
+	struct qpnp_lpg_chip *chip = pwm->chip;
+	struct pwm_period_config *period = &pwm->pwm_config.period;
 
 	/* PWM Period / N */
 	if (qpnp_check_gpled_lpg_channel(id))
@@ -443,6 +453,15 @@
 		period_n = (period_us >> n) * NSEC_PER_USEC;
 	}
 
+	if (force_pwm_size != 0) {
+		if (n < force_pwm_size)
+			period_n = period_n >> (force_pwm_size - n);
+		else
+			period_n = period_n << (n - force_pwm_size);
+		n = force_pwm_size;
+		pr_info("LPG channel '%d' pwm size is forced to=%d\n", id, n);
+	}
+
 	min_err = last_err = (unsigned)(-1);
 	best_m = 0;
 	best_clk = 0;
@@ -476,19 +495,20 @@
 	}
 
 	/* Adapt to optimal pwm size, the higher the resolution the better */
-	if (qpnp_check_gpled_lpg_channel(id)) {
-		if (n == 7 && best_m >= 1) {
-			n += 1;
-			best_m -= 1;
-		}
-	} else {
-		if (n == 6 && best_m >= 3) {
-			n += 3;
-			best_m -= 3;
-		} else {
-			if (n == 6) {
-				n += best_m;
-				best_m -= best_m;
+	if (!force_pwm_size) {
+		if (qpnp_check_gpled_lpg_channel(id)) {
+			if (n == 7 && best_m >= 1) {
+				n += 1;
+				best_m -= 1;
+			}
+		} else if (n == 6) {
+			if (best_m >= 3) {
+				n += 3;
+				best_m -= 3;
+			} else if (best_m >= 1 &&
+				chip->sub_type != QPNP_PWM_MODE_ONLY_SUB_TYPE) {
+				n += 1;
+				best_m -= 1;
 			}
 		}
 	}
@@ -1075,7 +1095,7 @@
 	period = &pwm_config->period;
 
 	if (pwm_config->pwm_period != period_us) {
-		qpnp_lpg_calc_period(period_us, pwm_config);
+		qpnp_lpg_calc_period(period_us, pwm);
 		qpnp_lpg_save_period(pwm);
 		pwm_config->pwm_period = period_us;
 	}
@@ -1131,7 +1151,7 @@
 	period = &pwm_config->period;
 
 	if (pwm_config->pwm_period != period_us) {
-		qpnp_lpg_calc_period(period_us, pwm_config);
+		qpnp_lpg_calc_period(period_us, pwm);
 		qpnp_lpg_save_period(pwm);
 		pwm_config->pwm_period = period_us;
 	}
@@ -1715,6 +1735,7 @@
 	struct pwm_device	*pwm_dev = &chip->pwm_dev;
 	struct qpnp_lpg_config	*lpg_config = &chip->lpg_config;
 	struct qpnp_lut_config	*lut_config = &lpg_config->lut_config;
+	int			force_pwm_size = 0;
 
 	rc = of_property_read_u32(of_node, "qcom,channel-id",
 				&pwm_dev->pwm_config.channel_id);
@@ -1724,6 +1745,27 @@
 		goto out;
 	}
 
+	/*
+	 * For cetrain LPG channels PWM size can be forced. So that
+	 * for every requested pwm period closest pwm frequency is
+	 * selected in qpnp_lpg_calc_period() for the forced pwm size.
+	 */
+	rc = of_property_read_u32(of_node, "qcom,force-pwm-size",
+				&force_pwm_size);
+	if (qpnp_check_gpled_lpg_channel(pwm_dev->pwm_config.channel_id)) {
+		if (!(force_pwm_size == QPNP_PWM_SIZE_7_BIT ||
+				force_pwm_size == QPNP_PWM_SIZE_8_BIT))
+			force_pwm_size = 0;
+	} else if (chip->sub_type == QPNP_PWM_MODE_ONLY_SUB_TYPE) {
+		if (!(force_pwm_size == QPNP_PWM_SIZE_6_BIT ||
+				force_pwm_size == QPNP_PWM_SIZE_9_BIT))
+			force_pwm_size = 0;
+	} else if (!(force_pwm_size == QPNP_PWM_SIZE_6_BIT ||
+				force_pwm_size == QPNP_PWM_SIZE_7_BIT ||
+				force_pwm_size == QPNP_PWM_SIZE_9_BIT))
+			force_pwm_size = 0;
+
+	pwm_dev->pwm_config.force_pwm_size = force_pwm_size;
 	res = spmi_get_resource_byname(spmi, NULL, IORESOURCE_MEM,
 					QPNP_LPG_CHANNEL_BASE);
 	if (!res) {
diff --git a/drivers/power/qpnp-bms.c b/drivers/power/qpnp-bms.c
index 38fb895..49e57b9 100644
--- a/drivers/power/qpnp-bms.c
+++ b/drivers/power/qpnp-bms.c
@@ -83,7 +83,7 @@
 #define IAVG_STEP_SIZE_MA		50
 #define IAVG_START			600
 #define IAVG_INVALID			0xFF
-#define SOC_INVALID			0xFF
+#define SOC_INVALID			0x7E
 
 #define IAVG_SAMPLES 16
 
@@ -147,6 +147,8 @@
 	wait_queue_head_t		bms_wait_queue;
 	u16				base;
 	u16				iadc_base;
+	u16				batt_pres_addr;
+	u16				soc_storage_addr;
 
 	u8				revision1;
 	u8				revision2;
@@ -188,6 +190,7 @@
 	struct mutex			vbat_monitor_mutex;
 	struct mutex			soc_invalidation_mutex;
 	struct mutex			last_soc_mutex;
+	struct mutex			status_lock;
 
 	bool				use_external_rsense;
 	bool				use_ocv_thresholds;
@@ -293,6 +296,7 @@
 
 static enum power_supply_property msm_bms_power_props[] = {
 	POWER_SUPPLY_PROP_CAPACITY,
+	POWER_SUPPLY_PROP_STATUS,
 	POWER_SUPPLY_PROP_CURRENT_NOW,
 	POWER_SUPPLY_PROP_RESISTANCE,
 	POWER_SUPPLY_PROP_CHARGE_COUNTER,
@@ -1510,24 +1514,6 @@
 	pr_debug("UUC = %uuAh\n", params->uuc_uah);
 }
 
-static bool is_shutdown_soc_within_limits(struct qpnp_bms_chip *chip, int soc)
-{
-	if (chip->shutdown_soc_invalid) {
-		pr_debug("NOT forcing shutdown soc = %d\n", chip->shutdown_soc);
-		return 0;
-	}
-
-	if (abs(chip->shutdown_soc - soc) > chip->shutdown_soc_valid_limit) {
-		pr_debug("rejecting shutdown soc = %d, soc = %d limit = %d\n",
-			chip->shutdown_soc, soc,
-			chip->shutdown_soc_valid_limit);
-		chip->shutdown_soc_invalid = true;
-		return 0;
-	}
-
-	return 1;
-}
-
 static int bound_soc(int soc)
 {
 	soc = max(0, soc);
@@ -1614,6 +1600,7 @@
 
 module_param_cb(bms_reset, &bms_reset_ops, &bms_reset, 0644);
 
+#define SOC_STORAGE_MASK	0xFE
 static void backup_soc_and_iavg(struct qpnp_bms_chip *chip, int batt_temp,
 				int soc)
 {
@@ -1626,15 +1613,12 @@
 	else
 		temp = 0;
 
-	rc = qpnp_write_wrapper(chip, &temp,
-			chip->base + IAVG_STORAGE_REG, 1);
-
-	temp = soc;
+	rc = qpnp_write_wrapper(chip, &temp, chip->base + IAVG_STORAGE_REG, 1);
 
 	/* 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);
+		qpnp_masked_write_base(chip, chip->soc_storage_addr,
+				SOC_STORAGE_MASK, (soc + 1) << 1);
 }
 
 static int scale_soc_while_chg(struct qpnp_bms_chip *chip, int chg_time_sec,
@@ -1822,6 +1806,7 @@
 				int vbat_uv, int ibat_ua, int batt_temp)
 {
 	int chg_soc, soc_ibat, batt_terminal_uv, weight_ibat, weight_cc;
+	int new_ocv_uv;
 
 	batt_terminal_uv = vbat_uv + (ibat_ua * chip->r_conn_mohm) / 1000;
 
@@ -1873,8 +1858,6 @@
 
 	/* always report a higher soc */
 	if (chg_soc > chip->prev_chg_soc) {
-		int new_ocv_uv;
-
 		chip->prev_chg_soc = chg_soc;
 
 		find_ocv_for_soc(chip, params, batt_temp, chg_soc, &new_ocv_uv);
@@ -2186,37 +2169,22 @@
 			(uint16_t)ocv_raw);
 }
 
-#define SLEEP_RECALC_INTERVAL	3
-static int calculate_state_of_charge(struct qpnp_bms_chip *chip,
+static int calculate_raw_soc(struct qpnp_bms_chip *chip,
 					struct raw_soc_params *raw,
+					struct soc_params *params,
 					int batt_temp)
 {
-	int soc, new_ocv_uv, previous_soc;
-	int shutdown_soc, new_calculated_soc, remaining_usable_charge_uah;
-	struct soc_params params;
+	int soc, new_ocv_uv;
+	int remaining_usable_charge_uah;
 
-	if (!is_battery_present(chip)) {
-		pr_debug("battery gone, reporting 100\n");
-		new_calculated_soc = 100;
-		goto done_calculating;
-	}
-	calculate_soc_params(chip, raw, &params, batt_temp);
 	/* calculate remaining usable charge */
-	remaining_usable_charge_uah = params.ocv_charge_uah
-					- params.cc_uah
-					- params.uuc_uah;
-
+	remaining_usable_charge_uah = params->ocv_charge_uah
+					- params->cc_uah
+					- params->uuc_uah;
 	pr_debug("RUC = %duAh\n", remaining_usable_charge_uah);
-	if (params.fcc_uah - params.uuc_uah <= 0) {
-		pr_debug("FCC = %duAh, UUC = %duAh forcing soc = 0\n",
-						params.fcc_uah,
-						params.uuc_uah);
-		new_calculated_soc = 0;
-		goto done_calculating;
-	}
 
 	soc = DIV_ROUND_CLOSEST((remaining_usable_charge_uah * 100),
-				(params.fcc_uah - params.uuc_uah));
+				(params->fcc_uah - params->uuc_uah));
 
 	if (chip->first_time_calc_soc && soc < 0) {
 		/*
@@ -2224,16 +2192,16 @@
 		 * in a bad soc. Adjust ocv to get 0 soc
 		 */
 		pr_debug("soc is %d, adjusting pon ocv to make it 0\n", soc);
-		find_ocv_for_soc(chip, &params, batt_temp, 0, &new_ocv_uv);
+		find_ocv_for_soc(chip, params, batt_temp, 0, &new_ocv_uv);
 		chip->last_ocv_uv = new_ocv_uv;
 
-		remaining_usable_charge_uah = params.ocv_charge_uah
-					- params.cc_uah
-					- params.uuc_uah;
+		remaining_usable_charge_uah = params->ocv_charge_uah
+					- params->cc_uah
+					- params->uuc_uah;
 
 		soc = DIV_ROUND_CLOSEST((remaining_usable_charge_uah * 100),
-					(params.fcc_uah
-						- params.uuc_uah));
+					(params->fcc_uah
+						- params->uuc_uah));
 		pr_debug("DONE for O soc is %d, pon ocv adjusted to %duV\n",
 				soc, chip->last_ocv_uv);
 	}
@@ -2244,20 +2212,49 @@
 	if (soc < 0) {
 		pr_debug("bad rem_usb_chg = %d rem_chg %d, cc_uah %d, unusb_chg %d\n",
 				remaining_usable_charge_uah,
-				params.ocv_charge_uah,
-				params.cc_uah, params.uuc_uah);
+				params->ocv_charge_uah,
+				params->cc_uah, params->uuc_uah);
 
 		pr_debug("for bad rem_usb_chg last_ocv_uv = %d batt_temp = %d fcc = %d soc =%d\n",
 				chip->last_ocv_uv, batt_temp,
-				params.fcc_uah, soc);
+				params->fcc_uah, soc);
 		soc = 0;
 	}
 
+	return soc;
+}
+
+#define SLEEP_RECALC_INTERVAL	3
+static int calculate_state_of_charge(struct qpnp_bms_chip *chip,
+					struct raw_soc_params *raw,
+					int batt_temp)
+{
+	struct soc_params params;
+	int soc, previous_soc, shutdown_soc, new_calculated_soc;
+	int remaining_usable_charge_uah, new_ocv_uv;
+
+	calculate_soc_params(chip, raw, &params, batt_temp);
+	if (!is_battery_present(chip)) {
+		pr_debug("battery gone, reporting 100\n");
+		new_calculated_soc = 100;
+		goto done_calculating;
+	}
+
+	if (params.fcc_uah - params.uuc_uah <= 0) {
+		pr_debug("FCC = %duAh, UUC = %duAh forcing soc = 0\n",
+						params.fcc_uah,
+						params.uuc_uah);
+		new_calculated_soc = 0;
+		goto done_calculating;
+	}
+
+	soc = calculate_raw_soc(chip, raw, &params, batt_temp);
+
 	mutex_lock(&chip->soc_invalidation_mutex);
 	shutdown_soc = chip->shutdown_soc;
 
 	if (chip->first_time_calc_soc && soc != shutdown_soc
-			&& is_shutdown_soc_within_limits(chip, soc)) {
+			&& !chip->shutdown_soc_invalid) {
 		/*
 		 * soc for the first time - use shutdown soc
 		 * to adjust pon ocv since it is a small percent away from
@@ -2367,6 +2364,53 @@
 	return voltage_based_soc;
 }
 
+static int recalculate_raw_soc(struct qpnp_bms_chip *chip)
+{
+	int batt_temp, rc, soc;
+	struct qpnp_vadc_result result;
+	struct raw_soc_params raw;
+	struct soc_params params;
+
+	bms_stay_awake(&chip->soc_wake_source);
+	if (chip->use_voltage_soc) {
+		soc = calculate_soc_from_voltage(chip);
+	} else {
+		if (!chip->batfet_closed)
+			qpnp_iadc_calibrate_for_trim(chip->iadc_dev, true);
+		rc = qpnp_vadc_read(chip->vadc_dev, LR_MUX1_BATT_THERM,
+								&result);
+		if (rc) {
+			pr_err("error reading vadc LR_MUX1_BATT_THERM = %d, rc = %d\n",
+						LR_MUX1_BATT_THERM, rc);
+			soc = chip->calculated_soc;
+		} else {
+			pr_debug("batt_temp phy = %lld meas = 0x%llx\n",
+							result.physical,
+							result.measurement);
+			batt_temp = (int)result.physical;
+
+			mutex_lock(&chip->last_ocv_uv_mutex);
+			read_soc_params_raw(chip, &raw, batt_temp);
+			calculate_soc_params(chip, &raw, &params, batt_temp);
+			if (!is_battery_present(chip)) {
+				pr_debug("battery gone\n");
+				soc = 0;
+			} else if (params.fcc_uah - params.uuc_uah <= 0) {
+				pr_debug("FCC = %duAh, UUC = %duAh forcing soc = 0\n",
+							params.fcc_uah,
+							params.uuc_uah);
+				soc = 0;
+			} else {
+				soc = calculate_raw_soc(chip, &raw,
+							&params, batt_temp);
+			}
+			mutex_unlock(&chip->last_ocv_uv_mutex);
+		}
+	}
+	bms_relax(&chip->soc_wake_source);
+	return soc;
+}
+
 static int recalculate_soc(struct qpnp_bms_chip *chip)
 {
 	int batt_temp, rc, soc;
@@ -3068,6 +3112,7 @@
 {
 	int status = get_battery_status(chip);
 
+	mutex_lock(&chip->status_lock);
 	if (chip->battery_status != status) {
 		pr_debug("status = %d, shadow status = %d\n",
 				status, chip->battery_status);
@@ -3084,6 +3129,7 @@
 			pr_debug("battery full\n");
 			enable_bms_irq(&chip->ocv_thr_irq);
 			enable_bms_irq(&chip->sw_cc_thr_irq);
+			recalculate_soc(chip);
 		} else if (chip->battery_status
 				== POWER_SUPPLY_STATUS_FULL) {
 			pr_debug("battery not full any more\n");
@@ -3096,6 +3142,7 @@
 		 * recalculation to update the SoC */
 		schedule_work(&chip->recalc_work);
 	}
+	mutex_unlock(&chip->status_lock);
 }
 
 #define CALIB_WRKARND_DIG_MAJOR_MAX		0x03
@@ -3170,6 +3217,9 @@
 	case POWER_SUPPLY_PROP_CAPACITY:
 		val->intval = get_prop_bms_capacity(chip);
 		break;
+	case POWER_SUPPLY_PROP_STATUS:
+		val->intval = chip->battery_status;
+		break;
 	case POWER_SUPPLY_PROP_CURRENT_NOW:
 		val->intval = get_prop_bms_current_now(chip);
 		break;
@@ -3234,61 +3284,120 @@
 	return 0;
 }
 
-static void read_shutdown_soc_and_iavg(struct qpnp_bms_chip *chip)
+static int read_shutdown_iavg_ma(struct qpnp_bms_chip *chip)
 {
+	u8 iavg;
 	int rc;
-	u8 temp;
 
-	if (chip->ignore_shutdown_soc) {
-		chip->shutdown_soc_invalid = true;
-		chip->shutdown_soc = 0;
-		chip->shutdown_iavg_ma = 0;
+	rc = qpnp_read_wrapper(chip, &iavg, chip->base + IAVG_STORAGE_REG, 1);
+	if (rc) {
+		pr_err("failed to read addr = %d %d assuming %d\n",
+				chip->base + IAVG_STORAGE_REG, rc,
+				IAVG_START);
+		return IAVG_START;
+	} else if (iavg == IAVG_INVALID) {
+		pr_err("invalid iavg read from BMS1_DATA_REG_1, using %d\n",
+				IAVG_START);
+		return IAVG_START;
 	} else {
-		rc = qpnp_read_wrapper(chip, &temp,
-				chip->base + IAVG_STORAGE_REG, 1);
-		if (rc) {
-			pr_err("failed to read addr = %d %d assuming %d\n",
-					chip->base + IAVG_STORAGE_REG, rc,
-					IAVG_START);
-			chip->shutdown_iavg_ma = IAVG_START;
-		} else if (temp == IAVG_INVALID) {
-			pr_err("invalid iavg read from BMS1_DATA_REG_1, using %d\n",
-					IAVG_START);
-			chip->shutdown_iavg_ma = IAVG_START;
-		} else {
-			if (temp == 0) {
-				chip->shutdown_iavg_ma = IAVG_START;
-			} else {
-				chip->shutdown_iavg_ma = IAVG_START
-					+ IAVG_STEP_SIZE_MA * (temp + 1);
-			}
-		}
+		if (iavg == 0)
+			return IAVG_START;
+		else
+			return IAVG_START + IAVG_STEP_SIZE_MA * (iavg + 1);
+	}
+}
 
-		rc = qpnp_read_wrapper(chip, &temp,
-				chip->base + SOC_STORAGE_REG, 1);
-		if (rc) {
-			pr_err("failed to read addr = %d %d\n",
-					chip->base + SOC_STORAGE_REG, rc);
-		} else {
-			chip->shutdown_soc = temp;
+static int read_shutdown_soc(struct qpnp_bms_chip *chip)
+{
+	u8 stored_soc;
+	int rc, shutdown_soc;
 
-			if (chip->shutdown_soc == SOC_INVALID) {
-				pr_debug("No shutdown soc available\n");
-				chip->shutdown_soc_invalid = true;
-				chip->shutdown_iavg_ma = 0;
-			}
-		}
+	/*
+	 * The previous SOC is stored in the first 7 bits of the register as
+	 * (Shutdown SOC + 1). This allows for register reset values of both
+	 * 0x00 and 0x7F.
+	 */
+	rc = qpnp_read_wrapper(chip, &stored_soc, chip->soc_storage_addr, 1);
+	if (rc) {
+		pr_err("failed to read addr = %d %d\n",
+				chip->soc_storage_addr, rc);
+		return SOC_INVALID;
 	}
 
-	/* read the SOC storage to determine if there was a battery removal */
-	rc = qpnp_read_wrapper(chip, &temp, chip->base + SOC_STORAGE_REG, 1);
-	if (!rc) {
-		if (temp == SOC_INVALID)
-			chip->battery_removed = true;
+	if ((stored_soc >> 1) > 0)
+		shutdown_soc = (stored_soc >> 1) - 1;
+	else
+		shutdown_soc = SOC_INVALID;
+
+	pr_debug("stored soc = 0x%02x, shutdown_soc = %d\n",
+			stored_soc, shutdown_soc);
+	return shutdown_soc;
+}
+
+#define BAT_REMOVED_OFFMODE_BIT		BIT(6)
+static bool is_battery_replaced_in_offmode(struct qpnp_bms_chip *chip)
+{
+	u8 batt_pres;
+	int rc;
+
+	if (chip->batt_pres_addr) {
+		rc = qpnp_read_wrapper(chip, &batt_pres,
+				chip->batt_pres_addr, 1);
+		pr_debug("offmode removed: %02x\n", batt_pres);
+		if (!rc && (batt_pres & BAT_REMOVED_OFFMODE_BIT))
+			return true;
+	}
+	return false;
+}
+
+static void load_shutdown_data(struct qpnp_bms_chip *chip)
+{
+	int calculated_soc, shutdown_soc;
+	bool invalid_stored_soc;
+	bool offmode_battery_replaced;
+	bool shutdown_soc_out_of_limit;
+
+	/*
+	 * Read the saved shutdown SoC from the configured register and
+	 * check if the value has been reset
+	 */
+	shutdown_soc = read_shutdown_soc(chip);
+	invalid_stored_soc = (shutdown_soc == SOC_INVALID);
+
+	/*
+	 * Do a quick run of SoC calculation to find whether the shutdown soc
+	 * is close enough.
+	 */
+	calculated_soc = recalculate_raw_soc(chip);
+	shutdown_soc_out_of_limit = (abs(shutdown_soc - calculated_soc)
+			> chip->shutdown_soc_valid_limit);
+	pr_debug("calculated_soc = %d, valid_limit = %d\n",
+			calculated_soc, chip->shutdown_soc_valid_limit);
+
+	/*
+	 * Check if the battery has been replaced while the system was powered
+	 * down.
+	 */
+	offmode_battery_replaced = is_battery_replaced_in_offmode(chip);
+
+	/* Invalidate the shutdown SoC if any of these conditions hold true */
+	if (chip->ignore_shutdown_soc
+			|| invalid_stored_soc
+			|| offmode_battery_replaced
+			|| shutdown_soc_out_of_limit) {
+		chip->battery_removed = true;
+		chip->shutdown_soc_invalid = true;
+		chip->shutdown_iavg_ma = 0;
+		pr_debug("Ignoring shutdown SoC: invalid = %d, offmode = %d, out_of_limit = %d\n",
+				invalid_stored_soc, offmode_battery_replaced,
+				shutdown_soc_out_of_limit);
+	} else {
+		chip->shutdown_iavg_ma = read_shutdown_iavg_ma(chip);
+		chip->shutdown_soc = shutdown_soc;
 	}
 
-
-	pr_debug("shutdown_soc = %d shutdown_iavg = %d shutdown_soc_invalid = %d, battery_removed = %d\n",
+	pr_debug("raw_soc = %d shutdown_soc = %d shutdown_iavg = %d shutdown_soc_invalid = %d, battery_removed = %d\n",
+			calculated_soc,
 			chip->shutdown_soc,
 			chip->shutdown_iavg_ma,
 			chip->shutdown_soc_invalid,
@@ -3646,6 +3755,18 @@
 			return -ENXIO;
 		}
 
+		pr_debug("Node name = %s\n", spmi_resource->of_node->name);
+
+		if (strcmp("qcom,batt-pres-status",
+					spmi_resource->of_node->name) == 0) {
+			chip->batt_pres_addr = resource->start;
+			continue;
+		} else if (strcmp("qcom,soc-storage-reg",
+					spmi_resource->of_node->name) == 0) {
+			chip->soc_storage_addr = resource->start;
+			continue;
+		}
+
 		rc = qpnp_read_wrapper(chip, &type,
 				resource->start + REG_OFFSET_PERP_TYPE, 1);
 		if (rc) {
@@ -3684,7 +3805,14 @@
 		dev_err(&spmi->dev, "BMS_IADC peripheral was not registered\n");
 		return -EINVAL;
 	}
+	if (chip->soc_storage_addr == 0) {
+		/* default to dvdd backed BMS data reg0 */
+		chip->soc_storage_addr = chip->base + SOC_STORAGE_REG;
+	}
 
+	pr_debug("bms-base = 0x%04x, iadc-base = 0x%04x, bat-pres-reg = 0x%04x, soc-storage-reg = 0x%04x\n",
+			chip->base, chip->iadc_base,
+			chip->batt_pres_addr, chip->soc_storage_addr);
 	return 0;
 }
 
@@ -3869,6 +3997,7 @@
 	mutex_init(&chip->vbat_monitor_mutex);
 	mutex_init(&chip->soc_invalidation_mutex);
 	mutex_init(&chip->last_soc_mutex);
+	mutex_init(&chip->status_lock);
 	init_waitqueue_head(&chip->bms_wait_queue);
 
 	warm_reset = qpnp_pon_is_warm_reset();
@@ -3954,7 +4083,10 @@
 	INIT_WORK(&chip->recalc_work, recalculate_work);
 	INIT_WORK(&chip->batfet_open_work, batfet_open_work);
 
-	read_shutdown_soc_and_iavg(chip);
+	dev_set_drvdata(&spmi->dev, chip);
+	device_init_wakeup(&spmi->dev, 1);
+
+	load_shutdown_data(chip);
 
 	if (chip->enable_fcc_learning) {
 		if (chip->battery_removed) {
@@ -3974,9 +4106,6 @@
 		}
 	}
 
-	dev_set_drvdata(&spmi->dev, chip);
-	device_init_wakeup(&spmi->dev, 1);
-
 	rc = setup_vbat_monitoring(chip);
 	if (rc < 0) {
 		pr_err("failed to set up voltage notifications: %d\n", rc);
diff --git a/drivers/power/qpnp-charger.c b/drivers/power/qpnp-charger.c
index f9e05fc..6e9dc57 100644
--- a/drivers/power/qpnp-charger.c
+++ b/drivers/power/qpnp-charger.c
@@ -1693,7 +1693,7 @@
 get_prop_capacity(struct qpnp_chg_chip *chip)
 {
 	union power_supply_propval ret = {0,};
-	int battery_status, charger_in;
+	int battery_status, bms_status, soc, charger_in;
 
 	if (chip->use_default_batt_values || !get_prop_batt_present(chip))
 		return DEFAULT_CAPACITY;
@@ -1701,28 +1701,32 @@
 	if (chip->bms_psy) {
 		chip->bms_psy->get_property(chip->bms_psy,
 				POWER_SUPPLY_PROP_CAPACITY, &ret);
+		soc = ret.intval;
 		battery_status = get_prop_batt_status(chip);
+		chip->bms_psy->get_property(chip->bms_psy,
+				POWER_SUPPLY_PROP_STATUS, &ret);
+		bms_status = ret.intval;
 		charger_in = qpnp_chg_is_usb_chg_plugged_in(chip) ||
 			qpnp_chg_is_dc_chg_plugged_in(chip);
 
 		if (battery_status != POWER_SUPPLY_STATUS_CHARGING
+				&& bms_status != POWER_SUPPLY_STATUS_CHARGING
 				&& charger_in
 				&& !chip->resuming_charging
 				&& !chip->charging_disabled
 				&& chip->soc_resume_limit
-				&& ret.intval <= chip->soc_resume_limit) {
-			pr_debug("resuming charging at %d%% soc\n",
-					ret.intval);
+				&& soc <= chip->soc_resume_limit) {
+			pr_debug("resuming charging at %d%% soc\n", soc);
 			chip->resuming_charging = true;
 			qpnp_chg_set_appropriate_vbatdet(chip);
 			qpnp_chg_charge_en(chip, !chip->charging_disabled);
 		}
-		if (ret.intval == 0) {
+		if (soc == 0) {
 			if (!qpnp_chg_is_usb_chg_plugged_in(chip)
 				&& !qpnp_chg_is_usb_chg_plugged_in(chip))
 				pr_warn_ratelimited("Battery 0, CHG absent\n");
 		}
-		return ret.intval;
+		return soc;
 	} else {
 		pr_debug("No BMS supply registered return 50\n");
 	}
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index 0ebb944..450c4fb 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -3357,14 +3357,6 @@
 		ret = set_supply(rdev, r);
 		if (ret < 0)
 			goto scrub;
-
-		/* Enable supply if rail is enabled */
-		if (rdev->desc->ops->is_enabled &&
-				rdev->desc->ops->is_enabled(rdev)) {
-			ret = regulator_enable(rdev->supply);
-			if (ret < 0)
-				goto scrub;
-		}
 	}
 
 	/* add consumers devices */
diff --git a/drivers/staging/android/binder.c b/drivers/staging/android/binder.c
index 3abc3b9..b7bf74e 100644
--- a/drivers/staging/android/binder.c
+++ b/drivers/staging/android/binder.c
@@ -33,6 +33,7 @@
 #include <linux/uaccess.h>
 #include <linux/vmalloc.h>
 #include <linux/slab.h>
+#include <linux/security.h>
 
 #include "binder.h"
 
@@ -1488,6 +1489,10 @@
 			return_error = BR_DEAD_REPLY;
 			goto err_dead_binder;
 		}
+		if (security_binder_transaction(proc->tsk, target_proc->tsk) < 0) {
+			return_error = BR_FAILED_REPLY;
+			goto err_invalid_target_handle;
+		}
 		if (!(tr->flags & TF_ONE_WAY) && thread->transaction_stack) {
 			struct binder_transaction *tmp;
 			tmp = thread->transaction_stack;
@@ -1633,6 +1638,10 @@
 					fp->cookie, node->cookie);
 				goto err_binder_get_ref_for_node_failed;
 			}
+			if (security_binder_transfer_binder(proc->tsk, target_proc->tsk)) {
+				return_error = BR_FAILED_REPLY;
+				goto err_binder_get_ref_for_node_failed;
+			}
 			ref = binder_get_ref_for_node(target_proc, node);
 			if (ref == NULL) {
 				return_error = BR_FAILED_REPLY;
@@ -1662,6 +1671,10 @@
 				return_error = BR_FAILED_REPLY;
 				goto err_binder_get_ref_failed;
 			}
+			if (security_binder_transfer_binder(proc->tsk, target_proc->tsk)) {
+				return_error = BR_FAILED_REPLY;
+				goto err_binder_get_ref_failed;
+			}
 			if (ref->node->proc == target_proc) {
 				if (fp->type == BINDER_TYPE_HANDLE)
 					fp->type = BINDER_TYPE_BINDER;
@@ -1715,6 +1728,11 @@
 				return_error = BR_FAILED_REPLY;
 				goto err_fget_failed;
 			}
+			if (security_binder_transfer_file(proc->tsk, target_proc->tsk, file) < 0) {
+				fput(file);
+				return_error = BR_FAILED_REPLY;
+				goto err_get_unused_fd_failed;
+			}
 			target_fd = task_get_unused_fd_flags(target_proc, O_CLOEXEC);
 			if (target_fd < 0) {
 				fput(file);
@@ -2748,6 +2766,9 @@
 			ret = -EBUSY;
 			goto err;
 		}
+		ret = security_binder_set_context_mgr(proc->tsk);
+		if (ret < 0)
+			goto err;
 		if (binder_context_mgr_uid != -1) {
 			if (binder_context_mgr_uid != current->cred->euid) {
 				binder_debug(BINDER_DEBUG_TOP_ERRORS,
diff --git a/drivers/thermal/qpnp-adc-tm.c b/drivers/thermal/qpnp-adc-tm.c
index 7dcd45f..cf1801b 100644
--- a/drivers/thermal/qpnp-adc-tm.c
+++ b/drivers/thermal/qpnp-adc-tm.c
@@ -169,6 +169,19 @@
 #define QPNP_MIN_TIME			2000
 #define QPNP_MAX_TIME			2100
 
+struct qpnp_adc_thr_client_info {
+	struct list_head		list;
+	struct qpnp_adc_tm_btm_param	*btm_param;
+	int32_t				low_thr_requested;
+	int32_t				high_thr_requested;
+	enum qpnp_state_request		state_requested;
+	enum qpnp_state_request		state_req_copy;
+	bool				low_thr_set;
+	bool				high_thr_set;
+	bool				notify_low_thr;
+	bool				notify_high_thr;
+};
+
 struct qpnp_adc_tm_sensor {
 	struct thermal_zone_device	*tz_dev;
 	struct qpnp_adc_tm_chip		*chip;
@@ -181,14 +194,13 @@
 	uint32_t			btm_channel_num;
 	uint32_t			vadc_channel_num;
 	struct work_struct		work;
-	struct qpnp_adc_tm_btm_param	*btm_param;
 	bool				thermal_node;
-	bool				low_thr_notify;
-	bool				high_thr_notify;
 	uint32_t			scale_type;
+	struct list_head		thr_list;
 };
 
 struct qpnp_adc_tm_chip {
+	struct device			*dev;
 	struct qpnp_adc_drv		*adc;
 	struct list_head		list;
 	bool				adc_tm_initialized;
@@ -202,53 +214,62 @@
 LIST_HEAD(qpnp_adc_tm_device_list);
 
 struct qpnp_adc_tm_trip_reg_type {
-	uint16_t low_thr_lsb_addr;
-	uint16_t low_thr_msb_addr;
-	uint16_t high_thr_lsb_addr;
-	uint16_t high_thr_msb_addr;
-	u8 multi_meas_en;
-	u8 low_thr_int_chan_en;
-	u8 high_thr_int_chan_en;
-	u8 meas_interval_ctl;
+	enum qpnp_adc_tm_channel_select	btm_amux_chan;
+	uint16_t			low_thr_lsb_addr;
+	uint16_t			low_thr_msb_addr;
+	uint16_t			high_thr_lsb_addr;
+	uint16_t			high_thr_msb_addr;
+	u8				multi_meas_en;
+	u8				low_thr_int_chan_en;
+	u8				high_thr_int_chan_en;
+	u8				meas_interval_ctl;
 };
 
 static struct qpnp_adc_tm_trip_reg_type adc_tm_data[] = {
-	[QPNP_ADC_TM_M0_ADC_CH_SEL_CTL] = {QPNP_M0_LOW_THR_LSB,
+	[QPNP_ADC_TM_CHAN0] = {QPNP_ADC_TM_M0_ADC_CH_SEL_CTL,
+		QPNP_M0_LOW_THR_LSB,
 		QPNP_M0_LOW_THR_MSB, QPNP_M0_HIGH_THR_LSB,
 		QPNP_M0_HIGH_THR_MSB, QPNP_ADC_TM_MULTI_MEAS_EN_M0,
 		QPNP_ADC_TM_LOW_THR_INT_EN_M0, QPNP_ADC_TM_HIGH_THR_INT_EN_M0,
 		QPNP_ADC_TM_M0_MEAS_INTERVAL_CTL},
-	[QPNP_ADC_TM_M1_ADC_CH_SEL_CTL] = {QPNP_M1_LOW_THR_LSB,
+	[QPNP_ADC_TM_CHAN1] = {QPNP_ADC_TM_M1_ADC_CH_SEL_CTL,
+		QPNP_M1_LOW_THR_LSB,
 		QPNP_M1_LOW_THR_MSB, QPNP_M1_HIGH_THR_LSB,
 		QPNP_M1_HIGH_THR_MSB, QPNP_ADC_TM_MULTI_MEAS_EN_M1,
 		QPNP_ADC_TM_LOW_THR_INT_EN_M1, QPNP_ADC_TM_HIGH_THR_INT_EN_M1,
 		QPNP_ADC_TM_M1_MEAS_INTERVAL_CTL},
-	[QPNP_ADC_TM_M2_ADC_CH_SEL_CTL] = {QPNP_M2_LOW_THR_LSB,
+	[QPNP_ADC_TM_CHAN2] = {QPNP_ADC_TM_M2_ADC_CH_SEL_CTL,
+		QPNP_M2_LOW_THR_LSB,
 		QPNP_M2_LOW_THR_MSB, QPNP_M2_HIGH_THR_LSB,
 		QPNP_M2_HIGH_THR_MSB, QPNP_ADC_TM_MULTI_MEAS_EN_M2,
 		QPNP_ADC_TM_LOW_THR_INT_EN_M2, QPNP_ADC_TM_HIGH_THR_INT_EN_M2,
 		QPNP_ADC_TM_M2_MEAS_INTERVAL_CTL},
-	[QPNP_ADC_TM_M3_ADC_CH_SEL_CTL] = {QPNP_M3_LOW_THR_LSB,
+	[QPNP_ADC_TM_CHAN3] = {QPNP_ADC_TM_M3_ADC_CH_SEL_CTL,
+		QPNP_M3_LOW_THR_LSB,
 		QPNP_M3_LOW_THR_MSB, QPNP_M3_HIGH_THR_LSB,
 		QPNP_M3_HIGH_THR_MSB, QPNP_ADC_TM_MULTI_MEAS_EN_M3,
 		QPNP_ADC_TM_LOW_THR_INT_EN_M3, QPNP_ADC_TM_HIGH_THR_INT_EN_M3,
 		QPNP_ADC_TM_M3_MEAS_INTERVAL_CTL},
-	[QPNP_ADC_TM_M4_ADC_CH_SEL_CTL] = {QPNP_M4_LOW_THR_LSB,
+	[QPNP_ADC_TM_CHAN4] = {QPNP_ADC_TM_M4_ADC_CH_SEL_CTL,
+		QPNP_M4_LOW_THR_LSB,
 		QPNP_M4_LOW_THR_MSB, QPNP_M4_HIGH_THR_LSB,
 		QPNP_M4_HIGH_THR_MSB, QPNP_ADC_TM_MULTI_MEAS_EN_M4,
 		QPNP_ADC_TM_LOW_THR_INT_EN_M4, QPNP_ADC_TM_HIGH_THR_INT_EN_M4,
 		QPNP_ADC_TM_M4_MEAS_INTERVAL_CTL},
-	[QPNP_ADC_TM_M5_ADC_CH_SEL_CTL] = {QPNP_M5_LOW_THR_LSB,
+	[QPNP_ADC_TM_CHAN5] = {QPNP_ADC_TM_M5_ADC_CH_SEL_CTL,
+		QPNP_M5_LOW_THR_LSB,
 		QPNP_M5_LOW_THR_MSB, QPNP_M5_HIGH_THR_LSB,
 		QPNP_M5_HIGH_THR_MSB, QPNP_ADC_TM_MULTI_MEAS_EN_M5,
 		QPNP_ADC_TM_LOW_THR_INT_EN_M5, QPNP_ADC_TM_HIGH_THR_INT_EN_M5,
 		QPNP_ADC_TM_M5_MEAS_INTERVAL_CTL},
-	[QPNP_ADC_TM_M6_ADC_CH_SEL_CTL] = {QPNP_M6_LOW_THR_LSB,
+	[QPNP_ADC_TM_CHAN6] = {QPNP_ADC_TM_M6_ADC_CH_SEL_CTL,
+		QPNP_M6_LOW_THR_LSB,
 		QPNP_M6_LOW_THR_MSB, QPNP_M6_HIGH_THR_LSB,
 		QPNP_M6_HIGH_THR_MSB, QPNP_ADC_TM_MULTI_MEAS_EN_M6,
 		QPNP_ADC_TM_LOW_THR_INT_EN_M6, QPNP_ADC_TM_HIGH_THR_INT_EN_M6,
 		QPNP_ADC_TM_M6_MEAS_INTERVAL_CTL},
-	[QPNP_ADC_TM_M7_ADC_CH_SEL_CTL] = {QPNP_M7_LOW_THR_LSB,
+	[QPNP_ADC_TM_CHAN7] = {QPNP_ADC_TM_M7_ADC_CH_SEL_CTL,
+		QPNP_M7_LOW_THR_LSB,
 		QPNP_M7_LOW_THR_MSB, QPNP_M7_HIGH_THR_LSB,
 		QPNP_M7_HIGH_THR_MSB, QPNP_ADC_TM_MULTI_MEAS_EN_M7,
 		QPNP_ADC_TM_LOW_THR_INT_EN_M7, QPNP_ADC_TM_HIGH_THR_INT_EN_M7,
@@ -384,6 +405,25 @@
 	return rc;
 }
 
+static int32_t qpnp_adc_tm_get_btm_idx(uint32_t btm_chan,
+						uint32_t *btm_chan_idx)
+{
+	int rc = 0, i;
+	bool chan_found = false;
+
+	for (i = 0; i < QPNP_ADC_TM_CHAN_NONE; i++) {
+		if (adc_tm_data[i].btm_amux_chan == btm_chan) {
+			*btm_chan_idx = i;
+			chan_found = true;
+		}
+	}
+
+	if (!chan_found)
+		return -EINVAL;
+
+	return rc;
+}
+
 static int32_t qpnp_adc_tm_check_revision(struct qpnp_adc_tm_chip *chip,
 							uint32_t btm_chan_num)
 {
@@ -433,6 +473,7 @@
 {
 	int rc;
 	u8 meas_interval_timer2 = 0;
+	uint32_t btm_chan_idx = 0;
 
 	/* Configure kernel clients to timer1 */
 	switch (chan_prop->timer_select) {
@@ -489,11 +530,60 @@
 	}
 
 	/* Select the timer to use for the corresponding channel */
-	adc_tm_data[btm_chan].meas_interval_ctl = chan_prop->timer_select;
+	rc = qpnp_adc_tm_get_btm_idx(btm_chan, &btm_chan_idx);
+	if (rc < 0) {
+		pr_err("Invalid btm channel idx\n");
+		return rc;
+	}
+	adc_tm_data[btm_chan_idx].meas_interval_ctl = chan_prop->timer_select;
 
 	return rc;
 }
 
+static int32_t qpnp_adc_tm_add_to_list(struct qpnp_adc_tm_chip *chip,
+				uint32_t dt_index,
+				struct qpnp_adc_tm_btm_param *param,
+				struct qpnp_vadc_chan_properties *chan_prop)
+{
+	struct qpnp_adc_thr_client_info *client_info = NULL;
+	bool client_info_exists = false;
+
+	list_for_each_entry(client_info,
+			&chip->sensor[dt_index].thr_list, list) {
+		if (client_info->btm_param == param) {
+			client_info->low_thr_requested = chan_prop->low_thr;
+			client_info->high_thr_requested = chan_prop->high_thr;
+			client_info->state_requested = param->state_request;
+			client_info->state_req_copy = param->state_request;
+			client_info->notify_low_thr = false;
+			client_info->notify_high_thr = false;
+			client_info_exists = true;
+			pr_debug("client found\n");
+		}
+	}
+
+	if (!client_info_exists) {
+		client_info = devm_kzalloc(chip->dev,
+			sizeof(struct qpnp_adc_thr_client_info), GFP_KERNEL);
+		if (!client_info) {
+			pr_err("%s: kzalloc() failed.\n", __func__);
+			return -ENOMEM;
+		}
+
+		pr_debug("new client\n");
+		client_info->btm_param = param;
+		client_info->low_thr_requested = chan_prop->low_thr;
+		client_info->high_thr_requested = chan_prop->high_thr;
+		client_info->state_requested = param->state_request;
+		client_info->state_req_copy = param->state_request;
+
+		list_add_tail(&client_info->list,
+					&chip->sensor[dt_index].thr_list);
+	}
+
+	return 0;
+}
+
 static int32_t qpnp_adc_tm_reg_update(struct qpnp_adc_tm_chip *chip,
 		uint16_t addr, u8 mask, bool state)
 {
@@ -522,55 +612,137 @@
 }
 
 static int32_t qpnp_adc_tm_thr_update(struct qpnp_adc_tm_chip *chip,
-			uint32_t btm_chan,
-			struct qpnp_vadc_chan_properties *chan_prop)
+			uint32_t btm_chan, int32_t high_thr, int32_t low_thr)
 {
 	int rc = 0;
+	uint32_t btm_chan_idx = 0;
+
+	rc = qpnp_adc_tm_get_btm_idx(btm_chan, &btm_chan_idx);
+	if (rc < 0) {
+		pr_err("Invalid btm channel idx\n");
+		return rc;
+	}
 
 	rc = qpnp_adc_tm_write_reg(chip,
-			adc_tm_data[btm_chan].low_thr_lsb_addr,
-			QPNP_ADC_TM_THR_LSB_MASK(chan_prop->low_thr));
+			adc_tm_data[btm_chan_idx].low_thr_lsb_addr,
+			QPNP_ADC_TM_THR_LSB_MASK(low_thr));
 	if (rc < 0) {
 		pr_err("low threshold lsb setting failed\n");
 		return rc;
 	}
 
 	rc = qpnp_adc_tm_write_reg(chip,
-		adc_tm_data[btm_chan].low_thr_msb_addr,
-		QPNP_ADC_TM_THR_MSB_MASK(chan_prop->low_thr));
+		adc_tm_data[btm_chan_idx].low_thr_msb_addr,
+		QPNP_ADC_TM_THR_MSB_MASK(low_thr));
 	if (rc < 0) {
 		pr_err("low threshold msb setting failed\n");
 		return rc;
 	}
 
 	rc = qpnp_adc_tm_write_reg(chip,
-		adc_tm_data[btm_chan].high_thr_lsb_addr,
-		QPNP_ADC_TM_THR_LSB_MASK(chan_prop->high_thr));
+		adc_tm_data[btm_chan_idx].high_thr_lsb_addr,
+		QPNP_ADC_TM_THR_LSB_MASK(high_thr));
 	if (rc < 0) {
 		pr_err("high threshold lsb setting failed\n");
 		return rc;
 	}
 
 	rc = qpnp_adc_tm_write_reg(chip,
-		adc_tm_data[btm_chan].high_thr_msb_addr,
-		QPNP_ADC_TM_THR_MSB_MASK(chan_prop->high_thr));
+		adc_tm_data[btm_chan_idx].high_thr_msb_addr,
+		QPNP_ADC_TM_THR_MSB_MASK(high_thr));
 	if (rc < 0)
 		pr_err("high threshold msb setting failed\n");
 
-	pr_debug("client requested low:%d and high:%d\n",
-		chan_prop->low_thr, chan_prop->high_thr);
+	pr_debug("client requested high:%d and low:%d\n",
+		high_thr, low_thr);
 
 	return rc;
 }
 
+static int32_t qpnp_adc_tm_manage_thresholds(struct qpnp_adc_tm_chip *chip,
+		uint32_t dt_index, uint32_t btm_chan)
+{
+	struct qpnp_adc_thr_client_info *client_info = NULL;
+	struct list_head *thr_list;
+	int high_thr = 0, low_thr = 0, rc = 0;
+
+
+	/* high_thr/low_thr starting point and reset the high_thr_set and
+		low_thr_set back to reset since the thresholds will be
+		recomputed */
+	list_for_each(thr_list,
+			&chip->sensor[dt_index].thr_list) {
+		client_info = list_entry(thr_list,
+					struct qpnp_adc_thr_client_info, list);
+		high_thr = client_info->high_thr_requested;
+		low_thr = client_info->low_thr_requested;
+		client_info->high_thr_set = false;
+		client_info->low_thr_set = false;
+	}
+
+	pr_debug("init threshold is high:%d and low:%d\n", high_thr, low_thr);
+
+	/* Find the min of high_thr and max of low_thr */
+	list_for_each(thr_list,
+			&chip->sensor[dt_index].thr_list) {
+		client_info = list_entry(thr_list,
+					struct qpnp_adc_thr_client_info, list);
+		if ((client_info->state_req_copy == ADC_TM_HIGH_THR_ENABLE) ||
+			(client_info->state_req_copy ==
+						ADC_TM_HIGH_LOW_THR_ENABLE))
+			if (client_info->high_thr_requested < high_thr)
+				high_thr = client_info->high_thr_requested;
+
+		if ((client_info->state_req_copy == ADC_TM_LOW_THR_ENABLE) ||
+			(client_info->state_req_copy ==
+						ADC_TM_HIGH_LOW_THR_ENABLE))
+			if (client_info->low_thr_requested > low_thr)
+				low_thr = client_info->low_thr_requested;
+
+		pr_debug("threshold compared is high:%d and low:%d\n",
+				client_info->high_thr_requested,
+				client_info->low_thr_requested);
+		pr_debug("current threshold is high:%d and low:%d\n",
+							high_thr, low_thr);
+	}
+
+	/* Check which of the high_thr and low_thr got set */
+	list_for_each(thr_list,
+			&chip->sensor[dt_index].thr_list) {
+		client_info = list_entry(thr_list,
+					struct qpnp_adc_thr_client_info, list);
+		if ((client_info->state_req_copy == ADC_TM_HIGH_THR_ENABLE) ||
+			(client_info->state_req_copy ==
+						ADC_TM_HIGH_LOW_THR_ENABLE))
+			if (high_thr == client_info->high_thr_requested)
+				client_info->high_thr_set = true;
+
+		if ((client_info->state_req_copy == ADC_TM_LOW_THR_ENABLE) ||
+			(client_info->state_req_copy ==
+						ADC_TM_HIGH_LOW_THR_ENABLE))
+			if (low_thr == client_info->low_thr_requested)
+				client_info->low_thr_set = true;
+	}
+
+	rc = qpnp_adc_tm_thr_update(chip, btm_chan, high_thr, low_thr);
+	if (rc < 0)
+		pr_err("setting chan:%d threshold failed\n", btm_chan);
+
+	pr_debug("threshold written is high:%d and low:%d\n",
+							high_thr, low_thr);
+
+	return 0;
+}
+
 static int32_t qpnp_adc_tm_channel_configure(struct qpnp_adc_tm_chip *chip,
 			uint32_t btm_chan,
 			struct qpnp_vadc_chan_properties *chan_prop,
 			uint32_t amux_channel)
 {
 	int rc = 0, i = 0, chan_idx = 0;
-	bool chan_found = false;
+	bool chan_found = false, high_thr_set = false, low_thr_set = false;
 	u8 sensor_mask = 0;
+	struct qpnp_adc_thr_client_info *client_info = NULL;
 
 	while (i < chip->max_channels_available) {
 		if (chip->sensor[i].btm_channel_num == btm_chan) {
@@ -589,17 +761,22 @@
 	sensor_mask = 1 << chan_idx;
 	if (!chip->sensor[chan_idx].thermal_node) {
 		/* Update low and high notification thresholds */
-		rc = qpnp_adc_tm_thr_update(chip, btm_chan,
-				chan_prop);
+		rc = qpnp_adc_tm_manage_thresholds(chip, chan_idx,
+				btm_chan);
 		if (rc < 0) {
 			pr_err("setting chan:%d threshold failed\n", btm_chan);
 			return rc;
 		}
 
-		if ((chan_prop->state_request ==
-					ADC_TM_LOW_THR_ENABLE) ||
-			(chan_prop->state_request ==
-					ADC_TM_HIGH_LOW_THR_ENABLE)) {
+		list_for_each_entry(client_info,
+				&chip->sensor[chan_idx].thr_list, list) {
+			if (client_info->high_thr_set == true)
+				high_thr_set = true;
+			if (client_info->low_thr_set == true)
+				low_thr_set = true;
+		}
+
+		if (low_thr_set) {
 			pr_debug("low sensor mask:%x with state:%d\n",
 					sensor_mask, chan_prop->state_request);
 			/* Enable low threshold's interrupt */
@@ -611,10 +788,7 @@
 			}
 		}
 
-		if ((chan_prop->state_request ==
-					ADC_TM_HIGH_THR_ENABLE) ||
-			(chan_prop->state_request ==
-					ADC_TM_HIGH_LOW_THR_ENABLE)) {
+		if (high_thr_set) {
 			/* Enable high threshold's interrupt */
 			pr_debug("high sensor mask:%x\n", sensor_mask);
 			rc = qpnp_adc_tm_reg_update(chip,
@@ -760,8 +934,10 @@
 	int rc = 0, channel;
 	u8 sensor_mask = 0;
 
-	if (qpnp_adc_tm_is_valid(chip))
+	if (qpnp_adc_tm_is_valid(chip)) {
+		pr_err("invalid device\n");
 		return -ENODEV;
+	}
 
 	if (qpnp_adc_tm_check_revision(chip, adc_tm->btm_channel_num))
 		return -EINVAL;
@@ -860,9 +1036,10 @@
 	struct qpnp_adc_tm_chip *chip = adc_tm_sensor->chip;
 	int64_t result = 0;
 	u8 trip_cool_thr0, trip_cool_thr1, trip_warm_thr0, trip_warm_thr1;
-	unsigned int reg, rc = 0, btm_channel_num;
+	unsigned int reg, rc = 0;
 	uint16_t reg_low_thr_lsb, reg_low_thr_msb;
 	uint16_t reg_high_thr_lsb, reg_high_thr_msb;
+	uint32_t btm_chan_idx = 0, btm_chan = 0;
 
 	if (qpnp_adc_tm_is_valid(chip))
 		return -ENODEV;
@@ -870,11 +1047,17 @@
 	if (qpnp_adc_tm_check_revision(chip, adc_tm_sensor->btm_channel_num))
 		return -EINVAL;
 
-	btm_channel_num = adc_tm_sensor->btm_channel_num;
-	reg_low_thr_lsb = adc_tm_data[btm_channel_num].low_thr_lsb_addr;
-	reg_low_thr_msb = adc_tm_data[btm_channel_num].low_thr_msb_addr;
-	reg_high_thr_lsb = adc_tm_data[btm_channel_num].high_thr_lsb_addr;
-	reg_high_thr_msb = adc_tm_data[btm_channel_num].high_thr_msb_addr;
+	btm_chan = adc_tm_sensor->btm_channel_num;
+	rc = qpnp_adc_tm_get_btm_idx(btm_chan, &btm_chan_idx);
+	if (rc < 0) {
+		pr_err("Invalid btm channel idx\n");
+		return rc;
+	}
+
+	reg_low_thr_lsb = adc_tm_data[btm_chan_idx].low_thr_lsb_addr;
+	reg_low_thr_msb = adc_tm_data[btm_chan_idx].low_thr_msb_addr;
+	reg_high_thr_lsb = adc_tm_data[btm_chan_idx].high_thr_lsb_addr;
+	reg_high_thr_msb = adc_tm_data[btm_chan_idx].high_thr_msb_addr;
 
 	switch (trip) {
 	case ADC_TM_TRIP_HIGH_WARM:
@@ -934,7 +1117,8 @@
 	u8 trip_cool_thr0, trip_cool_thr1, trip_warm_thr0, trip_warm_thr1;
 	uint16_t reg_low_thr_lsb, reg_low_thr_msb;
 	uint16_t reg_high_thr_lsb, reg_high_thr_msb;
-	int rc = 0, btm_channel_num;
+	int rc = 0;
+	uint32_t btm_chan = 0, btm_chan_idx = 0;
 
 	if (qpnp_adc_tm_is_valid(chip))
 		return -ENODEV;
@@ -967,11 +1151,17 @@
 	trip_cool_thr0 = ((tm_config.high_thr_voltage << 24) >> 24);
 	trip_cool_thr1 = ((tm_config.high_thr_voltage << 16) >> 24);
 
-	btm_channel_num = adc_tm->btm_channel_num;
-	reg_low_thr_lsb = adc_tm_data[btm_channel_num].low_thr_lsb_addr;
-	reg_low_thr_msb = adc_tm_data[btm_channel_num].low_thr_msb_addr;
-	reg_high_thr_lsb = adc_tm_data[btm_channel_num].high_thr_lsb_addr;
-	reg_high_thr_msb = adc_tm_data[btm_channel_num].high_thr_msb_addr;
+	btm_chan = adc_tm->btm_channel_num;
+	rc = qpnp_adc_tm_get_btm_idx(btm_chan, &btm_chan_idx);
+	if (rc < 0) {
+		pr_err("Invalid btm channel idx\n");
+		return rc;
+	}
+
+	reg_low_thr_lsb = adc_tm_data[btm_chan_idx].low_thr_lsb_addr;
+	reg_low_thr_msb = adc_tm_data[btm_chan_idx].low_thr_msb_addr;
+	reg_high_thr_lsb = adc_tm_data[btm_chan_idx].high_thr_lsb_addr;
+	reg_high_thr_msb = adc_tm_data[btm_chan_idx].high_thr_msb_addr;
 
 	switch (trip) {
 	case ADC_TM_TRIP_HIGH_WARM:
@@ -1015,20 +1205,25 @@
 
 static void notify_battery_therm(struct qpnp_adc_tm_sensor *adc_tm)
 {
-	/* Battery therm's warm temperature translates to low voltage */
-	if (adc_tm->low_thr_notify) {
-		/* HIGH_STATE = WARM_TEMP for battery client */
-		adc_tm->btm_param->threshold_notification(
-		ADC_TM_WARM_STATE, adc_tm->btm_param->btm_ctx);
-		adc_tm->low_thr_notify = false;
-	}
+	struct qpnp_adc_thr_client_info *client_info = NULL;
 
-	/* Battery therm's cool temperature translates to high voltage */
-	if (adc_tm->high_thr_notify) {
-		/* LOW_STATE = COOL_TEMP for battery client */
-		adc_tm->btm_param->threshold_notification(
-		ADC_TM_COOL_STATE, adc_tm->btm_param->btm_ctx);
-		adc_tm->high_thr_notify = false;
+	list_for_each_entry(client_info,
+			&adc_tm->thr_list, list) {
+		/* Batt therm's warm temperature translates to low voltage */
+		if (client_info->notify_low_thr) {
+			/* HIGH_STATE = WARM_TEMP for battery client */
+			client_info->btm_param->threshold_notification(
+			ADC_TM_WARM_STATE, client_info->btm_param->btm_ctx);
+			client_info->notify_low_thr = false;
+		}
+
+		/* Batt therm's cool temperature translates to high voltage */
+		if (client_info->notify_high_thr) {
+			/* LOW_STATE = COOL_TEMP for battery client */
+			client_info->btm_param->threshold_notification(
+			ADC_TM_COOL_STATE, client_info->btm_param->btm_ctx);
+			client_info->notify_high_thr = false;
+		}
 	}
 
 	return;
@@ -1036,19 +1231,32 @@
 
 static void notify_clients(struct qpnp_adc_tm_sensor *adc_tm)
 {
-	/* For non batt therm clients */
-	if (adc_tm->low_thr_notify) {
-		pr_debug("notify kernel with low state\n");
-		adc_tm->btm_param->threshold_notification(
-		ADC_TM_LOW_STATE, adc_tm->btm_param->btm_ctx);
-		adc_tm->low_thr_notify = false;
-	}
+	struct qpnp_adc_thr_client_info *client_info = NULL;
 
-	if (adc_tm->high_thr_notify) {
-		pr_debug("notify kernel with high state\n");
-		adc_tm->btm_param->threshold_notification(
-		ADC_TM_HIGH_STATE, adc_tm->btm_param->btm_ctx);
-		adc_tm->high_thr_notify = false;
+	list_for_each_entry(client_info,
+			&adc_tm->thr_list, list) {
+		/* For non batt therm clients */
+		if (client_info->notify_low_thr) {
+			if (client_info->btm_param->threshold_notification
+								!= NULL) {
+				pr_debug("notify kernel with low state\n");
+				client_info->btm_param->threshold_notification(
+					ADC_TM_LOW_STATE,
+					client_info->btm_param->btm_ctx);
+				client_info->notify_low_thr = false;
+			}
+		}
+
+		if (client_info->notify_high_thr) {
+			if (client_info->btm_param->threshold_notification
+								!= NULL) {
+				pr_debug("notify kernel with high state\n");
+				client_info->btm_param->threshold_notification(
+					ADC_TM_HIGH_STATE,
+					client_info->btm_param->btm_ctx);
+				client_info->notify_high_thr = false;
+			}
+		}
 	}
 
 	return;
@@ -1064,12 +1272,10 @@
 					NULL, "btm");
 		pr_debug("notifying uspace client\n");
 	} else {
-		if (adc_tm->btm_param->threshold_notification != NULL) {
-			if (adc_tm->scale_type == SCALE_RBATT_THERM)
-				notify_battery_therm(adc_tm);
-			else
-				notify_clients(adc_tm);
-		}
+		if (adc_tm->scale_type == SCALE_RBATT_THERM)
+			notify_battery_therm(adc_tm);
+		else
+			notify_clients(adc_tm);
 	}
 
 	return;
@@ -1083,6 +1289,7 @@
 	int rc = 0, sensor_mask = 0;
 	u8 thr_int_en = 0;
 	bool state = false;
+	uint32_t btm_chan_idx = 0, btm_chan = 0;
 
 	if (qpnp_adc_tm_is_valid(chip))
 		return -ENODEV;
@@ -1097,24 +1304,29 @@
 
 	pr_debug("Sensor number:%x with state:%d\n", adc_tm->sensor_num, state);
 
+	btm_chan = adc_tm->btm_channel_num;
+	rc = qpnp_adc_tm_get_btm_idx(btm_chan, &btm_chan_idx);
+	if (rc < 0) {
+		pr_err("Invalid btm channel idx\n");
+		return rc;
+	}
+
 	switch (trip) {
 	case ADC_TM_TRIP_HIGH_WARM:
 		/* low_thr (lower voltage) for higher temp */
-		thr_int_en = adc_tm_data[adc_tm->btm_channel_num].
-							low_thr_int_chan_en;
+		thr_int_en = adc_tm_data[btm_chan_idx].low_thr_int_chan_en;
 		rc = qpnp_adc_tm_reg_update(chip, QPNP_ADC_TM_LOW_THR_INT_EN,
 				sensor_mask, state);
 		if (rc)
-			pr_err("channel:%x failed\n", adc_tm->btm_channel_num);
+			pr_err("channel:%x failed\n", btm_chan);
 	break;
 	case ADC_TM_TRIP_LOW_COOL:
 		/* high_thr (higher voltage) for cooler temp */
-		thr_int_en = adc_tm_data[adc_tm->btm_channel_num].
-							high_thr_int_chan_en;
+		thr_int_en = adc_tm_data[btm_chan_idx].high_thr_int_chan_en;
 		rc = qpnp_adc_tm_reg_update(chip, QPNP_ADC_TM_HIGH_THR_INT_EN,
 				sensor_mask, state);
 		if (rc)
-			pr_err("channel:%x failed\n", adc_tm->btm_channel_num);
+			pr_err("channel:%x failed\n", btm_chan);
 	break;
 	default:
 		return -EINVAL;
@@ -1128,7 +1340,10 @@
 	u8 status_low = 0, status_high = 0, qpnp_adc_tm_meas_en = 0;
 	u8 adc_tm_low_enable = 0, adc_tm_high_enable = 0;
 	u8 sensor_mask = 0;
-	int rc = 0, sensor_notify_num = 0, i = 0, sensor_num = 0, btm_chan_num;
+	int rc = 0, sensor_notify_num = 0, i = 0, sensor_num = 0;
+	uint32_t btm_chan_num = 0;
+	struct qpnp_adc_thr_client_info *client_info = NULL;
+	struct list_head *thr_list;
 
 	if (qpnp_adc_tm_is_valid(chip))
 		return -ENODEV;
@@ -1190,7 +1405,6 @@
 				pr_err("high threshold int read failed\n");
 				goto fail;
 			}
-			chip->sensor[sensor_num].high_thr_notify = true;
 		} else {
 			/* Uses the thermal sysfs registered device to disable
 				the corresponding high voltage threshold which
@@ -1205,6 +1419,21 @@
 				goto fail;
 			}
 		}
+		list_for_each(thr_list, &chip->sensor[sensor_num].thr_list) {
+			client_info = list_entry(thr_list,
+					struct qpnp_adc_thr_client_info, list);
+			if (client_info->high_thr_set) {
+				client_info->high_thr_set = false;
+				client_info->notify_high_thr = true;
+				if (client_info->state_req_copy ==
+						ADC_TM_HIGH_LOW_THR_ENABLE)
+					client_info->state_req_copy =
+							ADC_TM_LOW_THR_ENABLE;
+				else
+					client_info->state_req_copy =
+							ADC_TM_HIGH_THR_DISABLE;
+			}
+		}
 	}
 
 	if (adc_tm_low_enable) {
@@ -1233,7 +1462,6 @@
 				pr_err("low threshold int read failed\n");
 				goto fail;
 			}
-			chip->sensor[sensor_num].low_thr_notify = true;
 		} else {
 			/* Uses the thermal sysfs registered device to disable
 				the corresponding low voltage threshold which
@@ -1248,8 +1476,27 @@
 				goto fail;
 			}
 		}
+		list_for_each(thr_list, &chip->sensor[sensor_num].thr_list) {
+			client_info = list_entry(thr_list,
+					struct qpnp_adc_thr_client_info, list);
+			if (client_info->low_thr_set) {
+				/* mark the corresponding clients threshold
+					as not set */
+				client_info->low_thr_set = false;
+				client_info->notify_low_thr = true;
+				if (client_info->state_req_copy ==
+						ADC_TM_HIGH_LOW_THR_ENABLE)
+					client_info->state_req_copy =
+							ADC_TM_HIGH_THR_ENABLE;
+				else
+					client_info->state_req_copy =
+							ADC_TM_LOW_THR_DISABLE;
+			}
+		}
 	}
 
+	qpnp_adc_tm_manage_thresholds(chip, sensor_num, btm_chan_num);
+
 	if (adc_tm_high_enable || adc_tm_low_enable) {
 		rc = qpnp_adc_tm_reg_update(chip, QPNP_ADC_TM_MULTI_MEAS_EN,
 			sensor_mask, false);
@@ -1359,8 +1606,10 @@
 	int rc = 0, i = 0;
 	bool chan_found = false;
 
-	if (qpnp_adc_tm_is_valid(chip))
+	if (qpnp_adc_tm_is_valid(chip)) {
+		pr_err("chip not valid\n");
 		return -ENODEV;
+	}
 
 	if (param->threshold_notification == NULL) {
 		pr_debug("No notification for high/low temp??\n");
@@ -1413,6 +1662,8 @@
 	adc_tm_rscale_fn[scale_type].chan(chip->vadc_dev, param,
 			&chip->adc->amux_prop->chan_prop->low_thr,
 			&chip->adc->amux_prop->chan_prop->high_thr);
+	qpnp_adc_tm_add_to_list(chip, dt_index, param,
+				chip->adc->amux_prop->chan_prop);
 	chip->adc->amux_prop->chan_prop->tm_channel_select =
 				chip->sensor[dt_index].btm_channel_num;
 	chip->adc->amux_prop->chan_prop->timer_select =
@@ -1425,7 +1676,6 @@
 		goto fail_unlock;
 	}
 
-	chip->sensor[dt_index].btm_param = param;
 	chip->sensor[dt_index].scale_type = scale_type;
 
 fail_unlock:
@@ -1577,6 +1827,7 @@
 		goto fail;
 	}
 
+	chip->dev = &(spmi->dev);
 	chip->adc = adc_qpnp;
 
 	rc = qpnp_adc_get_devicetree_data(spmi, chip->adc);
@@ -1652,6 +1903,7 @@
 				pr_err("thermal device register failed.\n");
 		}
 		INIT_WORK(&chip->sensor[sen_idx].work, notify_adc_tm_fn);
+		INIT_LIST_HEAD(&chip->sensor[sen_idx].thr_list);
 		sen_idx++;
 	}
 	chip->max_channels_available = count_adc_channel_list;
diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c
index 94b6eda..8eb5573 100644
--- a/drivers/tty/n_tty.c
+++ b/drivers/tty/n_tty.c
@@ -81,20 +81,31 @@
 }
 
 /**
- *	n_tty_set__room	-	receive space
+ *	n_tty_set_room	-	receive space
  *	@tty: terminal
  *
- *	Called by the driver to find out how much data it is
- *	permitted to feed to the line discipline without any being lost
- *	and thus to manage flow control. Not serialized. Answers for the
- *	"instant".
+ *	Sets tty->receive_room to reflect the currently available space
+ *	in the input buffer, and re-schedules the flip buffer work if space
+ *	just became available.
+ *
+ *	Locks: Concurrent update is protected with read_lock
  */
 
 static void n_tty_set_room(struct tty_struct *tty)
 {
-	/* tty->read_cnt is not read locked ? */
-	int	left = N_TTY_BUF_SIZE - tty->read_cnt - 1;
+	int left;
 	int old_left;
+	unsigned long flags;
+
+	spin_lock_irqsave(&tty->read_lock, flags);
+
+	if (I_PARMRK(tty)) {
+		/* Multiply read_cnt by 3, since each byte might take up to
+		 * three times as many spaces when PARMRK is set (depending on
+		 * its flags, e.g. parity error). */
+		left = N_TTY_BUF_SIZE - tty->read_cnt * 3 - 1;
+	} else
+		left = N_TTY_BUF_SIZE - tty->read_cnt - 1;
 
 	/*
 	 * If we are doing input canonicalization, and there are no
@@ -107,6 +118,8 @@
 	old_left = tty->receive_room;
 	tty->receive_room = left;
 
+	spin_unlock_irqrestore(&tty->read_lock, flags);
+
 	/* Did this open up the receive buffer? We may need to flip */
 	if (left && !old_left)
 		schedule_work(&tty->buf.work);
@@ -1811,7 +1824,6 @@
 				retval = -ERESTARTSYS;
 				break;
 			}
-			/* FIXME: does n_tty_set_room need locking ? */
 			n_tty_set_room(tty);
 			timeout = schedule_timeout(timeout);
 			BUG_ON(!tty->read_buf);
diff --git a/drivers/tty/tty_buffer.c b/drivers/tty/tty_buffer.c
index 81bc0f0..24b18cb 100644
--- a/drivers/tty/tty_buffer.c
+++ b/drivers/tty/tty_buffer.c
@@ -463,8 +463,6 @@
 			int count;
 			char *char_buf;
 			unsigned char *flag_buf;
-			unsigned int left = 0;
-			unsigned int max_space;
 
 			count = head->commit - head->read;
 			if (!count) {
@@ -475,32 +473,10 @@
 				continue;
 			}
 
-			/* update receive room */
-			spin_lock(&tty->read_lock);
-			if (tty->update_room_in_ldisc) {
-				if ((tty->read_cnt == N_TTY_BUF_SIZE - 1) &&
-					(tty->receive_room ==
-						N_TTY_BUF_SIZE - 1))
-					tty->rr_bug++;
-				left = N_TTY_BUF_SIZE - tty->read_cnt - 1;
-			}
-			spin_unlock(&tty->read_lock);
-
 			if (!tty->receive_room)
 				break;
-
-			if (tty->update_room_in_ldisc && !left) {
-				schedule_work(&tty->buf.work);
-				break;
-			}
-
-			if (tty->update_room_in_ldisc)
-				max_space = min(left, tty->receive_room);
-			else
-				max_space = tty->receive_room;
-
-			if (count > max_space)
-				count = max_space;
+			if (count > tty->receive_room)
+				count = tty->receive_room;
 			char_buf = head->char_buf_ptr + head->read;
 			flag_buf = head->flag_buf_ptr + head->read;
 			head->read += count;
diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c
index f43affb..60d7119 100644
--- a/drivers/usb/dwc3/dwc3-msm.c
+++ b/drivers/usb/dwc3/dwc3-msm.c
@@ -201,6 +201,7 @@
 	bool			lpm_irq_seen;
 	struct delayed_work	resume_work;
 	struct work_struct	restart_usb_work;
+	struct work_struct	usb_block_reset_work;
 	struct dwc3_charger	charger;
 	struct usb_phy		*otg_xceiv;
 	struct delayed_work	chg_work;
@@ -1495,6 +1496,11 @@
 	case DWC3_CONTROLLER_ERROR_EVENT:
 		dev_info(mdwc->dev, "DWC3_CONTROLLER_ERROR_EVENT received\n");
 		dwc3_msm_dump_phy_info(mdwc);
+		/*
+		 * schedule work for doing block reset for recovery from erratic
+		 * error event.
+		 */
+		queue_work(system_nrt_wq, &mdwc->usb_block_reset_work);
 		break;
 	case DWC3_CONTROLLER_RESET_EVENT:
 		dev_dbg(mdwc->dev, "DWC3_CONTROLLER_RESET_EVENT received\n");
@@ -1537,6 +1543,16 @@
 	dwc3_msm_dbm_soft_reset(mdwc, 0);
 }
 
+static void dwc3_block_reset_usb_work(struct work_struct *w)
+{
+	struct dwc3_msm *mdwc = container_of(w, struct dwc3_msm,
+						usb_block_reset_work);
+
+	dev_dbg(mdwc->dev, "%s\n", __func__);
+
+	dwc3_msm_block_reset(&mdwc->ext_xceiv, true);
+}
+
 static void dwc3_chg_enable_secondary_det(struct dwc3_msm *mdwc)
 {
 	u32 chg_ctrl;
@@ -2692,6 +2708,7 @@
 	INIT_DELAYED_WORK(&mdwc->chg_work, dwc3_chg_detect_work);
 	INIT_DELAYED_WORK(&mdwc->resume_work, dwc3_resume_work);
 	INIT_WORK(&mdwc->restart_usb_work, dwc3_restart_usb_work);
+	INIT_WORK(&mdwc->usb_block_reset_work, dwc3_block_reset_usb_work);
 	INIT_WORK(&mdwc->id_work, dwc3_id_work);
 	INIT_DELAYED_WORK(&mdwc->init_adc_work, dwc3_init_adc_work);
 	init_completion(&mdwc->ext_chg_wait);
diff --git a/drivers/usb/dwc3/dwc3_otg.c b/drivers/usb/dwc3/dwc3_otg.c
index e912e86..5348eb5 100644
--- a/drivers/usb/dwc3/dwc3_otg.c
+++ b/drivers/usb/dwc3/dwc3_otg.c
@@ -24,6 +24,7 @@
 #include "io.h"
 #include "xhci.h"
 
+#define VBUS_REG_CHECK_DELAY	(jiffies + msecs_to_jiffies(1000))
 #define MAX_INVALID_CHRGR_RETRY 3
 static int max_chgr_retry_count = MAX_INVALID_CHRGR_RETRY;
 module_param(max_chgr_retry_count, int, S_IRUGO | S_IWUSR);
@@ -336,13 +337,13 @@
 		dev_dbg(otg->phy->dev, "%s: set gadget %s\n",
 					__func__, gadget->name);
 		otg->gadget = gadget;
-		schedule_work(&dotg->sm_work);
+		queue_delayed_work(system_nrt_wq, &dotg->sm_work, 0);
 	} else {
 		if (otg->phy->state == OTG_STATE_B_PERIPHERAL) {
 			dwc3_otg_start_peripheral(otg, 0);
 			otg->gadget = NULL;
 			otg->phy->state = OTG_STATE_UNDEFINED;
-			schedule_work(&dotg->sm_work);
+			queue_delayed_work(system_nrt_wq, &dotg->sm_work, 0);
 		} else {
 			otg->gadget = NULL;
 		}
@@ -367,7 +368,7 @@
 	 * STOP chg_det as part of !BSV handling would reset the chg_det flags
 	 */
 	if (test_bit(B_SESS_VLD, &dotg->inputs))
-		schedule_work(&dotg->sm_work);
+		queue_delayed_work(system_nrt_wq, &dotg->sm_work, 0);
 }
 
 /**
@@ -406,7 +407,7 @@
 
 	/* Flush processing any pending events before handling new ones */
 	if (init)
-		flush_work(&dotg->sm_work);
+		flush_delayed_work(&dotg->sm_work);
 
 	if (event == DWC3_EVENT_PHY_RESUME) {
 		if (!pm_runtime_status_suspended(phy->dev)) {
@@ -453,15 +454,16 @@
 
 		if (!init) {
 			init = true;
-			if (!work_busy(&dotg->sm_work))
-				schedule_work(&dotg->sm_work);
+			if (!work_busy(&dotg->sm_work.work))
+				queue_delayed_work(system_nrt_wq,
+							&dotg->sm_work, 0);
 
 			complete(&dotg->dwc3_xcvr_vbus_init);
 			dev_dbg(phy->dev, "XCVR: BSV init complete\n");
 			return;
 		}
 
-		schedule_work(&dotg->sm_work);
+		queue_delayed_work(system_nrt_wq, &dotg->sm_work, 0);
 	}
 }
 
@@ -610,7 +612,7 @@
 			handled_irqs |= DWC3_OEVTEN_OTGBDEVVBUSCHNGEVNT;
 		}
 
-		schedule_work(&dotg->sm_work);
+		queue_delayed_work(system_nrt_wq, &dotg->sm_work, 0);
 
 		ret = IRQ_HANDLED;
 
@@ -671,10 +673,12 @@
  */
 static void dwc3_otg_sm_work(struct work_struct *w)
 {
-	struct dwc3_otg *dotg = container_of(w, struct dwc3_otg, sm_work);
+	struct dwc3_otg *dotg = container_of(w, struct dwc3_otg, sm_work.work);
 	struct usb_phy *phy = dotg->otg.phy;
 	struct dwc3_charger *charger = dotg->charger;
 	bool work = 0;
+	int ret = 0;
+	int delay = 0;
 
 	pm_runtime_resume(phy->dev);
 	dev_dbg(phy->dev, "%s state\n", otg_state_string(phy->state));
@@ -817,10 +821,23 @@
 		if (test_bit(ID, &dotg->inputs)) {
 			dev_dbg(phy->dev, "id\n");
 			phy->state = OTG_STATE_B_IDLE;
+			dotg->vbus_retry_count = 0;
 			work = 1;
 		} else {
 			phy->state = OTG_STATE_A_HOST;
-			if (dwc3_otg_start_host(&dotg->otg, 1)) {
+			ret = dwc3_otg_start_host(&dotg->otg, 1);
+			if ((ret == -EPROBE_DEFER) &&
+						dotg->vbus_retry_count < 3) {
+				/*
+				 * Get regulator failed as regulator driver is
+				 * not up yet. Will try to start host after 1sec
+				 */
+				phy->state = OTG_STATE_A_IDLE;
+				dev_dbg(phy->dev, "Unable to get vbus regulator. Retrying...\n");
+				delay = VBUS_REG_CHECK_DELAY;
+				work = 1;
+				dotg->vbus_retry_count++;
+			} else if (ret) {
 				/*
 				 * Probably set_host was not called yet.
 				 * We will re-try as soon as it will be called
@@ -839,6 +856,7 @@
 			dev_dbg(phy->dev, "id\n");
 			dwc3_otg_start_host(&dotg->otg, 0);
 			phy->state = OTG_STATE_B_IDLE;
+			dotg->vbus_retry_count = 0;
 			work = 1;
 		}
 		break;
@@ -849,7 +867,7 @@
 	}
 
 	if (work)
-		schedule_work(&dotg->sm_work);
+		queue_delayed_work(system_nrt_wq, &dotg->sm_work, delay);
 }
 
 
@@ -973,7 +991,7 @@
 	dotg->otg.phy->state = OTG_STATE_UNDEFINED;
 
 	init_completion(&dotg->dwc3_xcvr_vbus_init);
-	INIT_WORK(&dotg->sm_work, dwc3_otg_sm_work);
+	INIT_DELAYED_WORK(&dotg->sm_work, dwc3_otg_sm_work);
 
 	ret = request_irq(dotg->irq, dwc3_otg_interrupt, IRQF_SHARED,
 				"dwc3_otg", dotg);
@@ -988,7 +1006,7 @@
 	return 0;
 
 err3:
-	cancel_work_sync(&dotg->sm_work);
+	cancel_delayed_work_sync(&dotg->sm_work);
 	usb_set_transceiver(NULL);
 err2:
 	kfree(dotg->otg.phy);
@@ -1013,7 +1031,7 @@
 	if (dotg) {
 		if (dotg->charger)
 			dotg->charger->start_detection(dotg->charger, false);
-		cancel_work_sync(&dotg->sm_work);
+		cancel_delayed_work_sync(&dotg->sm_work);
 		usb_set_transceiver(NULL);
 		pm_runtime_put(dwc->dev);
 		free_irq(dotg->irq, dotg);
diff --git a/drivers/usb/dwc3/dwc3_otg.h b/drivers/usb/dwc3/dwc3_otg.h
index 7adf874..3a75b0a 100644
--- a/drivers/usb/dwc3/dwc3_otg.h
+++ b/drivers/usb/dwc3/dwc3_otg.h
@@ -41,7 +41,7 @@
 	struct dwc3		*dwc;
 	void __iomem		*regs;
 	struct regulator	*vbus_otg;
-	struct work_struct	sm_work;
+	struct delayed_work	sm_work;
 	struct dwc3_charger	*charger;
 	struct dwc3_ext_xceiv	*ext_xceiv;
 #define ID		0
@@ -51,6 +51,7 @@
 	struct completion	dwc3_xcvr_vbus_init;
 	int			host_bus_suspend;
 	int			charger_retry_count;
+	int			vbus_retry_count;
 };
 
 /**
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index aaa22f3..8fa4774 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -2656,9 +2656,6 @@
 	dbg_print_reg("OSTS", dwc3_readl(dwc->regs, DWC3_OSTS));
 
 	dwc3_notify_event(dwc, DWC3_CONTROLLER_ERROR_EVENT);
-
-	panic("DWC3 Erratic error\n");
-
 }
 
 static void dwc3_gadget_interrupt(struct dwc3 *dwc,
diff --git a/drivers/usb/gadget/android.c b/drivers/usb/gadget/android.c
index 9b38ed3..bbb206d 100644
--- a/drivers/usb/gadget/android.c
+++ b/drivers/usb/gadget/android.c
@@ -1776,11 +1776,18 @@
 	config->fsg.nluns = 1;
 	name[0] = "lun";
 	if (dev->pdata && dev->pdata->cdrom) {
-		config->fsg.nluns = 2;
-		config->fsg.luns[1].cdrom = 1;
-		config->fsg.luns[1].ro = 1;
-		config->fsg.luns[1].removable = 0;
-		name[1] = "lun0";
+		config->fsg.luns[config->fsg.nluns].cdrom = 1;
+		config->fsg.luns[config->fsg.nluns].ro = 1;
+		config->fsg.luns[config->fsg.nluns].removable = 0;
+		name[config->fsg.nluns] = "lun0";
+		config->fsg.nluns++;
+	}
+	if (dev->pdata && dev->pdata->internal_ums) {
+		config->fsg.luns[config->fsg.nluns].cdrom = 0;
+		config->fsg.luns[config->fsg.nluns].ro = 0;
+		config->fsg.luns[config->fsg.nluns].removable = 1;
+		name[config->fsg.nluns] = "lun1";
+		config->fsg.nluns++;
 	}
 
 	config->fsg.luns[0].removable = 1;
@@ -2899,6 +2906,8 @@
 				&pdata->swfi_latency);
 		pdata->cdrom = of_property_read_bool(pdev->dev.of_node,
 				"qcom,android-usb-cdrom");
+		pdata->internal_ums = of_property_read_bool(pdev->dev.of_node,
+				"qcom,android-usb-internal-ums");
 	} else {
 		pdata = pdev->dev.platform_data;
 	}
diff --git a/drivers/usb/gadget/u_ether.c b/drivers/usb/gadget/u_ether.c
index 325c2b5..9e789c5 100644
--- a/drivers/usb/gadget/u_ether.c
+++ b/drivers/usb/gadget/u_ether.c
@@ -553,6 +553,7 @@
 				}
 
 				new_req->length = length;
+				new_req->complete = tx_complete;
 				retval = usb_ep_queue(in, new_req, GFP_ATOMIC);
 				switch (retval) {
 				default:
diff --git a/drivers/usb/host/ehci-msm-hsic.c b/drivers/usb/host/ehci-msm-hsic.c
index d102c22..5d58f16 100644
--- a/drivers/usb/host/ehci-msm-hsic.c
+++ b/drivers/usb/host/ehci-msm-hsic.c
@@ -342,7 +342,7 @@
 
 #define HSIC_DBG1_REG		0x38
 
-static const int vdd_val[VDD_TYPE_MAX][VDD_VAL_MAX] = {
+static int vdd_val[VDD_TYPE_MAX][VDD_VAL_MAX] = {
 		{   /* VDD_CX CORNER Voting */
 			[VDD_NONE]	= RPM_VREG_CORNER_NONE,
 			[VDD_MIN]	= RPM_VREG_CORNER_NOMINAL,
@@ -359,6 +359,8 @@
 {
 	int ret = 0;
 	int none_vol, min_vol, max_vol;
+	u32 tmp[3];
+	int len = 0;
 
 	if (!mehci->hsic_vddcx) {
 		mehci->vdd_type = VDDCX_CORNER;
@@ -373,6 +375,22 @@
 			}
 			mehci->vdd_type = VDDCX;
 		}
+
+		if (mehci->dev->of_node) {
+			of_get_property(mehci->dev->of_node,
+					"hsic,vdd-voltage-level",
+					&len);
+			if (len == sizeof(tmp)) {
+				of_property_read_u32_array(mehci->dev->of_node,
+						"hsic,vdd-voltage-level",
+						tmp, len/sizeof(*tmp));
+				vdd_val[mehci->vdd_type][VDD_NONE] = tmp[0];
+				vdd_val[mehci->vdd_type][VDD_MIN] = tmp[1];
+				vdd_val[mehci->vdd_type][VDD_MAX] = tmp[2];
+			} else {
+				dev_dbg(mehci->dev, "Use default vdd config\n");
+			}
+		}
 	}
 
 	none_vol = vdd_val[mehci->vdd_type][VDD_NONE];
diff --git a/drivers/usb/host/ehci-msm2.c b/drivers/usb/host/ehci-msm2.c
index 0aecaad..dd04f49 100644
--- a/drivers/usb/host/ehci-msm2.c
+++ b/drivers/usb/host/ehci-msm2.c
@@ -40,6 +40,7 @@
 #include <mach/msm_xo.h>
 #include <mach/msm_iomap.h>
 #include <linux/debugfs.h>
+#include <mach/rpm-regulator.h>
 
 #define MSM_USB_BASE (hcd->regs)
 
@@ -76,6 +77,7 @@
 	int					wakeup_int_cnt;
 	bool					wakeup_irq_enabled;
 	int					wakeup_irq;
+	enum usb_vdd_type			vdd_type;
 };
 
 static inline struct msm_hcd *hcd_to_mhcd(struct usb_hcd *hcd)
@@ -96,26 +98,87 @@
 #define HSUSB_PHY_1P8_VOL_MAX		1800000 /* uV */
 #define HSUSB_PHY_1P8_HPM_LOAD		50000	/* uA */
 
+#define HSUSB_PHY_VDD_DIG_VOL_NONE	0	/* uV */
 #define HSUSB_PHY_VDD_DIG_VOL_MIN	1045000	/* uV */
 #define HSUSB_PHY_VDD_DIG_VOL_MAX	1320000	/* uV */
 #define HSUSB_PHY_VDD_DIG_LOAD		49360	/* uA */
 
+#define HSUSB_PHY_SUSP_DIG_VOL_P50  500000
+#define HSUSB_PHY_SUSP_DIG_VOL_P75  750000
+enum hsusb_vdd_value {
+	VDD_MIN_NONE = 0,
+	VDD_MIN_P50,
+	VDD_MIN_P75,
+	VDD_MIN_OP,
+	VDD_MAX_OP,
+	VDD_VAL_MAX_OP,
+};
+
+static int hsusb_vdd_val[VDD_TYPE_MAX][VDD_VAL_MAX_OP] = {
+		{   /* VDD_CX CORNER Voting */
+			[VDD_MIN_NONE]	= RPM_VREG_CORNER_NONE,
+			[VDD_MIN_P50]	= RPM_VREG_CORNER_NONE,
+			[VDD_MIN_P75]	= RPM_VREG_CORNER_NONE,
+			[VDD_MIN_OP]	= RPM_VREG_CORNER_NOMINAL,
+			[VDD_MAX_OP]	= RPM_VREG_CORNER_HIGH,
+		},
+		{   /* VDD_CX Voltage Voting */
+			[VDD_MIN_NONE]	= HSUSB_PHY_VDD_DIG_VOL_NONE,
+			[VDD_MIN_P50]	= HSUSB_PHY_SUSP_DIG_VOL_P50,
+			[VDD_MIN_P75]	= HSUSB_PHY_SUSP_DIG_VOL_P75,
+			[VDD_MIN_OP]	= HSUSB_PHY_VDD_DIG_VOL_MIN,
+			[VDD_MAX_OP]	= HSUSB_PHY_VDD_DIG_VOL_MAX,
+		},
+};
+
 static int msm_ehci_init_vddcx(struct msm_hcd *mhcd, int init)
 {
 	int ret = 0;
+	int none_vol, min_vol, max_vol;
+	u32 tmp[5];
+	int len = 0;
 
-	if (!init)
+	if (!init) {
+		none_vol = hsusb_vdd_val[mhcd->vdd_type][VDD_MIN_NONE];
+		max_vol = hsusb_vdd_val[mhcd->vdd_type][VDD_MAX_OP];
 		goto disable_reg;
-
-	mhcd->hsusb_vddcx = devm_regulator_get(mhcd->dev, "HSUSB_VDDCX");
-	if (IS_ERR(mhcd->hsusb_vddcx)) {
-		dev_err(mhcd->dev, "unable to get ehci vddcx\n");
-		return PTR_ERR(mhcd->hsusb_vddcx);
 	}
 
-	ret = regulator_set_voltage(mhcd->hsusb_vddcx,
-			HSUSB_PHY_VDD_DIG_VOL_MIN,
-			HSUSB_PHY_VDD_DIG_VOL_MAX);
+	mhcd->vdd_type = VDDCX_CORNER;
+	mhcd->hsusb_vddcx = devm_regulator_get(mhcd->dev, "hsusb_vdd_dig");
+	if (IS_ERR(mhcd->hsusb_vddcx)) {
+		mhcd->hsusb_vddcx = devm_regulator_get(mhcd->dev,
+							"HSUSB_VDDCX");
+		if (IS_ERR(mhcd->hsusb_vddcx)) {
+			dev_err(mhcd->dev, "unable to get ehci vddcx\n");
+			return PTR_ERR(mhcd->hsusb_vddcx);
+		}
+		mhcd->vdd_type = VDDCX;
+	}
+
+	if (mhcd->dev->of_node) {
+		of_get_property(mhcd->dev->of_node,
+				"qcom,vdd-voltage-level",
+				&len);
+		if (len == sizeof(tmp)) {
+			of_property_read_u32_array(mhcd->dev->of_node,
+					"qcom,vdd-voltage-level",
+					tmp, len/sizeof(*tmp));
+			hsusb_vdd_val[mhcd->vdd_type][VDD_MIN_NONE] = tmp[0];
+			hsusb_vdd_val[mhcd->vdd_type][VDD_MIN_P50] = tmp[1];
+			hsusb_vdd_val[mhcd->vdd_type][VDD_MIN_P75] = tmp[2];
+			hsusb_vdd_val[mhcd->vdd_type][VDD_MIN_OP] = tmp[3];
+			hsusb_vdd_val[mhcd->vdd_type][VDD_MAX_OP] = tmp[4];
+		} else {
+			dev_dbg(mhcd->dev, "Use default vdd config\n");
+		}
+	}
+
+	none_vol = hsusb_vdd_val[mhcd->vdd_type][VDD_MIN_NONE];
+	min_vol = hsusb_vdd_val[mhcd->vdd_type][VDD_MIN_OP];
+	max_vol = hsusb_vdd_val[mhcd->vdd_type][VDD_MAX_OP];
+
+	ret = regulator_set_voltage(mhcd->hsusb_vddcx, min_vol, max_vol);
 	if (ret) {
 		dev_err(mhcd->dev, "unable to set the voltage"
 				"for ehci vddcx\n");
@@ -143,8 +206,7 @@
 reg_enable_err:
 	regulator_set_optimum_mode(mhcd->hsusb_vddcx, 0);
 reg_optimum_mode_err:
-	regulator_set_voltage(mhcd->hsusb_vddcx, 0,
-				HSUSB_PHY_VDD_DIG_VOL_MIN);
+	regulator_set_voltage(mhcd->hsusb_vddcx, none_vol, max_vol);
 	return ret;
 
 }
@@ -194,24 +256,22 @@
 }
 
 #ifdef CONFIG_PM_SLEEP
-#define HSUSB_PHY_SUSP_DIG_VOL_P50  500000
-#define HSUSB_PHY_SUSP_DIG_VOL_P75  750000
 static int msm_ehci_config_vddcx(struct msm_hcd *mhcd, int high)
 {
 	struct msm_usb_host_platform_data *pdata;
-	int max_vol = HSUSB_PHY_VDD_DIG_VOL_MAX;
+	int max_vol = hsusb_vdd_val[mhcd->vdd_type][VDD_MAX_OP];
 	int min_vol;
 	int ret;
 
 	pdata = mhcd->dev->platform_data;
 
 	if (high)
-		min_vol = HSUSB_PHY_VDD_DIG_VOL_MIN;
+		min_vol = hsusb_vdd_val[mhcd->vdd_type][VDD_MIN_OP];
 	else if (pdata && pdata->dock_connect_irq &&
 			!irq_read_line(pdata->dock_connect_irq))
-		min_vol = HSUSB_PHY_SUSP_DIG_VOL_P75;
+		min_vol = hsusb_vdd_val[mhcd->vdd_type][VDD_MIN_P75];
 	else
-		min_vol = HSUSB_PHY_SUSP_DIG_VOL_P50;
+		min_vol = hsusb_vdd_val[mhcd->vdd_type][VDD_MIN_P50];
 
 	ret = regulator_set_voltage(mhcd->hsusb_vddcx, min_vol, max_vol);
 	if (ret) {
diff --git a/drivers/usb/serial/usb_wwan.c b/drivers/usb/serial/usb_wwan.c
index 1c8664c..ebe8c6e 100644
--- a/drivers/usb/serial/usb_wwan.c
+++ b/drivers/usb/serial/usb_wwan.c
@@ -516,7 +516,6 @@
 	/* explicitly set the driver mode to raw */
 	tty->raw = 1;
 	tty->real_raw = 1;
-	tty->update_room_in_ldisc = 1;
 
 	set_bit(TTY_NO_WRITE_SPLIT, &tty->flags);
 	dbg("%s", __func__);
diff --git a/drivers/video/msm/mdss/Makefile b/drivers/video/msm/mdss/Makefile
index 017fa8e..ba14d67 100644
--- a/drivers/video/msm/mdss/Makefile
+++ b/drivers/video/msm/mdss/Makefile
@@ -16,7 +16,7 @@
 obj-$(CONFIG_DEBUG_FS) += mdss_debug.o
 endif
 
-dsi-v2-objs = dsi_v2.o dsi_host_v2.o dsi_io_v2.o dsi_panel_v2.o
+dsi-v2-objs = dsi_v2.o dsi_host_v2.o dsi_io_v2.o
 obj-$(CONFIG_FB_MSM_MDSS) += dsi-v2.o
 
 mdss-dsi-objs := mdss_dsi.o mdss_dsi_host.o
diff --git a/drivers/video/msm/mdss/dsi_host_v2.c b/drivers/video/msm/mdss/dsi_host_v2.c
index 5554085..5264005 100644
--- a/drivers/video/msm/mdss/dsi_host_v2.c
+++ b/drivers/video/msm/mdss/dsi_host_v2.c
@@ -482,6 +482,8 @@
 	if (rc == 0) {
 		pr_err("DSI command transaction time out\n");
 		rc = -ETIME;
+	} else if (!IS_ERR_VALUE(rc)) {
+		rc = 0;
 	}
 
 	dma_unmap_single(&dsi_host_private->dis_dev, tp->dmap, size,
@@ -524,7 +526,7 @@
 {
 	struct dsi_cmd_desc *cm;
 	u32 dsi_ctrl, ctrl;
-	int i, video_mode;
+	int i, video_mode, rc = 0;
 	unsigned char *ctrl_base = dsi_host_private->dsi_base;
 
 	/* turn on cmd mode
@@ -546,8 +548,13 @@
 		dsi_buf_init(tp);
 		dsi_cmd_dma_add(tp, cm);
 		msm_dsi_cmd_dma_tx(tp);
-		if (cm->wait)
-			msleep(cm->wait);
+		rc = msm_dsi_cmd_dma_tx(tp);
+		if (IS_ERR_VALUE(rc)) {
+			pr_err("%s: failed to call cmd_dma_tx\n", __func__);
+			break;
+		}
+		if (cm->dchdr.wait)
+			msleep(cm->dchdr.wait);
 		cm++;
 	}
 
@@ -555,15 +562,15 @@
 
 	if (video_mode)
 		MIPI_OUTP(ctrl_base + DSI_CTRL, dsi_ctrl);
-	return 0;
+	return rc;
 }
 
 /* MDSS_DSI_MRPS, Maximum Return Packet Size */
 static char max_pktsize[2] = {0x00, 0x00}; /* LSB tx first, 10 bytes */
 
 static struct dsi_cmd_desc pkt_size_cmd[] = {
-	{DTYPE_MAX_PKTSIZE, 1, 0, 0, 0,
-		sizeof(max_pktsize), max_pktsize}
+	{{DTYPE_MAX_PKTSIZE, 1, 0, 0, 0,
+		sizeof(max_pktsize)}, max_pktsize}
 };
 
 /*
@@ -582,7 +589,7 @@
 			struct dsi_buf *tp, struct dsi_buf *rp,
 			struct dsi_cmd_desc *cmds, int rlen)
 {
-	int cnt, len, diff, pkt_size;
+	int cnt, len, diff, pkt_size, rc = 0;
 	char cmd;
 
 	if (pdata->panel_info.mipi.no_max_pkt_size)
@@ -594,8 +601,8 @@
 	if (len <= 2) {
 		cnt = 4;	/* short read */
 	} else {
-		if (len > DSI_LEN)
-			len = DSI_LEN;	/* 8 bytes at most */
+		if (len > MDSS_DSI_LEN)
+			len = MDSS_DSI_LEN;	/* 8 bytes at most */
 
 		len = ALIGN(len, 4); /* len 4 bytes align */
 		diff = len - rlen;
@@ -618,7 +625,13 @@
 		max_pktsize[0] = pkt_size;
 		dsi_buf_init(tp);
 		dsi_cmd_dma_add(tp, pkt_size_cmd);
-		msm_dsi_cmd_dma_tx(tp);
+		rc = msm_dsi_cmd_dma_tx(tp);
+		if (IS_ERR_VALUE(rc)) {
+			msm_dsi_disable_irq();
+			pr_err("%s: dma_tx failed\n", __func__);
+			rp->len = 0;
+			goto end;
+		}
 		pr_debug("%s: Max packet size sent\n", __func__);
 	}
 
@@ -627,6 +640,12 @@
 
 	/* transmit read comamnd to client */
 	msm_dsi_cmd_dma_tx(tp);
+	if (IS_ERR_VALUE(rc)) {
+		msm_dsi_disable_irq();
+		pr_err("%s: dma_tx failed\n", __func__);
+		rp->len = 0;
+		goto end;
+	}
 	/*
 	 * once cmd_dma_done interrupt received,
 	 * return data from client is ready and stored
@@ -680,6 +699,7 @@
 		break;
 	}
 
+end:
 	return rp->len;
 }
 
@@ -743,12 +763,18 @@
 	u32 dummy_xres, dummy_yres;
 	u32 bitclk_rate = 0, byteclk_rate = 0, pclk_rate = 0, dsiclk_rate = 0;
 	unsigned char *ctrl_base = dsi_host_private->dsi_base;
+	struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
 
 	pr_debug("msm_dsi_on\n");
 
 	pinfo = &pdata->panel_info;
 
-	ret = msm_dsi_regulator_enable();
+	ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
+				panel_data);
+
+	ret = msm_dss_enable_vreg(
+		ctrl_pdata->power_data.vreg_config,
+		ctrl_pdata->power_data.num_vreg, 1);
 	if (ret) {
 		pr_err("%s: DSI power on failed\n", __func__);
 		return ret;
@@ -843,6 +869,16 @@
 static int msm_dsi_off(struct mdss_panel_data *pdata)
 {
 	int ret = 0;
+	struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
+
+	if (pdata == NULL) {
+		pr_err("%s: Invalid input data\n", __func__);
+		ret = -EINVAL;
+		return ret;
+	}
+
+	ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
+				panel_data);
 
 	pr_debug("msm_dsi_off\n");
 	msm_dsi_controller_cfg(0);
@@ -852,7 +888,9 @@
 	msm_dsi_phy_off(dsi_host_private->dsi_base);
 	msm_dsi_ahb_ctrl(0);
 
-	ret = msm_dsi_regulator_disable();
+	ret = msm_dss_enable_vreg(
+		ctrl_pdata->power_data.vreg_config,
+		ctrl_pdata->power_data.num_vreg, 0);
 	if (ret) {
 		pr_err("%s: Panel power off failed\n", __func__);
 		return ret;
@@ -865,11 +903,24 @@
 {
 	struct mdss_panel_info *pinfo;
 	int ret = 0;
+	struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
+
+	if (pdata == NULL) {
+		pr_err("%s: Invalid input data\n", __func__);
+		ret = -EINVAL;
+		return ret;
+	}
+
 
 	pr_debug("%s:\n", __func__);
 
+	ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
+				panel_data);
+
 	pinfo = &pdata->panel_info;
-	ret = msm_dsi_regulator_enable();
+	ret = msm_dss_enable_vreg(
+		ctrl_pdata->power_data.vreg_config,
+		ctrl_pdata->power_data.num_vreg, 1);
 	if (ret) {
 		pr_err("%s: DSI power on failed\n", __func__);
 		return ret;
@@ -912,11 +963,109 @@
 	return rc;
 }
 
+static int dsi_get_panel_cfg(char *panel_cfg)
+{
+	int rc;
+	struct mdss_panel_cfg *pan_cfg = NULL;
+
+	if (!panel_cfg)
+		return MDSS_PANEL_INTF_INVALID;
+
+	pan_cfg = mdp3_panel_intf_type(MDSS_PANEL_INTF_DSI);
+	if (IS_ERR(pan_cfg)) {
+		panel_cfg[0] = 0;
+		return PTR_ERR(pan_cfg);
+	} else if (!pan_cfg) {
+		panel_cfg[0] = 0;
+		return 0;
+	}
+
+	pr_debug("%s:%d: cfg:[%s]\n", __func__, __LINE__,
+		 pan_cfg->arg_cfg);
+	rc = strlcpy(panel_cfg, pan_cfg->arg_cfg,
+				MDSS_MAX_PANEL_LEN);
+	return rc;
+}
+
+/**
+ * dsi_find_panel_of_node(): find device node of dsi panel
+ * @pdev: platform_device of the dsi ctrl node
+ * @panel_cfg: string containing intf specific config data
+ *
+ * Function finds the panel device node using the interface
+ * specific configuration data. This configuration data is
+ * could be derived from the result of bootloader's GCDB
+ * panel detection mechanism. If such config data doesn't
+ * exist then this panel returns the default panel configured
+ * in the device tree.
+ *
+ * returns pointer to panel node on success, NULL on error.
+ */
+static struct device_node *dsi_find_panel_of_node(
+		struct platform_device *pdev, char *panel_cfg)
+{
+	int l;
+	char *panel_name;
+	struct device_node *dsi_pan_node = NULL, *mdss_node = NULL;
+
+	if (!panel_cfg)
+		return NULL;
+
+	l = strlen(panel_cfg);
+	if (!l) {
+		/* no panel cfg chg, parse dt */
+		pr_debug("%s:%d: no cmd line cfg present\n",
+			 __func__, __LINE__);
+		dsi_pan_node = of_parse_phandle(
+			pdev->dev.of_node,
+			"qcom,dsi-pref-prim-pan", 0);
+		if (!dsi_pan_node) {
+			pr_err("%s:can't find panel phandle\n",
+			       __func__);
+			return NULL;
+		}
+	} else {
+		if (panel_cfg[0] != '0') {
+			pr_err("%s:%d:ctrl id=[%d] not supported\n",
+			       __func__, __LINE__, panel_cfg[0]);
+			return NULL;
+		}
+		/*
+		 * skip first two chars '<dsi_ctrl_id>' and
+		 * ':' to get to the panel name
+		 */
+		panel_name = panel_cfg + 2;
+		pr_debug("%s:%d:%s:%s\n", __func__, __LINE__,
+			 panel_cfg, panel_name);
+
+		mdss_node = of_parse_phandle(pdev->dev.of_node,
+					     "qcom,mdss-mdp", 0);
+
+		if (!mdss_node) {
+			pr_err("%s: %d: mdss_node null\n",
+			       __func__, __LINE__);
+			return NULL;
+		}
+		dsi_pan_node = of_find_node_by_name(mdss_node,
+						    panel_name);
+		if (!dsi_pan_node) {
+			pr_err("%s: invalid pan node\n",
+			       __func__);
+			return NULL;
+		}
+	}
+	return dsi_pan_node;
+}
 
 static int __devinit msm_dsi_probe(struct platform_device *pdev)
 {
 	struct dsi_interface intf;
+	char panel_cfg[MDSS_MAX_PANEL_LEN];
+	struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
 	int rc = 0;
+	struct device_node *dsi_pan_node = NULL;
+	bool cmd_cfg_cont_splash = false;
+	struct resource *mdss_dsi_mres;
 
 	pr_debug("%s\n", __func__);
 
@@ -924,61 +1073,103 @@
 	if (rc)
 		return rc;
 
-	if (pdev->dev.of_node) {
-		struct resource *mdss_dsi_mres;
-		pdev->id = 0;
-		mdss_dsi_mres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-		if (!mdss_dsi_mres) {
-			pr_err("%s:%d unable to get the MDSS reg resources",
-				__func__, __LINE__);
-			return -ENOMEM;
-		} else {
-			dsi_host_private->dsi_reg_size =
-						resource_size(mdss_dsi_mres);
-			dsi_host_private->dsi_base = ioremap(
-						mdss_dsi_mres->start,
-						dsi_host_private->dsi_reg_size);
-			if (!dsi_host_private->dsi_base) {
-				pr_err("%s:%d unable to remap dsi resources",
-					__func__, __LINE__);
-				return -ENOMEM;
-			}
-		}
-
-		mdss_dsi_mres = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
-		if (!mdss_dsi_mres || mdss_dsi_mres->start == 0) {
-			pr_err("%s:%d unable to get the MDSS irq resources",
-				__func__, __LINE__);
-			rc = -ENODEV;
-			goto dsi_probe_error;
-		} else {
-			rc = msm_dsi_irq_init(&pdev->dev, mdss_dsi_mres->start);
-			if (rc) {
-				dev_err(&pdev->dev,
-					"%s: failed to init irq, rc=%d\n",
-							__func__, rc);
-				goto dsi_probe_error;
-			}
-		}
-
-		rc = msm_dsi_io_init(pdev);
-		if (rc) {
-			dev_err(&pdev->dev,
-				"%s: failed to init DSI IO, rc=%d\n",
-							__func__, rc);
-			goto dsi_probe_error;
-		}
-
-		rc = of_platform_populate(pdev->dev.of_node,
-					NULL, NULL, &pdev->dev);
-		if (rc) {
-			dev_err(&pdev->dev,
-				"%s: failed to add child nodes, rc=%d\n",
-							__func__, rc);
-			goto dsi_probe_error;
-		}
-
+	if (!pdev->dev.of_node) {
+		pr_err("%s: Device node is not accessible\n", __func__);
+		rc = -ENODEV;
+		goto error_no_mem;
 	}
+	pdev->id = 0;
+
+	ctrl_pdata = platform_get_drvdata(pdev);
+	if (!ctrl_pdata) {
+		ctrl_pdata = devm_kzalloc(&pdev->dev,
+			sizeof(struct mdss_dsi_ctrl_pdata), GFP_KERNEL);
+		if (!ctrl_pdata) {
+			pr_err("%s: FAILED: cannot alloc dsi ctrl\n", __func__);
+			rc = -ENOMEM;
+			goto error_no_mem;
+		}
+		platform_set_drvdata(pdev, ctrl_pdata);
+	}
+
+	mdss_dsi_mres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!mdss_dsi_mres) {
+		pr_err("%s:%d unable to get the MDSS reg resources",
+							__func__, __LINE__);
+		rc = -ENOMEM;
+		goto error_io_resource;
+	} else {
+		dsi_host_private->dsi_reg_size = resource_size(mdss_dsi_mres);
+		dsi_host_private->dsi_base = ioremap(mdss_dsi_mres->start,
+						dsi_host_private->dsi_reg_size);
+		if (!dsi_host_private->dsi_base) {
+			pr_err("%s:%d unable to remap dsi resources",
+							__func__, __LINE__);
+			rc = -ENOMEM;
+			goto error_io_resource;
+		}
+	}
+
+	mdss_dsi_mres = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+	if (!mdss_dsi_mres || mdss_dsi_mres->start == 0) {
+		pr_err("%s:%d unable to get the MDSS irq resources",
+							__func__, __LINE__);
+		rc = -ENODEV;
+		goto error_irq_resource;
+	} else {
+		rc = msm_dsi_irq_init(&pdev->dev, mdss_dsi_mres->start);
+		if (rc) {
+			dev_err(&pdev->dev, "%s: failed to init irq, rc=%d\n",
+								__func__, rc);
+			goto error_irq_resource;
+		}
+	}
+
+	rc = of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev);
+	if (rc) {
+		dev_err(&pdev->dev, "%s: failed to add child nodes, rc=%d\n",
+								__func__, rc);
+		goto error_platform_pop;
+	}
+
+	/* DSI panels can be different between controllers */
+	rc = dsi_get_panel_cfg(panel_cfg);
+	if (!rc)
+		/* dsi panel cfg not present */
+		pr_warn("%s:%d:dsi specific cfg not present\n",
+							 __func__, __LINE__);
+
+	/* find panel device node */
+	dsi_pan_node = dsi_find_panel_of_node(pdev, panel_cfg);
+	if (!dsi_pan_node) {
+		pr_err("%s: can't find panel node %s\n", __func__,
+								panel_cfg);
+		goto error_pan_node;
+	}
+
+	cmd_cfg_cont_splash = mdp3_panel_get_boot_cfg() ? true : false;
+
+	rc = mdss_dsi_panel_init(dsi_pan_node, ctrl_pdata, cmd_cfg_cont_splash);
+	if (rc) {
+		pr_err("%s: dsi panel init failed\n", __func__);
+		goto error_pan_node;
+	}
+
+	rc = dsi_ctrl_config_init(pdev, ctrl_pdata);
+	if (rc) {
+		dev_err(&pdev->dev, "%s: failed to parse mdss dtsi rc=%d\n",
+								__func__, rc);
+		goto error_pan_node;
+	}
+
+	rc = msm_dsi_io_init(pdev, &(ctrl_pdata->power_data));
+	if (rc) {
+		dev_err(&pdev->dev, "%s: failed to init DSI IO, rc=%d\n",
+								__func__, rc);
+		goto error_io_init;
+	}
+
+	pr_debug("%s: Dsi Ctrl->0 initialized\n", __func__);
 
 	dsi_host_private->dis_dev = pdev->dev;
 	intf.on = msm_dsi_on;
@@ -992,25 +1183,51 @@
 	dsi_register_interface(&intf);
 
 	msm_dsi_debug_init();
+
+	rc = dsi_panel_device_register_v2(pdev, ctrl_pdata);
+	if (rc) {
+		pr_err("%s: dsi panel dev reg failed\n", __func__);
+		goto error_device_register;
+	}
 	pr_debug("%s success\n", __func__);
 	return 0;
-dsi_probe_error:
+error_device_register:
+	msm_dsi_io_deinit(pdev, &(ctrl_pdata->power_data));
+error_io_init:
+	dsi_ctrl_config_deinit(pdev, ctrl_pdata);
+error_pan_node:
+	of_node_put(dsi_pan_node);
+error_platform_pop:
+	msm_dsi_disable_irq();
+error_irq_resource:
 	if (dsi_host_private->dsi_base) {
 		iounmap(dsi_host_private->dsi_base);
 		dsi_host_private->dsi_base = NULL;
 	}
-	msm_dsi_io_deinit();
+error_io_resource:
+	devm_kfree(&pdev->dev, ctrl_pdata);
+error_no_mem:
 	msm_dsi_deinit();
+
 	return rc;
 }
 
 static int __devexit msm_dsi_remove(struct platform_device *pdev)
 {
+	struct mdss_dsi_ctrl_pdata *ctrl_pdata = platform_get_drvdata(pdev);
+	if (!ctrl_pdata) {
+		pr_err("%s: no driver data\n", __func__);
+		return -ENODEV;
+	}
+
 	msm_dsi_disable_irq();
-	msm_dsi_io_deinit();
+	msm_dsi_io_deinit(pdev, &(ctrl_pdata->power_data));
+	dsi_ctrl_config_deinit(pdev, ctrl_pdata);
 	iounmap(dsi_host_private->dsi_base);
 	dsi_host_private->dsi_base = NULL;
 	msm_dsi_deinit();
+	devm_kfree(&pdev->dev, ctrl_pdata);
+
 	return 0;
 }
 
diff --git a/drivers/video/msm/mdss/dsi_io_v2.c b/drivers/video/msm/mdss/dsi_io_v2.c
index 365c32f..2c2b3d1 100644
--- a/drivers/video/msm/mdss/dsi_io_v2.c
+++ b/drivers/video/msm/mdss/dsi_io_v2.c
@@ -24,7 +24,6 @@
 #include "dsi_host_v2.h"
 
 struct msm_dsi_io_private {
-	struct regulator *vdda_vreg;
 	struct clk *dsi_byte_clk;
 	struct clk *dsi_esc_clk;
 	struct clk *dsi_pixel_clk;
@@ -51,7 +50,7 @@
 	}
 }
 
-int msm_dsi_io_init(struct platform_device *dev)
+int msm_dsi_io_init(struct platform_device *pdev, struct dss_module_power *mp)
 {
 	int rc;
 
@@ -64,25 +63,29 @@
 		}
 	}
 
-	rc = msm_dsi_clk_init(dev);
+	rc = msm_dsi_clk_init(pdev);
 	if (rc) {
 		pr_err("fail to initialize DSI clock\n");
 		return rc;
 	}
 
-	rc = msm_dsi_regulator_init(dev);
+	rc = msm_dss_config_vreg(&pdev->dev, mp->vreg_config,
+						mp->num_vreg, 1);
 	if (rc) {
 		pr_err("fail to initialize DSI regulator\n");
 		return rc;
 	}
+
 	return 0;
 }
 
-void msm_dsi_io_deinit(void)
+void msm_dsi_io_deinit(struct platform_device *pdev,
+				 struct dss_module_power *mp)
 {
 	if (dsi_io_private) {
 		msm_dsi_clk_deinit();
-		msm_dsi_regulator_deinit();
+		msm_dss_config_vreg(&pdev->dev, mp->vreg_config,
+					mp->num_vreg, 0);
 		kfree(dsi_io_private);
 		dsi_io_private = NULL;
 	}
@@ -242,61 +245,6 @@
 	return 0;
 }
 
-int msm_dsi_regulator_init(struct platform_device *dev)
-{
-	int ret = 0;
-
-	dsi_io_private->vdda_vreg = devm_regulator_get(&dev->dev, "vdda");
-	if (IS_ERR(dsi_io_private->vdda_vreg)) {
-		ret = PTR_ERR(dsi_io_private->vdda_vreg);
-		pr_err("could not get vdda 8110_l4, ret=%d\n", ret);
-		return ret;
-	}
-
-	ret = regulator_set_voltage(dsi_io_private->vdda_vreg, DSI_VDDA_VOLTAGE,
-					DSI_VDDA_VOLTAGE);
-	if (ret)
-		pr_err("vdd_io_vreg->set_voltage failed, ret=%d\n", ret);
-
-	return ret;
-}
-
-void msm_dsi_regulator_deinit(void)
-{
-	if (!IS_ERR(dsi_io_private->vdda_vreg)) {
-		devm_regulator_put(dsi_io_private->vdda_vreg);
-		dsi_io_private->vdda_vreg = NULL;
-	}
-}
-
-int msm_dsi_regulator_enable(void)
-{
-	int ret;
-
-	ret = regulator_enable(dsi_io_private->vdda_vreg);
-	if (ret) {
-		pr_err("%s: Failed to enable regulator.\n", __func__);
-		return ret;
-	}
-	msleep(20); /*per DSI controller spec*/
-	return ret;
-}
-
-int msm_dsi_regulator_disable(void)
-{
-	int ret;
-
-	ret = regulator_disable(dsi_io_private->vdda_vreg);
-	if (ret) {
-		pr_err("%s: Failed to disable regulator.\n", __func__);
-		return ret;
-	}
-	wmb();
-	msleep(20); /*per DSI controller spec*/
-
-	return ret;
-}
-
 static void msm_dsi_phy_strength_init(unsigned char *ctrl_base,
 					struct mdss_dsi_phy_ctrl *pd)
 {
@@ -362,12 +310,12 @@
 	for (ln = 0; ln < 5; ln++) {
 		unsigned char *off = ctrl_base + 0x0300 + (ln * 0x40);
 		index = ln * 6;
-		MIPI_OUTP(off, pd->laneCfg[index]);
-		MIPI_OUTP(off + 4, pd->laneCfg[index + 1]);
-		MIPI_OUTP(off + 8, pd->laneCfg[index + 2]);
-		MIPI_OUTP(off + 12, pd->laneCfg[index + 3]);
-		MIPI_OUTP(off + 20, pd->laneCfg[index + 4]);
-		MIPI_OUTP(off + 24, pd->laneCfg[index + 5]);
+		MIPI_OUTP(off, pd->lanecfg[index]);
+		MIPI_OUTP(off + 4, pd->lanecfg[index + 1]);
+		MIPI_OUTP(off + 8, pd->lanecfg[index + 2]);
+		MIPI_OUTP(off + 12, pd->lanecfg[index + 3]);
+		MIPI_OUTP(off + 20, pd->lanecfg[index + 4]);
+		MIPI_OUTP(off + 24, pd->lanecfg[index + 5]);
 	}
 	wmb();
 }
@@ -386,9 +334,9 @@
 static void msm_dsi_phy_bist_init(unsigned char *ctrl_base,
 			struct mdss_dsi_phy_ctrl *pd)
 {
-	MIPI_OUTP(ctrl_base + DSI_DSIPHY_BIST_CTRL4, pd->bistCtrl[4]);
-	MIPI_OUTP(ctrl_base + DSI_DSIPHY_BIST_CTRL1, pd->bistCtrl[1]);
-	MIPI_OUTP(ctrl_base + DSI_DSIPHY_BIST_CTRL0, pd->bistCtrl[0]);
+	MIPI_OUTP(ctrl_base + DSI_DSIPHY_BIST_CTRL4, pd->bistctrl[4]);
+	MIPI_OUTP(ctrl_base + DSI_DSIPHY_BIST_CTRL1, pd->bistctrl[1]);
+	MIPI_OUTP(ctrl_base + DSI_DSIPHY_BIST_CTRL0, pd->bistctrl[0]);
 	MIPI_OUTP(ctrl_base + DSI_DSIPHY_BIST_CTRL4, 0);
 	wmb();
 }
@@ -398,7 +346,7 @@
 {
 	struct mdss_dsi_phy_ctrl *pd;
 
-	pd = pdata->panel_info.mipi.dsi_phy_db;
+	pd = &(pdata->panel_info.mipi.dsi_phy_db);
 
 	msm_dsi_phy_strength_init(ctrl_base, pd);
 
diff --git a/drivers/video/msm/mdss/dsi_io_v2.h b/drivers/video/msm/mdss/dsi_io_v2.h
index a7d43a0..fd1c41e 100644
--- a/drivers/video/msm/mdss/dsi_io_v2.h
+++ b/drivers/video/msm/mdss/dsi_io_v2.h
@@ -17,9 +17,11 @@
 
 void msm_dsi_ahb_ctrl(int enable);
 
-int msm_dsi_io_init(struct platform_device *dev);
+int msm_dsi_io_init(struct platform_device *dev,
+				struct dss_module_power *mp);
 
-void msm_dsi_io_deinit(void);
+void msm_dsi_io_deinit(struct platform_device *dev,
+				struct dss_module_power *mp);
 
 int msm_dsi_clk_init(struct platform_device *dev);
 
@@ -38,14 +40,6 @@
 
 int msm_dsi_clk_disable(void);
 
-int msm_dsi_regulator_init(struct platform_device *dev);
-
-void msm_dsi_regulator_deinit(void);
-
-int msm_dsi_regulator_enable(void);
-
-int msm_dsi_regulator_disable(void);
-
 int msm_dsi_phy_init(unsigned char *ctrl_base,
 			struct mdss_panel_data *pdata);
 
diff --git a/drivers/video/msm/mdss/dsi_panel_v2.c b/drivers/video/msm/mdss/dsi_panel_v2.c
deleted file mode 100644
index b1a4293..0000000
--- a/drivers/video/msm/mdss/dsi_panel_v2.c
+++ /dev/null
@@ -1,923 +0,0 @@
-/* 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/module.h>
-#include <linux/interrupt.h>
-#include <linux/of.h>
-#include <linux/of_gpio.h>
-#include <linux/of_device.h>
-#include <linux/qpnp/pin.h>
-#include <linux/gpio.h>
-#include <linux/delay.h>
-#include <linux/slab.h>
-#include <linux/leds.h>
-#include <linux/err.h>
-#include <linux/regulator/consumer.h>
-
-#include "dsi_v2.h"
-
-#define DT_CMD_HDR 6
-
-struct dsi_panel_private {
-	struct dsi_buf dsi_panel_tx_buf;
-	struct dsi_buf dsi_panel_rx_buf;
-
-	int rst_gpio;
-	int disp_en_gpio;
-	int video_mode_gpio;
-	int te_gpio;
-	char bl_ctrl;
-
-	struct regulator *vddio_vreg;
-	struct regulator *vdda_vreg;
-
-	struct dsi_panel_cmds_list *on_cmds_list;
-	struct dsi_panel_cmds_list *off_cmds_list;
-	struct mdss_dsi_phy_ctrl phy_params;
-
-	char *on_cmds;
-	char *off_cmds;
-};
-
-static struct dsi_panel_private *panel_private;
-
-DEFINE_LED_TRIGGER(bl_led_trigger);
-
-int dsi_panel_init(void)
-{
-	int rc;
-
-	if (!panel_private) {
-		panel_private = kzalloc(sizeof(struct dsi_panel_private),
-					GFP_KERNEL);
-		if (!panel_private) {
-			pr_err("fail to alloc dsi panel private data\n");
-			return -ENOMEM;
-		}
-	}
-
-	rc = dsi_buf_alloc(&panel_private->dsi_panel_tx_buf,
-				ALIGN(DSI_BUF_SIZE,
-				SZ_4K));
-	if (rc)
-		return rc;
-
-	rc = dsi_buf_alloc(&panel_private->dsi_panel_rx_buf,
-				ALIGN(DSI_BUF_SIZE,
-				SZ_4K));
-	if (rc)
-		return rc;
-
-	return 0;
-}
-
-void dsi_panel_deinit(void)
-{
-	if (!panel_private)
-		return;
-
-	kfree(panel_private->dsi_panel_tx_buf.start);
-	kfree(panel_private->dsi_panel_rx_buf.start);
-
-	if (!IS_ERR(panel_private->vddio_vreg))
-		devm_regulator_put(panel_private->vddio_vreg);
-
-	if (!IS_ERR(panel_private->vdda_vreg))
-		devm_regulator_put(panel_private->vdda_vreg);
-
-	if (panel_private->on_cmds_list) {
-		kfree(panel_private->on_cmds_list->buf);
-		kfree(panel_private->on_cmds_list);
-	}
-	if (panel_private->off_cmds_list) {
-		kfree(panel_private->off_cmds_list->buf);
-		kfree(panel_private->off_cmds_list);
-	}
-
-	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)
-{
-	int ret;
-	if (enable) {
-		ret = regulator_enable(panel_private->vddio_vreg);
-		if (ret) {
-			pr_err("dsi_panel_power regulator enable vddio fail\n");
-			return ret;
-		}
-		ret = regulator_enable(panel_private->vdda_vreg);
-		if (ret) {
-			pr_err("dsi_panel_power regulator enable vdda fail\n");
-			return ret;
-		}
-	} else {
-		ret = regulator_disable(panel_private->vddio_vreg);
-		if (ret) {
-			pr_err("dsi_panel_power regulator disable vddio fail\n");
-			return ret;
-		}
-		ret = regulator_disable(panel_private->vdda_vreg);
-		if (ret) {
-			pr_err("dsi_panel_power regulator dsiable vdda fail\n");
-			return ret;
-		}
-	}
-	return 0;
-}
-
-static char led_pwm1[2] = {0x51, 0x0};	/* DTYPE_DCS_WRITE1 */
-static struct dsi_cmd_desc backlight_cmd = {
-	DTYPE_DCS_WRITE1, 1, 0, 0, 1, sizeof(led_pwm1), led_pwm1};
-
-static void dsi_panel_bklt_dcs(struct mdss_panel_data *pdata, int level)
-{
-	struct mipi_panel_info *mipi;
-
-	mipi  = &pdata->panel_info.mipi;
-
-	pr_debug("%s: dcs level=%d\n", __func__, level);
-
-	led_pwm1[1] = (unsigned char)level;
-
-	if (DSI_VIDEO_MODE == mipi->mode) {
-		dsi_set_tx_power_mode(0);
-		dsi_cmds_tx_v2(pdata, &panel_private->dsi_panel_tx_buf,
-					&backlight_cmd,
-					1);
-		dsi_set_tx_power_mode(1);
-	}
-}
-
-void dsi_panel_reset(struct mdss_panel_data *pdata, int enable)
-{
-	if (pdata == NULL) {
-		pr_err("%s: Invalid input data\n", __func__);
-		return;
-	}
-
-	if (!gpio_is_valid(panel_private->disp_en_gpio)) {
-		pr_debug("%s:%d, reset line not configured\n",
-			   __func__, __LINE__);
-	}
-
-	if (!gpio_is_valid(panel_private->rst_gpio)) {
-		pr_debug("%s:%d, reset line not configured\n",
-			   __func__, __LINE__);
-		return;
-	}
-
-	pr_debug("%s: enable = %d\n", __func__, enable);
-
-	if (enable == 2) {
-		dsi_panel_power(1);
-		gpio_request(panel_private->rst_gpio, "panel_reset");
-		gpio_set_value(panel_private->rst_gpio, 1);
-		if (gpio_is_valid(panel_private->disp_en_gpio)) {
-			gpio_request(panel_private->disp_en_gpio,
-					"panel_enable");
-			gpio_set_value(panel_private->disp_en_gpio, 1);
-		}
-		if (gpio_is_valid(panel_private->video_mode_gpio)) {
-			gpio_request(panel_private->video_mode_gpio,
-					"panel_video_mdoe");
-			if (pdata->panel_info.mipi.mode == DSI_VIDEO_MODE)
-				gpio_set_value(panel_private->video_mode_gpio,
-						1);
-			else
-				gpio_set_value(panel_private->video_mode_gpio,
-						0);
-		}
-		if (gpio_is_valid(panel_private->te_gpio))
-			gpio_request(panel_private->te_gpio, "panel_te");
-	} else if (enable == 1) {
-		dsi_panel_power(1);
-		gpio_request(panel_private->rst_gpio, "panel_reset");
-		gpio_set_value(panel_private->rst_gpio, 1);
-		/*
-		 * these delay values are by experiments currently, will need
-		 * to move to device tree late
-		 */
-		msleep(20);
-		gpio_set_value(panel_private->rst_gpio, 0);
-		udelay(200);
-		gpio_set_value(panel_private->rst_gpio, 1);
-		msleep(20);
-		if (gpio_is_valid(panel_private->disp_en_gpio)) {
-			gpio_request(panel_private->disp_en_gpio,
-					"panel_enable");
-			gpio_set_value(panel_private->disp_en_gpio, 1);
-		}
-		if (gpio_is_valid(panel_private->video_mode_gpio)) {
-			gpio_request(panel_private->video_mode_gpio,
-					"panel_video_mdoe");
-			if (pdata->panel_info.mipi.mode == DSI_VIDEO_MODE)
-				gpio_set_value(panel_private->video_mode_gpio,
-						1);
-			else
-				gpio_set_value(panel_private->video_mode_gpio,
-						0);
-		}
-		if (gpio_is_valid(panel_private->te_gpio))
-			gpio_request(panel_private->te_gpio, "panel_te");
-	} else {
-		gpio_set_value(panel_private->rst_gpio, 0);
-		gpio_free(panel_private->rst_gpio);
-
-		if (gpio_is_valid(panel_private->disp_en_gpio)) {
-			gpio_set_value(panel_private->disp_en_gpio, 0);
-			gpio_free(panel_private->disp_en_gpio);
-		}
-
-		if (gpio_is_valid(panel_private->video_mode_gpio))
-			gpio_free(panel_private->video_mode_gpio);
-
-		if (gpio_is_valid(panel_private->te_gpio))
-			gpio_free(panel_private->te_gpio);
-		dsi_panel_power(0);
-	}
-}
-
-static void dsi_panel_bl_ctrl(struct mdss_panel_data *pdata,
-				u32 bl_level)
-{
-	if (panel_private->bl_ctrl) {
-		switch (panel_private->bl_ctrl) {
-		case BL_WLED:
-			led_trigger_event(bl_led_trigger, bl_level);
-			break;
-
-		case BL_DCS_CMD:
-			dsi_panel_bklt_dcs(pdata, bl_level);
-			break;
-
-		default:
-			pr_err("%s: Unknown bl_ctrl configuration\n",
-				__func__);
-			break;
-		}
-	} else
-		pr_err("%s:%d, bl_ctrl not configured", __func__, __LINE__);
-}
-
-static int dsi_panel_on(struct mdss_panel_data *pdata)
-{
-	struct mipi_panel_info *mipi;
-
-	mipi  = &pdata->panel_info.mipi;
-
-	pr_debug("%s:%d, debug info (mode) : %d\n", __func__, __LINE__,
-		 mipi->mode);
-
-
-	return dsi_cmds_tx_v2(pdata, &panel_private->dsi_panel_tx_buf,
-					panel_private->on_cmds_list->buf,
-					panel_private->on_cmds_list->size);
-}
-
-static int dsi_panel_off(struct mdss_panel_data *pdata)
-{
-	struct mipi_panel_info *mipi;
-	mipi  = &pdata->panel_info.mipi;
-
-	pr_debug("%s:%d, debug info\n", __func__, __LINE__);
-
-
-	return dsi_cmds_tx_v2(pdata, &panel_private->dsi_panel_tx_buf,
-					panel_private->off_cmds_list->buf,
-					panel_private->off_cmds_list->size);
-}
-
-static int dsi_panel_parse_gpio(struct platform_device *pdev)
-{
-	struct device_node *np = pdev->dev.of_node;
-	panel_private->disp_en_gpio = of_get_named_gpio(np,
-						"qcom,enable-gpio", 0);
-	panel_private->rst_gpio = of_get_named_gpio(np, "qcom,rst-gpio", 0);
-	panel_private->video_mode_gpio = of_get_named_gpio(np,
-						"qcom,mode-selection-gpio", 0);
-	panel_private->te_gpio = of_get_named_gpio(np,
-						"qcom,te-gpio", 0);
-	return 0;
-}
-
-static int dsi_panel_parse_regulator(struct platform_device *pdev)
-{
-	int ret;
-	panel_private->vddio_vreg = devm_regulator_get(&pdev->dev, "vddio");
-	if (IS_ERR(panel_private->vddio_vreg)) {
-		pr_err("%s: could not get vddio vreg, rc=%ld\n",
-			__func__, PTR_ERR(panel_private->vddio_vreg));
-		return PTR_ERR(panel_private->vddio_vreg);
-	}
-	ret = regulator_set_voltage(panel_private->vddio_vreg,
-					1800000,
-					1800000);
-	if (ret) {
-		pr_err("%s: set voltage failed on vddio_vreg, rc=%d\n",
-			__func__, ret);
-		return ret;
-	}
-	panel_private->vdda_vreg = devm_regulator_get(&pdev->dev, "vdda");
-	if (IS_ERR(panel_private->vdda_vreg)) {
-		pr_err("%s: could not get vdda_vreg , rc=%ld\n",
-			__func__, PTR_ERR(panel_private->vdda_vreg));
-		return PTR_ERR(panel_private->vdda_vreg);
-	}
-	ret = regulator_set_voltage(panel_private->vdda_vreg,
-					2850000,
-					2850000);
-	if (ret) {
-		pr_err("%s: set voltage failed on vdda_vreg, rc=%d\n",
-			__func__, ret);
-		return ret;
-	}
-	return 0;
-}
-
-static int dsi_panel_parse_timing(struct platform_device *pdev,
-				struct dsi_panel_common_pdata *panel_data)
-{
-	struct device_node *np = pdev->dev.of_node;
-	u32 res[6], tmp;
-	int rc;
-
-	rc = of_property_read_u32_array(np, "qcom,mdss-pan-res", res, 2);
-	if (rc) {
-		pr_err("%s:%d, panel resolution not specified\n",
-						__func__, __LINE__);
-		return -EINVAL;
-	}
-
-	panel_data->panel_info.xres = (!rc ? res[0] : 480);
-	panel_data->panel_info.yres = (!rc ? res[1] : 800);
-
-	rc = of_property_read_u32_array(np, "qcom,mdss-pan-active-res", res, 2);
-	if (rc == 0) {
-		panel_data->panel_info.lcdc.xres_pad =
-			panel_data->panel_info.xres - res[0];
-		panel_data->panel_info.lcdc.yres_pad =
-			panel_data->panel_info.yres - res[1];
-	}
-
-	rc = of_property_read_u32(np, "qcom,mdss-pan-bpp", &tmp);
-	if (rc) {
-		pr_err("%s:%d, panel bpp not specified\n",
-						__func__, __LINE__);
-		return -EINVAL;
-	}
-	panel_data->panel_info.bpp = (!rc ? tmp : 24);
-
-	rc = of_property_read_u32_array(np,
-		"qcom,mdss-pan-porch-values", res, 6);
-	if (rc) {
-		pr_err("%s:%d, panel porch not specified\n",
-						__func__, __LINE__);
-		return -EINVAL;
-	}
-
-	panel_data->panel_info.lcdc.h_back_porch = (!rc ? res[0] : 6);
-	panel_data->panel_info.lcdc.h_pulse_width = (!rc ? res[1] : 2);
-	panel_data->panel_info.lcdc.h_front_porch = (!rc ? res[2] : 6);
-	panel_data->panel_info.lcdc.v_back_porch = (!rc ? res[3] : 6);
-	panel_data->panel_info.lcdc.v_pulse_width = (!rc ? res[4] : 2);
-	panel_data->panel_info.lcdc.v_front_porch = (!rc ? res[5] : 6);
-
-	return 0;
-}
-
-static int dsi_panel_parse_phy(struct platform_device *pdev,
-				struct dsi_panel_common_pdata *panel_data)
-{
-	struct device_node *np = pdev->dev.of_node;
-	int i, len;
-	const char *data;
-
-	data = of_get_property(np, "qcom,panel-phy-regulatorSettings", &len);
-	if ((!data) || (len != 6)) {
-		pr_err("%s:%d, Unable to read Phy regulator settings",
-			__func__, __LINE__);
-		return -EINVAL;
-	}
-	for (i = 0; i < len; i++)
-		panel_private->phy_params.regulator[i] = data[i];
-
-	data = of_get_property(np, "qcom,panel-phy-timingSettings", &len);
-	if ((!data) || (len != 12)) {
-		pr_err("%s:%d, Unable to read Phy timing settings",
-			__func__, __LINE__);
-		return -EINVAL;
-	}
-	for (i = 0; i < len; i++)
-		panel_private->phy_params.timing[i] = data[i];
-
-	data = of_get_property(np, "qcom,panel-phy-strengthCtrl", &len);
-	if ((!data) || (len != 2)) {
-		pr_err("%s:%d, Unable to read Phy Strength ctrl settings",
-			__func__, __LINE__);
-		return -EINVAL;
-	}
-	panel_private->phy_params.strength[0] = data[0];
-	panel_private->phy_params.strength[1] = data[1];
-
-	data = of_get_property(np, "qcom,panel-phy-bistCtrl", &len);
-	if ((!data) || (len != 6)) {
-		pr_err("%s:%d, Unable to read Phy Bist Ctrl settings",
-			__func__, __LINE__);
-		return -EINVAL;
-	}
-	for (i = 0; i < len; i++)
-		panel_private->phy_params.bistCtrl[i] = data[i];
-
-	data = of_get_property(np, "qcom,panel-phy-laneConfig", &len);
-	if ((!data) || (len != 30)) {
-		pr_err("%s:%d, Unable to read Phy lane configure settings",
-			__func__, __LINE__);
-		return -EINVAL;
-	}
-	for (i = 0; i < len; i++)
-		panel_private->phy_params.laneCfg[i] = data[i];
-
-	panel_data->panel_info.mipi.dsi_phy_db = &panel_private->phy_params;
-	return 0;
-}
-
-static int dsi_panel_parse_init_cmds(struct platform_device *pdev,
-				struct dsi_panel_common_pdata *panel_data)
-{
-	struct device_node *np = pdev->dev.of_node;
-	int i, len;
-	int cmd_plen, data_offset;
-	const char *data;
-	const char *on_cmds_state, *off_cmds_state;
-	int num_of_on_cmds = 0, num_of_off_cmds = 0;
-
-	data = of_get_property(np, "qcom,panel-on-cmds", &len);
-	if (!data) {
-		pr_err("%s:%d, Unable to read ON cmds", __func__, __LINE__);
-		return -EINVAL;
-	}
-
-	panel_private->on_cmds = kzalloc(sizeof(char) * len, GFP_KERNEL);
-	if (!panel_private->on_cmds)
-		return -ENOMEM;
-
-	memcpy(panel_private->on_cmds, data, len);
-
-	data_offset = 0;
-	cmd_plen = 0;
-	while ((len - data_offset) >= DT_CMD_HDR) {
-		data_offset += (DT_CMD_HDR - 1);
-		cmd_plen = panel_private->on_cmds[data_offset++];
-		data_offset += cmd_plen;
-		num_of_on_cmds++;
-	}
-	if (!num_of_on_cmds) {
-		pr_err("%s:%d, No ON cmds specified", __func__, __LINE__);
-		return -EINVAL;
-	}
-
-	panel_private->on_cmds_list =
-		kzalloc(sizeof(struct dsi_panel_cmds_list), GFP_KERNEL);
-	if (!panel_private->on_cmds_list)
-		return -ENOMEM;
-
-	panel_private->on_cmds_list->buf =
-		kzalloc((num_of_on_cmds * sizeof(struct dsi_cmd_desc)),
-			GFP_KERNEL);
-	if (!panel_private->on_cmds_list->buf)
-		return -ENOMEM;
-
-	data_offset = 0;
-	for (i = 0; i < num_of_on_cmds; i++) {
-		panel_private->on_cmds_list->buf[i].dtype =
-					panel_private->on_cmds[data_offset++];
-		panel_private->on_cmds_list->buf[i].last =
-					panel_private->on_cmds[data_offset++];
-		panel_private->on_cmds_list->buf[i].vc =
-					panel_private->on_cmds[data_offset++];
-		panel_private->on_cmds_list->buf[i].ack =
-					panel_private->on_cmds[data_offset++];
-		panel_private->on_cmds_list->buf[i].wait =
-					panel_private->on_cmds[data_offset++];
-		panel_private->on_cmds_list->buf[i].dlen =
-					panel_private->on_cmds[data_offset++];
-		panel_private->on_cmds_list->buf[i].payload =
-					&panel_private->on_cmds[data_offset];
-		data_offset += (panel_private->on_cmds_list->buf[i].dlen);
-	}
-
-	if (data_offset != len) {
-		pr_err("%s:%d, Incorrect ON command entries",
-						__func__, __LINE__);
-		return -EINVAL;
-	}
-
-	panel_private->on_cmds_list->size = num_of_on_cmds;
-
-	on_cmds_state = of_get_property(pdev->dev.of_node,
-					"qcom,on-cmds-dsi-state", NULL);
-	if (!strncmp(on_cmds_state, "DSI_LP_MODE", 11)) {
-		panel_private->on_cmds_list->ctrl_state = DSI_LP_MODE;
-	} else if (!strncmp(on_cmds_state, "DSI_HS_MODE", 11)) {
-		panel_private->on_cmds_list->ctrl_state = DSI_HS_MODE;
-	} else {
-		pr_debug("%s: ON cmds state not specified. Set Default\n",
-							__func__);
-		panel_private->on_cmds_list->ctrl_state = DSI_LP_MODE;
-	}
-
-	panel_data->dsi_panel_on_cmds = panel_private->on_cmds_list;
-
-	data = of_get_property(np, "qcom,panel-off-cmds", &len);
-	if (!data) {
-		pr_err("%s:%d, Unable to read OFF cmds", __func__, __LINE__);
-		return -EINVAL;
-	}
-
-	panel_private->off_cmds = kzalloc(sizeof(char) * len, GFP_KERNEL);
-	if (!panel_private->off_cmds)
-		return -ENOMEM;
-
-	memcpy(panel_private->off_cmds, data, len);
-
-	data_offset = 0;
-	cmd_plen = 0;
-	while ((len - data_offset) >= DT_CMD_HDR) {
-		data_offset += (DT_CMD_HDR - 1);
-		cmd_plen = panel_private->off_cmds[data_offset++];
-		data_offset += cmd_plen;
-		num_of_off_cmds++;
-	}
-	if (!num_of_off_cmds) {
-		pr_err("%s:%d, No OFF cmds specified", __func__, __LINE__);
-		return -ENOMEM;
-	}
-
-	panel_private->off_cmds_list =
-		kzalloc(sizeof(struct dsi_panel_cmds_list), GFP_KERNEL);
-	if (!panel_private->off_cmds_list)
-		return -ENOMEM;
-
-	panel_private->off_cmds_list->buf = kzalloc(num_of_off_cmds
-					* sizeof(struct dsi_cmd_desc),
-						GFP_KERNEL);
-	if (!panel_private->off_cmds_list->buf)
-		return -ENOMEM;
-
-	data_offset = 0;
-	for (i = 0; i < num_of_off_cmds; i++) {
-		panel_private->off_cmds_list->buf[i].dtype =
-					panel_private->off_cmds[data_offset++];
-		panel_private->off_cmds_list->buf[i].last =
-					panel_private->off_cmds[data_offset++];
-		panel_private->off_cmds_list->buf[i].vc =
-					panel_private->off_cmds[data_offset++];
-		panel_private->off_cmds_list->buf[i].ack =
-					panel_private->off_cmds[data_offset++];
-		panel_private->off_cmds_list->buf[i].wait =
-					panel_private->off_cmds[data_offset++];
-		panel_private->off_cmds_list->buf[i].dlen =
-					panel_private->off_cmds[data_offset++];
-		panel_private->off_cmds_list->buf[i].payload =
-					&panel_private->off_cmds[data_offset];
-		data_offset += (panel_private->off_cmds_list->buf[i].dlen);
-	}
-
-	if (data_offset != len) {
-		pr_err("%s:%d, Incorrect OFF command entries",
-						__func__, __LINE__);
-		return -EINVAL;
-	}
-
-	panel_private->off_cmds_list->size = num_of_off_cmds;
-	off_cmds_state = of_get_property(pdev->dev.of_node,
-				"qcom,off-cmds-dsi-state", NULL);
-	if (!strncmp(off_cmds_state, "DSI_LP_MODE", 11)) {
-		panel_private->off_cmds_list->ctrl_state =
-						DSI_LP_MODE;
-	} else if (!strncmp(off_cmds_state, "DSI_HS_MODE", 11)) {
-		panel_private->off_cmds_list->ctrl_state = DSI_HS_MODE;
-	} else {
-		pr_debug("%s: ON cmds state not specified. Set Default\n",
-							__func__);
-		panel_private->off_cmds_list->ctrl_state = DSI_LP_MODE;
-	}
-
-	panel_data->dsi_panel_off_cmds = panel_private->off_cmds_list;
-
-	return 0;
-}
-
-static int dsi_panel_parse_backlight(struct platform_device *pdev,
-				struct dsi_panel_common_pdata *panel_data,
-				char *bl_ctrl)
-{
-	int rc;
-	u32 res[6];
-	static const char *bl_ctrl_type;
-
-	bl_ctrl_type = of_get_property(pdev->dev.of_node,
-				  "qcom,mdss-pan-bl-ctrl", NULL);
-	if ((bl_ctrl_type) && (!strncmp(bl_ctrl_type, "bl_ctrl_wled", 12))) {
-		led_trigger_register_simple("bkl-trigger", &bl_led_trigger);
-		pr_debug("%s: SUCCESS-> WLED TRIGGER register\n", __func__);
-		*bl_ctrl = BL_WLED;
-	} else if ((bl_ctrl_type) && (!strncmp(bl_ctrl_type,
-				"bl_ctrl_dcs", 11))) {
-		pr_debug("%s: SUCCESS-> DCS COMMAND register\n", __func__);
-		*bl_ctrl = BL_DCS_CMD;
-	}
-	rc = of_property_read_u32_array(pdev->dev.of_node,
-		"qcom,mdss-pan-bl-levels", res, 2);
-	panel_data->panel_info.bl_min = (!rc ? res[0] : 0);
-	panel_data->panel_info.bl_max = (!rc ? res[1] : 255);
-	return rc;
-}
-
-static int dsi_panel_parse_other(struct platform_device *pdev,
-				struct dsi_panel_common_pdata *panel_data)
-{
-	const char *pdest;
-	u32 tmp;
-	int rc;
-	bool cont_splash_enabled = false;
-
-	pdest = of_get_property(pdev->dev.of_node,
-				"qcom,mdss-pan-dest", NULL);
-	if (strlen(pdest) != 9) {
-		pr_err("%s: Unknown pdest specified\n", __func__);
-		return -EINVAL;
-	}
-	if (!strncmp(pdest, "display_1", 9)) {
-		panel_data->panel_info.pdest = DISPLAY_1;
-	} else if (!strncmp(pdest, "display_2", 9)) {
-		panel_data->panel_info.pdest = DISPLAY_2;
-	} else {
-		pr_debug("%s: pdest not specified. Set Default\n",
-							__func__);
-		panel_data->panel_info.pdest = DISPLAY_1;
-	}
-
-	rc = of_property_read_u32(pdev->dev.of_node,
-		"qcom,mdss-pan-underflow-clr", &tmp);
-	panel_data->panel_info.lcdc.underflow_clr = (!rc ? tmp : 0xff);
-
-	cont_splash_enabled = of_property_read_bool(pdev->dev.of_node,
-		"qcom,cont-splash-enabled");
-	if (!cont_splash_enabled) {
-		pr_debug("%s:%d Continuous splash flag not found.\n",
-				__func__, __LINE__);
-		panel_data->panel_info.cont_splash_enabled = 0;
-	} else {
-		pr_debug("%s:%d Continuous splash flag enabled.\n",
-				__func__, __LINE__);
-		panel_data->panel_info.cont_splash_enabled = 1;
-	}
-	return rc;
-}
-
-static int dsi_panel_parse_host_cfg(struct platform_device *pdev,
-				struct dsi_panel_common_pdata *panel_data)
-{
-	struct device_node *np = pdev->dev.of_node;
-	u32 res[6], tmp;
-	int rc;
-
-	rc = of_property_read_u32(np, "qcom,mdss-pan-dsi-mode", &tmp);
-	panel_data->panel_info.mipi.mode = (!rc ? tmp : DSI_VIDEO_MODE);
-
-	rc = of_property_read_u32(np,
-		"qcom,mdss-pan-dsi-h-pulse-mode", &tmp);
-	panel_data->panel_info.mipi.pulse_mode_hsa_he = (!rc ? tmp : false);
-
-	rc = of_property_read_u32_array(np,
-		"qcom,mdss-pan-dsi-h-power-stop", res, 3);
-	panel_data->panel_info.mipi.hbp_power_stop = (!rc ? res[0] : false);
-	panel_data->panel_info.mipi.hsa_power_stop = (!rc ? res[1] : false);
-	panel_data->panel_info.mipi.hfp_power_stop = (!rc ? res[2] : false);
-
-	rc = of_property_read_u32_array(np,
-		"qcom,mdss-pan-dsi-bllp-power-stop", res, 2);
-	panel_data->panel_info.mipi.bllp_power_stop =
-					(!rc ? res[0] : false);
-	panel_data->panel_info.mipi.eof_bllp_power_stop =
-					(!rc ? res[1] : false);
-
-	rc = of_property_read_u32(np,
-		"qcom,mdss-pan-dsi-traffic-mode", &tmp);
-	panel_data->panel_info.mipi.traffic_mode =
-			(!rc ? tmp : DSI_NON_BURST_SYNCH_PULSE);
-
-	rc = of_property_read_u32(np,
-		"qcom,mdss-pan-dsi-dst-format", &tmp);
-	panel_data->panel_info.mipi.dst_format =
-			(!rc ? tmp : DSI_VIDEO_DST_FORMAT_RGB888);
-
-	rc = of_property_read_u32(np, "qcom,mdss-pan-dsi-vc", &tmp);
-	panel_data->panel_info.mipi.vc = (!rc ? tmp : 0);
-
-	rc = of_property_read_u32(np, "qcom,mdss-pan-dsi-rgb-swap", &tmp);
-	panel_data->panel_info.mipi.rgb_swap = (!rc ? tmp : DSI_RGB_SWAP_RGB);
-
-	rc = of_property_read_u32_array(np,
-		"qcom,mdss-pan-dsi-data-lanes", res, 4);
-	panel_data->panel_info.mipi.data_lane0 = (!rc ? res[0] : true);
-	panel_data->panel_info.mipi.data_lane1 = (!rc ? res[1] : false);
-	panel_data->panel_info.mipi.data_lane2 = (!rc ? res[2] : false);
-	panel_data->panel_info.mipi.data_lane3 = (!rc ? res[3] : false);
-
-	rc = of_property_read_u32(np, "qcom,mdss-pan-dsi-dlane-swap", &tmp);
-	panel_data->panel_info.mipi.dlane_swap = (!rc ? tmp : 0);
-
-	rc = of_property_read_u32_array(np, "qcom,mdss-pan-dsi-t-clk", res, 2);
-	panel_data->panel_info.mipi.t_clk_pre = (!rc ? res[0] : 0x24);
-	panel_data->panel_info.mipi.t_clk_post = (!rc ? res[1] : 0x03);
-
-	rc = of_property_read_u32(np, "qcom,mdss-pan-dsi-stream", &tmp);
-	panel_data->panel_info.mipi.stream = (!rc ? tmp : 0);
-
-	rc = of_property_read_u32(np, "qcom,mdss-pan-te-sel", &tmp);
-	panel_data->panel_info.mipi.te_sel = (!rc ? tmp : 1);
-
-	rc = of_property_read_u32(np, "qcom,mdss-pan-insert-dcs-cmd", &tmp);
-	panel_data->panel_info.mipi.insert_dcs_cmd = (!rc ? tmp : 1);
-
-	rc = of_property_read_u32(np, "qcom,mdss-pan-wr-mem-continue", &tmp);
-	panel_data->panel_info.mipi.wr_mem_continue = (!rc ? tmp : 0x3c);
-	rc = of_property_read_u32(np, "qcom,mdss-pan-wr-mem-start", &tmp);
-	panel_data->panel_info.mipi.wr_mem_start = (!rc ? tmp : 0x2c);
-
-	rc = of_property_read_u32(np, "qcom,mdss-pan-dsi-mdp-tr", &tmp);
-	panel_data->panel_info.mipi.mdp_trigger =
-			(!rc ? tmp : DSI_CMD_TRIGGER_SW);
-	if (panel_data->panel_info.mipi.mdp_trigger > 6) {
-		pr_err("%s:%d, Invalid mdp trigger. Forcing to sw trigger",
-						 __func__, __LINE__);
-		panel_data->panel_info.mipi.mdp_trigger =
-					DSI_CMD_TRIGGER_SW;
-	}
-
-	rc = of_property_read_u32(np, "qcom,mdss-pan-dsi-dma-tr", &tmp);
-	panel_data->panel_info.mipi.dma_trigger =
-			(!rc ? tmp : DSI_CMD_TRIGGER_SW);
-	if (panel_data->panel_info.mipi.dma_trigger > 6) {
-		pr_err("%s:%d, Invalid dma trigger. Forcing to sw trigger",
-						 __func__, __LINE__);
-		panel_data->panel_info.mipi.dma_trigger =
-					DSI_CMD_TRIGGER_SW;
-	}
-
-	rc = of_property_read_u32(np, "qcom,mdss-pan-dsi-frame-rate", &tmp);
-	panel_data->panel_info.mipi.frame_rate = (!rc ? tmp : 60);
-	return rc;
-}
-
-static int dsi_panel_parse_dt(struct platform_device *pdev,
-				struct dsi_panel_common_pdata *panel_data,
-				char *bl_ctrl)
-{
-	int rc;
-
-	rc = dsi_panel_parse_gpio(pdev);
-	if (rc) {
-		pr_err("fail to parse panel GPIOs\n");
-		return rc;
-	}
-
-	rc = dsi_panel_parse_regulator(pdev);
-	if (rc) {
-		pr_err("fail to parse panel regulators\n");
-		return rc;
-	}
-
-	rc = dsi_panel_parse_timing(pdev, panel_data);
-	if (rc) {
-		pr_err("fail to parse panel timing\n");
-		return rc;
-	}
-
-	rc = dsi_panel_parse_phy(pdev, panel_data);
-	if (rc) {
-		pr_err("fail to parse DSI PHY settings\n");
-		return rc;
-	}
-
-	rc = dsi_panel_parse_backlight(pdev, panel_data, bl_ctrl);
-	if (rc) {
-		pr_err("fail to parse DSI backlight\n");
-		return rc;
-	}
-
-	rc = dsi_panel_parse_other(pdev, panel_data);
-	if (rc) {
-		pr_err("fail to parse DSI panel destination\n");
-		return rc;
-	}
-
-	rc = dsi_panel_parse_host_cfg(pdev, panel_data);
-	if (rc) {
-		pr_err("fail to parse DSI host configs\n");
-		return rc;
-	}
-
-	rc = dsi_panel_parse_init_cmds(pdev, panel_data);
-	if (rc) {
-		pr_err("fail to parse DSI init commands\n");
-		return rc;
-	}
-
-	return 0;
-}
-
-static int __devinit dsi_panel_probe(struct platform_device *pdev)
-{
-	int rc = 0;
-	static struct dsi_panel_common_pdata vendor_pdata;
-	static const char *panel_name;
-
-	pr_debug("%s:%d, debug info id=%d", __func__, __LINE__, pdev->id);
-	if (!pdev->dev.of_node)
-		return -ENODEV;
-
-	panel_name = of_get_property(pdev->dev.of_node, "label", NULL);
-	if (!panel_name)
-		pr_debug("%s:%d, panel name not specified\n",
-						__func__, __LINE__);
-	else
-		pr_debug("%s: Panel Name = %s\n", __func__, panel_name);
-
-	rc = dsi_panel_init();
-	if (rc) {
-		pr_err("dsi_panel_init failed %d\n", rc);
-		goto dsi_panel_probe_error;
-
-	}
-	rc = dsi_panel_parse_dt(pdev, &vendor_pdata, &panel_private->bl_ctrl);
-	if (rc) {
-		pr_err("dsi_panel_parse_dt failed %d\n", rc);
-		goto dsi_panel_probe_error;
-	}
-
-	vendor_pdata.on = dsi_panel_on;
-	vendor_pdata.off = dsi_panel_off;
-	vendor_pdata.reset = dsi_panel_reset;
-	vendor_pdata.bl_fnc = dsi_panel_bl_ctrl;
-
-	rc = dsi_panel_device_register_v2(pdev, &vendor_pdata,
-					panel_private->bl_ctrl);
-
-	if (rc) {
-		pr_err("dsi_panel_device_register_v2 failed %d\n", rc);
-		goto dsi_panel_probe_error;
-	}
-
-	return 0;
-dsi_panel_probe_error:
-	dsi_panel_deinit();
-	return rc;
-}
-
-static int __devexit dsi_panel_remove(struct platform_device *pdev)
-{
-	dsi_panel_deinit();
-	return 0;
-}
-
-
-static const struct of_device_id dsi_panel_match[] = {
-	{.compatible = "qcom,dsi-panel-v2"},
-	{}
-};
-
-static struct platform_driver this_driver = {
-	.probe  = dsi_panel_probe,
-	.remove = __devexit_p(dsi_panel_remove),
-	.driver = {
-		.name = "dsi_v2_panel",
-		.of_match_table = dsi_panel_match,
-	},
-};
-
-static int __init dsi_panel_module_init(void)
-{
-	return platform_driver_register(&this_driver);
-}
-module_init(dsi_panel_module_init);
diff --git a/drivers/video/msm/mdss/dsi_v2.c b/drivers/video/msm/mdss/dsi_v2.c
index 686ec01..9ca3461 100644
--- a/drivers/video/msm/mdss/dsi_v2.c
+++ b/drivers/video/msm/mdss/dsi_v2.c
@@ -16,12 +16,12 @@
 #include <linux/slab.h>
 #include <linux/iopoll.h>
 #include <linux/of_device.h>
+#include <linux/of_gpio.h>
 
-#include "mdss_panel.h"
 #include "dsi_v2.h"
 
-static struct dsi_panel_common_pdata *panel_common_data;
 static struct dsi_interface dsi_intf;
+static struct dsi_buf dsi_panel_tx_buf;
 
 static int dsi_off(struct mdss_panel_data *pdata)
 {
@@ -52,20 +52,24 @@
 	}
 	return rc;
 }
+
 static int dsi_panel_handler(struct mdss_panel_data *pdata, int enable)
 {
 	int rc = 0;
+	struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
 
 	pr_debug("dsi_panel_handler enable=%d\n", enable);
-	if (!panel_common_data || !pdata)
+	if (!pdata)
 		return -ENODEV;
+	ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
+				panel_data);
 
 	if (enable) {
-		if (panel_common_data->reset)
-			panel_common_data->reset(pdata, 1);
+		mdss_dsi_panel_reset(pdata, 1);
 
-		if (panel_common_data->on)
-			rc = panel_common_data->on(pdata);
+		rc = dsi_cmds_tx_v2(pdata, &dsi_panel_tx_buf,
+					ctrl_pdata->on_cmds.cmds,
+					ctrl_pdata->on_cmds.cmd_cnt);
 
 		if (rc)
 			pr_err("dsi_panel_handler panel on failed %d\n", rc);
@@ -73,11 +77,11 @@
 		if (dsi_intf.op_mode_config)
 			dsi_intf.op_mode_config(DSI_CMD_MODE, pdata);
 
-		if (panel_common_data->off)
-			panel_common_data->off(pdata);
+		dsi_cmds_tx_v2(pdata, &dsi_panel_tx_buf,
+					ctrl_pdata->off_cmds.cmds,
+					ctrl_pdata->off_cmds.cmd_cnt);
 
-		if (panel_common_data->reset)
-			panel_common_data->reset(pdata, 0);
+		mdss_dsi_panel_reset(pdata, 0);
 	}
 	return rc;
 }
@@ -88,9 +92,6 @@
 
 	pr_debug("%s:\n", __func__);
 
-	if (panel_common_data->reset)
-		panel_common_data->reset(pdata, 2);
-
 	if (dsi_intf.cont_on)
 		rc = dsi_intf.cont_on(pdata);
 
@@ -106,7 +107,7 @@
 {
 	int rc = 0;
 
-	if (!pdata || !panel_common_data) {
+	if (!pdata) {
 		pr_err("%s: Invalid input data\n", __func__);
 		return -ENODEV;
 	}
@@ -134,49 +135,399 @@
 	return rc;
 }
 
-static struct platform_device *get_dsi_platform_device(
-			struct platform_device *dev)
+static int dsi_parse_gpio(struct platform_device *pdev,
+				struct mdss_dsi_ctrl_pdata *ctrl_pdata)
 {
-	struct device_node *dsi_ctrl_np;
-	struct platform_device *ctrl_pdev;
+	struct device_node *np = pdev->dev.of_node;
+	int rc = 0, i = 0;
+	u32 tmp[9];
 
-	dsi_ctrl_np = of_parse_phandle(dev->dev.of_node,
-					"qcom,dsi-ctrl-phandle", 0);
+	ctrl_pdata->disp_en_gpio = of_get_named_gpio(np,
+		"qcom,platform-enable-gpio", 0);
 
-	if (!dsi_ctrl_np)
-		return NULL;
+	if (!gpio_is_valid(ctrl_pdata->disp_en_gpio)) {
+		pr_err("%s:%d, Disp_en gpio not specified\n",
+						__func__, __LINE__);
+	} else {
+		rc = gpio_request(ctrl_pdata->disp_en_gpio, "disp_enable");
+		if (rc) {
+			pr_err("request reset gpio failed, rc=%d\n",
+			       rc);
+			gpio_free(ctrl_pdata->disp_en_gpio);
+			return -ENODEV;
+		}
+	}
 
-	ctrl_pdev = of_find_device_by_node(dsi_ctrl_np);
-	if (!ctrl_pdev)
-		return NULL;
+	if (ctrl_pdata->panel_data.panel_info.mipi.mode == DSI_CMD_MODE) {
+		ctrl_pdata->disp_te_gpio = of_get_named_gpio(np,
+						"qcom,platform-te-gpio", 0);
+		if (!gpio_is_valid(ctrl_pdata->disp_te_gpio)) {
+			pr_err("%s:%d, Disp_te gpio not specified\n",
+							__func__, __LINE__);
+		} else {
+			rc = gpio_request(ctrl_pdata->disp_te_gpio, "disp_te");
+			if (rc) {
+				pr_err("request TE gpio failed, rc=%d\n",
+								       rc);
+				gpio_free(ctrl_pdata->disp_te_gpio);
+				return -ENODEV;
+			}
+			rc = gpio_tlmm_config(GPIO_CFG(
+					ctrl_pdata->disp_te_gpio, 1,
+					GPIO_CFG_INPUT,
+					GPIO_CFG_PULL_DOWN,
+					GPIO_CFG_2MA),
+					GPIO_CFG_ENABLE);
 
-	return ctrl_pdev;
+			if (rc) {
+				pr_err("%s: unable to config tlmm = %d\n",
+					__func__, ctrl_pdata->disp_te_gpio);
+				gpio_free(ctrl_pdata->disp_te_gpio);
+				return -ENODEV;
+			}
+
+			rc = gpio_direction_input(ctrl_pdata->disp_te_gpio);
+			if (rc) {
+				pr_err("set_direction for disp_en gpio failed, rc=%d\n",
+								       rc);
+				gpio_free(ctrl_pdata->disp_te_gpio);
+				if (gpio_is_valid(ctrl_pdata->disp_en_gpio))
+					gpio_free(ctrl_pdata->disp_en_gpio);
+				return -ENODEV;
+			}
+			pr_debug("%s: te_gpio=%d\n", __func__,
+					ctrl_pdata->disp_te_gpio);
+		}
+	}
+
+	rc = of_property_read_u32_array(np,
+		"qcom,platform-reset-sequence", tmp, MDSS_DSI_RST_SEQ_LEN);
+	if (rc)
+		pr_err("%s:%d, unable to read gpio reset sequence\n",
+						__func__, __LINE__);
+	else
+		for (i = 0; i < MDSS_DSI_RST_SEQ_LEN; ++i)
+			ctrl_pdata->rst_seq[i] = tmp[i];
+
+	ctrl_pdata->rst_gpio = of_get_named_gpio(np,
+					"qcom,platform-reset-gpio", 0);
+	if (!gpio_is_valid(ctrl_pdata->rst_gpio)) {
+		pr_err("%s:%d, reset gpio not specified\n",
+						__func__, __LINE__);
+	} else {
+		rc = gpio_request(ctrl_pdata->rst_gpio, "disp_rst_n");
+		if (rc) {
+			pr_err("request reset gpio failed, rc=%d\n",
+				rc);
+			gpio_free(ctrl_pdata->rst_gpio);
+			if (gpio_is_valid(ctrl_pdata->disp_en_gpio))
+				gpio_free(ctrl_pdata->disp_en_gpio);
+			if (gpio_is_valid(ctrl_pdata->disp_te_gpio))
+				gpio_free(ctrl_pdata->disp_te_gpio);
+			return -ENODEV;
+		}
+	}
+
+	if (ctrl_pdata->panel_data.panel_info.mode_gpio_state !=
+						MODE_GPIO_NOT_VALID) {
+		ctrl_pdata->mode_gpio = of_get_named_gpio(np,
+						"qcom,platform-mode-gpio", 0);
+		if (!gpio_is_valid(ctrl_pdata->mode_gpio)) {
+			pr_info("%s:%d, reset gpio not specified\n",
+							__func__, __LINE__);
+		} else {
+			rc = gpio_request(ctrl_pdata->mode_gpio, "panel_mode");
+			if (rc) {
+				pr_err("request panel mode gpio failed,rc=%d\n",
+									rc);
+				gpio_free(ctrl_pdata->mode_gpio);
+				if (gpio_is_valid(ctrl_pdata->disp_en_gpio))
+					gpio_free(ctrl_pdata->disp_en_gpio);
+				if (gpio_is_valid(ctrl_pdata->rst_gpio))
+					gpio_free(ctrl_pdata->rst_gpio);
+				if (gpio_is_valid(ctrl_pdata->disp_te_gpio))
+					gpio_free(ctrl_pdata->disp_te_gpio);
+				return -ENODEV;
+			}
+		}
+	}
+	return 0;
 }
 
+void dsi_ctrl_config_deinit(struct platform_device *pdev,
+				struct mdss_dsi_ctrl_pdata *ctrl_pdata)
+{
+	struct dss_module_power *module_power = &(ctrl_pdata->power_data);
+	if (!module_power) {
+		pr_err("%s: invalid input\n", __func__);
+		return;
+	}
+
+	if (module_power->vreg_config) {
+		devm_kfree(&(pdev->dev), module_power->vreg_config);
+		module_power->vreg_config = NULL;
+	}
+	module_power->num_vreg = 0;
+
+	if (gpio_is_valid(ctrl_pdata->disp_en_gpio))
+		gpio_free(ctrl_pdata->disp_en_gpio);
+	if (gpio_is_valid(ctrl_pdata->rst_gpio))
+		gpio_free(ctrl_pdata->rst_gpio);
+	if (gpio_is_valid(ctrl_pdata->disp_te_gpio))
+		gpio_free(ctrl_pdata->disp_te_gpio);
+	if (gpio_is_valid(ctrl_pdata->mode_gpio))
+		gpio_free(ctrl_pdata->mode_gpio);
+}
+
+static int dsi_parse_vreg(struct device *dev, struct dss_module_power *mp)
+{
+	int i = 0, rc = 0;
+	u32 tmp = 0;
+	struct device_node *supply_node = NULL;
+	struct device_node *np = NULL;
+
+	if (!dev || !mp) {
+		pr_err("%s: invalid input\n", __func__);
+		rc = -EINVAL;
+		goto error;
+	}
+
+	np = dev->of_node;
+
+	mp->num_vreg = 0;
+	for_each_child_of_node(np, supply_node) {
+		if (!strncmp(supply_node->name, "qcom,platform-supply-entry",
+					strlen("qcom,platform-supply-entry")))
+			++mp->num_vreg;
+	}
+	if (mp->num_vreg == 0) {
+		pr_err("%s: no vreg\n", __func__);
+		goto novreg;
+	} else {
+		pr_debug("%s: vreg found. count=%d\n", __func__, mp->num_vreg);
+	}
+
+	mp->vreg_config = devm_kzalloc(dev, sizeof(struct dss_vreg) *
+		mp->num_vreg, GFP_KERNEL);
+	if (!mp->vreg_config) {
+		pr_err("%s: can't alloc vreg mem\n", __func__);
+		rc = -ENOMEM;
+		goto error;
+	}
+
+	for_each_child_of_node(np, supply_node) {
+		if (!strncmp(supply_node->name, "qcom,platform-supply-entry",
+					strlen("qcom,platform-supply-entry"))) {
+			const char *st = NULL;
+			/* vreg-name */
+			rc = of_property_read_string(supply_node,
+				"qcom,supply-name", &st);
+			if (rc) {
+				pr_err("%s: error reading name. rc=%d\n",
+					__func__, rc);
+				goto error;
+			}
+			strlcpy(mp->vreg_config[i].vreg_name, st,
+				sizeof(mp->vreg_config[i].vreg_name));
+			/* vreg-min-voltage */
+			rc = of_property_read_u32(supply_node,
+				"qcom,supply-min-voltage", &tmp);
+			if (rc) {
+				pr_err("%s: error reading min volt. rc=%d\n",
+					__func__, rc);
+				goto error;
+			}
+			mp->vreg_config[i].min_voltage = tmp;
+
+			/* vreg-max-voltage */
+			rc = of_property_read_u32(supply_node,
+				"qcom,supply-max-voltage", &tmp);
+			if (rc) {
+				pr_err("%s: error reading max volt. rc=%d\n",
+					__func__, rc);
+				goto error;
+			}
+			mp->vreg_config[i].max_voltage = tmp;
+
+			/* enable-load */
+			rc = of_property_read_u32(supply_node,
+				"qcom,supply-enable-load", &tmp);
+			if (rc) {
+				pr_err("%s: error reading enable load. rc=%d\n",
+					__func__, rc);
+				goto error;
+			}
+			mp->vreg_config[i].enable_load = tmp;
+
+			/* disable-load */
+			rc = of_property_read_u32(supply_node,
+				"qcom,supply-disable-load", &tmp);
+			if (rc) {
+				pr_err("%s: error reading disable load. rc=%d\n",
+					__func__, rc);
+				goto error;
+			}
+			mp->vreg_config[i].disable_load = tmp;
+
+			/* pre-sleep */
+			rc = of_property_read_u32(supply_node,
+				"qcom,supply-pre-on-sleep", &tmp);
+			if (rc) {
+				pr_debug("%s: error reading supply pre sleep value. rc=%d\n",
+					__func__, rc);
+			}
+			mp->vreg_config[i].pre_on_sleep = (!rc ? tmp : 0);
+
+			rc = of_property_read_u32(supply_node,
+				"qcom,supply-pre-off-sleep", &tmp);
+			if (rc) {
+				pr_debug("%s: error reading supply pre sleep value. rc=%d\n",
+					__func__, rc);
+			}
+			mp->vreg_config[i].pre_off_sleep = (!rc ? tmp : 0);
+
+			/* post-sleep */
+			rc = of_property_read_u32(supply_node,
+				"qcom,supply-post-on-sleep", &tmp);
+			if (rc) {
+				pr_debug("%s: error reading supply post sleep value. rc=%d\n",
+					__func__, rc);
+			}
+			mp->vreg_config[i].post_on_sleep = (!rc ? tmp : 0);
+
+			rc = of_property_read_u32(supply_node,
+				"qcom,supply-post-off-sleep", &tmp);
+			if (rc) {
+				pr_debug("%s: error reading supply post sleep value. rc=%d\n",
+					__func__, rc);
+			}
+			mp->vreg_config[i].post_off_sleep = (!rc ? tmp : 0);
+
+			pr_debug("%s: %s min=%d, max=%d, enable=%d, disable=%d, preonsleep=%d, postonsleep=%d, preoffsleep=%d, postoffsleep=%d\n",
+				__func__,
+				mp->vreg_config[i].vreg_name,
+				mp->vreg_config[i].min_voltage,
+				mp->vreg_config[i].max_voltage,
+				mp->vreg_config[i].enable_load,
+				mp->vreg_config[i].disable_load,
+				mp->vreg_config[i].pre_on_sleep,
+				mp->vreg_config[i].post_on_sleep,
+				mp->vreg_config[i].pre_off_sleep,
+				mp->vreg_config[i].post_off_sleep
+				);
+			++i;
+		}
+	}
+
+	return 0;
+
+error:
+	if (mp->vreg_config) {
+		devm_kfree(dev, mp->vreg_config);
+		mp->vreg_config = NULL;
+	}
+novreg:
+	mp->num_vreg = 0;
+
+	return rc;
+}
+
+static int dsi_parse_phy(struct platform_device *pdev,
+				struct mdss_dsi_ctrl_pdata *ctrl_pdata)
+{
+	struct device_node *np = pdev->dev.of_node;
+	int i, len;
+	const char *data;
+	struct mdss_dsi_phy_ctrl *phy_db
+		= &(ctrl_pdata->panel_data.panel_info.mipi.dsi_phy_db);
+
+	data = of_get_property(np, "qcom,platform-regulator-settings", &len);
+	if ((!data) || (len != 6)) {
+		pr_err("%s:%d, Unable to read Phy regulator settings",
+			__func__, __LINE__);
+		return -EINVAL;
+	}
+	for (i = 0; i < len; i++)
+		phy_db->regulator[i] = data[i];
+
+	data = of_get_property(np, "qcom,platform-strength-ctrl", &len);
+	if ((!data) || (len != 2)) {
+		pr_err("%s:%d, Unable to read Phy Strength ctrl settings",
+			__func__, __LINE__);
+		return -EINVAL;
+	}
+	phy_db->strength[0] = data[0];
+	phy_db->strength[1] = data[1];
+
+	data = of_get_property(np, "qcom,platform-bist-ctrl", &len);
+	if ((!data) || (len != 6)) {
+		pr_err("%s:%d, Unable to read Phy Bist Ctrl settings",
+			__func__, __LINE__);
+		return -EINVAL;
+	}
+	for (i = 0; i < len; i++)
+		phy_db->bistctrl[i] = data[i];
+
+	data = of_get_property(np, "qcom,platform-lane-config", &len);
+	if ((!data) || (len != 30)) {
+		pr_err("%s:%d, Unable to read Phy lane configure settings",
+			__func__, __LINE__);
+		return -EINVAL;
+	}
+	for (i = 0; i < len; i++)
+		phy_db->lanecfg[i] = data[i];
+
+	return 0;
+}
+
+int dsi_ctrl_config_init(struct platform_device *pdev,
+				struct mdss_dsi_ctrl_pdata *ctrl_pdata)
+{
+	int rc;
+
+	rc = dsi_parse_vreg(&pdev->dev, &ctrl_pdata->power_data);
+	if (rc) {
+		pr_err("%s:%d unable to get the regulator resources",
+			__func__, __LINE__);
+		return rc;
+	}
+
+	rc = dsi_parse_gpio(pdev, ctrl_pdata);
+	if (rc) {
+		pr_err("fail to parse panel GPIOs\n");
+		return rc;
+	}
+
+	rc = dsi_parse_phy(pdev, ctrl_pdata);
+	if (rc) {
+		pr_err("fail to parse DSI PHY settings\n");
+		return rc;
+	}
+
+	return 0;
+}
 int dsi_panel_device_register_v2(struct platform_device *dev,
-				struct dsi_panel_common_pdata *panel_data,
-				char backlight_ctrl)
+				struct mdss_dsi_ctrl_pdata *ctrl_pdata)
 {
 	struct mipi_panel_info *mipi;
-	struct platform_device *ctrl_pdev;
 	int rc;
 	u8 lanes = 0, bpp;
 	u32 h_period, v_period;
-	static struct mdss_panel_data dsi_panel_data;
+	struct mdss_panel_info *pinfo = &(ctrl_pdata->panel_data.panel_info);
 
-	h_period = ((panel_data->panel_info.lcdc.h_pulse_width)
-			+ (panel_data->panel_info.lcdc.h_back_porch)
-			+ (panel_data->panel_info.xres)
-			+ (panel_data->panel_info.lcdc.h_front_porch));
+	h_period = ((pinfo->lcdc.h_pulse_width)
+			+ (pinfo->lcdc.h_back_porch)
+			+ (pinfo->xres)
+			+ (pinfo->lcdc.h_front_porch));
 
-	v_period = ((panel_data->panel_info.lcdc.v_pulse_width)
-			+ (panel_data->panel_info.lcdc.v_back_porch)
-			+ (panel_data->panel_info.yres)
-			+ (panel_data->panel_info.lcdc.v_front_porch));
+	v_period = ((pinfo->lcdc.v_pulse_width)
+			+ (pinfo->lcdc.v_back_porch)
+			+ (pinfo->yres)
+			+ (pinfo->lcdc.v_front_porch));
 
-	mipi  = &panel_data->panel_info.mipi;
+	mipi  = &pinfo->mipi;
 
-	panel_data->panel_info.type =
+	pinfo->type =
 		((mipi->mode == DSI_VIDEO_MODE)
 			? MIPI_VIDEO_PANEL : MIPI_CMD_PANEL);
 
@@ -189,7 +540,6 @@
 	if (mipi->data_lane0)
 		lanes += 1;
 
-
 	if ((mipi->dst_format == DSI_CMD_DST_FORMAT_RGB888)
 		|| (mipi->dst_format == DSI_VIDEO_DST_FORMAT_RGB888)
 		|| (mipi->dst_format == DSI_VIDEO_DST_FORMAT_RGB666_LOOSE))
@@ -200,39 +550,38 @@
 	else
 		bpp = 3; /* Default format set to RGB888 */
 
-	if (panel_data->panel_info.type == MIPI_VIDEO_PANEL &&
-		!panel_data->panel_info.clk_rate) {
-		h_period += panel_data->panel_info.lcdc.xres_pad;
-		v_period += panel_data->panel_info.lcdc.yres_pad;
+	if (pinfo->type == MIPI_VIDEO_PANEL &&
+		!pinfo->clk_rate) {
+		h_period += pinfo->lcdc.xres_pad;
+		v_period += pinfo->lcdc.yres_pad;
 
 		if (lanes > 0) {
-			panel_data->panel_info.clk_rate =
+			pinfo->clk_rate =
 			((h_period * v_period * (mipi->frame_rate) * bpp * 8)
 			   / lanes);
 		} else {
 			pr_err("%s: forcing mdss_dsi lanes to 1\n", __func__);
-			panel_data->panel_info.clk_rate =
+			pinfo->clk_rate =
 				(h_period * v_period
 					 * (mipi->frame_rate) * bpp * 8);
 		}
 	}
 
-	ctrl_pdev = get_dsi_platform_device(dev);
-	if (!ctrl_pdev)
-		return -EPROBE_DEFER;
+	ctrl_pdata->panel_data.event_handler = dsi_event_handler;
 
-	dsi_panel_data.event_handler = dsi_event_handler;
+	rc = dsi_buf_alloc(&dsi_panel_tx_buf,
+				ALIGN(DSI_BUF_SIZE,
+				SZ_4K));
+	if (rc)
+		return rc;
 
-	dsi_panel_data.panel_info = panel_data->panel_info;
-
-	dsi_panel_data.set_backlight = panel_data->bl_fnc;
-	panel_common_data = panel_data;
 	/*
 	 * register in mdp driver
 	 */
-	rc = mdss_register_panel(ctrl_pdev, &dsi_panel_data);
+	rc = mdss_register_panel(dev, &(ctrl_pdata->panel_data));
 	if (rc) {
 		dev_err(&dev->dev, "unable to register MIPI DSI panel\n");
+		kfree(dsi_panel_tx_buf.start);
 		return rc;
 	}
 
@@ -340,15 +689,16 @@
 	char *bp;
 	u32 *hp;
 	int i, len;
+	struct dsi_ctrl_hdr *dchdr = &cm->dchdr;
 
 	bp = dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
 
 	/* fill up payload */
 	if (cm->payload) {
-		len = cm->dlen;
+		len = dchdr->dlen;
 		len += 3;
 		len &= ~0x03; /* multipled by 4 */
-		for (i = 0; i < cm->dlen; i++)
+		for (i = 0; i < dchdr->dlen; i++)
 			*bp++ = cm->payload[i];
 
 		/* append 0xff to the end */
@@ -361,11 +711,11 @@
 	/* fill up header */
 	hp = dp->hdr;
 	*hp = 0;
-	*hp = DSI_HDR_WC(cm->dlen);
-	*hp |= DSI_HDR_VC(cm->vc);
+	*hp = DSI_HDR_WC(dchdr->dlen);
+	*hp |= DSI_HDR_VC(dchdr->vc);
 	*hp |= DSI_HDR_LONG_PKT;
 	*hp |= DSI_HDR_DTYPE(DTYPE_GEN_LWRITE);
-	if (cm->last)
+	if (dchdr->last)
 		*hp |= DSI_HDR_LAST;
 
 	dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
@@ -380,8 +730,9 @@
 {
 	u32 *hp;
 	int len;
+	struct dsi_ctrl_hdr *dchdr = &cm->dchdr;
 
-	if (cm->dlen && cm->payload == 0) {
+	if (dchdr->dlen && cm->payload == 0) {
 		pr_err("%s: NO payload error\n", __func__);
 		return 0;
 	}
@@ -389,11 +740,11 @@
 	dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
 	hp = dp->hdr;
 	*hp = 0;
-	*hp |= DSI_HDR_VC(cm->vc);
-	if (cm->last)
+	*hp |= DSI_HDR_VC(dchdr->vc);
+	if (dchdr->last)
 		*hp |= DSI_HDR_LAST;
 
-	len = (cm->dlen > 2) ? 2 : cm->dlen;
+	len = (dchdr->dlen > 2) ? 2 : dchdr->dlen;
 
 	if (len == 1) {
 		*hp |= DSI_HDR_DTYPE(DTYPE_GEN_WRITE1);
@@ -421,8 +772,9 @@
 {
 	u32 *hp;
 	int len;
+	struct dsi_ctrl_hdr *dchdr = &cm->dchdr;
 
-	if (cm->dlen && cm->payload == 0) {
+	if (dchdr->dlen && cm->payload == 0) {
 		pr_err("%s: NO payload error\n", __func__);
 		return 0;
 	}
@@ -430,12 +782,12 @@
 	dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
 	hp = dp->hdr;
 	*hp = 0;
-	*hp |= DSI_HDR_VC(cm->vc);
+	*hp |= DSI_HDR_VC(dchdr->vc);
 	*hp |= DSI_HDR_BTA;
-	if (cm->last)
+	if (dchdr->last)
 		*hp |= DSI_HDR_LAST;
 
-	len = (cm->dlen > 2) ? 2 : cm->dlen;
+	len = (dchdr->dlen > 2) ? 2 : dchdr->dlen;
 
 	if (len == 1) {
 		*hp |= DSI_HDR_DTYPE(DTYPE_GEN_READ1);
@@ -463,6 +815,7 @@
 	char *bp;
 	u32 *hp;
 	int i, len;
+	struct dsi_ctrl_hdr *dchdr = &cm->dchdr;
 
 	bp = dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
 
@@ -471,10 +824,10 @@
 	 * dcs command byte (first byte) followed by payload
 	 */
 	if (cm->payload) {
-		len = cm->dlen;
+		len = dchdr->dlen;
 		len += 3;
 		len &= ~0x03; /* multipled by 4 */
-		for (i = 0; i < cm->dlen; i++)
+		for (i = 0; i < dchdr->dlen; i++)
 			*bp++ = cm->payload[i];
 
 		/* append 0xff to the end */
@@ -487,11 +840,11 @@
 	/* fill up header */
 	hp = dp->hdr;
 	*hp = 0;
-	*hp = DSI_HDR_WC(cm->dlen);
-	*hp |= DSI_HDR_VC(cm->vc);
+	*hp = DSI_HDR_WC(dchdr->dlen);
+	*hp |= DSI_HDR_VC(dchdr->vc);
 	*hp |= DSI_HDR_LONG_PKT;
 	*hp |= DSI_HDR_DTYPE(DTYPE_DCS_LWRITE);
-	if (cm->last)
+	if (dchdr->last)
 		*hp |= DSI_HDR_LAST;
 
 	dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
@@ -506,6 +859,7 @@
 {
 	u32 *hp;
 	int len;
+	struct dsi_ctrl_hdr *dchdr = &cm->dchdr;
 
 	if (cm->payload == 0) {
 		pr_err("%s: NO payload error\n", __func__);
@@ -515,13 +869,13 @@
 	dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
 	hp = dp->hdr;
 	*hp = 0;
-	*hp |= DSI_HDR_VC(cm->vc);
-	if (cm->ack)
+	*hp |= DSI_HDR_VC(dchdr->vc);
+	if (dchdr->ack)
 		*hp |= DSI_HDR_BTA;
-	if (cm->last)
+	if (dchdr->last)
 		*hp |= DSI_HDR_LAST;
 
-	len = (cm->dlen > 1) ? 1 : cm->dlen;
+	len = (dchdr->dlen > 1) ? 1 : dchdr->dlen;
 
 	*hp |= DSI_HDR_DTYPE(DTYPE_DCS_WRITE);
 	*hp |= DSI_HDR_DATA1(cm->payload[0]); /* dcs command byte */
@@ -537,8 +891,9 @@
 static int dsi_dcs_swrite1(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
 {
 	u32 *hp;
+	struct dsi_ctrl_hdr *dchdr = &cm->dchdr;
 
-	if (cm->dlen < 2 || cm->payload == 0) {
+	if (dchdr->dlen < 2 || cm->payload == 0) {
 		pr_err("%s: NO payload error\n", __func__);
 		return -EINVAL;
 	}
@@ -546,10 +901,10 @@
 	dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
 	hp = dp->hdr;
 	*hp = 0;
-	*hp |= DSI_HDR_VC(cm->vc);
-	if (cm->ack)
+	*hp |= DSI_HDR_VC(dchdr->vc);
+	if (dchdr->ack)
 		*hp |= DSI_HDR_BTA;
-	if (cm->last)
+	if (dchdr->last)
 		*hp |= DSI_HDR_LAST;
 
 	*hp |= DSI_HDR_DTYPE(DTYPE_DCS_WRITE1);
@@ -567,6 +922,7 @@
 static int dsi_dcs_read(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
 {
 	u32 *hp;
+	struct dsi_ctrl_hdr *dchdr = &cm->dchdr;
 
 	if (cm->payload == 0) {
 		pr_err("%s: NO payload error\n", __func__);
@@ -576,10 +932,10 @@
 	dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
 	hp = dp->hdr;
 	*hp = 0;
-	*hp |= DSI_HDR_VC(cm->vc);
+	*hp |= DSI_HDR_VC(dchdr->vc);
 	*hp |= DSI_HDR_BTA;
 	*hp |= DSI_HDR_DTYPE(DTYPE_DCS_READ);
-	if (cm->last)
+	if (dchdr->last)
 		*hp |= DSI_HDR_LAST;
 
 	*hp |= DSI_HDR_DATA1(cm->payload[0]); /* dcs command byte */
@@ -593,13 +949,14 @@
 static int dsi_cm_on(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
 {
 	u32 *hp;
+	struct dsi_ctrl_hdr *dchdr = &cm->dchdr;
 
 	dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
 	hp = dp->hdr;
 	*hp = 0;
-	*hp |= DSI_HDR_VC(cm->vc);
+	*hp |= DSI_HDR_VC(dchdr->vc);
 	*hp |= DSI_HDR_DTYPE(DTYPE_CM_ON);
-	if (cm->last)
+	if (dchdr->last)
 		*hp |= DSI_HDR_LAST;
 
 	dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
@@ -610,13 +967,14 @@
 static int dsi_cm_off(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
 {
 	u32 *hp;
+	struct dsi_ctrl_hdr *dchdr = &cm->dchdr;
 
 	dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
 	hp = dp->hdr;
 	*hp = 0;
-	*hp |= DSI_HDR_VC(cm->vc);
+	*hp |= DSI_HDR_VC(dchdr->vc);
 	*hp |= DSI_HDR_DTYPE(DTYPE_CM_OFF);
-	if (cm->last)
+	if (dchdr->last)
 		*hp |= DSI_HDR_LAST;
 
 	dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
@@ -627,13 +985,14 @@
 static int dsi_peripheral_on(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
 {
 	u32 *hp;
+	struct dsi_ctrl_hdr *dchdr = &cm->dchdr;
 
 	dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
 	hp = dp->hdr;
 	*hp = 0;
-	*hp |= DSI_HDR_VC(cm->vc);
+	*hp |= DSI_HDR_VC(dchdr->vc);
 	*hp |= DSI_HDR_DTYPE(DTYPE_PERIPHERAL_ON);
-	if (cm->last)
+	if (dchdr->last)
 		*hp |= DSI_HDR_LAST;
 
 	dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
@@ -644,13 +1003,14 @@
 static int dsi_peripheral_off(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
 {
 	u32 *hp;
+	struct dsi_ctrl_hdr *dchdr = &cm->dchdr;
 
 	dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
 	hp = dp->hdr;
 	*hp = 0;
-	*hp |= DSI_HDR_VC(cm->vc);
+	*hp |= DSI_HDR_VC(dchdr->vc);
 	*hp |= DSI_HDR_DTYPE(DTYPE_PERIPHERAL_OFF);
-	if (cm->last)
+	if (dchdr->last)
 		*hp |= DSI_HDR_LAST;
 
 	dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
@@ -661,6 +1021,7 @@
 static int dsi_set_max_pktsize(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
 {
 	u32 *hp;
+	struct dsi_ctrl_hdr *dchdr = &cm->dchdr;
 
 	if (cm->payload == 0) {
 		pr_err("%s: NO payload error\n", __func__);
@@ -670,9 +1031,9 @@
 	dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
 	hp = dp->hdr;
 	*hp = 0;
-	*hp |= DSI_HDR_VC(cm->vc);
+	*hp |= DSI_HDR_VC(dchdr->vc);
 	*hp |= DSI_HDR_DTYPE(DTYPE_MAX_PKTSIZE);
-	if (cm->last)
+	if (dchdr->last)
 		*hp |= DSI_HDR_LAST;
 
 	*hp |= DSI_HDR_DATA1(cm->payload[0]);
@@ -686,15 +1047,16 @@
 static int dsi_null_pkt(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
 {
 	u32 *hp;
+	struct dsi_ctrl_hdr *dchdr = &cm->dchdr;
 
 	dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
 	hp = dp->hdr;
 	*hp = 0;
-	*hp = DSI_HDR_WC(cm->dlen);
+	*hp = DSI_HDR_WC(dchdr->dlen);
 	*hp |= DSI_HDR_LONG_PKT;
-	*hp |= DSI_HDR_VC(cm->vc);
+	*hp |= DSI_HDR_VC(dchdr->vc);
 	*hp |= DSI_HDR_DTYPE(DTYPE_NULL_PKT);
-	if (cm->last)
+	if (dchdr->last)
 		*hp |= DSI_HDR_LAST;
 
 	dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
@@ -705,15 +1067,16 @@
 static int dsi_blank_pkt(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
 {
 	u32 *hp;
+	struct dsi_ctrl_hdr *dchdr = &cm->dchdr;
 
 	dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
 	hp = dp->hdr;
 	*hp = 0;
-	*hp = DSI_HDR_WC(cm->dlen);
+	*hp = DSI_HDR_WC(dchdr->dlen);
 	*hp |= DSI_HDR_LONG_PKT;
-	*hp |= DSI_HDR_VC(cm->vc);
+	*hp |= DSI_HDR_VC(dchdr->vc);
 	*hp |= DSI_HDR_DTYPE(DTYPE_BLANK_PKT);
-	if (cm->last)
+	if (dchdr->last)
 		*hp |= DSI_HDR_LAST;
 
 	dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
@@ -727,8 +1090,9 @@
 int dsi_cmd_dma_add(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
 {
 	int len = 0;
+	struct dsi_ctrl_hdr *dchdr = &cm->dchdr;
 
-	switch (cm->dtype) {
+	switch (dchdr->dtype) {
 	case DTYPE_GEN_WRITE:
 	case DTYPE_GEN_WRITE1:
 	case DTYPE_GEN_WRITE2:
@@ -777,7 +1141,7 @@
 		break;
 	default:
 		pr_debug("%s: dtype=%x NOT supported\n",
-					__func__, cm->dtype);
+					__func__, dchdr->dtype);
 		break;
 
 	}
diff --git a/drivers/video/msm/mdss/dsi_v2.h b/drivers/video/msm/mdss/dsi_v2.h
index 73df790..a554856 100644
--- a/drivers/video/msm/mdss/dsi_v2.h
+++ b/drivers/video/msm/mdss/dsi_v2.h
@@ -11,190 +11,18 @@
  *
  */
 
-#ifndef MDSS_DSI_H
-#define MDSS_DSI_H
+#ifndef DSI_V2_H
+#define DSI_V2_H
 
 #include <linux/list.h>
 #include <mach/scm-io.h>
 
+#include "mdss_dsi.h"
 #include "mdss_panel.h"
 
-#define MIPI_OUTP(addr, data) writel_relaxed((data), (addr))
-#define MIPI_INP(addr) readl_relaxed(addr)
-
-#define MIPI_DSI_PRIM 1
-#define MIPI_DSI_SECD 2
-
-#define MIPI_DSI_PANEL_VGA	0
-#define MIPI_DSI_PANEL_WVGA	1
-#define MIPI_DSI_PANEL_WVGA_PT	2
-#define MIPI_DSI_PANEL_FWVGA_PT	3
-#define MIPI_DSI_PANEL_WSVGA_PT	4
-#define MIPI_DSI_PANEL_QHD_PT 5
-#define MIPI_DSI_PANEL_WXGA	6
-#define MIPI_DSI_PANEL_WUXGA	7
-#define MIPI_DSI_PANEL_720P_PT	8
-#define DSI_PANEL_MAX	8
-
-enum {
-	DSI_VIDEO_MODE,
-	DSI_CMD_MODE,
-};
-
-enum {
-	ST_DSI_CLK_OFF,
-	ST_DSI_SUSPEND,
-	ST_DSI_RESUME,
-	ST_DSI_PLAYING,
-	ST_DSI_NUM
-};
-
-enum {
-	EV_DSI_UPDATE,
-	EV_DSI_DONE,
-	EV_DSI_TOUT,
-	EV_DSI_NUM
-};
-
-enum {
-	LANDSCAPE = 1,
-	PORTRAIT = 2,
-};
-
-enum {
-	DSI_CMD_MODE_DMA,
-	DSI_CMD_MODE_MDP,
-};
-
-enum {
-	BL_PWM,
-	BL_WLED,
-	BL_DCS_CMD,
-	UNKNOWN_CTRL,
-};
-
-enum {
-	DSI_LP_MODE,
-	DSI_HS_MODE,
-};
-
-#define DSI_NON_BURST_SYNCH_PULSE	0
-#define DSI_NON_BURST_SYNCH_EVENT	1
-#define DSI_BURST_MODE			2
-
-#define DSI_RGB_SWAP_RGB	0
-#define DSI_RGB_SWAP_RBG	1
-#define DSI_RGB_SWAP_BGR	2
-#define DSI_RGB_SWAP_BRG	3
-#define DSI_RGB_SWAP_GRB	4
-#define DSI_RGB_SWAP_GBR	5
-
-#define DSI_VIDEO_DST_FORMAT_RGB565		0
-#define DSI_VIDEO_DST_FORMAT_RGB666		1
-#define DSI_VIDEO_DST_FORMAT_RGB666_LOOSE	2
-#define DSI_VIDEO_DST_FORMAT_RGB888		3
-
-#define DSI_CMD_DST_FORMAT_RGB111	0
-#define DSI_CMD_DST_FORMAT_RGB332	3
-#define DSI_CMD_DST_FORMAT_RGB444	4
-#define DSI_CMD_DST_FORMAT_RGB565	6
-#define DSI_CMD_DST_FORMAT_RGB666	7
-#define DSI_CMD_DST_FORMAT_RGB888	8
-
-#define DSI_CMD_TRIGGER_NONE		0x0	/* mdp trigger */
-#define DSI_CMD_TRIGGER_TE		0x02
-#define DSI_CMD_TRIGGER_SW		0x04
-#define DSI_CMD_TRIGGER_SW_SEOF		0x05	/* cmd dma only */
-#define DSI_CMD_TRIGGER_SW_TE		0x06
-
-#define DSI_HOST_HDR_SIZE	4
-#define DSI_HDR_LAST		BIT(31)
-#define DSI_HDR_LONG_PKT	BIT(30)
-#define DSI_HDR_BTA		BIT(29)
-#define DSI_HDR_VC(vc)		(((vc) & 0x03) << 22)
-#define DSI_HDR_DTYPE(dtype)	(((dtype) & 0x03f) << 16)
-#define DSI_HDR_DATA2(data)	(((data) & 0x0ff) << 8)
-#define DSI_HDR_DATA1(data)	((data) & 0x0ff)
-#define DSI_HDR_WC(wc)		((wc) & 0x0ffff)
-
 #define DSI_BUF_SIZE	1024
 #define DSI_MRPS	0x04  /* Maximum Return Packet Size */
 
-#define DSI_LEN 8 /* 4 x 4 - 6 - 2, bytes dcs header+crc-align  */
-
-struct dsi_buf {
-	u32 *hdr;	/* dsi host header */
-	char *start;	/* buffer start addr */
-	char *end;	/* buffer end addr */
-	int size;	/* size of buffer */
-	char *data;	/* buffer */
-	int len;	/* data length */
-	dma_addr_t dmap; /* mapped dma addr */
-};
-
-/* dcs read/write */
-#define DTYPE_DCS_WRITE		0x05	/* short write, 0 parameter */
-#define DTYPE_DCS_WRITE1	0x15	/* short write, 1 parameter */
-#define DTYPE_DCS_READ		0x06	/* read */
-#define DTYPE_DCS_LWRITE	0x39	/* long write */
-
-/* generic read/write */
-#define DTYPE_GEN_WRITE		0x03	/* short write, 0 parameter */
-#define DTYPE_GEN_WRITE1	0x13	/* short write, 1 parameter */
-#define DTYPE_GEN_WRITE2	0x23	/* short write, 2 parameter */
-#define DTYPE_GEN_LWRITE	0x29	/* long write */
-#define DTYPE_GEN_READ		0x04	/* long read, 0 parameter */
-#define DTYPE_GEN_READ1		0x14	/* long read, 1 parameter */
-#define DTYPE_GEN_READ2		0x24	/* long read, 2 parameter */
-
-#define DTYPE_TEAR_ON		0x35	/* set tear on */
-#define DTYPE_MAX_PKTSIZE	0x37	/* set max packet size */
-#define DTYPE_NULL_PKT		0x09	/* null packet, no data */
-#define DTYPE_BLANK_PKT		0x19	/* blankiing packet, no data */
-
-#define DTYPE_CM_ON		0x02	/* color mode off */
-#define DTYPE_CM_OFF		0x12	/* color mode on */
-#define DTYPE_PERIPHERAL_OFF	0x22
-#define DTYPE_PERIPHERAL_ON	0x32
-
-/*
- * dcs response
- */
-#define DTYPE_ACK_ERR_RESP      0x02
-#define DTYPE_EOT_RESP          0x08    /* end of tx */
-#define DTYPE_GEN_READ1_RESP    0x11    /* 1 parameter, short */
-#define DTYPE_GEN_READ2_RESP    0x12    /* 2 parameter, short */
-#define DTYPE_GEN_LREAD_RESP    0x1a
-#define DTYPE_DCS_LREAD_RESP    0x1c
-#define DTYPE_DCS_READ1_RESP    0x21    /* 1 parameter, short */
-#define DTYPE_DCS_READ2_RESP    0x22    /* 2 parameter, short */
-
-struct dsi_cmd_desc {
-	int dtype;
-	int last;
-	int vc;
-	int ack;	/* ask ACK from peripheral */
-	int wait;
-	int dlen;
-	char *payload;
-};
-
-struct dsi_panel_cmds_list {
-	struct dsi_cmd_desc *buf;
-	int size;
-	char ctrl_state;
-};
-
-struct dsi_panel_common_pdata {
-	struct mdss_panel_info panel_info;
-	int (*on) (struct mdss_panel_data *pdata);
-	int (*off) (struct mdss_panel_data *pdata);
-	void (*reset)(struct mdss_panel_data *pdata, int enable);
-	void (*bl_fnc) (struct mdss_panel_data *pdata, u32 bl_level);
-	struct dsi_panel_cmds_list *dsi_panel_on_cmds;
-	struct dsi_panel_cmds_list *dsi_panel_off_cmds;
-};
-
 struct dsi_interface {
 	int (*on)(struct mdss_panel_data *pdata);
 	int (*off)(struct mdss_panel_data *pdata);
@@ -210,8 +38,7 @@
 };
 
 int dsi_panel_device_register_v2(struct platform_device *pdev,
-				struct dsi_panel_common_pdata *panel_data,
-				char bl_ctrl);
+				struct mdss_dsi_ctrl_pdata *ctrl_pdata);
 
 void dsi_register_interface(struct dsi_interface *intf);
 
@@ -237,4 +64,14 @@
 
 void dsi_set_tx_power_mode(int mode);
 
-#endif /* MDSS_DSI_H */
+void dsi_ctrl_config_deinit(struct platform_device *pdev,
+				struct mdss_dsi_ctrl_pdata *ctrl_pdata);
+
+int dsi_ctrl_config_init(struct platform_device *pdev,
+				struct mdss_dsi_ctrl_pdata *ctrl_pdata);
+
+struct mdss_panel_cfg *mdp3_panel_intf_type(int intf_val);
+
+int mdp3_panel_get_boot_cfg(void);
+
+#endif /* DSI_V2_H */
diff --git a/drivers/video/msm/mdss/mdp3.c b/drivers/video/msm/mdss/mdp3.c
index 66ad706..8a5f1ee 100644
--- a/drivers/video/msm/mdss/mdp3.c
+++ b/drivers/video/msm/mdss/mdp3.c
@@ -15,6 +15,7 @@
 
 #include <linux/clk.h>
 #include <linux/debugfs.h>
+#include <linux/dma-buf.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
@@ -92,6 +93,10 @@
 static struct msm_bus_paths
 	mdp_bus_ppp_usecases[ARRAY_SIZE(mdp_bus_ppp_vectors)];
 
+static struct mdss_panel_intf pan_types[] = {
+	{"dsi", MDSS_PANEL_INTF_DSI},
+};
+
 static struct msm_bus_scale_pdata mdp_bus_ppp_scale_table = {
 	.usecase = mdp_bus_ppp_usecases,
 	.num_usecases = ARRAY_SIZE(mdp_bus_ppp_usecases),
@@ -116,8 +121,19 @@
 };
 
 struct mdp3_iommu_domain_map mdp3_iommu_domains[MDP3_IOMMU_DOMAIN_MAX] = {
-	[MDP3_IOMMU_DOMAIN] = {
-		.domain_type = MDP3_IOMMU_DOMAIN,
+	[MDP3_PPP_IOMMU_DOMAIN] = {
+		.domain_type = MDP3_PPP_IOMMU_DOMAIN,
+		.client_name = "mdp_ppp",
+		.partitions = {
+			{
+				.start = SZ_128K,
+				.size = SZ_1G - SZ_128K,
+			},
+		},
+		.npartitions = 1,
+	},
+	[MDP3_DMA_IOMMU_DOMAIN] = {
+		.domain_type = MDP3_DMA_IOMMU_DOMAIN,
 		.client_name = "mdp_dma",
 		.partitions = {
 			{
@@ -132,27 +148,27 @@
 struct mdp3_iommu_ctx_map mdp3_iommu_contexts[MDP3_IOMMU_CTX_MAX] = {
 	[MDP3_IOMMU_CTX_PPP_0] = {
 		.ctx_type = MDP3_IOMMU_CTX_PPP_0,
-		.domain = &mdp3_iommu_domains[MDP3_IOMMU_DOMAIN],
+		.domain = &mdp3_iommu_domains[MDP3_PPP_IOMMU_DOMAIN],
 		.ctx_name = "mdpe_0",
 		.attached = 0,
 	},
 	[MDP3_IOMMU_CTX_PPP_1] = {
 		.ctx_type = MDP3_IOMMU_CTX_PPP_1,
-		.domain = &mdp3_iommu_domains[MDP3_IOMMU_DOMAIN],
+		.domain = &mdp3_iommu_domains[MDP3_PPP_IOMMU_DOMAIN],
 		.ctx_name = "mdpe_1",
 		.attached = 0,
 	},
 
 	[MDP3_IOMMU_CTX_DMA_0] = {
 		.ctx_type = MDP3_IOMMU_CTX_DMA_0,
-		.domain = &mdp3_iommu_domains[MDP3_IOMMU_DOMAIN],
+		.domain = &mdp3_iommu_domains[MDP3_DMA_IOMMU_DOMAIN],
 		.ctx_name = "mdps_0",
 		.attached = 0,
 	},
 
 	[MDP3_IOMMU_CTX_DMA_1] = {
 		.ctx_type = MDP3_IOMMU_CTX_DMA_1,
-		.domain = &mdp3_iommu_domains[MDP3_IOMMU_DOMAIN],
+		.domain = &mdp3_iommu_domains[MDP3_DMA_IOMMU_DOMAIN],
 		.ctx_name = "mdps_1",
 		.attached = 0,
 	},
@@ -379,7 +395,7 @@
 
 static int mdp3_clk_update(u32 clk_idx, u32 enable)
 {
-	int ret = -EINVAL;
+	int ret = 0;
 	struct clk *clk;
 	int count = 0;
 
@@ -681,6 +697,8 @@
 {
 	int ret;
 
+	mutex_init(&mdp3_res->iommu_lock);
+
 	ret = mdp3_iommu_domain_init();
 	if (ret) {
 		pr_err("mdp3 iommu domain init fails\n");
@@ -807,9 +825,191 @@
 		devm_free_irq(&mdp3_res->pdev->dev, mdp3_res->irq, mdp3_res);
 }
 
+static int mdp3_get_pan_intf(const char *pan_intf)
+{
+	int i, rc = MDSS_PANEL_INTF_INVALID;
+
+	if (!pan_intf)
+		return rc;
+
+	for (i = 0; i < ARRAY_SIZE(pan_types); i++) {
+		if (!strncmp(pan_intf, pan_types[i].name,
+				strlen(pan_types[i].name))) {
+			rc = pan_types[i].type;
+			break;
+		}
+	}
+
+	return rc;
+}
+
+static int mdp3_parse_dt_pan_intf(struct platform_device *pdev)
+{
+	int rc;
+	struct mdp3_hw_resource *mdata = platform_get_drvdata(pdev);
+	const char *prim_intf = NULL;
+
+	rc = of_property_read_string(pdev->dev.of_node,
+				"qcom,mdss-pref-prim-intf", &prim_intf);
+	if (rc)
+		return -ENODEV;
+
+	rc = mdp3_get_pan_intf(prim_intf);
+	if (rc < 0) {
+		mdata->pan_cfg.pan_intf = MDSS_PANEL_INTF_INVALID;
+	} else {
+		mdata->pan_cfg.pan_intf = rc;
+		rc = 0;
+	}
+	return rc;
+}
+
+static int mdp3_get_pan_cfg(struct mdss_panel_cfg *pan_cfg)
+{
+	char *t = NULL;
+	char pan_intf_str[MDSS_MAX_PANEL_LEN];
+	int rc, i;
+	char pan_name[MDSS_MAX_PANEL_LEN];
+
+	if (!pan_cfg)
+		return -EINVAL;
+
+	strlcpy(pan_name, &pan_cfg->arg_cfg[0], sizeof(pan_cfg->arg_cfg));
+	if (pan_name[0] == '0') {
+		pan_cfg->lk_cfg = false;
+	} else if (pan_name[0] == '1') {
+		pan_cfg->lk_cfg = true;
+	} else {
+		/* read from dt */
+		pan_cfg->lk_cfg = true;
+		pan_cfg->pan_intf = MDSS_PANEL_INTF_INVALID;
+		return -EINVAL;
+	}
+
+	/* skip lk cfg and delimiter; ex: "0:" */
+	strlcpy(pan_name, &pan_name[2], MDSS_MAX_PANEL_LEN);
+	t = strnstr(pan_name, ":", MDSS_MAX_PANEL_LEN);
+	if (!t) {
+		pr_err("%s: pan_name=[%s] invalid\n",
+			__func__, pan_name);
+		pan_cfg->pan_intf = MDSS_PANEL_INTF_INVALID;
+		return -EINVAL;
+	}
+
+	for (i = 0; ((pan_name + i) < t) && (i < 4); i++)
+		pan_intf_str[i] = *(pan_name + i);
+	pan_intf_str[i] = 0;
+	pr_debug("%s:%d panel intf %s\n", __func__, __LINE__, pan_intf_str);
+	/* point to the start of panel name */
+	t = t + 1;
+	strlcpy(&pan_cfg->arg_cfg[0], t, sizeof(pan_cfg->arg_cfg));
+	pr_debug("%s:%d: t=[%s] panel name=[%s]\n", __func__, __LINE__,
+		t, pan_cfg->arg_cfg);
+	rc = mdp3_get_pan_intf(pan_intf_str);
+	pan_cfg->pan_intf = (rc < 0) ?  MDSS_PANEL_INTF_INVALID : rc;
+	return 0;
+}
+
+static int mdp3_parse_bootarg(struct platform_device *pdev)
+{
+	struct device_node *chosen_node;
+	static const char *cmd_line;
+	char *disp_idx, *end_idx;
+	int rc, len = 0, name_len, cmd_len;
+	int *intf_type;
+	char *panel_name;
+	struct mdss_panel_cfg *pan_cfg;
+	struct mdp3_hw_resource *mdata = platform_get_drvdata(pdev);
+
+	mdata->pan_cfg.arg_cfg[MDSS_MAX_PANEL_LEN] = 0;
+	pan_cfg = &mdata->pan_cfg;
+	panel_name = &pan_cfg->arg_cfg[0];
+	intf_type = &pan_cfg->pan_intf;
+
+	/* reads from dt by default */
+	pan_cfg->lk_cfg = true;
+
+	chosen_node = of_find_node_by_name(NULL, "chosen");
+	if (!chosen_node) {
+		pr_err("%s: get chosen node failed\n", __func__);
+		rc = -ENODEV;
+		goto get_dt_pan;
+	}
+
+	cmd_line = of_get_property(chosen_node, "bootargs", &len);
+	if (!cmd_line || len <= 0) {
+		pr_err("%s: get bootargs failed\n", __func__);
+		rc = -ENODEV;
+		goto get_dt_pan;
+	}
+
+	name_len = strlen("mdss_mdp.panel=");
+	cmd_len = strlen(cmd_line);
+	disp_idx = strnstr(cmd_line, "mdss_mdp.panel=", cmd_len);
+	if (!disp_idx) {
+		pr_err("%s:%d:cmdline panel not set disp_idx=[%p]\n",
+				__func__, __LINE__, disp_idx);
+		memset(panel_name, 0x00, MDSS_MAX_PANEL_LEN);
+		*intf_type = MDSS_PANEL_INTF_INVALID;
+		rc = MDSS_PANEL_INTF_INVALID;
+		goto get_dt_pan;
+	}
+
+	disp_idx += name_len;
+
+	end_idx = strnstr(disp_idx, " ", MDSS_MAX_PANEL_LEN);
+	pr_debug("%s:%d: pan_name=[%s] end=[%s]\n", __func__, __LINE__,
+		 disp_idx, end_idx);
+	if (!end_idx) {
+		end_idx = disp_idx + strlen(disp_idx) + 1;
+		pr_warn("%s:%d: pan_name=[%s] end=[%s]\n", __func__,
+		       __LINE__, disp_idx, end_idx);
+	}
+
+	if (end_idx <= disp_idx) {
+		pr_err("%s:%d:cmdline pan incorrect end=[%p] disp=[%p]\n",
+			__func__, __LINE__, end_idx, disp_idx);
+		memset(panel_name, 0x00, MDSS_MAX_PANEL_LEN);
+		*intf_type = MDSS_PANEL_INTF_INVALID;
+		rc = MDSS_PANEL_INTF_INVALID;
+		goto get_dt_pan;
+	}
+
+	*end_idx = 0;
+	len = end_idx - disp_idx + 1;
+	if (len <= 0) {
+		pr_warn("%s: panel name not rx", __func__);
+		rc = -EINVAL;
+		goto get_dt_pan;
+	}
+
+	strlcpy(panel_name, disp_idx, min(++len, MDSS_MAX_PANEL_LEN));
+	pr_debug("%s:%d panel:[%s]", __func__, __LINE__, panel_name);
+	of_node_put(chosen_node);
+
+	rc = mdp3_get_pan_cfg(pan_cfg);
+	if (!rc)
+		pan_cfg->init_done = true;
+
+	return rc;
+
+get_dt_pan:
+	rc = mdp3_parse_dt_pan_intf(pdev);
+	/* if pref pan intf is not present */
+	if (rc)
+		pr_err("%s:unable to parse device tree for pan intf\n",
+			__func__);
+	else
+		pan_cfg->init_done = true;
+
+	of_node_put(chosen_node);
+	return rc;
+}
+
 static int mdp3_parse_dt(struct platform_device *pdev)
 {
 	struct resource *res;
+	int rc;
 
 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mdp_phys");
 	if (!res) {
@@ -836,20 +1036,345 @@
 	}
 	mdp3_res->irq = res->start;
 
+	rc = mdp3_parse_bootarg(pdev);
+	if (rc) {
+		pr_err("%s: Error in panel override:rc=[%d]\n",
+		       __func__, rc);
+		return rc;
+	}
+
 	return 0;
 }
 
-int mdp3_put_img(struct mdp3_img_data *data)
+static void mdp3_iommu_heap_unmap_iommu(struct mdp3_iommu_meta *meta)
+{
+	unsigned int domain_num;
+	unsigned int partition_num = 0;
+	struct iommu_domain *domain;
+
+	domain_num = (mdp3_res->domains + MDP3_PPP_IOMMU_DOMAIN)->domain_idx;
+	domain = msm_get_iommu_domain(domain_num);
+
+	if (!domain) {
+		pr_err("Could not get domain %d. Corruption?\n", domain_num);
+		return;
+	}
+
+	iommu_unmap_range(domain, meta->iova_addr, meta->mapped_size);
+	msm_free_iova_address(meta->iova_addr, domain_num, partition_num,
+		meta->mapped_size);
+
+	return;
+}
+
+static void mdp3_iommu_meta_destroy(struct kref *kref)
+{
+	struct mdp3_iommu_meta *meta =
+			container_of(kref, struct mdp3_iommu_meta, ref);
+
+	rb_erase(&meta->node, &mdp3_res->iommu_root);
+	mdp3_iommu_heap_unmap_iommu(meta);
+	dma_buf_put(meta->dbuf);
+	kfree(meta);
+}
+
+
+static void mdp3_iommu_meta_put(struct mdp3_iommu_meta *meta)
+{
+	/* Need to lock here to prevent race against map/unmap */
+	mutex_lock(&mdp3_res->iommu_lock);
+	kref_put(&meta->ref, mdp3_iommu_meta_destroy);
+	mutex_unlock(&mdp3_res->iommu_lock);
+}
+
+static struct mdp3_iommu_meta *mdp3_iommu_meta_lookup(struct sg_table *table)
+{
+	struct rb_root *root = &mdp3_res->iommu_root;
+	struct rb_node **p = &root->rb_node;
+	struct rb_node *parent = NULL;
+	struct mdp3_iommu_meta *entry = NULL;
+
+	while (*p) {
+		parent = *p;
+		entry = rb_entry(parent, struct mdp3_iommu_meta, node);
+
+		if (table < entry->table)
+			p = &(*p)->rb_left;
+		else if (table > entry->table)
+			p = &(*p)->rb_right;
+		else
+			return entry;
+	}
+	return NULL;
+}
+
+void mdp3_unmap_iommu(struct ion_client *client, struct ion_handle *handle)
+{
+	struct mdp3_iommu_meta *meta;
+	struct sg_table *table;
+
+	table = ion_sg_table(client, handle);
+
+	mutex_lock(&mdp3_res->iommu_lock);
+	meta = mdp3_iommu_meta_lookup(table);
+	if (!meta) {
+		WARN(1, "%s: buffer was never mapped for %p\n", __func__,
+				handle);
+		mutex_unlock(&mdp3_res->iommu_lock);
+		goto out;
+	}
+	mutex_unlock(&mdp3_res->iommu_lock);
+
+	mdp3_iommu_meta_put(meta);
+out:
+	return;
+}
+
+static void mdp3_iommu_meta_add(struct mdp3_iommu_meta *meta)
+{
+	struct rb_root *root = &mdp3_res->iommu_root;
+	struct rb_node **p = &root->rb_node;
+	struct rb_node *parent = NULL;
+	struct mdp3_iommu_meta *entry;
+
+	while (*p) {
+		parent = *p;
+		entry = rb_entry(parent, struct mdp3_iommu_meta, node);
+
+		if (meta->table < entry->table) {
+			p = &(*p)->rb_left;
+		} else if (meta->table > entry->table) {
+			p = &(*p)->rb_right;
+		} else {
+			pr_err("%s: handle %p already exists\n", __func__,
+				entry->handle);
+			BUG();
+		}
+	}
+
+	rb_link_node(&meta->node, parent, p);
+	rb_insert_color(&meta->node, root);
+}
+
+static int mdp3_iommu_map_iommu(struct mdp3_iommu_meta *meta,
+	unsigned long align, unsigned long iova_length,
+	unsigned int padding, unsigned long flags)
+{
+	struct iommu_domain *domain;
+	int ret = 0;
+	unsigned long size;
+	unsigned long unmap_size;
+	struct sg_table *table;
+	int prot = IOMMU_WRITE | IOMMU_READ;
+	unsigned int domain_num = (mdp3_res->domains +
+			MDP3_PPP_IOMMU_DOMAIN)->domain_idx;
+	unsigned int partition_num = 0;
+
+	size = meta->size;
+	table = meta->table;
+
+	/* Use the biggest alignment to allow bigger IOMMU mappings.
+	 * Use the first entry since the first entry will always be the
+	 * biggest entry. To take advantage of bigger mapping sizes both the
+	 * VA and PA addresses have to be aligned to the biggest size.
+	 */
+	if (sg_dma_len(table->sgl) > align)
+		align = sg_dma_len(table->sgl);
+
+	ret = msm_allocate_iova_address(domain_num, partition_num,
+			meta->mapped_size, align, &meta->iova_addr);
+
+	if (ret)
+		goto out;
+
+	domain = msm_get_iommu_domain(domain_num);
+
+	if (!domain) {
+		ret = -ENOMEM;
+		goto out1;
+	}
+
+	/* Adding padding to before buffer */
+	if (padding) {
+		unsigned long phys_addr = sg_phys(table->sgl);
+		ret = msm_iommu_map_extra(domain, meta->iova_addr, phys_addr,
+				padding, SZ_4K, prot);
+		if (ret)
+			goto out1;
+	}
+
+	/* Mapping actual buffer */
+	ret = iommu_map_range(domain, meta->iova_addr + padding,
+			table->sgl, size, prot);
+	if (ret) {
+		pr_err("%s: could not map %lx in domain %p\n",
+			__func__, meta->iova_addr, domain);
+			unmap_size = padding;
+		goto out2;
+	}
+
+	/* Adding padding to end of buffer */
+	if (padding) {
+		unsigned long phys_addr = sg_phys(table->sgl);
+		unsigned long extra_iova_addr = meta->iova_addr +
+				padding + size;
+		ret = msm_iommu_map_extra(domain, extra_iova_addr, phys_addr,
+				padding, SZ_4K, prot);
+		if (ret) {
+			unmap_size = padding + size;
+			goto out2;
+		}
+	}
+	return ret;
+
+out2:
+	iommu_unmap_range(domain, meta->iova_addr, unmap_size);
+out1:
+	msm_free_iova_address(meta->iova_addr, domain_num, partition_num,
+				iova_length);
+
+out:
+	return ret;
+}
+
+static struct mdp3_iommu_meta *mdp3_iommu_meta_create(struct ion_client *client,
+	struct ion_handle *handle, struct sg_table *table, unsigned long size,
+	unsigned long align, unsigned long iova_length, unsigned int padding,
+	unsigned long flags, unsigned long *iova)
+{
+	struct mdp3_iommu_meta *meta;
+	int ret;
+
+	meta = kzalloc(sizeof(*meta), GFP_KERNEL);
+
+	if (!meta)
+		return ERR_PTR(-ENOMEM);
+
+	meta->handle = handle;
+	meta->table = table;
+	meta->size = size;
+	meta->mapped_size = iova_length;
+	meta->dbuf = ion_share_dma_buf(client, handle);
+	kref_init(&meta->ref);
+
+	ret = mdp3_iommu_map_iommu(meta,
+		align, iova_length, padding, flags);
+	if (ret < 0)	{
+		pr_err("%s: Unable to map buffer\n", __func__);
+		goto out;
+	}
+
+	*iova = meta->iova_addr;
+	mdp3_iommu_meta_add(meta);
+
+	return meta;
+out:
+	kfree(meta);
+	return ERR_PTR(ret);
+}
+
+/*
+ * PPP hw reads in tiles of 16 which might be outside mapped region
+ * need to map buffers ourseleve to add extra padding
+ */
+int mdp3_self_map_iommu(struct ion_client *client, struct ion_handle *handle,
+	unsigned long align, unsigned long padding, unsigned long *iova,
+	unsigned long *buffer_size, unsigned long flags,
+	unsigned long iommu_flags)
+{
+	struct mdp3_iommu_meta *iommu_meta = NULL;
+	struct sg_table *table;
+	struct scatterlist *sg;
+	unsigned long size = 0, iova_length = 0;
+	int ret = 0;
+	int i;
+
+	table = ion_sg_table(client, handle);
+	if (IS_ERR_OR_NULL(table))
+		return PTR_ERR(table);
+
+	for_each_sg(table->sgl, sg, table->nents, i)
+		size += sg_dma_len(sg);
+
+	padding = PAGE_ALIGN(padding);
+
+	/* Adding 16 lines padding before and after buffer */
+	iova_length = size + 2 * padding;
+
+	if (size & ~PAGE_MASK) {
+		pr_debug("%s: buffer size %lx is not aligned to %lx", __func__,
+			size, PAGE_SIZE);
+		ret = -EINVAL;
+		goto out;
+	}
+
+	if (iova_length & ~PAGE_MASK) {
+		pr_debug("%s: iova_length %lx is not aligned to %lx", __func__,
+			iova_length, PAGE_SIZE);
+		ret = -EINVAL;
+		goto out;
+	}
+
+	mutex_lock(&mdp3_res->iommu_lock);
+	iommu_meta = mdp3_iommu_meta_lookup(table);
+
+	if (!iommu_meta) {
+		iommu_meta = mdp3_iommu_meta_create(client, handle, table, size,
+				align, iova_length, padding, flags, iova);
+		if (!IS_ERR_OR_NULL(iommu_meta)) {
+			iommu_meta->flags = iommu_flags;
+			ret = 0;
+		} else {
+			ret = PTR_ERR(iommu_meta);
+			goto out_unlock;
+		}
+	} else {
+		if (iommu_meta->flags != iommu_flags) {
+			pr_err("%s: handle %p is already mapped with diff flag\n",
+				__func__, handle);
+			ret = -EINVAL;
+			goto out_unlock;
+		} else if (iommu_meta->mapped_size != iova_length) {
+			pr_err("%s: handle %p is already mapped with diff len\n",
+				__func__, handle);
+			ret = -EINVAL;
+			goto out_unlock;
+		} else {
+			kref_get(&iommu_meta->ref);
+			*iova = iommu_meta->iova_addr;
+		}
+	}
+	BUG_ON(iommu_meta->size != size);
+	mutex_unlock(&mdp3_res->iommu_lock);
+
+	*iova = *iova + padding;
+	*buffer_size = size;
+	return ret;
+
+out_unlock:
+	mutex_unlock(&mdp3_res->iommu_lock);
+out:
+	mdp3_iommu_meta_put(iommu_meta);
+	return ret;
+}
+
+int mdp3_put_img(struct mdp3_img_data *data, int client)
 {
 	struct ion_client *iclient = mdp3_res->ion_client;
-	int dom = (mdp3_res->domains + MDP3_IOMMU_DOMAIN)->domain_idx;
+	int dom;
 
 	 if (data->flags & MDP_MEMORY_ID_TYPE_FB) {
 		pr_info("mdp3_put_img fb mem buf=0x%x\n", data->addr);
 		fput_light(data->srcp_file, data->p_need);
 		data->srcp_file = NULL;
 	} else if (!IS_ERR_OR_NULL(data->srcp_ihdl)) {
-		ion_unmap_iommu(iclient, data->srcp_ihdl, dom, 0);
+		if (client == MDP3_CLIENT_DMA_P) {
+			dom = (mdp3_res->domains +
+				MDP3_DMA_IOMMU_DOMAIN)->domain_idx;
+			ion_unmap_iommu(iclient, data->srcp_ihdl, dom, 0);
+		} else {
+			mdp3_unmap_iommu(iclient, data->srcp_ihdl);
+		}
 		ion_free(iclient, data->srcp_ihdl);
 		data->srcp_ihdl = NULL;
 	} else {
@@ -858,14 +1383,15 @@
 	return 0;
 }
 
-int mdp3_get_img(struct msmfb_data *img, struct mdp3_img_data *data)
+int mdp3_get_img(struct msmfb_data *img, struct mdp3_img_data *data,
+		int client)
 {
 	struct file *file;
 	int ret = -EINVAL;
 	int fb_num;
 	unsigned long *start, *len;
 	struct ion_client *iclient = mdp3_res->ion_client;
-	int dom = (mdp3_res->domains + MDP3_IOMMU_DOMAIN)->domain_idx;
+	int dom;
 
 	start = (unsigned long *) &data->addr;
 	len = (unsigned long *) &data->len;
@@ -907,10 +1433,15 @@
 			data->srcp_ihdl = NULL;
 			return ret;
 		}
-
-		ret = ion_map_iommu(iclient, data->srcp_ihdl, dom,
-		    0, SZ_4K, 0, start, len, 0, 0);
-
+		if (client == MDP3_CLIENT_DMA_P) {
+			dom = (mdp3_res->domains +
+					MDP3_DMA_IOMMU_DOMAIN)->domain_idx;
+			ret = ion_map_iommu(iclient, data->srcp_ihdl, dom,
+					0, SZ_4K, 0, start, len, 0, 0);
+		} else {
+			ret = mdp3_self_map_iommu(iclient, data->srcp_ihdl,
+				SZ_4K, data->padding, start, len, 0, 0);
+		}
 		if (IS_ERR_VALUE(ret)) {
 			ion_free(iclient, data->srcp_ihdl);
 			pr_err("failed to map ion handle (%d)\n", ret);
@@ -925,7 +1456,7 @@
 		pr_debug("mem=%d ihdl=%p buf=0x%x len=0x%x\n", img->memory_id,
 			 data->srcp_ihdl, data->addr, data->len);
 	} else {
-		mdp3_put_img(data);
+		mdp3_put_img(data, client);
 		return -EINVAL;
 	}
 
@@ -1095,7 +1626,7 @@
 {
 	if (!mdp3_res)
 		return -ENODEV;
-	return mdp3_res->domains[MDP3_IOMMU_DOMAIN].domain_idx;
+	return mdp3_res->domains[MDP3_DMA_IOMMU_DOMAIN].domain_idx;
 }
 
 int mdp3_continuous_splash_copy(struct mdss_panel_data *pdata)
@@ -1210,7 +1741,8 @@
 	return 0;
 
 splash_on_err:
-	mdp3_clk_enable(0);
+	if (mdp3_clk_enable(0))
+		pr_err("%s: Unable to disable mdp3 clocks\n", __func__);
 	return rc;
 }
 
@@ -1350,6 +1882,31 @@
 	return rc;
 }
 
+struct mdss_panel_cfg *mdp3_panel_intf_type(int intf_val)
+{
+	if (!mdp3_res || !mdp3_res->pan_cfg.init_done)
+		return ERR_PTR(-EPROBE_DEFER);
+
+	if (mdp3_res->pan_cfg.pan_intf == intf_val)
+		return &mdp3_res->pan_cfg;
+	else
+		return NULL;
+}
+EXPORT_SYMBOL(mdp3_panel_intf_type);
+
+int mdp3_panel_get_boot_cfg(void)
+{
+	int rc;
+
+	if (!mdp3_res || !mdp3_res->pan_cfg.init_done)
+		rc = -EPROBE_DEFER;
+	if (mdp3_res->pan_cfg.lk_cfg)
+		rc = 1;
+	else
+		rc = 0;
+	return rc;
+}
+
 static  int mdp3_suspend_sub(struct mdp3_hw_resource *mdata)
 {
 	return 0;
diff --git a/drivers/video/msm/mdss/mdp3.h b/drivers/video/msm/mdss/mdp3.h
index bd1c03d..2f73c42 100644
--- a/drivers/video/msm/mdss/mdp3.h
+++ b/drivers/video/msm/mdss/mdp3.h
@@ -41,8 +41,9 @@
 };
 
 enum {
-	MDP3_IOMMU_DOMAIN,
-	MDP3_IOMMU_DOMAIN_MAX
+	MDP3_DMA_IOMMU_DOMAIN,
+	MDP3_PPP_IOMMU_DOMAIN,
+	MDP3_IOMMU_DOMAIN_MAX,
 };
 
 enum {
@@ -58,6 +59,12 @@
 	MDP3_CLIENT_PPP,
 };
 
+enum {
+	DI_PARTITION_NUM = 0,
+	DI_DOMAIN_NUM = 1,
+	DI_MAX,
+};
+
 struct mdp3_bus_handle_map {
 	struct msm_bus_vectors *bus_vector;
 	struct msm_bus_paths *usecases;
@@ -83,6 +90,19 @@
 	int attached;
 };
 
+struct mdp3_iommu_meta {
+	struct rb_node node;
+	struct ion_handle *handle;
+	struct rb_root iommu_maps;
+	struct kref ref;
+	struct sg_table *table;
+	struct dma_buf *dbuf;
+	int mapped_size;
+	unsigned long size;
+	unsigned long iova_addr;
+	unsigned long flags;
+};
+
 #define MDP3_MAX_INTR 28
 
 struct mdp3_intr_cb {
@@ -111,6 +131,8 @@
 	struct mdp3_iommu_domain_map *domains;
 	struct mdp3_iommu_ctx_map *iommu_contexts;
 	struct ion_handle *ion_handle;
+	struct mutex iommu_lock;
+	struct rb_root iommu_root;
 	void *virt;
 	unsigned long phys;
 	size_t size;
@@ -126,11 +148,13 @@
 	int irq_registered;
 
 	struct early_suspend suspend_handler;
+	struct mdss_panel_cfg pan_cfg;
 };
 
 struct mdp3_img_data {
 	u32 addr;
 	u32 len;
+	u32 padding;
 	u32 flags;
 	int p_need;
 	struct file *srcp_file;
@@ -150,8 +174,9 @@
 int mdp3_clk_set_rate(int clk_type, unsigned long clk_rate, int client);
 int mdp3_clk_enable(int enable);
 int mdp3_bus_scale_set_quota(int client, u64 ab_quota, u64 ib_quota);
-int mdp3_put_img(struct mdp3_img_data *data);
-int mdp3_get_img(struct msmfb_data *img, struct mdp3_img_data *data);
+int mdp3_put_img(struct mdp3_img_data *data, int client);
+int mdp3_get_img(struct msmfb_data *img, struct mdp3_img_data *data,
+		int client);
 int mdp3_iommu_enable(int client);
 int mdp3_iommu_disable(int client);
 int mdp3_iommu_is_attached(int client);
diff --git a/drivers/video/msm/mdss/mdp3_ctrl.c b/drivers/video/msm/mdss/mdp3_ctrl.c
index bb53f33..ac3fd3a 100644
--- a/drivers/video/msm/mdss/mdp3_ctrl.c
+++ b/drivers/video/msm/mdss/mdp3_ctrl.c
@@ -50,7 +50,7 @@
 	while (count--) {
 		struct mdp3_img_data *data = &bufq->img_data[bufq->pop_idx];
 		bufq->pop_idx = (bufq->pop_idx + 1) % MDP3_MAX_BUF_QUEUE;
-		mdp3_put_img(data);
+		mdp3_put_img(data, MDP3_CLIENT_DMA_P);
 	}
 	bufq->count = 0;
 	bufq->push_idx = 0;
@@ -557,6 +557,88 @@
 	return 0;
 }
 
+static int mdp3_ctrl_reset(struct msm_fb_data_type *mfd)
+{
+	int rc = 0;
+	struct mdp3_session_data *mdp3_session;
+	struct mdp3_dma *mdp3_dma;
+	struct mdss_panel_data *panel;
+	struct mdp3_vsync_notification vsync_client;
+
+	pr_debug("mdp3_ctrl_reset\n");
+	mdp3_session = (struct mdp3_session_data *)mfd->mdp.private1;
+	if (!mdp3_session || !mdp3_session->panel || !mdp3_session->dma ||
+		!mdp3_session->intf) {
+		pr_err("mdp3_ctrl_reset no device");
+		return -ENODEV;
+	}
+
+	panel = mdp3_session->panel;
+	mdp3_dma = mdp3_session->dma;
+	mutex_lock(&mdp3_session->lock);
+
+	vsync_client = mdp3_dma->vsync_client;
+
+	rc = mdp3_dma->stop(mdp3_dma, mdp3_session->intf);
+	if (rc) {
+		pr_err("fail to stop the MDP3 dma\n");
+		goto reset_error;
+	}
+
+	rc = panel->event_handler(panel, MDSS_EVENT_PANEL_OFF, NULL);
+	if (rc)
+		pr_err("fail to turn off panel\n");
+
+	rc = mdp3_ctrl_res_req_clk(mfd, 0);
+	if (rc) {
+		pr_err("fail to release mdp clocks\n");
+		goto reset_error;
+	}
+
+	rc = panel->event_handler(panel, MDSS_EVENT_BLANK, NULL);
+	if (rc) {
+		pr_err("fail to blank the panel\n");
+		goto reset_error;
+	}
+
+	rc = mdp3_iommu_enable(MDP3_CLIENT_DMA_P);
+	if (rc) {
+		pr_err("fail to attach dma iommu\n");
+		goto reset_error;
+	}
+
+	rc = panel->event_handler(panel, MDSS_EVENT_UNBLANK, NULL);
+	if (rc) {
+		pr_err("fail to unblank the panel\n");
+		goto reset_error;
+	}
+
+	rc = panel->event_handler(panel, MDSS_EVENT_PANEL_ON, NULL);
+	if (rc) {
+		pr_err("fail to turn on the panel\n");
+		goto reset_error;
+	}
+
+	rc = mdp3_ctrl_res_req_clk(mfd, 1);
+	if (rc) {
+		pr_err("fail to turn on mdp clks\n");
+		goto reset_error;
+	}
+
+	mdp3_ctrl_intf_init(mfd, mdp3_session->intf);
+	mdp3_ctrl_dma_init(mfd, mdp3_dma);
+
+	if (vsync_client.handler)
+		mdp3_dma->vsync_enable(mdp3_dma, &vsync_client);
+
+	if (mfd->fbi->screen_base)
+		rc = mdp3_dma->start(mdp3_dma, mdp3_session->intf);
+
+reset_error:
+	mutex_unlock(&mdp3_session->lock);
+	return rc;
+}
+
 static int mdp3_overlay_get(struct msm_fb_data_type *mfd,
 				struct mdp_overlay *req)
 {
@@ -583,15 +665,15 @@
 
 	mutex_lock(&mdp3_session->lock);
 
-	if (mdp3_session->overlay.id == req->id) {
-		mdp3_session->overlay = *req;
-		if (req->id == MSMFB_NEW_REQUEST) {
-			mdp3_session->overlay.id = 1;
-			req->id = 1;
-		}
-	} else {
-		rc = -EINVAL;
+	if (mdp3_session->overlay.id != req->id)
+		pr_err("overlay was not released, continue to recover\n");
+
+	mdp3_session->overlay = *req;
+	if (req->id == MSMFB_NEW_REQUEST) {
+		mdp3_session->overlay.id = 1;
+		req->id = 1;
 	}
+
 	mutex_unlock(&mdp3_session->lock);
 
 	return rc;
@@ -624,7 +706,7 @@
 	struct msmfb_data *img = &req->data;
 	struct mdp3_img_data data;
 
-	rc = mdp3_get_img(img, &data);
+	rc = mdp3_get_img(img, &data, MDP3_CLIENT_DMA_P);
 	if (rc) {
 		pr_err("fail to get overlay buffer\n");
 		return rc;
@@ -633,7 +715,7 @@
 	rc = mdp3_bufq_push(&mdp3_session->bufq_in, &data);
 	if (rc) {
 		pr_err("fail to queue the overlay buffer, buffer drop\n");
-		mdp3_put_img(&data);
+		mdp3_put_img(&data, MDP3_CLIENT_DMA_P);
 		return rc;
 	}
 	return 0;
@@ -673,20 +755,20 @@
 	if (!mdp3_session || !mdp3_session->dma)
 		return -EINVAL;
 
-	if (!mdp3_session->status) {
-		pr_err("%s, display off!\n", __func__);
-		return -EPERM;
-	}
-
 	if (!mdp3_iommu_is_attached(MDP3_CLIENT_DMA_P)) {
 		pr_debug("continuous splash screen, IOMMU not attached\n");
-		mdp3_ctrl_off(mfd);
-		mdp3_ctrl_on(mfd);
+		mdp3_ctrl_reset(mfd);
 		mdp3_free();
 	}
 
 	mutex_lock(&mdp3_session->lock);
 
+	if (!mdp3_session->status) {
+		pr_err("%s, display off!\n", __func__);
+		mutex_unlock(&mdp3_session->lock);
+		return -EPERM;
+	}
+
 	data = mdp3_bufq_pop(&mdp3_session->bufq_in);
 	if (data) {
 		mdp3_session->dma->update(mdp3_session->dma,
@@ -697,7 +779,7 @@
 
 	if (mdp3_bufq_count(&mdp3_session->bufq_out) > 2) {
 		data = mdp3_bufq_pop(&mdp3_session->bufq_out);
-		mdp3_put_img(data);
+		mdp3_put_img(data, MDP3_CLIENT_DMA_P);
 	}
 	mutex_unlock(&mdp3_session->lock);
 
@@ -721,11 +803,6 @@
 	if (!mdp3_session || !mdp3_session->dma)
 		return;
 
-	if (!mdp3_session->status) {
-		pr_err("mdp3_ctrl_pan_display, display off!\n");
-		return;
-	}
-
 	if (!mdp3_iommu_is_attached(MDP3_CLIENT_DMA_P)) {
 		pr_debug("continuous splash screen, IOMMU not attached\n");
 		mdp3_ctrl_off(mfd);
@@ -733,6 +810,12 @@
 	}
 
 	mutex_lock(&mdp3_session->lock);
+
+	if (!mdp3_session->status) {
+		pr_err("mdp3_ctrl_pan_display, display off!\n");
+		goto pan_error;
+	}
+
 	fbi = mfd->fbi;
 
 	bpp = fbi->var.bits_per_pixel / 8;
@@ -1136,7 +1219,8 @@
 	if (!mdp3_session->dma->config_lut)
 		return -EINVAL;
 
-	if (cmap->start + cmap->len > MDP_LUT_SIZE) {
+	if (cmap->start > MDP_LUT_SIZE || cmap->len > MDP_LUT_SIZE ||
+			(cmap->start + cmap->len > MDP_LUT_SIZE)) {
 		pr_err("mdp3_ctrl_lut_update invalid arguments\n");
 		return  -EINVAL;
 	}
diff --git a/drivers/video/msm/mdss/mdp3_dma.c b/drivers/video/msm/mdss/mdp3_dma.c
index 31b9deb..5874286 100644
--- a/drivers/video/msm/mdss/mdp3_dma.c
+++ b/drivers/video/msm/mdss/mdp3_dma.c
@@ -292,12 +292,7 @@
 	MDP3_REG_WRITE(MDP3_REG_DMA_P_IBUF_Y_STRIDE, source_config->stride);
 	MDP3_REG_WRITE(MDP3_REG_DMA_P_OUT_XY, dma_p_out_xy);
 
-	/*
-	 * 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, 0x20);
-
+	MDP3_REG_WRITE(MDP3_REG_DMA_P_FETCH_CFG, 0x40);
 
 	dma->source_config = *source_config;
 	dma->output_config = *output_config;
@@ -831,6 +826,7 @@
 					MDP3_DMA_CALLBACK_TYPE_DMA_DONE);
 
 	init_completion(&dma->dma_comp);
+	dma->vsync_client.handler = NULL;
 	return ret;
 }
 
diff --git a/drivers/video/msm/mdss/mdp3_ppp.c b/drivers/video/msm/mdss/mdp3_ppp.c
index 8e1dd66..e1f2d10 100644
--- a/drivers/video/msm/mdss/mdp3_ppp.c
+++ b/drivers/video/msm/mdss/mdp3_ppp.c
@@ -119,11 +119,22 @@
 		struct mdp3_img_data *data)
 {
 	struct msmfb_data fb_data;
+	uint32_t stride;
+	int bpp = ppp_bpp(img->format);
+
+	if (bpp <= 0) {
+		pr_err("%s incorrect format %d\n", __func__, img->format);
+		return -EINVAL;
+	}
+
 	fb_data.flags = img->priv;
 	fb_data.memory_id = img->memory_id;
 	fb_data.offset = 0;
 
-	return mdp3_get_img(&fb_data, data);
+	stride = img->width * bpp;
+	data->padding = 16 * stride;
+
+	return mdp3_get_img(&fb_data, data, MDP3_CLIENT_PPP);
 }
 
 /* Check format */
@@ -346,6 +357,7 @@
 	struct mdss_panel_info *panel_info = mfd->panel_info;
 	uint64_t ab = 0, ib = 0;
 	int rate = 0;
+	int rc;
 
 	if (on_off) {
 		rate = MDP_BLIT_CLK_RATE;
@@ -357,8 +369,17 @@
 		ib = (ab * 3) / 2;
 	}
 	mdp3_clk_set_rate(MDP3_CLK_CORE, rate, MDP3_CLIENT_PPP);
-	mdp3_clk_enable(on_off);
-	mdp3_bus_scale_set_quota(MDP3_CLIENT_PPP, ab, ib);
+	rc = mdp3_clk_enable(on_off);
+	if (rc < 0) {
+		pr_err("%s: mdp3_clk_enable failed\n", __func__);
+		return rc;
+	}
+	rc = mdp3_bus_scale_set_quota(MDP3_CLIENT_PPP, ab, ib);
+	if (rc < 0) {
+		mdp3_clk_enable(!on_off);
+		pr_err("%s: scale_set_quota failed\n", __func__);
+		return rc;
+	}
 	ppp_stat->bw_on = on_off;
 	return 0;
 }
@@ -909,10 +930,14 @@
 static void mdp3_free_bw_wq_handler(struct work_struct *work)
 {
 	struct msm_fb_data_type *mfd = ppp_stat->mfd;
+	int rc;
+
 	mutex_lock(&ppp_stat->config_ppp_mutex);
 	if (ppp_stat->bw_on) {
 		mdp3_ppp_turnon(mfd, 0);
-		mdp3_iommu_disable(MDP3_CLIENT_PPP);
+		rc = mdp3_iommu_disable(MDP3_CLIENT_PPP);
+		if (rc < 0)
+			WARN(1, "Unable to disable ppp iommu\n");
 	}
 	mutex_unlock(&ppp_stat->config_ppp_mutex);
 }
@@ -931,8 +956,19 @@
 	}
 
 	if (!ppp_stat->bw_on) {
-		mdp3_iommu_enable(MDP3_CLIENT_PPP);
+		rc = mdp3_iommu_enable(MDP3_CLIENT_PPP);
+		if (rc < 0) {
+			mutex_unlock(&ppp_stat->config_ppp_mutex);
+			pr_err("%s: mdp3_iommu_enable failed\n", __func__);
+			return;
+		}
 		mdp3_ppp_turnon(mfd, 1);
+		if (rc < 0) {
+			mdp3_iommu_disable(MDP3_CLIENT_PPP);
+			mutex_unlock(&ppp_stat->config_ppp_mutex);
+			pr_err("%s: Enable ppp resources failed\n", __func__);
+			return;
+		}
 	}
 	while (req) {
 		mdp3_ppp_wait_for_fence(req);
@@ -945,8 +981,10 @@
 						&req->src_data[i],
 						&req->dst_data[i]);
 				}
-				mdp3_put_img(&req->src_data[i]);
-				mdp3_put_img(&req->dst_data[i]);
+				mdp3_put_img(&req->src_data[i],
+					MDP3_CLIENT_PPP);
+				mdp3_put_img(&req->dst_data[i],
+					MDP3_CLIENT_PPP);
 			}
 		}
 		/* Signal to release fence */
@@ -1017,7 +1055,7 @@
 		rc = mdp3_ppp_get_img(&req->req_list[i].dst,
 				&req->req_list[i], &req->dst_data[i]);
 		if (rc < 0 || req->dst_data[i].len == 0) {
-			mdp3_put_img(&req->src_data[i]);
+			mdp3_put_img(&req->src_data[i], MDP3_CLIENT_PPP);
 			pr_err("mdp_ppp: couldn't retrieve dest img from mem\n");
 			goto parse_err_1;
 		}
@@ -1060,8 +1098,8 @@
 	put_unused_fd(req->cur_rel_fen_fd);
 parse_err_1:
 	for (i--; i >= 0; i--) {
-		mdp3_put_img(&req->src_data[i]);
-		mdp3_put_img(&req->dst_data[i]);
+		mdp3_put_img(&req->src_data[i], MDP3_CLIENT_PPP);
+		mdp3_put_img(&req->dst_data[i], MDP3_CLIENT_PPP);
 	}
 	mdp3_ppp_deinit_buf_sync(req);
 	mutex_unlock(&ppp_stat->req_mutex);
diff --git a/drivers/video/msm/mdss/mdp3_ppp_hwio.c b/drivers/video/msm/mdss/mdp3_ppp_hwio.c
index 199387f..a051037 100644
--- a/drivers/video/msm/mdss/mdp3_ppp_hwio.c
+++ b/drivers/video/msm/mdss/mdp3_ppp_hwio.c
@@ -361,38 +361,6 @@
 	return rgb;
 }
 
-uint8_t *mdp_bg_adjust_rot_addr(struct ppp_blit_op *iBuf,
-	uint8_t *addr, uint32_t bpp, uint32_t uv)
-{
-	uint32_t dest_ystride = iBuf->bg.prop.width * bpp;
-	uint32_t h_slice = 1, min_val;
-
-	if (uv && ((iBuf->bg.color_fmt == MDP_Y_CBCR_H2V2) ||
-		(iBuf->bg.color_fmt == MDP_Y_CRCB_H2V2)))
-		h_slice = 2;
-
-	if (((iBuf->mdp_op & MDPOP_ROT90) == MDPOP_ROT90) ^
-		((iBuf->mdp_op & MDPOP_LR) == MDPOP_LR)) {
-		min_val = (iBuf->bg.roi.width + iBuf->bg.roi.x) % 16;
-		if (!min_val)
-			min_val = 16;
-		addr +=
-		    (iBuf->bg.roi.width -
-			    MIN(min_val, iBuf->bg.roi.width)) * bpp;
-	}
-	if ((iBuf->mdp_op & MDPOP_UD) == MDPOP_UD) {
-		min_val = (iBuf->bg.roi.height + iBuf->bg.roi.y) % 16;
-		if (!min_val)
-			min_val = 16;
-		addr +=
-			((iBuf->bg.roi.height -
-			MIN(min_val, iBuf->bg.roi.height))/h_slice) *
-			dest_ystride;
-	}
-
-	return addr;
-}
-
 uint8_t *mdp_dst_adjust_rot_addr(struct ppp_blit_op *iBuf,
 	uint8_t *addr, uint32_t bpp, uint32_t uv)
 {
@@ -434,9 +402,7 @@
 		img->p0 += (x + y * ALIGN(width, 128)) * bpp;
 	else
 		img->p0 += (x + y * width) * bpp;
-	if (layer == 1)
-		img->p0 = mdp_bg_adjust_rot_addr(blit_op, img->p0, bpp, 0);
-	else if (layer == 2)
+	if (layer != 0)
 		img->p0 = mdp_dst_adjust_rot_addr(blit_op, img->p0, bpp, 0);
 
 	if (img->p1) {
@@ -454,13 +420,9 @@
 			img->p1 += ((x / h_slice) * h_slice +
 			((y == 0) ? 0 : ((y + 1) / v_slice - 1) * width)) * bpp;
 
-		if (layer == 1) {
-			img->p0 = mdp_bg_adjust_rot_addr(blit_op,
-					img->p0, bpp, 0);
-		} else if (layer == 2) {
+		if (layer != 0)
 			img->p0 = mdp_dst_adjust_rot_addr(blit_op,
 					img->p0, bpp, 0);
-		}
 	}
 }
 
diff --git a/drivers/video/msm/mdss/mdss.h b/drivers/video/msm/mdss/mdss.h
index 24b53c7..dd1a95b 100644
--- a/drivers/video/msm/mdss/mdss.h
+++ b/drivers/video/msm/mdss/mdss.h
@@ -82,6 +82,7 @@
 	u32 has_bwc;
 	u32 has_decimation;
 	u8 has_wfd_blk;
+	u8 has_wb_ad;
 
 	u32 mdp_irq_mask;
 	u32 mdp_hist_irq_mask;
@@ -120,6 +121,7 @@
 	void *video_intf;
 	u32 nintf;
 
+	u32 pp_bus_hdl;
 	struct mdss_ad_info *ad_cfgs;
 	u32 nad_cfgs;
 	struct workqueue_struct *ad_calc_wq;
diff --git a/drivers/video/msm/mdss/mdss_dsi.c b/drivers/video/msm/mdss/mdss_dsi.c
index 877525e..e156116 100644
--- a/drivers/video/msm/mdss/mdss_dsi.c
+++ b/drivers/video/msm/mdss/mdss_dsi.c
@@ -743,7 +743,6 @@
 	char panel_cfg[MDSS_MAX_PANEL_LEN];
 	struct resource *mdss_dsi_mres;
 	const char *ctrl_name;
-	static struct mdss_panel_common_pdata vendor_pdata;
 	bool cmd_cfg_cont_splash = true;
 
 	if (!mdss_is_ready()) {
@@ -843,14 +842,13 @@
 
 	cmd_cfg_cont_splash = mdss_panel_get_boot_cfg() ? true : false;
 
-	rc = mdss_dsi_panel_init(dsi_pan_node, &vendor_pdata);
+	rc = mdss_dsi_panel_init(dsi_pan_node, ctrl_pdata, cmd_cfg_cont_splash);
 	if (rc) {
 		pr_err("%s: dsi panel init failed\n", __func__);
 		goto error_pan_node;
 	}
 
-	rc = dsi_panel_device_register(dsi_pan_node, &vendor_pdata,
-				       cmd_cfg_cont_splash);
+	rc = dsi_panel_device_register(dsi_pan_node, ctrl_pdata);
 	if (rc) {
 		pr_err("%s: dsi panel dev reg failed\n", __func__);
 		goto error_pan_node;
@@ -950,32 +948,31 @@
 }
 
 int dsi_panel_device_register(struct device_node *pan_node,
-			      struct mdss_panel_common_pdata *panel_data,
-			      bool cmd_cfg_cont_splash)
+				struct mdss_dsi_ctrl_pdata *ctrl_pdata)
 {
 	struct mipi_panel_info *mipi;
 	int rc, i, len;
 	u8 lanes = 0, bpp;
 	u32 h_period, v_period, dsi_pclk_rate, tmp[9];
-	struct mdss_dsi_ctrl_pdata *ctrl_pdata;
 	struct device_node *dsi_ctrl_np = NULL;
 	struct platform_device *ctrl_pdev = NULL;
-	bool cont_splash_enabled = false;
 	const char *data;
+	struct mdss_panel_info *pinfo = &(ctrl_pdata->panel_data.panel_info);
 
-	h_period = ((panel_data->panel_info.lcdc.h_pulse_width)
-			+ (panel_data->panel_info.lcdc.h_back_porch)
-			+ (panel_data->panel_info.xres)
-			+ (panel_data->panel_info.lcdc.h_front_porch));
+	h_period = ((pinfo->lcdc.h_pulse_width)
+			+ (pinfo->lcdc.h_back_porch)
+			+ (pinfo->xres)
+			+ (pinfo->lcdc.h_front_porch));
 
-	v_period = ((panel_data->panel_info.lcdc.v_pulse_width)
-			+ (panel_data->panel_info.lcdc.v_back_porch)
-			+ (panel_data->panel_info.yres)
-			+ (panel_data->panel_info.lcdc.v_front_porch));
+	v_period = ((pinfo->lcdc.v_pulse_width)
+			+ (pinfo->lcdc.v_back_porch)
+			+ (pinfo->yres)
+			+ (pinfo->lcdc.v_front_porch));
 
-	mipi  = &panel_data->panel_info.mipi;
+	mipi  = &pinfo->mipi;
+	mipi  = &(pinfo->mipi);
 
-	panel_data->panel_info.type =
+	pinfo->type =
 		((mipi->mode == DSI_VIDEO_MODE)
 			? MIPI_VIDEO_PANEL : MIPI_CMD_PANEL);
 
@@ -999,22 +996,22 @@
 	else
 		bpp = 3;		/* Default format set to RGB888 */
 
-	if (!panel_data->panel_info.clk_rate) {
-		h_period += panel_data->panel_info.lcdc.xres_pad;
-		v_period += panel_data->panel_info.lcdc.yres_pad;
+	if (!pinfo->clk_rate) {
+		h_period += pinfo->lcdc.xres_pad;
+		v_period += pinfo->lcdc.yres_pad;
 
 		if (lanes > 0) {
-			panel_data->panel_info.clk_rate =
+			pinfo->clk_rate =
 			((h_period * v_period * (mipi->frame_rate) * bpp * 8)
 			   / lanes);
 		} else {
 			pr_err("%s: forcing mdss_dsi lanes to 1\n", __func__);
-			panel_data->panel_info.clk_rate =
+			pinfo->clk_rate =
 				(h_period * v_period
 					 * (mipi->frame_rate) * bpp * 8);
 		}
 	}
-	pll_divider_config.clk_rate = panel_data->panel_info.clk_rate;
+	pll_divider_config.clk_rate = pinfo->clk_rate;
 
 	rc = mdss_dsi_clk_div_config(bpp, lanes, &dsi_pclk_rate);
 	if (rc) {
@@ -1034,11 +1031,6 @@
 	}
 
 	ctrl_pdev = of_find_device_by_node(dsi_ctrl_np);
-	ctrl_pdata = platform_get_drvdata(ctrl_pdev);
-	if (!ctrl_pdata) {
-		pr_err("%s: no dsi ctrl driver data\n", __func__);
-		return -EINVAL;
-	}
 
 	rc = mdss_dsi_regulator_init(ctrl_pdev);
 	if (rc) {
@@ -1054,8 +1046,8 @@
 			__func__, __LINE__);
 		return -EINVAL;
 	}
-	(panel_data->panel_info.mipi.dsi_phy_db)->strength[0] = data[0];
-	(panel_data->panel_info.mipi.dsi_phy_db)->strength[1] = data[1];
+	pinfo->mipi.dsi_phy_db.strength[0] = data[0];
+	pinfo->mipi.dsi_phy_db.strength[1] = data[1];
 
 	data = of_get_property(ctrl_pdev->dev.of_node,
 		"qcom,platform-regulator-settings", &len);
@@ -1065,7 +1057,7 @@
 		return -EINVAL;
 	}
 	for (i = 0; i < len; i++) {
-		(panel_data->panel_info.mipi.dsi_phy_db)->regulator[i]
+		pinfo->mipi.dsi_phy_db.regulator[i]
 			= data[i];
 	}
 
@@ -1077,7 +1069,7 @@
 		return -EINVAL;
 	}
 	for (i = 0; i < len; i++) {
-		(panel_data->panel_info.mipi.dsi_phy_db)->bistCtrl[i]
+		pinfo->mipi.dsi_phy_db.bistctrl[i]
 			= data[i];
 	}
 
@@ -1089,7 +1081,7 @@
 		return -EINVAL;
 	}
 	for (i = 0; i < len; i++) {
-		(panel_data->panel_info.mipi.dsi_phy_db)->laneCfg[i] =
+		pinfo->mipi.dsi_phy_db.lanecfg[i] =
 			data[i];
 	}
 
@@ -1112,7 +1104,7 @@
 		}
 	}
 
-	if (panel_data->panel_info.type == MIPI_CMD_PANEL) {
+	if (pinfo->type == MIPI_CMD_PANEL) {
 		ctrl_pdata->disp_te_gpio = of_get_named_gpio(ctrl_pdev->dev.of_node,
 						"qcom,platform-te-gpio", 0);
 		if (!gpio_is_valid(ctrl_pdata->disp_te_gpio)) {
@@ -1180,13 +1172,38 @@
 		}
 	}
 
+	if (pinfo->mode_gpio_state != MODE_GPIO_NOT_VALID) {
+
+		ctrl_pdata->mode_gpio = of_get_named_gpio(
+					ctrl_pdev->dev.of_node,
+					"qcom,platform-mode-gpio", 0);
+		if (!gpio_is_valid(ctrl_pdata->mode_gpio)) {
+			pr_info("%s:%d, mode gpio not specified\n",
+							__func__, __LINE__);
+		} else {
+			rc = gpio_request(ctrl_pdata->mode_gpio, "panel_mode");
+			if (rc) {
+				pr_err("request panel mode gpio failed,rc=%d\n",
+									rc);
+				gpio_free(ctrl_pdata->mode_gpio);
+				if (gpio_is_valid(ctrl_pdata->disp_en_gpio))
+					gpio_free(ctrl_pdata->disp_en_gpio);
+				if (gpio_is_valid(ctrl_pdata->rst_gpio))
+					gpio_free(ctrl_pdata->rst_gpio);
+				if (gpio_is_valid(ctrl_pdata->disp_te_gpio))
+					gpio_free(ctrl_pdata->disp_te_gpio);
+				return -ENODEV;
+			}
+		}
+	}
+
 	if (mdss_dsi_clk_init(ctrl_pdev, ctrl_pdata)) {
 		pr_err("%s: unable to initialize Dsi ctrl clks\n", __func__);
 		return -EPERM;
 	}
 
 	if (mdss_dsi_retrieve_ctrl_resources(ctrl_pdev,
-					     panel_data->panel_info.pdest,
+					     pinfo->pdest,
 					     ctrl_pdata)) {
 		pr_err("%s: unable to get Dsi controller res\n", __func__);
 		return -EPERM;
@@ -1194,20 +1211,6 @@
 
 	ctrl_pdata->panel_data.event_handler = mdss_dsi_event_handler;
 
-	ctrl_pdata->on_cmds = panel_data->on_cmds;
-	ctrl_pdata->off_cmds = panel_data->off_cmds;
-
-	memcpy(&((ctrl_pdata->panel_data).panel_info),
-				&(panel_data->panel_info),
-				       sizeof(struct mdss_panel_info));
-
-	ctrl_pdata->panel_data.set_backlight = panel_data->bl_fnc;
-	ctrl_pdata->bklt_ctrl = panel_data->panel_info.bklt_ctrl;
-	ctrl_pdata->pwm_pmic_gpio = panel_data->panel_info.pwm_pmic_gpio;
-	ctrl_pdata->pwm_period = panel_data->panel_info.pwm_period;
-	ctrl_pdata->pwm_lpg_chan = panel_data->panel_info.pwm_lpg_chan;
-	ctrl_pdata->bklt_max = panel_data->panel_info.bl_max;
-
 	if (ctrl_pdata->bklt_ctrl == BL_PWM)
 		mdss_dsi_panel_pwm_cfg(ctrl_pdata);
 
@@ -1217,27 +1220,14 @@
 	 */
 
 	ctrl_pdata->pclk_rate = dsi_pclk_rate;
-	ctrl_pdata->byte_clk_rate = panel_data->panel_info.clk_rate / 8;
+	ctrl_pdata->byte_clk_rate = pinfo->clk_rate / 8;
 	pr_debug("%s: pclk=%d, bclk=%d\n", __func__,
 			ctrl_pdata->pclk_rate, ctrl_pdata->byte_clk_rate);
 
 	ctrl_pdata->ctrl_state = CTRL_STATE_UNKNOWN;
-	if (cmd_cfg_cont_splash)
-		cont_splash_enabled = of_property_read_bool(pan_node,
-				"qcom,cont-splash-enabled");
-	else
-		cont_splash_enabled = false;
-	if (!cont_splash_enabled) {
-		pr_info("%s:%d Continuous splash flag not found.\n",
-				__func__, __LINE__);
-		ctrl_pdata->panel_data.panel_info.cont_splash_enabled = 0;
-		ctrl_pdata->panel_data.panel_info.panel_power_on = 0;
-	} else {
-		pr_info("%s:%d Continuous splash flag enabled.\n",
-				__func__, __LINE__);
 
-		ctrl_pdata->panel_data.panel_info.cont_splash_enabled = 1;
-		ctrl_pdata->panel_data.panel_info.panel_power_on = 1;
+	if (pinfo->cont_splash_enabled) {
+		pinfo->panel_power_on = 1;
 		rc = mdss_dsi_panel_power_on(&(ctrl_pdata->panel_data), 1);
 		if (rc) {
 			pr_err("%s: Panel power on failed\n", __func__);
@@ -1247,6 +1237,8 @@
 		mdss_dsi_clk_ctrl(ctrl_pdata, 1);
 		ctrl_pdata->ctrl_state |=
 			(CTRL_STATE_PANEL_INIT | CTRL_STATE_MDP_ACTIVE);
+	} else {
+		pinfo->panel_power_on = 0;
 	}
 
 	rc = mdss_register_panel(ctrl_pdev, &(ctrl_pdata->panel_data));
@@ -1259,10 +1251,7 @@
 		return rc;
 	}
 
-	ctrl_pdata->on = panel_data->on;
-	ctrl_pdata->off = panel_data->off;
-
-	if (panel_data->panel_info.pdest == DISPLAY_1) {
+	if (pinfo->pdest == DISPLAY_1) {
 		mdss_debug_register_base("dsi0",
 			ctrl_pdata->ctrl_base, ctrl_pdata->reg_size);
 		ctrl_pdata->ndx = 0;
diff --git a/drivers/video/msm/mdss/mdss_dsi.h b/drivers/video/msm/mdss/mdss_dsi.h
index fe60fec..2d63532 100644
--- a/drivers/video/msm/mdss/mdss_dsi.h
+++ b/drivers/video/msm/mdss/mdss_dsi.h
@@ -296,16 +296,6 @@
 	void *data;
 };
 
-struct mdss_panel_common_pdata {
-	struct mdss_panel_info panel_info;
-	int (*on) (struct mdss_panel_data *pdata);
-	int (*off) (struct mdss_panel_data *pdata);
-	void (*bl_fnc) (struct mdss_panel_data *pdata, u32 bl_level);
-
-	struct dsi_panel_cmds on_cmds;
-	struct dsi_panel_cmds off_cmds;
-};
-
 struct dsi_drv_cm_data {
 	struct regulator *vdd_vreg;
 	struct regulator *vdd_io_vreg;
@@ -333,11 +323,13 @@
 	struct clk *esc_clk;
 	struct clk *pixel_clk;
 	u8 ctrl_state;
+	int panel_mode;
 	int irq_cnt;
 	int mdss_dsi_clk_on;
 	int rst_gpio;
 	int disp_en_gpio;
 	int disp_te_gpio;
+	int mode_gpio;
 	int bklt_ctrl;	/* backlight ctrl */
 	int pwm_period;
 	int pwm_pmic_gpio;
@@ -370,8 +362,7 @@
 };
 
 int dsi_panel_device_register(struct device_node *pan_node,
-			      struct mdss_panel_common_pdata *panel_data,
-			      bool cmd_cfg_cont_splash);
+				struct mdss_dsi_ctrl_pdata *ctrl_pdata);
 
 char *mdss_dsi_buf_reserve_hdr(struct dsi_buf *dp, int hlen);
 char *mdss_dsi_buf_init(struct dsi_buf *dp);
@@ -430,5 +421,6 @@
 void mdss_dsi_cmdlist_kickoff(int intf);
 
 int mdss_dsi_panel_init(struct device_node *node,
-		struct mdss_panel_common_pdata *vendor_pdata);
+		struct mdss_dsi_ctrl_pdata *ctrl_pdata,
+		bool cmd_cfg_cont_splash);
 #endif /* MDSS_DSI_H */
diff --git a/drivers/video/msm/mdss/mdss_dsi_host.c b/drivers/video/msm/mdss/mdss_dsi_host.c
index e48d0d2..62bc7e6 100644
--- a/drivers/video/msm/mdss/mdss_dsi_host.c
+++ b/drivers/video/msm/mdss/mdss_dsi_host.c
@@ -25,6 +25,8 @@
 #include "mdss.h"
 #include "mdss_dsi.h"
 
+#define VSYNC_PERIOD 17
+
 static struct mdss_dsi_ctrl_pdata *left_ctrl_pdata;
 
 static struct mdss_dsi_ctrl_pdata *ctrl_list[DSI_CTRL_MAX];
@@ -766,6 +768,8 @@
 
 	pinfo->rgb_swap = DSI_RGB_SWAP_RGB;
 
+	ctrl_pdata->panel_mode = pinfo->mode;
+
 	if (pinfo->mode == DSI_VIDEO_MODE) {
 		data = 0;
 		if (pinfo->pulse_mode_hsa_he)
@@ -1135,6 +1139,8 @@
 	return 4;
 }
 
+static int mdss_dsi_wait4video_eng_busy(struct mdss_dsi_ctrl_pdata *ctrl);
+
 static int mdss_dsi_cmd_dma_tx(struct mdss_dsi_ctrl_pdata *ctrl,
 					struct dsi_buf *tp);
 
@@ -1147,7 +1153,7 @@
 	struct dsi_buf *tp;
 	struct dsi_cmd_desc *cm;
 	struct dsi_ctrl_hdr *dchdr;
-	int len, tot = 0;
+	int len, wait, tot = 0;
 
 	tp = &ctrl->tx_buf;
 	mdss_dsi_buf_init(tp);
@@ -1164,6 +1170,9 @@
 		tot += len;
 		if (dchdr->last) {
 			tp->data = tp->start; /* begin of buf */
+
+			wait = mdss_dsi_wait4video_eng_busy(ctrl);
+
 			mdss_dsi_enable_irq(ctrl, DSI_CMD_TERM);
 			len = mdss_dsi_cmd_dma_tx(ctrl, tp);
 			if (IS_ERR_VALUE(len)) {
@@ -1172,7 +1181,8 @@
 					__func__,  cmds->payload[0]);
 				return -EINVAL;
 			}
-			if (dchdr->wait)
+
+			if (!wait || dchdr->wait > VSYNC_PERIOD)
 				usleep(dchdr->wait * 1000);
 
 			mdss_dsi_buf_init(tp);
@@ -1357,6 +1367,9 @@
 			rp->len = 0;
 			goto end;
 		}
+
+		mdss_dsi_wait4video_eng_busy(ctrl);
+
 		mdss_dsi_enable_irq(ctrl, DSI_CMD_TERM);
 		ret = mdss_dsi_cmd_dma_tx(ctrl, tp);
 		if (IS_ERR_VALUE(ret)) {
@@ -1377,6 +1390,8 @@
 		goto end;
 	}
 
+	mdss_dsi_wait4video_eng_busy(ctrl);
+
 	mdss_dsi_enable_irq(ctrl, DSI_CMD_TERM);
 	/* transmit read comamnd to client */
 	ret = mdss_dsi_cmd_dma_tx(ctrl, tp);
@@ -1541,7 +1556,6 @@
 	return rlen;
 }
 
-#define VSYNC_PERIOD 17
 
 void mdss_dsi_wait4video_done(struct mdss_dsi_ctrl_pdata *ctrl)
 {
@@ -1567,11 +1581,21 @@
 	MIPI_OUTP((ctrl->ctrl_base) + 0x0110, data);
 }
 
-static void mdss_dsi_wait4video_eng_busy(struct mdss_dsi_ctrl_pdata *ctrl)
+static int mdss_dsi_wait4video_eng_busy(struct mdss_dsi_ctrl_pdata *ctrl)
 {
-	mdss_dsi_wait4video_done(ctrl);
-	/* delay 4 ms to skip BLLP */
-	usleep(4000);
+	int ret = 0;
+
+	if (ctrl->panel_mode == DSI_CMD_MODE)
+		return ret;
+
+	if (ctrl->ctrl_state & CTRL_STATE_MDP_ACTIVE) {
+		mdss_dsi_wait4video_done(ctrl);
+		/* delay 4 ms to skip BLLP */
+		usleep(4000);
+		ret = 1;
+	}
+
+	return ret;
 }
 
 void mdss_dsi_cmd_mdp_start(struct mdss_dsi_ctrl_pdata *ctrl)
@@ -1638,7 +1662,6 @@
 void mdss_dsi_cmdlist_commit(struct mdss_dsi_ctrl_pdata *ctrl, int from_mdp)
 {
 	struct dcs_cmd_req *req;
-	u32 data;
 
 	mutex_lock(&ctrl->cmd_mutex);
 	req = mdss_dsi_cmdlist_get(ctrl);
@@ -1646,26 +1669,14 @@
 	/* make sure dsi_cmd_mdp is idle */
 	mdss_dsi_cmd_mdp_busy(ctrl);
 
+	pr_debug("%s:  from_mdp=%d pid=%d\n", __func__, from_mdp, current->pid);
+
 	if (req == NULL)
 		goto need_lock;
 
 	pr_debug("%s:  from_mdp=%d pid=%d\n", __func__, from_mdp, current->pid);
 	mdss_dsi_clk_ctrl(ctrl, 1);
 
-	data = MIPI_INP((ctrl->ctrl_base) + 0x0004);
-	if (data & 0x02) {
-		/* video mode, make sure video engine is busy
-		 * so dcs command will be sent at start of BLLP
-		 */
-		mdss_dsi_wait4video_eng_busy(ctrl);
-	} else {
-		/* command mode */
-		if (!from_mdp) { /* cmdlist_put */
-			/* make sure dsi_cmd_mdp is idle */
-			mdss_dsi_cmd_mdp_busy(ctrl);
-		}
-	}
-
 	if (req->flags & CMD_REQ_RX)
 		mdss_dsi_cmdlist_rx(ctrl, req);
 	else
diff --git a/drivers/video/msm/mdss/mdss_dsi_panel.c b/drivers/video/msm/mdss/mdss_dsi_panel.c
index 29898db..203900c 100644
--- a/drivers/video/msm/mdss/mdss_dsi_panel.c
+++ b/drivers/video/msm/mdss/mdss_dsi_panel.c
@@ -28,8 +28,6 @@
 
 DEFINE_LED_TRIGGER(bl_led_trigger);
 
-static struct mdss_dsi_phy_ctrl phy_params;
-
 void mdss_dsi_panel_pwm_cfg(struct mdss_dsi_ctrl_pdata *ctrl)
 {
 	int ret;
@@ -158,6 +156,7 @@
 void mdss_dsi_panel_reset(struct mdss_panel_data *pdata, int enable)
 {
 	struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
+	struct mdss_panel_info *pinfo = NULL;
 	int i;
 
 	if (pdata == NULL) {
@@ -180,6 +179,7 @@
 	}
 
 	pr_debug("%s: enable = %d\n", __func__, enable);
+	pinfo = &(ctrl_pdata->panel_data.panel_info);
 
 	if (enable) {
 		for (i = 0; i < MDSS_DSI_RST_SEQ_LEN; ++i) {
@@ -189,6 +189,13 @@
 		}
 		if (gpio_is_valid(ctrl_pdata->disp_en_gpio))
 			gpio_set_value((ctrl_pdata->disp_en_gpio), 1);
+
+		if (gpio_is_valid(ctrl_pdata->mode_gpio)) {
+			if (pinfo->mode_gpio_state == MODE_GPIO_HIGH)
+				gpio_set_value((ctrl_pdata->mode_gpio), 1);
+			else if (pinfo->mode_gpio_state == MODE_GPIO_LOW)
+				gpio_set_value((ctrl_pdata->mode_gpio), 0);
+		}
 		if (ctrl_pdata->ctrl_state & CTRL_STATE_PANEL_INIT) {
 			pr_debug("%s: Panel Not properly turned OFF\n",
 						__func__);
@@ -486,12 +493,13 @@
 
 
 static int mdss_panel_parse_dt(struct device_node *np,
-			       struct mdss_panel_common_pdata *panel_data)
+			struct mdss_dsi_ctrl_pdata *ctrl_pdata)
 {
 	u32 tmp;
 	int rc, i, len;
 	const char *data;
 	static const char *pdest;
+	struct mdss_panel_info *pinfo = &(ctrl_pdata->panel_data.panel_info);
 
 	rc = of_property_read_u32(np, "qcom,mdss-dsi-panel-width", &tmp);
 	if (rc) {
@@ -499,7 +507,7 @@
 						__func__, __LINE__);
 		return -EINVAL;
 	}
-	panel_data->panel_info.xres = (!rc ? tmp : 640);
+	pinfo->xres = (!rc ? tmp : 640);
 
 	rc = of_property_read_u32(np, "qcom,mdss-dsi-panel-height", &tmp);
 	if (rc) {
@@ -507,43 +515,43 @@
 						__func__, __LINE__);
 		return -EINVAL;
 	}
-	panel_data->panel_info.yres = (!rc ? tmp : 480);
+	pinfo->yres = (!rc ? tmp : 480);
 
 	rc = of_property_read_u32(np,
 		"qcom,mdss-pan-physical-width-dimension", &tmp);
-	panel_data->panel_info.physical_width = (!rc ? tmp : 0);
+	pinfo->physical_width = (!rc ? tmp : 0);
 	rc = of_property_read_u32(np,
 		"qcom,mdss-pan-physical-height-dimension", &tmp);
-	panel_data->panel_info.physical_height = (!rc ? tmp : 0);
+	pinfo->physical_height = (!rc ? tmp : 0);
 	rc = of_property_read_u32(np, "qcom,mdss-dsi-h-left-border", &tmp);
-	panel_data->panel_info.lcdc.xres_pad = (!rc ? tmp : 0);
+	pinfo->lcdc.xres_pad = (!rc ? tmp : 0);
 	rc = of_property_read_u32(np, "qcom,mdss-dsi-h-right-border", &tmp);
 	if (!rc)
-		panel_data->panel_info.lcdc.xres_pad += tmp;
+		pinfo->lcdc.xres_pad += tmp;
 	rc = of_property_read_u32(np, "qcom,mdss-dsi-v-top-border", &tmp);
-	panel_data->panel_info.lcdc.yres_pad = (!rc ? tmp : 0);
+	pinfo->lcdc.yres_pad = (!rc ? tmp : 0);
 	rc = of_property_read_u32(np, "qcom,mdss-dsi-v-bottom-border", &tmp);
 	if (!rc)
-		panel_data->panel_info.lcdc.yres_pad += tmp;
+		pinfo->lcdc.yres_pad += tmp;
 	rc = of_property_read_u32(np, "qcom,mdss-dsi-bpp", &tmp);
 	if (rc) {
 		pr_err("%s:%d, bpp not specified\n", __func__, __LINE__);
 		return -EINVAL;
 	}
-	panel_data->panel_info.bpp = (!rc ? tmp : 24);
-	panel_data->panel_info.mipi.mode = DSI_VIDEO_MODE;
+	pinfo->bpp = (!rc ? tmp : 24);
+	pinfo->mipi.mode = DSI_VIDEO_MODE;
 	data = of_get_property(np, "qcom,mdss-dsi-panel-type", NULL);
 	if (data && !strncmp(data, "dsi_cmd_mode", 12))
-		panel_data->panel_info.mipi.mode = DSI_CMD_MODE;
+		pinfo->mipi.mode = DSI_CMD_MODE;
 	rc = of_property_read_u32(np, "qcom,mdss-dsi-pixel-packing", &tmp);
 	tmp = (!rc ? tmp : 0);
-	rc = mdss_panel_dt_get_dst_fmt(panel_data->panel_info.bpp,
-		panel_data->panel_info.mipi.mode, tmp,
-		&(panel_data->panel_info.mipi.dst_format));
+	rc = mdss_panel_dt_get_dst_fmt(pinfo->bpp,
+		pinfo->mipi.mode, tmp,
+		&(pinfo->mipi.dst_format));
 	if (rc) {
 		pr_debug("%s: problem determining dst format. Set Default\n",
 			__func__);
-		panel_data->panel_info.mipi.dst_format =
+		pinfo->mipi.dst_format =
 			DSI_VIDEO_DST_FORMAT_RGB888;
 	}
 	pdest = of_get_property(np,
@@ -554,35 +562,35 @@
 		return -EINVAL;
 	}
 	if (!strncmp(pdest, "display_1", 9))
-		panel_data->panel_info.pdest = DISPLAY_1;
+		pinfo->pdest = DISPLAY_1;
 	else if (!strncmp(pdest, "display_2", 9))
-		panel_data->panel_info.pdest = DISPLAY_2;
+		pinfo->pdest = DISPLAY_2;
 	else {
 		pr_debug("%s: pdest not specified. Set Default\n",
 							__func__);
-		panel_data->panel_info.pdest = DISPLAY_1;
+		pinfo->pdest = DISPLAY_1;
 	}
 	rc = of_property_read_u32(np, "qcom,mdss-dsi-h-front-porch", &tmp);
-	panel_data->panel_info.lcdc.h_front_porch = (!rc ? tmp : 6);
+	pinfo->lcdc.h_front_porch = (!rc ? tmp : 6);
 	rc = of_property_read_u32(np, "qcom,mdss-dsi-h-back-porch", &tmp);
-	panel_data->panel_info.lcdc.h_back_porch = (!rc ? tmp : 6);
+	pinfo->lcdc.h_back_porch = (!rc ? tmp : 6);
 	rc = of_property_read_u32(np, "qcom,mdss-dsi-h-pulse-width", &tmp);
-	panel_data->panel_info.lcdc.h_pulse_width = (!rc ? tmp : 2);
+	pinfo->lcdc.h_pulse_width = (!rc ? tmp : 2);
 	rc = of_property_read_u32(np, "qcom,mdss-dsi-h-sync-skew", &tmp);
-	panel_data->panel_info.lcdc.hsync_skew = (!rc ? tmp : 0);
+	pinfo->lcdc.hsync_skew = (!rc ? tmp : 0);
 	rc = of_property_read_u32(np, "qcom,mdss-dsi-v-back-porch", &tmp);
-	panel_data->panel_info.lcdc.v_back_porch = (!rc ? tmp : 6);
+	pinfo->lcdc.v_back_porch = (!rc ? tmp : 6);
 	rc = of_property_read_u32(np, "qcom,mdss-dsi-v-front-porch", &tmp);
-	panel_data->panel_info.lcdc.v_front_porch = (!rc ? tmp : 6);
+	pinfo->lcdc.v_front_porch = (!rc ? tmp : 6);
 	rc = of_property_read_u32(np, "qcom,mdss-dsi-v-pulse-width", &tmp);
-	panel_data->panel_info.lcdc.v_pulse_width = (!rc ? tmp : 2);
+	pinfo->lcdc.v_pulse_width = (!rc ? tmp : 2);
 	rc = of_property_read_u32(np,
 		"qcom,mdss-dsi-underflow-color", &tmp);
-	panel_data->panel_info.lcdc.underflow_clr = (!rc ? tmp : 0xff);
+	pinfo->lcdc.underflow_clr = (!rc ? tmp : 0xff);
 	rc = of_property_read_u32(np,
 		"qcom,mdss-dsi-border-color", &tmp);
-	panel_data->panel_info.lcdc.border_clr = (!rc ? tmp : 0);
-	panel_data->panel_info.bklt_ctrl = UNKNOWN_CTRL;
+	pinfo->lcdc.border_clr = (!rc ? tmp : 0);
+	pinfo->bklt_ctrl = UNKNOWN_CTRL;
 	data = of_get_property(np, "qcom,mdss-dsi-bl-pmic-control-type", NULL);
 	if (data) {
 		if (!strncmp(data, "bl_ctrl_wled", 12)) {
@@ -590,9 +598,9 @@
 				&bl_led_trigger);
 			pr_debug("%s: SUCCESS-> WLED TRIGGER register\n",
 				__func__);
-			panel_data->panel_info.bklt_ctrl = BL_WLED;
+			ctrl_pdata->bklt_ctrl = BL_WLED;
 		} else if (!strncmp(data, "bl_ctrl_pwm", 11)) {
-			panel_data->panel_info.bklt_ctrl = BL_PWM;
+			ctrl_pdata->bklt_ctrl = BL_PWM;
 			rc = of_property_read_u32(np,
 				"qcom,mdss-dsi-bl-pmic-pwm-frequency", &tmp);
 			if (rc) {
@@ -600,7 +608,7 @@
 						__func__, __LINE__);
 				return -EINVAL;
 			}
-			panel_data->panel_info.pwm_period = tmp;
+			ctrl_pdata->pwm_period = tmp;
 			rc = of_property_read_u32(np,
 				"qcom,mdss-dsi-bl-pmic-bank-select", &tmp);
 			if (rc) {
@@ -608,108 +616,119 @@
 						__func__, __LINE__);
 				return -EINVAL;
 			}
-			panel_data->panel_info.pwm_lpg_chan = tmp;
+			ctrl_pdata->pwm_lpg_chan = tmp;
 			tmp = of_get_named_gpio(np,
 				"qcom,mdss-dsi-pwm-gpio", 0);
-			panel_data->panel_info.pwm_pmic_gpio = tmp;
+			ctrl_pdata->pwm_pmic_gpio = tmp;
 		} else if (!strncmp(data, "bl_ctrl_dcs", 11)) {
-			panel_data->panel_info.bklt_ctrl = BL_DCS_CMD;
+			ctrl_pdata->bklt_ctrl = BL_DCS_CMD;
 		}
 	}
 	rc = of_property_read_u32(np, "qcom,mdss-dsi-bl-min-level", &tmp);
-	panel_data->panel_info.bl_min = (!rc ? tmp : 0);
+	pinfo->bl_min = (!rc ? tmp : 0);
 	rc = of_property_read_u32(np, "qcom,mdss-dsi-bl-max-level", &tmp);
-	panel_data->panel_info.bl_max = (!rc ? tmp : 255);
+	pinfo->bl_max = (!rc ? tmp : 255);
+	ctrl_pdata->bklt_max = pinfo->bl_max;
 
 	rc = of_property_read_u32(np, "qcom,mdss-dsi-interleave-mode", &tmp);
-	panel_data->panel_info.mipi.interleave_mode = (!rc ? tmp : 0);
+	pinfo->mipi.interleave_mode = (!rc ? tmp : 0);
 
-	panel_data->panel_info.mipi.vsync_enable = of_property_read_bool(np,
+	pinfo->mipi.vsync_enable = of_property_read_bool(np,
 		"qcom,mdss-dsi-te-check-enable");
-	panel_data->panel_info.mipi.hw_vsync_mode = of_property_read_bool(np,
+	pinfo->mipi.hw_vsync_mode = of_property_read_bool(np,
 		"qcom,mdss-dsi-te-using-te-pin");
 
 	rc = of_property_read_u32(np,
 		"qcom,mdss-dsi-h-sync-pulse", &tmp);
-	panel_data->panel_info.mipi.pulse_mode_hsa_he = (!rc ? tmp : false);
+	pinfo->mipi.pulse_mode_hsa_he = (!rc ? tmp : false);
 
-	panel_data->panel_info.mipi.hfp_power_stop = of_property_read_bool(np,
+	pinfo->mipi.hfp_power_stop = of_property_read_bool(np,
 		"qcom,mdss-dsi-hfp-power-mode");
-	panel_data->panel_info.mipi.hsa_power_stop = of_property_read_bool(np,
+	pinfo->mipi.hsa_power_stop = of_property_read_bool(np,
 		"qcom,mdss-dsi-hsa-power-mode");
-	panel_data->panel_info.mipi.hbp_power_stop = of_property_read_bool(np,
+	pinfo->mipi.hbp_power_stop = of_property_read_bool(np,
 		"qcom,mdss-dsi-hbp-power-mode");
-	panel_data->panel_info.mipi.bllp_power_stop = of_property_read_bool(np,
+	pinfo->mipi.bllp_power_stop = of_property_read_bool(np,
 		"qcom,mdss-dsi-bllp-power-mode");
-	panel_data->panel_info.mipi.eof_bllp_power_stop = of_property_read_bool(
+	pinfo->mipi.eof_bllp_power_stop = of_property_read_bool(
 		np, "qcom,mdss-dsi-bllp-eof-power-mode");
 	rc = of_property_read_u32(np,
 		"qcom,mdss-dsi-traffic-mode", &tmp);
-	panel_data->panel_info.mipi.traffic_mode =
+	pinfo->mipi.traffic_mode =
 			(!rc ? tmp : DSI_NON_BURST_SYNCH_PULSE);
 	rc = of_property_read_u32(np,
 		"qcom,mdss-dsi-te-dcs-command", &tmp);
-	panel_data->panel_info.mipi.insert_dcs_cmd =
+	pinfo->mipi.insert_dcs_cmd =
 			(!rc ? tmp : 1);
 	rc = of_property_read_u32(np,
 		"qcom,mdss-dsi-te-v-sync-continue-lines", &tmp);
-	panel_data->panel_info.mipi.wr_mem_continue =
+	pinfo->mipi.wr_mem_continue =
 			(!rc ? tmp : 0x3c);
 	rc = of_property_read_u32(np,
 		"qcom,mdss-dsi-te-v-sync-rd-ptr-irq-line", &tmp);
-	panel_data->panel_info.mipi.wr_mem_start =
+	pinfo->mipi.wr_mem_start =
 			(!rc ? tmp : 0x2c);
 	rc = of_property_read_u32(np,
 		"qcom,mdss-dsi-te-pin-select", &tmp);
-	panel_data->panel_info.mipi.te_sel =
+	pinfo->mipi.te_sel =
 			(!rc ? tmp : 1);
 	rc = of_property_read_u32(np, "qcom,mdss-dsi-virtual-channel-id", &tmp);
-	panel_data->panel_info.mipi.vc = (!rc ? tmp : 0);
+	pinfo->mipi.vc = (!rc ? tmp : 0);
 	rc = of_property_read_u32(np, "qcom,mdss-dsi-color-order", &tmp);
-	panel_data->panel_info.mipi.rgb_swap = (!rc ? tmp : DSI_RGB_SWAP_RGB);
-	panel_data->panel_info.mipi.data_lane0 = of_property_read_bool(np,
+	pinfo->mipi.rgb_swap = (!rc ? tmp : DSI_RGB_SWAP_RGB);
+	pinfo->mipi.data_lane0 = of_property_read_bool(np,
 		"qcom,mdss-dsi-lane-0-state");
-	panel_data->panel_info.mipi.data_lane1 = of_property_read_bool(np,
+	pinfo->mipi.data_lane1 = of_property_read_bool(np,
 		"qcom,mdss-dsi-lane-1-state");
-	panel_data->panel_info.mipi.data_lane2 = of_property_read_bool(np,
+	pinfo->mipi.data_lane2 = of_property_read_bool(np,
 		"qcom,mdss-dsi-lane-2-state");
-	panel_data->panel_info.mipi.data_lane3 = of_property_read_bool(np,
+	pinfo->mipi.data_lane3 = of_property_read_bool(np,
 		"qcom,mdss-dsi-lane-3-state");
 
 	rc = of_property_read_u32(np, "qcom,mdss-dsi-lane-map", &tmp);
-	panel_data->panel_info.mipi.dlane_swap = (!rc ? tmp : 0);
+	pinfo->mipi.dlane_swap = (!rc ? tmp : 0);
 
 	rc = of_property_read_u32(np, "qcom,mdss-dsi-t-clk-pre", &tmp);
-	panel_data->panel_info.mipi.t_clk_pre = (!rc ? tmp : 0x24);
+	pinfo->mipi.t_clk_pre = (!rc ? tmp : 0x24);
 	rc = of_property_read_u32(np, "qcom,mdss-dsi-t-clk-post", &tmp);
-	panel_data->panel_info.mipi.t_clk_post = (!rc ? tmp : 0x03);
+	pinfo->mipi.t_clk_post = (!rc ? tmp : 0x03);
 
 	rc = of_property_read_u32(np, "qcom,mdss-dsi-stream", &tmp);
-	panel_data->panel_info.mipi.stream = (!rc ? tmp : 0);
+	pinfo->mipi.stream = (!rc ? tmp : 0);
 
 	rc = of_property_read_u32(np, "qcom,mdss-dsi-mdp-trigger", &tmp);
-	panel_data->panel_info.mipi.mdp_trigger =
+	pinfo->mipi.mdp_trigger =
 			(!rc ? tmp : DSI_CMD_TRIGGER_SW);
-	if (panel_data->panel_info.mipi.mdp_trigger > 6) {
+	if (pinfo->mipi.mdp_trigger > 6) {
 		pr_err("%s:%d, Invalid mdp trigger. Forcing to sw trigger",
 						 __func__, __LINE__);
-		panel_data->panel_info.mipi.mdp_trigger =
+		pinfo->mipi.mdp_trigger =
 					DSI_CMD_TRIGGER_SW;
 	}
 
 	rc = of_property_read_u32(np, "qcom,mdss-dsi-dma-trigger", &tmp);
-	panel_data->panel_info.mipi.dma_trigger =
+	pinfo->mipi.dma_trigger =
 			(!rc ? tmp : DSI_CMD_TRIGGER_SW);
-	if (panel_data->panel_info.mipi.dma_trigger > 6) {
+	if (pinfo->mipi.dma_trigger > 6) {
 		pr_err("%s:%d, Invalid dma trigger. Forcing to sw trigger",
 						 __func__, __LINE__);
-		panel_data->panel_info.mipi.dma_trigger =
+		pinfo->mipi.dma_trigger =
 					DSI_CMD_TRIGGER_SW;
 	}
+	data = of_get_property(np, "qcom,mdss-dsi-panel-mode-gpio-state", &tmp);
+	if (data) {
+		if (!strcmp(data, "high"))
+			pinfo->mode_gpio_state = MODE_GPIO_HIGH;
+		else if (!strcmp(data, "low"))
+			pinfo->mode_gpio_state = MODE_GPIO_LOW;
+	} else {
+		pinfo->mode_gpio_state = MODE_GPIO_NOT_VALID;
+	}
+
 	rc = of_property_read_u32(np, "qcom,mdss-dsi-panel-frame-rate", &tmp);
-	panel_data->panel_info.mipi.frame_rate = (!rc ? tmp : 60);
+	pinfo->mipi.frame_rate = (!rc ? tmp : 60);
 	rc = of_property_read_u32(np, "qcom,mdss-dsi-panel-clock-rate", &tmp);
-	panel_data->panel_info.clk_rate = (!rc ? tmp : 0);
+	pinfo->clk_rate = (!rc ? tmp : 0);
 	data = of_get_property(np, "qcom,mdss-dsi-panel-timings", &len);
 	if ((!data) || (len != 12)) {
 		pr_err("%s:%d, Unable to read Phy timing settings",
@@ -717,16 +736,14 @@
 		goto error;
 	}
 	for (i = 0; i < len; i++)
-		phy_params.timing[i] = data[i];
+		pinfo->mipi.dsi_phy_db.timing[i] = data[i];
 
-	panel_data->panel_info.mipi.dsi_phy_db = &phy_params;
+	mdss_dsi_parse_fbc_params(np, pinfo);
 
-	mdss_dsi_parse_fbc_params(np, &panel_data->panel_info);
-
-	mdss_dsi_parse_dcs_cmds(np, &panel_data->on_cmds,
+	mdss_dsi_parse_dcs_cmds(np, &ctrl_pdata->on_cmds,
 		"qcom,mdss-dsi-on-command", "qcom,mdss-dsi-on-command-state");
 
-	mdss_dsi_parse_dcs_cmds(np, &panel_data->off_cmds,
+	mdss_dsi_parse_dcs_cmds(np, &ctrl_pdata->off_cmds,
 		"qcom,mdss-dsi-off-command", "qcom,mdss-dsi-off-command-state");
 
 	return 0;
@@ -736,10 +753,12 @@
 }
 
 int mdss_dsi_panel_init(struct device_node *node,
-	struct mdss_panel_common_pdata *vendor_pdata)
+	struct mdss_dsi_ctrl_pdata *ctrl_pdata,
+	bool cmd_cfg_cont_splash)
 {
 	int rc = 0;
 	static const char *panel_name;
+	bool cont_splash_enabled;
 
 	if (!node) {
 		pr_err("%s: no panel node\n", __func__);
@@ -754,15 +773,31 @@
 	else
 		pr_info("%s: Panel Name = %s\n", __func__, panel_name);
 
-	rc = mdss_panel_parse_dt(node, vendor_pdata);
+	rc = mdss_panel_parse_dt(node, ctrl_pdata);
 	if (rc) {
 		pr_err("%s:%d panel dt parse failed\n", __func__, __LINE__);
 		return rc;
 	}
 
-	vendor_pdata->on = mdss_dsi_panel_on;
-	vendor_pdata->off = mdss_dsi_panel_off;
-	vendor_pdata->bl_fnc = mdss_dsi_panel_bl_ctrl;
+	if (cmd_cfg_cont_splash)
+		cont_splash_enabled = of_property_read_bool(node,
+				"qcom,cont-splash-enabled");
+	else
+		cont_splash_enabled = false;
+	if (!cont_splash_enabled) {
+		pr_info("%s:%d Continuous splash flag not found.\n",
+				__func__, __LINE__);
+		ctrl_pdata->panel_data.panel_info.cont_splash_enabled = 0;
+	} else {
+		pr_info("%s:%d Continuous splash flag enabled.\n",
+				__func__, __LINE__);
+
+		ctrl_pdata->panel_data.panel_info.cont_splash_enabled = 1;
+	}
+
+	ctrl_pdata->on = mdss_dsi_panel_on;
+	ctrl_pdata->off = mdss_dsi_panel_off;
+	ctrl_pdata->panel_data.set_backlight = mdss_dsi_panel_bl_ctrl;
 
 	return 0;
 }
diff --git a/drivers/video/msm/mdss/mdss_fb.c b/drivers/video/msm/mdss/mdss_fb.c
index a4a2af4..793cbd7 100644
--- a/drivers/video/msm/mdss/mdss_fb.c
+++ b/drivers/video/msm/mdss/mdss_fb.c
@@ -242,12 +242,28 @@
 	return ret;
 }
 
+static ssize_t mdss_mdp_show_blank_event(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct fb_info *fbi = dev_get_drvdata(dev);
+	struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)fbi->par;
+	int ret;
+
+	pr_debug("fb%d panel_power_on = %d\n", mfd->index, mfd->panel_power_on);
+	ret = scnprintf(buf, PAGE_SIZE, "panel_power_on = %d\n",
+						mfd->panel_power_on);
+
+	return ret;
+}
+
 static DEVICE_ATTR(msm_fb_type, S_IRUGO, mdss_fb_get_type, NULL);
 static DEVICE_ATTR(msm_fb_split, S_IRUGO, mdss_fb_get_split, NULL);
+static DEVICE_ATTR(show_blank_event, S_IRUGO, mdss_mdp_show_blank_event, NULL);
 
 static struct attribute *mdss_fb_attrs[] = {
 	&dev_attr_msm_fb_type.attr,
 	&dev_attr_msm_fb_split.attr,
+	&dev_attr_show_blank_event.attr,
 	NULL,
 };
 
@@ -313,6 +329,7 @@
 	mfd->index = fbi_list_index;
 	mfd->mdp_fb_page_protection = MDP_FB_PAGE_PROTECTION_WRITECOMBINE;
 
+	mfd->ext_ad_ctrl = -1;
 	mfd->bl_level = 0;
 	mfd->bl_scale = 1024;
 	mfd->bl_min_lvl = 30;
@@ -606,6 +623,7 @@
 void mdss_fb_set_backlight(struct msm_fb_data_type *mfd, u32 bkl_lvl)
 {
 	struct mdss_panel_data *pdata;
+	int (*update_ad_input)(struct msm_fb_data_type *mfd);
 	u32 temp = bkl_lvl;
 
 	if ((!mfd->panel_power_on || !bl_updated) && !IS_CALIB_MODE_BL(mfd)) {
@@ -637,9 +655,10 @@
 		bl_level_old = temp;
 
 		if (mfd->mdp.update_ad_input) {
+			update_ad_input = mfd->mdp.update_ad_input;
 			mutex_unlock(&mfd->bl_lock);
 			/* Will trigger ad_setup which will grab bl_lock */
-			mfd->mdp.update_ad_input(mfd);
+			update_ad_input(mfd);
 			mutex_lock(&mfd->bl_lock);
 		}
 	}
@@ -703,11 +722,8 @@
 
 			mfd->op_enable = false;
 			curr_pwr_state = mfd->panel_power_on;
-			mutex_lock(&mfd->bl_lock);
-			mdss_fb_set_backlight(mfd, 0);
 			mfd->panel_power_on = false;
 			bl_updated = 0;
-			mutex_unlock(&mfd->bl_lock);
 
 			ret = mfd->mdp.off_fnc(mfd);
 			if (ret)
diff --git a/drivers/video/msm/mdss/mdss_fb.h b/drivers/video/msm/mdss/mdss_fb.h
index 65218c0..fd96e63 100644
--- a/drivers/video/msm/mdss/mdss_fb.h
+++ b/drivers/video/msm/mdss/mdss_fb.h
@@ -118,6 +118,7 @@
 	unsigned long cursor_buf_phys;
 	unsigned long cursor_buf_iova;
 
+	int ext_ad_ctrl;
 	u32 ext_bl_ctrl;
 	u32 calib_mode;
 	u32 bl_level;
diff --git a/drivers/video/msm/mdss/mdss_mdp.c b/drivers/video/msm/mdss/mdss_mdp.c
index 86a2e45..3107e38 100644
--- a/drivers/video/msm/mdss/mdss_mdp.c
+++ b/drivers/video/msm/mdss/mdss_mdp.c
@@ -1105,8 +1105,8 @@
 probe_done:
 	if (IS_ERR_VALUE(rc)) {
 		mdss_mdp_hw.ptr = NULL;
-		mdss_res = NULL;
 		mdss_mdp_pp_term(&pdev->dev);
+		mdss_res = NULL;
 	}
 
 	return rc;
@@ -1821,6 +1821,9 @@
 	if (mdata->nad_cfgs > mdata->nmixers_intf)
 		return -EINVAL;
 
+	mdata->has_wb_ad = of_property_read_bool(pdev->dev.of_node,
+		"qcom,mdss-has-wb-ad");
+
 	ad_offsets = kzalloc(sizeof(u32) * mdata->nad_cfgs, GFP_KERNEL);
 	if (!ad_offsets) {
 		pr_err("no mem assigned: kzalloc fail\n");
diff --git a/drivers/video/msm/mdss/mdss_mdp.h b/drivers/video/msm/mdss/mdss_mdp.h
index 70d9107..351d52b 100644
--- a/drivers/video/msm/mdss/mdss_mdp.h
+++ b/drivers/video/msm/mdss/mdss_mdp.h
@@ -116,6 +116,7 @@
 
 struct mdss_mdp_vsync_handler {
 	bool enabled;
+	bool cmd_post_flush;
 	mdp_vsync_handler_t vsync_handler;
 	struct list_head list;
 };
@@ -272,6 +273,7 @@
 	struct mutex lock;
 	struct work_struct calc_work;
 	struct msm_fb_data_type *mfd;
+	struct msm_fb_data_type *bl_mfd;
 	struct mdss_mdp_vsync_handler handle;
 	struct completion comp;
 	u32 last_str;
@@ -384,6 +386,7 @@
 
 	struct mdss_mdp_data free_list[MAX_FREE_LIST_SIZE];
 	int free_list_size;
+	int ad_state;
 };
 
 struct mdss_mdp_perf_params {
diff --git a/drivers/video/msm/mdss/mdss_mdp_ctl.c b/drivers/video/msm/mdss/mdss_mdp_ctl.c
index 176d0df..d2c684f 100644
--- a/drivers/video/msm/mdss/mdss_mdp_ctl.c
+++ b/drivers/video/msm/mdss/mdss_mdp_ctl.c
@@ -212,7 +212,14 @@
 
 	quota = fps * pipe->src.w * src_h;
 	if (pipe->src_fmt->chroma_sample == MDSS_MDP_CHROMA_420)
-		quota = (quota * 3) / 2;
+		/*
+		 * with decimation, chroma is not downsampled, this means we
+		 * need to allocate bw for extra lines that will be fetched
+		 */
+		if (pipe->vert_deci)
+			quota *= 2;
+		else
+			quota = (quota * 3) / 2;
 	else
 		quota *= pipe->src_fmt->bpp;
 
@@ -420,6 +427,7 @@
 	ctl->read_line_cnt_fnc = NULL;
 	ctl->add_vsync_handler = NULL;
 	ctl->remove_vsync_handler = NULL;
+	ctl->panel_data = NULL;
 	mutex_unlock(&mdss_mdp_ctl_lock);
 
 	return 0;
@@ -428,7 +436,7 @@
 static struct mdss_mdp_mixer *mdss_mdp_mixer_alloc(
 		struct mdss_mdp_ctl *ctl, u32 type, int mux)
 {
-	struct mdss_mdp_mixer *mixer = NULL;
+	struct mdss_mdp_mixer *mixer = NULL, *alt_mixer = NULL;
 	u32 nmixers_intf;
 	u32 nmixers_wb;
 	u32 i;
@@ -446,6 +454,16 @@
 	case MDSS_MDP_MIXER_TYPE_INTF:
 		mixer_pool = ctl->mdata->mixer_intf;
 		nmixers = nmixers_intf;
+
+		/*
+		 * try to reserve first layer mixer for write back if
+		 * assertive display needs to be supported through wfd
+		 */
+		if (ctl->mdata->has_wb_ad && ctl->intf_num) {
+			alt_mixer = mixer_pool;
+			mixer_pool++;
+			nmixers--;
+		}
 		break;
 
 	case MDSS_MDP_MIXER_TYPE_WRITEBACK:
@@ -484,6 +502,9 @@
 		}
 		mixer = NULL;
 	}
+
+	if (!mixer && alt_mixer && (alt_mixer->ref_cnt == 0))
+		mixer = alt_mixer;
 	mutex_unlock(&mdss_mdp_ctl_lock);
 
 	return mixer;
diff --git a/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c b/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c
index cb4c1f2..920c231 100644
--- a/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c
+++ b/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c
@@ -34,7 +34,7 @@
 	u8 ref_cnt;
 	struct completion pp_comp;
 	struct completion stop_comp;
-	mdp_vsync_handler_t send_vsync;
+	struct list_head vsync_handlers;
 	int panel_on;
 	int koff_cnt;
 	int clk_enabled;
@@ -232,6 +232,7 @@
 {
 	struct mdss_mdp_ctl *ctl = arg;
 	struct mdss_mdp_cmd_ctx *ctx = ctl->priv_data;
+	struct mdss_mdp_vsync_handler *tmp;
 	ktime_t vsync_time;
 
 	if (!ctx) {
@@ -243,8 +244,10 @@
 	ctl->vsync_cnt++;
 
 	spin_lock(&ctx->clk_lock);
-	if (ctx->send_vsync)
-		ctx->send_vsync(ctl, vsync_time);
+	list_for_each_entry(tmp, &ctx->vsync_handlers, list) {
+		if (tmp->enabled && !tmp->cmd_post_flush)
+			tmp->vsync_handler(ctl, vsync_time);
+	}
 
 	if (!ctx->vsync_enabled) {
 		if (ctx->rdptr_enabled)
@@ -265,6 +268,8 @@
 {
 	struct mdss_mdp_ctl *ctl = arg;
 	struct mdss_mdp_cmd_ctx *ctx = ctl->priv_data;
+	struct mdss_mdp_vsync_handler *tmp;
+	ktime_t vsync_time;
 
 	if (!ctx) {
 		pr_err("%s: invalid ctx\n", __func__);
@@ -272,6 +277,10 @@
 	}
 
 	spin_lock(&ctx->clk_lock);
+	list_for_each_entry(tmp, &ctx->vsync_handlers, list) {
+		if (tmp->enabled && tmp->cmd_post_flush)
+			tmp->vsync_handler(ctl, vsync_time);
+	}
 	mdss_mdp_irq_disable_nosync(MDSS_MDP_IRQ_PING_PONG_COMP, ctx->pp_num);
 
 	complete_all(&ctx->pp_comp);
@@ -318,15 +327,16 @@
 	}
 
 	spin_lock_irqsave(&ctx->clk_lock, flags);
-	if (ctx->vsync_enabled) {
-		spin_unlock_irqrestore(&ctx->clk_lock, flags);
-		return 0;
+	if (!handle->enabled) {
+		handle->enabled = true;
+		list_add(&handle->list, &ctx->vsync_handlers);
+		if (!handle->cmd_post_flush)
+			ctx->vsync_enabled = 1;
 	}
-	ctx->vsync_enabled = 1;
-	ctx->send_vsync = handle->vsync_handler;
 	spin_unlock_irqrestore(&ctx->clk_lock, flags);
 
-	mdss_mdp_cmd_clk_on(ctx);
+	if (!handle->cmd_post_flush)
+		mdss_mdp_cmd_clk_on(ctx);
 
 	return 0;
 }
@@ -337,6 +347,8 @@
 
 	struct mdss_mdp_cmd_ctx *ctx;
 	unsigned long flags;
+	struct mdss_mdp_vsync_handler *tmp;
+	int num_rdptr_vsync = 0;
 
 	ctx = (struct mdss_mdp_cmd_ctx *) ctl->priv_data;
 	if (!ctx) {
@@ -346,13 +358,18 @@
 
 
 	spin_lock_irqsave(&ctx->clk_lock, flags);
-	if (!ctx->vsync_enabled) {
-		spin_unlock_irqrestore(&ctx->clk_lock, flags);
-		return 0;
+	if (handle->enabled) {
+		handle->enabled = false;
+		list_del_init(&handle->list);
 	}
-	ctx->vsync_enabled = 0;
-	ctx->send_vsync = NULL;
-	ctx->rdptr_enabled = VSYNC_EXPIRE_TICK;
+	list_for_each_entry(tmp, &ctx->vsync_handlers, list) {
+		if (!tmp->cmd_post_flush)
+			num_rdptr_vsync++;
+	}
+	if (!num_rdptr_vsync) {
+		ctx->vsync_enabled = 0;
+		ctx->rdptr_enabled = VSYNC_EXPIRE_TICK;
+	}
 	spin_unlock_irqrestore(&ctx->clk_lock, flags);
 	return 0;
 }
@@ -455,6 +472,7 @@
 {
 	struct mdss_mdp_cmd_ctx *ctx;
 	unsigned long flags;
+	struct mdss_mdp_vsync_handler *tmp, *handle;
 	int need_wait = 0;
 	int ret = 0;
 
@@ -468,10 +486,6 @@
 		INIT_COMPLETION(ctx->stop_comp);
 		need_wait = 1;
 	}
-	if (ctx->vsync_enabled) {
-		pr_err("%s: vsync should be disabled\n", __func__);
-		ctx->vsync_enabled = 0;
-	}
 	spin_unlock_irqrestore(&ctx->clk_lock, flags);
 
 	if (need_wait)
@@ -486,6 +500,9 @@
 
 	ctx->panel_on = 0;
 
+	list_for_each_entry_safe(handle, tmp, &ctx->vsync_handlers, list)
+		mdss_mdp_cmd_remove_vsync_handler(ctl, handle);
+
 	mdss_mdp_set_intr_callback(MDSS_MDP_IRQ_PING_PONG_RD_PTR, ctx->pp_num,
 				   NULL, NULL);
 	mdss_mdp_set_intr_callback(MDSS_MDP_IRQ_PING_PONG_COMP, ctx->pp_num,
@@ -550,6 +567,7 @@
 	spin_lock_init(&ctx->clk_lock);
 	mutex_init(&ctx->clk_mtx);
 	INIT_WORK(&ctx->clk_work, clk_ctrl_work);
+	INIT_LIST_HEAD(&ctx->vsync_handlers);
 
 	pr_debug("%s: ctx=%p num=%d mixer=%d\n", __func__,
 				ctx, ctx->pp_num, mixer->num);
diff --git a/drivers/video/msm/mdss/mdss_mdp_intf_writeback.c b/drivers/video/msm/mdss/mdss_mdp_intf_writeback.c
index ff977a9..2b07428 100644
--- a/drivers/video/msm/mdss/mdss_mdp_intf_writeback.c
+++ b/drivers/video/msm/mdss/mdss_mdp_intf_writeback.c
@@ -48,6 +48,8 @@
 
 	void (*callback_fnc) (void *arg);
 	void *callback_arg;
+	spinlock_t wb_lock;
+	struct list_head vsync_handlers;
 };
 
 static struct mdss_mdp_writeback_ctx wb_ctx_list[MDSS_MDP_MAX_WRITEBACK] = {
@@ -293,16 +295,75 @@
 	return mdss_mdp_writeback_format_setup(ctx, format);
 }
 
+static int mdss_mdp_wb_add_vsync_handler(struct mdss_mdp_ctl *ctl,
+		struct mdss_mdp_vsync_handler *handle)
+{
+	struct mdss_mdp_writeback_ctx *ctx;
+	unsigned long flags;
+	int ret = 0;
+
+	if (!handle || !(handle->vsync_handler)) {
+		ret = -EINVAL;
+		goto exit;
+	}
+
+	ctx = (struct mdss_mdp_writeback_ctx *) ctl->priv_data;
+	if (!ctx) {
+		pr_err("invalid ctx for ctl=%d\n", ctl->num);
+		ret = -ENODEV;
+		goto exit;
+	}
+
+	spin_lock_irqsave(&ctx->wb_lock, flags);
+	if (!handle->enabled) {
+		handle->enabled = true;
+		list_add(&handle->list, &ctx->vsync_handlers);
+	}
+	spin_unlock_irqrestore(&ctx->wb_lock, flags);
+exit:
+	return ret;
+}
+
+static int mdss_mdp_wb_remove_vsync_handler(struct mdss_mdp_ctl *ctl,
+		struct mdss_mdp_vsync_handler *handle)
+{
+	struct mdss_mdp_writeback_ctx *ctx;
+	unsigned long flags;
+	int ret = 0;
+	if (!handle || !(handle->vsync_handler)) {
+		ret = -EINVAL;
+		goto exit;
+	}
+	ctx = (struct mdss_mdp_writeback_ctx *) ctl->priv_data;
+	if (!ctx) {
+		pr_err("invalid ctx for ctl=%d\n", ctl->num);
+		ret = -ENODEV;
+		goto exit;
+	}
+	spin_lock_irqsave(&ctx->wb_lock, flags);
+	if (handle->enabled) {
+		handle->enabled = false;
+		list_del_init(&handle->list);
+	}
+	spin_unlock_irqrestore(&ctx->wb_lock, flags);
+exit:
+	return ret;
+}
+
 static int mdss_mdp_writeback_stop(struct mdss_mdp_ctl *ctl)
 {
 	struct mdss_mdp_writeback_ctx *ctx;
+	struct mdss_mdp_vsync_handler *t, *handle;
 
 	pr_debug("stop ctl=%d\n", ctl->num);
 
 	ctx = (struct mdss_mdp_writeback_ctx *) ctl->priv_data;
 	if (ctx) {
+		list_for_each_entry_safe(handle, t, &ctx->vsync_handlers, list)
+			mdss_mdp_wb_remove_vsync_handler(ctl, handle);
+
 		mdss_mdp_set_intr_callback(ctx->intr_type, ctx->intf_num,
-				   NULL, NULL);
+				NULL, NULL);
 
 		ctl->priv_data = NULL;
 		ctx->ref_cnt--;
@@ -313,13 +374,16 @@
 
 static void mdss_mdp_writeback_intr_done(void *arg)
 {
-	struct mdss_mdp_writeback_ctx *ctx;
+	struct mdss_mdp_ctl *ctl = arg;
+	struct mdss_mdp_writeback_ctx *ctx = ctl->priv_data;
+	struct mdss_mdp_vsync_handler *tmp;
+	ktime_t vsync_time;
 
-	ctx = (struct mdss_mdp_writeback_ctx *) arg;
 	if (!ctx) {
 		pr_err("invalid ctx\n");
 		return;
 	}
+	vsync_time = ktime_get();
 
 	pr_debug("intr wb_num=%d\n", ctx->wb_num);
 
@@ -328,6 +392,12 @@
 	if (ctx->callback_fnc)
 		ctx->callback_fnc(ctx->callback_arg);
 
+	spin_lock(&ctx->wb_lock);
+	list_for_each_entry(tmp, &ctx->vsync_handlers, list) {
+		tmp->vsync_handler(ctl, vsync_time);
+	}
+	spin_unlock(&ctx->wb_lock);
+
 	complete_all(&ctx->wb_comp);
 }
 
@@ -393,7 +463,7 @@
 	}
 
 	mdss_mdp_set_intr_callback(ctx->intr_type, ctx->intf_num,
-		   mdss_mdp_writeback_intr_done, ctx);
+		   mdss_mdp_writeback_intr_done, ctl);
 
 	ctx->callback_fnc = wb_args->callback_fnc;
 	ctx->callback_arg = wb_args->priv_data;
@@ -439,6 +509,8 @@
 	ctx->base = ctl->wb_base;
 	ctx->initialized = false;
 	init_completion(&ctx->wb_comp);
+	spin_lock_init(&ctx->wb_lock);
+	INIT_LIST_HEAD(&ctx->vsync_handlers);
 
 	if (ctx->type == MDSS_MDP_WRITEBACK_TYPE_ROTATOR)
 		ctl->prepare_fnc = mdss_mdp_writeback_prepare_rot;
@@ -447,6 +519,8 @@
 	ctl->stop_fnc = mdss_mdp_writeback_stop;
 	ctl->display_fnc = mdss_mdp_writeback_display;
 	ctl->wait_fnc = mdss_mdp_wb_wait4comp;
+	ctl->add_vsync_handler = mdss_mdp_wb_add_vsync_handler;
+	ctl->remove_vsync_handler = mdss_mdp_wb_remove_vsync_handler;
 
 	return ret;
 }
diff --git a/drivers/video/msm/mdss/mdss_mdp_overlay.c b/drivers/video/msm/mdss/mdss_mdp_overlay.c
index 55889da..fcc87f6 100644
--- a/drivers/video/msm/mdss/mdss_mdp_overlay.c
+++ b/drivers/video/msm/mdss/mdss_mdp_overlay.c
@@ -25,6 +25,7 @@
 
 #include <mach/iommu_domains.h>
 #include <mach/event_timer.h>
+#include <mach/msm_bus.h>
 
 #include "mdss.h"
 #include "mdss_debug.h"
@@ -37,6 +38,9 @@
 #define CHECK_BOUNDS(offset, size, max_size) \
 	(((size) > (max_size)) || ((offset) > ((max_size) - (size))))
 
+#define PP_CLK_CFG_OFF 0
+#define PP_CLK_CFG_ON 1
+
 static atomic_t ov_active_panels = ATOMIC_INIT(0);
 static int mdss_mdp_overlay_free_fb_pipe(struct msm_fb_data_type *mfd);
 static int mdss_mdp_overlay_fb_parse_dt(struct msm_fb_data_type *mfd);
@@ -823,7 +827,7 @@
 int mdss_mdp_overlay_kickoff(struct msm_fb_data_type *mfd)
 {
 	struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
-	struct mdss_mdp_pipe *pipe, *next;
+	struct mdss_mdp_pipe *pipe;
 	struct mdss_mdp_ctl *ctl = mfd_to_ctl(mfd);
 	struct mdss_mdp_ctl *tmp;
 	int ret;
@@ -843,8 +847,7 @@
 		return ret;
 	}
 
-	list_for_each_entry_safe(pipe, next, &mdp5_data->pipes_used,
-			used_list) {
+	list_for_each_entry(pipe, &mdp5_data->pipes_used, used_list) {
 		struct mdss_mdp_data *buf;
 		/*
 		 * When external is connected and no dedicated wfd is present,
@@ -882,12 +885,6 @@
 			pipe->params_changed++;
 			buf = &pipe->front_buf;
 		} else if (!pipe->params_changed) {
-			if (pipe->mixer && !mdss_mdp_pipe_is_staged(pipe) &&
-			    !list_empty(&pipe->used_list)) {
-				list_del_init(&pipe->used_list);
-				list_add(&pipe->cleanup_list,
-					&mdp5_data->pipes_cleanup);
-			}
 			continue;
 		} else if (pipe->front_buf.num_planes) {
 			buf = &pipe->front_buf;
@@ -1450,14 +1447,9 @@
 	if (!ctl->add_vsync_handler || !ctl->remove_vsync_handler)
 		return -EOPNOTSUPP;
 
-	rc = mutex_lock_interruptible(&ctl->lock);
-	if (rc)
-		return rc;
-
 	if (!ctl->power_on) {
 		pr_debug("fb%d vsync pending first update en=%d\n",
 				mfd->index, en);
-		mutex_unlock(&ctl->lock);
 		return -EPERM;
 	}
 
@@ -1470,8 +1462,6 @@
 		rc = ctl->remove_vsync_handler(ctl, &ctl->vsync_handler);
 	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
 
-	mutex_unlock(&ctl->lock);
-
 	return rc;
 }
 
@@ -1495,15 +1485,81 @@
 	return ret;
 }
 
-static DEVICE_ATTR(vsync_event, S_IRUGO, mdss_mdp_vsync_show_event, NULL);
+static inline int mdss_mdp_ad_is_supported(struct msm_fb_data_type *mfd)
+{
+	struct mdss_mdp_ctl *ctl = mfd_to_ctl(mfd);
+	struct mdss_mdp_mixer *mixer;
 
-static struct attribute *vsync_fs_attrs[] = {
+	if (!ctl) {
+		pr_debug("there is no ctl attached to fb\n");
+		return 0;
+	}
+
+	mixer = mdss_mdp_mixer_get(ctl, MDSS_MDP_MIXER_MUX_LEFT);
+	if (mixer && (mixer->num > ctl->mdata->nad_cfgs)) {
+		if (!mixer)
+			pr_warn("there is no mixer attached to fb\n");
+		else
+			pr_debug("mixer attached (%d) doesnt support ad\n",
+				 mixer->num);
+		return 0;
+	}
+
+	mixer = mdss_mdp_mixer_get(ctl, MDSS_MDP_MIXER_MUX_RIGHT);
+	if (mixer && (mixer->num > ctl->mdata->nad_cfgs))
+		return 0;
+
+	return 1;
+}
+
+static ssize_t mdss_mdp_ad_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct fb_info *fbi = dev_get_drvdata(dev);
+	struct msm_fb_data_type *mfd = fbi->par;
+	struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
+	int ret, state;
+
+	state = mdss_mdp_ad_is_supported(mfd) ? mdp5_data->ad_state : -1;
+
+	ret = scnprintf(buf, PAGE_SIZE, "%d", state);
+
+	return ret;
+}
+
+static ssize_t mdss_mdp_ad_store(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count)
+{
+	struct fb_info *fbi = dev_get_drvdata(dev);
+	struct msm_fb_data_type *mfd = fbi->par;
+	struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
+	int ret, ad;
+
+	ret = kstrtoint(buf, 10, &ad);
+	if (ret) {
+		pr_err("Invalid input for ad\n");
+		return -EINVAL;
+	}
+
+	mdp5_data->ad_state = ad;
+	sysfs_notify(&dev->kobj, NULL, "ad");
+
+	return count;
+}
+
+
+static DEVICE_ATTR(vsync_event, S_IRUGO, mdss_mdp_vsync_show_event, NULL);
+static DEVICE_ATTR(ad, S_IRUGO | S_IWUSR | S_IWGRP, mdss_mdp_ad_show,
+	mdss_mdp_ad_store);
+
+static struct attribute *mdp_overlay_sysfs_attrs[] = {
 	&dev_attr_vsync_event.attr,
+	&dev_attr_ad.attr,
 	NULL,
 };
 
-static struct attribute_group vsync_fs_attr_group = {
-	.attrs = vsync_fs_attrs,
+static struct attribute_group mdp_overlay_sysfs_group = {
+	.attrs = mdp_overlay_sysfs_attrs,
 };
 
 static int mdss_mdp_hw_cursor_update(struct msm_fb_data_type *mfd,
@@ -1779,12 +1835,20 @@
 	struct mdp_histogram_start_req hist_req;
 	u32 block;
 	struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
+	u32 pp_bus_handle;
+	static int req = -1;
 
 	switch (cmd) {
 	case MSMFB_HISTOGRAM_START:
 		if (!mfd->panel_power_on)
 			return -EPERM;
 
+		pp_bus_handle = mdss_mdp_get_mdata()->pp_bus_hdl;
+		req = msm_bus_scale_client_update_request(pp_bus_handle,
+				PP_CLK_CFG_ON);
+		if (req)
+			pr_err("Updated pp_bus_scale failed, ret = %d", req);
+
 		ret = copy_from_user(&hist_req, argp, sizeof(hist_req));
 		if (ret)
 			return ret;
@@ -1798,6 +1862,17 @@
 			return ret;
 
 		ret = mdss_mdp_histogram_stop(mdp5_data->ctl, block);
+		if (ret)
+			return ret;
+
+		if (!req) {
+			pp_bus_handle = mdss_mdp_get_mdata()->pp_bus_hdl;
+			req = msm_bus_scale_client_update_request(pp_bus_handle,
+				 PP_CLK_CFG_OFF);
+			if (req)
+				pr_err("Updated pp_bus_scale failed, ret = %d",
+					req);
+		}
 		break;
 
 	case MSMFB_HISTOGRAM:
@@ -2051,6 +2126,7 @@
 		}
 		ctl->vsync_handler.vsync_handler =
 						mdss_mdp_overlay_handle_vsync;
+		ctl->vsync_handler.cmd_post_flush = false;
 
 		if (mfd->split_display && pdata->next) {
 			/* enable split display */
@@ -2063,10 +2139,11 @@
 		mdp5_data->ctl = ctl;
 	}
 
-	if (!mfd->panel_info->cont_splash_enabled) {
+	if (!mfd->panel_info->cont_splash_enabled &&
+		(mfd->panel_info->type != DTV_PANEL) &&
+		(mfd->panel_info->type != WRITEBACK_PANEL)) {
 		rc = mdss_mdp_overlay_start(mfd);
-		if (!IS_ERR_VALUE(rc) && (mfd->panel_info->type != DTV_PANEL) &&
-			(mfd->panel_info->type != WRITEBACK_PANEL))
+		if (!IS_ERR_VALUE(rc))
 			rc = mdss_mdp_overlay_kickoff(mfd);
 	} else {
 		rc = mdss_mdp_ctl_setup(mdp5_data->ctl);
@@ -2201,7 +2278,7 @@
 	if (rc)
 		return rc;
 
-	rc = sysfs_create_group(&dev->kobj, &vsync_fs_attr_group);
+	rc = sysfs_create_group(&dev->kobj, &mdp_overlay_sysfs_group);
 	if (rc) {
 		pr_err("vsync sysfs group creation failed, ret=%d\n", rc);
 		goto init_fail;
diff --git a/drivers/video/msm/mdss/mdss_mdp_pipe.c b/drivers/video/msm/mdss/mdss_mdp_pipe.c
index 3f75053..16ea7dc 100644
--- a/drivers/video/msm/mdss/mdss_mdp_pipe.c
+++ b/drivers/video/msm/mdss/mdss_mdp_pipe.c
@@ -173,21 +173,39 @@
 			return rc;
 		pr_debug("BWC SMP strides ystride0=%x ystride1=%x\n",
 			ps.ystride[0], ps.ystride[1]);
-	} else if (mdata->has_decimation && pipe->src_fmt->is_yuv) {
-		ps.num_planes = 2;
-		ps.ystride[0] = width;
-		ps.ystride[1] = ps.ystride[0];
 	} else {
 		rc = mdss_mdp_get_plane_sizes(pipe->src_fmt->format,
 			width, pipe->src.h, &ps, 0);
 		if (rc)
 			return rc;
 
-		if (pipe->mixer && pipe->mixer->rotator_mode)
+		if (pipe->mixer && pipe->mixer->rotator_mode) {
 			rot_mode = 1;
-		else if (ps.num_planes == 1)
+		} else if (ps.num_planes == 1) {
 			ps.ystride[0] = MAX_BPP *
 				max(pipe->mixer->width, width);
+		} else if (mdata->has_decimation) {
+			/*
+			 * when decimation block is used, all chroma planes
+			 * are fetched on a single SMP plane for chroma pixels
+			 */
+			if (ps.num_planes == 3) {
+				ps.num_planes = 2;
+				ps.ystride[1] += ps.ystride[2];
+			}
+
+			/*
+			 * To avoid quailty loss, MDP does one less decimation
+			 * on chroma components if they are subsampled.
+			 * Account for this to have enough SMPs for latency
+			 */
+			switch (pipe->src_fmt->chroma_sample) {
+			case MDSS_MDP_CHROMA_H2V1:
+			case MDSS_MDP_CHROMA_420:
+				ps.ystride[1] <<= 1;
+				break;
+			}
+		}
 	}
 
 	nlines = pipe->bwc_mode ? 1 : 2;
diff --git a/drivers/video/msm/mdss/mdss_mdp_pp.c b/drivers/video/msm/mdss/mdss_mdp_pp.c
index 95eb381..09b789b 100644
--- a/drivers/video/msm/mdss/mdss_mdp_pp.c
+++ b/drivers/video/msm/mdss/mdss_mdp_pp.c
@@ -19,6 +19,8 @@
 #include <linux/uaccess.h>
 #include <linux/spinlock.h>
 #include <linux/delay.h>
+#include <mach/msm_bus.h>
+#include <mach/msm_bus_board.h>
 
 struct mdp_csc_cfg mdp_csc_convert[MDSS_MDP_MAX_CSC] = {
 	[MDSS_MDP_CSC_RGB2RGB] = {
@@ -226,6 +228,27 @@
 #define SHARP_SMOOTH_THR_DEFAULT	8
 #define SHARP_NOISE_THR_DEFAULT	2
 
+#define MDP_PP_BUS_VECTOR_ENTRY(ab_val, ib_val)		\
+	{						\
+		.src = MSM_BUS_MASTER_SPDM,		\
+		.dst = MSM_BUS_SLAVE_IMEM_CFG,		\
+		.ab = (ab_val),				\
+		.ib = (ib_val),				\
+	}
+
+#define SZ_37_5M (37500000 * 8)
+
+static struct msm_bus_vectors mdp_pp_bus_vectors[] = {
+	MDP_PP_BUS_VECTOR_ENTRY(0, 0),
+	MDP_PP_BUS_VECTOR_ENTRY(0, SZ_37_5M),
+};
+static struct msm_bus_paths mdp_pp_bus_usecases[ARRAY_SIZE(mdp_pp_bus_vectors)];
+static struct msm_bus_scale_pdata mdp_pp_bus_scale_table = {
+	.usecase = mdp_pp_bus_usecases,
+	.num_usecases = ARRAY_SIZE(mdp_pp_bus_usecases),
+	.name = "mdss_pp",
+};
+
 struct mdss_pp_res_type {
 	/* logical info */
 	u32 pp_disp_flags[MDSS_BLOCK_DISP_NUM];
@@ -266,7 +289,8 @@
 static void pp_update_igc_lut(struct mdp_igc_lut_data *cfg,
 				u32 offset, u32 blk_idx);
 static void pp_update_gc_one_lut(u32 offset,
-				struct mdp_ar_gc_lut_data *lut_data);
+				struct mdp_ar_gc_lut_data *lut_data,
+				uint8_t num_stages);
 static void pp_update_argc_lut(u32 offset,
 				struct mdp_pgc_lut_data *config);
 static void pp_update_hist_lut(char __iomem *base,
@@ -1008,8 +1032,7 @@
 		flags = 0;
 
 	mixer_cnt = mdss_mdp_get_ctl_mixers(disp_num, mixer_id);
-	if (dspp_num < mdata->nad_cfgs && (mixer_cnt != 2) &&
-			ctl->mfd->panel_info->type != MIPI_CMD_PANEL) {
+	if (dspp_num < mdata->nad_cfgs && (mixer_cnt != 2)) {
 		ret = mdss_mdp_ad_setup(ctl->mfd);
 		if (ret < 0)
 			pr_warn("ad_setup(dspp%d) returns %d", dspp_num, ret);
@@ -1188,7 +1211,7 @@
 		if (PP_AD_STATE_INIT & ad->state)
 			pp_ad_init_write(ad);
 		if (PP_AD_STATE_DATA & ad->state) {
-			bl = ctl->mfd->bl_level;
+			bl = ad->bl_mfd->bl_level;
 			ad->last_bl = bl;
 			if (ad->state & PP_AD_STATE_BL_LIN) {
 				bl = ad->bl_lin[bl >> ad->bl_bright_shift];
@@ -1268,6 +1291,7 @@
 	int i, ret = 0;
 	struct mdss_data_type *mdata = mdss_mdp_get_mdata();
 	struct mdss_mdp_pipe *vig;
+	struct msm_bus_scale_pdata *pp_bus_pdata;
 
 	mutex_lock(&mdss_pp_mutex);
 	if (!mdss_pp_res) {
@@ -1289,12 +1313,34 @@
 			mutex_init(&vig[i].pp_res.hist.hist_mutex);
 			spin_lock_init(&vig[i].pp_res.hist.hist_lock);
 		}
+		if (!mdata->pp_bus_hdl) {
+			pp_bus_pdata = &mdp_pp_bus_scale_table;
+			for (i = 0; i < pp_bus_pdata->num_usecases; i++) {
+				mdp_pp_bus_usecases[i].num_paths = 1;
+				mdp_pp_bus_usecases[i].vectors =
+					&mdp_pp_bus_vectors[i];
+			}
+
+			mdata->pp_bus_hdl =
+				msm_bus_scale_register_client(pp_bus_pdata);
+			if (!mdata->pp_bus_hdl) {
+				pr_err("not able to register pp_bus_scale\n");
+				ret = -ENOMEM;
+			}
+			pr_debug("register pp_bus_hdl=%x\n", mdata->pp_bus_hdl);
+		}
+
 	}
 	mutex_unlock(&mdss_pp_mutex);
 	return ret;
 }
 void mdss_mdp_pp_term(struct device *dev)
 {
+	struct mdss_data_type *mdata = mdss_mdp_get_mdata();
+	if (mdata->pp_bus_hdl) {
+		msm_bus_scale_unregister_client(mdata->pp_bus_hdl);
+		mdata->pp_bus_hdl = 0;
+	}
 	if (!mdss_pp_res) {
 		mutex_lock(&mdss_pp_mutex);
 		devm_kfree(dev, mdss_pp_res);
@@ -1707,35 +1753,48 @@
 	return ret;
 }
 static void pp_update_gc_one_lut(u32 offset,
-		struct mdp_ar_gc_lut_data *lut_data)
+		struct mdp_ar_gc_lut_data *lut_data,
+		uint8_t num_stages)
 {
-	int i, start_idx;
+	int i, start_idx, idx;
 
 	start_idx = (MDSS_MDP_REG_READ(offset) >> 16) & 0xF;
-	for (i = start_idx; i < GC_LUT_SEGMENTS; i++)
-		MDSS_MDP_REG_WRITE(offset, lut_data[i].x_start);
-	for (i = 0; i < start_idx; i++)
-		MDSS_MDP_REG_WRITE(offset, lut_data[i].x_start);
+	for (i = start_idx; i < GC_LUT_SEGMENTS; i++) {
+		idx = min((uint8_t)i, (uint8_t)(num_stages-1));
+		MDSS_MDP_REG_WRITE(offset, lut_data[idx].x_start);
+	}
+	for (i = 0; i < start_idx; i++) {
+		idx = min((uint8_t)i, (uint8_t)(num_stages-1));
+		MDSS_MDP_REG_WRITE(offset, lut_data[idx].x_start);
+	}
 	offset += 4;
 	start_idx = (MDSS_MDP_REG_READ(offset) >> 16) & 0xF;
-	for (i = start_idx; i < GC_LUT_SEGMENTS; i++)
-		MDSS_MDP_REG_WRITE(offset, lut_data[i].slope);
-	for (i = 0; i < start_idx; i++)
-		MDSS_MDP_REG_WRITE(offset, lut_data[i].slope);
+	for (i = start_idx; i < GC_LUT_SEGMENTS; i++) {
+		idx = min((uint8_t)i, (uint8_t)(num_stages-1));
+		MDSS_MDP_REG_WRITE(offset, lut_data[idx].slope);
+	}
+	for (i = 0; i < start_idx; i++) {
+		idx = min((uint8_t)i, (uint8_t)(num_stages-1));
+		MDSS_MDP_REG_WRITE(offset, lut_data[idx].slope);
+	}
 	offset += 4;
 	start_idx = (MDSS_MDP_REG_READ(offset) >> 16) & 0xF;
-	for (i = start_idx; i < GC_LUT_SEGMENTS; i++)
-		MDSS_MDP_REG_WRITE(offset, lut_data[i].offset);
-	for (i = 0; i < start_idx; i++)
-		MDSS_MDP_REG_WRITE(offset, lut_data[i].offset);
+	for (i = start_idx; i < GC_LUT_SEGMENTS; i++) {
+		idx = min((uint8_t)i, (uint8_t)(num_stages-1));
+		MDSS_MDP_REG_WRITE(offset, lut_data[idx].offset);
+	}
+	for (i = 0; i < start_idx; i++) {
+		idx = min((uint8_t)i, (uint8_t)(num_stages-1));
+		MDSS_MDP_REG_WRITE(offset, lut_data[idx].offset);
+	}
 }
 static void pp_update_argc_lut(u32 offset, struct mdp_pgc_lut_data *config)
 {
-	pp_update_gc_one_lut(offset, config->r_data);
+	pp_update_gc_one_lut(offset, config->r_data, config->num_r_stages);
 	offset += 0x10;
-	pp_update_gc_one_lut(offset, config->g_data);
+	pp_update_gc_one_lut(offset, config->g_data, config->num_g_stages);
 	offset += 0x10;
-	pp_update_gc_one_lut(offset, config->b_data);
+	pp_update_gc_one_lut(offset, config->b_data, config->num_b_stages);
 }
 static void pp_read_gc_one_lut(u32 offset,
 		struct mdp_ar_gc_lut_data *gc_data)
@@ -1813,7 +1872,7 @@
 	u32 argc_offset = 0, disp_num, dspp_num = 0;
 	struct mdp_pgc_lut_data local_cfg;
 	struct mdp_pgc_lut_data *pgc_ptr;
-	u32 tbl_size;
+	u32 tbl_size, r_size, g_size, b_size;
 
 	if (!ctl)
 		return -EINVAL;
@@ -1884,18 +1943,35 @@
 		*copyback = 1;
 		mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
 	} else {
+		r_size = config->num_r_stages *
+			sizeof(struct mdp_ar_gc_lut_data);
+		g_size = config->num_g_stages *
+			sizeof(struct mdp_ar_gc_lut_data);
+		b_size = config->num_b_stages *
+			sizeof(struct mdp_ar_gc_lut_data);
+		if (r_size > tbl_size ||
+			g_size > tbl_size ||
+			b_size > tbl_size ||
+			r_size == 0 ||
+			g_size == 0 ||
+			b_size == 0) {
+			ret = -EINVAL;
+			pr_warn("%s, number of rgb stages invalid",
+				__func__);
+			goto argc_config_exit;
+		}
 		if (copy_from_user(&mdss_pp_res->gc_lut_r[disp_num][0],
-			config->r_data, tbl_size)) {
+			config->r_data, r_size)) {
 			ret = -EFAULT;
 			goto argc_config_exit;
 		}
 		if (copy_from_user(&mdss_pp_res->gc_lut_g[disp_num][0],
-			config->g_data, tbl_size)) {
+			config->g_data, g_size)) {
 			ret = -EFAULT;
 			goto argc_config_exit;
 		}
 		if (copy_from_user(&mdss_pp_res->gc_lut_b[disp_num][0],
-			config->b_data, tbl_size)) {
+			config->b_data, b_size)) {
 			ret = -EFAULT;
 			goto argc_config_exit;
 		}
@@ -2537,13 +2613,13 @@
 			if (ret)
 				goto hist_collect_exit;
 		}
+		if (hist->bin_cnt != HIST_V_SIZE) {
+			pr_err("User not expecting size %d output",
+							HIST_V_SIZE);
+			ret = -EINVAL;
+			goto hist_collect_exit;
+		}
 		if (hist_cnt > 1) {
-			if (hist->bin_cnt != HIST_V_SIZE) {
-				pr_err("User not expecting size %d output",
-								HIST_V_SIZE);
-				ret = -EINVAL;
-				goto hist_collect_exit;
-			}
 			hist_concat = kmalloc(HIST_V_SIZE * sizeof(u32),
 								GFP_KERNEL);
 			if (!hist_concat) {
@@ -2607,13 +2683,14 @@
 			if (ret)
 				goto hist_collect_exit;
 		}
+		if (pipe_cnt != 0 &&
+			(hist->bin_cnt != (HIST_V_SIZE * pipe_cnt))) {
+			pr_err("User not expecting size %d output",
+						pipe_cnt * HIST_V_SIZE);
+			ret = -EINVAL;
+			goto hist_collect_exit;
+		}
 		if (pipe_cnt > 1) {
-			if (hist->bin_cnt != (HIST_V_SIZE * pipe_cnt)) {
-				pr_err("User not expecting size %d output",
-							pipe_cnt * HIST_V_SIZE);
-				ret = -EINVAL;
-				goto hist_collect_exit;
-			}
 			hist_concat = kmalloc(HIST_V_SIZE * pipe_cnt *
 						sizeof(u32), GFP_KERNEL);
 			if (!hist_concat) {
@@ -2716,6 +2793,22 @@
 	};
 }
 
+static struct msm_fb_data_type *mdss_get_mfd_from_index(int index)
+{
+	struct msm_fb_data_type *out = NULL;
+	struct mdss_mdp_ctl *ctl;
+	struct mdss_data_type *mdata = mdss_mdp_get_mdata();
+	int i;
+
+	for (i = 0; i < mdata->nctl; i++) {
+		ctl = mdata->ctl_off + i;
+		if ((ctl->power_on) && (ctl->mfd)
+				&& (ctl->mfd->index == index))
+			out = ctl->mfd;
+	}
+	return out;
+}
+
 #define MDSS_AD_MAX_MIXERS 1
 static int mdss_ad_init_checks(struct msm_fb_data_type *mfd)
 {
@@ -2724,8 +2817,12 @@
 	u32 ret = -EINVAL;
 	int i = 0;
 	struct mdss_data_type *mdata = mfd_to_mdata(mfd);
+	struct msm_fb_data_type *ad_mfd = mfd;
 
-	if (!mfd || !mdata)
+	if (ad_mfd->ext_ad_ctrl >= 0)
+		ad_mfd = mdss_get_mfd_from_index(ad_mfd->ext_ad_ctrl);
+
+	if (!ad_mfd || !mdata)
 		return ret;
 
 	if (mdata->nad_cfgs == 0) {
@@ -2733,18 +2830,13 @@
 		return -ENODEV;
 	}
 
-	if (mfd->panel_info->type == MIPI_CMD_PANEL) {
-		pr_debug("Command panel not supported");
-		return -EINVAL;
-	}
-
-	mixer_num = mdss_mdp_get_ctl_mixers(mfd->index, mixer_id);
+	mixer_num = mdss_mdp_get_ctl_mixers(ad_mfd->index, mixer_id);
 	if (!mixer_num) {
 		pr_debug("no mixers connected, %d", mixer_num);
 		return -EHOSTDOWN;
 	}
 	if (mixer_num > MDSS_AD_MAX_MIXERS) {
-		pr_warn("too many mixers, not supported, %d", mixer_num);
+		pr_debug("too many mixers, not supported, %d", mixer_num);
 		return ret;
 	}
 
@@ -2811,12 +2903,20 @@
 {
 	struct mdss_ad_info *ad;
 	struct mdss_mdp_ctl *ctl;
+	struct msm_fb_data_type *bl_mfd;
 	int lin_ret = -1, inv_ret = -1, ret = 0;
 	u32 ratio_temp, shift = 0;
 
 	ret = mdss_mdp_get_ad(mfd, &ad);
 	if (ret)
 		return ret;
+	if (mfd->panel_info->type == WRITEBACK_PANEL) {
+		bl_mfd = mdss_get_mfd_from_index(0);
+		if (!bl_mfd)
+			return ret;
+	} else {
+		bl_mfd = mfd;
+	}
 
 	mutex_lock(&ad->lock);
 	if (init_cfg->ops & MDP_PP_AD_INIT) {
@@ -2853,7 +2953,7 @@
 		 * TODO: specify panel independent range of input from cfg,
 		 * scale input backlight_scale to panel bl_max's range
 		 */
-		ad->cfg.backlight_scale = mfd->panel_info->bl_max;
+		ad->cfg.backlight_scale = bl_mfd->panel_info->bl_max;
 		ad->sts |= PP_AD_STS_DIRTY_CFG;
 	}
 
@@ -2863,9 +2963,11 @@
 		cancel_work_sync(&ad->calc_work);
 		mutex_lock(&ad->lock);
 		ad->mfd = NULL;
+		ad->bl_mfd = NULL;
 	} else if (!ret && (init_cfg->ops & MDP_PP_OPS_ENABLE)) {
 		ad->sts |= PP_STS_ENABLE;
 		ad->mfd = mfd;
+		ad->bl_mfd = bl_mfd;
 	}
 	mutex_unlock(&ad->lock);
 	ctl = mfd_to_ctl(mfd);
@@ -2902,7 +3004,7 @@
 			goto error;
 		}
 		ad->ad_data_mode = MDSS_AD_INPUT_AMBIENT;
-
+		pr_debug("ambient = %d", input->in.amb_light);
 		ad->ad_data = input->in.amb_light;
 		ad->calc_itr = ad->cfg.stab_itr;
 		ad->sts |= PP_AD_STS_DIRTY_VSYNC;
@@ -2916,6 +3018,7 @@
 			goto error;
 		}
 		ad->ad_data_mode = MDSS_AD_INPUT_STRENGTH;
+		pr_debug("strength = %d", input->in.strength);
 		ad->ad_data = input->in.strength;
 		ad->calc_itr = ad->cfg.stab_itr;
 		ad->sts |= PP_AD_STS_DIRTY_VSYNC;
@@ -3090,12 +3193,22 @@
 	int ret = 0;
 	struct mdss_ad_info *ad;
 	struct mdss_mdp_ctl *ctl = mfd_to_ctl(mfd);
+	struct msm_fb_data_type *bl_mfd;
 	char __iomem *base;
+	u32 temp;
 	u32 bypass = MDSS_PP_AD_BYPASS_DEF, bl;
 
 	ret = mdss_mdp_get_ad(mfd, &ad);
 	if (ret)
 		return ret;
+	if (mfd->panel_info->type == WRITEBACK_PANEL) {
+		bl_mfd = mdss_get_mfd_from_index(0);
+		if (!bl_mfd)
+			return ret;
+	} else {
+		bl_mfd = mfd;
+	}
+
 
 	base = ad->base;
 
@@ -3115,21 +3228,21 @@
 		 */
 		ad->sts &= ~PP_AD_STS_DIRTY_DATA;
 		ad->state |= PP_AD_STATE_DATA;
-		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;
-			}
+		mutex_lock(&bl_mfd->bl_lock);
+		bl = bl_mfd->bl_level;
+		pr_debug("dirty data, last_bl = %d ", ad->last_bl);
+		if ((ad->cfg.mode == MDSS_AD_MODE_AUTO_STR) &&
+							(ad->last_bl != 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);
+			mutex_unlock(&bl_mfd->bl_lock);
 		}
+		mutex_unlock(&mfd->bl_lock);
 		pp_ad_input_write(ad, bl);
 	}
 
@@ -3151,14 +3264,31 @@
 		pp_ad_init_write(ad);
 	}
 
+	/* update ad screen size if it has changed since last configuration */
+	if (mfd->panel_info->type == WRITEBACK_PANEL &&
+		(ad->init.frame_w != ctl->width ||
+			ad->init.frame_h != ctl->height)) {
+		pr_debug("changing from %dx%d to %dx%d", ad->init.frame_w,
+							ad->init.frame_h,
+							ctl->width,
+							ctl->height);
+		ad->init.frame_w = ctl->width;
+		ad->init.frame_h = ctl->height;
+		temp = ad->init.frame_w << 16;
+		temp |= ad->init.frame_h & 0xFFFF;
+		writel_relaxed(temp, base + MDSS_MDP_REG_AD_FRAME_SIZE);
+	}
+
 	if ((ad->sts & PP_STS_ENABLE) && PP_AD_STATE_IS_READY(ad->state)) {
 		bypass = 0;
 		ret = 1;
 		ad->state |= PP_AD_STATE_RUN;
-		mutex_lock(&mfd->bl_lock);
-		mfd->mdp.update_ad_input = pp_update_ad_input;
-		mfd->ext_bl_ctrl = ad->cfg.bl_ctrl_mode;
-		mutex_unlock(&mfd->bl_lock);
+		mutex_lock(&bl_mfd->bl_lock);
+		if (bl_mfd != mfd)
+			bl_mfd->ext_ad_ctrl = mfd->index;
+		bl_mfd->mdp.update_ad_input = pp_update_ad_input;
+		bl_mfd->ext_bl_ctrl = ad->cfg.bl_ctrl_mode;
+		mutex_unlock(&bl_mfd->bl_lock);
 
 	} else {
 		if (ad->state & PP_AD_STATE_RUN) {
@@ -3173,6 +3303,7 @@
 			ad->bl_bright_shift = 0;
 			ad->ad_data = 0;
 			ad->ad_data_mode = 0;
+			ad->last_bl = 0;
 			ad->calc_itr = 0;
 			memset(&ad->bl_lin, 0, sizeof(uint32_t) *
 								AD_BL_LIN_LEN);
@@ -3180,10 +3311,11 @@
 								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;
-			mfd->ext_bl_ctrl = 0;
-			mutex_unlock(&mfd->bl_lock);
+			mutex_lock(&bl_mfd->bl_lock);
+			bl_mfd->mdp.update_ad_input = NULL;
+			bl_mfd->ext_bl_ctrl = 0;
+			bl_mfd->ext_ad_ctrl = -1;
+			mutex_unlock(&bl_mfd->bl_lock);
 		}
 		ad->state &= ~PP_AD_STATE_RUN;
 	}
@@ -3218,18 +3350,24 @@
 {
 	struct mdss_ad_info *ad;
 	struct mdss_mdp_ctl *ctl;
-	struct msm_fb_data_type *mfd;
+	struct msm_fb_data_type *mfd, *bl_mfd;
 	u32 bl, calc_done = 0;
 	ad = container_of(work, struct mdss_ad_info, calc_work);
 
 	mutex_lock(&ad->lock);
-	if (!ad->mfd || !(ad->sts & PP_STS_ENABLE)) {
+	if (!ad->mfd  || !ad->bl_mfd || !(ad->sts & PP_STS_ENABLE)) {
 		mutex_unlock(&ad->lock);
 		return;
 	}
 	mfd = ad->mfd;
+	bl_mfd = ad->bl_mfd;
 	ctl = mfd_to_ctl(ad->mfd);
 
+	if ((ad->cfg.mode == MDSS_AD_MODE_AUTO_STR) && (ad->last_bl == 0)) {
+		mutex_unlock(&ad->lock);
+		return;
+	}
+
 	if (PP_AD_STATE_RUN & ad->state) {
 		/* Kick off calculation */
 		ad->calc_itr--;
@@ -3257,9 +3395,10 @@
 				}
 				pr_debug("calc bl = %d", bl);
 				ad->last_str |= bl << 16;
-				mutex_lock(&ad->mfd->bl_lock);
-				mdss_fb_set_backlight(ad->mfd, bl);
-				mutex_unlock(&ad->mfd->bl_lock);
+				mutex_lock(&ad->bl_mfd->bl_lock);
+				if (ad->bl_mfd->bl_level)
+					mdss_fb_set_backlight(ad->bl_mfd, bl);
+				mutex_unlock(&ad->bl_mfd->bl_lock);
 			}
 			pr_debug("calc_str = %d, calc_itr %d",
 							ad->last_str & 0xFF,
@@ -3280,7 +3419,7 @@
 	mutex_unlock(&mfd->lock);
 
 	/* Trigger update notify to wake up those waiting for display updates */
-	mdss_fb_update_notify_update(mfd);
+	mdss_fb_update_notify_update(bl_mfd);
 }
 
 #define PP_AD_LUT_LEN 33
@@ -3318,8 +3457,10 @@
 		mdata->ad_cfgs[i].num = i;
 		mdata->ad_cfgs[i].calc_itr = 0;
 		mdata->ad_cfgs[i].last_str = 0xFFFFFFFF;
+		mdata->ad_cfgs[i].last_bl = 0;
 		mutex_init(&mdata->ad_cfgs[i].lock);
 		mdata->ad_cfgs[i].handle.vsync_handler = pp_ad_vsync_handler;
+		mdata->ad_cfgs[i].handle.cmd_post_flush = true;
 		INIT_WORK(&mdata->ad_cfgs[i].calc_work, pp_ad_calc_worker);
 	}
 	return rc;
@@ -3376,7 +3517,7 @@
 				ret = 1;
 		else if (ptr >= 0x3220 && ptr <= 0x3228)
 				ret = 1;
-		else if (ptr >= 0x3200 || ptr == 0x100)
+		else if (ptr == 0x3200 || ptr == 0x100)
 				ret = 1;
 		else if (ptr == 0x104 || ptr == 0x614 || ptr == 0x714 ||
 			ptr == 0x814 || ptr == 0x914 || ptr == 0xa14)
diff --git a/drivers/video/msm/mdss/mdss_mdp_wb.c b/drivers/video/msm/mdss/mdss_mdp_wb.c
index 72288c2..a9f3e35 100644
--- a/drivers/video/msm/mdss/mdss_mdp_wb.c
+++ b/drivers/video/msm/mdss/mdss_mdp_wb.c
@@ -675,7 +675,8 @@
 		break;
 	case MSMFB_WRITEBACK_QUEUE_BUFFER:
 		if (!copy_from_user(&data, arg, sizeof(data))) {
-			ret = mdss_mdp_wb_queue(mfd, arg, false);
+			ret = mdss_mdp_wb_queue(mfd, &data, false);
+			ret = copy_to_user(arg, &data, sizeof(data));
 		} else {
 			pr_err("wb queue buf failed on copy_from_user\n");
 			ret = -EFAULT;
@@ -683,7 +684,8 @@
 		break;
 	case MSMFB_WRITEBACK_DEQUEUE_BUFFER:
 		if (!copy_from_user(&data, arg, sizeof(data))) {
-			ret = mdss_mdp_wb_dequeue(mfd, arg);
+			ret = mdss_mdp_wb_dequeue(mfd, &data);
+			ret = copy_to_user(arg, &data, sizeof(data));
 		} else {
 			pr_err("wb dequeue buf failed on copy_from_user\n");
 			ret = -EFAULT;
diff --git a/drivers/video/msm/mdss/mdss_panel.h b/drivers/video/msm/mdss/mdss_panel.h
index 833bf14..d05ca66 100644
--- a/drivers/video/msm/mdss/mdss_panel.h
+++ b/drivers/video/msm/mdss/mdss_panel.h
@@ -64,11 +64,16 @@
 	MDSS_PANEL_INTF_HDMI,
 };
 
+enum {
+	MODE_GPIO_NOT_VALID = 0,
+	MODE_GPIO_HIGH,
+	MODE_GPIO_LOW,
+};
+
 #define MDSS_MAX_PANEL_LEN      256
 #define MDSS_INTF_MAX_NAME_LEN 5
 struct mdss_panel_intf {
 	char name[MDSS_INTF_MAX_NAME_LEN];
-	u8   len;
 	int  type;
 };
 
@@ -155,9 +160,9 @@
 	uint32_t timing[12];
 	uint32_t ctrl[4];
 	uint32_t strength[2];
-	char bistCtrl[6];
+	char bistctrl[6];
 	uint32_t pll[21];
-	char laneCfg[45];
+	char lanecfg[45];
 };
 
 struct mipi_panel_info {
@@ -180,7 +185,7 @@
 	char t_clk_post; /* 0xc0, DSI_CLKOUT_TIMING_CTRL */
 	char t_clk_pre;  /* 0xc0, DSI_CLKOUT_TIMING_CTRL */
 	char vc;	/* virtual channel */
-	struct mdss_dsi_phy_ctrl *dsi_phy_db;
+	struct mdss_dsi_phy_ctrl dsi_phy_db;
 	/* video mode */
 	char pulse_mode_hsa_he;
 	char hfp_power_stop;
@@ -263,6 +268,7 @@
 	int pwm_pmic_gpio;
 	int pwm_lpg_chan;
 	int pwm_period;
+	u32 mode_gpio_state;
 
 	u32 cont_splash_enabled;
 	struct ion_handle *splash_ihdl;
diff --git a/drivers/video/msm/mdss/msm_mdss_io_8974.c b/drivers/video/msm/mdss/msm_mdss_io_8974.c
index 7b89eff..d24daab 100644
--- a/drivers/video/msm/mdss/msm_mdss_io_8974.c
+++ b/drivers/video/msm/mdss/msm_mdss_io_8974.c
@@ -504,7 +504,7 @@
 		return;
 	}
 
-	pd = ((ctrl_pdata->panel_data).panel_info.mipi).dsi_phy_db;
+	pd = &(((ctrl_pdata->panel_data).panel_info.mipi).dsi_phy_db);
 
 	/* Strength ctrl 0 */
 	MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x0484, pd->strength[0]);
@@ -564,7 +564,7 @@
 		for (i = 0; i < 9; i++) {
 			offset = i + (ln * 9);
 			MIPI_OUTP((ctrl_pdata->ctrl_base) + off,
-							pd->laneCfg[offset]);
+							pd->lanecfg[offset]);
 			wmb();
 			off += 4;
 		}
@@ -583,7 +583,7 @@
 
 	off = 0x04b4;	/* phy BIST ctrl 0 - 5 */
 	for (i = 0; i < 6; i++) {
-		MIPI_OUTP((ctrl_pdata->ctrl_base) + off, pd->bistCtrl[i]);
+		MIPI_OUTP((ctrl_pdata->ctrl_base) + off, pd->bistctrl[i]);
 		wmb();
 		off += 4;
 	}
diff --git a/include/linux/input/synaptics_dsx.h b/include/linux/input/synaptics_dsx.h
index 5df022e..6716ce3 100644
--- a/include/linux/input/synaptics_dsx.h
+++ b/include/linux/input/synaptics_dsx.h
@@ -43,6 +43,15 @@
  * @reset_gpio: reset gpio
  * @panel_x: panel maximum values on the x
  * @panel_y: panel maximum values on the y
+ * @disp_maxx: display panel maximum values on the x
+ * @disp_maxy: display panel maximum values on the y
+ * @disp_minx: display panel minimum values on the x
+ * @disp_miny: display panel minimum values on the y
+ * @panel_maxx: touch panel maximum values on the x
+ * @panel_maxy: touch panel maximum values on the y
+ * @panel_minx: touch panel minimum values on the x
+ * @panel_miny: touch panel minimum values on the y
+ * @reset_delay: reset delay
  * @gpio_config: pointer to gpio configuration function
  * @capacitance_button_map: pointer to 0d button map
  */
@@ -52,12 +61,20 @@
 	bool i2c_pull_up;
 	bool power_down_enable;
 	bool disable_gpios;
+	bool do_lockdown;
 	unsigned irq_gpio;
 	u32 irq_flags;
 	u32 reset_flags;
 	unsigned reset_gpio;
-	unsigned panel_x;
-	unsigned panel_y;
+	unsigned panel_minx;
+	unsigned panel_miny;
+	unsigned panel_maxx;
+	unsigned panel_maxy;
+	unsigned disp_minx;
+	unsigned disp_miny;
+	unsigned disp_maxx;
+	unsigned disp_maxy;
+	unsigned reset_delay;
 	const char *fw_image_name;
 	int (*gpio_config)(unsigned gpio, bool configure);
 	struct synaptics_rmi4_capacitance_button_map *capacitance_button_map;
diff --git a/include/linux/msm_audio_acdb.h b/include/linux/msm_audio_acdb.h
index e8ca1cd..853899e 100644
--- a/include/linux/msm_audio_acdb.h
+++ b/include/linux/msm_audio_acdb.h
@@ -63,6 +63,10 @@
 			(AUDIO_MAX_COMMON_IOCTL_NUM+28), unsigned)
 #define AUDIO_DEREGISTER_VOCPROC_VOL_TABLE	_IOW(AUDIO_IOCTL_MAGIC, \
 			(AUDIO_MAX_COMMON_IOCTL_NUM+29), unsigned)
+#define AUDIO_SET_HW_DELAY_RX	_IOW(AUDIO_IOCTL_MAGIC, \
+			(AUDIO_MAX_COMMON_IOCTL_NUM+30), struct hw_delay)
+#define AUDIO_SET_HW_DELAY_TX	_IOW(AUDIO_IOCTL_MAGIC, \
+			(AUDIO_MAX_COMMON_IOCTL_NUM+31), struct hw_delay)
 #define	AUDIO_MAX_ACDB_IOCTL	(AUDIO_MAX_COMMON_IOCTL_NUM+40)
 
 /* ACDB structures */
@@ -96,6 +100,11 @@
 	int status;
 };
 
+struct hw_delay {
+	uint32_t num_entries;
+	void *delay_info;
+};
+
 /* For Real-Time Audio Calibration */
 #define AUDIO_GET_RTAC_ADM_INFO		_IOR(AUDIO_IOCTL_MAGIC, \
 			(AUDIO_MAX_ACDB_IOCTL+1), unsigned)
diff --git a/include/linux/qpnp/qpnp-adc.h b/include/linux/qpnp/qpnp-adc.h
index 13bef66..6e711c2 100644
--- a/include/linux/qpnp/qpnp-adc.h
+++ b/include/linux/qpnp/qpnp-adc.h
@@ -615,6 +615,21 @@
 	QPNP_ADC_TM_CH_SELECT_NONE
 };
 
+/**
+ * Channel index for the corresponding index to qpnp_adc_tm_channel_selec
+ */
+enum qpnp_adc_tm_channel_num {
+	QPNP_ADC_TM_CHAN0 = 0,
+	QPNP_ADC_TM_CHAN1,
+	QPNP_ADC_TM_CHAN2,
+	QPNP_ADC_TM_CHAN3,
+	QPNP_ADC_TM_CHAN4,
+	QPNP_ADC_TM_CHAN5,
+	QPNP_ADC_TM_CHAN6,
+	QPNP_ADC_TM_CHAN7,
+	QPNP_ADC_TM_CHAN_NONE
+};
+
 enum qpnp_comp_scheme_type {
 	COMP_ID_GF = 0,
 	COMP_ID_SMIC,
diff --git a/include/linux/security.h b/include/linux/security.h
index 673afbb..b62f396 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -1381,6 +1381,11 @@
 struct security_operations {
 	char name[SECURITY_NAME_MAX + 1];
 
+	int (*binder_set_context_mgr) (struct task_struct *mgr);
+	int (*binder_transaction) (struct task_struct *from, struct task_struct *to);
+	int (*binder_transfer_binder) (struct task_struct *from, struct task_struct *to);
+	int (*binder_transfer_file) (struct task_struct *from, struct task_struct *to, struct file *file);
+
 	int (*ptrace_access_check) (struct task_struct *child, unsigned int mode);
 	int (*ptrace_traceme) (struct task_struct *parent);
 	int (*capget) (struct task_struct *target,
@@ -1664,6 +1669,10 @@
 
 
 /* Security operations */
+int security_binder_set_context_mgr(struct task_struct *mgr);
+int security_binder_transaction(struct task_struct *from, struct task_struct *to);
+int security_binder_transfer_binder(struct task_struct *from, struct task_struct *to);
+int security_binder_transfer_file(struct task_struct *from, struct task_struct *to, struct file *file);
 int security_ptrace_access_check(struct task_struct *child, unsigned int mode);
 int security_ptrace_traceme(struct task_struct *parent);
 int security_capget(struct task_struct *target,
@@ -1842,6 +1851,26 @@
 	return 0;
 }
 
+static inline int security_binder_set_context_mgr(struct task_struct *mgr)
+{
+	return 0;
+}
+
+static inline int security_binder_transaction(struct task_struct *from, struct task_struct *to)
+{
+	return 0;
+}
+
+static inline int security_binder_transfer_binder(struct task_struct *from, struct task_struct *to)
+{
+	return 0;
+}
+
+static inline int security_binder_transfer_file(struct task_struct *from, struct task_struct *to, struct file *file)
+{
+	return 0;
+}
+
 static inline int security_ptrace_access_check(struct task_struct *child,
 					     unsigned int mode)
 {
diff --git a/include/linux/tty.h b/include/linux/tty.h
index 6fcafa8..6a0259d 100644
--- a/include/linux/tty.h
+++ b/include/linux/tty.h
@@ -282,10 +282,8 @@
 	struct winsize winsize;		/* termios mutex */
 	unsigned char stopped:1, hw_stopped:1, flow_stopped:1, packet:1;
 	unsigned char low_latency:1, warned:1;
-	unsigned char update_room_in_ldisc:1;
 	unsigned char ctrl_status;	/* ctrl_lock */
 	unsigned int receive_room;	/* Bytes free for queue */
-	unsigned int rr_bug;
 
 	struct tty_struct *link;
 	struct fasync_struct *fasync;
diff --git a/include/linux/usb/android.h b/include/linux/usb/android.h
index 0b11fdaf..e17e978 100644
--- a/include/linux/usb/android.h
+++ b/include/linux/usb/android.h
@@ -24,6 +24,7 @@
 	u32 swfi_latency;
 	u8 usb_core_id;
 	bool cdrom;
+	bool internal_ums;
 };
 
 #ifndef CONFIG_TARGET_CORE
diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
index 38877cc..e1c096b 100644
--- a/include/linux/videodev2.h
+++ b/include/linux/videodev2.h
@@ -403,6 +403,7 @@
 #define V4L2_PIX_FMT_DIVX      v4l2_fourcc('D', 'I', 'V', 'X') /* DIVX        */
 #define V4L2_PIX_FMT_VP8 v4l2_fourcc('V', 'P', '8', '0') /* ON2 VP8 stream */
 #define V4L2_PIX_FMT_HEVC v4l2_fourcc('H', 'E', 'V', 'C') /* for HEVC stream */
+#define V4L2_PIX_FMT_HEVC_HYBRID v4l2_fourcc('H', 'V', 'C', 'H')
 
 /*  Vendor-specific formats   */
 #define V4L2_PIX_FMT_CPIA1    v4l2_fourcc('C', 'P', 'I', 'A') /* cpia1 YUV */
@@ -705,6 +706,7 @@
 #define V4L2_QCOM_BUF_DATA_CORRUPT 0x80000
 #define V4L2_QCOM_BUF_DROP_FRAME 0x100000
 #define V4L2_QCOM_BUF_INPUT_UNSUPPORTED 0x200000
+#define V4L2_QCOM_BUF_FLAG_EOS          0x2000
 
 /*
  *	O V E R L A Y   P R E V I E W
diff --git a/include/linux/vmalloc.h b/include/linux/vmalloc.h
index 6071e91..663bc05 100644
--- a/include/linux/vmalloc.h
+++ b/include/linux/vmalloc.h
@@ -134,6 +134,7 @@
 extern struct vm_struct *vmlist;
 extern __init void vm_area_add_early(struct vm_struct *vm);
 extern __init void vm_area_register_early(struct vm_struct *vm, size_t align);
+extern __init int vm_area_check_early(struct vm_struct *vm);
 
 #ifdef CONFIG_SMP
 # ifdef CONFIG_MMU
diff --git a/include/sound/apr_audio-v2.h b/include/sound/apr_audio-v2.h
index fb58d12..bbda72e 100644
--- a/include/sound/apr_audio-v2.h
+++ b/include/sound/apr_audio-v2.h
@@ -1968,6 +1968,14 @@
 	 */
 } __packed;
 
+#define AFE_PARAM_ID_DEVICE_HW_DELAY     0x00010243
+#define AFE_API_VERSION_DEVICE_HW_DELAY  0x1
+
+struct afe_param_id_device_hw_delay_cfg {
+	uint32_t    device_hw_delay_minor_version;
+	uint32_t    delay_in_us;
+} __packed;
+
 union afe_port_config {
 	struct afe_param_id_pcm_cfg               pcm;
 	struct afe_param_id_i2s_cfg               i2s;
@@ -1976,6 +1984,7 @@
 	struct afe_param_id_rt_proxy_port_cfg     rtproxy;
 	struct afe_param_id_internal_bt_fm_cfg    int_bt_fm;
 	struct afe_param_id_pseudo_port_cfg       pseudo_port;
+	struct afe_param_id_device_hw_delay_cfg   hw_delay;
 } __packed;
 
 struct afe_audioif_config_command_no_payload {
@@ -2481,6 +2490,8 @@
 
 #define ASM_STREAM_POSTPROC_TOPO_ID_DEFAULT 0x00010BE4
 
+#define ASM_STREAM_POSTPROC_TOPO_ID_NONE 0x00010C68
+
 #define ASM_MEDIA_FMT_EVRCB_FS 0x00010BEF
 
 #define ASM_MEDIA_FMT_EVRCWB_FS 0x00010BF0
@@ -4298,7 +4309,6 @@
 struct asm_aac_dual_mono_mapping_param {
 	struct apr_hdr							hdr;
 	struct asm_stream_cmd_set_encdec_param	encdec;
-	struct asm_enc_cfg_blk_param_v2			encblk;
 	u16    left_channel_sce;
 	u16    right_channel_sce;
 
diff --git a/include/sound/q6afe-v2.h b/include/sound/q6afe-v2.h
index 594d750..3fc85b2 100644
--- a/include/sound/q6afe-v2.h
+++ b/include/sound/q6afe-v2.h
@@ -92,7 +92,8 @@
 	MAD_HW_NONE = 0x00,
 	MAD_HW_AUDIO = 0x01,
 	MAD_HW_BEACON = 0x02,
-	MAD_HW_ULTRASOUND = 0x04
+	MAD_HW_ULTRASOUND = 0x04,
+	MAD_SW_AUDIO = 0x05,
 };
 
 struct afe_audio_buffer {
diff --git a/kernel/smp.c b/kernel/smp.c
index 2f8b10e..3cbd828 100644
--- a/kernel/smp.c
+++ b/kernel/smp.c
@@ -310,20 +310,20 @@
 	 */
 	this_cpu = get_cpu();
 
-	/*
-	 * Can deadlock when called with interrupts disabled.
-	 * We allow cpu's that are not yet online though, as no one else can
-	 * send smp call function interrupt to this cpu and as such deadlocks
-	 * can't happen.
-	 */
-	WARN_ON_ONCE(cpu_online(this_cpu) && irqs_disabled()
-		     && !oops_in_progress);
-
 	if (cpu == this_cpu) {
 		local_irq_save(flags);
 		func(info);
 		local_irq_restore(flags);
 	} else {
+		/*
+		 * Can deadlock when called with interrupts disabled.
+		 * We allow cpu's that are not yet online though, as no one else
+		 * can send smp call function interrupt to this cpu and as such
+		 * deadlocks can't happen.
+		 */
+		WARN_ON_ONCE(cpu_online(this_cpu) && irqs_disabled()
+			     && !oops_in_progress);
+
 		if ((unsigned)cpu < nr_cpu_ids && cpu_online(cpu)) {
 			struct call_single_data *data = &d;
 
@@ -408,20 +408,21 @@
 	unsigned long flags;
 
 	this_cpu = get_cpu();
-	/*
-	 * Can deadlock when called with interrupts disabled.
-	 * We allow cpu's that are not yet online though, as no one else can
-	 * send smp call function interrupt to this cpu and as such deadlocks
-	 * can't happen.
-	 */
-	WARN_ON_ONCE(cpu_online(smp_processor_id()) && wait && irqs_disabled()
-		     && !oops_in_progress);
 
 	if (cpu == this_cpu) {
 		local_irq_save(flags);
 		data->func(data->info);
 		local_irq_restore(flags);
 	} else {
+		/*
+		 * Can deadlock when called with interrupts disabled.
+		 * We allow cpu's that are not yet online though, as no one else
+		 * can send smp call function interrupt to this cpu and as such
+		 * deadlocks can't happen.
+		 */
+		WARN_ON_ONCE(cpu_online(smp_processor_id()) && wait
+			     && irqs_disabled() && !oops_in_progress);
+
 		csd_lock(data);
 		generic_exec_single(cpu, data, wait);
 	}
diff --git a/kernel/watchdog.c b/kernel/watchdog.c
index df30ee0..818920f 100644
--- a/kernel/watchdog.c
+++ b/kernel/watchdog.c
@@ -127,7 +127,7 @@
 /* Commands for resetting the watchdog */
 static void __touch_watchdog(void)
 {
-	int this_cpu = smp_processor_id();
+	int this_cpu = raw_smp_processor_id();
 
 	__this_cpu_write(watchdog_touch_ts, get_timestamp(this_cpu));
 }
diff --git a/mm/bootmem.c b/mm/bootmem.c
index 0131170..3db5820 100644
--- a/mm/bootmem.c
+++ b/mm/bootmem.c
@@ -154,7 +154,7 @@
  * down, but we are still initializing the system.  Pages are given directly
  * to the page allocator, no bootmem metadata is updated because it is gone.
  */
-void __init free_bootmem_late(unsigned long addr, unsigned long size)
+void free_bootmem_late(unsigned long addr, unsigned long size)
 {
 	unsigned long cursor, end;
 
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 9cc2f45..46ccd2f 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -745,7 +745,7 @@
 	local_irq_restore(flags);
 }
 
-void __meminit __free_pages_bootmem(struct page *page, unsigned int order)
+void __free_pages_bootmem(struct page *page, unsigned int order)
 {
 	unsigned int nr_pages = 1 << order;
 	unsigned int loop;
diff --git a/mm/vmalloc.c b/mm/vmalloc.c
index 5065adb..a2ab2ab 100644
--- a/mm/vmalloc.c
+++ b/mm/vmalloc.c
@@ -1116,7 +1116,31 @@
 	return mem;
 }
 EXPORT_SYMBOL(vm_map_ram);
+/**
+ * vm_area_check_early - check if vmap area is already mapped
+ * @vm: vm_struct to be checked
+ *
+ * This function is used to check if the vmap area has been
+ * mapped already. @vm->addr, @vm->size and @vm->flags should
+ * contain proper values.
+ *
+ */
+int __init vm_area_check_early(struct vm_struct *vm)
+{
+	struct vm_struct *tmp, **p;
 
+	BUG_ON(vmap_initialized);
+	for (p = &vmlist; (tmp = *p) != NULL; p = &tmp->next) {
+		if (tmp->addr >= vm->addr) {
+			if (tmp->addr < vm->addr + vm->size)
+				return 1;
+		} else {
+			if (tmp->addr + tmp->size > vm->addr)
+				return 1;
+		}
+	}
+	return 0;
+}
 /**
  * vm_area_add_early - add vmap area early during boot
  * @vm: vm_struct to add
@@ -1392,15 +1416,26 @@
  */
 struct vm_struct *get_vm_area(unsigned long size, unsigned long flags)
 {
+#ifdef CONFIG_ENABLE_VMALLOC_SAVING
+	return __get_vm_area_node(size, 1, flags, PAGE_OFFSET, VMALLOC_END,
+				-1, GFP_KERNEL, __builtin_return_address(0));
+#else
 	return __get_vm_area_node(size, 1, flags, VMALLOC_START, VMALLOC_END,
 				-1, GFP_KERNEL, __builtin_return_address(0));
+#endif
+
 }
 
 struct vm_struct *get_vm_area_caller(unsigned long size, unsigned long flags,
 				const void *caller)
 {
-	return __get_vm_area_node(size, 1, flags, VMALLOC_START, VMALLOC_END,
+#ifdef CONFIG_ENABLE_VMALLOC_SAVING
+	return __get_vm_area_node(size, 1, flags, PAGE_OFFSET, VMALLOC_END,
 						-1, GFP_KERNEL, caller);
+#else
+	return __get_vm_area_node(size, 1, flags, VMALLOC_START, VMALLOC_END,
+				-1, GFP_KERNEL, __builtin_return_address(0));
+#endif
 }
 
 /**
diff --git a/security/capability.c b/security/capability.c
index 5bb21b1..fc991bc 100644
--- a/security/capability.c
+++ b/security/capability.c
@@ -12,6 +12,26 @@
 
 #include <linux/security.h>
 
+static int cap_binder_set_context_mgr(struct task_struct *mgr)
+{
+	return 0;
+}
+
+static int cap_binder_transaction(struct task_struct *from, struct task_struct *to)
+{
+	return 0;
+}
+
+static int cap_binder_transfer_binder(struct task_struct *from, struct task_struct *to)
+{
+	return 0;
+}
+
+static int cap_binder_transfer_file(struct task_struct *from, struct task_struct *to, struct file *file)
+{
+	return 0;
+}
+
 static int cap_syslog(int type)
 {
 	return 0;
@@ -877,6 +897,10 @@
 
 void __init security_fixup_ops(struct security_operations *ops)
 {
+	set_to_cap_if_null(ops, binder_set_context_mgr);
+	set_to_cap_if_null(ops, binder_transaction);
+	set_to_cap_if_null(ops, binder_transfer_binder);
+	set_to_cap_if_null(ops, binder_transfer_file);
 	set_to_cap_if_null(ops, ptrace_access_check);
 	set_to_cap_if_null(ops, ptrace_traceme);
 	set_to_cap_if_null(ops, capget);
diff --git a/security/security.c b/security/security.c
index bf619ff..cecd55e 100644
--- a/security/security.c
+++ b/security/security.c
@@ -130,6 +130,26 @@
 
 /* Security operations */
 
+int security_binder_set_context_mgr(struct task_struct *mgr)
+{
+	return security_ops->binder_set_context_mgr(mgr);
+}
+
+int security_binder_transaction(struct task_struct *from, struct task_struct *to)
+{
+	return security_ops->binder_transaction(from, to);
+}
+
+int security_binder_transfer_binder(struct task_struct *from, struct task_struct *to)
+{
+	return security_ops->binder_transfer_binder(from, to);
+}
+
+int security_binder_transfer_file(struct task_struct *from, struct task_struct *to, struct file *file)
+{
+	return security_ops->binder_transfer_file(from, to, file);
+}
+
 int security_ptrace_access_check(struct task_struct *child, unsigned int mode)
 {
 	return security_ops->ptrace_access_check(child, mode);
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index d85b793..b28b7eb 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -1818,6 +1818,67 @@
 
 /* Hook functions begin here. */
 
+static int selinux_binder_set_context_mgr(struct task_struct *mgr)
+{
+	u32 mysid = current_sid();
+	u32 mgrsid = task_sid(mgr);
+
+	return avc_has_perm(mysid, mgrsid, SECCLASS_BINDER, BINDER__SET_CONTEXT_MGR, NULL);
+}
+
+static int selinux_binder_transaction(struct task_struct *from, struct task_struct *to)
+{
+	u32 mysid = current_sid();
+	u32 fromsid = task_sid(from);
+	u32 tosid = task_sid(to);
+	int rc;
+
+	if (mysid != fromsid) {
+		rc = avc_has_perm(mysid, fromsid, SECCLASS_BINDER, BINDER__IMPERSONATE, NULL);
+		if (rc)
+			return rc;
+	}
+
+	return avc_has_perm(fromsid, tosid, SECCLASS_BINDER, BINDER__CALL, NULL);
+}
+
+static int selinux_binder_transfer_binder(struct task_struct *from, struct task_struct *to)
+{
+	u32 fromsid = task_sid(from);
+	u32 tosid = task_sid(to);
+	return avc_has_perm(fromsid, tosid, SECCLASS_BINDER, BINDER__TRANSFER, NULL);
+}
+
+static int selinux_binder_transfer_file(struct task_struct *from, struct task_struct *to, struct file *file)
+{
+	u32 sid = task_sid(to);
+	struct file_security_struct *fsec = file->f_security;
+	struct inode *inode = file->f_path.dentry->d_inode;
+	struct inode_security_struct *isec = inode->i_security;
+	struct common_audit_data ad;
+	struct selinux_audit_data sad = {0,};
+	int rc;
+
+	COMMON_AUDIT_DATA_INIT(&ad, PATH);
+	ad.u.path = file->f_path;
+	ad.selinux_audit_data = &sad;
+
+	if (sid != fsec->sid) {
+		rc = avc_has_perm(sid, fsec->sid,
+				  SECCLASS_FD,
+				  FD__USE,
+				  &ad);
+		if (rc)
+			return rc;
+	}
+
+	if (unlikely(IS_PRIVATE(inode)))
+		return 0;
+
+	return avc_has_perm(sid, isec->sid, isec->sclass, file_to_av(file),
+			    &ad);
+}
+
 static int selinux_ptrace_access_check(struct task_struct *child,
 				     unsigned int mode)
 {
@@ -5523,6 +5584,11 @@
 static struct security_operations selinux_ops = {
 	.name =				"selinux",
 
+	.binder_set_context_mgr =	selinux_binder_set_context_mgr,
+	.binder_transaction =		selinux_binder_transaction,
+	.binder_transfer_binder =	selinux_binder_transfer_binder,
+	.binder_transfer_file =		selinux_binder_transfer_file,
+
 	.ptrace_access_check =		selinux_ptrace_access_check,
 	.ptrace_traceme =		selinux_ptrace_traceme,
 	.capget =			selinux_capget,
diff --git a/security/selinux/include/classmap.h b/security/selinux/include/classmap.h
index b8c5372..4a4a9ae 100644
--- a/security/selinux/include/classmap.h
+++ b/security/selinux/include/classmap.h
@@ -149,5 +149,6 @@
 	{ "kernel_service", { "use_as_override", "create_files_as", NULL } },
 	{ "tun_socket",
 	  { COMMON_SOCK_PERMS, NULL } },
+	{ "binder", { "impersonate", "call", "set_context_mgr", "transfer", NULL } },
 	{ NULL }
   };
diff --git a/sound/soc/codecs/msm8x10-wcd.c b/sound/soc/codecs/msm8x10-wcd.c
index bd4f926..4e3df21 100644
--- a/sound/soc/codecs/msm8x10-wcd.c
+++ b/sound/soc/codecs/msm8x10-wcd.c
@@ -1136,9 +1136,6 @@
 			  MSM8X10_WCD_A_CDC_IIR1_GAIN_B4_CTL,
 			  -84,	40, digital_gain),
 
-	SOC_SINGLE("MICBIAS1 CAPLESS Switch",
-		   MSM8X10_WCD_A_MICB_1_CTL, 4, 1, 1),
-
 	SOC_ENUM("TX1 HPF cut off", cf_dec1_enum),
 	SOC_ENUM("TX2 HPF cut off", cf_dec2_enum),
 
@@ -1431,13 +1428,8 @@
 		snd_soc_update_bits(codec,
 				    MSM8X10_WCD_A_CDC_ANA_CLK_CTL,
 				    0x20, 0x20);
-	} else {
+	} else
 		wcd8x10->adc_count--;
-		if (!wcd8x10->adc_count)
-			snd_soc_update_bits(codec,
-					    MSM8X10_WCD_A_CDC_ANA_CLK_CTL,
-					    0x20, 0x0);
-	}
 }
 
 static int msm8x10_wcd_codec_enable_adc(struct snd_soc_dapm_widget *w,
@@ -1577,15 +1569,20 @@
 	struct snd_kcontrol *kcontrol, int event)
 {
 	struct snd_soc_codec *codec = w->codec;
+	struct msm8x10_wcd_priv *msm8x10_wcd = snd_soc_codec_get_drvdata(codec);
 	u16 micb_int_reg;
 	char *internal1_text = "Internal1";
 	char *internal2_text = "Internal2";
 	char *internal3_text = "Internal3";
+	enum wcd9xxx_notify_event e_post_off, e_pre_on, e_post_on;
 
 	dev_dbg(codec->dev, "%s %d\n", __func__, event);
 	switch (w->reg) {
 	case MSM8X10_WCD_A_MICB_1_CTL:
 		micb_int_reg = MSM8X10_WCD_A_MICB_1_INT_RBIAS;
+		e_pre_on = WCD9XXX_EVENT_PRE_MICBIAS_1_ON;
+		e_post_on = WCD9XXX_EVENT_POST_MICBIAS_1_ON;
+		e_post_off = WCD9XXX_EVENT_POST_MICBIAS_1_OFF;
 		break;
 	default:
 		dev_err(codec->dev,
@@ -1596,17 +1593,28 @@
 
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
+		/* Let MBHC module know micbias is about to turn ON */
+		wcd9xxx_resmgr_notifier_call(&msm8x10_wcd->resmgr, e_pre_on);
+
 		if (strnstr(w->name, internal1_text, 30))
 			snd_soc_update_bits(codec, micb_int_reg, 0x80, 0x80);
 		else if (strnstr(w->name, internal2_text, 30))
 			snd_soc_update_bits(codec, micb_int_reg, 0x10, 0x10);
 		else if (strnstr(w->name, internal3_text, 30))
 			snd_soc_update_bits(codec, micb_int_reg, 0x2, 0x2);
+
+		/* Always pull up TxFe for TX2 to Micbias */
+		snd_soc_update_bits(codec, micb_int_reg, 0x04, 0x04);
 		break;
 	case SND_SOC_DAPM_POST_PMU:
 		usleep_range(20000, 20100);
+		/* Let MBHC module know so micbias is on */
+		wcd9xxx_resmgr_notifier_call(&msm8x10_wcd->resmgr, e_post_on);
 		break;
 	case SND_SOC_DAPM_POST_PMD:
+		/* Let MBHC module know so micbias switch to be off */
+		wcd9xxx_resmgr_notifier_call(&msm8x10_wcd->resmgr, e_post_off);
+
 		if (strnstr(w->name, internal1_text, 30))
 			snd_soc_update_bits(codec, micb_int_reg, 0x80, 0x00);
 		else if (strnstr(w->name, internal2_text, 30))
@@ -1614,6 +1622,8 @@
 		else if (strnstr(w->name, internal3_text, 30))
 			snd_soc_update_bits(codec, micb_int_reg, 0x2, 0x0);
 
+		/* Disable pull up TxFe for TX2 to Micbias */
+		snd_soc_update_bits(codec, micb_int_reg, 0x04, 0x00);
 		break;
 	}
 	return 0;
@@ -1910,6 +1920,13 @@
 	{"EAR PA", NULL, "DAC1"},
 	{"DAC1", NULL, "CP"},
 
+	/* Clocks for playback path */
+	{"DAC1", NULL, "EAR CLK"},
+	{"HPHL DAC", NULL, "HPHL CLK"},
+	{"HPHR DAC", NULL, "HPHR CLK"},
+	{"SPK DAC", NULL, "SPK CLK"},
+	{"LINEOUT DAC", NULL, "LINEOUT CLK"},
+
 	/* Headset (RX MIX1 and RX MIX2) */
 	{"HEADPHONE", NULL, "HPHL"},
 	{"HEADPHONE", NULL, "HPHR"},
@@ -2336,6 +2353,17 @@
 	SND_SOC_DAPM_MIXER("RX3 CHAIN", MSM8X10_WCD_A_CDC_RX3_B6_CTL,
 		5, 0, NULL, 0),
 
+	SND_SOC_DAPM_SUPPLY("HPHR CLK", MSM8X10_WCD_A_CDC_ANA_CLK_CTL,
+		0, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("HPHL CLK", MSM8X10_WCD_A_CDC_ANA_CLK_CTL,
+		1, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("EAR CLK", MSM8X10_WCD_A_CDC_ANA_CLK_CTL,
+		2, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("LINEOUT CLK", MSM8X10_WCD_A_CDC_ANA_CLK_CTL,
+		3, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("SPK CLK", MSM8X10_WCD_A_CDC_ANA_CLK_CTL,
+		4, 0, NULL, 0),
+
 	SND_SOC_DAPM_MUX("RX1 MIX1 INP1", SND_SOC_NOPM, 0, 0,
 		&rx_mix1_inp1_mux),
 	SND_SOC_DAPM_MUX("RX1 MIX1 INP2", SND_SOC_NOPM, 0, 0,
@@ -2629,6 +2657,48 @@
 	snd_soc_update_bits(codec, MSM8X10_WCD_A_CDC_TOP_CLK_CTL, 0x10, 0x10);
 }
 
+static void msm8x10_wcd_mbhc_txfe(struct snd_soc_codec *codec, bool on)
+{
+	snd_soc_update_bits(codec, MSM8X10_WCD_A_TX_7_MBHC_EN_ATEST_CTRL,
+			    0x80, on ? 0x80 : 0x00);
+}
+
+static int msm8x10_wcd_enable_ext_mb_source(struct snd_soc_codec *codec,
+	bool turn_on)
+{
+	int ret = 0;
+
+	if (turn_on)
+		ret = snd_soc_dapm_force_enable_pin(&codec->dapm,
+				"MICBIAS_REGULATOR");
+	else
+		ret = snd_soc_dapm_disable_pin(&codec->dapm,
+				"MICBIAS_REGULATOR");
+
+	snd_soc_dapm_sync(&codec->dapm);
+
+	if (ret)
+		dev_err(codec->dev, "%s: Failed to %s external micbias source\n",
+			__func__, turn_on ? "enable" : "disabled");
+	else
+		dev_dbg(codec->dev, "%s: %s external micbias source\n",
+			 __func__, turn_on ? "Enabled" : "Disabled");
+
+	return ret;
+}
+
+static void msm8x10_wcd_micb_internal(struct snd_soc_codec *codec, bool on)
+{
+	snd_soc_update_bits(codec, MSM8X10_WCD_A_MICB_1_INT_RBIAS,
+			    0x1C, on ? 0x14 : 0x00);
+}
+
+static void msm8x10_wcd_enable_mb_vddio(struct snd_soc_codec *codec, bool on)
+{
+	snd_soc_update_bits(codec, MSM8X10_WCD_A_MICB_CFILT_1_CTL,
+			    0x40, on ? 0x40 : 0x00);
+}
+
 static const struct wcd9xxx_mbhc_cb mbhc_cb = {
 	.enable_mux_bias_block = msm8x10_wcd_enable_mux_bias_block,
 	.cfilt_fast_mode = msm8x10_wcd_put_cfilt_fast_mode,
@@ -2639,6 +2709,10 @@
 	.free_irq = msm8x10_wcd_free_irq,
 	.get_cdc_type = msm8x10_wcd_get_cdc_type,
 	.enable_clock_gate = msm8x10_wcd_mbhc_clk_gate,
+	.enable_mbhc_txfe = msm8x10_wcd_mbhc_txfe,
+	.enable_mb_source = msm8x10_wcd_enable_ext_mb_source,
+	.setup_int_rbias = msm8x10_wcd_micb_internal,
+	.pull_mb_to_vddio = msm8x10_wcd_enable_mb_vddio,
 };
 
 static void delayed_hs_detect_fn(struct work_struct *work)
@@ -2748,6 +2822,7 @@
 	struct msm8x10_wcd *msm8x10_wcd;
 	struct wcd9xxx_core_resource *core_res;
 	int i, ret = 0;
+	struct msm8x10_wcd_pdata *pdata;
 
 	dev_dbg(codec->dev, "%s()\n", __func__);
 
@@ -2793,6 +2868,17 @@
 	msm8x10_wcd_bringup(codec);
 	msm8x10_wcd_codec_init_reg(codec);
 	msm8x10_wcd_update_reg_defaults(codec);
+
+	pdata = dev_get_platdata(msm8x10_wcd->dev);
+	if (!pdata) {
+		dev_err(msm8x10_wcd->dev, "%s: platform data not found\n",
+			__func__);
+	}
+
+	/* update micbias capless mode */
+	snd_soc_update_bits(codec, MSM8X10_WCD_A_MICB_1_CTL, 0x10,
+			    pdata->micbias.bias1_cap_mode << 4);
+
 	msm8x10_wcd_priv->on_demand_list[ON_DEMAND_CP].supply =
 				wcd8x10_wcd_codec_find_regulator(
 				codec->control_data,
diff --git a/sound/soc/codecs/wcd9306.c b/sound/soc/codecs/wcd9306.c
index c509b08..4e07d7f 100644
--- a/sound/soc/codecs/wcd9306.c
+++ b/sound/soc/codecs/wcd9306.c
@@ -45,6 +45,15 @@
 #define TAPAN_VDD_CX_OPTIMAL_UA 10000
 #define TAPAN_VDD_CX_SLEEP_UA 2000
 
+/* RX_HPH_CNP_WG_TIME increases by 0.24ms */
+#define TAPAN_WG_TIME_FACTOR_US  240
+
+#define TAPAN_SB_PGD_PORT_RX_BASE   0x40
+#define TAPAN_SB_PGD_PORT_TX_BASE   0x50
+#define TAPAN_REGISTER_START_OFFSET 0x800
+
+#define CODEC_REG_CFG_MINOR_VER 1
+
 static struct regulator *tapan_codec_find_regulator(
 	struct snd_soc_codec *codec,
 	const char *name);
@@ -97,6 +106,60 @@
 
 static enum tapan_codec_type codec_ver;
 
+/*
+ * Multiplication factor to compute impedance on Tapan
+ * This is computed from (Vx / (m*Ical)) = (10mV/(180*30uA))
+ */
+#define TAPAN_ZDET_MUL_FACTOR 1852
+
+static struct afe_param_cdc_reg_cfg audio_reg_cfg[] = {
+	{
+		CODEC_REG_CFG_MINOR_VER,
+		(TAPAN_REGISTER_START_OFFSET + TAPAN_SB_PGD_PORT_TX_BASE),
+		SB_PGD_PORT_TX_WATERMARK_N, 0x1E, 8, 0x1
+	},
+	{
+		CODEC_REG_CFG_MINOR_VER,
+		(TAPAN_REGISTER_START_OFFSET + TAPAN_SB_PGD_PORT_TX_BASE),
+		SB_PGD_PORT_TX_ENABLE_N, 0x1, 8, 0x1
+	},
+	{
+		CODEC_REG_CFG_MINOR_VER,
+		(TAPAN_REGISTER_START_OFFSET + TAPAN_SB_PGD_PORT_RX_BASE),
+		SB_PGD_PORT_RX_WATERMARK_N, 0x1E, 8, 0x1
+	},
+	{
+		CODEC_REG_CFG_MINOR_VER,
+		(TAPAN_REGISTER_START_OFFSET + TAPAN_SB_PGD_PORT_RX_BASE),
+		SB_PGD_PORT_RX_ENABLE_N, 0x1, 8, 0x1
+	},
+	{
+		CODEC_REG_CFG_MINOR_VER,
+		(TAPAN_REGISTER_START_OFFSET + TAPAN_A_CDC_ANC1_IIR_B1_CTL),
+		AANC_FF_GAIN_ADAPTIVE, 0x4, 8, 0
+	},
+	{
+		CODEC_REG_CFG_MINOR_VER,
+		(TAPAN_REGISTER_START_OFFSET + TAPAN_A_CDC_ANC1_IIR_B1_CTL),
+		AANC_FFGAIN_ADAPTIVE_EN, 0x8, 8, 0
+	},
+	{
+		CODEC_REG_CFG_MINOR_VER,
+		(TAPAN_REGISTER_START_OFFSET + TAPAN_A_CDC_ANC1_GAIN_CTL),
+		AANC_GAIN_CONTROL, 0xFF, 8, 0
+	},
+};
+
+static struct afe_param_cdc_reg_cfg_data tapan_audio_reg_cfg = {
+	.num_registers = ARRAY_SIZE(audio_reg_cfg),
+	.reg_data = audio_reg_cfg,
+};
+
+static struct afe_param_id_cdc_aanc_version tapan_cdc_aanc_version = {
+	.cdc_aanc_minor_version = AFE_API_VERSION_CDC_AANC_VERSION,
+	.aanc_hw_version        = AANC_HW_BLOCK_VERSION_2,
+};
+
 enum {
 	AIF1_PB = 0,
 	AIF1_CAP,
@@ -241,6 +304,8 @@
 
 	bool spkr_pa_widget_on;
 
+	struct afe_param_cdc_slimbus_slave_cfg slimbus_slave_cfg;
+
 	/* resmgr module */
 	struct wcd9xxx_resmgr resmgr;
 	/* mbhc module */
@@ -251,6 +316,15 @@
 
 	/* pointers to regulators required for chargepump */
 	struct regulator *cp_regulators[CP_REG_MAX];
+
+	/*
+	 * list used to save/restore registers at start and
+	 * end of impedance measurement
+	 */
+	struct list_head reg_save_restore;
+
+	int (*machine_codec_event_cb)(struct snd_soc_codec *codec,
+					enum wcd9xxx_codec_event);
 };
 
 static const u32 comp_shift[] = {
@@ -2949,6 +3023,9 @@
 
 static int tapan_volatile(struct snd_soc_codec *ssc, unsigned int reg)
 {
+
+	int i = 0;
+
 	/* Registers lower than 0x100 are top level registers which can be
 	 * written by the Tapan core driver.
 	 */
@@ -2982,6 +3059,11 @@
 	if (reg == TAPAN_A_MBHC_INSERT_DET_STATUS)
 		return 1;
 
+	for (i = 0; i < ARRAY_SIZE(audio_reg_cfg); i++)
+		if (audio_reg_cfg[i].reg_logical_addr -
+			TAPAN_REGISTER_START_OFFSET == reg)
+			return 1;
+
 	return 0;
 }
 
@@ -4807,6 +4889,46 @@
 	{TAPAN_A_RX_HPH_CHOP_CTL, 0xFF, 0x24},
 };
 
+void *tapan_get_afe_config(struct snd_soc_codec *codec,
+			   enum afe_config_type config_type)
+{
+	struct tapan_priv *priv = snd_soc_codec_get_drvdata(codec);
+
+	switch (config_type) {
+	case AFE_SLIMBUS_SLAVE_CONFIG:
+		return &priv->slimbus_slave_cfg;
+	case AFE_CDC_REGISTERS_CONFIG:
+		return &tapan_audio_reg_cfg;
+	case AFE_AANC_VERSION:
+		return &tapan_cdc_aanc_version;
+	default:
+		pr_err("%s: Unknown config_type 0x%x\n", __func__, config_type);
+		return NULL;
+	}
+}
+
+static void tapan_init_slim_slave_cfg(struct snd_soc_codec *codec)
+{
+	struct tapan_priv *priv = snd_soc_codec_get_drvdata(codec);
+	struct afe_param_cdc_slimbus_slave_cfg *cfg;
+	struct wcd9xxx *wcd9xxx = codec->control_data;
+	uint64_t eaddr = 0;
+
+	pr_debug("%s\n", __func__);
+	cfg = &priv->slimbus_slave_cfg;
+	cfg->minor_version = 1;
+	cfg->tx_slave_port_offset = 0;
+	cfg->rx_slave_port_offset = 16;
+
+	memcpy(&eaddr, &wcd9xxx->slim->e_addr, sizeof(wcd9xxx->slim->e_addr));
+	/* e-addr is 6-byte elemental address of the device */
+	WARN_ON(sizeof(wcd9xxx->slim->e_addr) != 6);
+	cfg->device_enum_addr_lsw = eaddr & 0xFFFFFFFF;
+	cfg->device_enum_addr_msw = eaddr >> 32;
+
+	pr_debug("%s: slimbus logical address 0x%llx\n", __func__, eaddr);
+}
+
 static void tapan_codec_init_reg(struct snd_soc_codec *codec)
 {
 	u32 i;
@@ -4917,6 +5039,255 @@
 	return WCD9XXX_CDC_TYPE_TAPAN;
 }
 
+static void wcd9xxx_prepare_hph_pa(struct wcd9xxx_mbhc *mbhc,
+				   struct list_head *lh)
+{
+	int i;
+	struct snd_soc_codec *codec = mbhc->codec;
+	u32 delay;
+
+	const struct wcd9xxx_reg_mask_val reg_set_paon[] = {
+		{WCD9XXX_A_CDC_CLSH_B1_CTL, 0x0F, 0x00},
+		{WCD9XXX_A_RX_HPH_CHOP_CTL, 0xFF, 0xA4},
+		{WCD9XXX_A_RX_HPH_OCP_CTL, 0xFF, 0x67},
+		{WCD9XXX_A_RX_HPH_L_TEST, 0x1, 0x0},
+		{WCD9XXX_A_RX_HPH_R_TEST, 0x1, 0x0},
+		{WCD9XXX_A_RX_HPH_BIAS_WG_OCP, 0xFF, 0x1A},
+		{WCD9XXX_A_RX_HPH_CNP_WG_CTL, 0xFF, 0xDB},
+		{WCD9XXX_A_RX_HPH_CNP_WG_TIME, 0xFF, 0x2A},
+		{TAPAN_A_CDC_CONN_RX2_B2_CTL, 0xFF, 0x10},
+		{WCD9XXX_A_CDC_CLK_OTHR_CTL, 0xFF, 0x05},
+		{WCD9XXX_A_CDC_RX1_B6_CTL, 0xFF, 0x81},
+		{WCD9XXX_A_CDC_CLK_RX_B1_CTL, 0x03, 0x03},
+		{WCD9XXX_A_RX_HPH_L_GAIN, 0xFF, 0x2C},
+		{WCD9XXX_A_CDC_RX2_B6_CTL, 0xFF, 0x81},
+		{WCD9XXX_A_RX_HPH_R_GAIN, 0xFF, 0x2C},
+		{WCD9XXX_A_BUCK_CTRL_CCL_4, 0xFF, 0x50},
+		{WCD9XXX_A_BUCK_CTRL_VCL_1, 0xFF, 0x08},
+		{WCD9XXX_A_BUCK_CTRL_CCL_1, 0xFF, 0x5B},
+		{WCD9XXX_A_NCP_CLK, 0xFF, 0x9C},
+		{WCD9XXX_A_NCP_CLK, 0xFF, 0xFC},
+		{WCD9XXX_A_BUCK_MODE_3, 0xFF, 0xCE},
+		{WCD9XXX_A_BUCK_CTRL_CCL_3, 0xFF, 0x6B},
+		{WCD9XXX_A_BUCK_CTRL_CCL_3, 0xFF, 0x6F},
+		{TAPAN_A_RX_BUCK_BIAS1, 0xFF, 0x62},
+		{TAPAN_A_RX_HPH_BIAS_PA, 0xFF, 0x7A},
+		{TAPAN_A_CDC_CLK_RDAC_CLK_EN_CTL, 0xFF, 0x02},
+		{TAPAN_A_CDC_CLK_RDAC_CLK_EN_CTL, 0xFF, 0x06},
+		{WCD9XXX_A_RX_COM_BIAS, 0xFF, 0x80},
+		{WCD9XXX_A_BUCK_MODE_3, 0xFF, 0xC6},
+		{WCD9XXX_A_BUCK_MODE_4, 0xFF, 0xE6},
+		{WCD9XXX_A_BUCK_MODE_5, 0xFF, 0x02},
+		{WCD9XXX_A_BUCK_MODE_1, 0xFF, 0xA1},
+		/* Delay 1ms */
+		{WCD9XXX_A_NCP_EN, 0xFF, 0xFF},
+		/* Delay 1ms */
+		{WCD9XXX_A_BUCK_MODE_5, 0xFF, 0x03},
+		{WCD9XXX_A_BUCK_MODE_5, 0xFF, 0x7B},
+		{WCD9XXX_A_CDC_CLSH_B1_CTL, 0xFF, 0xE6},
+		{WCD9XXX_A_RX_HPH_L_DAC_CTL, 0xFF, 0x40},
+		{WCD9XXX_A_RX_HPH_L_DAC_CTL, 0xFF, 0xC0},
+		{WCD9XXX_A_RX_HPH_R_DAC_CTL, 0xFF, 0x40},
+		{WCD9XXX_A_RX_HPH_R_DAC_CTL, 0xFF, 0xC0},
+		{WCD9XXX_A_NCP_STATIC, 0xFF, 0x08},
+		{WCD9XXX_A_RX_HPH_L_DAC_CTL, 0x03, 0x01},
+		{WCD9XXX_A_RX_HPH_R_DAC_CTL, 0x03, 0x01},
+	};
+
+	/*
+	 * Configure PA in class-AB, -18dB gain,
+	 * companding off, OCP off, Chopping ON
+	 */
+	for (i = 0; i < ARRAY_SIZE(reg_set_paon); i++) {
+		/*
+		 * Some of the codec registers like BUCK_MODE_1
+		 * and NCP_EN requires 1ms wait time for them
+		 * to take effect. Other register writes for
+		 * PA configuration do not require any wait time.
+		 */
+		if (reg_set_paon[i].reg == WCD9XXX_A_BUCK_MODE_1 ||
+		    reg_set_paon[i].reg == WCD9XXX_A_NCP_EN)
+			delay = 1000;
+		else
+			delay = 0;
+		wcd9xxx_soc_update_bits_push(codec, lh,
+					     reg_set_paon[i].reg,
+					     reg_set_paon[i].mask,
+					     reg_set_paon[i].val, delay);
+	}
+	pr_debug("%s: PAs are prepared\n", __func__);
+	return;
+}
+
+static int wcd9xxx_enable_static_pa(struct wcd9xxx_mbhc *mbhc, bool enable)
+{
+	struct snd_soc_codec *codec = mbhc->codec;
+	int wg_time = snd_soc_read(codec, WCD9XXX_A_RX_HPH_CNP_WG_TIME) *
+				   TAPAN_WG_TIME_FACTOR_US;
+	/*
+	 * Tapan requires additional time to enable PA.
+	 * It is observed during experiments that we need
+	 * an additional wait time about 0.35 times of
+	 * the WG_TIME
+	 */
+	wg_time += (int) (wg_time * 35) / 100;
+
+	snd_soc_update_bits(codec, WCD9XXX_A_RX_HPH_CNP_EN, 0x30,
+			    enable ? 0x30 : 0x0);
+	/* Wait for wave gen time to avoid pop noise */
+	usleep_range(wg_time, wg_time + WCD9XXX_USLEEP_RANGE_MARGIN_US);
+	pr_debug("%s: PAs are %s as static mode (wg_time %d)\n", __func__,
+		 enable ? "enabled" : "disabled", wg_time);
+	return 0;
+}
+
+static int tapan_setup_zdet(struct wcd9xxx_mbhc *mbhc,
+			    enum mbhc_impedance_detect_stages stage)
+{
+
+	int ret = 0;
+	struct snd_soc_codec *codec = mbhc->codec;
+	struct tapan_priv *tapan = snd_soc_codec_get_drvdata(codec);
+	const int mux_wait_us = 25;
+
+	switch (stage) {
+
+	case PRE_MEAS:
+		INIT_LIST_HEAD(&tapan->reg_save_restore);
+		/* Configure PA */
+		wcd9xxx_prepare_hph_pa(mbhc, &tapan->reg_save_restore);
+
+#define __wr(reg, mask, value)						  \
+	do {								  \
+		ret = wcd9xxx_soc_update_bits_push(codec,		  \
+						   &tapan->reg_save_restore, \
+						   reg, mask, value, 0);  \
+		if (ret < 0)						  \
+			return ret;					  \
+	} while (0)
+
+		/* Setup MBHC */
+		__wr(WCD9XXX_A_MBHC_SCALING_MUX_1, 0x7F, 0x40);
+		__wr(WCD9XXX_A_MBHC_SCALING_MUX_2, 0xFF, 0xF0);
+		__wr(WCD9XXX_A_TX_7_MBHC_TEST_CTL, 0xFF, 0x78);
+		__wr(WCD9XXX_A_TX_7_MBHC_EN, 0xFF, 0xEC);
+		__wr(WCD9XXX_A_CDC_MBHC_TIMER_B4_CTL, 0xFF, 0x45);
+		__wr(WCD9XXX_A_CDC_MBHC_TIMER_B5_CTL, 0xFF, 0x80);
+
+		__wr(WCD9XXX_A_CDC_MBHC_CLK_CTL, 0xFF, 0x0A);
+		snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_EN_CTL, 0x2);
+		__wr(WCD9XXX_A_CDC_MBHC_CLK_CTL, 0xFF, 0x02);
+
+		/* Enable Impedance Detection */
+		__wr(WCD9XXX_A_MBHC_HPH, 0xFF, 0xC8);
+
+		/*
+		 * CnP setup for 0mV
+		 * Route static data as input to noise shaper
+		 */
+		__wr(TAPAN_A_CDC_RX1_B3_CTL, 0xFF, 0x02);
+		__wr(TAPAN_A_CDC_RX2_B3_CTL, 0xFF, 0x02);
+
+		snd_soc_update_bits(codec, WCD9XXX_A_RX_HPH_L_TEST,
+				    0x02, 0x00);
+		snd_soc_update_bits(codec, WCD9XXX_A_RX_HPH_R_TEST,
+				    0x02, 0x00);
+
+		/* Reset the HPHL static data pointer */
+		__wr(TAPAN_A_CDC_RX1_B2_CTL, 0xFF, 0x00);
+		/* Four consecutive writes to set 0V as static data input */
+		snd_soc_write(codec, TAPAN_A_CDC_RX1_B1_CTL, 0x00);
+		snd_soc_write(codec, TAPAN_A_CDC_RX1_B1_CTL, 0x00);
+		snd_soc_write(codec, TAPAN_A_CDC_RX1_B1_CTL, 0x00);
+		snd_soc_write(codec, TAPAN_A_CDC_RX1_B1_CTL, 0x00);
+
+		/* Reset the HPHR static data pointer */
+		__wr(TAPAN_A_CDC_RX2_B2_CTL, 0xFF, 0x00);
+		/* Four consecutive writes to set 0V as static data input */
+		snd_soc_write(codec, TAPAN_A_CDC_RX2_B1_CTL, 0x00);
+		snd_soc_write(codec, TAPAN_A_CDC_RX2_B1_CTL, 0x00);
+		snd_soc_write(codec, TAPAN_A_CDC_RX2_B1_CTL, 0x00);
+		snd_soc_write(codec, TAPAN_A_CDC_RX2_B1_CTL, 0x00);
+
+		/* Enable the HPHL and HPHR PA */
+		wcd9xxx_enable_static_pa(mbhc, true);
+		break;
+	case POST_MEAS:
+		/* Turn off ICAL */
+		snd_soc_write(codec, WCD9XXX_A_MBHC_SCALING_MUX_2, 0xF0);
+
+		wcd9xxx_enable_static_pa(mbhc, false);
+
+		/*
+		 * Setup CnP wavegen to ramp to the desired
+		 * output using a 40ms ramp
+		 */
+
+		/* CnP wavegen current to 0.5uA */
+		snd_soc_write(codec, WCD9XXX_A_RX_HPH_BIAS_WG_OCP, 0x1A);
+		/* Set the current division ratio to 2000 */
+		snd_soc_write(codec, WCD9XXX_A_RX_HPH_CNP_WG_CTL, 0xDF);
+		/* Set the wavegen timer to max (60msec) */
+		snd_soc_write(codec, WCD9XXX_A_RX_HPH_CNP_WG_TIME, 0xA0);
+		/* Set the CnP reference current to sc_bias */
+		snd_soc_write(codec, WCD9XXX_A_RX_HPH_OCP_CTL, 0x6D);
+
+		snd_soc_write(codec, TAPAN_A_CDC_RX1_B2_CTL, 0x00);
+		/* Four consecutive writes to set -10mV as static data input */
+		snd_soc_write(codec, TAPAN_A_CDC_RX1_B1_CTL, 0x00);
+		snd_soc_write(codec, TAPAN_A_CDC_RX1_B1_CTL, 0x1F);
+		snd_soc_write(codec, TAPAN_A_CDC_RX1_B1_CTL, 0x19);
+		snd_soc_write(codec, TAPAN_A_CDC_RX1_B1_CTL, 0xAA);
+
+		snd_soc_write(codec, TAPAN_A_CDC_RX2_B2_CTL, 0x00);
+		/* Four consecutive writes to set -10mV as static data input */
+		snd_soc_write(codec, TAPAN_A_CDC_RX2_B1_CTL, 0x00);
+		snd_soc_write(codec, TAPAN_A_CDC_RX2_B1_CTL, 0x1F);
+		snd_soc_write(codec, TAPAN_A_CDC_RX2_B1_CTL, 0x19);
+		snd_soc_write(codec, TAPAN_A_CDC_RX2_B1_CTL, 0xAA);
+
+		snd_soc_update_bits(codec, WCD9XXX_A_RX_HPH_L_TEST,
+				    0x02, 0x02);
+		snd_soc_update_bits(codec, WCD9XXX_A_RX_HPH_R_TEST,
+				    0x02, 0x02);
+		/* Enable the HPHL and HPHR PA and wait for 60mS */
+		wcd9xxx_enable_static_pa(mbhc, true);
+
+		snd_soc_update_bits(codec, WCD9XXX_A_MBHC_SCALING_MUX_1,
+				    0x7F, 0x40);
+		usleep_range(mux_wait_us,
+				mux_wait_us + WCD9XXX_USLEEP_RANGE_MARGIN_US);
+		break;
+	case PA_DISABLE:
+		wcd9xxx_enable_static_pa(mbhc, false);
+		wcd9xxx_restore_registers(codec, &tapan->reg_save_restore);
+		break;
+	}
+#undef __wr
+
+	return ret;
+}
+
+static void tapan_compute_impedance(s16 *l, s16 *r, uint32_t *zl, uint32_t *zr)
+{
+	int zln, zld;
+	int zrn, zrd;
+	int rl = 0, rr = 0;
+
+	zln = (l[1] - l[0]) * TAPAN_ZDET_MUL_FACTOR;
+	zld = (l[2] - l[0]);
+	if (zld)
+		rl = zln / zld;
+
+	zrn = (r[1] - r[0]) * TAPAN_ZDET_MUL_FACTOR;
+	zrd = (r[2] - r[0]);
+	if (zrd)
+		rr = zrn / zrd;
+
+	*zl = rl;
+	*zr = rr;
+}
+
 static const struct wcd9xxx_mbhc_cb mbhc_cb = {
 	.enable_mux_bias_block = tapan_enable_mux_bias_block,
 	.cfilt_fast_mode = tapan_put_cfilt_fast_mode,
@@ -4926,6 +5297,8 @@
 	.select_cfilt = tapan_select_cfilt,
 	.free_irq = tapan_free_irq,
 	.get_cdc_type = tapan_get_cdc_type,
+	.setup_zdet = tapan_setup_zdet,
+	.compute_impedance = tapan_compute_impedance,
 };
 
 int tapan_hs_detect(struct snd_soc_codec *codec,
@@ -4943,6 +5316,16 @@
 }
 EXPORT_SYMBOL(tapan_hs_detect_exit);
 
+void tapan_event_register(
+	int (*machine_event_cb)(struct snd_soc_codec *codec,
+				enum wcd9xxx_codec_event),
+	struct snd_soc_codec *codec)
+{
+	struct tapan_priv *tapan = snd_soc_codec_get_drvdata(codec);
+	tapan->machine_codec_event_cb = machine_event_cb;
+}
+EXPORT_SYMBOL(tapan_event_register);
+
 static int tapan_device_down(struct wcd9xxx *wcd9xxx)
 {
 	struct snd_soc_codec *codec;
@@ -5000,7 +5383,8 @@
 		rco_clk_rate = TAPAN_MCLK_CLK_9P6MHZ;
 
 	ret = wcd9xxx_mbhc_init(&tapan->mbhc, &tapan->resmgr, codec, NULL,
-				&mbhc_cb, rco_clk_rate, false);
+				&mbhc_cb, rco_clk_rate,
+				TAPAN_CDC_ZDET_SUPPORTED);
 	if (ret)
 		pr_err("%s: mbhc init failed %d\n", __func__, ret);
 	else
@@ -5011,6 +5395,8 @@
 	if (ret)
 		pr_err("%s: Failed to setup irq: %d\n", __func__, ret);
 
+	tapan->machine_codec_event_cb(codec, WCD9XXX_CODEC_EVENT_CODEC_UP);
+
 	mutex_unlock(&codec->mutex);
 	return ret;
 }
@@ -5203,7 +5589,8 @@
 		rco_clk_rate = TAPAN_MCLK_CLK_9P6MHZ;
 
 	ret = wcd9xxx_mbhc_init(&tapan->mbhc, &tapan->resmgr, codec, NULL,
-				&mbhc_cb, rco_clk_rate, false);
+				&mbhc_cb, rco_clk_rate,
+				TAPAN_CDC_ZDET_SUPPORTED);
 
 	if (ret) {
 		pr_err("%s: mbhc init failed %d\n", __func__, ret);
@@ -5255,6 +5642,7 @@
 			INIT_LIST_HEAD(&tapan->dai[i].wcd9xxx_ch_list);
 			init_waitqueue_head(&tapan->dai[i].dai_wait);
 		}
+		tapan_init_slim_slave_cfg(codec);
 	}
 
 	if (codec_ver == WCD9306) {
diff --git a/sound/soc/codecs/wcd9306.h b/sound/soc/codecs/wcd9306.h
index fdd62d1..07b2175 100644
--- a/sound/soc/codecs/wcd9306.h
+++ b/sound/soc/codecs/wcd9306.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
@@ -14,9 +14,11 @@
 
 #include <sound/soc.h>
 #include <sound/jack.h>
+#include <sound/apr_audio-v2.h>
 #include <linux/mfd/wcd9xxx/wcd9xxx-slimslave.h>
 #include "wcd9xxx-mbhc.h"
 #include "wcd9xxx-resmgr.h"
+#include "wcd9xxx-common.h"
 
 #define TAPAN_NUM_REGISTERS 0x400
 #define TAPAN_MAX_REGISTER (TAPAN_NUM_REGISTERS-1)
@@ -24,6 +26,8 @@
 
 #define TAPAN_REG_VAL(reg, val)		{reg, 0, val}
 
+#define TAPAN_CDC_ZDET_SUPPORTED  true
+
 extern const u8 tapan_reg_readable[TAPAN_CACHE_SIZE];
 extern const u8 tapan_reset_reg_defaults[TAPAN_CACHE_SIZE];
 struct tapan_codec_dai_data {
@@ -75,5 +79,10 @@
 			     bool dapm);
 extern int tapan_hs_detect(struct snd_soc_codec *codec,
 			   struct wcd9xxx_mbhc_config *mbhc_cfg);
-
+extern void *tapan_get_afe_config(struct snd_soc_codec *codec,
+				  enum afe_config_type config_type);
+extern void tapan_event_register(
+	int (*machine_event_cb)(struct snd_soc_codec *codec,
+				 enum wcd9xxx_codec_event),
+	struct snd_soc_codec *codec);
 #endif
diff --git a/sound/soc/codecs/wcd9320.c b/sound/soc/codecs/wcd9320.c
index 3621879..4ce9b4a 100644
--- a/sound/soc/codecs/wcd9320.c
+++ b/sound/soc/codecs/wcd9320.c
@@ -49,6 +49,9 @@
 
 #define DAPM_MICBIAS2_EXTERNAL_STANDALONE "MIC BIAS2 External Standalone"
 
+/* RX_HPH_CNP_WG_TIME increases by 0.24ms */
+#define TAIKO_WG_TIME_FACTOR_US	240
+
 static atomic_t kp_taiko_priv;
 static int spkr_drv_wrnd_param_set(const char *val,
 				   const struct kernel_param *kp);
@@ -69,63 +72,6 @@
 	.num_channels = 1
 };
 
-enum {
-	RESERVED = 0,
-	AANC_LPF_FF_FB = 1,
-	AANC_LPF_COEFF_MSB,
-	AANC_LPF_COEFF_LSB,
-	HW_MAD_AUDIO_ENABLE,
-	HW_MAD_ULTR_ENABLE,
-	HW_MAD_BEACON_ENABLE,
-	HW_MAD_AUDIO_SLEEP_TIME,
-	HW_MAD_ULTR_SLEEP_TIME,
-	HW_MAD_BEACON_SLEEP_TIME,
-	HW_MAD_TX_AUDIO_SWITCH_OFF,
-	HW_MAD_TX_ULTR_SWITCH_OFF,
-	HW_MAD_TX_BEACON_SWITCH_OFF,
-	MAD_AUDIO_INT_DEST_SELECT_REG,
-	MAD_ULT_INT_DEST_SELECT_REG,
-	MAD_BEACON_INT_DEST_SELECT_REG,
-	MAD_CLIP_INT_DEST_SELECT_REG,
-	MAD_VBAT_INT_DEST_SELECT_REG,
-	MAD_AUDIO_INT_MASK_REG,
-	MAD_ULT_INT_MASK_REG,
-	MAD_BEACON_INT_MASK_REG,
-	MAD_CLIP_INT_MASK_REG,
-	MAD_VBAT_INT_MASK_REG,
-	MAD_AUDIO_INT_STATUS_REG,
-	MAD_ULT_INT_STATUS_REG,
-	MAD_BEACON_INT_STATUS_REG,
-	MAD_CLIP_INT_STATUS_REG,
-	MAD_VBAT_INT_STATUS_REG,
-	MAD_AUDIO_INT_CLEAR_REG,
-	MAD_ULT_INT_CLEAR_REG,
-	MAD_BEACON_INT_CLEAR_REG,
-	MAD_CLIP_INT_CLEAR_REG,
-	MAD_VBAT_INT_CLEAR_REG,
-	SB_PGD_PORT_TX_WATERMARK_n,
-	SB_PGD_PORT_TX_ENABLE_n,
-	SB_PGD_PORT_RX_WATERMARK_n,
-	SB_PGD_PORT_RX_ENABLE_n,
-	SB_PGD_TX_PORTn_MULTI_CHNL_0,
-	SB_PGD_TX_PORTn_MULTI_CHNL_1,
-	SB_PGD_RX_PORTn_MULTI_CHNL_0,
-	SB_PGD_RX_PORTn_MULTI_CHNL_1,
-	AANC_FF_GAIN_ADAPTIVE,
-	AANC_FFGAIN_ADAPTIVE_EN,
-	AANC_GAIN_CONTROL,
-	SPKR_CLIP_PIPE_BANK_SEL,
-	SPKR_CLIPDET_VAL0,
-	SPKR_CLIPDET_VAL1,
-	SPKR_CLIPDET_VAL2,
-	SPKR_CLIPDET_VAL3,
-	SPKR_CLIPDET_VAL4,
-	SPKR_CLIPDET_VAL5,
-	SPKR_CLIPDET_VAL6,
-	SPKR_CLIPDET_VAL7,
-	MAX_CFG_REGISTERS,
-};
-
 static struct afe_param_cdc_reg_cfg audio_reg_cfg[] = {
 	{
 		1,
@@ -165,22 +111,22 @@
 	{
 		1,
 		(TAIKO_REGISTER_START_OFFSET + TAIKO_SB_PGD_PORT_TX_BASE),
-		SB_PGD_PORT_TX_WATERMARK_n, 0x1E, 8, 0x1
+		SB_PGD_PORT_TX_WATERMARK_N, 0x1E, 8, 0x1
 	},
 	{
 		1,
 		(TAIKO_REGISTER_START_OFFSET + TAIKO_SB_PGD_PORT_TX_BASE),
-		SB_PGD_PORT_TX_ENABLE_n, 0x1, 8, 0x1
+		SB_PGD_PORT_TX_ENABLE_N, 0x1, 8, 0x1
 	},
 	{
 		1,
 		(TAIKO_REGISTER_START_OFFSET + TAIKO_SB_PGD_PORT_RX_BASE),
-		SB_PGD_PORT_RX_WATERMARK_n, 0x1E, 8, 0x1
+		SB_PGD_PORT_RX_WATERMARK_N, 0x1E, 8, 0x1
 	},
 	{
 		1,
 		(TAIKO_REGISTER_START_OFFSET + TAIKO_SB_PGD_PORT_RX_BASE),
-		SB_PGD_PORT_RX_ENABLE_n, 0x1, 8, 0x1
+		SB_PGD_PORT_RX_ENABLE_N, 0x1, 8, 0x1
 	},
 	{	1,
 		(TAIKO_REGISTER_START_OFFSET + TAIKO_A_CDC_ANC1_IIR_B1_CTL),
@@ -509,6 +455,12 @@
 
 	int (*machine_codec_event_cb)(struct snd_soc_codec *codec,
 			enum wcd9xxx_codec_event);
+
+	/*
+	 * list used to save/restore registers at start and
+	 * end of impedance measurement
+	 */
+	struct list_head reg_save_restore;
 };
 
 static const u32 comp_shift[] = {
@@ -6239,6 +6191,198 @@
 	return 0;
 }
 
+static int wcd9xxx_prepare_static_pa(struct wcd9xxx_mbhc *mbhc,
+				     struct list_head *lh)
+{
+	int i;
+	struct snd_soc_codec *codec = mbhc->codec;
+
+	const struct wcd9xxx_reg_mask_val reg_set_paon[] = {
+		{WCD9XXX_A_RX_HPH_OCP_CTL, 0x18, 0x00},
+		{WCD9XXX_A_RX_HPH_L_TEST, 0x1, 0x0},
+		{WCD9XXX_A_RX_HPH_R_TEST, 0x1, 0x0},
+		{WCD9XXX_A_RX_HPH_BIAS_WG_OCP, 0xff, 0x1A},
+		{WCD9XXX_A_RX_HPH_CNP_WG_CTL, 0xff, 0xDB},
+		{WCD9XXX_A_RX_HPH_CNP_WG_TIME, 0xff, 0x15},
+		{WCD9XXX_A_CDC_RX1_B6_CTL, 0xff, 0x81},
+		{WCD9XXX_A_CDC_CLK_RX_B1_CTL, 0x01, 0x01},
+		{WCD9XXX_A_RX_HPH_CHOP_CTL, 0xff, 0xA4},
+		{WCD9XXX_A_RX_HPH_L_GAIN, 0xff, 0x2C},
+		{WCD9XXX_A_CDC_RX2_B6_CTL, 0xff, 0x81},
+		{WCD9XXX_A_CDC_CLK_RX_B1_CTL, 0x02, 0x02},
+		{WCD9XXX_A_RX_HPH_R_GAIN, 0xff, 0x2C},
+		{WCD9XXX_A_NCP_CLK, 0xff, 0xFC},
+		{WCD9XXX_A_BUCK_CTRL_CCL_3, 0xff, 0x60},
+		{WCD9XXX_A_RX_COM_BIAS, 0xff, 0x80},
+		{WCD9XXX_A_BUCK_MODE_3, 0xff, 0xC6},
+		{WCD9XXX_A_BUCK_MODE_4, 0xff, 0xE6},
+		{WCD9XXX_A_BUCK_MODE_5, 0xff, 0x02},
+		{WCD9XXX_A_BUCK_MODE_1, 0xff, 0xA1},
+		{WCD9XXX_A_NCP_EN, 0xff, 0xFF},
+		{WCD9XXX_A_BUCK_MODE_5, 0xff, 0x7B},
+		{WCD9XXX_A_CDC_CLSH_B1_CTL, 0xff, 0xE6},
+		{WCD9XXX_A_RX_HPH_L_DAC_CTL, 0xff, 0xC0},
+		{WCD9XXX_A_RX_HPH_R_DAC_CTL, 0xff, 0xC0},
+	};
+
+	for (i = 0; i < ARRAY_SIZE(reg_set_paon); i++)
+		wcd9xxx_soc_update_bits_push(codec, lh,
+					     reg_set_paon[i].reg,
+					     reg_set_paon[i].mask,
+					     reg_set_paon[i].val, 0);
+	pr_debug("%s: PAs are prepared\n", __func__);
+
+	return 0;
+}
+
+static int wcd9xxx_enable_static_pa(struct wcd9xxx_mbhc *mbhc, bool enable)
+{
+	struct snd_soc_codec *codec = mbhc->codec;
+	const int wg_time = snd_soc_read(codec, WCD9XXX_A_RX_HPH_CNP_WG_TIME) *
+			    TAIKO_WG_TIME_FACTOR_US;
+
+	snd_soc_update_bits(codec, WCD9XXX_A_RX_HPH_CNP_EN, 0x30,
+			    enable ? 0x30 : 0x0);
+	/* Wait for wave gen time to avoid pop noise */
+	usleep_range(wg_time, wg_time + WCD9XXX_USLEEP_RANGE_MARGIN_US);
+	pr_debug("%s: PAs are %s as static mode (wg_time %d)\n", __func__,
+		 enable ? "enabled" : "disabled", wg_time);
+	return 0;
+}
+
+static int taiko_setup_zdet(struct wcd9xxx_mbhc *mbhc,
+			    enum mbhc_impedance_detect_stages stage)
+{
+	int ret = 0;
+	struct snd_soc_codec *codec = mbhc->codec;
+	struct taiko_priv *taiko = snd_soc_codec_get_drvdata(codec);
+	const int ramp_wait_us = 18 * 1000;
+
+#define __wr(reg, mask, value)						  \
+	do {								  \
+		ret = wcd9xxx_soc_update_bits_push(codec,		  \
+						   &taiko->reg_save_restore, \
+						   reg, mask, value, 0);  \
+		if (ret < 0)						  \
+			return ret;					  \
+	} while (0)
+
+	switch (stage) {
+
+	case PRE_MEAS:
+		INIT_LIST_HEAD(&taiko->reg_save_restore);
+		wcd9xxx_prepare_static_pa(mbhc, &taiko->reg_save_restore);
+		wcd9xxx_enable_static_pa(mbhc, true);
+
+		/*
+		 * save old value of registers and write the new value to
+		 * restore old value back, WCD9XXX_A_CDC_PA_RAMP_B{1,2,3,4}_CTL
+		 * registers don't need to be restored as those are solely used
+		 * by impedance detection.
+		 */
+		/* Phase 1 */
+		/* Reset the PA Ramp */
+		snd_soc_write(codec, WCD9XXX_A_CDC_PA_RAMP_B1_CTL, 0x1C);
+		/*
+		 * Connect the PA Ramp to PA chain and release reset with
+		 * keep it connected.
+		 */
+		snd_soc_write(codec, WCD9XXX_A_CDC_PA_RAMP_B1_CTL, 0x1F);
+		snd_soc_write(codec, WCD9XXX_A_CDC_PA_RAMP_B1_CTL, 0x03);
+		/*
+		 * Program the PA Ramp to FS_48K, L shift 1 and sample
+		 * num to 24
+		 */
+		snd_soc_write(codec, WCD9XXX_A_CDC_PA_RAMP_B3_CTL,
+			      0x3 << 4 | 0x6);
+		/* 0x56 for 10mv.  0xC0 is for 50mv */
+		snd_soc_write(codec, WCD9XXX_A_CDC_PA_RAMP_B4_CTL, 0xC0);
+		/* Enable MBHC MUX, Set MUX current to 37.5uA and ADC7 */
+		__wr(WCD9XXX_A_MBHC_SCALING_MUX_1, 0xFF, 0xC0);
+		__wr(WCD9XXX_A_MBHC_SCALING_MUX_2, 0xFF, 0xF0);
+		__wr(WCD9XXX_A_TX_7_MBHC_TEST_CTL, 0xFF, 0x78);
+		__wr(WCD9XXX_A_TX_7_MBHC_EN, 0xFF, 0x8C);
+		/* Change NSA and NAVG */
+		__wr(WCD9XXX_A_CDC_MBHC_TIMER_B4_CTL, 0x4 << 4, 0x4 << 4);
+		__wr(WCD9XXX_A_CDC_MBHC_TIMER_B5_CTL, 0xFF, 0x10);
+		/* Reset MBHC and set it up for STA */
+		__wr(WCD9XXX_A_CDC_MBHC_CLK_CTL, 0xFF, 0x0A);
+		__wr(WCD9XXX_A_CDC_MBHC_EN_CTL, 0xFF, 0x02);
+		__wr(WCD9XXX_A_CDC_MBHC_CLK_CTL, 0xFF, 0x02);
+
+		/* Set HPH_MBHC for zdet */
+		__wr(WCD9XXX_A_MBHC_HPH, 0xB3, 0x80);
+		break;
+	case POST_MEAS:
+		/* Phase 2 */
+		/* Start the PA ramp on HPH L and R */
+		snd_soc_write(codec, WCD9XXX_A_CDC_PA_RAMP_B2_CTL, 0x05);
+		/* Ramp generator takes ~17ms */
+		usleep_range(ramp_wait_us,
+				ramp_wait_us + WCD9XXX_USLEEP_RANGE_MARGIN_US);
+
+		/* Disable Ical */
+		snd_soc_write(codec, WCD9XXX_A_CDC_PA_RAMP_B2_CTL, 0x00);
+		/* Ramp generator takes ~17ms */
+		usleep_range(ramp_wait_us,
+				ramp_wait_us + WCD9XXX_USLEEP_RANGE_MARGIN_US);
+		break;
+	case PA_DISABLE:
+		/* Ramp HPH L & R back to Zero */
+		snd_soc_write(codec, WCD9XXX_A_CDC_PA_RAMP_B2_CTL, 0x0A);
+		/* Ramp generator takes ~17ms */
+		usleep_range(ramp_wait_us,
+				ramp_wait_us + WCD9XXX_USLEEP_RANGE_MARGIN_US);
+		snd_soc_write(codec, WCD9XXX_A_CDC_PA_RAMP_B2_CTL, 0x00);
+
+		/* Clean up starts */
+		/* Turn off PA ramp generator */
+		snd_soc_write(codec, WCD9XXX_A_CDC_PA_RAMP_B1_CTL, 0x0);
+		wcd9xxx_enable_static_pa(mbhc, false);
+		wcd9xxx_restore_registers(codec, &taiko->reg_save_restore);
+		break;
+	}
+#undef __wr
+
+	return ret;
+}
+
+static void taiko_compute_impedance(s16 *l, s16 *r, uint32_t *zl, uint32_t *zr)
+{
+
+	int64_t rl, rr = 0; /* milliohm */
+	const int alphal = 364; /* 0.005555 * 65536 = 364.05 */
+	const int alphar = 364; /* 0.005555 * 65536 = 364.05 */
+	const int beta = 3855; /* 0.011765 * 5 * 65536 = 3855.15 */
+	const int rref = 11333; /* not scaled up */
+	const int shift = 16;
+
+	rl = (int)(l[0] - l[1]) * 1000 / (l[0] - l[2]);
+	rl = rl * rref * alphal;
+	rl = rl >> shift;
+	rl = rl * beta;
+	rl = rl >> shift;
+	*zl = rl;
+
+	rr = (int)(r[0] - r[1]) * 1000 / (r[0] - r[2]);
+	rr = rr * rref  * alphar;
+	rr = rr >> shift;
+	rr = rr * beta;
+	rr = rr >> shift;
+	*zr = rr;
+}
+
+static enum wcd9xxx_cdc_type taiko_get_cdc_type(void)
+{
+	return WCD9XXX_CDC_TYPE_TAIKO;
+}
+
+static const struct wcd9xxx_mbhc_cb mbhc_cb = {
+	.get_cdc_type = taiko_get_cdc_type,
+	.setup_zdet = taiko_setup_zdet,
+	.compute_impedance = taiko_compute_impedance,
+};
+
 static int taiko_post_reset_cb(struct wcd9xxx *wcd9xxx)
 {
 	int ret = 0;
@@ -6284,7 +6428,7 @@
 
 		ret = wcd9xxx_mbhc_init(&taiko->mbhc, &taiko->resmgr, codec,
 					taiko_enable_mbhc_micbias,
-					NULL, rco_clk_rate, true);
+					&mbhc_cb, rco_clk_rate, true);
 		if (ret)
 			pr_err("%s: mbhc init failed %d\n", __func__, ret);
 		else
@@ -6473,7 +6617,7 @@
 	/* init and start mbhc */
 	ret = wcd9xxx_mbhc_init(&taiko->mbhc, &taiko->resmgr, codec,
 				taiko_enable_mbhc_micbias,
-				NULL, rco_clk_rate, true);
+				&mbhc_cb, rco_clk_rate, true);
 	if (ret) {
 		pr_err("%s: mbhc init failed %d\n", __func__, ret);
 		goto err_init;
diff --git a/sound/soc/codecs/wcd9xxx-common.c b/sound/soc/codecs/wcd9xxx-common.c
index d00b843..05f2191 100644
--- a/sound/soc/codecs/wcd9xxx-common.c
+++ b/sound/soc/codecs/wcd9xxx-common.c
@@ -11,6 +11,7 @@
  */
 
 #include <linux/module.h>
+#include <linux/slab.h>
 #include <sound/soc.h>
 #include <linux/kernel.h>
 #include <linux/delay.h>
@@ -32,6 +33,8 @@
 
 #define MAX_IMPED_PARAMS 13
 
+#define USLEEP_RANGE_MARGIN_US 100
+
 struct wcd9xxx_imped_val {
 	u32 imped_val;
 	u8 index;
@@ -614,6 +617,46 @@
 	}
 }
 
+
+int wcd9xxx_soc_update_bits_push(struct snd_soc_codec *codec,
+					struct list_head *list,
+					uint16_t reg, uint8_t mask,
+					uint8_t value, int delay)
+{
+	int rc;
+	struct wcd9xxx_register_save_node *node;
+
+	node = kmalloc(sizeof(*node), GFP_KERNEL);
+	if (unlikely(!node)) {
+		pr_err("%s: Not enough memory\n", __func__);
+		return -ENOMEM;
+	}
+	node->reg = reg;
+	node->value = snd_soc_read(codec, reg);
+	list_add(&node->lh, list);
+	if (mask == 0xFF)
+		rc = snd_soc_write(codec, reg, value);
+	else
+		rc = snd_soc_update_bits(codec, reg, mask, value);
+	if (delay)
+		usleep_range(delay, delay + USLEEP_RANGE_MARGIN_US);
+	return rc;
+}
+EXPORT_SYMBOL(wcd9xxx_soc_update_bits_push);
+
+void wcd9xxx_restore_registers(struct snd_soc_codec *codec,
+			       struct list_head *lh)
+{
+	struct wcd9xxx_register_save_node *node, *nodetmp;
+
+	list_for_each_entry_safe(node, nodetmp, lh, lh) {
+		snd_soc_write(codec, node->reg, node->value);
+		list_del(&node->lh);
+		kfree(node);
+	}
+}
+EXPORT_SYMBOL(wcd9xxx_restore_registers);
+
 static void wcd9xxx_enable_buck_mode(struct snd_soc_codec *codec,
 		u8 buck_vref)
 {
diff --git a/sound/soc/codecs/wcd9xxx-common.h b/sound/soc/codecs/wcd9xxx-common.h
index 654964e..e63d36a 100644
--- a/sound/soc/codecs/wcd9xxx-common.h
+++ b/sound/soc/codecs/wcd9xxx-common.h
@@ -81,4 +81,73 @@
 	WCD9XXX_CODEC_EVENT_CODEC_UP = 0,
 };
 
+struct wcd9xxx_register_save_node {
+	struct list_head lh;
+	u16 reg;
+	u16 value;
+};
+
+extern int wcd9xxx_soc_update_bits_push(struct snd_soc_codec *codec,
+					struct list_head *lh,
+					uint16_t reg, uint8_t mask,
+					uint8_t value, int delay);
+extern void wcd9xxx_restore_registers(struct snd_soc_codec *codec,
+				      struct list_head *lh);
+enum {
+	RESERVED = 0,
+	AANC_LPF_FF_FB = 1,
+	AANC_LPF_COEFF_MSB,
+	AANC_LPF_COEFF_LSB,
+	HW_MAD_AUDIO_ENABLE,
+	HW_MAD_ULTR_ENABLE,
+	HW_MAD_BEACON_ENABLE,
+	HW_MAD_AUDIO_SLEEP_TIME,
+	HW_MAD_ULTR_SLEEP_TIME,
+	HW_MAD_BEACON_SLEEP_TIME,
+	HW_MAD_TX_AUDIO_SWITCH_OFF,
+	HW_MAD_TX_ULTR_SWITCH_OFF,
+	HW_MAD_TX_BEACON_SWITCH_OFF,
+	MAD_AUDIO_INT_DEST_SELECT_REG,
+	MAD_ULT_INT_DEST_SELECT_REG,
+	MAD_BEACON_INT_DEST_SELECT_REG,
+	MAD_CLIP_INT_DEST_SELECT_REG,
+	MAD_VBAT_INT_DEST_SELECT_REG,
+	MAD_AUDIO_INT_MASK_REG,
+	MAD_ULT_INT_MASK_REG,
+	MAD_BEACON_INT_MASK_REG,
+	MAD_CLIP_INT_MASK_REG,
+	MAD_VBAT_INT_MASK_REG,
+	MAD_AUDIO_INT_STATUS_REG,
+	MAD_ULT_INT_STATUS_REG,
+	MAD_BEACON_INT_STATUS_REG,
+	MAD_CLIP_INT_STATUS_REG,
+	MAD_VBAT_INT_STATUS_REG,
+	MAD_AUDIO_INT_CLEAR_REG,
+	MAD_ULT_INT_CLEAR_REG,
+	MAD_BEACON_INT_CLEAR_REG,
+	MAD_CLIP_INT_CLEAR_REG,
+	MAD_VBAT_INT_CLEAR_REG,
+	SB_PGD_PORT_TX_WATERMARK_N,
+	SB_PGD_PORT_TX_ENABLE_N,
+	SB_PGD_PORT_RX_WATERMARK_N,
+	SB_PGD_PORT_RX_ENABLE_N,
+	SB_PGD_TX_PORTn_MULTI_CHNL_0,
+	SB_PGD_TX_PORTn_MULTI_CHNL_1,
+	SB_PGD_RX_PORTn_MULTI_CHNL_0,
+	SB_PGD_RX_PORTn_MULTI_CHNL_1,
+	AANC_FF_GAIN_ADAPTIVE,
+	AANC_FFGAIN_ADAPTIVE_EN,
+	AANC_GAIN_CONTROL,
+	SPKR_CLIP_PIPE_BANK_SEL,
+	SPKR_CLIPDET_VAL0,
+	SPKR_CLIPDET_VAL1,
+	SPKR_CLIPDET_VAL2,
+	SPKR_CLIPDET_VAL3,
+	SPKR_CLIPDET_VAL4,
+	SPKR_CLIPDET_VAL5,
+	SPKR_CLIPDET_VAL6,
+	SPKR_CLIPDET_VAL7,
+	MAX_CFG_REGISTERS,
+};
+
 #endif
diff --git a/sound/soc/codecs/wcd9xxx-mbhc.c b/sound/soc/codecs/wcd9xxx-mbhc.c
index acb86416..c2d626b 100644
--- a/sound/soc/codecs/wcd9xxx-mbhc.c
+++ b/sound/soc/codecs/wcd9xxx-mbhc.c
@@ -142,12 +142,6 @@
 	enum wcd9xxx_mbhc_plug_type _type;
 };
 
-struct wcd9xxx_register_save_node {
-	struct list_head lh;
-	u16 reg;
-	u16 value;
-};
-
 enum meas_type {
 	STA = 0,
 	DCE,
@@ -182,15 +176,19 @@
 				    uint32_t *zr);
 static s16 wcd9xxx_get_current_v(struct wcd9xxx_mbhc *mbhc,
 				 const enum wcd9xxx_current_v_idx idx);
+static void wcd9xxx_get_z(struct wcd9xxx_mbhc *mbhc, s16 *dce_z, s16 *sta_z);
+static void wcd9xxx_mbhc_calc_thres(struct wcd9xxx_mbhc *mbhc);
 
 static bool wcd9xxx_mbhc_polling(struct wcd9xxx_mbhc *mbhc)
 {
 	return mbhc->polling_active;
 }
 
-static void wcd9xxx_turn_onoff_override(struct snd_soc_codec *codec, bool on)
+static void wcd9xxx_turn_onoff_override(struct wcd9xxx_mbhc *mbhc, bool on)
 {
-	snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_B1_CTL, 0x04, on << 2);
+	struct snd_soc_codec *codec = mbhc->codec;
+	snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_B1_CTL,
+			    0x04, on ? 0x04 : 0x00);
 }
 
 /* called under codec_resource_lock acquisition */
@@ -300,7 +298,7 @@
 		override = snd_soc_read(codec, WCD9XXX_A_CDC_MBHC_B1_CTL) &
 			   0x04;
 		if (!override)
-			wcd9xxx_turn_onoff_override(codec, true);
+			wcd9xxx_turn_onoff_override(mbhc, true);
 		/* Adjust threshold if Mic Bias voltage changes */
 		if (d->micb_mv != VDDIO_MICBIAS_MV) {
 			cfilt_k_val = __wcd9xxx_resmgr_get_k_val(mbhc,
@@ -342,7 +340,7 @@
 		snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.mbhc_reg,
 				    0x10, 0x00);
 		if (!override)
-			wcd9xxx_turn_onoff_override(codec, false);
+			wcd9xxx_turn_onoff_override(mbhc, false);
 		if (restartpolling)
 			wcd9xxx_start_hs_polling(mbhc);
 
@@ -973,6 +971,7 @@
 	if (noreldetection)
 		wcd9xxx_turn_onoff_rel_detection(codec, false);
 
+	snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x2, 0x0);
 	/* Turn on the override */
 	if (!override_bypass)
 		snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_B1_CTL, 0x4, 0x4);
@@ -982,6 +981,8 @@
 		snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_EN_CTL, 0x4);
 		snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x8,
 				    0x0);
+		snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x2,
+				    0x2);
 		usleep_range(mbhc->mbhc_data.t_sta_dce,
 			     mbhc->mbhc_data.t_sta_dce);
 		snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_EN_CTL, 0x4);
@@ -993,6 +994,8 @@
 		snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_EN_CTL, 0x2);
 		snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x8,
 				    0x0);
+		snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x2,
+				    0x2);
 		usleep_range(mbhc->mbhc_data.t_sta_dce,
 			     mbhc->mbhc_data.t_sta_dce);
 		snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_EN_CTL, 0x2);
@@ -1055,6 +1058,10 @@
 	struct snd_soc_codec *codec = mbhc->codec;
 	short bias_value;
 	u8 cfilt_mode;
+	s16 reg;
+	int change;
+	struct wcd9xxx_mbhc_btn_detect_cfg *btn_det;
+	s16 sta_z = 0, dce_z = 0;
 
 	WCD9XXX_BCL_ASSERT_LOCKED(mbhc->resmgr);
 
@@ -1064,6 +1071,11 @@
 		return -ENODEV;
 	}
 
+	btn_det = WCD9XXX_MBHC_CAL_BTN_DET_PTR(mbhc->mbhc_cfg->calibration);
+	/* Enable external voltage source to micbias if present */
+	if (mbhc->mbhc_cb && mbhc->mbhc_cb->enable_mb_source)
+		mbhc->mbhc_cb->enable_mb_source(codec, true);
+
 	/*
 	 * Request BG and clock.
 	 * These will be released by wcd9xxx_cleanup_hs_polling
@@ -1102,14 +1114,48 @@
 	snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_B1_CTL, 0x2, 0x2);
 	snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
 
-	if (!is_cs_enable)
-		wcd9xxx_calibrate_hs_polling(mbhc);
-
 	/* don't flip override */
 	bias_value = __wcd9xxx_codec_sta_dce(mbhc, 1, true, true);
 	snd_soc_write(codec, mbhc->mbhc_bias_regs.cfilt_ctl, cfilt_mode);
 	snd_soc_update_bits(codec, WCD9XXX_A_MBHC_HPH, 0x13, 0x00);
 
+	/* recalibrate dce_z and sta_z */
+	reg = snd_soc_read(codec, WCD9XXX_A_CDC_MBHC_B1_CTL);
+	change = snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_B1_CTL, 0x78,
+				     btn_det->mbhc_nsc << 3);
+	wcd9xxx_get_z(mbhc, &dce_z, &sta_z);
+	if (change)
+		snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_B1_CTL, reg);
+	if (dce_z && sta_z) {
+		pr_debug("%s: sta_z 0x%x -> 0x%x, dce_z 0x%x -> 0x%x\n",
+			 __func__,
+			 mbhc->mbhc_data.sta_z, sta_z & 0xffff,
+			 mbhc->mbhc_data.dce_z, dce_z & 0xffff);
+		mbhc->mbhc_data.dce_z = dce_z;
+		mbhc->mbhc_data.sta_z = sta_z;
+		wcd9xxx_mbhc_calc_thres(mbhc);
+		wcd9xxx_calibrate_hs_polling(mbhc);
+	} else {
+		pr_warn("%s: failed get new dce_z/sta_z 0x%x/0x%x\n", __func__,
+			dce_z, sta_z);
+	}
+
+	if (is_cs_enable) {
+		/* recalibrate dce_nsc_cs_z */
+		reg = snd_soc_read(mbhc->codec, WCD9XXX_A_CDC_MBHC_B1_CTL);
+		snd_soc_update_bits(mbhc->codec, WCD9XXX_A_CDC_MBHC_B1_CTL,
+				    0x78, WCD9XXX_MBHC_NSC_CS << 3);
+		wcd9xxx_get_z(mbhc, &dce_z, NULL);
+		snd_soc_write(mbhc->codec, WCD9XXX_A_CDC_MBHC_B1_CTL, reg);
+		if (dce_z) {
+			pr_debug("%s: dce_nsc_cs_z 0x%x -> 0x%x\n", __func__,
+				 mbhc->mbhc_data.dce_nsc_cs_z, dce_z & 0xffff);
+			mbhc->mbhc_data.dce_nsc_cs_z = dce_z;
+		} else {
+			pr_debug("%s: failed get new dce_nsc_cs_z\n", __func__);
+		}
+	}
+
 	return bias_value;
 }
 
@@ -1143,6 +1189,8 @@
 
 static void wcd9xxx_cleanup_hs_polling(struct wcd9xxx_mbhc *mbhc)
 {
+
+	pr_debug("%s: enter\n", __func__);
 	WCD9XXX_BCL_ASSERT_LOCKED(mbhc->resmgr);
 
 	wcd9xxx_shutdown_hs_removal_detect(mbhc);
@@ -1153,8 +1201,13 @@
 	wcd9xxx_resmgr_put_bandgap(mbhc->resmgr, WCD9XXX_BANDGAP_MBHC_MODE);
 	WCD9XXX_BG_CLK_UNLOCK(mbhc->resmgr);
 
+	/* Disable external voltage source to micbias if present */
+	if (mbhc->mbhc_cb && mbhc->mbhc_cb->enable_mb_source)
+		mbhc->mbhc_cb->enable_mb_source(mbhc->codec, false);
+
 	mbhc->polling_active = false;
 	mbhc->mbhc_state = MBHC_STATE_NONE;
+	pr_debug("%s: leave\n", __func__);
 }
 
 /* called under codec_resource_lock acquisition */
@@ -1168,6 +1221,12 @@
 static void wcd9xxx_onoff_vddio_switch(struct wcd9xxx_mbhc *mbhc, bool on)
 {
 	pr_debug("%s: vddio %d\n", __func__, on);
+
+	if (mbhc->mbhc_cb && mbhc->mbhc_cb->pull_mb_to_vddio) {
+		mbhc->mbhc_cb->pull_mb_to_vddio(mbhc->codec, on);
+		goto exit;
+	}
+
 	if (on) {
 		snd_soc_update_bits(mbhc->codec, mbhc->mbhc_bias_regs.mbhc_reg,
 				    1 << 7, 1 << 7);
@@ -1179,6 +1238,12 @@
 		snd_soc_update_bits(mbhc->codec, mbhc->mbhc_bias_regs.mbhc_reg,
 				    1 << 7, 0);
 	}
+
+exit:
+	/*
+	 * Wait for the micbias to settle down to vddio
+	 * when the micbias to vddio switch is enabled.
+	 */
 	if (on)
 		usleep_range(10000, 10000);
 }
@@ -1859,7 +1924,7 @@
 					    0);
 	}
 
-	if (mbhc->resmgr->reg_addr->micb_4_mbhc)
+	if (mbhc->resmgr->reg_addr && mbhc->resmgr->reg_addr->micb_4_mbhc)
 		snd_soc_update_bits(codec, mbhc->resmgr->reg_addr->micb_4_mbhc,
 				    0x3, mbhc->mbhc_cfg->micbias);
 
@@ -1947,7 +2012,6 @@
 static void wcd9xxx_mbhc_decide_swch_plug(struct wcd9xxx_mbhc *mbhc)
 {
 	enum wcd9xxx_mbhc_plug_type plug_type;
-	struct snd_soc_codec *codec = mbhc->codec;
 	bool current_source_enable;
 
 	pr_debug("%s: enter\n", __func__);
@@ -1961,9 +2025,9 @@
 		plug_type = wcd9xxx_codec_cs_get_plug_type(mbhc, false);
 		wcd9xxx_turn_onoff_current_source(mbhc, false, false);
 	} else {
-		wcd9xxx_turn_onoff_override(codec, true);
+		wcd9xxx_turn_onoff_override(mbhc, true);
 		plug_type = wcd9xxx_codec_get_plug_type(mbhc, true);
-		wcd9xxx_turn_onoff_override(codec, false);
+		wcd9xxx_turn_onoff_override(mbhc, false);
 	}
 
 	if (wcd9xxx_swch_level_remove(mbhc)) {
@@ -1974,13 +2038,16 @@
 
 	if (plug_type == PLUG_TYPE_INVALID ||
 	    plug_type == PLUG_TYPE_GND_MIC_SWAP) {
+		wcd9xxx_cleanup_hs_polling(mbhc);
 		wcd9xxx_schedule_hs_detect_plug(mbhc,
 						&mbhc->correct_plug_swch);
 	} else if (plug_type == PLUG_TYPE_HEADPHONE) {
 		wcd9xxx_report_plug(mbhc, 1, SND_JACK_HEADPHONE);
+		wcd9xxx_cleanup_hs_polling(mbhc);
 		wcd9xxx_schedule_hs_detect_plug(mbhc,
 						&mbhc->correct_plug_swch);
 	} else if (plug_type == PLUG_TYPE_HIGH_HPH) {
+		wcd9xxx_cleanup_hs_polling(mbhc);
 		wcd9xxx_schedule_hs_detect_plug(mbhc,
 						&mbhc->correct_plug_swch);
 	} else {
@@ -2602,7 +2669,7 @@
 		wcd9xxx_turn_onoff_current_source(mbhc, true,
 						  false);
 	else
-		wcd9xxx_turn_onoff_override(codec, true);
+		wcd9xxx_turn_onoff_override(mbhc, true);
 
 	timeout = jiffies + msecs_to_jiffies(HS_DETECT_PLUG_TIME_MS);
 	while (!time_after(jiffies, timeout)) {
@@ -2687,7 +2754,7 @@
 				wcd9xxx_turn_onoff_current_source(mbhc, false,
 								  false);
 			else
-				wcd9xxx_turn_onoff_override(codec, false);
+				wcd9xxx_turn_onoff_override(mbhc, false);
 			/*
 			 * The valid plug also includes PLUG_TYPE_GND_MIC_SWAP
 			 */
@@ -2713,7 +2780,7 @@
 	if (!correction && current_source_enable)
 		wcd9xxx_turn_onoff_current_source(mbhc, false, highhph);
 	else if (!correction)
-		wcd9xxx_turn_onoff_override(codec, false);
+		wcd9xxx_turn_onoff_override(mbhc, false);
 
 	wcd9xxx_onoff_ext_mclk(mbhc, false);
 
@@ -2812,7 +2879,7 @@
 			snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL,
 					    0x08, 0x00);
 			/* Turn off override */
-			wcd9xxx_turn_onoff_override(codec, false);
+			wcd9xxx_turn_onoff_override(mbhc, false);
 		}
 	}
 
@@ -2946,9 +3013,10 @@
 	return mask;
 }
 
-void wcd9xxx_get_z(struct wcd9xxx_mbhc *mbhc, s16 *dce_z, s16 *sta_z)
+static void wcd9xxx_get_z(struct wcd9xxx_mbhc *mbhc, s16 *dce_z, s16 *sta_z)
 {
 	s16 reg0, reg1;
+	int change;
 	struct snd_soc_codec *codec = mbhc->codec;
 
 	WCD9XXX_BCL_ASSERT_LOCKED(mbhc->resmgr);
@@ -2959,16 +3027,21 @@
 	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);
+	change = 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);
+	if (sta_z)
+		*sta_z = wcd9xxx_codec_sta_dce(mbhc, 0, false);
+	if (dce_z)
+		*dce_z = wcd9xxx_codec_sta_dce(mbhc, 1, false);
 
 	pr_debug("%s: sta_z 0x%x, dce_z 0x%x\n", __func__, *sta_z & 0xFFFF,
 		 *dce_z & 0xFFFF);
 
 	/* Connect override from micbias */
-	snd_soc_update_bits(codec, WCD9XXX_A_MAD_ANA_CTRL, 1 << 4, 1 << 4);
+	if (change)
+		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);
@@ -3396,7 +3469,13 @@
 	 * LDOH and CFILT are already configured during pdata handling.
 	 * Only need to make sure CFILT and bandgap are in Fast mode.
 	 * Need to restore defaults once calculation is done.
+	 *
+	 * In case when Micbias is powered by external source, request
+	 * turn on the external voltage source for Calibration.
 	 */
+	if (mbhc->mbhc_cb && mbhc->mbhc_cb->enable_mb_source)
+		mbhc->mbhc_cb->enable_mb_source(codec, true);
+
 	cfilt_mode = snd_soc_read(codec, mbhc->mbhc_bias_regs.cfilt_ctl);
 	if (mbhc->mbhc_cb && mbhc->mbhc_cb->cfilt_fast_mode)
 		mbhc->mbhc_cb->cfilt_fast_mode(codec, mbhc);
@@ -3516,6 +3595,9 @@
 				    0x80, 0x80);
 	usleep_range(100, 100);
 
+	if (mbhc->mbhc_cb && mbhc->mbhc_cb->enable_mb_source)
+		mbhc->mbhc_cb->enable_mb_source(codec, false);
+
 	wcd9xxx_enable_irq(mbhc->resmgr->core_res, WCD9XXX_IRQ_MBHC_POTENTIAL);
 	wcd9xxx_turn_onoff_rel_detection(codec, true);
 
@@ -3740,6 +3822,11 @@
 		      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, "dce_nsc_cs_z = %x(%dmv)\n",
+		      p->dce_nsc_cs_z,
+		      __wcd9xxx_codec_sta_dce_v(mbhc, 1, p->dce_nsc_cs_z,
+						p->dce_nsc_cs_z,
+						VDDIO_MICBIAS_MV));
 	n += scnprintf(buffer + n, size - n, "sta_z = %x(%dmv)\n",
 		       p->sta_z, wcd9xxx_codec_sta_dce_v(mbhc, 0, p->sta_z));
 	n += scnprintf(buffer + n, size - n, "sta_mb = %x(%dmv)\n",
@@ -3871,6 +3958,18 @@
 		0x40, WCD9XXX_CFILT_FAST_MODE);
 
 	/*
+	 * setup internal micbias if codec uses internal micbias for
+	 * headset detection
+	 */
+	if (mbhc->mbhc_cfg->use_int_rbias) {
+		if (mbhc->mbhc_cb && mbhc->mbhc_cb->setup_int_rbias)
+			mbhc->mbhc_cb->setup_int_rbias(codec, true);
+		else
+			pr_info("%s: internal bias is requested but codec did not provide callback\n",
+				__func__);
+	}
+
+	/*
 	 * If codec has specific clock gating for MBHC,
 	 * remove the clock gate
 	 */
@@ -3995,6 +4094,15 @@
 	return cfilt;
 }
 
+static void wcd9xxx_enable_mbhc_txfe(struct wcd9xxx_mbhc *mbhc, bool on)
+{
+	if (mbhc->mbhc_cb && mbhc->mbhc_cb->enable_mbhc_txfe)
+		mbhc->mbhc_cb->enable_mbhc_txfe(mbhc->codec, on);
+	else
+		snd_soc_update_bits(mbhc->codec, WCD9XXX_A_TX_7_MBHC_TEST_CTL,
+				    0x40, on ? 0x40 : 0x00);
+}
+
 static int wcd9xxx_event_notify(struct notifier_block *self, unsigned long val,
 				void *data)
 {
@@ -4012,14 +4120,22 @@
 	case WCD9XXX_EVENT_PRE_MICBIAS_2_ON:
 	case WCD9XXX_EVENT_PRE_MICBIAS_3_ON:
 	case WCD9XXX_EVENT_PRE_MICBIAS_4_ON:
-		if (mbhc->mbhc_cfg->micbias == wcd9xxx_event_to_micbias(event))
+		if (mbhc->mbhc_cfg && mbhc->mbhc_cfg->micbias ==
+		    wcd9xxx_event_to_micbias(event)) {
 			wcd9xxx_switch_micbias(mbhc, 0);
+			/*
+			 * Enable MBHC TxFE whenever  micbias is
+			 * turned ON and polling is active
+			 */
+			if (mbhc->polling_active)
+				wcd9xxx_enable_mbhc_txfe(mbhc, true);
+		}
 		break;
 	case WCD9XXX_EVENT_POST_MICBIAS_1_ON:
 	case WCD9XXX_EVENT_POST_MICBIAS_2_ON:
 	case WCD9XXX_EVENT_POST_MICBIAS_3_ON:
 	case WCD9XXX_EVENT_POST_MICBIAS_4_ON:
-		if (mbhc->mbhc_cfg->micbias ==
+		if (mbhc->mbhc_cfg && mbhc->mbhc_cfg->micbias ==
 		    wcd9xxx_event_to_micbias(event) &&
 		    wcd9xxx_mbhc_polling(mbhc)) {
 			/* if polling is on, restart it */
@@ -4031,11 +4147,17 @@
 	case WCD9XXX_EVENT_POST_MICBIAS_2_OFF:
 	case WCD9XXX_EVENT_POST_MICBIAS_3_OFF:
 	case WCD9XXX_EVENT_POST_MICBIAS_4_OFF:
-		if (mbhc->mbhc_cfg->micbias ==
-		    wcd9xxx_event_to_micbias(event) &&
-		    (mbhc->event_state &
-		     (1 << MBHC_EVENT_PA_HPHL | 1 << MBHC_EVENT_PA_HPHR)))
-			wcd9xxx_switch_micbias(mbhc, 1);
+		if (mbhc->mbhc_cfg && mbhc->mbhc_cfg->micbias ==
+		    wcd9xxx_event_to_micbias(event)) {
+			if (mbhc->event_state &
+			   (1 << MBHC_EVENT_PA_HPHL | 1 << MBHC_EVENT_PA_HPHR))
+				wcd9xxx_switch_micbias(mbhc, 1);
+			/*
+			 * Disable MBHC TxFE, in case it was enabled
+			 * earlier when micbias was enabled.
+			 */
+			wcd9xxx_enable_mbhc_txfe(mbhc, false);
+		}
 		break;
 	/* PA usage change */
 	case WCD9XXX_EVENT_PRE_HPHL_PA_ON:
@@ -4158,107 +4280,6 @@
 	return ret;
 }
 
-static int wcd9xxx_soc_update_bits_push(struct snd_soc_codec *codec,
-					struct list_head *list,
-					uint16_t reg, uint8_t mask,
-					uint8_t value)
-{
-	int rc;
-	struct wcd9xxx_register_save_node *node;
-
-	node = kmalloc(sizeof(*node), GFP_KERNEL);
-	if (unlikely(!node)) {
-		pr_err("%s: Not enough memory\n", __func__);
-		return -ENOMEM;
-	}
-	node->reg = reg;
-	node->value = snd_soc_read(codec, reg);
-	list_add(&node->lh, list);
-	if (mask == 0xFF)
-		rc = snd_soc_write(codec, reg, value);
-	else
-		rc = snd_soc_update_bits(codec, reg, mask, value);
-	return rc;
-}
-
-static int wcd9xxx_prepare_static_pa(struct wcd9xxx_mbhc *mbhc,
-				     struct list_head *lh)
-{
-	int i;
-	struct snd_soc_codec *codec = mbhc->codec;
-
-	const struct wcd9xxx_reg_mask_val reg_set_paon[] = {
-		{WCD9XXX_A_RX_HPH_OCP_CTL, 0x18, 0x00},
-		{WCD9XXX_A_RX_HPH_L_TEST, 0x1, 0x0},
-		{WCD9XXX_A_RX_HPH_R_TEST, 0x1, 0x0},
-		{WCD9XXX_A_RX_HPH_BIAS_WG_OCP, 0xff, 0x1A},
-		{WCD9XXX_A_RX_HPH_CNP_WG_CTL, 0xff, 0xDB},
-		{WCD9XXX_A_RX_HPH_CNP_WG_TIME, 0xff, 0x15},
-		{WCD9XXX_A_CDC_RX1_B6_CTL, 0xff, 0x81},
-		{WCD9XXX_A_CDC_CLK_RX_B1_CTL, 0x01, 0x01},
-		{WCD9XXX_A_RX_HPH_CHOP_CTL, 0xff, 0xA4},
-		{WCD9XXX_A_RX_HPH_L_GAIN, 0xff, 0x2C},
-		{WCD9XXX_A_CDC_RX2_B6_CTL, 0xff, 0x81},
-		{WCD9XXX_A_CDC_CLK_RX_B1_CTL, 0x02, 0x02},
-		{WCD9XXX_A_RX_HPH_R_GAIN, 0xff, 0x2C},
-		{WCD9XXX_A_NCP_CLK, 0xff, 0xFC},
-		{WCD9XXX_A_BUCK_CTRL_CCL_3, 0xff, 0x60},
-		{WCD9XXX_A_RX_COM_BIAS, 0xff, 0x80},
-		{WCD9XXX_A_BUCK_MODE_3, 0xff, 0xC6},
-		{WCD9XXX_A_BUCK_MODE_4, 0xff, 0xE6},
-		{WCD9XXX_A_BUCK_MODE_5, 0xff, 0x02},
-		{WCD9XXX_A_BUCK_MODE_1, 0xff, 0xA1},
-		{WCD9XXX_A_NCP_EN, 0xff, 0xFF},
-		{WCD9XXX_A_BUCK_MODE_5, 0xff, 0x7B},
-		{WCD9XXX_A_CDC_CLSH_B1_CTL, 0xff, 0xE6},
-		{WCD9XXX_A_RX_HPH_L_DAC_CTL, 0xff, 0xC0},
-		{WCD9XXX_A_RX_HPH_R_DAC_CTL, 0xff, 0xC0},
-	};
-
-	for (i = 0; i < ARRAY_SIZE(reg_set_paon); i++)
-		wcd9xxx_soc_update_bits_push(codec, lh,
-					     reg_set_paon[i].reg,
-					     reg_set_paon[i].mask,
-					     reg_set_paon[i].val);
-	pr_debug("%s: PAs are prepared\n", __func__);
-
-	return 0;
-}
-
-static void wcd9xxx_restore_registers(struct wcd9xxx_mbhc *mbhc,
-				      struct list_head *lh)
-{
-	struct wcd9xxx_register_save_node *node, *nodetmp;
-	struct snd_soc_codec *codec = mbhc->codec;
-
-	list_for_each_entry_safe(node, nodetmp, lh, lh) {
-		snd_soc_write(codec, node->reg, node->value);
-		list_del(&node->lh);
-		kfree(node);
-	}
-}
-
-static void wcd9xxx_unprepare_static_pa(struct wcd9xxx_mbhc *mbhc,
-					struct list_head *lh)
-{
-	wcd9xxx_restore_registers(mbhc, lh);
-}
-
-static int wcd9xxx_enable_static_pa(struct wcd9xxx_mbhc *mbhc, bool enable)
-{
-	struct snd_soc_codec *codec = mbhc->codec;
-	const int wg_time = snd_soc_read(codec, WCD9XXX_A_RX_HPH_CNP_WG_TIME) *
-			    WCD9XXX_WG_TIME_FACTOR_US;
-
-	snd_soc_update_bits(codec, WCD9XXX_A_RX_HPH_CNP_EN, 0x30,
-			    enable ? 0x30 : 0x0);
-	/* Wait for wave gen time to avoid pop noise */
-	usleep_range(wg_time, wg_time + WCD9XXX_USLEEP_RANGE_MARGIN_US);
-	pr_debug("%s: PAs are %s as static mode (wg_time %d)\n", __func__,
-		 enable ? "enabled" : "disabled", wg_time);
-	return 0;
-}
-
 static int wcd9xxx_detect_impedance(struct wcd9xxx_mbhc *mbhc, uint32_t *zl,
 				    uint32_t *zr)
 {
@@ -4268,17 +4289,8 @@
 	s16 *z[] = {
 		&l[0], &r[0], &r[1], &l[1], &l[2], &r[2],
 	};
-	LIST_HEAD(lh);
-	LIST_HEAD(lhpa);
 	struct snd_soc_codec *codec = mbhc->codec;
-	const int ramp_wait_us = 18 * 1000;
 	const int mux_wait_us = 25;
-	const int alphal = 364; /* 0.005555 * 65536 = 364.05 */
-	const int alphar = 364; /* 0.005555 * 65536 = 364.05 */
-	const int beta = 3855; /* 0.011765 * 5 * 65536 = 3855.15 */
-	const int rref = 11333; /* not scaled up */
-	const int shift = 16;
-	int64_t rl, rr = 0; /* milliohm */
 	const struct wcd9xxx_reg_mask_val reg_set_mux[] = {
 		/* Phase 1 */
 		/* Set MBHC_MUX for HPHL without ical */
@@ -4299,6 +4311,11 @@
 	pr_debug("%s: enter\n", __func__);
 	WCD9XXX_BCL_ASSERT_LOCKED(mbhc->resmgr);
 
+	if (!mbhc->mbhc_cb || !mbhc->mbhc_cb->setup_zdet ||
+	    !mbhc->mbhc_cb->compute_impedance || !zl ||
+	    !zr)
+		return -EINVAL;
+
 	/*
 	 * Impedance detection is an intrusive function as it mutes RX paths,
 	 * enable PAs and etc.  Therefore codec drvier including ALSA
@@ -4317,127 +4334,66 @@
 	wcd9xxx_resmgr_get_clk_block(mbhc->resmgr, WCD9XXX_CLK_RCO);
 	WCD9XXX_BG_CLK_UNLOCK(mbhc->resmgr);
 
+	wcd9xxx_turn_onoff_override(mbhc, true);
 	pr_debug("%s: Setting impedance detection\n", __func__);
-	wcd9xxx_prepare_static_pa(mbhc, &lhpa);
-	wcd9xxx_enable_static_pa(mbhc, true);
 
-	/*
-	 * save old value of registers and write the new value to restore old
-	 * value back, WCD9XXX_A_CDC_PA_RAMP_B{1,2,3,4}_CTL registers don't
-	 * need to be restored as those are solely used by impedance detection.
-	 */
-#define __w(reg, mask, value)						  \
-	do {								  \
-		ret = wcd9xxx_soc_update_bits_push(codec, &lh, reg, mask, \
-						   value);		  \
-		if (ret < 0)						  \
-			return ret;					  \
-	} while (0)
-
-	/* Reset the PA Ramp */
-	snd_soc_write(codec, WCD9XXX_A_CDC_PA_RAMP_B1_CTL, 0x1C);
-	/*
-	 * Connect the PA Ramp to PA chain and release reset with keep it
-	 * connected.
-	 */
-	snd_soc_write(codec, WCD9XXX_A_CDC_PA_RAMP_B1_CTL, 0x1F);
-	snd_soc_write(codec, WCD9XXX_A_CDC_PA_RAMP_B1_CTL, 0x03);
-	/* Program the PA Ramp to FS_48K, L shift 1 and sample num to 24 */
-	snd_soc_write(codec, WCD9XXX_A_CDC_PA_RAMP_B3_CTL, 0x3 << 4 | 0x6);
-	/* 0x56 for 10mv.  0xC0 is for 50mv */
-	snd_soc_write(codec, WCD9XXX_A_CDC_PA_RAMP_B4_CTL, 0xC0);
-	/* Enable MBHC MUX, Set MUX current to 37.5uA and ADC7 */
-	__w(WCD9XXX_A_MBHC_SCALING_MUX_1, 0xFF, 0xC0);
-	__w(WCD9XXX_A_MBHC_SCALING_MUX_2, 0xFF, 0xF0);
-	__w(WCD9XXX_A_TX_7_MBHC_TEST_CTL, 0xFF, 0x78);
-	__w(WCD9XXX_A_TX_7_MBHC_EN, 0xFF, 0x8C);
-	/* Change NSA and NAVG */
-	__w(WCD9XXX_A_CDC_MBHC_TIMER_B4_CTL, 0x4 << 4, 0x4 << 4);
-	__w(WCD9XXX_A_CDC_MBHC_TIMER_B5_CTL, 0xFF, 0x10);
-	/* Reset MBHC and set it up for STA */
-	__w(WCD9XXX_A_CDC_MBHC_CLK_CTL, 0xFF, 0x0A);
-	__w(WCD9XXX_A_CDC_MBHC_EN_CTL, 0xFF, 0x02);
-	__w(WCD9XXX_A_CDC_MBHC_CLK_CTL, 0xFF, 0x02);
-
-	/* Set HPH_MBHC for zdet */
-	__w(WCD9XXX_A_MBHC_HPH, 0xB3, 0x80);
+	/* Codec specific setup for L0, R0, L1 and R1 measurements */
+	mbhc->mbhc_cb->setup_zdet(mbhc, PRE_MEAS);
 
 	pr_debug("%s: Performing impedance detection\n", __func__);
-	/* Phase 1 */
 	for (i = 0; i < ARRAY_SIZE(reg_set_mux) - 2; i++) {
-		__w(reg_set_mux[i].reg, reg_set_mux[i].mask,
-		    reg_set_mux[i].val);
+		snd_soc_update_bits(codec, reg_set_mux[i].reg,
+				    reg_set_mux[i].mask,
+				    reg_set_mux[i].val);
+		if (mbhc->mbhc_cb && mbhc->mbhc_cb->enable_mux_bias_block)
+			mbhc->mbhc_cb->enable_mux_bias_block(codec);
+		else
+			snd_soc_update_bits(codec,
+					    WCD9XXX_A_MBHC_SCALING_MUX_1,
+					    0x80, 0x80);
 		/* 25us is required after mux change to settle down */
 		usleep_range(mux_wait_us,
 			     mux_wait_us + WCD9XXX_USLEEP_RANGE_MARGIN_US);
-		*(z[i]) = __wcd9xxx_codec_sta_dce(mbhc, 0, false, false);
+		*(z[i]) = __wcd9xxx_codec_sta_dce(mbhc, 0, true, false);
 	}
 
-	/* Phase 2 */
-	/* Start the PA ramp on HPH L and R */
-	snd_soc_write(codec, WCD9XXX_A_CDC_PA_RAMP_B2_CTL, 0x05);
-	/* Ramp generator takes ~17ms */
-	usleep_range(ramp_wait_us,
-		     ramp_wait_us + WCD9XXX_USLEEP_RANGE_MARGIN_US);
+	/* Codec specific setup for L2 and R2 measurements */
+	mbhc->mbhc_cb->setup_zdet(mbhc, POST_MEAS);
 
-	/* Disable Ical */
-	snd_soc_write(codec, WCD9XXX_A_CDC_PA_RAMP_B2_CTL, 0x00);
-	/* Ramp generator takes ~17ms */
-	usleep_range(ramp_wait_us,
-		     ramp_wait_us + WCD9XXX_USLEEP_RANGE_MARGIN_US);
 	for (; i < ARRAY_SIZE(reg_set_mux); i++) {
-		__w(reg_set_mux[i].reg, reg_set_mux[i].mask,
-		    reg_set_mux[i].val);
+		snd_soc_update_bits(codec, reg_set_mux[i].reg,
+				    reg_set_mux[i].mask,
+				    reg_set_mux[i].val);
+		if (mbhc->mbhc_cb && mbhc->mbhc_cb->enable_mux_bias_block)
+			mbhc->mbhc_cb->enable_mux_bias_block(codec);
+		else
+			snd_soc_update_bits(codec,
+					    WCD9XXX_A_MBHC_SCALING_MUX_1,
+					    0x80, 0x80);
 		/* 25us is required after mux change to settle down */
 		usleep_range(mux_wait_us,
 			     mux_wait_us + WCD9XXX_USLEEP_RANGE_MARGIN_US);
-		*(z[i]) = __wcd9xxx_codec_sta_dce(mbhc, 0, false, false);
+		*(z[i]) = __wcd9xxx_codec_sta_dce(mbhc, 0, true, false);
 	}
 
-	/* Ramp HPH L & R back to Zero */
-	snd_soc_write(codec, WCD9XXX_A_CDC_PA_RAMP_B2_CTL, 0x0A);
-	/* Ramp generator takes ~17ms */
-	usleep_range(ramp_wait_us,
-		     ramp_wait_us + WCD9XXX_USLEEP_RANGE_MARGIN_US);
-	snd_soc_write(codec, WCD9XXX_A_CDC_PA_RAMP_B2_CTL, 0x00);
-#undef __w
-
-	/* Clean up starts */
-	/* Turn off PA ramp generator */
-	snd_soc_write(codec, WCD9XXX_A_CDC_PA_RAMP_B1_CTL, 0x0);
-	wcd9xxx_enable_static_pa(mbhc, false);
-	wcd9xxx_restore_registers(mbhc, &lh);
-	wcd9xxx_unprepare_static_pa(mbhc, &lhpa);
+	mbhc->mbhc_cb->setup_zdet(mbhc, PA_DISABLE);
 
 	mutex_unlock(&codec->mutex);
 
 	WCD9XXX_BG_CLK_LOCK(mbhc->resmgr);
-	wcd9xxx_resmgr_put_bandgap(mbhc->resmgr, WCD9XXX_BANDGAP_MBHC_MODE);
+	wcd9xxx_resmgr_put_bandgap(mbhc->resmgr, WCD9XXX_BANDGAP_AUDIO_MODE);
 	wcd9xxx_resmgr_put_clk_block(mbhc->resmgr, WCD9XXX_CLK_RCO);
 	WCD9XXX_BG_CLK_UNLOCK(mbhc->resmgr);
 
-	rl = (int)(l[0] - l[1]) * 1000 / (l[0] - l[2]);
-	rl = rl * rref * alphal;
-	rl = rl >> shift;
-	rl = rl * beta;
-	rl = rl >> shift;
-	*zl = rl;
+	wcd9xxx_turn_onoff_override(mbhc, false);
+	mbhc->mbhc_cb->compute_impedance(l, r, zl, zr);
 
-	rr = (int)(r[0] - r[1]) * 1000 / (r[0] - r[2]);
-	rr = rr * rref  * alphar;
-	rr = rr >> shift;
-	rr = rr * beta;
-	rr = rr >> shift;
-	*zr = rr;
-
-	pr_debug("%s: L0: 0x%x(%d), L1: 0x%x(%d), L2: 0x%x(%d), rl: %lld\n",
+	pr_debug("%s: L0: 0x%x(%d), L1: 0x%x(%d), L2: 0x%x(%d)\n",
 		 __func__,
-		 l[0] & 0xffff, l[0], l[1] & 0xffff, l[1], l[2] & 0xffff, l[2],
-		 rl);
-	pr_debug("%s: R0: 0x%x(%d), R1: 0x%x(%d), R2: 0x%x(%d), rr: %lld\n",
+		 l[0] & 0xffff, l[0], l[1] & 0xffff, l[1], l[2] & 0xffff, l[2]);
+	pr_debug("%s: R0: 0x%x(%d), R1: 0x%x(%d), R2: 0x%x(%d)\n",
 		 __func__,
-		 r[0] & 0xffff, r[0], r[1] & 0xffff, r[1], r[2] & 0xffff, r[2],
-		 rr);
+		 r[0] & 0xffff, r[0], r[1] & 0xffff, r[1], r[2] & 0xffff, r[2]);
 	pr_debug("%s: RL %d milliohm, RR %d milliohm\n", __func__, *zl, *zr);
 	pr_debug("%s: Impedance detection completed\n", __func__);
 
diff --git a/sound/soc/codecs/wcd9xxx-mbhc.h b/sound/soc/codecs/wcd9xxx-mbhc.h
index 3040bc4..91280e4 100644
--- a/sound/soc/codecs/wcd9xxx-mbhc.h
+++ b/sound/soc/codecs/wcd9xxx-mbhc.h
@@ -19,6 +19,8 @@
 #define WCD9XXX_CFILT_EXT_PRCHG_EN 0x30
 #define WCD9XXX_CFILT_EXT_PRCHG_DSBL 0x00
 
+#define WCD9XXX_USLEEP_RANGE_MARGIN_US 100
+
 struct mbhc_micbias_regs {
 	u16 cfilt_val;
 	u16 cfilt_ctl;
@@ -40,6 +42,12 @@
 	MBHC_CAL_NUM,
 };
 
+enum mbhc_impedance_detect_stages {
+	PRE_MEAS,
+	POST_MEAS,
+	PA_DISABLE,
+};
+
 /* Data used by MBHC */
 struct mbhc_internal_cal_data {
 	u16 dce_z;
@@ -219,6 +227,7 @@
 	/* swap_gnd_mic returns true if extern GND/MIC swap switch toggled */
 	bool (*swap_gnd_mic) (struct snd_soc_codec *);
 	unsigned long cs_enable_flags;
+	bool use_int_rbias;
 };
 
 struct wcd9xxx_cfilt_mode {
@@ -239,6 +248,13 @@
 	void (*free_irq) (struct wcd9xxx_mbhc *);
 	enum wcd9xxx_cdc_type (*get_cdc_type) (void);
 	void (*enable_clock_gate) (struct snd_soc_codec *, bool);
+	int (*setup_zdet) (struct wcd9xxx_mbhc *,
+			   enum mbhc_impedance_detect_stages stage);
+	void (*compute_impedance) (s16 *, s16 *, uint32_t *, uint32_t *);
+	void (*enable_mbhc_txfe) (struct snd_soc_codec *, bool);
+	int (*enable_mb_source) (struct snd_soc_codec *, bool);
+	void (*setup_int_rbias) (struct snd_soc_codec *, bool);
+	void (*pull_mb_to_vddio) (struct snd_soc_codec *, bool);
 };
 
 struct wcd9xxx_mbhc {
diff --git a/sound/soc/msm/Kconfig b/sound/soc/msm/Kconfig
index 40661ff..86dd840 100644
--- a/sound/soc/msm/Kconfig
+++ b/sound/soc/msm/Kconfig
@@ -215,6 +215,7 @@
 	select SND_SOC_MSM_HOSTLESS_PCM
 	select SND_SOC_WCD9306
 	select SND_DYNAMIC_MINORS
+	select DOLBY_DAP
 	help
 	 To add support for SoC audio on MSM8226.
 	 This will enable sound soc drivers which
diff --git a/sound/soc/msm/msm8226.c b/sound/soc/msm/msm8226.c
index 55a5e57..9460ec0 100644
--- a/sound/soc/msm/msm8226.c
+++ b/sound/soc/msm/msm8226.c
@@ -17,16 +17,20 @@
 #include <linux/platform_device.h>
 #include <linux/slab.h>
 #include <linux/mfd/pm8xxx/pm8921.h>
+#include <linux/io.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 <mach/subsystem_notif.h>
 #include <qdsp6v2/msm-pcm-routing-v2.h>
+#include "qdsp6v2/q6core.h"
+#include "../codecs/wcd9xxx-common.h"
 #include "../codecs/wcd9306.h"
-#include <linux/io.h>
 
 #define DRV_NAME "msm8226-asoc-tapan"
 
@@ -50,6 +54,10 @@
 #define LO_1_SPK_AMP   0x1
 #define LO_2_SPK_AMP   0x2
 
+#define ADSP_STATE_READY_TIMEOUT_MS 3000
+
+static void *adsp_state_notifier;
+
 static int msm8226_auxpcm_rate = 8000;
 static atomic_t auxpcm_rsc_ref;
 static const char *const auxpcm_rate_text[] = {"rate_8000", "rate_16000"};
@@ -336,6 +344,9 @@
 	SND_SOC_DAPM_MIC("Digital Mic5", NULL),
 	SND_SOC_DAPM_MIC("Digital Mic6", NULL),
 
+	SND_SOC_DAPM_MIC("Analog Mic3", NULL),
+	SND_SOC_DAPM_MIC("Analog Mic4", NULL),
+
 	SND_SOC_DAPM_SPK("Lineout_1 amp", msm8226_ext_spkramp_event),
 	SND_SOC_DAPM_SPK("Lineout_2 amp", msm8226_ext_spkramp_event),
 
@@ -696,6 +707,107 @@
 			msm_proxy_rx_ch_get, msm_proxy_rx_ch_put),
 };
 
+static int msm_afe_set_config(struct snd_soc_codec *codec)
+{
+	int rc;
+	void *config_data;
+
+	pr_debug("%s: enter\n", __func__);
+	config_data = tapan_get_afe_config(codec, AFE_CDC_REGISTERS_CONFIG);
+	rc = afe_set_config(AFE_CDC_REGISTERS_CONFIG, config_data, 0);
+	if (rc) {
+		pr_err("%s: Failed to set codec registers config %d\n",
+			__func__, rc);
+		return rc;
+	}
+	config_data = tapan_get_afe_config(codec, AFE_SLIMBUS_SLAVE_CONFIG);
+	rc = afe_set_config(AFE_SLIMBUS_SLAVE_CONFIG, config_data, 0);
+	if (rc) {
+		pr_err("%s: Failed to set slimbus slave config %d\n", __func__,
+			rc);
+		return rc;
+	}
+	config_data = tapan_get_afe_config(codec, AFE_AANC_VERSION);
+	rc = afe_set_config(AFE_AANC_VERSION, config_data, 0);
+	if (rc) {
+		pr_err("%s: Failed to set AANC version %d\n", __func__,
+			rc);
+		return rc;
+	}
+	return 0;
+}
+
+static void msm_afe_clear_config(void)
+{
+	afe_clear_config(AFE_CDC_REGISTERS_CONFIG);
+	afe_clear_config(AFE_SLIMBUS_SLAVE_CONFIG);
+	afe_clear_config(AFE_AANC_VERSION);
+}
+
+static int  msm8226_adsp_state_callback(struct notifier_block *nb,
+		unsigned long value, void *priv)
+{
+	if (value == SUBSYS_BEFORE_SHUTDOWN) {
+		pr_debug("%s: ADSP is about to shutdown. Clearing AFE config\n",
+			 __func__);
+		msm_afe_clear_config();
+	} else if (value == SUBSYS_AFTER_POWERUP) {
+		pr_debug("%s: ADSP is up\n", __func__);
+	}
+
+	return NOTIFY_OK;
+}
+
+static struct notifier_block adsp_state_notifier_block = {
+	.notifier_call = msm8226_adsp_state_callback,
+	.priority = -INT_MAX,
+};
+
+static int msm8226_tapan_codec_up(struct snd_soc_codec *codec)
+{
+	int err;
+	unsigned long timeout;
+	int adsp_ready = 0;
+
+	pr_debug("%s\n", __func__);
+	timeout = jiffies +
+		msecs_to_jiffies(ADSP_STATE_READY_TIMEOUT_MS);
+
+	do {
+		if (!q6core_is_adsp_ready()) {
+			pr_err("%s: ADSP Audio isn't ready\n", __func__);
+		} else {
+			pr_debug("%s: ADSP Audio is ready\n", __func__);
+			adsp_ready = 1;
+			break;
+		}
+	} while (time_after(timeout, jiffies));
+
+	if (!adsp_ready) {
+		pr_err("%s: timed out waiting for ADSP Audio\n", __func__);
+		return -ETIMEDOUT;
+	}
+
+	err = msm_afe_set_config(codec);
+	if (err)
+		pr_err("%s: Failed to set AFE config. err %d\n",
+			__func__, err);
+	return err;
+}
+
+static int msm8226_tapan_event_cb(struct snd_soc_codec *codec,
+	enum wcd9xxx_codec_event codec_event)
+{
+	switch (codec_event) {
+	case WCD9XXX_CODEC_EVENT_CODEC_UP:
+		return msm8226_tapan_codec_up(codec);
+	default:
+		pr_err("%s: UnSupported codec event %d\n",
+			__func__, codec_event);
+		return -EINVAL;
+	}
+}
+
 static int msm_audrx_init(struct snd_soc_pcm_runtime *rtd)
 {
 	int err;
@@ -736,13 +848,37 @@
 	snd_soc_dai_set_channel_map(codec_dai, ARRAY_SIZE(tx_ch),
 				    tx_ch, ARRAY_SIZE(rx_ch), rx_ch);
 
+	err = msm_afe_set_config(codec);
+	if (err) {
+		pr_err("%s: Failed to set AFE config %d\n",
+			__func__, err);
+		return err;
+	}
+
 	/* start mbhc */
 	mbhc_cfg.calibration = def_tapan_mbhc_cal();
-	if (mbhc_cfg.calibration)
+	if (mbhc_cfg.calibration) {
 		err = tapan_hs_detect(codec, &mbhc_cfg);
-	else
+	} else {
 		err = -ENOMEM;
+		goto out;
+	}
 
+	adsp_state_notifier =
+		subsys_notif_register_notifier("adsp",
+			&adsp_state_notifier_block);
+
+	if (!adsp_state_notifier) {
+		pr_err("%s: Failed to register adsp state notifier\n",
+			__func__);
+		err = -EFAULT;
+		goto out;
+	}
+
+	tapan_event_register(msm8226_tapan_event_cb, rtd->codec);
+	return 0;
+
+out:
 	return err;
 }
 
@@ -1165,6 +1301,38 @@
 		.codec_name = "snd-soc-dummy",
 		.be_id = MSM_FRONTEND_DAI_VOLTE,
 	},
+	{
+		.name = "QCHAT",
+		.stream_name = "QCHAT",
+		.cpu_dai_name   = "QCHAT",
+		.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_QCHAT,
+	},
+	/* 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,
@@ -1457,6 +1625,19 @@
 		.ops = &msm8226_be_ops,
 		.ignore_suspend = 1,
 	},
+	{
+		.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 = "tapan_codec",
+		.codec_dai_name = "tapan_tx1",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_SLIMBUS_5_TX,
+		.be_hw_params_fixup = msm_slim_0_tx_be_hw_params_fixup,
+		.ops = &msm8226_be_ops,
+		.ignore_suspend = 1,
+	},
 };
 
 static struct snd_soc_dai_link msm8226_9302_dai[] = {
@@ -1573,6 +1754,19 @@
 		.ops = &msm8226_be_ops,
 		.ignore_suspend = 1,
 	},
+	{
+		.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 = "tapan_codec",
+		.codec_dai_name = "tapan9302_tx1",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_SLIMBUS_5_TX,
+		.be_hw_params_fixup = msm_slim_0_tx_be_hw_params_fixup,
+		.ops = &msm8226_be_ops,
+		.ignore_suspend = 1,
+	},
 };
 
 static struct snd_soc_dai_link msm8226_9306_dai_links[
diff --git a/sound/soc/msm/msm8x10.c b/sound/soc/msm/msm8x10.c
index dfde85c..4b61db6 100644
--- a/sound/soc/msm/msm8x10.c
+++ b/sound/soc/msm/msm8x10.c
@@ -72,6 +72,7 @@
 	.detect_extn_cable = false,
 	.insert_detect = true,
 	.swap_gnd_mic = NULL,
+	.use_int_rbias = false,
 };
 
 /*
@@ -817,6 +818,22 @@
 		.codec_dai_name = "snd-soc-dummy-dai",
 		.codec_name = "snd-soc-dummy",
 	},
+	{/* hw:x,14 */
+		.name = "QCHAT",
+		.stream_name = "QCHAT",
+		.cpu_dai_name   = "QCHAT",
+		.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_QCHAT,
+	},
 	/* Backend I2S DAI Links */
 	{
 		.name = LPASS_BE_SEC_MI2S_RX,
@@ -1008,6 +1025,8 @@
 	atomic_set(&mclk_rsc_ref, 0);
 	mbhc_cfg.gpio_level_insert = of_property_read_bool(pdev->dev.of_node,
 						"qcom,headset-jack-type-NC");
+	mbhc_cfg.use_int_rbias = of_property_read_bool(pdev->dev.of_node,
+						"qcom,mbhc-bias-internal");
 
 	spdev = pdev;
 
diff --git a/sound/soc/msm/qdsp6v2/audio_acdb.c b/sound/soc/msm/qdsp6v2/audio_acdb.c
index 3e93b6e..9a2d4d3 100644
--- a/sound/soc/msm/qdsp6v2/audio_acdb.c
+++ b/sound/soc/msm/qdsp6v2/audio_acdb.c
@@ -36,6 +36,7 @@
 #define NUM_VOCPROC_BLOCKS		(6 * MAX_NETWORKS)
 #define ACDB_TOTAL_VOICE_ALLOCATION	(ACDB_BLOCK_SIZE * NUM_VOCPROC_BLOCKS)
 
+#define MAX_HW_DELAY_ENTRIES	25
 
 struct sidetone_atomic_cal {
 	atomic_t	enable;
@@ -98,6 +99,10 @@
 
 	/* Speaker protection */
 	struct msm_spk_prot_cfg spk_prot_cfg;
+
+	/* Av sync delay info */
+	struct hw_delay hw_delay_rx;
+	struct hw_delay hw_delay_tx;
 };
 
 static struct acdb_data		acdb_data;
@@ -371,6 +376,122 @@
 	return result;
 }
 
+int get_hw_delay(int32_t path, struct hw_delay_entry *entry)
+{
+	int i, result = 0;
+	struct hw_delay *delay = NULL;
+	struct hw_delay_entry *info = NULL;
+	pr_debug("%s,\n", __func__);
+
+	if (entry == NULL) {
+		pr_err("ACDB=> NULL pointer sent to %s\n", __func__);
+		result = -EINVAL;
+		goto ret;
+	}
+	if ((path >= MAX_AUDPROC_TYPES) || (path < 0)) {
+		pr_err("ACDB=> Bad path sent to %s, path: %d\n",
+		       __func__, path);
+		result = -EINVAL;
+		goto ret;
+	}
+	mutex_lock(&acdb_data.acdb_mutex);
+	if (path == RX_CAL)
+		delay = &acdb_data.hw_delay_rx;
+	else if (path == TX_CAL)
+		delay = &acdb_data.hw_delay_tx;
+
+	if ((delay == NULL) || ((delay != NULL) && delay->num_entries == 0)) {
+		pr_err("ACDB=> %s Invalid delay/ delay entries\n", __func__);
+		result = -EINVAL;
+		goto done;
+	}
+
+	info = (struct hw_delay_entry *)(delay->delay_info);
+	if (info == NULL) {
+		pr_err("ACDB=> %s Delay entries info is NULL\n", __func__);
+		result = -EFAULT;
+		goto done;
+	}
+	for (i = 0; i < delay->num_entries; i++) {
+		if (info[i].sample_rate == entry->sample_rate) {
+			entry->delay_usec = info[i].delay_usec;
+			break;
+		}
+	}
+	if (i == delay->num_entries) {
+		pr_err("ACDB=> %s: Unable to find delay for sample rate %d\n",
+		       __func__, entry->sample_rate);
+		result = -EFAULT;
+	}
+
+done:
+	mutex_unlock(&acdb_data.acdb_mutex);
+ret:
+	pr_debug("ACDB=> %s: Path = %d samplerate = %u usec = %u status %d\n",
+		 __func__, path, entry->sample_rate, entry->delay_usec, result);
+	return result;
+}
+
+int store_hw_delay(int32_t path, void *arg)
+{
+	int result = 0;
+	struct hw_delay delay;
+	struct hw_delay *delay_dest = NULL;
+	pr_debug("%s,\n", __func__);
+
+	if ((path >= MAX_AUDPROC_TYPES) || (path < 0) || (arg == NULL)) {
+		pr_err("ACDB=> Bad path/ pointer sent to %s, path: %d\n",
+		      __func__, path);
+		result = -EINVAL;
+		goto done;
+	}
+	result = copy_from_user((void *)&delay, (void *)arg,
+				sizeof(struct hw_delay));
+	if (result) {
+		pr_err("ACDB=> %s failed to copy hw delay: result=%d path=%d\n",
+		       __func__, result, path);
+		result = -EFAULT;
+		goto done;
+	}
+	if ((delay.num_entries <= 0) ||
+		(delay.num_entries > MAX_HW_DELAY_ENTRIES)) {
+		pr_err("ACDB=> %s incorrect no of hw delay entries: %d\n",
+		       __func__, delay.num_entries);
+		result = -EINVAL;
+		goto done;
+	}
+	if ((path >= MAX_AUDPROC_TYPES) || (path < 0)) {
+		pr_err("ACDB=> Bad path sent to %s, path: %d\n",
+		__func__, path);
+		result = -EINVAL;
+		goto done;
+	}
+
+	pr_debug("ACDB=> %s : Path = %d num_entries = %d\n",
+		 __func__, path, delay.num_entries);
+
+	mutex_lock(&acdb_data.acdb_mutex);
+	if (path == RX_CAL)
+		delay_dest = &acdb_data.hw_delay_rx;
+	else if (path == TX_CAL)
+		delay_dest = &acdb_data.hw_delay_tx;
+
+	delay_dest->num_entries = delay.num_entries;
+
+	result = copy_from_user(delay_dest->delay_info,
+				delay.delay_info,
+				(sizeof(struct hw_delay_entry)*
+				delay.num_entries));
+	if (result) {
+		pr_err("ACDB=> %s failed to copy hw delay info res=%d path=%d",
+		       __func__, result, path);
+		result = -EFAULT;
+	}
+	mutex_unlock(&acdb_data.acdb_mutex);
+done:
+	return result;
+}
+
 int get_anc_cal(struct acdb_cal_block *cal_block)
 {
 	int result = 0;
@@ -998,6 +1119,29 @@
 	atomic_set(&acdb_data.valid_adm_custom_top, 1);
 	atomic_set(&acdb_data.valid_asm_custom_top, 1);
 	atomic_inc(&usage_count);
+
+	/* Allocate memory for hw delay entries */
+	mutex_lock(&acdb_data.acdb_mutex);
+	acdb_data.hw_delay_rx.num_entries = 0;
+	acdb_data.hw_delay_tx.num_entries = 0;
+	acdb_data.hw_delay_rx.delay_info =
+				kmalloc(sizeof(struct hw_delay_entry)*
+					MAX_HW_DELAY_ENTRIES,
+					GFP_KERNEL);
+	if (acdb_data.hw_delay_rx.delay_info == NULL) {
+		pr_err("%s : Failed to allocate av sync delay entries rx\n",
+			__func__);
+	}
+	acdb_data.hw_delay_tx.delay_info =
+				kmalloc(sizeof(struct hw_delay_entry)*
+					MAX_HW_DELAY_ENTRIES,
+					GFP_KERNEL);
+	if (acdb_data.hw_delay_tx.delay_info == NULL) {
+		pr_err("%s : Failed to allocate av sync delay entries tx\n",
+			__func__);
+	}
+	mutex_unlock(&acdb_data.acdb_mutex);
+
 	return result;
 }
 
@@ -1066,6 +1210,8 @@
 			acdb_data.col_data[i] = NULL;
 		}
 		msm_audio_ion_free(acdb_data.ion_client, acdb_data.ion_handle);
+		acdb_data.ion_client = NULL;
+		acdb_data.ion_handle = NULL;
 		mutex_unlock(&acdb_data.acdb_mutex);
 	}
 	return result;
@@ -1114,8 +1260,6 @@
 
 	return result;
 err_ion_handle:
-	msm_audio_ion_free(acdb_data.ion_client, acdb_data.ion_handle);
-
 	atomic64_set(&acdb_data.mem_len, 0);
 	mutex_unlock(&acdb_data.acdb_mutex);
 	return result;
@@ -1238,6 +1382,12 @@
 	case AUDIO_DEREGISTER_VOCPROC_VOL_TABLE:
 		result = deregister_vocvol_table();
 		goto done;
+	case AUDIO_SET_HW_DELAY_RX:
+		result = store_hw_delay(RX_CAL, (void *)arg);
+		goto done;
+	case AUDIO_SET_HW_DELAY_TX:
+		result = store_hw_delay(TX_CAL, (void *)arg);
+		goto done;
 	}
 
 	if (copy_from_user(&size, (void *) arg, sizeof(size))) {
@@ -1393,6 +1543,9 @@
 	else
 		result = deregister_memory();
 
+	kfree(acdb_data.hw_delay_rx.delay_info);
+	kfree(acdb_data.hw_delay_tx.delay_info);
+
 	return result;
 }
 
diff --git a/sound/soc/msm/qdsp6v2/audio_acdb.h b/sound/soc/msm/qdsp6v2/audio_acdb.h
index d9c1210..e2ca395 100644
--- a/sound/soc/msm/qdsp6v2/audio_acdb.h
+++ b/sound/soc/msm/qdsp6v2/audio_acdb.h
@@ -41,6 +41,11 @@
 	atomic_t		cal_paddr;
 };
 
+struct hw_delay_entry {
+	uint32_t sample_rate;
+	uint32_t delay_usec;
+};
+
 uint32_t get_voice_rx_topology(void);
 uint32_t get_voice_tx_topology(void);
 uint32_t get_adm_rx_topology(void);
@@ -65,5 +70,6 @@
 int get_sidetone_cal(struct sidetone_cal *cal_data);
 int get_spk_protection_cfg(struct msm_spk_prot_cfg *prot_cfg);
 int get_aanc_cal(struct acdb_cal_block *cal_block);
+int get_hw_delay(int32_t path, struct hw_delay_entry *delay_info);
 
 #endif
diff --git a/sound/soc/msm/qdsp6v2/msm-dolby-dap-config.c b/sound/soc/msm/qdsp6v2/msm-dolby-dap-config.c
index cd08b39..307d63e 100644
--- a/sound/soc/msm/qdsp6v2/msm-dolby-dap-config.c
+++ b/sound/soc/msm/qdsp6v2/msm-dolby-dap-config.c
@@ -43,75 +43,190 @@
 
 const struct dolby_dap_endp_params_s
 			dolby_dap_endp_params[NUM_DOLBY_ENDP_DEVICE] = {
-	{EARPIECE,			2, DOLBY_ENDP_EXT_SPEAKERS,
-		{DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH},
-		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-320} },
-	{SPEAKER,			2, DOLBY_ENDP_INT_SPEAKERS,
-		{DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH},
-		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-320} },
-	{WIRED_HEADSET,			2, DOLBY_ENDP_HEADPHONES,
-		{DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH},
-		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-320} },
-	{WIRED_HEADPHONE,		2, DOLBY_ENDP_HEADPHONES,
-		{DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH},
-		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-320} },
-	{BLUETOOTH_SCO,			2, DOLBY_ENDP_EXT_SPEAKERS,
-		{DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH},
-		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-320} },
-	{BLUETOOTH_SCO_HEADSET,		2, DOLBY_ENDP_EXT_SPEAKERS,
-		{DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH},
-		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-320} },
-	{BLUETOOTH_SCO_CARKIT,		2, DOLBY_ENDP_EXT_SPEAKERS,
-		{DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH},
-		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-320} },
-	{BLUETOOTH_A2DP,		2, DOLBY_ENDP_EXT_SPEAKERS,
-		{DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH},
-		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-320} },
-	{BLUETOOTH_A2DP_HEADPHONES,	2, DOLBY_ENDP_HEADPHONES,
-		{DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH},
-		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-320} },
-	{BLUETOOTH_A2DP_SPEAKER,	2, DOLBY_ENDP_EXT_SPEAKERS,
-		{DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH},
-		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-320} },
-	{AUX_DIGITAL,			2, DOLBY_ENDP_HDMI,
-		{DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH},
-		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-640} },
-	{AUX_DIGITAL,			6, DOLBY_ENDP_HDMI,
-		{DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH},
-		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-640} },
-	{AUX_DIGITAL,			8, DOLBY_ENDP_HDMI,
-		{DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH},
-		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-640} },
-	{ANLG_DOCK_HEADSET,		2, DOLBY_ENDP_HEADPHONES,
-		{DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH},
-		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-320} },
-	{DGTL_DOCK_HEADSET,		2, DOLBY_ENDP_HEADPHONES,
-		{DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH},
-		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-320} },
-	{USB_ACCESSORY,			2, DOLBY_ENDP_EXT_SPEAKERS,
-		{DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH},
-		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-320} },
-	{USB_DEVICE,			2, DOLBY_ENDP_EXT_SPEAKERS,
-		{DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH},
-		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-320} },
-	{REMOTE_SUBMIX,			2, DOLBY_ENDP_EXT_SPEAKERS,
-		{DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH},
-		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-320} },
-	{ANC_HEADSET,			2, DOLBY_ENDP_HEADPHONES,
-		{DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH},
-		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-320} },
-	{ANC_HEADPHONE,			2, DOLBY_ENDP_HEADPHONES,
-		{DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH},
-		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-320} },
-	{PROXY,				2, DOLBY_ENDP_EXT_SPEAKERS,
-		{DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH},
-		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-320} },
-	{FM,				2, DOLBY_ENDP_EXT_SPEAKERS,
-		{DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH},
-		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-320} },
-	{FM_TX,				2, DOLBY_ENDP_EXT_SPEAKERS,
-		{DOLBY_PARAM_ID_DVLO}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH},
-		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET}, {-320} },
+	{EARPIECE, 2, DOLBY_ENDP_EXT_SPEAKERS,
+		{DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
+		{DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
+		 DOLBY_ENDDEP_PARAM_VMB_LENGTH},
+		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
+		 DOLBY_ENDDEP_PARAM_VMB_OFFSET},
+		{-320, -320, 144}
+	},
+	{SPEAKER, 2, DOLBY_ENDP_INT_SPEAKERS,
+		{DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
+		{DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
+		 DOLBY_ENDDEP_PARAM_VMB_LENGTH},
+		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
+		 DOLBY_ENDDEP_PARAM_VMB_OFFSET},
+		{-320, -320, 144}
+	},
+	{WIRED_HEADSET,	2, DOLBY_ENDP_HEADPHONES,
+		{DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
+		{DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
+		 DOLBY_ENDDEP_PARAM_VMB_LENGTH},
+		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
+		 DOLBY_ENDDEP_PARAM_VMB_OFFSET},
+		{-320, -320, 144}
+	},
+	{WIRED_HEADPHONE, 2, DOLBY_ENDP_HEADPHONES,
+		{DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
+		{DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
+		 DOLBY_ENDDEP_PARAM_VMB_LENGTH},
+		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
+		 DOLBY_ENDDEP_PARAM_VMB_OFFSET},
+		{-320, -320, 144}
+	},
+	{BLUETOOTH_SCO,	2, DOLBY_ENDP_EXT_SPEAKERS,
+		{DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
+		{DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
+		 DOLBY_ENDDEP_PARAM_VMB_LENGTH},
+		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
+		 DOLBY_ENDDEP_PARAM_VMB_OFFSET},
+		{-320, -320, 144}
+	},
+	{BLUETOOTH_SCO_HEADSET,	2, DOLBY_ENDP_EXT_SPEAKERS,
+		{DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
+		{DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
+		 DOLBY_ENDDEP_PARAM_VMB_LENGTH},
+		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
+		 DOLBY_ENDDEP_PARAM_VMB_OFFSET},
+		{-320, -320, 144}
+	},
+	{BLUETOOTH_SCO_CARKIT, 2, DOLBY_ENDP_EXT_SPEAKERS,
+		{DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
+		{DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
+		 DOLBY_ENDDEP_PARAM_VMB_LENGTH},
+		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
+		 DOLBY_ENDDEP_PARAM_VMB_OFFSET},
+		{-320, -320, 144}
+	},
+	{BLUETOOTH_A2DP, 2, DOLBY_ENDP_EXT_SPEAKERS,
+		{DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
+		{DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
+		 DOLBY_ENDDEP_PARAM_VMB_LENGTH},
+		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
+		 DOLBY_ENDDEP_PARAM_VMB_OFFSET},
+		{-320, -320, 144}
+	},
+	{BLUETOOTH_A2DP_HEADPHONES, 2, DOLBY_ENDP_HEADPHONES,
+		{DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
+		{DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
+		 DOLBY_ENDDEP_PARAM_VMB_LENGTH},
+		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
+		 DOLBY_ENDDEP_PARAM_VMB_OFFSET},
+		{-320, -320, 144}
+	},
+	{BLUETOOTH_A2DP_SPEAKER, 2, DOLBY_ENDP_EXT_SPEAKERS,
+		{DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
+		{DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
+		 DOLBY_ENDDEP_PARAM_VMB_LENGTH},
+		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
+		 DOLBY_ENDDEP_PARAM_VMB_OFFSET},
+		{-320, -320, 144}
+	},
+	{AUX_DIGITAL, 2, DOLBY_ENDP_HDMI,
+		{DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
+		{DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
+		 DOLBY_ENDDEP_PARAM_VMB_LENGTH},
+		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
+		 DOLBY_ENDDEP_PARAM_VMB_OFFSET},
+		{-496, -496, 0}
+	},
+	{AUX_DIGITAL, 6, DOLBY_ENDP_HDMI,
+		{DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
+		{DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
+		 DOLBY_ENDDEP_PARAM_VMB_LENGTH},
+		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
+		 DOLBY_ENDDEP_PARAM_VMB_OFFSET},
+		{-496, -496, 0}
+	},
+	{AUX_DIGITAL, 8, DOLBY_ENDP_HDMI,
+		{DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
+		{DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
+		 DOLBY_ENDDEP_PARAM_VMB_LENGTH},
+		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
+		 DOLBY_ENDDEP_PARAM_VMB_OFFSET},
+		{-496, -496, 0}
+	},
+	{ANLG_DOCK_HEADSET, 2, DOLBY_ENDP_HEADPHONES,
+		{DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
+		{DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
+		 DOLBY_ENDDEP_PARAM_VMB_LENGTH},
+		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
+		 DOLBY_ENDDEP_PARAM_VMB_OFFSET},
+		{-320, -320, 144}
+	},
+	{DGTL_DOCK_HEADSET, 2, DOLBY_ENDP_HEADPHONES,
+		{DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
+		{DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
+		 DOLBY_ENDDEP_PARAM_VMB_LENGTH},
+		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
+		 DOLBY_ENDDEP_PARAM_VMB_OFFSET},
+		{-320, -320, 144}
+	},
+	{USB_ACCESSORY,	2, DOLBY_ENDP_EXT_SPEAKERS,
+		{DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
+		{DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
+		 DOLBY_ENDDEP_PARAM_VMB_LENGTH},
+		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
+		 DOLBY_ENDDEP_PARAM_VMB_OFFSET},
+		{-320, -320, 144}
+	},
+	{USB_DEVICE, 2, DOLBY_ENDP_EXT_SPEAKERS,
+		{DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
+		{DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
+		 DOLBY_ENDDEP_PARAM_VMB_LENGTH},
+		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
+		 DOLBY_ENDDEP_PARAM_VMB_OFFSET},
+		{-320, -320, 144}
+	},
+	{REMOTE_SUBMIX,	2, DOLBY_ENDP_EXT_SPEAKERS,
+		{DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
+		{DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
+		 DOLBY_ENDDEP_PARAM_VMB_LENGTH},
+		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
+		 DOLBY_ENDDEP_PARAM_VMB_OFFSET},
+		{-320, -320, 144}
+	},
+	{ANC_HEADSET, 2, DOLBY_ENDP_HEADPHONES,
+		{DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
+		{DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
+		 DOLBY_ENDDEP_PARAM_VMB_LENGTH},
+		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
+		 DOLBY_ENDDEP_PARAM_VMB_OFFSET},
+		{-320, -320, 144}
+	},
+	{ANC_HEADPHONE,	2, DOLBY_ENDP_HEADPHONES,
+		{DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
+		{DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
+		 DOLBY_ENDDEP_PARAM_VMB_LENGTH},
+		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
+		 DOLBY_ENDDEP_PARAM_VMB_OFFSET},
+		{-320, -320, 144}
+	},
+	{PROXY,	2, DOLBY_ENDP_EXT_SPEAKERS,
+		{DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
+		{DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
+		 DOLBY_ENDDEP_PARAM_VMB_LENGTH},
+		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
+		 DOLBY_ENDDEP_PARAM_VMB_OFFSET},
+		{-320, -320, 144}
+	},
+	{FM, 2, DOLBY_ENDP_EXT_SPEAKERS,
+		{DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
+		{DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
+		 DOLBY_ENDDEP_PARAM_VMB_LENGTH},
+		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
+		 DOLBY_ENDDEP_PARAM_VMB_OFFSET},
+		{-320, -320, 144}
+	},
+	{FM_TX,	2, DOLBY_ENDP_EXT_SPEAKERS,
+		{DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
+		{DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
+		 DOLBY_ENDDEP_PARAM_VMB_LENGTH},
+		{DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
+		 DOLBY_ENDDEP_PARAM_VMB_OFFSET},
+		{-320, -320, 144}
+	},
 };
 
 /* dolby param ids to/from dsp */
diff --git a/sound/soc/msm/qdsp6v2/msm-dolby-dap-config.h b/sound/soc/msm/qdsp6v2/msm-dolby-dap-config.h
index 113d85f..4544fea 100644
--- a/sound/soc/msm/qdsp6v2/msm-dolby-dap-config.h
+++ b/sound/soc/msm/qdsp6v2/msm-dolby-dap-config.h
@@ -226,10 +226,17 @@
 #define DOLBY_PARAM_PAYLOAD_SIZE		3
 #define DOLBY_MAX_LENGTH_INDIVIDUAL_PARAM	329
 
-#define DOLBY_NUM_ENDP_DEPENDENT_PARAMS		1
-#define DOLBY_ENDDEP_PARAM_DVLO_OFFSET		0
-#define DOLBY_ENDDEP_PARAM_DVLO_LENGTH		1
-#define DOLBY_ENDDEP_PARAM_LENGTH		DOLBY_ENDDEP_PARAM_DVLO_LENGTH
+#define DOLBY_NUM_ENDP_DEPENDENT_PARAMS	  3
+#define DOLBY_ENDDEP_PARAM_DVLO_OFFSET	  0
+#define DOLBY_ENDDEP_PARAM_DVLO_LENGTH	  1
+#define DOLBY_ENDDEP_PARAM_DVLI_OFFSET    (DOLBY_ENDDEP_PARAM_DVLO_OFFSET + \
+						DOLBY_ENDDEP_PARAM_DVLO_LENGTH)
+#define DOLBY_ENDDEP_PARAM_DVLI_LENGTH    1
+#define DOLBY_ENDDEP_PARAM_VMB_OFFSET     (DOLBY_ENDDEP_PARAM_DVLI_OFFSET + \
+						DOLBY_ENDDEP_PARAM_DVLI_LENGTH)
+#define DOLBY_ENDDEP_PARAM_VMB_LENGTH     1
+#define DOLBY_ENDDEP_PARAM_LENGTH         (DOLBY_ENDDEP_PARAM_DVLO_LENGTH + \
+		DOLBY_ENDDEP_PARAM_DVLI_LENGTH + DOLBY_ENDDEP_PARAM_VMB_LENGTH)
 
 #define MAX_DOLBY_PARAMS			47
 #define MAX_DOLBY_CTRL_PARAMS			5
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
index 42a24fc..f6ea266 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
@@ -68,7 +68,8 @@
 	MADNONE,
 	MADAUDIO,
 	MADBEACON,
-	MADULTRASOUND
+	MADULTRASOUND,
+	MADSWAUDIO,
 };
 
 #define SLIMBUS_0_TX_TEXT "SLIMBUS_0_TX"
@@ -191,7 +192,7 @@
 		topology_id = get_adm_tx_topology();
 
 	if (topology_id  == 0)
-		topology_id = DEFAULT_COPP_TOPOLOGY;
+		topology_id = NULL_COPP_TOPOLOGY;
 
 	return topology_id;
 }
@@ -882,6 +883,9 @@
 	case MAD_HW_ULTRASOUND:
 		ucontrol->value.integer.value[0] = MADULTRASOUND;
 		break;
+	case MAD_SW_AUDIO:
+		ucontrol->value.integer.value[0] = MADSWAUDIO;
+	break;
 	default:
 		WARN(1, "Unknown\n");
 		return -EINVAL;
@@ -921,6 +925,9 @@
 	case MADULTRASOUND:
 		mad_type = MAD_HW_ULTRASOUND;
 		break;
+	case MADSWAUDIO:
+		mad_type = MAD_SW_AUDIO;
+		break;
 	default:
 		WARN(1, "Unknown\n");
 		return -EINVAL;
@@ -1337,7 +1344,7 @@
 		break;
 	case 1:
 		msm_route_ec_ref_rx = 1;
-		ec_ref_port_id = PRIMARY_I2S_RX;
+		ec_ref_port_id = AFE_PORT_ID_PRIMARY_MI2S_RX;
 		break;
 	default:
 		msm_route_ec_ref_rx = 3; /* NONE */
@@ -2427,7 +2434,7 @@
 			  msm_routing_lsm_mux_put);
 
 static const char * const lsm_func_text[] = {
-	"None", "AUDIO", "BEACON", "ULTRASOUND"
+	"None", "AUDIO", "BEACON", "ULTRASOUND", "SWAUDIO",
 };
 static const struct soc_enum lsm_func_enum =
 	SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(lsm_func_text), lsm_func_text);
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-voip-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-voip-v2.c
index 158009f..6cfc2ef 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-voip-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-voip-v2.c
@@ -46,6 +46,7 @@
 #define MODE_AMR		0x5
 #define MODE_AMR_WB		0xD
 #define MODE_PCM		0xC
+#define MODE_4GV_NW		0xE
 
 enum format {
 	FORMAT_S16_LE = 2,
@@ -140,6 +141,9 @@
 	unsigned int pcm_capture_count;
 	unsigned int pcm_capture_irq_pos;       /* IRQ position */
 	unsigned int pcm_capture_buf_pos;       /* position in buffer */
+
+	uint32_t evrc_min_rate;
+	uint32_t evrc_max_rate;
 };
 
 static int voip_get_media_type(uint32_t mode,
@@ -148,10 +152,15 @@
 static int voip_get_rate_type(uint32_t mode,
 				uint32_t rate,
 				uint32_t *rate_type);
+static int voip_config_vocoder(struct snd_pcm_substream *substream);
 static int msm_voip_mode_rate_config_put(struct snd_kcontrol *kcontrol,
 					struct snd_ctl_elem_value *ucontrol);
 static int msm_voip_mode_rate_config_get(struct snd_kcontrol *kcontrol,
 					struct snd_ctl_elem_value *ucontrol);
+static int msm_voip_evrc_min_max_rate_config_put(struct snd_kcontrol *kcontrol,
+					 struct snd_ctl_elem_value *ucontrol);
+static int msm_voip_evrc_min_max_rate_config_get(struct snd_kcontrol *kcontrol,
+					 struct snd_ctl_elem_value *ucontrol);
 
 static struct voip_drv_info voip_info;
 
@@ -261,6 +270,9 @@
 	SOC_SINGLE_MULTI_EXT("Voip Mode Rate Config", SND_SOC_NOPM, 0, 23850,
 			     0, 2, msm_voip_mode_rate_config_get,
 			     msm_voip_mode_rate_config_put),
+	SOC_SINGLE_MULTI_EXT("Voip Evrc Min Max Rate Config", SND_SOC_NOPM,
+			     0, 4, 0, 2, msm_voip_evrc_min_max_rate_config_get,
+			     msm_voip_evrc_min_max_rate_config_put),
 	SOC_SINGLE_EXT("Voip Dtx Mode", SND_SOC_NOPM, 0, 1, 0,
 		       msm_voip_dtx_mode_get, msm_voip_dtx_mode_put),
 };
@@ -318,7 +330,8 @@
 		}
 		case MODE_IS127:
 		case MODE_4GV_NB:
-		case MODE_4GV_WB: {
+		case MODE_4GV_WB:
+		case MODE_4GV_NW: {
 			/* Remove the DSP frame info header.
 			 * Header format:
 			 * Bits 0-3: frame rate
@@ -397,7 +410,8 @@
 		}
 		case MODE_IS127:
 		case MODE_4GV_NB:
-		case MODE_4GV_WB: {
+		case MODE_4GV_WB:
+		case MODE_4GV_NW: {
 			*((uint32_t *)voc_pkt) = buf_node->frame.pktlen +
 							 DSP_FRAME_HDR_LEN;
 			/* Advance to the header of voip packet */
@@ -769,13 +783,137 @@
 
 	return ret;
 }
-static int msm_pcm_prepare(struct snd_pcm_substream *substream)
+
+static int voip_config_vocoder(struct snd_pcm_substream *substream)
 {
 	int ret = 0;
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct voip_drv_info *prtd = runtime->private_data;
 	uint32_t media_type = 0;
 	uint32_t rate_type = 0;
+	uint32_t evrc_min_rate_type = 0;
+	uint32_t evrc_max_rate_type = 0;
+
+	if ((runtime->format != FORMAT_SPECIAL) &&
+	    ((prtd->mode == MODE_AMR) || (prtd->mode == MODE_AMR_WB) ||
+	    (prtd->mode == MODE_IS127) || (prtd->mode == MODE_4GV_NB) ||
+	    (prtd->mode == MODE_4GV_WB) || (prtd->mode == MODE_4GV_NW))) {
+		pr_err("%s(): mode:%d and format:%u are not mached\n",
+			__func__, prtd->mode, (uint32_t)runtime->format);
+
+		ret =  -EINVAL;
+		goto done;
+	}
+
+	if ((runtime->format != FORMAT_S16_LE) &&
+	    (prtd->mode == MODE_PCM)) {
+		pr_err("%s(): mode:%d and format:%u are not mached\n",
+			__func__, prtd->mode, (uint32_t)runtime->format);
+
+		ret = -EINVAL;
+		goto done;
+	}
+
+	ret = voip_get_media_type(prtd->mode,
+				  prtd->play_samp_rate,
+				  &media_type);
+	if (ret < 0) {
+		pr_err("%s(): fail at getting media_type, ret=%d\n",
+			__func__, ret);
+
+		ret = -EINVAL;
+		goto done;
+	}
+	pr_debug("%s(): media_type=%d\n", __func__, media_type);
+
+	if ((prtd->mode == MODE_PCM) ||
+	    (prtd->mode == MODE_AMR) ||
+	    (prtd->mode == MODE_AMR_WB)) {
+		ret = voip_get_rate_type(prtd->mode,
+					 prtd->rate,
+					 &rate_type);
+		if (ret < 0) {
+			pr_err("%s(): fail at getting rate_type, ret=%d\n",
+				__func__, ret);
+
+			ret = -EINVAL;
+			goto done;
+		}
+		prtd->rate_type = rate_type;
+		pr_debug("rate_type=%d\n", rate_type);
+
+	} else if ((prtd->mode == MODE_IS127) ||
+		   (prtd->mode == MODE_4GV_NB) ||
+		   (prtd->mode == MODE_4GV_WB) ||
+		   (prtd->mode == MODE_4GV_NW)) {
+		ret = voip_get_rate_type(prtd->mode,
+					 prtd->evrc_min_rate,
+					 &evrc_min_rate_type);
+		if (ret < 0) {
+			pr_err("%s(): fail at getting min rate, ret=%d\n",
+				__func__, ret);
+
+			ret = -EINVAL;
+			goto done;
+		}
+		if (evrc_min_rate_type == VOC_0_RATE)
+			evrc_min_rate_type = VOC_8_RATE;
+
+		ret = voip_get_rate_type(prtd->mode,
+					 prtd->evrc_max_rate,
+					 &evrc_max_rate_type);
+		if (ret < 0) {
+			pr_err("%s(): fail at getting max rate, ret=%d\n",
+				__func__, ret);
+
+			ret = -EINVAL;
+			goto done;
+		}
+		if (evrc_max_rate_type == VOC_0_RATE)
+			evrc_max_rate_type = VOC_1_RATE;
+
+		if (evrc_max_rate_type < evrc_min_rate_type) {
+			pr_err("%s(): Invalid EVRC min max rates: %d, %d\n",
+				__func__, evrc_min_rate_type,
+				evrc_max_rate_type);
+
+			ret = -EINVAL;
+			goto done;
+		}
+		pr_debug("%s(): min rate=%d, max rate=%d\n",
+			  __func__, evrc_min_rate_type, evrc_max_rate_type);
+	}
+	if ((prtd->play_samp_rate == 8000) &&
+	    (prtd->cap_samp_rate == 8000))
+		voc_config_vocoder(media_type, rate_type,
+				   VSS_NETWORK_ID_VOIP_NB,
+				   voip_info.dtx_mode,
+				   evrc_min_rate_type,
+				   evrc_max_rate_type);
+	else if ((prtd->play_samp_rate == 16000) &&
+		 (prtd->cap_samp_rate == 16000))
+		voc_config_vocoder(media_type, rate_type,
+				   VSS_NETWORK_ID_VOIP_WB,
+				   voip_info.dtx_mode,
+				   evrc_min_rate_type,
+				   evrc_max_rate_type);
+	else {
+		pr_debug("%s: Invalid rate playback %d, capture %d\n",
+			 __func__, prtd->play_samp_rate,
+			 prtd->cap_samp_rate);
+
+		ret = -EINVAL;
+	}
+done:
+
+	return ret;
+}
+
+static int msm_pcm_prepare(struct snd_pcm_substream *substream)
+{
+	int ret = 0;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct voip_drv_info *prtd = runtime->private_data;
 
 	mutex_lock(&prtd->lock);
 
@@ -784,63 +922,19 @@
 	else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
 		ret = msm_pcm_capture_prepare(substream);
 
-	if ((runtime->format != FORMAT_SPECIAL) &&
-		 ((prtd->mode == MODE_AMR) || (prtd->mode == MODE_AMR_WB) ||
-		 (prtd->mode == MODE_IS127) || (prtd->mode == MODE_4GV_NB) ||
-		 (prtd->mode == MODE_4GV_WB))) {
-		pr_err("mode:%d and format:%u are not mached\n",
-			prtd->mode, (uint32_t)runtime->format);
-		ret =  -EINVAL;
-		goto done;
-	}
-
-	if ((runtime->format != FORMAT_S16_LE) &&
-		(prtd->mode == MODE_PCM)) {
-		pr_err("mode:%d and format:%u are not mached\n",
-			prtd->mode, (uint32_t)runtime->format);
-		ret = -EINVAL;
-		goto done;
-	}
-
 	if (prtd->playback_instance && prtd->capture_instance
-				&& (prtd->state != VOIP_STARTED)) {
+	    && (prtd->state != VOIP_STARTED)) {
+		ret = voip_config_vocoder(substream);
+		if (ret < 0) {
+			pr_err("%s(): fail at configuring vocoder for voip, ret=%d\n",
+				__func__, ret);
 
-		ret = voip_get_rate_type(prtd->mode,
-					prtd->rate,
-					&rate_type);
-		if (ret < 0) {
-			pr_err("fail at getting rate_type\n");
-			ret = -EINVAL;
 			goto done;
 		}
-		prtd->rate_type = rate_type;
-		ret = voip_get_media_type(prtd->mode,
-						prtd->play_samp_rate,
-						&media_type);
-		if (ret < 0) {
-			pr_err("fail at getting media_type\n");
-			goto done;
-		}
-		pr_debug(" media_type=%d, rate_type=%d\n", media_type,
-			rate_type);
-		if ((prtd->play_samp_rate == 8000) &&
-					(prtd->cap_samp_rate == 8000))
-			voc_config_vocoder(media_type, rate_type,
-					VSS_NETWORK_ID_VOIP_NB,
-					voip_info.dtx_mode);
-		else if ((prtd->play_samp_rate == 16000) &&
-					(prtd->cap_samp_rate == 16000))
-			voc_config_vocoder(media_type, rate_type,
-					VSS_NETWORK_ID_VOIP_WB,
-					voip_info.dtx_mode);
-		else {
-			pr_debug("%s: Invalid rate playback %d, capture %d\n",
-				 __func__, prtd->play_samp_rate,
-				 prtd->cap_samp_rate);
-			goto done;
-		}
+
 		voc_register_mvs_cb(voip_process_ul_pkt,
-					voip_process_dl_pkt, prtd);
+				    voip_process_dl_pkt, prtd);
+
 		ret = voc_start_voice_call(
 				voc_get_session_id(VOIP_SESSION_NAME));
 
@@ -986,6 +1080,35 @@
 	return 0;
 }
 
+static int msm_voip_evrc_min_max_rate_config_get(struct snd_kcontrol *kcontrol,
+					 struct snd_ctl_elem_value *ucontrol)
+{
+	mutex_lock(&voip_info.lock);
+
+	ucontrol->value.integer.value[0] = voip_info.evrc_min_rate;
+	ucontrol->value.integer.value[1] = voip_info.evrc_max_rate;
+
+	mutex_unlock(&voip_info.lock);
+
+	return 0;
+}
+
+static int msm_voip_evrc_min_max_rate_config_put(struct snd_kcontrol *kcontrol,
+					 struct snd_ctl_elem_value *ucontrol)
+{
+	mutex_lock(&voip_info.lock);
+
+	voip_info.evrc_min_rate = ucontrol->value.integer.value[0];
+	voip_info.evrc_max_rate = ucontrol->value.integer.value[1];
+
+	pr_debug("%s(): evrc_min_rate=%d,evrc_max_rate=%d\n", __func__,
+		  voip_info.evrc_min_rate, voip_info.evrc_max_rate);
+
+	mutex_unlock(&voip_info.lock);
+
+	return 0;
+}
+
 static int voip_get_rate_type(uint32_t mode, uint32_t rate,
 				 uint32_t *rate_type)
 {
@@ -1083,6 +1206,23 @@
 		}
 		break;
 	}
+	case MODE_4GV_NW: {
+		switch (rate) {
+		case VOC_0_RATE:
+		case VOC_8_RATE:
+		case VOC_4_RATE:
+		case VOC_2_RATE:
+		case VOC_1_RATE:
+		case VOC_8_RATE_NC:
+			*rate_type = rate;
+			break;
+		default:
+			pr_err("wrong rate for 4GV_NW.\n");
+			ret = -EINVAL;
+			break;
+		}
+		break;
+	}
 	default:
 		pr_err("wrong mode type.\n");
 		ret = -EINVAL;
@@ -1122,6 +1262,9 @@
 	case MODE_4GV_WB: /* EVRC-WB */
 		*media_type = VSS_MEDIA_ID_4GV_WB_MODEM;
 		break;
+	case MODE_4GV_NW: /* EVRC-NW */
+		*media_type = VSS_MEDIA_ID_4GV_NW_MODEM;
+		break;
 	default:
 		pr_debug(" input mode is not supported\n");
 		ret = -EINVAL;
diff --git a/sound/soc/msm/qdsp6v2/q6adm.c b/sound/soc/msm/qdsp6v2/q6adm.c
index 297a386..bba4c14 100644
--- a/sound/soc/msm/qdsp6v2/q6adm.c
+++ b/sound/soc/msm/qdsp6v2/q6adm.c
@@ -35,6 +35,7 @@
 /* 2 is to account for module & param ID in payload */
 #define ADM_GET_PARAMETER_LENGTH  (4096 - APR_HDR_SIZE - 2 * sizeof(uint32_t))
 
+#define ULL_SUPPORTED_SAMPLE_RATE 48000
 
 enum {
 	ADM_RX_AUDPROC_CAL,
@@ -1124,11 +1125,14 @@
 			(open.topology_id == VPM_TX_DM_FLUENCE_COPP_TOPOLOGY))
 				rate = 16000;
 
-		if (perf_mode)
+		if (perf_mode) {
 			open.topology_id = NULL_COPP_TOPOLOGY;
+			rate = ULL_SUPPORTED_SAMPLE_RATE;
+		}
 
 		open.dev_num_channel = channel_mode & 0x00FF;
 		open.bit_width = bits_per_sample;
+		WARN_ON(perf_mode && (rate != 48000));
 		open.sample_rate  = rate;
 		memset(open.dev_channel_mapping, 0, 8);
 
diff --git a/sound/soc/msm/qdsp6v2/q6afe.c b/sound/soc/msm/qdsp6v2/q6afe.c
index 2108f6b..59113fe 100644
--- a/sound/soc/msm/qdsp6v2/q6afe.c
+++ b/sound/soc/msm/qdsp6v2/q6afe.c
@@ -357,7 +357,8 @@
 {
 	int ret;
 
-	atomic_set(&this_afe.state, 1);
+	if (wait)
+		atomic_set(&this_afe.state, 1);
 	atomic_set(&this_afe.status, 0);
 	ret = apr_send_pkt(this_afe.apr, data);
 	if (ret > 0) {
@@ -631,6 +632,71 @@
 	}
 }
 
+static int afe_send_hw_delay(u16 port_id, u32 rate)
+{
+	struct hw_delay_entry delay_entry;
+	struct afe_audioif_config_command config;
+	int index = 0;
+	int ret = -EINVAL;
+
+	pr_debug("%s\n", __func__);
+
+	delay_entry.sample_rate = rate;
+	if (afe_get_port_type(port_id) == MSM_AFE_PORT_TYPE_TX)
+		ret = get_hw_delay(TX_CAL, &delay_entry);
+	else if (afe_get_port_type(port_id) == MSM_AFE_PORT_TYPE_RX)
+		ret = get_hw_delay(RX_CAL, &delay_entry);
+
+	if (ret != 0) {
+		pr_warn("%s: Failed to get hw delay info\n", __func__);
+		goto fail_cmd;
+	}
+	index = q6audio_get_port_index(port_id);
+	if (index < 0) {
+		pr_debug("%s: AFE port index invalid!\n", __func__);
+		goto fail_cmd;
+	}
+
+	config.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+				APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+	config.hdr.pkt_size = sizeof(config);
+	config.hdr.src_port = 0;
+	config.hdr.dest_port = 0;
+	config.hdr.token = index;
+
+	config.hdr.opcode = AFE_PORT_CMD_SET_PARAM_V2;
+	config.param.port_id = q6audio_get_port_id(port_id);
+	config.param.payload_size = sizeof(config) - sizeof(struct apr_hdr) -
+				    sizeof(config.param);
+	config.param.payload_address_lsw = 0x00;
+	config.param.payload_address_msw = 0x00;
+	config.param.mem_map_handle = 0x00;
+	config.pdata.module_id = AFE_MODULE_AUDIO_DEV_INTERFACE;
+	config.pdata.param_id = AFE_PARAM_ID_DEVICE_HW_DELAY;
+	config.pdata.param_size = sizeof(config.port);
+
+	config.port.hw_delay.delay_in_us = delay_entry.delay_usec;
+	config.port.hw_delay.device_hw_delay_minor_version =
+				AFE_API_VERSION_DEVICE_HW_DELAY;
+
+	ret = afe_apr_send_pkt(&config, &this_afe.wait[index]);
+	if (ret) {
+		pr_err("%s: AFE hw delay for port %#x failed\n",
+		       __func__, port_id);
+		goto fail_cmd;
+	} else if (atomic_read(&this_afe.status) != 0) {
+		pr_err("%s: config cmd failed\n", __func__);
+		ret = -EINVAL;
+		goto fail_cmd;
+	}
+
+fail_cmd:
+	pr_debug("%s port_id %u rate %u delay_usec %d status %d\n",
+	__func__, port_id, rate, delay_entry.delay_usec, ret);
+	return ret;
+
+}
+
 void afe_send_cal(u16 port_id)
 {
 	pr_debug("%s\n", __func__);
@@ -1247,12 +1313,19 @@
 		return ret;
 
 	afe_send_cal(port_id);
+	afe_send_hw_delay(port_id, rate);
 
 	/* Start SW MAD module */
 	mad_type = afe_port_get_mad_type(port_id);
 	pr_debug("%s: port_id 0x%x, mad_type %d\n", __func__, port_id,
 		 mad_type);
-	if (mad_type != MAD_HW_NONE) {
+	if (mad_type != MAD_HW_NONE && mad_type != MAD_SW_AUDIO) {
+		if (!afe_has_config(AFE_CDC_REGISTERS_CONFIG) ||
+		    !afe_has_config(AFE_SLIMBUS_SLAVE_CONFIG)) {
+			pr_err("%s: AFE isn't configured yet for HW MAD\n",
+			       __func__);
+			return -EINVAL;
+		}
 		ret = afe_turn_onoff_hw_mad(mad_type, true);
 		if (ret) {
 			pr_err("%s: afe_turn_onoff_hw_mad failed %d\n",
@@ -2118,7 +2191,6 @@
 	cnt = port->max_buf_cnt - 1;
 
 	if (port->buf[0].data) {
-		msm_audio_ion_free(port->buf[0].client, port->buf[0].handle);
 		pr_debug("%s:data[%p]phys[%p][%p] , client[%p] handle[%p]\n",
 			__func__,
 			(void *)port->buf[0].data,
@@ -2126,6 +2198,9 @@
 			(void *)&port->buf[0].phys,
 			(void *)port->buf[0].client,
 			(void *)port->buf[0].handle);
+		msm_audio_ion_free(port->buf[0].client, port->buf[0].handle);
+		port->buf[0].client = NULL;
+		port->buf[0].handle = NULL;
 	}
 
 	while (cnt >= 0) {
@@ -2845,7 +2920,7 @@
 	mad_type = afe_port_get_mad_type(port_id);
 	pr_debug("%s: port_id 0x%x, mad_type %d\n", __func__, port_id,
 		 mad_type);
-	if (mad_type != MAD_HW_NONE) {
+	if (mad_type != MAD_HW_NONE && mad_type != MAD_SW_AUDIO) {
 		pr_debug("%s: Turn off MAD\n", __func__);
 		ret = afe_turn_onoff_hw_mad(mad_type, false);
 		if (ret) {
diff --git a/sound/soc/msm/qdsp6v2/q6asm.c b/sound/soc/msm/qdsp6v2/q6asm.c
index c153d10..9c0c362 100644
--- a/sound/soc/msm/qdsp6v2/q6asm.c
+++ b/sound/soc/msm/qdsp6v2/q6asm.c
@@ -650,6 +650,8 @@
 			if (port->buf[cnt].data) {
 				msm_audio_ion_free(port->buf[cnt].client,
 						   port->buf[cnt].handle);
+				port->buf[cnt].client = NULL;
+				port->buf[cnt].handle = NULL;
 				port->buf[cnt].data = NULL;
 				port->buf[cnt].phys = 0;
 				--(port->max_buf_cnt);
@@ -686,7 +688,6 @@
 	}
 
 	if (port->buf[0].data) {
-		msm_audio_ion_free(port->buf[0].client, port->buf[0].handle);
 		pr_debug("%s:data[%p]phys[%p][%p] , client[%p] handle[%p]\n",
 			__func__,
 			(void *)port->buf[0].data,
@@ -694,6 +695,9 @@
 			(void *)&port->buf[0].phys,
 			(void *)port->buf[0].client,
 			(void *)port->buf[0].handle);
+		msm_audio_ion_free(port->buf[0].client, port->buf[0].handle);
+		port->buf[0].client = NULL;
+		port->buf[0].handle = NULL;
 	}
 
 	while (cnt >= 0) {
@@ -1603,7 +1607,7 @@
 
 	open.preprocopo_id = get_asm_topology();
 	if (open.preprocopo_id == 0)
-		open.preprocopo_id = ASM_STREAM_POSTPROC_TOPO_ID_DEFAULT;
+		open.preprocopo_id = ASM_STREAM_POSTPROC_TOPO_ID_NONE;
 	open.bits_per_sample = bits_per_sample;
 	open.mode_flags = 0x0;
 
@@ -1702,7 +1706,7 @@
 
 	open.postprocopo_id = get_asm_topology();
 	if (open.postprocopo_id == 0)
-		open.postprocopo_id = ASM_STREAM_POSTPROC_TOPO_ID_DEFAULT;
+		open.postprocopo_id = ASM_STREAM_POSTPROC_TOPO_ID_NONE;
 
 	switch (format) {
 	case FORMAT_LINEAR_PCM:
@@ -1786,7 +1790,7 @@
 	/* source endpoint : matrix */
 	open.postprocopo_id = get_asm_topology();
 	if (open.postprocopo_id == 0)
-		open.postprocopo_id = ASM_STREAM_POSTPROC_TOPO_ID_DEFAULT;
+		open.postprocopo_id = ASM_STREAM_POSTPROC_TOPO_ID_NONE;
 
 	switch (wr_format) {
 	case FORMAT_LINEAR_PCM:
@@ -2233,7 +2237,6 @@
 			uint16_t sce_left, uint16_t sce_right)
 {
 	struct asm_aac_dual_mono_mapping_param dual_mono;
-	u32 frames_per_buf = 0;
 
 	int rc = 0;
 
@@ -2244,11 +2247,8 @@
 
 	dual_mono.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
 	dual_mono.encdec.param_id = ASM_PARAM_ID_AAC_DUAL_MONO_MAPPING;
-	dual_mono.encdec.param_size = sizeof(struct asm_aac_enc_cfg_v2) -
-				sizeof(struct asm_stream_cmd_set_encdec_param);
-	dual_mono.encblk.frames_per_buf = frames_per_buf;
-	dual_mono.encblk.enc_cfg_blk_size  = dual_mono.encdec.param_size -
-				sizeof(struct asm_enc_cfg_blk_param_v2);
+	dual_mono.encdec.param_size = sizeof(dual_mono.left_channel_sce) +
+				sizeof(dual_mono.right_channel_sce);
 	dual_mono.left_channel_sce = sce_left;
 	dual_mono.right_channel_sce = sce_right;
 
diff --git a/sound/soc/msm/qdsp6v2/q6lsm.c b/sound/soc/msm/qdsp6v2/q6lsm.c
index e8880d1..9227b23 100644
--- a/sound/soc/msm/qdsp6v2/q6lsm.c
+++ b/sound/soc/msm/qdsp6v2/q6lsm.c
@@ -320,13 +320,6 @@
 	int rc;
 	struct lsm_stream_cmd_open_tx open;
 
-	if (!afe_has_config(AFE_CDC_REGISTERS_CONFIG) ||
-	    !afe_has_config(AFE_SLIMBUS_SLAVE_CONFIG)) {
-		pr_err("%s: AFE isn't configured yet\n", __func__);
-		rc = -EAGAIN;
-		goto exit;
-	}
-
 	memset(&open, 0, sizeof(open));
 	q6lsm_add_hdr(client, &open.hdr, sizeof(open), true);
 
@@ -339,8 +332,6 @@
 		pr_err("%s: Open failed opcode 0x%x, rc %d\n",
 		       __func__, open.hdr.opcode, rc);
 
-exit:
-	pr_debug("%s: leave %d\n", __func__, rc);
 	return rc;
 }
 
diff --git a/sound/soc/msm/qdsp6v2/q6voice.c b/sound/soc/msm/qdsp6v2/q6voice.c
index ae5bbbf..c16b14c 100644
--- a/sound/soc/msm/qdsp6v2/q6voice.c
+++ b/sound/soc/msm/qdsp6v2/q6voice.c
@@ -1544,7 +1544,8 @@
 	switch (common.mvs_info.media_type) {
 	case VSS_MEDIA_ID_EVRC_MODEM:
 	case VSS_MEDIA_ID_4GV_NB_MODEM:
-	case VSS_MEDIA_ID_4GV_WB_MODEM: {
+	case VSS_MEDIA_ID_4GV_WB_MODEM:
+	case VSS_MEDIA_ID_4GV_NW_MODEM: {
 		struct cvs_set_cdma_enc_minmax_rate_cmd cvs_set_cdma_rate;
 
 		pr_debug("Setting EVRC min-max rate\n");
@@ -1561,8 +1562,10 @@
 		cvs_set_cdma_rate.hdr.token = 0;
 		cvs_set_cdma_rate.hdr.opcode =
 				VSS_ISTREAM_CMD_CDMA_SET_ENC_MINMAX_RATE;
-		cvs_set_cdma_rate.cdma_rate.min_rate = common.mvs_info.rate;
-		cvs_set_cdma_rate.cdma_rate.max_rate = common.mvs_info.rate;
+		cvs_set_cdma_rate.cdma_rate.min_rate =
+				common.mvs_info.evrc_min_rate;
+		cvs_set_cdma_rate.cdma_rate.max_rate =
+				common.mvs_info.evrc_max_rate;
 
 		v->cvs_state = CMD_STATUS_FAIL;
 
@@ -1580,6 +1583,13 @@
 
 			goto fail;
 		}
+
+		if (common.mvs_info.media_type != VSS_MEDIA_ID_EVRC_MODEM) {
+			ret = voice_set_dtx(v);
+			if (ret < 0)
+				goto fail;
+		}
+
 		break;
 	}
 	case VSS_MEDIA_ID_AMR_NB_MODEM: {
@@ -3622,7 +3632,8 @@
 	return -EINVAL;
 }
 
-static int voice_send_stream_mute_cmd(struct voice_data *v)
+static int voice_send_stream_mute_cmd(struct voice_data *v, uint16_t direction,
+				     uint16_t mute_flag, uint32_t ramp_duration)
 {
 	struct cvs_set_mute_cmd cvs_mute_cmd;
 	int ret = 0;
@@ -3650,10 +3661,9 @@
 	cvs_mute_cmd.hdr.dest_port = voice_get_cvs_handle(v);
 	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->stream_tx.stream_mute;
-	cvs_mute_cmd.cvs_set_mute.ramp_duration_ms =
-				v->stream_tx.stream_mute_ramp_duration_ms;
+	cvs_mute_cmd.cvs_set_mute.direction = direction;
+	cvs_mute_cmd.cvs_set_mute.mute_flag = mute_flag;
+	cvs_mute_cmd.cvs_set_mute.ramp_duration_ms = ramp_duration;
 
 	v->cvs_state = CMD_STATUS_FAIL;
 	ret = apr_send_pkt(common.apr_q6_cvs, (uint32_t *) &cvs_mute_cmd);
@@ -4309,6 +4319,13 @@
 						VSS_IVOLUME_DIRECTION_RX,
 						VSS_IVOLUME_MUTE_ON,
 						DEFAULT_MUTE_RAMP_DURATION);
+			/* Send unmute cmd as the TX stream
+			 * might be muted previously
+			 */
+			voice_send_stream_mute_cmd(v,
+						VSS_IVOLUME_DIRECTION_TX,
+						VSS_IVOLUME_MUTE_OFF,
+						DEFAULT_MUTE_RAMP_DURATION);
 		} else if (v->lch_mode == VOICE_LCH_STOP) {
 			pr_debug("%s: TX and RX mute OFF\n", __func__);
 
@@ -4323,7 +4340,10 @@
 			/* Reset lch mode when VOICE_LCH_STOP is recieved */
 			v->lch_mode = 0;
 			/* Apply cached mute setting */
-			voice_send_stream_mute_cmd(v);
+			voice_send_stream_mute_cmd(v,
+				VSS_IVOLUME_DIRECTION_TX,
+				v->stream_tx.stream_mute,
+				v->stream_tx.stream_mute_ramp_duration_ms);
 		} else {
 			pr_debug("%s: Mute commands not sent for lch_mode=%d\n",
 				 __func__, v->lch_mode);
@@ -4403,7 +4423,10 @@
 								ramp_duration;
 			if (is_voc_state_active(v->voc_state) &&
 				(v->lch_mode == 0))
-				ret = voice_send_stream_mute_cmd(v);
+				ret = voice_send_stream_mute_cmd(v,
+				VSS_IVOLUME_DIRECTION_TX,
+				v->stream_tx.stream_mute,
+				v->stream_tx.stream_mute_ramp_duration_ms);
 			mutex_unlock(&v->lock);
 		} else {
 			pr_err("%s: invalid session_id 0x%x\n", __func__,
@@ -4889,7 +4912,10 @@
 		if (ret < 0)
 			pr_err("voice volume failed\n");
 
-		ret = voice_send_stream_mute_cmd(v);
+		ret = voice_send_stream_mute_cmd(v,
+				VSS_IVOLUME_DIRECTION_TX,
+				v->stream_tx.stream_mute,
+				v->stream_tx.stream_mute_ramp_duration_ms);
 		if (ret < 0)
 			pr_err("voice mute failed\n");
 
@@ -4929,14 +4955,18 @@
 }
 
 void voc_config_vocoder(uint32_t media_type,
-			  uint32_t rate,
-			  uint32_t network_type,
-			  uint32_t dtx_mode)
+			uint32_t rate,
+			uint32_t network_type,
+			uint32_t dtx_mode,
+			uint32_t evrc_min_rate,
+			uint32_t evrc_max_rate)
 {
 	common.mvs_info.media_type = media_type;
 	common.mvs_info.rate = rate;
 	common.mvs_info.network_type = network_type;
 	common.mvs_info.dtx_mode = dtx_mode;
+	common.mvs_info.evrc_min_rate = evrc_min_rate;
+	common.mvs_info.evrc_max_rate = evrc_max_rate;
 }
 
 static int32_t qdsp_mvm_callback(struct apr_client_data *data, void *priv)
@@ -5487,6 +5517,8 @@
 
 	rc = msm_audio_ion_free(v->shmem_info.sh_buf.client,
 				v->shmem_info.sh_buf.handle);
+	v->shmem_info.sh_buf.client = NULL;
+	v->shmem_info.sh_buf.handle = NULL;
 	if (rc < 0) {
 		pr_err("%s: Error:%d freeing memory\n", __func__, rc);
 
diff --git a/sound/soc/msm/qdsp6v2/q6voice.h b/sound/soc/msm/qdsp6v2/q6voice.h
index 798391d..39f0986 100644
--- a/sound/soc/msm/qdsp6v2/q6voice.h
+++ b/sound/soc/msm/qdsp6v2/q6voice.h
@@ -217,7 +217,8 @@
 		VOC_8_RATE, /* 1/8 rate    */
 		VOC_4_RATE, /* 1/4 rate    */
 		VOC_2_RATE, /* 1/2 rate    */
-		VOC_1_RATE  /* Full rate   */
+		VOC_1_RATE,  /* Full rate   */
+		VOC_8_RATE_NC  /* Noncritical 1/8 rate   */
 };
 
 struct vss_istream_cmd_set_tty_mode_t {
@@ -981,6 +982,8 @@
 /*CDMA EVRC-B vocoder modem format */
 #define VSS_MEDIA_ID_4GV_WB_MODEM	0x00010FC4
 /*CDMA EVRC-WB vocoder modem format */
+#define VSS_MEDIA_ID_4GV_NW_MODEM	0x00010FC5
+/*CDMA EVRC-NW vocoder modem format */
 
 #define VSS_IVOCPROC_CMD_CREATE_FULL_CONTROL_SESSION_V2	0x000112BF
 
@@ -1231,6 +1234,8 @@
 	ul_cb_fn ul_cb;
 	dl_cb_fn dl_cb;
 	void *private_data;
+	uint32_t evrc_min_rate;
+	uint32_t evrc_max_rate;
 };
 
 struct dtmf_driver_info {
@@ -1366,7 +1371,9 @@
 void voc_config_vocoder(uint32_t media_type,
 			uint32_t rate,
 			uint32_t network_type,
-			uint32_t dtx_mode);
+			uint32_t dtx_mode,
+			uint32_t evrc_min_rate,
+			uint32_t evrc_max_rate);
 
 enum {
 	DEV_RX = 0,
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index de98feb..55f8dc8 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -3231,8 +3231,11 @@
 	mutex_init(&card->dapm_power_mutex);
 
 	ret = snd_soc_instantiate_card(card);
-	if (ret != 0)
+	if (ret != 0) {
 		soc_cleanup_card_debugfs(card);
+		if (card->rtd)
+			kfree(card->rtd);
+	}
 
 
 	return ret;